#include "DHT.h" #include #include #include "config.h" #include "LittleFS.h" // network IPAddress my_ip(MY_IP); IPAddress gateway(MY_GW); IPAddress subnet(MY_NET); IPAddress sensor_ip(SENSOR_IP); // After how much time without connection we will // reboot (in millis) #define NON_CONNECTED_REBOOT_TIMEOUT 60000 // dht sensor #define DHTPIN D6 #define DHTTYPE AM2301 DHT dht(DHTPIN, DHTTYPE); #define DHT_UPDATE_INTERVAL 500 // relay #define RELAY_PIN D1 #define T_UPDATE_INTERVAL 500 // external t #define EXTERNAL_UPDATE_INTERVAL 1000 // logic consts // deviation from target t allowed (in degrees multiplied by 100) #define T_HYSTERESIS 150 // timeout to switch from external to internal temperature data (in milliseconds) #define SWITCH_TO_INTERNAL_TIMEOUT 50000 // modbus consts and works #define TCP_PORT 15000 #define MODE_AUTO 0 #define MODE_MANUAL 1 #define REGISTER_MODE 0 #define REGISTER_CUR_STATE 1 #define REGISTER_RELAY_TEMP 2 #define REGISTER_OVERHEAT 3 #define REGISTER_OVERRIDE_STATE 4 // desired temperature #define REGISTER_TARGET_T 5 // temperature from internal sensor #define REGISTER_INTERNAL_T 6 // temperatur from external sensor (received via modbus-tcp) #define REGISTER_EXTERNAL_T 7 // critical relay temp (degrees multiplied by 100) #define CRITICAL_T 6000 ModbusIP mb; char id[64]; int cur_mode = MODE_AUTO; int cur_state = 0; int relay_t = 0; int overheat = 0; int override_state = 0; int target_t = 0; int internal_t = 0; int external_t = 0; void LoadState() { File f = LittleFS.open("/target_t.txt", "r"); if (!f) return; String s = f.readStringUntil('\n'); target_t = atoi(s.c_str()); f.close(); } void SaveState() { File f = LittleFS.open("/target_t.txt", "w"); if (!f) return; f.println(target_t); f.close(); } void setup() { if (!LittleFS.begin()) { Serial.println("Unable to mount the filesystem"); ESP.restart(); } LoadState(); pinMode(DHTPIN, INPUT); pinMode(RELAY_PIN, OUTPUT); dht.begin(); Serial.begin(115200); Serial.println("Initialised..."); WiFi.mode(WIFI_STA); WiFi.config(my_ip, gateway, subnet); WiFi.setAutoReconnect(true); WiFi.begin(WIFI_NAME, WIFI_PASS); Serial.print("Connecting"); unsigned long start = millis(); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); if (millis() - start > NON_CONNECTED_REBOOT_TIMEOUT) { ESP.restart(); } } Serial.println(); Serial.print("Connected, IP address: "); Serial.println(WiFi.localIP()); uint8_t macAddr[6]; WiFi.macAddress(macAddr); sprintf(id, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]); Serial.printf("Connected, mac address: %s\n", id); mb.server(15000); mb.addHreg(REGISTER_MODE, cur_mode); mb.addHreg(REGISTER_CUR_STATE, cur_state); mb.addHreg(REGISTER_RELAY_TEMP, relay_t); mb.addHreg(REGISTER_OVERHEAT, overheat); mb.addHreg(REGISTER_OVERRIDE_STATE, override_state); mb.addHreg(REGISTER_TARGET_T, target_t); mb.addHreg(REGISTER_INTERNAL_T, internal_t); mb.addHreg(REGISTER_EXTERNAL_T, external_t); } ////////////////////////////////////////////////////////////////// // thermistor (relay temperature) ////////////////////////////////////////////////////////////////// #define THERMISTORPIN A0 #define THERMISTORNOMINAL 10000 #define TEMPERATURENOMINAL 25 #define NUMSAMPLES 5 #define BCOEFFICIENT 3950 #define SERIESRESISTOR 10000 unsigned long last_relay_update = 0; void UpdateRelayT() { float average = 0; for (int i = 0; i < NUMSAMPLES; i++) { average += analogRead(THERMISTORPIN); delay(10); } average /= NUMSAMPLES; average = 1023 / average - 1; average = SERIESRESISTOR / average; float steinhart; steinhart = average / THERMISTORNOMINAL; // (R/Ro) steinhart = log(steinhart); // ln(R/Ro) steinhart /= BCOEFFICIENT; // 1/B * ln(R/Ro) steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To) steinhart = 1.0 / steinhart; // инвертируем steinhart -= 273.15; // конвертируем в градусы по Цельсию relay_t = int(steinhart * 100); last_relay_update = millis(); } //////////////////////////////////////////////////////////////////////// // DHT (internal thermo sensor) //////////////////////////////////////////////////////////////////////// unsigned long last_dht_update = 0; void UpdateDHT() { float t = dht.readTemperature(); internal_t = (int)(t * 100); last_dht_update = millis(); } //////////////////////////////////////////////////////////////////////// // Modbus client (external sensor t) //////////////////////////////////////////////////////////////////////// #define ANSWER_READ_TIMEOUT 1000 unsigned long last_external_update = 0; bool was_external_update = false; WiFiClient client; #define SENSOR_T_REGISTER 0 uint8_t mb_message[50]; uint8_t mb_answer[50]; int mb_answer_len; void UpdateExternalT() { if (!client.connect(sensor_ip, SENSOR_PORT)) { Serial.println("Unable to connect to sensor"); return; } mb_message[0] = 0; // transaction id mb_message[1] = 0; mb_message[2] = 0; // protocol id mb_message[3] = 0; mb_message[4] = 0; // length mb_message[5] = 6; mb_message[6] = 0; // unit id mb_message[7] = 3; // function mb_message[8] = (SENSOR_T_REGISTER >> 8) & 0xFF; // address - high mb_message[9] = (SENSOR_T_REGISTER) & 0xFF; // address - low mb_message[10] = 0; // amount mb_message[11] = 1; client.write(mb_message, 12); client.flush(); // read answer (it should be 8 (header) + 1 (amount received bytes) + 2 (actual data) mb_answer_len = 0; unsigned long start = millis(); while (millis() - start < ANSWER_READ_TIMEOUT && mb_answer_len < 11) { int result = client.read(); if (result != -1) { mb_answer[mb_answer_len++] = result; } } if (mb_answer_len < 11) { Serial.println("Too short answer from sensor"); return; } external_t = (((int)mb_answer[9]) << 8) | ((int)mb_answer[10]); last_external_update = millis(); was_external_update = true; } //////////////////////////////////////////////////////////////////////// int GetCurrentT() { unsigned long current = millis(); // case when we did not receive external T since device boot if (!was_external_update) return internal_t; if (current < last_external_update || current - last_external_update < SWITCH_TO_INTERNAL_TIMEOUT) { return external_t; } return internal_t; } unsigned long last_connected = 0; void loop() { unsigned long current = millis(); int u = 0; if (current < last_relay_update || current - last_relay_update >= T_UPDATE_INTERVAL) { UpdateRelayT(); u = 1; } if (current < last_dht_update || current - last_dht_update >= DHT_UPDATE_INTERVAL) { UpdateDHT(); u = 1; } if (current < last_external_update || current - last_external_update >= EXTERNAL_UPDATE_INTERVAL) { UpdateExternalT(); u = 1; } mb.task(); cur_mode = mb.Hreg(REGISTER_MODE); override_state = mb.Hreg(REGISTER_OVERRIDE_STATE); target_t = mb.Hreg(REGISTER_TARGET_T); int current_t = GetCurrentT(); if (cur_mode == MODE_AUTO) { if (current_t < target_t - T_HYSTERESIS) { cur_state = 1; } else if (current_t > target_t + T_HYSTERESIS) { cur_state = 0; } } else { cur_state = override_state; } if (relay_t > CRITICAL_T) { //Serial.printf("Critical overheat, t = %d\n", relay_t); cur_state = 0; overheat = 1; } else overheat = 0; digitalWrite(RELAY_PIN, cur_state); if (u) { Serial.printf("State %d Relay t %d Internal t %d External t %d Current t %d Target t %d\n", cur_state, relay_t, internal_t, external_t, current_t, target_t); SaveState(); } mb.Hreg(REGISTER_MODE, cur_mode); mb.Hreg(REGISTER_RELAY_TEMP, relay_t); mb.Hreg(REGISTER_OVERHEAT, overheat); mb.Hreg(REGISTER_CUR_STATE, cur_state); mb.Hreg(REGISTER_INTERNAL_T, internal_t); mb.Hreg(REGISTER_EXTERNAL_T, external_t); if (WiFi.status() != WL_CONNECTED) { WiFi.reconnect(); } else { last_connected = current; } if (current < last_connected || current - last_connected > NON_CONNECTED_REBOOT_TIMEOUT) { SaveState(); ESP.restart(); } }