Visualizzazione post con etichetta micropython. Mostra tutti i post
Visualizzazione post con etichetta micropython. Mostra tutti i post

venerdì 5 novembre 2021

Setup server di ricezione dati IOT

 


Sistemati i test di collazione e quello di invio dei dati, come nei post precedenti, adesso vediamo come ho gestito il sistema lato server. Quindi , ricapitolando, il sistema prevede la raccolta dei dati da una macchina industriale attraverso  il protocollo ModBus. L'invio di questi dati attraverso una chiamata request in POST verso un server che si occuperà di ricevere e di registrare i dati raccolti su MySQL standard.

Qui di seguito descrivo la ricezione dei dati attraverso una pagina PHP che si occupa anche dell'invio verso MySql  dei dati stessi, quindi il nostro server dovrà avere caricato e funzionante il PHP, il MySql ed un web server con certificato SSL che possa ricevere chiamate https.

Ipotizziamo di ricevere dei dati da una macchina industriale, per esempio questi:


                "ser"

                "t1"

                "t2"

                "ai"

                "ah"

                "h1"

                "h2" 

                "h3"

                "h4"

                "i1" 

                "i2"

                "i3"

                "i4"

                "i5"

                "f1"

                "f2"

                "f3"

                "f4"

                "f5"

                "t1_max"

                "t1_min"

                "t2_max"

                "t2_min"

                "IS"

                "ai_max"

                "vers_soft"

                "mac"

                "eth0"

                "ipp"

                "gw"

                "sft_ver"

                "power_up_time"

                "wlan0"

                "O3_ppm"

                "temperature"

                "humidity"

Per poterli inserire in un  database, dobbiamo intanto creare una tabella che si aspetti di ricevere questi dati, oltre al timestamp per definire il tempo di ricezione ed il numero ID progressivo dell'operazione.

Quindi Creata la tabella ed inseriti i nomi dei campi sul server MySql (settati i vari parametri relativi al MySql), a questo punto dobbiamo costruire una pagina php che riceva la chiamata request POST dal nostro ESP32 e si preoccupi di prelevare i dati allegati al POST, e correttamente li inserisca in una query di INSERT nel database.

<?php


/*

  TecnoGeppetto

  Inserimento dati in DB 

  11/07/2020

*/

$servername = "localhost:3306";

$dbname = "NAME DB";

$username = "DB USERNAME";

$password = "DB PASSW"; 

// Change this value, the ESP32 sketch needs to match

$api_key_value = "YOUR API KEY";

//Build variables 

$api_key= $ser = $t1 = $t2 = $ai = $ah = $h1 = $h2 = $h3 = $h4 = $i1 = $i2 = $i3 = $i4 = $i5 = "";

if ($_SERVER["REQUEST_METHOD"] == "POST") {

    $api_key = test_input($_POST["API_KEY"]);

if($api_key == $api_key_value) {

$post = file_get_contents('php://input');

$post  = json_decode($post, TRUE);

echo var_dump($post);

        $ser = test_input($post["ser"]);

        $t1 = test_input($post["t1"]);

        $t2 = test_input($post["t2"]);

        $ai = test_input($post["ai"]);

        $ah = test_input($post["ah"]);

        

        // Create connection

        $conn = new mysqli($servername, $username, $password, $dbname);

        // Check connection

        if ($conn->connect_error) {

            die("Connection failed: " . $conn->connect_error);

        } 

        

        $sql = "INSERT INTO sensor_data (ser, t1, t2, ai, ah)

        VALUES ('" . $ser . "', '" . $t1 . "', '" . $t2 . "', '" . $ai . "', '" . $ah . "')";

        

        if ($conn->query($sql) === TRUE) {

            echo "New record created successfully";

        } 

        else {

            echo "Error: " . $sql . "<br>" . $conn->error;

        }

    

        $conn->close();

    }

    else {

        echo "Wrong API Key provided.";

    }


}

else {

    echo "No data posted with HTTP POST.";

}


function test_input($data) {

    $data = trim($data);

    $data = stripslashes($data);

    $data = htmlspecialchars($data);

    return $data;

}

?> 

Come potete leggere nel codice sopra per la fase di test ho deciso di inviare solo alcune delle variabili  (ser, t1, t2, ai, ah), le altre le ho omesse solo per praticità.

Il codice sopra dovrà essere inserito in un file .php  sul server web in cloud. Detto file verrà quindi chiamato dal codice che gira su ESP32 e che effettua la chiamata request POST.


Buon Lavoro

TecnoGeppetto

Come creare un flusso di dati con ESP32

 Dopo aver realizzato le esperienze con ModBus ed ESP32 descritte nel precedente post, avere cioè creato un device che in funzione Master interroga dei device Slave con il protocollo MobBus attraverso un collegamento seriale, si presenta il problema di trasmettere questi dati da qualche parte per poterli utilizzare, magari su Dashboard intelligenti.

Photo by Jorge Ramirez on Unsplash

Come fare?

La prima cosa che ho pensato è quella di rendere possibile la trasmissione dei dati raccolti attraverso una connessione ad un server in Cloud. I sistemi di  connessione più noti sono la classica GET o la sorella maggiore POST. La differenza tra i due metodi è molto semplice, la GET trasmette i dati aggiungendoli direttamente in chiaro , all'indirizzo di chiamata ( tipo : http//ilsitoRicevente.it?id=111&dato1=222)

Il metodo POST invece non passa i parametri direttamente nell'indirizzo, ma li allega come file e li trasmette a parte all'indirizzo del server ricevente. Questo metodo è più sicuro perchè è più difficile intercettare i dati così trasmessi e quindi viene usato quando è importante la privacy e l'integrità del dato.

Per costruire la chiamata POST al mio server utilizzo la libreria  urequest già presente nella configurazione di base del Micropython installata sul ESP32, quindi basta importarla nel programma.

Qui di seguito il programma di base che ho impostato per inviare i dai con una chiamata POST .


import urequests as requests

import ujson

url = "https://iot.sottosopraweb.com/register.php"


header = {'api_key': '***LA MIA API KEY****',

           'Content-Type': 'application/json'}


data = {"ser":"777", "t1": "22", "t2": "23", "ai": "24", "ah": "25"}

data = ujson.dumps(data)

r = requests.post(url, data=data, headers=header)

print(r.text)

Dopo aver importato le librerie  necessarie, costruisco l'header della chiamata, a cui aggiungo il codice ApiKey che servirà come chiave per far accettare il pacchetto al server. costruisco la variabile data , passo la variabile data alla libreria ujson per formattare il testo in modo "digeribile" dal sistema ricevitore ed in finale creo la request (faccio la chiamata al server) e mi stampo la risposta da parte del server.

 

Spero di essere stato utile a qualcuno 
TecnoGeppetto

mercoledì 28 luglio 2021

ESP32 esperienze con ModBus

 Nell'era di Industria 4.0 tutte le aziende stanno effettuando la conversione dei propri sistemi verso i nuovi metodi di  gestione dei dati. Oggi i nuovi macchinari sono tutti "intelligenti", cioè sono in grado di trasmettere il proprio stato e lo stato delle lavorazioni, verso dashboard di controllo sempre più avanzate, che rendono la gestione del tempo e delle lavorazioni sempre più efficacie e consentono anche la manutenzione preventiva, per evitare i malfunzionamenti ed eventuali onerosi blocchi macchina.


Anche i macchinari più anziani, però, possono essere resi Smart, con l'ausilio di sensori e metodi di trasmissione dei dati sempre più piccoli e facilmente integrabili.

In questi giorni sto aiutando un amico proprio in un progetto di questo tipo, cioè la conversione di un macchinario al quale è stato già integrato un sistema di trasmissione dei dati su modulo ModBus seriale RS485. Il sistema attualmente trasmette i dati via cavo seriale RS485, l'intenzione è quella di convertire il sistema per poter trasmettere via WiFi gli stessi dati.


La scelta naturalmente è stata quella di utilizzare i moduli ESP32, che sono economici e molto facili da utilizzare, veloci e sicuri.

Riporto qui a fianco lo schema della GPIO del modulo che ho utilizzato per fare i test. Ho scelto il modello Mini ESP32 in quanto per questo progetto non ci sono particolari necessità di piedinatura, ed il fattore forma, per semplificare la possibilità di integrazione è una delle variabili più importanti.

Per prima cosa, ho caricato sul mio ESP32 il Micropython, come descritto in questa veloce guida ed anche in questo post qui

Successivamente, come spiegato qui, ho collegato il modulo attraverso RSHELL che per lavorare con Micropython è lo strumento più utile in assoluto.

. Sempre attraverso RSHELL ho caricato la libreria che gestirà la comunicazione con il device già inserito nella apparecchiatura, la libreria uModBus che è molto essenziale e gestisce in modo corretto la conversione dei pacchetti con i device in modalità RTU.


Per fare i primi test ho caricato la libreria direttamente dentro la flash del ESP32, anche se la maniera migliore per lavorare con librerie specifiche sarebbe quella di compilare il Micropython direttamente con le librerie che servono, attraverso l'SDK che Espressif mette a disposizione. Lo farò sicuramente finiti i primi test.

A questo punto, per poter controllare il funzionamento o meno del sistema appena montato ho bisogno di un device slave che risponda a chiamate ModBus. Problema!. In casa non ho nulla di questo genere! Ho scoperto però, che esiste un programma linux che consente di simulare il comportamento di un device slave ModBus, proprio per poter testare sistemi come il mio..... Ottimo!

Diagslave funziona in diverse modalità, a me interessa che risponda a chiamate RTU seriali, quindi , caricato su una Raspberry Pi sulla quale sta girando un Debian appena aggiornato all'utlima versione, faccio partire il programma con :

arm-linux-gnueabihf/diagslave -a 1 -m rtu -b 4800 -d 8 -s 1 -p none /dev/ttyAMA0

chiamando l'help si ha la spiegazione di ogni parametro utilizzabile, per la mia configurazione io chiamo il nuovo device 1 con -a 1 (a = address), scelgo il modo RTU con -m rtu, scelgo la velocità di comunicazione con -b 4800 -d 8 -s 1 -p none   e scelgo la seriale sul quale inviare la comunicazione  /dev/ttyAMA0

che corrisponde ai pin UART0 della Raspberry Pi

Pin 8 e 10 come da schema GPIO qui a fianco riportato.

Infatti, proprio sui Pin 8 e 10 , rispettivamente TX e RX della seriale interna UART0 di Raspberry Pi mi sono collegato con i cavetti provenienti dall'ESP32. Sul ESP32 ho indirizzato la seriale sui Pin 12 e 4 (sono Pin non utilizzati da nessun servizio interno e sui quali avevo gia' saldato di Pin rigidi, quindi ho scelto questi per comodità, ma possono essere scelti due Pin qualsiasi, ovviamente liberi da altri servizi).

A questo punto, facendo una richiesta ModBus da ESP32 il programma che gira su Raspberry Pi e che è in ascolto sulla seriale ttyAMA0, dovrebbe rispondere regolarmente.

Per effettuare le richieste dal lato ESP32 ho creato queste  poche righe di codice Micropython:

from uModBusSerial import uModBusSerial as Seriale

seriale = Seriale(uart_id = 2, baudrate = 4800, data_bits=8, stop_bits=1, parity= None, pins=(12,4), ctrl_pin=None) # inizializzo la seriale e creo l'oggetto

seriale.write_single_register(1, 100, 111, True)    #Scrive un singolo registro  sullo Slave 1 nel registro 100 scrive il valore 111

seriale.read_input_registers(1, 100, 3, signed=True) #Legge 3 registri a partire dal 100 

seriale.read_discrete_inputs(1, 99, 3)[0:3] #Legge 3 registri a partire dal 99


Il codice sopra ovviamente è solo per testare la comunicazione e fa queste cose:

from uModBusSerial import uModBusSerial as Seriale

Carica la libreria, 

seriale = Seriale(uart_id = 2, baudrate = 4800, data_bits=8, stop_bits=1, parity= None, pins=(12,4), ctrl_pin=None)

crea l'oggetto "seriale " ,passando i parametri per la configurazione della seriale sui PIN scelti in fase di cablaggio.

seriale.write_single_register(1, 100, 111, True)

Crea una chiamata di scrittura  con seriale.write_single_register(device_ID, REGISTRO, VALORE, segno)

device_ID = il numero identificativo del device ( in una rete ModBus su seriale RS485 possono coesistere fino a 255 device, che avranno ID diversi in funzione della loro collocazione fisica (1, 2 3,......, 255) 

REGISTRO E VALORE sono parametri intuitivi

segno se settato = a True, mantiene il segno scritto nel registro, se settato a False, rende il valore del registro senza tenere conto del segno eventuale (elimina il segno meno davanti al valore del registro se esiste)

seriale.read_input_registers(1, 100, 3, signed=True)

Crea una chiamata di lettura di uno specifico registro (in questo caso il 100, quello su cui, alla riga precedente, avevo scritto il valore 111) il valore 3 indica al sistema di leggere 3 registri consecutivi, che nel nostro caso varranno 111 (l'unico valore che ho programmato alla riga precedente), 0, 0 (naturalmente i valori dei registri 101 e 102 saranno 0 in quanto non sono ancora stati scritti.

seriale.read_discrete_inputs(1, 99, 3)[0:3] 

Questo è un metodo di lettura alternativo, che consente di leggere il contenuto di uno o più  registri di un determinato device. Questo metodo ha bisogno della specifica dell'intervallo di lettura tra parentesi quadre, come riportato nel comando sopra.

Qui sotto il video dove e' possibile vedere le due finestre di terminale affiancate, una corrisponde al sistema Diagslave (quella in alto a DX) l'altra finestra, corrisponde alle chiamate effettuate dal modulo ESP32 utilizzato come Master in questa configurazione.



Buon Lavoro a tutti
TecnoGeppetto

sabato 23 gennaio 2021

ESP32 gestione di striscia Led indirizzabile Neopixel WS2812

 I miei test sul sistema MicroPython ed ESP32 vanno avanti di gran lena, oggi ho completato il montaggio di un semplice circuito con un ESP32 ed una barretta di Led WS2812 molto comoda e facilmente inseribile nei vari circuiti che possiamo costruire "sulla scrivania".

Ho montato il circuito come da schema qui sotto, ma ho avuto dei problemi allo startup del ESP, che "sente" il GPIO basso, e si mette in Dounload mode, cioe' pronto a ricevere il firmware, e non entra in posizione lavoro. Quindi ho deciso di utilizzare un'altra porta (ce ne sono tante!) per evitare l'inconveniente


La verisone di ESP sulla quale sto lavorando, probabilmente ha dei problemi di circuito, infatti non funziona il Pin dei 5V (il Vin, cioe' il pin che e' collegato all'alimentazione proveniente  dalla USB, di conseguenza sono sato costretto a collegarmi alla 3,3V per alimentare la barretta di Led ( siamo un po' sotto il limite della minima tensione ammessa, che e' di 4V, ma dai testi funziona ugualmente!!). Con questa configurazione pero' devo stare attento ad accendere i Led mai alla massima potenza, in quanto assorbirebbero tropo per il componente stabilizzatore di tensione installato sulla scheda (infatti , se funzionasse!, sarebbe certamente meglio usare l'alimentazione diretta dalla USB per alimentare la barretta di LED, questo modo che ho scelto io, passa attraverso lo stabilizzatore di tensione che si occupa di alimentare il microcontrollore ed il wifi, quindi ha gia' il suo bel da fare!)

Di seguito il codice uploadato sull ESP che fa accendere i led di un colorino arancione uno per volta fino ad accendere tutta la barretta, poi fa il percorso inverso e spenge tutti uno alla volta. Fa' questo di continuo, fino a che non riceve un break (Ctrl-C) da terminale.

from machine import Pin
from neopixel import NeoPixel
import time

pin = Pin(16, Pin.OUT)   # set GPIO16 to output to drive NeoPixels
np = NeoPixel(pin, 8)   # create NeoPixel driver on GPIO0 for 8 pixels
while True:
    for i in range(8):
        np[i] = (2555)      # set the first pixel to orange
        np.write()              # write data to all pixels
        time.sleep_ms(500)
    for i in range(80, -1):
        np[i-1] = (000)      # set the first pixel to orange
        np.write()              # write data to all pixels
        time.sleep_ms(500)


Buon divertimento 

TecnoGeppetto




venerdì 22 gennaio 2021

ESP32Cam gestione dei Led della scheda

 Continua la serie di articoli sulla scheda ESP32Cam che inquesto periodo e' sotto i miei riflettori; Con questo articolo parliamo della attivazione e della gestione del LED principale e del Led di servizio. Infatti la scheda ha un bel Led 5050 sulla parte frontale, molto luminoso, che risponde al GPIO 4 ed un Led Rosso sulla scheda interna, vicino al modulo ESP vero e proprio, che viene utilizzato anche dal sistema per messaggi di stato.

Il MicroPython ci consente di gestire piuttosto facilmente questi due led semplicemente alzando o abbassando il livello dei Pin relativi. Bisogna comunque fare attenzione al fatto che il GPIO 4 al quale e' collegato il Led principale Bianco, e' anche utilizzato per la gestione della scheda MicroSD, infatti sul GPIO 4 e' collegata anche il segnale DATA1 della comunicazione tra il microcontrollore e la MicroSD, quindi non e' possibile utilizzare le due periferiche contemporaneamente.


Per il LED Bianco

from machine import Pin
import time

LEDb = Pin(4, Pin.OUT) 
while True:
    LEDb.value(1)
    time.sleep_ms(500)
    LEDb.value(0)
    time.sleep_ms(500)


Per il LED Rosso

#gestione del LED di servizio Rosso della scheda sul GPIO33
LEDr = Pin(33, Pin.OUT) 
while True:
    LEDr.value(1)
    time.sleep_ms(500)
    LEDr.value(0)
    time.sleep_ms(500)

Nota che il LED Rosso funziona alla rovescia rispetto all'altro quindi si accendera' con il Pin 33 basso, mentre si spengera' con il Pin 33 tenuto alto.


Buoni esperimenti

TecnoGeppetto



ESP32Cam primi approcci

 Veramente orami e' qualche mese che ho ricevuto dalla Cina il mio primo ESP32Cam, un mostriciattolo che ha a bordo il ESP32 uno slot per MicroSD card, una telecamera ed una serie di pin a cui poter collegare il ....resto del mondo!



Ho gia' fatto un sacco di progettini con l'ESP32, tutti in C, utilizzando la IDE di Arduino e la modalita' "classica" di programmazione: upload via seriale del firmware compilato attraverso la Ide di Arduino .

Su questo sistema di operare, ci sono in rete migliaia di Tutorial anche blasonati, come per esempio quelli di Adafruit, mentre per quanto riguarda Python e MicroPython, ancora non si trova un granche'.

Considerato pero' che ho imparato a programmare con Python, vorrei imparare anche a sviluppare qualcosa di mio su ESP con questo linguaggio.


Quindi , vediamo un po' come fare per far diventare produttiva la giornata!

Intanto, primo consiglio, in rete si trovano diverse fonnti che vendono la scheda ESP32Cam, io consiglio quella completa  della sua basetta con presa USB e interfaccia seriale integrata, che e' molto comoda, viene riconosciuta subito dal sistema operativo, e ci evita di dover ricorre a fili volanti e interfacce seriali posticce, per poter lavorare. Costa pochissino (meno di 1 euro) e non ci sono motivi per non utilizzarla, almeno per la fase di prototipazione, quando fare l'upload del firmware e' una operazione frequente. Quando la parte di sviluppo sara' terminata, se volessimo utilizzare bene gli spazi, potremmo sempre sfilare la basetta seriale e, magari costruirne una apposita con i sensori di cui necessitiamo gia' previste e montati onboard.Quindi nel caso si volesse optare per la soluzione con scheda seriale esterna questi sono le connessioni da effettuare:


Il ponticello tra GPIO0 e GND e' indispensabile per "dire" al microcontrollore che siamo in flash mode e che stiamo per inviare il firmware.

Recuperare l'ultima versione del firmware dal sito 

Dal alto pc, se siamo su Linux, il comando per fare upload del sistema operativo MicroPython si deve utilizzare :

$ esptool.py –chip esp32 -p <nome_porta> write_flash -z 0x1000 <path_del_firmware>

Se siamo su windows ed abbiamo difficolta' ad installare il sistema di siluppo di Espressif (esptools), possiamo :

Scaricare il Flash Dowload Tools qui   ( questa e' l'ultima versione, prebdere ovviamente la versione piu' recente) basta scompattarlo in una cartella ed siamo  subito operativi.

Fare click sul file  flash_download_tool_3.8.5.exe e scegliere il tasto Developer Mode e nella successiva finestra il tasto relativo al modello di ESP che abbiamo a disposizione.

Si aprira' questa finestra:


All'interno della quale va soltanto caricato il path del firmware appena scaricato del MicroPython. Gli altgri parametri dovrebbero andare bene senza essere toccati.

 A questo punto fare ERASE per cancellare la memoria flash da alti eventuali upload.

Poi  START, per iniziare l'upload.

Se tutto e' andato bene. ci trovermo, al termine del processo, il nostro ESP32Cam che sara' pronto per essere programmato in Python. Bastera' quindi collegarlo con PuTTY (per esempio) sulla porta COM che windows gli avra' assegnato. nel mio caso la COM10.

Alla prima connessione il nostro ESP rispondera' con il prompt di Python e sara' gia' pienamente operativo.

Cosa fare adesso?

Adesso abbiamo il mostriciattolo che risponde ai comandi, ma ancora non e' collegato alla rete e non puo' essere collegato da remoto. Quindi la prima cosa da fare e' farlo collegare alla rete.

Ci viene in aiuto la documentazione ufficiale di MicroPython per ESP32

import network

wlan = network.WLAN(network.STA_IF) # create station interface
wlan.active(True)       # activate the interface
wlan.scan()             # scan for access points
wlan.isconnected()      # check if the station is connected to an AP
wlan.connect('essid', 'password') # connect to an AP
wlan.config('mac')      # get the interface's MAC address
wlan.ifconfig()         # get the interface's IP/netmask/gw/DNS addresses

ap = network.WLAN(network.AP_IF) # create access-point interface
ap.config(essid='ESP-AP') # set the ESSID of the access point
ap.config(max_clients=10) # set how many clients can connect to the network
ap.active(True)         # activate the interface

Fatta la connessione al router casalingo (modificare opportunamente essid e password nel codice sopra con quelli corretti per la connessione al proprio router)

Attiviamo il WEBREPL per poter effettuare la connessione da remoto ed utilizzare la funzionalita' di upload e download dei file dal sistema operativo del ESP32Cam ( si perche' il sistema che abbiamo caricato si comporta come un vero e proprio sistema operativo sul quale possiamo caricare, scrivere leggere e cancellare file.

PS Se utilizziamo Linux e' tutto piu' semplice, come sempre, esiste infatti una applicazione ampy che basta chiamare per fare direttamente l'upload da terminale cosi:

$ ampy -p dev/ttyUSB0 put boot.py

Ma stiamo utilizzando windows, mio malgrado, quindi , secondo me, la maniera piu' veloce per ottenere il buon funzionamento del ESP32Cam e' questo, cioe' passare da WEBREPL per fare l'upload dei file che ci interessa caricare sul sistema.

import webrepl_setup

Con questa riga, e poi seguendo le richieste del programma, si stabilisce una password e si abilita la partenza del WEBREPL ad ogni restart o reset del sistema.

Proviamo se tutto funziona a dovere:

Da un qualsiasi browser connettere: http://micropython.org/webrepl/#1p2.168.NUMERO_IP_ESP:8266/

Inserire naturalmente l' IP dell'ESP32Cam, ed utilizzare la porta 8266 come specificato. Dovrebbe rispondere il nuovo sistema con la richiesta diella password di accesso che abbiamo creato con la prima chiamata del WEBREPL. Dare la password corretta ed il sistema rispondera' con il prompt di MicroPython

Ok a questo punto che siamo connessi e abbiamo il WEBREPL attivato, non ci resta altro che rendere queste modifiche permanenti in maniera che ad ogni statup del sistema questo si connetta al router in automatico e renda disponibile l'interfaccia remota per poter essere contattato anche se non direttamente collegato al pc.

Dal WEBREPL scarichiamo il file boot.py e modifichiamo la parte relativa ala connessione, per renderla automatica cosi:

fare il get del file boot.py


modificarlo con :

<code>

# This file is executed on every boot (including wake-boot from deepsleep)
import esp
esp.osdebug(None)
import webrepl
webrepl.start()
def do_connect():
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network...')
        wlan.connect('essid''password')
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())
do_connect()

</code>

E fare l'upload del file appena modificato con l'apposita funzione disponibile sul browser



A questo punto siamo pronti. Basta resettare (anche togliendo l'alimentazione) il nostro ESP32Cam ed al riavvio, in automatico si collleghera' al router e sara' connettibile tramite interfaccia WEBREPL all'indirizzo : IP_del_ESP:8266 da un qualsiasi browser.

Buon divertimento 

TecnoGeppetto



 





giovedì 31 dicembre 2020

MQTT publisher sistema di test del protocollo MQTT

 Chi non volesse costruire il device come trattato negli articoli precedenti, ma avesse comunque necessita' di veder funzionare il sistema basato sui pacchetti di messaggi MQTT, puo' sempre far girare un software sul pc che simula il device stesso e che fornisce messaggi sul broket MQTT necessari.

Per questi test ho scelto il broker messo a disposizione dal progetto Eclipse che potete trovare qui 

Per far questo, sempre attraverso il progetto Eclipse ho trovato un codice che con poche righe consente di inviare messaggi ad un qualsiasi broker MQTT ad intervalli regolari

Utilizzando sempre il sitema Linux su WSL in Windows, nella mia shell, sempre nella cartella mqtt_client, ho creato un nuovo file chiamato publisher.py che crea una connessione con il broker MQTT, ed invia una serie di messaggi sul topic scelto ( nel mio caso TecnoGeppetto/topic

publisher.py

import paho.mqtt.client as mqtt
import time

def on_connect(client, userdata, flags, rc):
    print(f"Connected with result code {rc}")
    
client = mqtt.Client()
client.on_connect = on_connect
client.connect("broker.emqx.io", 1883, 60)

# send a message to the TecnoGeppetto/topic every 10 second, 50 times in a row
for i in range(50):
    # the four parameters are topic, sending content, QoS and whether retaining the message respectively
    client.publish('TecnoGeppetto/topic', payload=i, qos=0, retain=False)
    print(f"send {i} to TecnoGeppetto/topic")
    time.sleep(1)

client.loop_forever()

Quindi, su un sistema sul quale gira python 3 e sul quale e' installata la libreria paho.mqtt.client bastera' chiamare python3 publisher.py per ottenere una serie di 50 messaggi ogni 10 secondi pubblicati sul broker pubblico scelto sul topic preferito (nel caso del codice in oggetto, sul topic  TecnoGeppetto/topic

Naturalmente i messaggi potranno essere ricevuto su un'altra shell sulla quale gira il software subcriber, descritto nel post precedente.


Buon divertimento 

TecnoGeppetto




Client MQTT subscriber e publisher per linux - Raspberry Pi

 A seguire gli esperimenti di questi giorni, oggi mi sono dedicato alla configurazione su linux di un sistema per leggere i messaggi inviati dal sensore. Ho cercato un client MQTT che potesse essere utilizzato da linea di comando ed ho trovato e configurato questo che adesso decrivero'.


Ho trovato il progetto Eclipse che fa al caso mio, hanno sviluppato una libreria disponibile su github per la gestione delle comunicazioni con un broker MQTT che si chiama paho che risolve la maggior parte dei problemi e consente con 4 righe di codice  di ottenere cio' di cui ho bisogno.

I passi necessari per far funzionare tutto sono questi:

su linux ( io per praticita' utilizzo una shell linux in WSL su windows, perche' in questo periodo sto usando un pc con windows) creo la mia direttory di progetto che ho chiamato mqtt_client 


quindi entro nella cartella appena creata con 


quindi creo il file che conterra' il codice del programma MQTT client subscriber


edito il contenuto del file con i dati del mio broker MQTT pubblico  scelto.

file  subscribe.py:

# subscribe.py
import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    print(f"Connected with result code {rc}")
    # subscribe, which need to put into on_connect
    # if reconnect after losing the connection with the broker, it will continue to subscribe to the raspberry/topic topic
    client.subscribe("TecnoGeppetto/topic")

# the callback function, it will be triggered when receiving messages
def on_message(client, userdata, msg):
    print(f"{msg.topic} {msg.payload}")
    
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

# set the will message, when the system is powered off, or the network is interrupted abnormally, it will send the will message to other clients
client.will_set('TecnoGeppetto/status', b'{"status": "Off"}')

# create connection, the three parameters are broker address, broker port number, and keep-alive time respectively
client.connect("broker.emqx.io", 1883, 60)

# set the network loop blocking, it will not actively end the program before calling disconnect() or the program crash
client.loop_forever()

Naturalmente per far funzionare tutto sulla distribuzione linux che ho scelto e' presente python 3.xx, se non lo fosse e' necessario installarlo  assieme a pip3 che servira' per installare la libreria di cui si fa       l' import nel codice.

sudo apt install python3

poi

pip3 install paho-mqtt

A questo punto per far girare il client in ricezione sui topic scelti nel codice ( nel caso qui pubblicato TecnoGeppetto/topic  , basta chiamare 



Nel caso di problemi di connesisone il sistema rende un codice di errore, questa di seguito e' la legenda dei possibili codici

0: connection succeeded
1: connection failed - incorrect protocol version
2: connection failed - invalid client identifier
3: connection failed - the broker is not available
4: connection failed - wrong username or password
5: connection failed - unauthorized
6-255: undefined
If it is other issues, you can check the network situation, or check whether `paho-mqtt` has been installed.


Naturalmente il topic da scegliere deve essere lo stesso sul quale trasmette il sensore, in modo da poter regolarmente ricevere il messaggio trasmesso ogni volta dal sensore.


Buon divertimento 

TecnoGeppetto




martedì 29 dicembre 2020

ESP8266 e MQTT con MicroPython, connessione e primi vagiti

 Dopo aver domato i mostriciattoli ESP8266  ed ESP32 come visto nei post precedenti, oggi mi sono cimentato nella pubblicazione di dati con il protocollo MQTT.
Il sistema lo avevo testato per la prima volta durante un corso che ho fatto quest'anno, in sonstanza e' molto semplice, un server dove gira il software Mosquitto, riceve messaggi da un nodo e li "gira" a tutti i nodi che sono in ricezione su un determinato "topic".

Il sistema che ho testato si compone di due ESP8266, uno che si preoccupa di inviare un messaggio su uno specifico "topic" ed ascolta invece un topic diverso attraverso il quale ricevera' la notifica di ricezione dall'altro nodo (un suo fratello ESP8266). L'altro ovviamente, ricevera' sul canale di trasmissione del primo, e  trasmettera' su quello di ricezione del primo. in maniera di avere un sistema che trasmette un messaggio su un canale e riceve ok di ricezione su un altro. 


Quindi il codice per il primo ESP8266 sara' il seguente:

boot.py

# TecnoGeppetto
# Sistema MQTT con esp8266 / esp32
#
# ESP#1
# 
import time
from umqttsimple import MQTTClient
import ubinascii
import machine
import micropython
import network
import esp
esp.osdebug(None)
import gc
gc.collect()
import webrepl


ssid = "XXXXXXXXXXXXXXXX"
password = "XXXXXXXXXXXXXXX"
mqtt_server = 'XXXXXXXXXXXXXXX'
#EXAMPLE IP ADDRESS
#mqtt_server = '192.168.1.144'
client_id = ubinascii.hexlify(machine.unique_id())
topic_sub = b'TecnoGeppetto/notifica'
topic_pub = b'TecnoGeppetto/ciao'

last_message = 0
message_interval = 5
counter = 0

station = network.WLAN(network.STA_IF)

station.active(True)
station.connect(ssid, password)

while station.isconnected() == False:
  pass

print('Connection successful')
print(station.ifconfig())
webrepl.start()
    

main.py

# ESP #1

def sub_cb(topic, msg):
  print((topic, msg))
  if topic == b'TecnoGeppetto/notifica' and msg == b'received':
    print('ESP received hello message')

def connect_and_subscribe():
  global client_id, mqtt_server, topic_sub
  client = MQTTClient(client_id, mqtt_server)
  client.set_callback(sub_cb)
  client.connect()
  client.subscribe(topic_sub)
  print('Connected to %s MQTT broker, subscribed to %s topic' % (mqtt_server, topic_sub))
  return client

def restart_and_reconnect():
  print('Failed to connect to MQTT broker. Reconnecting...')
  time.sleep(10)
  machine.reset()

try:
  client = connect_and_subscribe()
except OSError as e:
  restart_and_reconnect()

while True:
  try:
    client.check_msg()
    if (time.time() - last_message) > message_interval:
      msg = b'Hello #%d' % counter
      client.publish(topic_pub, msg)
      last_message = time.time()
      counter += 1
  except OSError as e:
    restart_and_reconnect()


Questi sopra sono i file di cui fare upload sul primo ESP8266 nei quali va sostituito al posto delle XXXXXX i dati per accedere al proprio router per il collegamento ad internet ed il numero IP del broker MQTT. ( in un altro progetto che pubblichero' piu' avanti, un server MQTT fatto in casa con Raspberry).
Come detto sopra, il primo device crea una connessione con il broker, sottoscrive un topic sul quale rimane in ascolto, nel caso in esempio : TecnoGeppetto/notifica 
Quando sono trascorsi 5 secondi, pubblica sul topic  TecnoGeppetto/ciao   un  saluto "Hello"

L'altro ESP8266 avra' invece questo software :


boot.py

# ESP#2

import time
from umqttsimple import MQTTClient
import ubinascii
import machine
import micropython
import network
import esp
esp.osdebug(None)
import gc
gc.collect()

ssid = "XXXXXXXXXXXX"
password = "XXXXXXXXXX"
mqtt_server = 'xxxxxxxxxxxx'
#EXAMPLE IP ADDRESS
#mqtt_server = '192.168.1.144'
client_id = ubinascii.hexlify(machine.unique_id())
topic_sub = b'TecnoGeppetto/ciao'
topic_pub = b'TecnoGeppetto/notifica'

station = network.WLAN(network.STA_IF)

station.active(True)
station.connect(ssid, password)

while station.isconnected() == False:
  pass

print('Connection successful')
print(station.ifconfig())


main.py

# ESP#2

def sub_cb(topic, msg):
  print((topic, msg))

def connect_and_subscribe():
  global client_id, mqtt_server, topic_sub
  client = MQTTClient(client_id, mqtt_server)
  client.set_callback(sub_cb)
  client.connect()
  client.subscribe(topic_sub)
  print('Connected to %s MQTT broker, subscribed to %s topic' % (mqtt_server, topic_sub))
  return client

def restart_and_reconnect():
  print('Failed to connect to MQTT broker. Reconnecting...')
  time.sleep(10)
  machine.reset()

try:
  client = connect_and_subscribe()
except OSError as e:
  restart_and_reconnect()

while True:
  try:
    new_message = client.check_msg()
    if new_message != 'None':
      client.publish(topic_pub, b'received')
    time.sleep(1)
  except OSError as e:
    restart_and_reconnect()

Che apre una connessione ad internet via router, si connette al broker MQTT, si mette in ascolto del topic :  TecnoGeppetto/ciao      e quando riceve il "saluto" inviato dal primo, pubblica sul topic:  TecnoGeppetto/notifica       la conferma di ricezione.

Elaborato dal progetto originale che puoi trovare qui 

Buon divertimento
TecnoGeppetto

lunedì 28 dicembre 2020

DHT11 ESP8266 NEOPIXEL e Micropython

 Ho ripreso in mano il mio ESP8266 per approfondirne la conoscenza. Nell'ultimo post ho imparato a caricare il Micropython ed a collegare il mio ESP8266 da remoto con WebREPL.


In questo modo e' possibile caricare i file di programma nel file system del ESP8266, in modo da poterli poi far "girare" chiamandoli direttamente da termionale o madandoli in esecuzione direttamente al boot, utilizzando il file di sistema boot.py.

Infatti il MicroPython, gia' dalla sua istallazione prevede il file boot.py che in automatico la macchina chiama ad ogni reboot, quindi e' facile poter far partire tutti i programmi che vogliamo opportunamente impostando solamente  quest'ultimo file.


Avevo in un cassetto un ESP8266 superstite da alcuni altri passati esperimenti, al quale era gia' collegato e funzionante una barretta di 8 led Neopixel ed un sensore DHT11.

Niente di meglio per fare amicizia con il sistema Micropython.

Ho iniziato ad impostare la rete in modo fisso, in maniera che ad ogni reboot l'ESP si colleghi in automatico con il router di casa, semplicemente copiando le istruzioni necessarie nel file  boot.py (le stesse che abbiamo visto nel post di ieri).

Fatto questo e reso automatica la partenza del sistema WebREPL come visto ieri, impostando la password.

Ho iniziato a caricare tramite WebREPL il file di un semplice programma che legge la temperatura dal sensore e la stampa sulla consolle.

TEMP.PY :

#questo programma legge la temperatura e l'umidita' dal sensore DHT11 
#collegato al Pin 14 del ESP8266 (il pin contrassegnato con D5)

from machine import Pin
#from time import sleep
import dht 
#sensor = dht.DHT22(Pin(14))
sensor = dht.DHT11(Pin(14))

def get_temp():
    sensor.measure()
    temp = sensor.temperature()
    hum = sensor.humidity()
    return [temp,hum]


def leggi_temp():
    sensor.measure()
    temp = sensor.temperature()
    hum = sensor.humidity()
    print('Temperature: %3.1f C' %temp)
    print('Humidity: %3.1f %%' %hum)
    


Poi ho caricato un secondo file leds.py che gestira' i leds della barretta di Neopixel con a bordo il famoso led WS2812B.

LEDS.PY :

# questo programma scrive colori su neopixel ws2812B
# i neopixel sono collegati al Pin 5 che e' marcato D1 sulla scheda esp8266

import machine, neopixel
from time import sleep
import temp
n = 8 #numero dei pixel disponibili
p = 5 #pin sul quale sono collegati i led

np = neopixel.NeoPixel(machine.Pin(p), n)

def temp_leds():
    lista = temp.get_temp()
    if lista[0] <= 16:
        np[0] = (0,0,5)
        np[1] = (0,0,0)
        np[2] = (0,0,0)
        np[3] = (0,0,0)
        np[4] = (0,0,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 17:
        np[0] = (0,0,5)
        np[1] = (0,0,5)
        np[2] = (0,0,0)
        np[3] = (0,0,0)
        np[4] = (0,0,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 18:
        np[0] = (0,5,3)
        np[1] = (0,5,3)
        np[2] = (0,5,0)
        np[3] = (0,0,0)
        np[4] = (0,0,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 19:
        np[0] = (0,5,3)
        np[1] = (0,5,3)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (0,0,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 20:
        np[0] = (0,5,0)
        np[1] = (0,5,0)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (5,5,0)
        np[5] = (0,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 21:
        np[0] = (0,5,0)
        np[1] = (0,5,0)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (5,5,0)
        np[5] = (5,0,0)
        np[6] = (0,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 22:
        np[0] = (0,5,0)
        np[1] = (0,5,0)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (5,5,0)
        np[5] = (5,0,0)
        np[6] = (5,0,0)
        np[7] = (0,0,0)
        np.write()
    elif lista[0] == 23:
        np[0] = (0,5,0)
        np[1] = (0,5,0)
        np[2] = (0,5,0)
        np[3] = (0,5,0)
        np[4] = (5,5,0)
        np[5] = (5,0,0)
        np[6] = (5,0,0)
        np[7] = (5,0,0)
        np.write()
    else:
        np[0] = (3,0,0)
        np[1] = (3,0,0)
        np[2] = (3,0,0)
        np[3] = (3,0,0)
        np[4] = (5,0,0)
        np[5] = (5,0,0)
        np[6] = (5,0,0)
        np[7] = (5,0,0)
        np.write()
def smooth_red():
    for led in range(8):
        for i in range(50):
            np[led] = (i, 0, 0)
            np.write()
            sleep(0.025)

def spengi_leds():
    for i in range(8):
        np[i] = (0, 0, 0)
    np.write()

def smooth_green():
    for led in range(8):
        for i in range(50):
            np[led] = (0, i, 0)
            np.write()
            sleep(0.025)

def smooth_blu():
    for led in range(8):
        for i in range(50):
            np[led] = (0, i, 0)
            np.write()
            sleep(0.025)
        

Inizialmente ho fatto amicizia con i colori (attenzione a non far partire alla massima intensita' tutti i led assieme che potrebbe essere dannoso per l'alimentazione del computer al quale e' collegato l'ESP, a causa del  troppo assorbimento - circa 60 mA per ogni led)

Infine li ho inseriti nel file di boot.py per far si che possano funzionare gia' dal reboot:

Il sistema cosi impostato, legge la temperatura una sola volta all'accensione, e in funzione del valore letto, accende i led di colore blu se la temperatura e' al di sotto dei 16 - 17 gradi
di colore verde per valori tra i 17 ed i 20 gradi e di rosso se la temperatura supera i 20 gradi.
I led si accendono in modo che la scala sia "parlante" in funzione dell'aumento della temperatura.
Cioe' < 16 gradi solo il primo led - poi via via fino a 24 gradi con tutti e 8 i led accesi.

E' ovvio che il tutto e' fatto per test e per fare conoscenza! Per fare un device intelligente, la temperatura va letta ad iintervalli costanti ed aggiornata la scla dei led in conseguenza. Ma non era questo lo scopo dei miei test di oggi (comunque bastano altre due righe di codice per farlo!)


BOOT.PY


# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
import uos, machine
#uos.dupterm(None, 1) # disable REPL on UART(0)
import gc
import webrepl
import network
import temp
import leds
sta_if = network.WLAN(network.STA_IF)
sta_if.connect("XXXXXXXXXXXXXXXXXX","XXXXXXXXXXX") # Connect to an AP
print("LA mia connessione e' attiva e questo e' il mio indirizzo: ", sta_if.ifconfig())
webrepl.start()
gc.collect()
temp.leggi_temp()

leds.temp_leds()


Oggi sono arrivato fino qui!
A domani (forse ) per la prossima puntata.
TecnoGeppetto