Temperature Control in Server Cabinets with Arduino
In one of the previous posts, I talked about projects created by users of the FLProg program. And today I want to talk about the system that I created myself. The server room at the station where I work, as it should be, is in a separate room. To cool the servers there are two air conditioners installed. Unfortunately, these are ordinary household models, so regularly one or the other is under repair. The department management, knowing about my work on the FLProg project, suggested creating a system for monitoring the temperature in server cabinets and controlling the operation of their fans. Information about the current temperature should be displayed on the board in the room of the duty engineers, and in case of temperature rise above a certain threshold, give an audible alarm. I took up this work, and this is what happened ...
The situation was complicated by the fact that we are somewhere 200 kilometers from the nearest civilization, and we had to assemble the system from the reserves that I had with me, plus something from the old rubbish from the pantries. In my possession were:
1. Arduino Nano
2. Temperature sensor DS18B20
3. Two temperature and humidity sensors DHT-22
4. Four-line display with 20 characters per line with the I2C board
The device diagram was developed: Schematic diagram
Then the circuit boards were developed:
Basic board in the program Sprint-Layout_6
Button board in the program Sprint-Layout_6
Iron and special paper for LUT technology was not found, so I had to remember my childhood and draw boards with handles with varnish, begged from a cleaning lady.




After the initial assembly and filling of the trial sketch, the first problems arose. Firstly, the relays refused to operate, although 5 volts came to the coils. Before installing on the board, I naturally checked the resistance of the coils and applied power to them with a check of the trip. It turned out that the relay is very tricky. Although there are no diodes inside (the coils ring the same on both sides), the power polarity on the coils plays a role for them. Most likely, they have a magnetized armature to reduce the trip current. Because of this, the reels moved to the other side of the board. After moving the reels, everything worked fine.


Then the final firmware for the board was developed.
The project is in the FLProg program .
#include
#include
#include
#include
#include "DHT.h"
LiquidCrystal_I2C _lcd1(0x3F, 20, 4);
int _dispTempLength1=0;
boolean _isNeedClearDisp1;
byte _d18x2x1Addr[8]={0x28, 0xFF, 0x11, 0x94, 0x3C, 0x4, 0x0, 0x48};
DHT _dht1(11, DHT22);
OneWire _ow10(10);
bool _gtv1 = 0;
bool _gtv3 = 0;
bool _gtv4 = 0;
bool _gtv5 = 0;
int _gtv2 = 23;
int _gtv6 = 27;
int _gtv7 = 30;
int _gtv8 = 35;
int _gtv9 = 0;
bool _gtv10 = 0;
String _gtv11 = "_C";
bool _gtv12 = 0;
bool _gtv13 = 0;
float _gtv14 = 0;
float _gtv15 = 0;
bool _gtv16 = 0;
int _gtv17 = 10;
bool _gtv18 = 0;
bool _gtv19 = 0;
bool _gtv20 = 0;
bool _gtv21 = 0;
bool _gtv22 = 0;
bool _gtv23 = 0;
bool _gtv24 = 0;
bool _gtv25 = 0;
bool _gtv26 = 0;
bool _gtv27 = 0;
bool _gtv28 = 0;
bool _trgrt9 = 0;
bool _trgrt9I = 0;
bool _bounse1S = 0;
bool _bounse1O = 0;
unsigned long _bounse1P = 0UL;
bool _trgrt4 = 0;
bool _trgrt4I = 0;
bool _bounse2S = 0;
bool _bounse2O = 0;
unsigned long _bounse2P = 0UL;
bool _trgrt5 = 0;
bool _trgrt5I = 0;
bool _bounse3S = 0;
bool _bounse3O = 0;
unsigned long _bounse3P = 0UL;
bool _trgrt8 = 0;
bool _trgrt8I = 0;
bool _count1I = 0;
int _count1P = 0;
bool _tim1I = 0;
bool _tim1O = 0;
unsigned long _tim1P = 0UL;
bool _trgrt1 = 0;
bool _trgrt1I = 0;
bool _trgrt2 = 0;
bool _trgrt2I = 0;
bool _trgrt3 = 0;
bool _trgrt3I = 0;
int _disp1oldLength = 0;
String _mux1;
int _disp3oldLength = 0;
int _disp4oldLength = 0;
int _disp5oldLength = 0;
int _disp6oldLength = 0;
int _disp7oldLength = 0;
String _swi2;
String _swi3;
int _disp2oldLength = 0;
String _mux2;
int _disp8oldLength = 0;
int _disp9oldLength = 0;
int _disp10oldLength = 0;
int _disp11oldLength = 0;
int _disp12oldLength = 0;
String _swi4;
String _swi5;
bool _trgrt10 = 0;
bool _trgrt10I = 0;
bool _trgrt11 = 0;
bool _trgrt11I = 0;
bool _trgrt12 = 0;
bool _trgrt12I = 0;
bool _trgrt13 = 0;
bool _trgrt13I = 0;
unsigned long _d18x2x1Tti = 0UL;
float _d18x2x1O = 0.00;
unsigned long _dht1Tti = 0UL;
float _dht1t = 0.00;
float _dht1h = 0.00;
bool _trgr1 = 0;
bool _trgr2 = 0;
bool _trgrt6 = 0;
bool _trgrt6I = 0;
bool _trgr3 = 0;
bool _trgr4 = 0;
bool _trgrt7 = 0;
bool _trgrt7I = 0;
bool _trgr5 = 0;
bool _pzs1OES = 0;
int _pzs1OFS = 0;
bool _gen1I = 0;
bool _gen1O = 0;
unsigned long _gen1P = 0UL;
int _swi1;
bool _D1B1 = 0;
bool _gen2I = 0;
bool _gen2O = 0;
unsigned long _gen2P = 0UL;
String _swi6;
int _disp13oldLength = 0;
bool _SEEPR1OSN = 0;
bool _SEEPR2OSN = 0;
bool _SEEPR3OSN = 0;
bool _SEEPR4OSN = 0;
void setup()
{
Wire.begin();
pinMode(12, OUTPUT);
pinMode(4, OUTPUT);
pinMode(3, OUTPUT);
pinMode(2, OUTPUT);
_lcd1.init();
_lcd1.noBacklight();
_dht1.begin();
}
void loop()
{if(_isTimer(_dht1Tti, 6000)) {
_dht1Tti = millis();
float tempDht11;
tempDht11 = _dht1.readTemperature();
if (!(isnan(tempDht11))){_dht1t=tempDht11; }
}if (_isNeedClearDisp1) {_lcd1.clear(); _isNeedClearDisp1= 0;}
if (1) { if (_trgrt9I) { _trgrt9 = 0;} else {_trgrt9 = 1; _trgrt9I = 1;} } else {_trgrt9 = 0; _trgrt9I = 0;};
if (_trgrt9) {
_gtv6 = (EEPROMReadInt(0));
}
if (_trgrt9) {
_gtv7 = (EEPROMReadInt(2));
}
if (_trgrt9) {
_gtv2 = (EEPROMReadInt(4));
}
if (_trgrt9) {
_gtv8 = (EEPROMReadInt(6));
}
bool _bounceTmp1 = ! (( (analogRead (3))) > (500));
if (_bounse1S)
{
if (millis() >= (_bounse1P + 40))
{_bounse1O= _bounceTmp1; _bounse1S=0;}
}
else
{
if (_bounceTmp1 != _bounse1O )
{_bounse1S=1; _bounse1P = millis();}
}
if (_bounse1O) { if (_trgrt4I) { _trgrt4 = 0;} else {_trgrt4 = 1; _trgrt4I = 1;} } else {_trgrt4 = 0; _trgrt4I = 0;};
_gtv3 = _bounse1O;
_gtv12 = (_trgrt4) && (!(_gtv20)) ;
bool _bounceTmp2 = ! (( (analogRead (2))) > (500));
if (_bounse2S)
{
if (millis() >= (_bounse2P + 40))
{_bounse2O= _bounceTmp2; _bounse2S=0;}
}
else
{
if (_bounceTmp2 != _bounse2O )
{_bounse2S=1; _bounse2P = millis();}
}
if (_bounse2O) { if (_trgrt5I) { _trgrt5 = 0;} else {_trgrt5 = 1; _trgrt5I = 1;} } else {_trgrt5 = 0; _trgrt5I = 0;};
_gtv4 = _bounse2O;
_gtv13 = (_trgrt5) && (!(_gtv20)) ;
bool _bounceTmp3 = ! (( (analogRead (1))) > (500));
if (_bounse3S)
{
if (millis() >= (_bounse3P + 40))
{_bounse3O= _bounceTmp3; _bounse3S=0;}
}
else
{
if (_bounceTmp3 != _bounse3O )
{_bounse3S=1; _bounse3P = millis();}
}
if (_bounse3O) { if (_trgrt8I) { _trgrt8 = 0;} else {_trgrt8 = 1; _trgrt8I = 1;} } else {_trgrt8 = 0; _trgrt8I = 0;};
_gtv5 = _bounse3O;
_gtv19 = (_trgrt8) && (!(_gtv20)) ;
if (_gtv19)
{
if (! _count1I)
{
_count1P = _count1P+1;
_count1I = 1;
}
}
else
{
_count1I=0;
}
if (_count1P < 0 ) _count1P = 0;
if ( (_gtv1) || (_gtv10) ) _count1P = 0;
if (_gtv5) { if (_trgrt1I) { _trgrt1 = 0;} else {_trgrt1 = 1; _trgrt1I = 1;} } else {_trgrt1 = 0; _trgrt1I = 0;};
if (_gtv3) { if (_trgrt2I) { _trgrt2 = 0;} else {_trgrt2 = 1; _trgrt2I = 1;} } else {_trgrt2 = 0; _trgrt2I = 0;};
if (_gtv4) { if (_trgrt3I) { _trgrt3 = 0;} else {_trgrt3 = 1; _trgrt3I = 1;} } else {_trgrt3 = 0; _trgrt3I = 0;};
if ( ((_count1P) > (0)) && ((! (_trgrt1) || (_trgrt2) || (_trgrt3) )) )
{
if (_tim1I)
{
if ( _isTimer(_tim1P, 60000)) _tim1O = 1;
}
else
{
_tim1I = 1;
_tim1P = millis();
}
}
else
{
_tim1O = 0;
_tim1I = 0;
}
_gtv9 = _count1P;
_gtv1 = _count1P >= 5;
_gtv10 = _tim1O;
if((_gtv9) == 0) {_mux1 = String("Terst");}
if((_gtv9) == 1) {_mux1 = String("Value Off");}
if((_gtv9) == 2) {_mux1 = String("Value 1 On");}
if((_gtv9) == 3) {_mux1 = String("Value 2 On");}
if((_gtv9) == 4) {_mux1 = String("Value Alarm");}
if ((_gtv9) > (0)) {
_dispTempLength1 = ((_mux1)).length();
if (_disp1oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp1oldLength = _dispTempLength1;
_lcd1.setCursor(int((20 - _dispTempLength1)/2), 0);
_lcd1.print((_mux1));
} else {
if (_disp1oldLength > 0) {_isNeedClearDisp1 = 1; _disp1oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = (String("SU T:")).length();
if (_disp3oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp3oldLength = _dispTempLength1;
_lcd1.setCursor(0, 0);
_lcd1.print(String("SU T:"));
} else {
if (_disp3oldLength > 0) {_isNeedClearDisp1 = 1; _disp3oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((( _floatToStringWitRaz(_gtv14,1)))).length();
if (_disp4oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp4oldLength = _dispTempLength1;
_lcd1.setCursor(5, 0);
_lcd1.print((( _floatToStringWitRaz(_gtv14,1))));
} else {
if (_disp4oldLength > 0) {_isNeedClearDisp1 = 1; _disp4oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = (String("C")).length();
if (_disp5oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp5oldLength = _dispTempLength1;
_lcd1.setCursor(9, 0);
_lcd1.print(String("C"));
} else {
if (_disp5oldLength > 0) {_isNeedClearDisp1 = 1; _disp5oldLength = 0;}
}
if(_gtv21)
{_swi2=String("*");}
else
{_swi2=String("-");}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((_swi2)).length();
if (_disp6oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp6oldLength = _dispTempLength1;
_lcd1.setCursor(11, 0);
_lcd1.print((_swi2));
} else {
if (_disp6oldLength > 0) {_isNeedClearDisp1 = 1; _disp6oldLength = 0;}
}
if(_gtv22)
{_swi3=String("*");}
else
{_swi3=String("-");}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((_swi3)).length();
if (_disp7oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp7oldLength = _dispTempLength1;
_lcd1.setCursor(13, 0);
_lcd1.print((_swi3));
} else {
if (_disp7oldLength > 0) {_isNeedClearDisp1 = 1; _disp7oldLength = 0;}
}
if((_gtv9) == 0) {_mux2 = String("test");}
if((_gtv9) == 1) {_mux2 = (((String(_gtv2))) + (_gtv11));}
if((_gtv9) == 2) {_mux2 = (((String(_gtv6))) + (_gtv11));}
if((_gtv9) == 3) {_mux2 = (((String(_gtv7))) + (_gtv11));}
if((_gtv9) == 4) {_mux2 = (((String(_gtv8))) + (_gtv11));}
if ((_gtv9) > (0)) {
_dispTempLength1 = ((_mux2)).length();
if (_disp2oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp2oldLength = _dispTempLength1;
_lcd1.setCursor(int((20 - _dispTempLength1)/2), 1);
_lcd1.print((_mux2));
} else {
if (_disp2oldLength > 0) {_isNeedClearDisp1 = 1; _disp2oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = (String("CU T:")).length();
if (_disp8oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp8oldLength = _dispTempLength1;
_lcd1.setCursor(0, 1);
_lcd1.print(String("CU T:"));
} else {
if (_disp8oldLength > 0) {_isNeedClearDisp1 = 1; _disp8oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((( _floatToStringWitRaz(_gtv15,1)))).length();
if (_disp9oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp9oldLength = _dispTempLength1;
_lcd1.setCursor(5, 1);
_lcd1.print((( _floatToStringWitRaz(_gtv15,1))));
} else {
if (_disp9oldLength > 0) {_isNeedClearDisp1 = 1; _disp9oldLength = 0;}
}
if ((0) == (_gtv9)) {
_dispTempLength1 = (String("C")).length();
if (_disp10oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp10oldLength = _dispTempLength1;
_lcd1.setCursor(9, 1);
_lcd1.print(String("C"));
} else {
if (_disp10oldLength > 0) {_isNeedClearDisp1 = 1; _disp10oldLength = 0;}
}
if(_gtv23)
{_swi4=String("*");}
else
{_swi4=String("-");}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((_swi4)).length();
if (_disp11oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp11oldLength = _dispTempLength1;
_lcd1.setCursor(11, 1);
_lcd1.print((_swi4));
} else {
if (_disp11oldLength > 0) {_isNeedClearDisp1 = 1; _disp11oldLength = 0;}
}
if(_gtv24)
{_swi5=String("*");}
else
{_swi5=String("-");}
if ((0) == (_gtv9)) {
_dispTempLength1 = ((_swi5)).length();
if (_disp12oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp12oldLength = _dispTempLength1;
_lcd1.setCursor(13, 1);
_lcd1.print((_swi5));
} else {
if (_disp12oldLength > 0) {_isNeedClearDisp1 = 1; _disp12oldLength = 0;}
}
if ( (_gtv5) && (_gtv3) && (_gtv4) ) { if (_trgrt10I) { _trgrt10 = 0;} else {_trgrt10 = 1; _trgrt10I = 1;} } else {_trgrt10 = 0; _trgrt10I = 0;};
if ( (_gtv12) && ((_gtv9) == (1)) ) {
_gtv2 = (_gtv2)+(1);
}
if ( ((_gtv9) == (1)) && (_gtv13) ) {
_gtv2 = (_gtv2)-(1);
}
if (_trgrt10) {
_gtv2 = 25;
}
_gtv25 = ( (_gtv12) && ((_gtv9) == (1)) ) || ( ((_gtv9) == (1)) && (_gtv13) ) || (_trgrt10) ;
if ( (_gtv5) && (_gtv3) && (_gtv4) ) { if (_trgrt11I) { _trgrt11 = 0;} else {_trgrt11 = 1; _trgrt11I = 1;} } else {_trgrt11 = 0; _trgrt11I = 0;};
if ( (_gtv12) && ((_gtv9) == (2)) ) {
_gtv6 = (_gtv6)+(1);
}
if ( ((_gtv9) == (2)) && (_gtv13) ) {
_gtv6 = (_gtv6)-(1);
}
if (_trgrt11) {
_gtv6 = 27;
}
_gtv26 = ( (_gtv12) && ((_gtv9) == (2)) ) || ( ((_gtv9) == (2)) && (_gtv13) ) || (_trgrt11) ;
if ( (_gtv5) && (_gtv3) && (_gtv4) ) { if (_trgrt12I) { _trgrt12 = 0;} else {_trgrt12 = 1; _trgrt12I = 1;} } else {_trgrt12 = 0; _trgrt12I = 0;};
if ( (_gtv12) && ((_gtv9) == (3)) ) {
_gtv7 = (_gtv7)+(1);
}
if ( ((_gtv9) == (3)) && (_gtv13) ) {
_gtv7 = (_gtv7)-(1);
}
if (_trgrt12) {
_gtv7 = 30;
}
_gtv27 = ( (_gtv12) && ((_gtv9) == (3)) ) || ( ((_gtv9) == (3)) && (_gtv13) ) || (_trgrt12) ;
if ( (_gtv5) && (_gtv3) && (_gtv4) ) { if (_trgrt13I) { _trgrt13 = 0;} else {_trgrt13 = 1; _trgrt13I = 1;} } else {_trgrt13 = 0; _trgrt13I = 0;};
if ( (_gtv12) && ((_gtv9) == (4)) ) {
_gtv8 = (_gtv8)+(1);
}
if ( ((_gtv9) == (4)) && (_gtv13) ) {
_gtv8 = (_gtv8)-(1);
}
if (_trgrt13) {
_gtv8 = 35;
}
_gtv28 = ( (_gtv12) && ((_gtv9) == (4)) ) || ( ((_gtv9) == (4)) && (_gtv13) ) || (_trgrt13) ;
if(_isTimer(_d18x2x1Tti, 5000)) {
_d18x2x1Tti = millis();
_d18x2x1O= _readDS18_ow10(_d18x2x1Addr, 0);}
_gtv14 = (_d18x2x1O);
_gtv15 = _dht1t;
if(((int((_gtv14)*(_gtv17)))) < ((_gtv2)*(_gtv17))) _trgr1 = 0;
if(((int((_gtv14)*(_gtv17)))) > ((_gtv6)*(_gtv17))) _trgr1 = 1;
if(((int((_gtv14)*(_gtv17)))) < ((_gtv2)*(_gtv17))) _trgr2 = 0;
if(((int((_gtv14)*(_gtv17)))) > ((_gtv7)*(_gtv17))) _trgr2 = 1;
if (((int((_gtv14)*(_gtv17)))) > ((_gtv17)*(_gtv8))) { if (_trgrt6I) { _trgrt6 = 0;} else {_trgrt6 = 1; _trgrt6I = 1;} } else {_trgrt6 = 0; _trgrt6I = 0;};
if(((int((_gtv17)*(_gtv15)))) < ((_gtv2)*(_gtv17))) _trgr3 = 0;
if(((int((_gtv17)*(_gtv15)))) > ((_gtv6)*(_gtv17))) _trgr3 = 1;
if(((int((_gtv17)*(_gtv15)))) < ((_gtv2)*(_gtv17))) _trgr4 = 0;
if(((int((_gtv17)*(_gtv15)))) > ((_gtv7)*(_gtv17))) _trgr4 = 1;
if (((int((_gtv17)*(_gtv15)))) > ((_gtv17)*(_gtv8))) { if (_trgrt7I) { _trgrt7 = 0;} else {_trgrt7 = 1; _trgrt7I = 1;} } else {_trgrt7 = 0; _trgrt7I = 0;};
_gtv16 = _trgrt6;
_gtv21 = _trgr1;
digitalWrite(12, _trgr1);
digitalWrite(3, _trgr3);
_gtv18 = _trgrt7;
_gtv23 = _trgr3;
_gtv22 = _trgr2;
digitalWrite(4, _trgr2);
digitalWrite(2, _trgr4);
_gtv24 = _trgr4;
if( (_gtv5) || (_gtv3) || (_gtv4) ) _trgr5 = 0;
if( (_gtv16) || (_gtv18) ) _trgr5 = 1;
if (_trgr5)
{
if (! _gen1I)
{
_gen1I = 1;
_gen1O = 1;
_gen1P = millis();
}
}
else
{
_gen1I = 0 ;
_gen1O= 0;
}
if (_gen1I )
{
if ( _isTimer ( _gen1P , 500 ))
{
_gen1P = millis();
_gen1O = ! _gen1O;
}
}
if( (!(_trgr5)) || (_gen1O) ) {if(! _D1B1){_lcd1.backlight(); _D1B1=1; }} else {if(_D1B1){_lcd1.noBacklight(); _D1B1=0; }}
if(_gen1O)
{_swi1=3000;}
else
{_swi1=2500;}
if(_trgr5)
{if((!_pzs1OES) || (_swi1 != _pzs1OFS)){ tone(13, (_swi1)); _pzs1OES =1;_pzs1OFS = _swi1;}} else {if(_pzs1OES){noTone(13); _pzs1OES =0; }}
_gtv20 = _trgr5;
if (1)
{
if (! _gen2I)
{
_gen2I = 1;
_gen2O = 1;
_gen2P = millis();
}
}
else
{
_gen2I = 0 ;
_gen2O= 0;
}
if (_gen2I )
{
if ( _isTimer ( _gen2P , 1000 ))
{
_gen2P = millis();
_gen2O = ! _gen2O;
}
}
if(_gen2O)
{_swi6=String("----");}
else
{_swi6=String("****");}
if (1) {
_dispTempLength1 = ((_swi6)).length();
if (_disp13oldLength > _dispTempLength1) {_isNeedClearDisp1 = 1;}
_disp13oldLength = _dispTempLength1;
_lcd1.setCursor(int((20 - _dispTempLength1)/2), 2);
_lcd1.print((_swi6));
} else {
if (_disp13oldLength > 0) {_isNeedClearDisp1 = 1; _disp13oldLength = 0;}
}
if(_gtv26){ if(!_SEEPR1OSN){ EEPROMWriteInt(0, _gtv6); _SEEPR1OSN=1;} }else{ if(_SEEPR1OSN){_SEEPR1OSN=0;}}
if(_gtv27){ if(!_SEEPR2OSN){ EEPROMWriteInt(2, _gtv7); _SEEPR2OSN=1;} }else{ if(_SEEPR2OSN){_SEEPR2OSN=0;}}
if(_gtv25){ if(!_SEEPR3OSN){ EEPROMWriteInt(4, _gtv2); _SEEPR3OSN=1;} }else{ if(_SEEPR3OSN){_SEEPR3OSN=0;}}
if(_gtv28){ if(!_SEEPR4OSN){ EEPROMWriteInt(6, _gtv8); _SEEPR4OSN=1;} }else{ if(_SEEPR4OSN){_SEEPR4OSN=0;}}
}
bool _isTimer(unsigned long startTime, unsigned long period )
{
unsigned long endTime;
endTime = startTime+period;
return (millis() >= endTime);
}
String _floatToStringWitRaz(float value, int raz)
{
float tv;
int ti = int(value);
String ts = String(ti);
if (raz == 0) {
return ts;
}
ts += ".";
float tf = abs(value - ti);
for (int i = 1; i <= raz; i++ )
{
tv = tf * 10;
ti = int(tv);
ts += String(ti);
tf = (tv - ti);
}
return ts;
}
float _convertDS18x2xData(byte type_s, byte data[12])
{
int16_t raw = (data[1] << 8) | data[0];
if (type_s)
{
raw = raw << 3;
if (data[7] == 0x10) { raw = (raw & 0xFFF0) + 12 - data[6]; }
}
else
{
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw & ~7; else if (cfg == 0x20) raw = raw & ~3; else if (cfg == 0x40) raw = raw & ~1;
}
return (float)raw / 16.0;
}
float _readDS18_ow10(byte addr[8], byte type_s)
{ byte data[12];
byte i;
_ow10.reset();
_ow10.select(addr);
_ow10.write(0xBE);
for ( i = 0; i < 9; i++) {
data[i] = _ow10.read();}
_ow10.reset();
_ow10.select(addr);
_ow10.write(0x44, 1);
return _convertDS18x2xData(type_s, data);}int EEPROMReadInt(int p_address)
{
byte lowByte = EEPROM.read(p_address);
byte highByte = EEPROM.read(p_address + 1);
return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
}
void EEPROMWriteInt(int p_address, int p_value)
{
byte lowByte = ((p_value >> 0) & 0xFF);
byte highByte = ((p_value >> 8) & 0xFF);
EEPROM.write(p_address, lowByte);
EEPROM.write(p_address + 1, highByte);
}
How the system works.
When power is supplied to the controller, the threshold settings for switching on the steps of the cabinet fans and the alarm are subtracted from the EEPROM.
Every 5 seconds, data from the sensors is read and displayed. When the temperature in the cabinet of the first threshold is exceeded, the first fan turns on, the second fan turns on the second, and when the emergency temperature threshold is exceeded, a two-tone audible alarm sounds and the display backlight blinks. Acknowledgment of an alarm occurs when any of the buttons is pressed. When the temperature drops below the fan shutdown setting, both fans stop.
Each time you press the “Menu” button, all settings are displayed in sequence on the display screen. Each setting can be changed using the “Add” and “Decrease” buttons. In this case, the new setpoint value is immediately recorded in the EEPROM.
If within 1 minute you do not perform any actions with the buttons, you go to the main temperature display screen
When you press three buttons at once, all settings are reset to the initial values recorded in the program. This is necessary when starting the controller for the first time, when unpredictable values are in the EEPROM. For example, I had an emergency temperature of 387 degrees, and I would be very tired of knocking it down to 35 degrees by pressing the “Reduce” button.
Starting the system on the table and warming up the sensors with a hairdryer showed the performance of the program.

Sensors were installed and cables laid to the cabinets.




During the trial operation, the following subtlety was found out.
Firstly, in no case should you lay the cables to the sensors together with the cables to the fans. I made this mistake, relying on small fan currents. As a result, from time to time, when the fan stops, the controller freezes. After the cables were spaced apart from each other, these freezes stopped. Perhaps it would also help - applying shielded wires to the sensors, but none were available.

Please do not pay attention to the original display mount, but I thought it was too bold to put the four-line display on a permanent basis, and on the next shift I will replace it with a two-line one.
At the moment, the system has been working for the third week without freezes and failures 24/7.
Now a bit of geek porn. I could not resist and gutted the burnt DHT-22 sensor. Inside, he turned out to be very smart.

