Ieri notte è mancata la corrente per 5 ore e mezza. Decisamente troppo anche per dei buoni gruppi di continuità. Purtroppo alcuni sistemi possono danneggiarsi quando si toglie di botto l’alimentazione. I gruppi di continuità fanno quello che possono, ma in un “Paese Civile” non ci si aspetta che, in piena notte, tutti i sistemi di un’intera zona industriale possano rimanere senza corrente per 5 ore e mezza. E’, come dire, disdicevole.
Avevo un vecchio progettino in garage e sono andato a riprenderlo. E’ molto semplice. Normalmente, sui gruppi di continuità, c’è già un sistema in grado di trasmettere (in qualche modo) la condizione di power-fail, ma spesso i drivers per intercettare questo avviso sono farraginosi e qualche volta, durante l’installazione, si rischia di bloccare l’intero sistema. Allora io, che amo le cose semplici, ho deciso di farmi un circuito che mi avvisi e che sia facile da gestire, con un programmino di controllo scritto da me medesimo.
Vediamo l’hardware: è composto di due sezioni. Questa è la prima
Occhio a non metterci le dita! C’è la tensione a 220V che vi può friggere!
E qui c’è la realizzazione pratica:
Si tratta di un circuito molto semplice. In pratica, si accendono due led in modo “transformerless” grazie alla reattanza di un condensatore, in una configurazione ben nota. I led coinvolti sono quello nell’optocoupler, che serve per lo stadio successivo, e l’altro visibile che serve sia per proteggere il precedente da tensioni inverse, sia come “monitor” per visualizzare la presenza della tensione di rete.
Ora passiamo alla seconda metà del circuito.
In pratica, se l’optocoupler è acceso (c’è corrente) il transistor si chiude e quel che accade è che qualsiasi segnale trasmesso sulla porta seriale viene immediatamente ricevuto (tx ed rx sono praticamente collegati tra loro). Se il transistor non conduce, è segno di mancanza di rete e il led è spento e quindi non avremo più l’eco dei caratteri trasmessi. Ecco la seconda parte del circuito, con una interfaccia usb-seriale “very low cost” collegata:
Molto semplice. Con qualsiasi computer, se si riesce a controllare la porta seriale (non mi è mai capitato di avere difficoltà) si può scrivere un programmino che invii un pacchetto di dati sulla usb-serial e verifichi che questi siano subito ricevuti. Se lo sono, la tensione di rete c’è. Se non lo sono, siamo in power-down e dobbiamo fare qualcosa. Possiamo mandare una email all’amministratore e quindi fare uno shutdown pulito, oppure possiamo aspettare un po’ per vedere se la tensione ritorna, ma tutto sarà veramente facile. Si tratterà solo di scrivere un banale programmino di controllo e i drivers da aggiungere al sistema saranno quelli idonei per l’interfaccia seriale che useremo.
Nel caso in cui il nostro sistema disponga di pin di I/O (tipo una Raspberry PI), allora potremo cambiare completamente filosofia e usare il circuito che segue:
In questo caso, la mancanza di corrente porterà un livello basso sul collettore del transistor e quindi sarà facile scrivere un programmino che verifichi lo stato della linea e decida di conseguenza le operazioni da fare. Si noti il pulsante, che permette di fare uno shutdown pulito anche manualmente.
Ecco un’immagine del circuito montato su una scheda per prototipi:
Questo è cio che vediamo sul morsetto d’ingresso quando il circuito a 220V è alimentato:
Ho scritto un piccolo programmino in Python per realizzare quanto voluto, cioè spegnere la Raspberry PI se la tensione di rete (a 220V) manca per un minuto. Questo è il listato (molto minimalista)
import RPi.GPIO as GPIO import time from subprocess import call cnt = 0 # reset counter for pushbutton pressed GPIO.setmode(GPIO.BCM) # set GPIO mode while True: # main loop GPIO.setup(4, GPIO.OUT) # GPIO.4 set as output GPIO.output(4, False) # GPIO.4 output set at low level (led ON) time.sleep(0.2) # 200mS pause with led ON GPIO.setup(4, GPIO.IN, pull_up_down = GPIO.PUD_OFF) # GPIO.4 is input, no pull-up for n in range(0,2): # exec twice time.sleep(0.1) # wait for 100 mS prior to read GPIO.4 status if GPIO.input(4): # if GPIO.4 is high (no power-fail, no button pressed) cnt = 0 # reset counter else: # if GPIO.4 is low (power-fail or button pressed) cnt += 1 # increment counter if cnt >= 120: # if continuously LOW for 60 seconds (cnt increments 2 times in a second) call("sudo poweroff", shell=True) # terminate and shutdown break time.sleep(0.6) # if not poweroff, wait the remaining time for 1 Sec main cycle
Questo file viene salvato come ‘service.py’ nella cartella /home/pi. Per avviarlo automaticamente al boot, dovremo dare da terminale il comando ‘sudo crontab -e’ e aggiungere alla fine del file la linea:
@reboot sudo python /home/pi/service.py &
Come si vede dal listato, ho usato la linea GPIO4 e ho aggiunto anche un led rosso, per fare da monitor del funzionamento del programma. Il led si accenderà lampeggiando se la tensione di rete è presente, altrimenti diventerà a luce fissa e dopo un minuto -continuativo- di mancanza di tensione, verrà eseguito lo shutdown. ATTENZIONE: se abilitate il programma di controllo e non avete l’hardware collegato, la Raspberry si spegnerà un minuto dopo l’avvio, perché leggerà (in assenza di circuito) un livello basso sul pin di test. Quindi, per fare le prove software con tranquillità, mettete una resistenza da 10K tra il pin GPIO4 e il +3.3V, come hardware di simulazione minimale.
Questo è lo schema modificato con il led (il pulsante si può mettere oppure no, a scelta):
Naturalmente, per eseguire lo shutdown dopo un minuto dalla mancanza di tensione, è necessario che la Raspberry PI sia alimentata da un sistema con batteria! Vi invito a leggere un mio vecchio articolo (in Inglese, ma c’è il traduttore a fondo pagina) che spiega come realizzare questa cosa con relativa semplicità. Trovate l’articolo a questo link:
Single 3.7V Li-ion cell battery back-up for Raspberry Pi
Ecco una vista d’insieme del circuito di test in fase di collaudo:
Notate il piccolo connettore montato sui primi pin della Raspberry PI. I segnali utilizzati sono +3.3V, +5V, GND e GPIO4
Mentre il circuito del monitor di rete è PERICOLOSO e non si può toccare (deve essere ben chiuso e isolato) la parte dopo il fotoaccoppiatore non è problematica. Siamo isolati dalla tensione di rete e quindi non ci sono problemi. Io ho messo la parte “pericolosa” all’interno di una lucina notturna comprata per un euro in un negozio (poi smontata e adattata allo scopo) e ho portato fuori con un cavo la sezione isolata dell’optocoupler.
Ora, veniamo all’applicazione che usa l’eco sulla seriale, per dispositivi (tipo notebook) in cui non possiamo usare un pin di I/O per verificare lo stato di un segnale. Ho scritto un programmino usando Gambas2 (una vecchia versione) che gira sul mio vecchissimo notebook con S.O. Puppy Linux 4.3.1 e qui c’è il listato:
' Gambas module file '------------------- ' last update: 2021/07/25 ' PUBLIC gbComm1 AS NEW SerialPort PUBLIC SUB Main() DIM rxd AS String = "" ' rx buffer for COM port DIM cnt AS Integer = 0 ' num of rx errors PRINT ": Service started: "; Now() TRY CLOSE gbComm1 ' try close the com if open gbComm1.PortName = "/dev/ttyUSB0" ' com name default - change if needed gbComm1.FlowControl = 0 gbComm1.DataBits = 8 gbComm1.StopBits = 1 gbComm1.Parity = 0 gbComm1.Speed = 38400 PRINT "> Open Com port: " & gbComm1.PortName & " speed: " & gbComm1.Speed TRY gbComm1.OPEN() ' open comm port IF ERROR THEN ' if port error PRINT "#ERR: Com port not available" QUIT ' terminate for unrecoverable error ENDIF WHILE 1 ' loop forever (ctrl-c to quit) READ #gbComm1, rxd, Lof(gbComm1) ' flush rx queue PRINT #gbComm1, "AT" ' send AT to com port PRINT "tx: AT" WAIT 1 ' delay 1000 mS READ #gbComm1, rxd, Lof(gbComm1) ' read echo IF InStr(rxd, "AT") > 0 THEN ' echo received cnt = 0 ' reset error counter PRINT "rx: AT" ' console print rx data ELSE ' no echo (power-fail) cnt = cnt + 1 PRINT "rx=["; rxd; "] cnt="; cnt ' console print rxd and error counter IF cnt >= 60 THEN ' if one minute without echo SHELL "wmpoweroff" ' shutdown command in Puppy Linux ENDIF ENDIF WEND TRY CLOSE gbComm1 ' close com PRINT ": Service terminated: "; Now() ' service closed END
Si tratta di una versione elementare, giusto per dare un’idea. Come nella versione in Python, anche qui, se manca alimentazione di rete per un minuto, il sistema va in shutdown. In questo caso, trattandosi di un notebook, l’alimentazione è garantita dalla batteria interna, per il tempo necessario.
Con questo concludo. Al prossimo “progetto del weekend” ! 🙂