Files
hotwater/hotwater.ino
T
2026-01-14 22:04:16 +03:00

189 lines
3.9 KiB
Arduino

#include <OneWire.h>
#include <DallasTemperature.h>
#include <ESP8266WiFi.h>
#include <ModbusIP_ESP8266.h>
#include "config.h"
#include "LittleFS.h"
#include <LiquidCrystal_I2C.h>
// Display
#define LCD_COLUMNS 16
#define LCD_ROWS 2
#define LCD_ADDRESS 0x27
#define RELAY_PIN D3
#define TEMP_SENSOR_PIN D5
// network
// After how much time without connection we will
// reboot (in millis)
#define NON_CONNECTED_REBOOT_TIMEOUT 60000
#define RECONNECT_TIMEOUT 10000
IPAddress my_ip(MY_IP);
IPAddress gateway(MY_GW);
IPAddress subnet(MY_NET);
// modbus consts and works
#define TCP_PORT 15000
#define T_UPDATE_INTERVAL 1000
#define REGISTER_TARGET_T 0
#define REGISTER_HYSTERESIS 1
#define REGISTER_CUR_TEMP 2
#define REGISTER_CUR_STATE 3
ModbusIP mb;
OneWire oneWire(TEMP_SENSOR_PIN);
DallasTemperature sensor(&oneWire);
LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLUMNS, LCD_ROWS);
long last_poll;
long last_update;
int t_target = 7000;
int hyst = 200;
int cur_t = 0;
int cur_state = 0;
bool TryLoad(char *filename)
{
File f = LittleFS.open(filename, "r");
if (!f) return false;
String s = f.readStringUntil('\n');
t_target = atoi(s.c_str());
s = f.readStringUntil('\n');
hyst = atoi(s.c_str());
f.close();
if (t_target == 0) return false;
return true;
}
void LoadState()
{
if (TryLoad("/settings.txt")) return;
TryLoad("/settings.txt.bak");
}
void SaveTo(char *filename)
{
File f = LittleFS.open(filename, "w");
if (!f) return;
f.println(t_target);
f.println(hyst);
f.close();
}
void SaveState()
{
SaveTo("/settings.txt");
SaveTo("/settings.txt.bak");
}
void setup()
{
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
if (!LittleFS.begin())
{
Serial.println("Unable to mount the filesystem");
lcd.print("ERR: FS");
ESP.restart();
}
LoadState();
pinMode(RELAY_PIN, OUTPUT);
pinMode(TEMP_SENSOR_PIN, INPUT);
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");
lcd.print("Connecting...");
delay(500);
Serial.println();
last_poll = millis();
mb.server(15000);
mb.addHreg(REGISTER_TARGET_T, t_target);
mb.addHreg(REGISTER_HYSTERESIS, hyst);
mb.addHreg(REGISTER_CUR_TEMP, cur_t);
mb.addHreg(REGISTER_CUR_STATE, cur_state);
//
sensor.begin();
sensor.setResolution(12);
}
void UpdateCurrent()
{
sensor.requestTemperatures();
cur_t = int(sensor.getTempCByIndex(0) * 100);
last_update = millis();
}
unsigned long last_connected = 0;
unsigned long last_connecting = 0;
void loop()
{
unsigned long current = millis();
int u = 0;
if (current < last_update || current - last_update >= T_UPDATE_INTERVAL)
{
UpdateCurrent();
u = 1;
}
mb.task();
t_target = mb.Hreg(REGISTER_TARGET_T);
hyst = mb.Hreg(REGISTER_HYSTERESIS);
if (cur_t < t_target - hyst) cur_state = 1;
else if (cur_t > t_target + hyst) cur_state = 0;
mb.Hreg(REGISTER_CUR_STATE, cur_state);
digitalWrite(RELAY_PIN, cur_state);
if (u)
{
SaveState();
Serial.println("Cur state");
Serial.println(cur_state);
Serial.println(cur_t);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("T: ");
lcd.print((cur_t) / 100.0, 2);
lcd.print(" (");
lcd.print(t_target / 100);
lcd.print(")");
lcd.setCursor(0, 1);
lcd.print("S: ");
lcd.print(cur_state);
lcd.print("WiFi: ");
lcd.print(WiFi.status());
}
mb.Hreg(REGISTER_TARGET_T, t_target);
mb.Hreg(REGISTER_HYSTERESIS, hyst);
mb.Hreg(REGISTER_CUR_TEMP, cur_t);
mb.Hreg(REGISTER_CUR_STATE, cur_state);
if (WiFi.status() != WL_CONNECTED)
{
if (current < last_connecting || current - last_connecting > RECONNECT_TIMEOUT)
{
WiFi.reconnect();
last_connecting = current;
}
}
else
{
last_connected = current;
}
if (current < last_connected || current - last_connected > NON_CONNECTED_REBOOT_TIMEOUT)
{
SaveState();
ESP.restart();
}
}