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

Prototipo Shelly, Esp01 e Raspberry per casa "domotica"

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 2 e diversi device.

Sul Raspberry Pi 2 ho installato Windows 10 Core IOT. Questo sarà l'HUB del sistema, il broker MQTT e ha il compito di interfacciare i device con tutto ciò che è all'esterno della mia rete.

I device sono di diversi tipi:

  • Autocostruiti con Esp 01
  • Shelly 1v3 - che hanno la funzione di Switch

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

Inizialmente, prima di utilizzare gli Shelly, i device con ESP01 avevano il compito di leggere lo stato dei punti luce nelle diverse camere e comandarli.

Tutti i devices non sono connessi a internet, ma comunicano tra di loro tramite messaggi MQTT.

Requisiti

Il requisito principale è che tutto deve continuare a funzionare anche senza rete e/o connessione a internet.

Il secondo requisito è che l'installazione deve essere poco invasiva.

L'impianto elettrico esistente

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

  1. Tramite singolo interruttore che accende e spegne la lampada
  2. Tramite interruttore che attiva un classico relè aperto/chiuso
  3. Tramite tasto che attiva un relè passo passo

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.

Primo caso - Singolo punto luce con interruttore

L'automazione in questo caso avverrà tramite uno Shelly (1V3 per la precisione).

Ho scoperto Shelly da poco e ho acquistato qualche device per fare degli esperimenti e di conseguenza poter valutarli. Magari farò un articolo ad hoc. Per il momento posso affermare che è un ottimo prodotto e abbastanza flessibile per quelle che sono le mie esigenze.

L'unico svantaggio che ho rilevato e ancora non so come aggirare è che il broker MQTT deve essere su http o locale. Di fatto sono riuscito a impostare come broker quello pubblico di HiveMQ "broker.hivemq.com:1883", ma vorrei impostare come broker uno dei miei cluster (cloud) creati in HiveMQ e che hanno indirizzi del tipo 1XXXXXXXX61.s2.eu.hivemq.cloud

In realtà la cosa mi da parecchio fastidio perchè essendo il broker pubblico (a meno che non voglia tenerne uno in casa), chiunque potrebbe comandare il mio e tutti gli altri Shelly connessi allo stesso broker MQTT inviando un comando "on" al topic "shellies/command".

Certo, potrei crearmi un broker locale con un Raspberry o un mini pc, ma vorrei tenere bassi i consumi di corrente e al momento non ho trovato il modo di costruire un broker MQTT con un Raspberry Pi Pico. 

Oltre a MQTT, lo Shelly 1v3 espone dei servizi REST che possono essere utilizzati per comandare la lampada. In particolare sono da menzionare i seguenti endpoints:

http:/ /192.168.99.171/status
http:/ /192.168.99.171/relay/0?turn=on
http:/ /192.168.99.171/relay/0?turn=off

Schema collegamento Shelly 1v3 (Shelly, interruttore/pulsanti e lampada)

Gli schemi proposti sul sito di Shelly Italia sono i seguenti:

Shelly 1v3 - Collegamento lampada e interruttore

Caso Shelly 1v3, singolo punto luce (interruttore) e lampada

Shelly 1v3 - Collegamento lampada e pulsanti

Caso Shelly 1v3, multipli punti luce (pulsanti) e lampada

La soluzione a singolo punto luce con interruttore la escludo perchè se "spengo" lo Shelly tramite timer, app, api o MQTT ma l'avevo acceso tramite l'interruttore  avrei la spiacevole situazione di ritrovarmi con lo stato del'interruttore inconsistente con lo stato della lampada.

Schema a blocchi

Lo schema completo è il seguente:

Schema completo

Lo Shelly ha il compito di gestire la lampada connessa ad esso e comunica con l'hub tramite richieste MQTT (locale).

In caso di assenza di rete o dell'hub il funzionamento è garantito poichè i pulsanti sono direttamente connessi allo Shelly.

L'hub ha il compito di creare un broker MQTT (locale) e gestire in sicurezza le connessioni con tutto ciò che è fuori dalla mia rete.

Il broker locale è utilizzato dai device mentre per le connessioni tramite l'esterno viene utilizzato un broker cloud di HiveMQ.

Ho costruito l'hub utilizzando un Raspberry Pi con Windows IOT Core e una universal App. Ho connesso via HDMI un piccolo display da 3'5 pollici per diagnostica, ma successivamente potrei creare una UI adatta per il televisore e quindi avere una dashboard con misuratore di consumi, lampade accese e sensoristica varia anche sulla mia TV.

Questo schema richiede un po di configurazione dello Shelly. Nel dettaglio:

  • Annotare l'ip dell'HUB (è possibile settare un ip statico). 
  • Shelly - Settare in Internet & Security -> MQTT l'indirizzo e eventuali credenziali per la connessione al broker locale

ESP01 - Principio di funzionamento

Così come gli Shelly, anche gli ESP 01 comunicano con l'HUB tramite MQTT Locale.

Quando un dispositivo si connette alla rete invia un messaggio di "Announcement".

Ogni 30 secondi invia il suo stato. 

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 sembra non essere necessario.

Dispositivo fisico - ESP01 e alimentatore da 220 volts

Lo schema è il seguente:

Device breadboard Esp01 con alimentatore 220 volt

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

NOTA: Se lo Shelly non è più "visibile" sulla rete o se è ncessario resettarlo alle impostazioni di fabbrica, basta premere 5 volte (entro un minuto da quando viene alimentato) il pulsante connesso all'ingresso SW.