Back to Home

Budget temperature monitoring: Arduino + Zabbix

We have an organization deployed Zabbix server to monitor the performance of servers and AWPs. Due to the peculiarities of the technical process · the equipment is “spread out” in several rooms and spaced apart ...

Budget temperature monitoring: Arduino + Zabbix

We have an organization deployed Zabbix server to monitor the performance of servers and AWPs. Due to the peculiarities of the technical process, the equipment is “spread out” in several rooms and distributed throughout the enterprise. Naturally, together with the basic parameters of computers (it works / does not work) I want to control the microclimate in server computers. At the same time, as usual, the possibilities are very limited, and “knocking out” significant funds for complex temperature monitoring systems (including the control boards with thermal sensors for rack-mount APC UPSs) is a separate quest.

In the main server everything is simple - one such board was installed (purchased a long time ago by the predecessor along with the main equipment), an APC-shny thermal sensor was plugged in, an agent was brought in Zabbiks, everything works via SNMP. It's boring :) There is no monitoring of remote hardware, there are no funds either - see above. Therefore, it was decided to show ingenuity, save the budget and at the same time pump the new skill by constructing a simple and cheap “knee” solution that fits, nevertheless, into the existing infrastructure of monitoring Zabbix.

Required components:


The total cost of the components is $ 10 with delivery.

Assembling the device is not difficult. The network module is put on the main board with a “sandwich”, the thermal sensor is soldered to its pins. Sensor connection: red +5 V, black - ground, yellow - data; between + 5V and Data we solder a 4.7 kΩ pull-up resistor.

The pin for the data is selected based on the pins used by the network module (D10 - SS; D11 - MOSI; D12 - MISO; D13 - SCK; D2 - IRQ).

Rake: in the prototype of the device faced with a conflict - the data on the temperature were issued randomly, "after two for the third." The reason was that I attached a thermal sensor to pin 2, which, as I later foundon the Internet, it is used by the network module to generate an interrupt when a packet arrives. I rearranged on the 4th - it worked like a clock.

After assembling the hardware, go to the software.

The device will work on the network and pretend to be a zabbiks agent, for this it needs a MAC and an IP address. We decide how it is more convenient to hard-sew when programming, generate a MAC from the address of the temperature sensor and receive IP via DHCP, etc. I went along the simplest path and zahardkodil both parameters.

The exchange protocol with the zabbiks-server is described in the documentation . Our device will respond to two commands - agent.ping and env.temp(there is room for further creativity here, you can attach any of the expansion modules available to the Arduino - even if it is a humidity sensor, even if there is illumination - yes, whatever you want). For all other commands, it will swear to respond with a standard answer, understandable zabbiks-server.

For those who start from scratch (like me) - the Arduino programming is done using the Arduino IDE , the installation and configuration of which is elementary. The components require the UIPEthernet and OneWire libraries, which are installed and connected to the project via the Sketch menu, Connect Library, Manage Libraries ...
If you have other components (for example, a network module not on enc28j60, but on another chip), other libraries will also be needed !

The code for working with the network module and with the temperature sensor is typical, from the Internet, with some assumptions and simplifications.

After uploading the code to the controller and connecting the ethernet cable, we check from the console:

$ zabbix_get -s 192.168.4.5 -k agent.ping
1
$ zabbix_get -s 192.168.4.5 -k env.temp
23.12
$ zabbix_get -s 192.168.4.5 -k bla-blah
ZBX_NOTSUPPORTED

Rake: The compiled version of zabbix_get for Windows laid out on zabbix.com is outdated and uses a different protocol (with the ZBXD \ x01 header in the server request). Linux version is relevant and the protocol corresponds to the code given.

Everything works as intended. In the admin panel of the zabbiks we create a new host with the selected IP, in it there are two keys, Numeric (unsigned) agent.ping and Numeric (float) env.temp, enjoy the work. Charts, triggers - as usual.

Power device - via native USB. Body - optional: suitable plastic box, shrink, blue electrical tape.

The sensor resolution is about 0.06 (more precisely, 1/16) ° C, accuracy - when immersed in melting snow, it showed 0.19 ° C (maybe it would have dropped even lower, but there was little snow and it all melted quickly). I think for a device worth $ 10 and the described goals are more than enough.

Sketch
#include<OneWire.h>#include<UIPEthernet.h>
byte mac[] = { 0xDE, 0x05, 0xB6, 0x27, 0x39, 0x19 }; // random MAC
byte ip[] = { 192, 168, 4, 5 }; // IP address in local network
String readString = String(20); 
byte addr[8];
OneWire ds(4); // DS18B20 at pin 4EthernetServer server(10050); // Zabbix portvoidsetup(){
  Ethernet.begin(mac, ip);
  server.begin();
  ds.search(addr);
}
voidloop(){
  byte data[2];
  float celsius;
  readString = "";
  if (EthernetClient client = server.available())
  {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n') // end of query from zabbix server 
        {
          client.print("ZBXD\x01"); // response headerif (readString == "agent.ping") {
            byte responseBytes [] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '1'}; 
            client.write(responseBytes, 9);
          } elseif (readString == "env.temp") {
            ds.reset();
            ds.select(addr);
            ds.write(0x44);  // start conversion with regular (non-parasite!) power
            delay(1000);  
            ds.reset();
            ds.select(addr);
            ds.write(0xBE);  // read Scratchpad
            data[0] = ds.read();
            data[1] = ds.read();
            int16_t raw = (data[1] << 8) | data[0];
            celsius = (float)raw / 16.0;
            byte responseBytes [] = {(byte) String(celsius).length(), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
            client.write(responseBytes, 8);
            client.print(celsius);
          }
          else {
            byte responseBytes [] = {0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
            client.write(responseBytes, 8);
            client.print("ZBX_NOTSUPPORTED");
          }
          break;
        }
        elseif (readString.length() < 20) {
          readString = readString + c;
        }
      }
    }
    delay(10);
    client.stop();
  }
}

Read Next