Vai al contenuto

Interfacciare SlimLine ad un termostato Shelly

L’integrazione tra dispositivi di automazione domestica rappresenta oggi un elemento fondamentale per migliorare comfort, efficienza energetica e controllo degli impianti domestici. L’integrazione tra un controllore programmabile come SlimLine ed i termostati Shelly non solo permette di monitorare e regolare in tempo reale la temperatura degli ambienti, ma offre anche la possibilità di implementare logiche di controllo avanzate. Ad esempio, il PLC può decidere automaticamente quali zone riscaldare o raffrescare in base a parametri come orari programmati, presenza in ambiente, valori di temperatura esterna o scenari predefiniti.

Il sistema SlimLine Elsist è un PLC (Programmable Logic Controller) compatto e versatile, progettato per l’automazione di impianti civili e industriali. Grazie alla modularità e alla possibilità di programmare logiche complesse, consente il controllo di sistemi elettrici, termici e meccanici in modo affidabile e personalizzabile. L’ambiente di sviluppo gratuito LogicLab ne permette la programmazione nei 5 linguaggi sia grafici che testuali definiti dalla norma IEC61131.

Il termostato Shelly è un dispositivo smart progettato per il controllo automatico dei sistemi di riscaldamento e raffrescamento all’interno di impianti domotici e tradizionali. Grazie alla connettività integrata e alla compatibilità con numerosi protocolli di automazione, consente una gestione avanzata della temperatura ambiente.

L’integrazione si realizza utilizzando dallo SlimLine chiamate HTTP REST API tramite il FB HTTPClient in accordo al protocollo RPC Protocol di Shelly. Grazie al formato JSON dei dati, la comunicazione tra SlimLine e i termostati Shelly è estremamente flessibile e scalabile. È possibile aggiungere nuovi dispositivi alla rete senza modifiche sostanziali alla logica di controllo, semplificando l’espansione dell’impianto. L’uso di JSONEncoder e JSONDecoder consente al PLC di interpretare facilmente i dati ricevuti dai termostati, elaborare comandi e inviare istruzioni ai dispositivi Shelly in modo sicuro e standardizzato.

Lo scopo di questo articolo è di scendere nel detlaglio di una realizzazione pratica di seguito riportiamo le operazioni da eseguire.

Termostato Shelly

Configurazione termostato

La prima operazione è configurare il termostato Shelly, questo disositivo nelle versioni più recenti (Gen2/Gen3) non ha l’Access Point Wi-Fi (AP mode) tradizionale, quindi non puoi collegarti direttamente al dispositivo tramite hotspot Wi-Fi come avveniva sulle Gen1. Occorre dal display accedere al menù impostazioni, abilitare il WiFi che visualizzerà le reti presenti e connettersi alla rete desiderata impostando la password di accesso.

Connesso alla rete verrà visualizzato l’indirizzo IP assegnato al dispositivo, da un browser è possibile definire l’indirizzo ed accedere alla pagina di configurazione. Per un test del protocollo RPC da browser basta indicare nella barra indirizzo http://IP Shelly/status e ci verrà ritornato un messaggio JSON con lo stato. I messaggi RPC vanno inviati all’indirizzo indirizzo http://IP Shelly/rpc.

Messaggi RPC
Funzione da eseguireRichiestaRisposta
Lettura temperatura{“id”:1, “method”:”Temperature.GetStatus”, “params”:{“id”:0}}{“id”:0,”tC”:26.2,”tF”:79.2}
Lettura umidità{“id”:1, “method”:”Humidity.GetStatus”, “params”:{“id”:0}}{“id”: 0,”rh”: 43.6}
Lettura illuminazione{“id”:1, “method”:”Illuminance.GetStatus”, “params”:{“id”:0}}{“id”: 0,”lux”: 200,”illumination”: “bright”}
Impostazione set termostato a 22.0 gradi{“id”: 1,”method”: “Thermostat.SetConfig”,”params”: {“id”: 0,”config”: {“target_C”: 22.0,”enable”: true}}}{“restart_required”: false}
Lettura stato termostato{“id”: 1,”method”: “Thermostat.GetStatus”,”params”: {“id”: 0}}{“id”: 0,”enable”: true,”target_C”: 14.5,”current_C”: 22.9,”output”: false,”schedules”: {“enable”: false}}

Scrittura programma su SlimLine

Ora vediamo come realizzare un semplice programma su di un dispositivo SlimLine per acquisire il valore di temperatura dal termostato. Il programma potrà essere modificato per gestire l’acquisizione di altre variabili e/o impostare il set di temperatura.

LogicLab (Ptp181, ShellyWallDisplay)
PROGRAM ShellyWallDisplay

VAR CONSTANT
    BSize : UDINT := 128;    (* Buffer size definition *)
END_VAR

VAR
    CaseNr : USINT; (* Program case *)
    Errors : UDINT; (* Execution errors *)
    TimeBf : UDINT; (* Time buffer (mS) *)
    Temperature : REAL; (* Temperature °C *)
    PStart : PVOID; (* Result start position *)
    PEnd : PVOID; (* Result end position *)
    Answer : STRING[ 128 ]; (* Page string *)
    TCPClient : SysTCPClient; (* TCP client management *)
    HTTPRq : HTTPClient_v5; (* HTTP client *)
END_VAR

// *****************************************************************************
// PROGRAM "ShellyWallDisplay"
// *****************************************************************************
// The program reads the current temperature from a Shelly Wall Display.
// -----------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // INITIALIZATIONS
    // -------------------------------------------------------------------------
    // Program initializations.

    IF (SysFirstLoop) THEN

        // Set TCPClient parameters.

        TCPClient.PeerAdd:=ADR('192.168.1.109'); //Peer address
        TCPClient.PeerPort:=80; //Peer port
        TCPClient.LocalAdd:=ADR('0.0.0.0'); //Local address
        TCPClient.LocalPort:=0; //Local port
        TCPClient.FlushTm:=50; //Flush time (mS)
        TCPClient.LifeTm:=20; //Life time (S)
        TCPClient.RxSize:=512; //Rx buffer size
        TCPClient.TxSize:=512; //Tx buffer size

        // Set HTTPClient parameters.

        HTTPRq.SpyOn:=TRUE; //Activate the spy
        HTTPRq.KeepAlive:=FALSE; //HTTP keep-alive
        HTTPRq.RMethod:=HTTP_REQUEST#HTTP_POST; //HTTP request method
        HTTPRq.HostName:=TCPClient.PeerAdd; // Hostname
        HTTPRq.Page:=ADR('rpc'); //Web page
        HTTPRq.Request:=eNULL; //Request string
        HTTPRq.Header:=ADR('Content-Type: application/json$r$nAccept: application/json$r$n'); //HTTP header
        HTTPRq.DBSize:=512; //Data buffer size
        HTTPRq.Timeout:=T#10s; //Execution timeout

        // Set local variables.

        TimeBf:=SysTimeGetMs(); //Time buffer (mS)
    END_IF;

    // -------------------------------------------------------------------------
    // MANAGE CONNECTION
    // -------------------------------------------------------------------------
    // Manage the TCP/HTTP connection.

    TCPClient(Connect:=HTTPRq.Connect); //Manage TCP client
    HTTPRq(Enable:=TRUE, File:=TCPClient.File); //Enable HTTP client
    IF (HTTPRq.Fault) THEN CaseNr:=0; END_IF;

    // -------------------------------------------------------------------------
    // PROGRAM SEQUENCES
    // -------------------------------------------------------------------------
    // Program sequences.

    CASE (CaseNr) OF

        // ---------------------------------------------------------------------
        // Initialize timer for acquisition delay.

        0:
        HTTPRq.Send:=FALSE; //Do not send request yet
        TimeBf:=SysTimeGetMs(); //Time buffer (mS)
        IF (HTTPRq.Request <> eNULL) THEN eTO_JUNK(SysRMFree(ADR(HTTPRq.Request))); END_IF;
        CaseNr:=CaseNr+1; //Move to next case

        // ---------------------------------------------------------------------
        // Wait for delay, then allocate buffers and enable client.

        1:
        IF ((SysTimeGetMs()-TimeBf) < TO_UDINT(T#10s)) THEN RETURN; END_IF;
        IF NOT(SysRMAlloc(BSize, ADR(HTTPRq.Request))) THEN RETURN; END_IF;
        CaseNr:=CaseNr+1; //Program case

        // ---------------------------------------------------------------------
        // Create an RPC request to read the temperature and send it.
        // {"id":1, "method":"Temperature.GetStatus", "params":{"id":0}}

        2:
        eTO_JUNK(SysVsnprintf(HTTPRq.Request, BSize, ADR('%s'), STRING_TYPE, ADR('{"id":1, "method":"Temperature.GetStatus", "params":{"id":0}}')));
        HTTPRq.Send:=TRUE; //Send request
        CaseNr:=CaseNr+1; //Move to next case

        // ---------------------------------------------------------------------
        // Waiting for the response.
        //{"id":1,"src":"ShellyWallDisplay-0008220BB6BE","result":{"id":0,"tC":23,"tF":73.4}}

        3:
        IF ((HTTPRq.DBChars <> 0) AND HTTPRq.HPSelector) THEN
            IF ((Sysstrlen(ADR(Answer))+HTTPRq.DBChars) < SIZEOF(Answer)) THEN
                eTO_JUNK(Sysmemmove(eTO_POINTER(ADR(Answer))+Sysstrlen(ADR(Answer)), HTTPRq.DBAddress, HTTPRq.DBChars));
            END_IF;
        END_IF;

        //  On completion, read the temperature.

        IF (HTTPRq.Done) THEN
            CaseNr:=0; //Reset program case
            IF NOT(HTTPRq.PLoad) THEN Errors:=Errors+1; RETURN; END_IF;

            // Find the "result" JSON from the response.

            PStart:=SysStrFind(ADR(Answer), ADR('"result":'), FIND_GET_END); //Start position of "result"
            PEnd:=SysStrFind(PStart, ADR('}'), FIND_DEFAULT); //End position of "result"
            eTO_JUNK(Sysmemmove(ADR(Answer), PStart, TO_UDINT(PEnd-PStart)));
            IF (JSONDecoder(ADR(Answer), ADR('tC'), REAL_TYPE, ADR(Temperature), 1, 0) <> 0) THEN Errors:=Errors+1; END_IF;
        END_IF;
    END_CASE;

// [End of file]
Was this article helpful?