We have a Zabbix server deployed in our organization to monitor the health 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 the server computers as well. 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 opened 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 Zabbix monitoring infrastructure.
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 found on the Internet, is used by the network module to generate an interrupt when a packet arrives. 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 convenient it is to hard-sew when programming, generate a
MAC from the address of the temperature sensor and get 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, you can attach any of the expansion modules available to Arduino - even a humidity sensor, even illumination - yes what you please). 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 a different chip), other libraries will 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). The Linux version is relevant and the protocol corresponds to the given code.
Everything works as intended. In the admin panel of the zabbiks we create a new host with the selected IP, it has 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 quickly melted). I think for a device worth 10 dollars and the described goals is 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 4 EthernetServer server(10050); // Zabbix port void setup() { Ethernet.begin(mac, ip); server.begin(); ds.search(addr); } void loop() { 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 header if (readString == "agent.ping") { byte responseBytes [] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '1'}; client.write(responseBytes, 9); } else if (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; } else if (readString.length() < 20) { readString = readString + c; } } } delay(10); client.stop(); } }