
Il controller usato:
Arduino nano

I sensori usati:
DHT11: il sensore di temperatura e umidità

Il relè:
KY-019 Funziona bene
Il display:
Display OLED I2C SSH1106

Il potenziometro: EC11

Lo Sketch (Versione 11.9.1):
#include <U8g2lib.h>
#include <Wire.h>
// --- LIBRERIE NECESSARIE ---
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <Encoder.h>
// **********************************************
// DICHIARAZIONE DEI PROTOTIPI
// **********************************************
void displayStatus(String status, int interventi);
void readSensorData();
// **********************************************
// CONFIGURAZIONE PIN
// **********************************************
#define PIN_RELE 7
#define DHTPIN 8
#define DHTTYPE DHT11
#define ENCODER_CLK_PIN 2
#define ENCODER_DT_PIN 3
#define ENCODER_SW_PIN 4
// Inizializzazione degli oggetti
DHT dht(DHTPIN, DHTTYPE);
U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, A5, A4);
Encoder myEncoder(ENCODER_CLK_PIN, ENCODER_DT_PIN);
// **********************************************
// VARIABILI GLOBALI E LOGICA
// **********************************************
bool isHeating = false;
int conteggioInterventi = 0;
float currentTemperature = 21.0;
float currentHumidity = 0.0;
float setpoint_target = 5.0; // Partenza sicura a 5 gradi
const float MIN_TEMP = 5.0;
const float MAX_TEMP = 20.0;
const float STEP_TEMP = 0.25;
// NUOVA ISTERESI: 1 grado di distacco dal Target per la riaccensione
const float HYSTERESIS = 1.0;
int lastButtonState = HIGH;
long oldPosition = -999;
const unsigned long INTERVALLO_LETTURA = 1000;
unsigned long ultimoLetturaMillis = 0;
// **********************************************
// SETUP
// **********************************************
void setup() {
Serial.begin(9600);
Serial.println("--- Termostato v11.9.1: Pronto! ---");
pinMode(PIN_RELE, OUTPUT);
digitalWrite(PIN_RELE, LOW);
isHeating = false;
pinMode(ENCODER_SW_PIN, INPUT_PULLUP);
u8g2.begin();
u8g2.setFont(u8g2_font_6x10_tf);
dht.begin();
// Sincronizza encoder con il setpoint iniziale
myEncoder.write(setpoint_target * (1 / STEP_TEMP));
ultimoLetturaMillis = millis();
readSensorData();
}
// **********************************************
// LOOP PRINCIPALE
// **********************************************
void loop() {
unsigned long currentMillis = millis();
// --- GESTIONE ENCODER (SETPOINT) ---
long newPosition = myEncoder.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
float newSetpoint = newPosition * STEP_TEMP;
if (newSetpoint < MIN_TEMP) {
newSetpoint = MIN_TEMP;
myEncoder.write(newSetpoint * (1 / STEP_TEMP));
} else if (newSetpoint > MAX_TEMP) {
newSetpoint = MAX_TEMP;
myEncoder.write(newSetpoint * (1 / STEP_TEMP));
}
setpoint_target = newSetpoint;
}
// --- LOGICA DI CONTROLLO (OGNI 1 SECONDO) ---
if (currentMillis - ultimoLetturaMillis >= INTERVALLO_LETTURA) {
ultimoLetturaMillis = currentMillis;
readSensorData();
// NUOVA LOGICA: Il Setpoint è il tetto massimo
// 1. Accensione: se la temperatura scende sotto (Target - 1.0)
if (!isHeating && currentTemperature <= (setpoint_target - HYSTERESIS)) {
isHeating = true;
conteggioInterventi++;
Serial.println("Caldaia: ON (Sotto soglia minima)");
}
// 2. Spegnimento: se la temperatura raggiunge il Target
else if (isHeating && currentTemperature >= setpoint_target) {
isHeating = false;
Serial.println("Caldaia: OFF (Target raggiunto)");
}
// --- LOGICA OSTINATA ANTI-DISTURBO ---
// Mantiene la tensione sul pin costante senza far scattare il relè
if (isHeating) {
digitalWrite(PIN_RELE, HIGH);
} else {
digitalWrite(PIN_RELE, LOW);
}
displayStatus(isHeating ? "ON" : "OFF", conteggioInterventi);
}
}
// **********************************************
// FUNZIONI DI SERVIZIO
// **********************************************
void readSensorData() {
float h = dht.readHumidity();
float t = dht.readTemperature();
if (!isnan(h) && !isnan(t)) {
currentHumidity = h;
currentTemperature = t;
}
Serial.print("T: "); Serial.print(currentTemperature, 1);
Serial.print(" | Ts: "); Serial.println(setpoint_target, 1);
}
void displayStatus(String status, int interventi) {
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_6x10_tf);
// Riga 1: Temp Attuale e Umidità
u8g2.drawStr(0, 10, ("Ta: " + String(currentTemperature, 1) + " C").c_str());
u8g2.drawStr(80, 10, ("H: " + String(currentHumidity, 0) + " %").c_str());
// Riga 2: Setpoint Target
u8g2.drawStr(0, 25, ("Ts: " + String(setpoint_target, 1) + " C").c_str());
// Riga 3: Stato Caldaia
u8g2.drawStr(0, 40, "CALDAIA:");
u8g2.drawStr(80, 40, status.c_str());
// Riga 4: Contatore
u8g2.drawStr(0, 55, "N Int:");
char buffer[4];
sprintf(buffer, "%03d", interventi);
u8g2.drawStr(40, 55, buffer);
} while ( u8g2.nextPage() );
}
Lascia un commento