'Domotizzare' casa con Esp-01 e Raspberry Pi Pico W

Prototipo Esp01 e Raspberry per rilevare stato luci e comandarle

In questo articolo presenterò un progetto che mi permetterà di domotizzare casa.

Ho scritto "domotizzare" tra virgolette perché con il temine domotica si intende un concetto molto più ampio.

Cercando domotica su Wikipedia si può leggere che la domotica ha lo scopo di:

  • migliorare la qualità della vita;
  • aumentare la sicurezza];
  • semplificare la progettazione, l'installazione, la manutenzione e l'utilizzo della tecnologia;
  • ridurre i costi di gestione;

Il prototipo che presenterò in questo articolo (per adesso) riuscirà solo ad accendere/spegnere le luci di diversi ambienti tramite app.

Premessa

Tutto ciò che è riportato in questo articolo è un prototipo e pertanto, il progetto in sé come i vari componenti non hanno le certificazioni necessarie per essere installati su un impianto domestico. Ricordo inoltre che modificare il proprio impianto elettrico invalida la certificazione dello stesso.

Concludo la premessa sconsigliando di modificare il proprio impianto e sottolineando che il presente ha solo scopo didattico.

Descrizione del progetto

Il sistema si compone di Raspberry Pi Pico W e diversi device.

Il Raspberry Pi Pico W ha la funzione di server e ha il compito di gestire i device

I device sono molto semplici e sono composti da un alimentatore da circuito stampato da 3.3V che alimenta un Esp-01

Server e devices, entrambi connessi a internet, comunicano tra di loro tramite messaggi MQTT.

Requisiti

I requisito principale è voler leggere lo stato dei punti luce nelle diverse camere e comandarli.

Il vincolo principale (che di fatto è un altro requisito) è che tutto deve continuare a funzionare se server o devices smettono di funzionare.

Il secondo vincolo è che non voglio cambiare assolutamente nulla all'impianto esistente.

Terzo vincolo è che il sistema non deve gestire nulla che sia a 220 volt.

L'impianto elettrico esistente

Nell'attuale impianto elettrico, le luci, vengono comandate in due modi:

  1. Tramite tasto che attiva un relè passo passo
  2. Tramite interruttore che attiva un classico relè aperto/chiuso

Il relè passo passo ha una ruota dentata e ogni volta che viene eccitato (per un tempo brevissimo) la ruota compie una parziale rotazione causando un'apertura del contatto se era chiuso oppure una chiusura del contatto se era aperto.

Il classico relè invece causa una chiusura del contatto quando è eccitato e un'apertura quando non è eccitato. Ovviamente quando è eccitato consuma corrente perché l'elettromagnete al suo interno deve essere alimentato.

Principio di funzionamento

Prima di capire come comandare le luci è fondamentale rilevare lo stato attuale della luce.

Rilevazione dello stato

Prendiamo in esame il caso del punto luce comandato dal relè classico. In questo caso è molto semplice capire lo stato della lampada che pilota perché la lampada è accesa se la bobina è alimentata. Una soluzione banale è collegare una luce alla bobina (a 220v o 12v a seconda della tensione che arriva alla bobina), metterla in un tubicino di gomma nero e dall'altro lato del tubo (per esempio) una fotoresistenza. Si possono utilizzare anche dei diodi ricevitore e trasmettitore ad infrarosso. 

Il caso del relè passo passo invece è più complesso perché la bobina viene eccitata per un breve periodo ma lo stato dipende dallo stato precedente. Quindi l'unico modo per capire se la lampada è accesa o meno è rilevare la tensione ai capi della lampada stessa.

La soluzione che ho pensato utilizza un alimentatore da circuito stampato e un Esp01. Praticamente l'ESP-01 pubblica un messaggio MQTT indicando il suo nome quando viene alimentato. La sua alimentazione è collegata alla lampada che il relè passo passo gestisce. L'unico inconveniente di questa soluzione è che quando la lampada viene accesa e l'ESp-01 viene alimentato è necessario qualche secondo affinché l'ESp-01 si connetta alla rete e pubblichi il messaggio MQTT.

Il device pubblica un messaggio ogni 2 secondi circa. Il server (Rpi Pico W) se non rileva messaggi per più di 5 secondi contrassegna il punto luce come "spento".

Accensione e spegnimento della lampada

Le modalità di accensione e spegnimento della lampada dipendono dalla presenza del relè classico o del relè passo passo.

Per la casistica con relè passo passo è necessario eccitare la bobina per 200 millisecondi.

Per la casistica con classico relè o semplice deviatore ho deciso di utilizzare dei relè deviatori da mettere in "serie" ai commutatori simulando un altro punto luce (commutatore).

Il device

Come accennato, il device è composto da un Esp-01 e da un alimentatore da circuito stampato da 3.3v stabilizzati.

Potrebbe essere utile un condensatore elettrolitico, ma dalle prove che ho fatto non è necessario.

Lo schema è il seguente:

Il codice davvero semplice e si commenta da solo.

Dopo la connessione alla rete WiFi casalinga si connette al broker MQTT e inizia a inviare messaggi con un json basilare.

Il device di fatto può essere esteso integrando altri sensori come un sensore si temperatura o di corrente (per monitorare i consumi).

#ifdef ESP8266
 #include <ESP8266WiFi.h>
 #else
 #include <WiFi.h>
#endif

#include <ArduinoJson.h>
#include <PubSubClient.h>
#include <WiFiClientSecure.h>

#define MY_BLUE_LED_PIN 1

/****** WiFi Connection Details *******/
const char* ssid = "<NOME RETE>";
const char* password = "<PASSWORD RETE>";

/******* MQTT Broker Connection Details *******/
const char* mqtt_server = "1XXXXXXX5.s2.eu.hivemq.cloud";
const char* mqtt_username = "gimqtttest1";
const char* mqtt_password = "<PASSWORD>";
const int mqtt_port =8883;

const char* deviceId = "Camera1";
const char* mqtt_publicsherTopic = "DeviceCamera1";

/****** root certificate *********/

static const char *root_ca PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
)EOF";

WiFiClientSecure espClient;
PubSubClient client(espClient);

unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];

/************* Connect to WiFi ***********/
void setup_wifi() {
  delay(10);
  Serial.print("\nConnecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("\nWiFi connected\nIP address: ");
  Serial.println(WiFi.localIP());
}

/************* Connect to MQTT Broker ***********/
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    String clientId = "ESP8266Client-";   // Create a random client ID
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {
      Serial.println("connected");
    } else {      
      Serial.println("failed try again in 5 seconds");   
      delay(5000);
    }
  }
}
/**** Method for Publishing MQTT Messages **********/
void publishMessage(const char* topic, String payload , boolean retained){
  if (client.publish(topic, payload.c_str(), true))
      Serial.println("Message publised ["+String(topic)+"]: "+payload);
}

void setup() {
  pinMode(MY_BLUE_LED_PIN, OUTPUT); //set up LED
  Serial.begin(9600);
  while (!Serial) delay(1);
  setup_wifi();

  #ifdef ESP8266
    espClient.setInsecure();
  #else
    espClient.setCACert(root_ca);      // enable this line and the the "certificate" code for secure connection
  #endif

  client.setServer(mqtt_server, mqtt_port);
}

void loop() {
  if (!client.connected()) reconnect(); // check if client is connected
    client.loop();

  delay(100);  

  DynamicJsonDocument doc(1024);

  doc["deviceId"] = deviceId;
  doc["status"] = 1;
  char mqtt_message[128];
  serializeJson(doc, mqtt_message);
  publishMessage(mqtt_publicsherTopic, mqtt_message, true);
  delay(2000);
}

Il server

Il server è leggermente più complesso perchè deve "capire" i device connessi e stabilire se uno o più device sono disconnessi.

Posterò schema e codice tra qualche giorno