#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
// --- CONFIGURAZIONE ---
LiquidCrystal_I2C lcd(0x27, 16, 2);
OneWire oneWire(2);
DallasTemperature sensors(&oneWire);
const int PIN_UP = A3;
const int PIN_DOWN = A2;
const int PIN_SET = 12;
const unsigned long TIMEOUT_MENU = 20000;
// --- VARIABILI GLOBALI ---
float setpoints[] = { 20.0, 20.0, 20.0, 20.0, 20.0 };
float temperature[] = { 20.0, 20.0, 20.0, 20.0, 20.0 };
String nomiZone[] = { "SALONE", "BAGNI", "CAMERA", "CORRIDOIO", "STUDIO" };
int mappaRele[5][3] = {
{0, 1, 3}, {4, -1, -1}, {5, 6, -1}, {7, -1, -1}, {8, -1, -1}
};
unsigned long ultimoCambioStato[5];
bool statoAttualeRele[5] = {false, false, false, false, false};
int modoZona[5] = {0, 0, 0, 0, 0};
bool modalitaSpurgo = false;
int zonaSelezionata = 0;
int statoMenu = 0;
unsigned long ultimoCambioDisplay = 0;
unsigned long ultimaAzioneUtente = 0;
void salvaDati() {
for (int i = 0; i < 5; i++) {
EEPROM.put(10 + (i * sizeof(float)), setpoints[i]);
EEPROM.write(100 + i, modoZona[i]);
}
lcd.clear(); lcd.print(" DATI SALVATI! "); delay(1000); lcd.clear();
}
void caricaDati() {
for (int i = 0; i < 5; i++) {
float v; EEPROM.get(10 + (i * sizeof(float)), v);
if (v > 5 && v < 35) setpoints[i] = v;
byte m = EEPROM.read(100 + i);
if (m == 0 || m == 1) modoZona[i] = m;
}
}
void setup() {
lcd.init(); lcd.backlight();
lcd.setCursor(0,0); lcd.print(" RADIANTE A ");
lcd.setCursor(0,1); lcd.print(" SOFFITTO ");
delay(2000); lcd.clear();
lcd.setCursor(0,0); lcd.print(" IDEATO E BY ");
lcd.setCursor(0,1); lcd.print(" RuSte... ");
delay(2500); lcd.clear();
sensors.begin();
caricaDati();
pinMode(PIN_UP, INPUT_PULLUP); pinMode(PIN_DOWN, INPUT_PULLUP); pinMode(PIN_SET, INPUT_PULLUP);
for (int i = 0; i < 5; i++) {
ultimoCambioStato[i] = millis() - 301000;
for (int j = 0; j < 3; j++) {
if (mappaRele[i][j] != -1) {
pinMode(mappaRele[i][j], OUTPUT);
digitalWrite(mappaRele[i][j], LOW);
}
}
}
}
void loop() {
sensors.requestTemperatures();
for (int i = 0; i < 5; i++) {
float t = sensors.getTempCByIndex(i);
if (t > -50) temperature[i] = t;
}
if (statoMenu != 0 && (millis() - ultimaAzioneUtente > TIMEOUT_MENU)) {
if (statoMenu != 3) salvaDati();
statoMenu = 0;
}
if (statoMenu == 0) {
if (millis() - ultimoCambioDisplay > 2000) {
zonaSelezionata = (zonaSelezionata + 1) % 5;
ultimoCambioDisplay = millis();
lcd.clear();
}
}
if (digitalRead(PIN_SET) == LOW) {
unsigned long tInizio = millis();
while(digitalRead(PIN_SET) == LOW);
unsigned long durata = millis() - tInizio;
ultimaAzioneUtente = millis();
ultimoCambioDisplay = millis();
if (statoMenu == 0) {
if (durata > 5000) statoMenu = 3;
else statoMenu = 1;
}
else if (statoMenu == 1) statoMenu = 2;
else if (statoMenu == 2) { salvaDati(); statoMenu = 0; }
else if (statoMenu == 3) { statoMenu = 0; lcd.clear(); lcd.print("MODALITA USCITA"); delay(1000); }
lcd.clear();
}
if (digitalRead(PIN_UP) == LOW || digitalRead(PIN_DOWN) == LOW) {
bool up = (digitalRead(PIN_UP) == LOW);
delay(200);
ultimaAzioneUtente = millis();
ultimoCambioDisplay = millis();
if (statoMenu == 0) {
if (up) zonaSelezionata = (zonaSelezionata + 1) % 5;
else zonaSelezionata = (zonaSelezionata == 0) ? 4 : zonaSelezionata - 1;
}
else if (statoMenu == 1) setpoints[zonaSelezionata] += (up ? 0.5 : -0.5);
else if (statoMenu == 2) modoZona[zonaSelezionata] = (modoZona[zonaSelezionata] == 0) ? 1 : 0;
else if (statoMenu == 3) modalitaSpurgo = !modalitaSpurgo;
lcd.clear();
}
lcd.setCursor(0, 0);
if (statoMenu < 3) {
lcd.print(nomiZone[zonaSelezionata]);
if (statoMenu == 1) {
lcd.print(" >SET<");
lcd.setCursor(0, 1); lcd.print("VALORE: "); lcd.print(setpoints[zonaSelezionata], 1); lcd.print(" C");
} else if (statoMenu == 2) {
lcd.print(" >MODO<");
lcd.setCursor(0, 1); lcd.print(modoZona[zonaSelezionata] == 1 ? ">> MANUALE <<" : ">> AUTOMATICO <<");
} else {
lcd.print(modoZona[zonaSelezionata] == 1 ? " [M]" : " [A]");
if (modalitaSpurgo) lcd.print(" !SP!");
lcd.setCursor(0, 1);
lcd.print("T:"); lcd.print(temperature[zonaSelezionata], 1);
lcd.print(" S:"); lcd.print(setpoints[zonaSelezionata], 1);
lcd.print(statoAttualeRele[zonaSelezionata] ? " ON" : " OFF");
}
} else {
lcd.print("FUNZIONE SPURGO:");
lcd.setCursor(0, 1);
lcd.print(modalitaSpurgo ? ">> ATTIVA <<" : ">> DISATTIVA <<");
}
int idMin = -1; float tMin = 100.0;
for (int i = 0; i < 5; i++) {
if (modoZona[i] == 0 && temperature[i] < (setpoints[i] - 0.5)) {
if (temperature[i] < tMin) { tMin = temperature[i]; idMin = i; }
}
}
for (int i = 0; i < 5; i++) {
bool on = false;
if (modalitaSpurgo || modoZona[i] == 1) on = true;
else if (idMin != -1 && temperature[i] < (setpoints[i] - 0.5)) {
if (i == idMin || tMin >= (temperature[i] - 0.5)) on = true;
}
if (on != statoAttualeRele[i]) {
// BYPASS TIMER: Se siamo in Spurgo o Manuale, onBypass diventa vero
bool onBypass = (modalitaSpurgo || modoZona[i] == 1);
if (onBypass || (millis() - ultimoCambioStato[i] >= 300000)) {
statoAttualeRele[i] = on;
ultimoCambioStato[i] = millis();
for (int j = 0; j < 3; j++) {
if (mappaRele[i][j] != -1) digitalWrite(mappaRele[i][j], on ? HIGH : LOW);
}
}
}
}
}