Leggiamo da Node-Red, via Modbus, il sensore di umiditá e temperatura XY-MD02 attraverso il Gateway USR-DR164
Ho avuto la necessitá di implementare dei sensori di umiditá e temperatura su una linea RS485 in un’ambiente in cui era giá utilizzato il protocollo Modbus, per cui illustro qui i vari passaggi fatti, il materiale scelto, qualche considerazione e curiositá. Non sará un tutorial come quelli a cui siete abituati, in cui descrivo ogni singola cosa per filo e per segno perché questo vorrebbe dire parlarvi della RS485, del Modbus e di tante altre piccole cose per le quali purtroppo non ho piú il tempo che avevo una volta, per cui procederó a grandi passi e la trattazione é chiaramente rivolta a chi giá mastica di questi argomenti di automazione industriale, anche se ci saranno delle piccole curiositá e ripassi che secondo me tornano utili a tutti.
Indice dei contenuti
Componenti necessari
Oltre ad un sensore di umiditá e temperatura ho inserito un gateway Modbus ⇒ WiFi in maniera da potermi collegare ai sensori via Wi-Fi evitando di passare ulteriori cavi e garantendomi anche possibilitá di espansione a basso costo, per cui elenco di seguito i due oggetti che ho utilizzato. Premetto che il sensore si trova ad un costo molto piú basso sul noto sito cinese di shopping, mentre il Gateway ha lo stesso prezzo anche li:

Assumo chiaramente che abbiate un alimentatore con una tensione da 5 a 24V dato che i due dispositivi vanno alimentati con una tensione in questo range, ma piú giú consiglio qualcosa di stampo industriale eventualmente decidiate di tenere questa postazione fissa o di implementare questa soluzione ex-novo in un impianto.
Software
- OpenModScan (per me ormai indispensabile per fare test su linee Modbus)
- SSCom (optional – difficile da usare perché tradotto male)
- Node-Red (se giá lo sapete usare, altrimenti ci sono migliaia di tutorial *)
* ovviamente Node-Red non é strettamente necessario se state implementando questa soluzione per qualche altro sistema che giá avete in piedi a casa o nella vostra azienda e che permette di prendere i dati da una linea Modbus TCP e riportarli su un’interfaccia. Dato che io uso Node-Red sia a casa che nelle aziende per cui lavoro, ho aggiunto una parte in questo tutorial che mostra come prelevare i dati dal Gateway scelto per poi mostrarli nella Dashboard. Sicuramente é indispensabile la parte di testing e settaggi via modbus, per la quale OpenModScad per me fa da padrone.
Per fare diagnostica in caso di problemi, o per imparare, lo strumento sempre valido ed efficace rimane un analizzatore logico e non posso che consigliare questo. Avere un adattatore RS485 / USB anche é molto utile in quanto, in assenza di Gateway, possiamo collegare direttamente gli apparecchi Modbus RTU al computer per fare dei test o per configurarli. Io ultimamente sto utilizzando questo adattatore, che va bene anche per la RS422, che é veramente solido, ben fatto e basato su chip FTDI.
Nodi aggiuntivi da installare in Node-Red
Materiali optional
Dato che per lavorare nel campo industriale mi sono fatto tutta una serie di comoditá, che uso quotidianamente per facilitarmi il lavoro e tenere il banco piú ordinato, vi consiglio qui qualcosa di quello che uso io:
- Guida DIN in alluminio
- Guida DIN in acciaio
- Alimentatore Meanwell 12V 2A per guida DIN
- Stampa 3D – Stand per singola guida DIN – semplice, immediato
- Stampa 3D – Stand per 4 guide DIN – professionale, dotato di presa IEC e interruttore, ma piú complesso e con varie parti singole da stampare
- Modulo ingresso IEC + interruttore – É quello che ho comprato io per lo stand a 4 guide del link di sopra
- Adattatore RS485/RS422 ↔ USB – É quello di cui parlavo sopra, che riporto qui per questioni di ordine
In aggiunta, per quanto riguarda gli alimentatori, ho disegnato un supporto per guida DIN fatto esclusivamente per gli alimentatori switching della Meanwell da 25W, ovvero i seguenti disponibili su Amazon:
Chiaramente per questa specifica applicazione quello da 3.3V non puó essere utilizzato, mentre 24V é sicuramente la scelta piú industriale. Il modello di cui vi parlo l’ho condiviso gratuitamente su Makerworld e lo vedete nella foto successiva.
Nota sulle guide DIN
Le guide DIN in acciaio vanno sicuramente bene se le installate in armadi. Se invece vi realizzate a casa un harness stampato in 3D come quelli che ho consigliato, sappiate che questi oggetti 3D sono progettati per alloggiare guide DIN che abbiano i bordi dritti, secondo standard, quindi angoli di piegatura perfettamente a 90° e, in tal caso, la scelta migliore sarebbero le guide in alluminio che hanno i bordi perfettamente dritti.

Le guide in ferro/acciaio non sono fuse in un solo blocco come in genere avviene per quelle in alluminio ma vengono realizzate per pressopiegatura da una piastra per cui hanno gli angoli di piegatura leggermente ricurvi ed entrano nelle stampe 3D solo martellandocele dentro con forza: se scegliete questa strada vi avviso che non potete stampare gli stand utilizzando il PLA a prescindere (che non andrebbe usato soprattutto nel caso dello stand con il connettore IEC, per il quale andrebbe usato un materiale ignifugo) dato che andando a martellare la guida in acciaio dentro, si spaccherebbe. Io ho usato sia le guide in alluminio che quelle in acciaio, ma le mie preferite rimangono quelle in acciaio, che ho martellato nelle stampe 3D in PET-G (con pareti triple) senza problemi. Anche se il PET-G non é ignifugo ma sono cose che uso per sperimentare e quindi ci sto sempre davanti, con un estintore affianco.
Informazioni preliminari
Il sensore scelto comunica in Modbus RTU su linea RS485, per cui in uscita, anche se utilizzate, ad esempio adattatori RS485/USB, non vi ritroverete nulla su un qualsiasi software emulazione terminale qualsiasi in quanto il dispositivo va interrogato in maniera opportuna: ecco perché ho messo SSCom tra i software consigliati nonostante lo trovi un bel po’ incasinato ma permette di salvare una serie di comandi in file di configurazione e quindi inviarli e tenerseli conservati e in piú consente di comunicare sia in locale (RTU) che in remoto (TCP), ma sicuramente OpenModScan é piú semplice da utilizzare in quanto specifico per protocollo Modbus ed usabile anch’esso sia da locale che da remoto.
In realtá questo sensore potrebbe comunicare anche in UART e fornire i dati in continuo, ma non prenderó in considerazione questa opportunitá perché non mi serve
Come dicevo nella premessa non forniró qui informazioni su come funziona il protocollo Modbus, né su come funziona una linea fisica RS485 (ricordo: RS485 non é un protocollo ma un modo, fisico, di trasmettere i dati, mentre Modbus é un protocollo, ovvero la lingua e il modo di scambiarsi le informazioni, tra due o piú dispositivi) per cui assumo in partenza che giá abbiate conoscenza di questo mondo che sarebbe davvero lungo per me da descrivere in un singolo tutorial.
Analogamente assumo abbiate giá conoscenza di Node-Red (come/dove si installa, come creare dashboard, come scrivere flussi ecc) eventualmente decidiate di seguire questa strada che, ripeto, é del tutto soggettiva e personale ma é la mia preferita in quanto, anche se con una curva di apprendimento un po’ piú alta rispetto ad altri sistemi e che richiede molto lavoro, é sicuramente quella che mi ha sempre risolto qualsiasi problema di interfacciamento uomo-macchina. Ma ad ogni modo é chiaro che i dati da una linea RS485+Modbus li potete prendere come meglio ritenete opportuno e magari leggere il paragrafo relativo a Node-Red solo per avere delle informazioni in piú.
Sensore XY-MD02
Ho scelto questo perché avevo bisogno di un sensore che si interfacciasse direttamente in Modbus e fosse preferibilmente in un contenitore munito di scanalatura per guida DIN: facendo delle ricerche viene fuori praticamente solo questo! All’interno la stragrande maggioranza dichiara di avere un SHT20, ma in realtá io l’ho comprato per SHT20 e invece dentro ci é uscito un SHT40 (l’SHT20 é difatti dichiarato dalla Sensirion Not Reccomended for New Design in quanto c’é il modello nuovo e quindi le scorte del modello vecchio finiranno).
Gli SHT20/30/40 sono prodotti dalla Sensirion e se ne parla generalmente molto bene, ad ogni modo qualsiasi sensore che sia contemporaneamente sensibile sia all’umiditá che al calore soffre di autoriscaldamento: chi piú e chi meno. Questi della Sensirion li reputo abbastanza buoni da questo punto di vista e comunque l’XY-MD02 ha a bordo un micro a 32bit che immagino esegua anche tutta una serie di compensazioni e calcoli per fornire un dato stabile e veritiero e poi sta soprattutto a noi cercare di avere delle misure congrue posizionando il sensore in un’area che abbia una certa ventilazione e sicuramente al riparo da sole, fonti di calore dirette e acqua, dal momento che il sensore non é certo impermeabile. Per quello che mi riguarda ho fatto delle comparazioni della temperatura insieme ad una DS18B20 e onestamente non trovo differenze esagerate.
Il sensore in oggetto rispetta lo standard Modbus RTU ed esce su linea RS485. Queste sono le caratteristiche salienti:
- Tensione di alimentazione: 5 ~ 30V
- Indirizzo Modbus: default 1, modificabile fino a 247
- Range temperatura: -40°C ~ 60°C
- Precisione temperatura: ±0.5°C
- Risoluzione temperatura: 0.1°C
- Range umiditá: 0~80%UR
- Precisione umiditá: ±3%UR
- Risoluzione umiditá: 0.1%UR
- Baudrate di default: 9600
I fili si collegano mediante 4 screw terminals a innesto (che possono cioé anche essere rimossi), che é una delle soluzioni che preferisco.
I valori di temperatura e umiditá sono contenuti negli input registers, rispettivamente 1 e 2 (quindi 3×0001 e 3×0002 usando la notazione Modicon in esadecimale, oppure 30001 e 30002 in decimale, che personalmente odio ma purtroppo é ancora largamente usata sui manuali per cui bisogna abituarcisi!); la lettura dei valori si fa utilizzando il function code 4 (read input registers).
I valori sono signed 16bit (-32768 ÷ 32767) moltiplicato 10, per cui la lettura si fa utilizzando il complemento a due nel caso il valore sia negativo: se il bit piú significativo é 0 (ovvero valori inferiori a 0x8000), allora il numero é positivo e si legge tal quale, se il bit piú significativo é 1 allora il numero é negativo: si invertono tutti i bit (XOR 0xFFFF) e si aggiunge 1. E nel caso del nostro sensore si divide anche per 10. Esempio:
- Temperatura= 0x0131 (é positivo) => 305 in decimale => il valore di temperatura é 30.5°C
- Temperatura= 0xFF33 (é negativo in quanto superiore a 0x8000) => 0xFF33 XOR 0xFFFF = 0x00CC (204 in decimale) => aggiungo 1 = 205. La temperatura é -20.5 °C
Per l’umiditá abbiamo la stessa cosa, ma nel caso dell’umiditá non esistono valori negativi per cui il valore restituito é sempre positivo oppure semplicemente consideriamo i registri come unsigned int16. Non preoccupatevi perché poi piú in basso faccio un esempio di lettura con Node-Red in cui vi illustro anche qualche chicca che magari non conoscete.
Altro registro importante é quello dell’indirizzo che potremmo scegliere di modificare in quanto magari, sulla stessa linea RS485, vorremmo poter mettere piú sensori oppure potrebbero coesistere altri apparati. L’indirizzo é contenuto nell’holding register 0x0101 in esadecimale (quindi 4×0101 o 40257 in notazione modicon o semplicemente 257 in decimale) per cui possiamo leggerlo con il function code 3 (read holding register) o modificarlo con il function code 6 (write holding register). Piú in basso faccio un esempio di cambio indirizzo.
Il manuale di questo sensore chiama Keep Register gli Holding Register: come tutte le questioni riguardanti il modbus, ognuno utilizza nomenclature che piú gli piacciono
Esiste un manuale completo con tutti i registri, anche se per un device del genere sono pochi, ma purtroppo non posso metterne qui il download, ad ogni modo si trova molto facilmente. Altro registro che potrebbe tornare subito utile é quello dove é contenuto il baudrate, ovvero l’Holding register 0x0102 (258): il valore qui contenuto é 0 per il baudrate di default 9600, 1 per 14400 e 2 per 19200.
Inutile ricordarlo: ma tutti i device sullo stesso bus devono essere configurati con lo stesso baudrate.
Teardown XY-MD02


A bordo cé un ARM-Cortex M0 (32bit – questo)

Gateway PUSR USR-DR164
Il dispositivo in oggetto, molto economico ma che funziona benissimo, riceve in ingresso una linea RS485 e trasferisce i dati via Wi-Fi in vari modi: quello che interessava a me era convertire una linea di comunicazione Modbus RTU in Modbus TCP utilizzando il Gateway come Master Station. Il DR164 scelto fa la conversione in automatico e dalle interfacce basta semplicemente collegarsi all’indirizzo IP del gateway (o al nome host) e quindi avviare una comunicazione Modbus semplice passando l’indirizzo del device con il quale si vuole comunicare (quello del sensore nella fattispecie).

Il grosso vantaggio della comunicazione Modbus TCP é che nei frame manca tutta la parte di checksum del dato dato che i controlli di errore vengono giá eseguiti dal protocollo TCP. Questo piccolo ma potente Gateway della PUSR puó restituire i dati in svariati modi (anche via MQTT!) e operare sia come Station che come Access Point che come entrambi contemporaneamente!
Onestamente non ho testato tutte le modalitá perché avevo necessitá di andare dritto al punto, senza perdere tempo. Per quello che mi serviva posso dire che funziona egregiamente ed é anche facile da configurare. Tutte le informazioni su questo dispositivo le trovate sulla pagina ufficiale del prodotto.
Il DR164 ha la scanalatura per l’aggancio su Guida DIN e va alimentato con una tensione continua da 5 a 36V. I fili si collegano mediante terminali a molla: il filo si inserisce nel foro e rimane incastrato, poi per toglierlo si preme una levetta al di sopra. Anche qui il connettore é rimovibile. Purtroppo i fori per i fili sono davvero piccoli e la cosa migliore é stagnarli prima: non ho trovato terminalini del diametro cosí piccolo.
Configurazione Gateway
Diamo alimentazione al DR164 e configuriamolo: la prima volta, da pc o da cellulare vediamo una rete Wi-Fi che si chiama USR-DR164-xxxx. Connettiamoci alla rete esposta dal Gateway: non c’é password, apriamo quindi il browser e digitiamo l’indirizzo ip 10.10.100.254. Qui si apre un pop-up che richiede nome utente e password: scrivere admin in entrambi i campi.
Andiamo nella sezione Work Mode e in Select Mode scegliamo STA mode : questa scelta ci consentirá di collegare il Gateway ad una rete Wi-Fi pre-esistente. Dopo aver fatto la selezione, premere sul tasto Save.

Passiamo quindi a STA Setting per impostare la rete Wi-Fi alla quale vogliamo che il dispositivo si colleghi:

Io qui ho scelto di ottenere l’indirizzo IP automaticamente: tanto successivamente per collegarmi direttamente al dispositivo posso digitare il nome host (USR-DR164USR-DR164) e posso usare anche il nome host per collegarmi ai device sulla sua linea RS485. Premere sul tasto Save.
Andiamo quindi in Serial Setting: qui le due cose essenziali da modificare sono il Baud Rate, che di default per il sensore scelto é 9600 e quindi in ModBUS Enabled bisogna fare la selezione Protocol Conversion altrimenti poi non funzionerá nulla. Premere sul tasto Save.

Andiamo quindi in Net Setting. Nel campo Protocol dobbiamo selezionare TCP-Server. In Port ID il DR164 ha di default il valore 8899: nulla vieta di utilizzarlo purché poi ce lo ricordiamo. Io per coerenza lo cambio sempre in 502 che é la porta riconosciuta universalmente come standard per il Modbus TCP ma, ripeto: non é necessario. Lasciamo invariati tutti gli altri parametri. Premere sul tasto Save.

La configurazione é terminata. Andiamo alla voce Reboot e premiamo il tasto Restart. Aspettiamo che il dispositivo si riavvii: nel momento in cui si collega correttamente alla rete Wi-Fi che abbiamo impostato, diventa fisso in blu il led Link. A questo punto, eventualmente volessimo cambiare qualche parametro di configurazione, da un browser collegato alla stessa rete del gateway, possiamo digitare il nome host: http://usr-dr164usr-dr164/ : fatelo questo passaggio perché ci assicura che il dispositivo é accessibile dalla rete locale ed é necessario per poterci poi collegare successivamente per leggere i dati dal sensore di umiditá e temperatura.
Eventualmente non riuscissimo a collegarci al device dal nome host perché qualcosa va storto con il servizio di DNS locale, possiamo ricorrere a software gratuiti come Advanced IP scanner, fargli scansionare la rete, trovare nella lista il nostro device e recuperarne quindi l’indirizzo IP (e a questo punto metterlo fisso). Ad ogni modo anche a me capita che il led blu “Link” sia fisso (il che vuol dire che il device é correttamente collegato alla rete) ma non riesco ad accedervi subito dopo averlo acceso: in genere dopo 4/5 minuti riesco ad accedervi: non é un problema del dispositivo ma della rete.
Nel caso in cui ci siano problemi di configurazione che ci impediscono di accedere al Gateway, possiamo sempre resettarlo alle impostazioni di fabbrica tenendo premuto per almeno 4÷15 secondi il tastino laterale.
Come cambiare il nome host al device, soprattutto nel caso in cui avessimo sulla stesse rete piú di un dispositivo simile? Purtroppo attualmente non si puó fare: non c’é questo parametro di configurazione. In tal caso bisogna assegnare IP fisso ai dispositivi.
Collegamento
Il sensore, almeno in questa fase, non va configurato perché ci stanno bene tutti i parametri di default: ovvero baudrate di 9600 e device id=1. Quindi non dobbiamo fare altro che collegarlo al Gateway e all’alimentazione: Terminale B- del sensore a terminale B del DR164 e terminale A+ del sensore con terminale A del DR164. Tutto qui.
Lettura dei valori da OpenModScan
Facciamo un test preliminare con OpenModScan . Dal menú Connection clicchiamo Connect

In Connect Using selezioniamo Remote TCP/IP Server e impostiamo indirizzo e porta del Gateway:

Come vedete io in IP Address ho messo il nome host e in Service Port ho messo la porta (502) che ho scelto nella configurazione del DR164. Premere quindi OK. A questo punto OpenModScan giá avvia la connessione ma chiaramente leggeremo un errore nell’area terminale. Nella finestra in basso (ModSca1) assicuriamoci che Address Base sia 0-based, mettiamo quindi 1 in Start Address (per dirgli che intendiamo leggere i dati a partire dal registro 1) e 2 in Length (per indicare che vogliamo leggere due registri di seguito, registro 1 incluso – quindi registri 1 e 2). In Device Id lasciamo 1 perché non abbiamo ancora cambiato l’indirizzo di default del sensore, e in Modbus Point Type va selezionato il Function Code corretto per accedere al giusto banco di registri: come dicevo sopra i valori che ci interessano si trovano negli Input Register per cui il Function Code per eseguire la lettura di tali registri é il 04:

Adesso vediamo che nella finestra terminale appaiono i due registri con la notazione Modicon in decimale (ovvero preceduti dal numero che identifica il tipo di registro) seguiti dal valore del registro a 16 bit scritto in binario. Dalla barra degli strumenti sopra clicchiamo sul tastino i16, che converte la lettura in Integer 16bit:

I valori adesso appaiono in decimale:

e vediamo che il registro 1, che contiene la temperatura, ci dice che ci sono 16.1°C mentre il registro 2, che contiene l’umiditá relativa, ci dice che l’umiditá é del 71.3%. Semplicissimo no? Adesso vediamo come leggere questi dati da Node-Red e mostrarli su una dashboard.
Lettura valori da Node-Red
Creiamo un nuovo Flow con questa struttura:

In pratica la sequenza di nodi da inserire e collegare é Timestamp → Funzione → Modbus Flex Getter. Quindi dal primo output nodo Modbus Flex Getter abbiamo un primo collegamento a Funzione → Text e un secondo collegamento diretto ad un’altro nodo Text.
Come detto sopra sto usando la Dashboard 2 di Flowfuse (@flowfuse/node-red-dashboard precisamente nell’ultima versione attualmente disponibile, 1.30.1), per cui tutti i nodi di interfaccia sono totalmente diversi da quelli di altre dashboard. Ho chiamato i nodi Text (ui-text) come Label perché per me una Label, concettualmente, é piú rappresentativa di un campo di testo non editabile rispetto alla dicitura Text che é troppo generica. Chi ha programmato in Visual Basic puó capirmi.
Il Timestamp va impostato per inviare un payload qualsiasi dopo un po’ e quindi triggerare di continuo ogni 2 secondi oppure ogni quanto ritenete opportuno aggiornare i valori di temperatura e umiditá:

Il successivo nodo funzione l’ho messo per costruire un payload adatto da inviare al nodo seguente Modbus Flex Getter. In realtá avrei potuto tranquillamente omettere questo nodo funzione e utilizzare invece un nodo Modbus Getter (quindi non flex) preconfigurato, oppure, solo per fare dei test, un nodo Modbus Read (che é possibile triggerare solo manualmente e quindi non é usabile per fare la richiesta automatica ogni x secondi): ma é bene imparare ad usare il Flex Getter, perché come dice il nome, é flessibile e ci consente di avere un codice piú pulito specie se bisogna interrogare molti endpoint modbus. Preparo quindi il payload per il Flex Getter all’interno del nodo funzione in questo modo:

In pratica il payload conterrá 4 sotto-valori il cui nome non me lo sono inventato io ma fa parte della documentazione del nodo: le note che ho messo sono auto-esplicative e come vedete riflettono pari pari le impostazioni che abbiamo utilizzato poc’anzi in OpenModScan. Dopo aver composto il payload, il nodo funzione restituisce il messaggio verso il nodo successivo: Modbus Flex Getter.
Questo nodo va impostato per collegarsi al Gateway Modbus TCP che abbiamo configurato prima: il nostro DR164. La configurazione che andremo a salvare qui, come sapete se usate Node-Red, sará automaticamente disponibile anche in eventuali altri nodi, cosí come succede per i nodi MQTT o altri nodi che richiedano configurazioni di rete. Diamo doppio click sul nodo flex getter. Qui avremo, la prima volta, none come server: clicchiamo sul tastino + affianco per inserire un nuovo server:

Ci ritroviamo quindi la pagina di configurazione in cui inserire i dati del server TCP:
Specifico Server TCP, ma in realtá dal punto di vista del Modbus questo é un piú propriamente un Client (chiamato Master se invece comunichiamo in RTU), mentre, sempre dal punto di vista del Modbus, il Server (o Slave via RTU), é il sensore perché serve (fornisce) i dati. Si lo so, la notazione Modbus é un casino.

Nel campo Name io ho scritto il modello del mio Gateway: metteteci quello che vi pare. In Host va messo l’indirizzo IP o il nome host del dispositivo riconosciuto dal DNS resolver interno: come detto sopra se questo sistema non vi funziona, la cosa piú semplice é assegnare IP fisso e mettere qui l’indirizzo IP. Nel campo Port va messa la porta configurata nel Gateway: io l’ho cambiata in 502, se l’avete lasciata a 8899 allora scrivete 8899: basta che i numeri combacino in tutte le configurazioni. Tutto il resto non va toccato. Cliccate quindi il tasto rosso Update e venite riportati al settings principale:

Nel campo Server ora compare il segnaposto che avete scritto in Name nella pagina precedente ad indicare che é stato selezionata quella configurazione. Premete il tasto rosso Done per concludere.
Adesso, solo per fare un test, possiamo mettere due nodi Debug ognuno su un’uscita del flex getter, giusto perché quando ci troviamo davanti un nodo con il quale non abbiamo mai lavorato, abbiamo bisogno di capire come tira fuori i dati. Andremo a creare quindi una cosa del genere:

debug 1 sulla prima uscita e debug 2 sulla seconda. Facciamo il deploy e, se tutto é configurato correttamente, nella finestra di debug cominciamo a vedere i dati che arrivano dalle due uscite:

Vediamo che dalla prima uscita viene fuori un payload che contiene un array: sono i due valori di umiditá e temperatura che ci interessano. Dalla seconda uscita abbiamo un payload piú complesso: viene restituito un oggetto composto da due elementi: data e buffer, espandiamo un attimo il responso per leggerne il contenuto:

Vediamo che il campo Data contiene i valori che ci interessano, ma con uno scalino in piú da percorrere, mentre il campo buffer é l’uscita grezza dei dati prelevati in esadecimale, in pratica i registri letti vengono spezzati in elementi ad 8 bit e restituiti separatamente (qualora ne avessimo bisogno in questo formato): gli elementi 0 e 1 sono la rappresentazione della temperatura (0x009A = 154 = 15.4°C) e gli elementi 2 e 3 l’umiditá (0x02E6 = 742 = 74.2%).
Si, il mio laboratorio é freddo e umido, ma non vi preoccupate perché ero appena entrato e subito dopo ho acceso la stufa. Ma non avete idea dei problemi che ho con i filamenti per la stampa 3D!
Ovviamente a questo punto é chiaro che i dati cosí come ci servono ce li andremo a prendere dall’uscita 1 senza complicarci la vita. Ritorniamo quindi alla situazione iniziale: se vogliamo i nodi di debug li possiamo anche lasciare. Aggiungiamo quindi un nodo Text (piú correttamente, data la dashboard che sto usando: ui-text), che serve a renderizzare del semplice testo non modificabile dall’utente, e andiamo a fare una magia dal momento che i nodi Text della Dashboard2 non hanno il campo Value Format come ce l’avevano invece i nodi text della vecchia dashboard (che nessuno ci vieta di utilizzare ma perché rimanere arretrati solo per questioni di pigrizia?).
Il linguaggio J – sonata?
Il dato di umiditá, cosí come quello di temperatura, ci arriva moltiplicato per 10, quindi innanzitutto dobbiamo dividerlo, giusto? In aggiunta per me, come per tutti gli ingegneri, fisici e matematici, un numero senza unitá di misura continua a rappresentare il nulla assoluto (a meno che non sia adimensionale, ovviamente), per cui voglio aggiungerci anche %UR (percentuale di umiditá relativa che non é proprio un’unitá di misura ma insomma ci siamo capiti).
Come fare su questo nodo dato che non abbiamo piú il campo Value Format che ci aiutava tantissimo nella dashboard vecchia ormai deprecata? Ma con il semplice campo Value impostato come expression ovviamente (anche se c’é da sbatterci un po’ di piú):

Quando il campo Value é formattato come expression qui dentro possiamo utilizzare le funzioni JSONata (avete notato che il logo é del tutto simile ad una chiave musicale?). Andremo a scrivere questa espressione:
$formatNumber(msg.payload[1]/10, '0.0') & '%UR' |
La funzione $formatNumber serve, appunto, per formattare un numero (si, le funzioni di sistema JSONata cominciano per dollaro): come primo parametro gli ho dato il secondo elemento dell’array-payload (che contiene il valore di umiditá) e l’ho diviso per 10, il secondo parametro é il pattern per la formattazione: scrivendo 0.0 gli ho detto di metterci un numero con un decimale (e mostrare lo zero decimale in ogni caso). Avrei potuto inserire l’unitá di misura anche qui dentro, ma purtroppo il simbolo di percentuale é uno specificatore di formato per cui mettendolo li dentro succede che moltiplico per 100 il valore. Quindi che faccio? Semplicemente lo concateno con l’operatore & e ci aggiungo anche UR. Sembra difficile ma pensandoci bene é sicuramente piú potente del sistema che avevamo nella vecchia dashboard in quanto qui dentro posso fare tutta una serie di cose micidiali.
Finiamo di configurare il nodo dandogli un nome, inserendo una label e soprattutto dicendogli in quale pagina e gruppo deve essere visualizzato (io ho creato una pagina di test chiamata Modbus con dentro un gruppo XY-MD02).

Ho scelto di visualizzare, centrati verticalmente, nome della label a sinistra e valore a destra. I piú esperti possono anche formattarsi il tutto con font, colori che vogliono e che cambiano in base al valore ecc ma non é questo l’argomento di oggi. Colleghiamo quindi questo nodo testo alla prima uscita del Modbus Flex Getter.
Avanti e Indietro
Dalle mie parti c’é un detto di cui in realtá non ho mai afferrato bene il concetto: chi fravc e sfravc nun perd maje tiemp (chi costruisce e demolisce non perde mai tempo) e mi é venuto in mente pensando a questa parte.
Per la temperatura, dato che come vi dicevo prima, potrebbero esserci valori negativi, dobbiamo ricorrere al complemento a due che vi ho spiegato prima: premetto che ci sono decine di sistemi per visualizzare il numero col segno in Node-Red, addirittura dei nodi specifici, ma scelgo di ricorrere ad un’altra curiositá tecnica che magari non conoscevate. Per questo motivo ho aggiunto un nodo funzione in cui faccio questa cosa:

Che ho fatto? Nella riga 1 prendo il valore del primo elemento dell’array-payload (temperatura) e lo memorizzo in una variabile. Quindi faccio prima uno shift a sinistra di 16 posizioni e poi prendo il risultato e lo shifto a destra di 16 posizioni. In pratica ho spostato il numero prima avanti e poi indietro dello stesso numero di posizioni: in qualsiasi linguaggio di programmazione, definito il tipo di variabile, questa é una ca**ata perché riottengo la stessa cosa.
Eh no amici miei…
NO!
NO!
Node-Red é Javascript e questo é uno dei tanti motivi per cui lo odio (ma uso Node-Red quindi intrinsecamente lo amo anche). In Javascript non esistono INT16, UINT16, INT8 ecc ecc: no…
Javascript é figo (?) e per lui l’unico tipo di numero intero esistente é quello che per noi programmatori ingenui si chiama INT32 che lui chiama amichevolmente number. Number, capito? (hey number! Tutto a posto bro?)
Vi spiego quello che succede in Javascript cercando di non imprecare ulteriormente. Prendiamo il numero che ho usato prima come esempio: 0xFF33, che dopo tutti i passaggi giá visti é venuto fuori che rappresenta una temperatura di -20.5°C. Scriviamolo in notazione binaria:

Noi umani semplici sappiamo che dobbiamo trattare questo numero come un intero (con segno) a 16 bit perché cosí ci ha detto il manuale del dispositivo. Automaticamente per noi questo é un numero negativo perché il bit piú significativo (quello piú a sinistra) é 1. Per Javascript quel numero non é scritto cosí come lo vediamo perché, come dicevo, per lui i numeri esistono solo a 32 bit con segno, quindi lui, il bro, lo legge in realtá cosí:

Ovvero con 16 zero prima che a te pare non siano significativi e invece lo sono! Trattandosi di un numero intero (con segno!) a 32 bit, quello zero la in cima conta eccome: il bit piú significativo ce l’avrá anche un motivo per meritarsi il sontuoso titolo di piú significativo, no? Quel bit vale zero, per cui per Javascript é (udite, udite): positivo! Quindi noi, che abbiamo studiato, che facciamo? Lo mandiamo avanti e indietro! Lo bitshiftiamo a sinistra di 16 posizioni e otteniamo questa roba qui (ho evidenziato il numero originale per farvi capire meglio):

Adesso abbiamo ottenuto chiaramente un numero totalmente diverso raggiungendo un obiettivo importante: il bit piú significativo del nostro intero iniziale a 16 bit, adesso é salito di grado ed é diventato il bit piú significativo del numero a 32 bit. Javascript vede quindi questo numero come negativo, sebbene legga, giustamente, un numero totalmente diverso dal primo. Adesso rispediamo tutto al mittente: spostiamo di nuovo tutto a destra sempre di 16 posizioni:

Cosa é successo? Una cosa abbastanza logica. Gli operatori shift a destra e shift a sinistra sono operatori bitwise: operano sui bit, non sul segno! Il segno quindi, durante queste operazioni, va preservato, e pertanto non viene intaccato dal bitshift, per cui spostando a destra succede questa cosa che tutti gli spazi vengono riempiti di 1 in modo che col complemento a due poi ci troviamo il risultato atteso!
Alla fine otteniamo il decimale 4.294.967.091 (0xFFFFFF33 in esadecimale) che, facendo il complemento a due (cosa su cui Javascript non ha nemmeno bisogno di pensare perché tanto per lui tutti i numeri interi sono con segno a 32 bit, a prescindere):
4.294.967.091 = 0xFFFFFF33 ⇒ 0xFFFFFF33 XOR 0xFFFFFFFF = 0xCC = 204 ⇒ 204+1 = 205 ⇒ – 205 ⇒ – 20.5°C
A voi sembra che abbiamo fatto un casino ma le operazioni bitshift sono praticamente istantanee e questa roba qui ci mette niente per essere realizzata. Alla fine dopo aver cambiato in qualche modo il mio numeretto iniziale per far capire a Javascript che quel maledetto numero era un intero a 16 bit col segno, restituisco in uscita dal nodo funzione il messaggio col payload aggiornato e lo mando nel nodo testo facendo piú o meno la stessa cosa che ho fatto per l’umiditá: invoco una funzione JSONata per formattare il numero come piace a me:
$formatNumber(msg.payload[0]/10, '0.0 °C') |
qui, dato che il simbolo di grado e la lettera C non sono tipi complicati come invece lo é il segno di percentuale, li posso anche infilare nel parametro del formato, che tanto verranno tirati fuori tal quale.
Finiamo quindi di configurare il nodo UI-Text:

Abbiamo finito. Diamo il Deploy. Se non abbiamo commesso errori, possiamo andare nella pagina della dashboard (indirizzoip:porta/dashboard) e cliccare sulla voce di menú della pagina che abbiamo creato (Modbus) per visualizzare i dati anche sul nostro cellulare:

Cambiare indirizzo al sensore
Adesso che abbiamo messo in funzione tutto, approfittando del fatto di poter passare un doppino per la linea RS485 dovunque, sfruttando un Gateway modbus/Wi-Fi che ormai abbiamo giá acquistato… perché non pensare di ficcare sulla linea qualche altro sensore? Tanto, voglio dire, sul sito di shopping cinese costano poco e dopo tutto tanto male non sono, considerando che ora ci stanno mettendo anche l’SHT40 che é bellissimo.
Per fare questo bisogna ovviamente cambiare gli indirizzi ad ogni sensore, che di default hanno indirizzo 1, altrimenti creiamo un macello. Dal manuale e da quello che ho scritto prima, sappiamo che l’indirizzo é contenuto nel keep (holding!) register 0x0101 in esadecimale (257 in decimale) per cui possiamo modificarlo con il function code 6 (write holding register).
Abbiamo due strade o usiamo un adattatore USB-RS485 (con OpenModScan, con sscom, con quello che sappiamo usare) oppure continuiamo per la nostra strada con gli strumenti che giá abbiamo comprato, per cui cambiamo sicuramente indirizzo all’unico sensore che é giá sulla linea in modo da poterne inserire un altro che avrá di default indirizzo 1.
Ricorriamo di nuovo ad OpenModScan e prima di cambiare l’indirizzo… leggiamolo:

Come start address metto 257 per quanto detto prima e 1 come lunghezza/quantitativo in quanto voglio leggere solo quello e non eventualmente altri che ci sono dopo o che magari, non esistendo, possono causare un errore e bloccare anche la lettura del primo.
OpenModScan, nei campi di input numerici, accetta soltanto valori scritti in decimale
Adesso peró, come function code, metto 3 che sta per Read Holding Register. Nella finestra terminale mi appare quindi 40257 (registro 257 della “zona 4” – ovvero input registers) seguito da 1 (ho lasciato la visualizzazione come int16). Sappiamo che il device ha indirizzo 1. D’altronde ne eravamo giá certi perché altrimenti con device id diverso da 1 avremmo avuto solo errori.
Adesso cambiamo questo valore utilizzando il function code 6. Per le operazioni di scrittura in OpenModScan si ricorre ai tasti numerici in alto che riflettono i codici funzione:

Clicchiamo quindi il tasto con su scritto 06 e diciamo che nel device Node 1, all’indirizzo 257 vogliamo metterci il valore 2. Premiamo ok. Automaticamente questa finestra si chiude e nel terminale vediamo subito:

Nel registro 40257 adesso c’é il valore 2, ma continuiamo a leggere senza problemi nonostante il device id sia ancora impostato sul valore 1. Chiaro: i valori dei parametri dalla eeprom vengono caricati in ram all’avvio. Nel registro c’é 2 ma il device ancora non lo sa, e continua a essere 1. Togliamo corrente al sensore e alimentiamolo di nuovo: da adesso per leggere questo sensore dovremmo usare 2 come device id.
Ricordo che sia il primo elemento della catena RS485 (il gateway) che l’ultimo dovranno avere la resistenza di terminazione da 120Ω che questo sensore non ha ma la si inserisce facilmente dall’esterno sui morsetti a vite. Ricordo inoltre che sulla stessa linea RS485 possono essere messi fino a 32 dispositivi, master incluso.


