Il mio termostato

Progetto Termostato

Il controller usato:
Arduino nano

Piedinatura Arduino

I sensori usati:

DHT11: il sensore di temperatura e umidità

Sensore DHT11

Il relè:

KY-019 Funziona bene

Relè difettoso

Il display:
Display OLED I2C SSH1106

Display OLED

Il potenziometro: EC11

Encoder 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() );
}
 

Commenti

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *