Non ci sono prodotti a carrello.
Utilizziamo la scheda FT1060M e l’applicazione didattica descritta nel libro “Raspberry Pi il mio primo Linux Embedded” con il micro PC PcDuino. Un esercizio di “porting” di un’applicazione tra due sistemi con l’analisi e la risoluzione delle differenze.
Chi ha seguito la serie di articoli sulla rivista, dedicati a RaspberryPi si ricorderà che avevamo previsto la crescita e la diffusione dei dispositivi in miniatura ARM RISC che possono funzionare con GNU/Linux. Quello che non avevamo previsto è stato il fatto che, più che di crescita, possiamo parlare di esplosione, cioè dell’arrivo sul mercato di dispositivi eterogenei, con caratteristiche diverse e che richiedono differenti procedure per “addomesticarli” all’utilizzo del sistema operativo GNU/Linux.
Nell’articolo sul numero 177 di ElettronicaIn abbiamo presentato una panoramica delle schede disponibili, con particolare attenzione alla loro utilizzabilità in ambito didattico e alla presenza o meno di espansioni GPIO, che le rendono appetibili per un utilizzo “embedded”.Tra le schede presentate ci siamo soffermati su PcDuino, una soluzione “ponte” tra il mondo GNU/Linux ed il mondo Arduino, e quindi particolarmente adatta a chi, avendo già acquisito esperienza in quest’ultimo ambiente, voglia affrontare l’ulteriore impegno di approfondire il mondo GNU/Linux.
Vi proponiamo di familiarizzare con l’utilizzo “embedded” di questa scheda utilizzando la scheda didattica FT1060M ed i contenuti del libro “Raspberry Pi – Il mio primo Linux embedded”. In questo documento sono descritte le sole differenze tra le operazioni descritte nel libro e quelle da eseguire utilizzando la scheda PcDuino.
PcDuino
PcDuino è un mini PC, in formato scheda di sviluppo, basato sul SoC Alllwinner A10, dotato di CPU ARM Cortex A8 da 1 GHz. La sua particolarità è la presenza di un’espansione GPIO che rispecchia la disposizione dei pin e la nomenclatura dei pin di Arduino Uno, ed in particolare:
- Fino a 13 pin di I/O digitali, molti dei quali, ovviamente, possono essere configurati per esprimere altre tipologie di interfacce;
- Fino a 6 pin di ingressi Analogici/Digitali, due dei quali, ADC0 e ADC1, hanno una risoluzione a 6 bit, gli altri hanno una risoluzione a 12 bit;
- Sono presenti due uscite PWM hardware, PWM1 e PWM2, che possono generare frequenze fino a 24Mhz, gli altri PWN sono simulati dal GPIO e possono generare frequenze fino a 100 Hz, non molto accurate;
- Un’interfaccia I2C;
- Un’interfaccia SPI.
Una nota importante sulle tensioni di riferimento. I livelli di tensione dei pin GPIO e dei bus di comunicazione sono a 3,3V, pertanto è importante tenerne conto, soprattutto nel caso di utilizzo di shield compatibili Arduino. Ancora più importanti sono le tensioni di riferimento per i pin di conversione analogica digitale: i pin ADC0 e ADC1, con la risoluzione di 6 bit utilizzano una tensione di riferimento interna di 2 V, mentre gli altri pin utilizzano la tensione di riferimento di 3,3V.
Figura 1
La scheda nasce con a bordo già installata una distribuzione Ubuntu di GNU/Linux, della famiglia di Debian, Dal punto di vista dell’utilizzatore finale, secondo noi, è una bella comodità che permette di iniziare subito a sperimentare, come visibile in Fig. 1, con una dotazione di applicativi già disponibili e con prestazioni più che apprezzabili. Nel nostro “porting” abbiamo preferito utilizzare una distribuzione sempre Ubuntu, ma totalmente contenuta su SDCard, in modo da poter disporre di una maggior quantità di memoria “disco” e di poter “pasticciare” a piacere senza danneggiare l’installazione originale.
Per far questo sfruttiamo la funzionalità nativa in PcDuino, che consente di eseguire il boot da una SDCard, se questa contiene una partizione di boot ed una partizione di root valide. Oltre alla scheda, nella confezione è fornito l’alimentatore che funziona a 220V, ma possiede una spina di tipo americano a cui va applicato un adattatore. Inoltre sono presenti un cavo HDMI e un HUB USB relativo cavo USB.
Sulla scheda sono presenti (Fig. 2):
- Due porte USB Host;
- La porta Ethernet RJ45;
- Il connettore di alimentazione;
- Un connettore seriale per la console di debug;
- L’alloggio per la micro SDCard;
- Un piccolo pulsante di “reset”;
- I connettori del GPIO che descriviamo in seguito.
Per quanto riguarda l’utilizzo della scheda, abbiamo già anticipato che è equivalente all’utilizzo del sistema operativo di RaspberryPi, comandi a terminale e gestione dei pacchetti inclusi.
Ci soffermiamo al momento solo sulla gestione del GPIO. Si accede ai pin GPIO utilizzando i file descrittori come nell’esempio di accensione del LED presentato nell’articolo sulla rivista Elettronica In n. 168 dedicato a RaspberryPi. Nell’implementazione di pcDuino i file descrittori dei pin del GPIO si trovano nelle cartelle:
/sys/devices/virtual/misc/gpio/mode//sys/devices/virtual/misc/gpio/pin/.
Figura 4
Nella cartella visibile in Fig. 4: /sys/devices/virtual/misc/gpio/mode/
si trovano i file descrittori con i quali è possibile impostare le modalità di utilizzo di ciascun pin; sono previsti diversi valori, i principali sono:
• ‘0’ – imposta il pin di I/O come INPUT;
• ‘1’ – imposta il pin di I/O come OUTPUT;
• ‘8’ – imposta il pin di I/O come INPUT, attivando la resistenza di pull-up interna.
I valori dei pin di I/O vengono letti e scritti nei file descrittori corrispondenti nella cartella (Fig. 5): /sys/devices/virtual/misc/gpio/pin/
Figura 5
Ricordiamo che il livello alto dei pin corrisponde a 3,3 V e che la corrente fornita da ciascun pin non è paragonabile a quella fornita dai pin di Arduino, ma è comunque sufficiente a mantenere acceso un LED.
Se vogliamo utilizzare i pin che possono essere utilizzati come convertitori ADC possiamo leggere i loro valori nei file descrittori contenuti nella cartella /proc/ con nome adcx (Fig. 6) dove “x” indica il pin ADC desiderato, da 0 a 5.
Figura 7
In Fig. 7 possiamo vedere il risultato delle letture degli ingressi ADC dove è possibile verificare che ADC0 e ADC1 hanno una risoluzione a 6 bit mentre i rimanenti l’hanno a 12 bit. Infine possiamo impostare i valori dei pin che forniscono funzionalità PWM, utilizzando i file descrittori nelle cartelle:
/sys/class/leds/pwmx/brightness
Figura 8
Figura 9
(Fig. 8), dove anche in questo caso “x” indica il pin PWM desiderato, da 0 a 5.
Per impostare il valore PWM si scrive il valore desiderato nel file descrittore “brightness” nella cartella corrispondente al PWM richiesto (Fig. 9):
per ciascun pin si possono impostare valori che vanno da 0 al valore contenuto nel file:
/sys/class/leds/pwmx/max_brightness
diverso per ogni uscita (Fig. 10):
Per quanto riguarda l’utilizzo del bus i2C, utilizzando il linguaggio python vale quanto descritto negli articoli dedicati a Raspberry Pi, con l’utilizzo della libreria “smbus”. Per la comunicazione SPI, sempre in python, è disponibile la libreria SPI-Py.
Molte informazioni, manuali, guide (in inglese) e file da scaricare si trovano sul sito dedicato a PcDuino all’indirizzo:
http://www.pcduino.com
CREIAMO LA SDCARD CON GNU/LINUX (CAPITOLO 4)
La procedura per l’installazione di GNU/Linux sulla SDCard prevede l’utilizzo del tool Win32DiskImager che permette di trasferire sulla SDCard stessa il sistema operativo che si desidera utilizzare a partire da un file che contiene il sistema operativo stesso in formato immagine .img. Abbiamo descritto questa operazione sia negli articoli precedenti dedicati a Raspberry Pi che nel libro, al quale rimandiamo per il completamento dell’operazione. Andiamo al sito di PcDuino, nel pannello “Download”, nella sezione “OS Images – Ubuntu” selezioniamo il link al sistema operativo Ubuntu SD Bootable Image che al momento della scrittura di questo documento riporta la data di creazione “05-31-2013”. Dopo avere scaricato il file creiamo la SDCard come descritto nel capitolo 4 del libro.
ACCENDIAMO PCDUINO (CAPITOLO 5)
Abbiamo accennato in precedenza che PcDuino non è dotato di un’uscita audio, quindi se vogliamo attivare anche le funzioni di gestione messaggi della nostra applicazione dobbiamo necessariamente utilizzare l’uscita audio del canale HDMI. Per fare questo dobbiamo collegare a PcDuino un monitor HDMI, utilizzando l’apposito cavo, per collegare l’uscita HDMI di PcDuino all’ingresso del monitor. Poi inseriamo nell’apposito slot la SDCard con il sistema operativo che abbiamo appena creato.
Colleghiamo il cavo di rete ad una presa di rete del nostro router domestico ed infine … l’alimentazione inserendo il cavo in uscita dall’alimentatore con una presa micro USB nell’ingresso PWR di PcDuino (quello vicino alla presa di rete).
Partirà la solita sequenza di avvio con i messaggi di console per terminare con l’apertura della videata di login del desktop. Autentichiamoci con userid “ubuntu” e password “ubuntu”. Ora apriamo una sessione terminale e digitiamo
ifconfig
Prendiamo nota dell’indirizzo IP assegnato alla scheda Ethernet eth0 ed utilizziamolo per aprire una sessione Putty ed una WinSCP.
Possiamo approfittarne per dare un IP statico a PcDuino in modo da non dover successivamente adattare di continuo i riferimenti IP per collegarsi a PcDuino e per la gestione di server e programmi. Attiviamo l’utente root in Putty, con il comando:
sudo passwd
ci verrà richiesta per due volte una password da assegnare all’utente root, noi abbiamo impostato “root”, per semplicità. Non stiamo presentando un corso sulla sicurezza dell’ambiente GNU/Linux.
Ora apriamo una sessione WinSCP con l’utente root e la relativa password. Andiamo alla cartella
/etc/network
apriamo il file “interfaces” e configuriamolo come segue, ovviamente utilizzando le configurazioni IP compatibili con le caratteristiche della rete gestita dal nostro router.
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.0.43
netmask 255.255.255
0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.0.254
Salviamo e chiudiamo il file, probabilmente ci verrà richiesta la password di root. Ora, nella cartella /etc apriamo il file
resolv.conf
e configuriamolo con l’aggiunta delle due righe:
nameserver 8.8.8.8
nameserver 8.8.4.4
Questa configurazione non si conserva tra due accensioni e spegnimenti. Nel prosieguo dell’articolo descriveremo come ovviare a questa situazione.
AGGIORNIAMO PCDUINO
Nella sezione di Download del sito http://www.pcduino.com sono presenti le release complete dei sistemi operativi disponibili per PcDuino ed anche eventuali upgrade e release note. Al momento attuale è possibile consultare le release note al link (o successivi):
Ubuntu Update 08-06-2013
Salvo diversamente indicato nelle istruzioni, gli update alle release di Ubuntu per PcDuino possono essere installate on il comando:
apt-get install pcduino
In assenza di release note, per aggiornare e configurare le feature di PcDuino utilizziamo il comando:
board-config.sh
che presenta un menu di configurazione molto simile a quello di Raspberry Pi (Fig 11):
ACCENDIAMO UN LED (CAPITOLO 7)
A questo punto, se lo desiderate, potete eseguire l’esercizio di accendere un LED tramite la gestione di un pin GPIO. Proviamoci, e senza scrivere una linea di codice. Prima però, da bravi elettronici, spegniamo PcDuino con il comando:
shutdown –h now
oppure, più bruscamente:
halt
Togliamo tensione e colleghiamo un LED rosso con in serie una resistenza da 120 Ohm tra il pin GPIO4 del connettore di PcDuino, e la massa GND.
Controlliamo attentamente i collegamenti ed il verso del LED, per evitare errori e compromettere irrimediabilmente la scheda.
Riaccendiamo. Se abbiamo dato un IP statico a PcDuino, possiamo collegarci direttamente usando Putty o Kitty utilizzando. Per Putty utilizziamo l’utente “ubuntu”, in quanto, differentemente rispetto a Raspberry Pi i processi ed i programmi che utilizzano il GPIO non richiedono i privilegi di root per poter essere eseguiti correttamente.
Per attivare il driver di gestione del GPIO diamo il comando:
sudo modprobe gpio
Abbiamo già visto che ciascun pin del GPIO, usato come I/O è descritto dai file contenuti nelle cartelle:
/sys/devices/virtual/misc/gpio/mode/
/sys/devices/virtual/misc/gpio/pin/
per il GPIO4 useremo i file:
/sys/devices/virtual/misc/gpio/mode/gpio4
/sys/devices/virtual/misc/gpio/pin/gpio4
Per impostare il pin come output diamo il comando:
echo “1” > /sys/devices/virtual/misc/gpio/mode/gpio4
Ora verifichiamo lo stato del pin con il comando:
cat /sys/devices/virtual/misc/gpio/pin/gpio4
otterremo “0”
Ricordiamo di fare attenzione ai livelli: i pin GPIO NON tollerano tensioni superiori a 3,3 volt. Ora diamo un’occhiata al nostro LED e verifichiamo che sia spento, in quanto il valore del pin è “0”. Per accenderlo basta portare a “1” il livello del pin, con il comando:
echo “1” > /sys/devices/virtual/misc/gpio/pin/gpio4
Verifichiamo ora che il LED sia acceso.
Ce l’abbiamo fatta!.
Ora lo spegniamo col comando:
echo “0” > /sys/devices/virtual/misc/gpio/pin/gpio4
Per verificare il valore corrente usiamo il comando:
cat /sys/devices/virtual/misc/gpio/pin/gpio4
Per quanto riguarda l’ottimizzazione della configurazione descritta nel Capitolo 9, non abbiamo a disposizione gli stessi file di configurazione che ci fornisce il Raspbian di Raspberry Pi e quindi le nostre possibilità di intervento sono alquanto limitate.
Rispetto a Raspberry Pi alcuni pacchetti non sono installati in modo predefinito. Approfittiamone per installarli ora. Iniziamo dal pacchetto NTP (Network Time Protocol) che aggiorna automaticamente la data e l’ora interrogando appositi server disponibili in internet. Lo installiamo con i comandi:
sudo apt-get update
sudo apt-get install ntp
In caso fossimo scollegati da internet possiamo sempre aggiornare la data e l’ora manualmente con il comando:
sudo date -s “08/27/2013 14:11:00
Installiamo ora il pacchetto man che ci permette di leggere i “manuali” messi a disposizioni dai vari pacchetti installati. Lo installiamo con il comando:
sudo apt-get install man
Per quanto riguarda l’installazione di rcconf ci viene richiesto di installare anche “dialog” come dipendenza, lo facciamo con il comando:
apt-get install dialog
MAPPA DI RIFERIMENTO (CAPITOLO 10)
Il progetto proposto nel libro deve essere adattato alla diversa configurazione e nomenclatura dei pin di PcDuino ed anche al diverso comportamento del driver di gestione del GPIO. Inoltre, non essendo disponibile un’uscita audio, come nel caso di Raspberry Pi, è possibile unicamente instradare l’audio verso la periferica HDMI e quindi, se vogliamo udire i messaggi vocali, è necessario mantenere collegato un monitor con ingresso HDMI.
Vediamo per prima cosa la mappa contenuta nel libro, “modificata” per essere adattata alle caratteristiche di PcDuino. In particolare, la “lista” dei pacchetti necessari al funzionamento dell’applicazione su Rasperry Pi, nel caso di PcDuino sono leggermente diversi, in particolare per quanto riguarda la gestione del GPIO e dell’uscita audio. Infine, per la gestione dei sensori, dei pulsanti, degli interruttori, dei LED e della gestione dei messaggi dobbiamo scrivere i nostri programmi che funzionano da “interfaccia” tra l’hardware ed il sistema operativo; dei veri e propri “server” dedicati ciascuno a un sensore o a una funzione particolare (gestione dei LED). Parimenti dobbiamo prevedere i programmi di creazione delle pagine web e di gestione interattiva dei singoli comandi da remoto.
I programmi python lato server sono quelli che nella mappa troviamo sotto la cartella /home/LR. I programmi in PHP che gestiscono le pagine web sono quelli che nella mappa troviamo sotto la cartella /var/www, che è la cartella predefinita dove vengono depositate le pagine che devono essere gestite dal server web Apache2.
Nella mappa abbiamo inserito i riferimenti grafici a sensori, pulsanti, interruttore e LED in modo da poterli identificare sia sulla scheda sperimentale, sia sul connettore GPIO. Per esempio prendete il primo riferimento FF (in rosso) in alto a sinistra nel riquadro “Architettura software PcDuino”. Si riferisce al pulsante P2 collegato al GPIO3 di PcDuino tramite il pin fisico #22 sul connettore RPI. Tutti i riferimenti sono riportati sia sulla scheda, sia nello schema del GPIO.
Abbiamo anche inserito dei riquadri con alcuni dei comandi principali e le riproduzioni delle pagine di login delle applicazioni utilizzate per potervi annotare userid e password, in modo da averle sempre a disposizione.
I dettagli dei collegamenti e della costruzione dell’ambiente di sviluppo sono descritti in seguito nel paragrafo dedicato allo schema elettrico dell’applicazione.
INSTALLAZIONE APACHE2 E MYSQL (CAPITOLO 11)
Seguite normalmente le istruzioni contenute nel Capitolo 11 per installare i server Apache2 e MySQL, non allarmatevi se non vedete partire correttamente uno o entrambi i server, il problema sta nel fatto che non vengono installate le cartelle di log dei due server, nel punto del file system dove i server si attendono di trovarle. Basta crearle, tra poco vedremo come. Per un’altra stranezza di comportamento dell’Ubuntu per PcDuino, quando si spegne e riaccende PcDuino, le cartelle di log vengono cancellate. Anche in questo caso, basta ricrearle prima di avviare i server, utilizzeremo lo script bash che fa partire tutta l’applicazione, ancora un attimo di pazienza.
GESTIONE GPIO (CAPITOLO 12)
Veniamo al Capitolo 12, a pag. 95 in fondo, dove non è necessario installare il pacchetto per la gestione del GPIO con i programmi python “python-rpi.gpio”, in quanto la gestione del GPIO nel caso di PcDuino è diversa rispetto alla gestione in Raspberry Pi.
Anche il nome del pacchetto “python-rpi.gpio” indica che è stato chiaramente scritto per Raspberry Pi. Il driver di gestione del GPIO per PcDuino è stato scritto in modo diverso, utilizza unicamente i file descrittori, non ha la possibilità di gestire gli interrupt ed è stato compilato come modulo non permanente, pertanto deve essere attivato con il comando:
modprobe gpio
Sempre nello stesso Capitolo 12, a pagina 97, è descritta l’installazione dei pacchetti per dare voce alla scheda Raspberry Pi.
Nel caso di PcDuino, oltre al pacchetto espeak dobbiamo installare anche i pacchetti pulseaudio, player e gespeaker con il comando:
apt-get install pulseaudio player gespeaker
In realtà quest’ultimo non è strettamente necessario, in quanto è un pacchetto text-to-speech gestito da interfaccia grafica, ma visto che dobbiamo tenere aperta una sessione sul monitor per udire l’audio via HDMI, ci è tornato molto utile per il debug, e per sperimentare la gestione della voce in quanto la pronuncia è molto buona, in diverse lingue ed è in grado di leggere da file di testo.
Sempre nel corso dell’istallazione di espeak NON diamo il comando di configurazione della destinazione audio:
amixer cset numid=3 1
in quanto su PcDuino non produce alcun effetto.
SCHEDA SPERIMENTALE E ADATTATORE RPY-PCDUINO (CAPITOLO 13)
Per la realizzazione della parte hardware del progetto abbiamo deciso di riutilizzare la scheda FT1060M già disponibile per Raspberry Pi, alla quale abbiamo collegato un’ ulteriore scheda di espansione FT1072K che riporta tutti i pin del connettore GPIO su un connettore adatto ad essere innestato su una breadbord di sperimentazione. Abbiamo poi realizzato tutti i collegamenti necessari tra i pin ex-Raspberry Pi ed i connettori di PcDuino utilizzando i cavetti con terminali maschio-femmina.Il risultato è quello visibile nella foto di Fig. 12.
Figura 12
PRIMI PROGRAMMI (CAPITOLO 14)
Riportiamo integralmente la descrizione dello schema elettrico, integrato con i riferimenti ai pin dei connettori di PcDuino.
Termostato
L’elemento principale della funzione termostato è la resistenza NTC da 10 kohm, collegata, tramite il partitore di tensione composto da R16 e dall’NTC stessa, all’ingresso analogico 0 dell’integrato PCF8591. La tensione di riferimento per la misura degli ingressi analogici è fornita dalla resistenza di limitazione R18, dal diodo Zener e dal condensatore elettrolitico C1, che mantiene stabile la tensione. Il circuito del termostato è completato dai due LED e dai relativi circuiti di potenza: LD2, che simula l’impianto di condizionamento, collegato al GPIO6 di PcDuino (pin 16 e GPIO23 per RPI), e LD3 collegato al GPIO7 (pin 18 e GPIO24 per RPI) per il riscaldamento. Ciascun circuito di potenza è realizzato con un transistor BC547. Quando il livello del pin di uscita digitale del GPIO è basso, non vi è tensione sulla base del transistor che, in questa condizione, non conduce. Quando il livello del pin assume il valore alto, la tensione sulla base del transistor supera il livello di soglia necessario a portare in conduzione il transistor, che porta a massa la resistenza di limitazione della corrente, permettendo al LED di essere alimentato dalla linea di tensione a 5 V, tramite la resistenza di limitazione da 330 ohm.
Misurazione della luminosità
Dal punto di vista “elettrico” la misura della luminosità richiede solamente il collegamento del sensore al pin AIN1, mediante il partitore di tensione composto dalla fotoresistenza stessa e da R17. Al variare della luminosità varia il valore resistivo della fotoresistenza e, di conseguenza, il valore di tensione misurato sull’ingresso analogico.
LED Flip/Flop
Il LED Flip/Flop è controllato dal lato hardware dal pulsante P2 collegato al GPIO3 (pin 15 e GPIO22 di RPI). Il LED corrispondente è LD1, collegato al GPIO5 (pin 12 e GPIO18 di RPI), alimentato per mezzo del transistor T1.
Interruttore AUX
L’interruttore SW1 è collegato al pin 11 (GPIO17) del connettore di Raspberry Pi. Il LED corrispondente è LD5, collegato al GPIO4 (pin 7 e GPIO4 di RPI), alimentato per mezzo del transistor T5.
Messaggio
L’esistenza di un messaggio da leggere viene evidenziato dall’accensione del LED LD4, collegato al GPIO8 (pin 22 e GPIO25 di RPI), tramite il transistor T4. Per ascoltare il messaggio si preme il pulsante P1, collegato al GPIO2 (pin 13 e GPIO27 di RPI).
L’uscita DAC, sul piedino AOUT del PCF8591, è collegata al LED LD6, tramite la resistenza di limitazione R19. A seconda del livello di tensione impostato sull’uscita AOUT, LD6 si accende con una luminosità più o meno accentuata.
Le linee del bus I2C, SDA ed SCL, sono collegate rispettivamente ai pin i2C-SDA (pin 3 di RPI) i2C-SCL (pin 5 di RPI). I pin di indirizzamento 3, 6 e 7 sull’integrato sono collegali a massa, ciascuno con un jumper, in modo da poter modificare l’impostazione dell’indirizzo del convertitore. Nel nostro progetto li teniamo tutti collegati a massa per mezzo dei selettori del DIP1 posizionati su ON.
I due ingressi analogici non utilizzati AIN2 e AIN3 sono collegati a massa, per evitare valori flottanti.
Nella progettazione di questo circuito abbiamo utilizzato componenti di facile reperibilità sul mercato e che non presentano difficoltà di montaggio.
Sempre con riferimento al Capitolo 13 alla pag. 104, in PcDuino il modulo di gestione del bus i2C fa parte del kernel, e quindi all’avvio è gia disponibile ed i bus i2C sono già visibili nella cartella /dev o con il comando lsmod.
Non è necessario editare il file raspi.blacklist,con (semplicemente non c’è) e nemmeno richiamare il modulo con modprobe. Se andiamo alla cartella /dev possiamo notare la presenza di tre bus i2C, quello al quale abbiamo collegato i pin che vanno all’integrato per la conversione A/D è il 2. I comandi da Pag. 109 diventano:
i2cdetect -y 2
i2cset –y 2 0x48 0x00
i2cget –y 2 0x48
Per l’uscita DAC:
i2cset –y 2 0x48 0x40 255
i2cset –y 2 0x48 0x40 0
E così di conseguenza per tutti i comandi e le istruzioni nei programmi destinati all’utilizzo del bus i2C, come, per esempio, nel Capitolo 14 a Pag. 116 dove l’istruzione di assegnazione del bus diventa:
bus = SMBus(2)
Veniamo ora alla descrizione delle modifiche ai programmi ed al database MySQL, necessarie per poterli far funzionare su PcDuino. Possiamo classificare le modifiche in tre categorie:
Le modifiche d’ambiente come il diverso riferimento al bus i2C e la necessità di ovviare alla “starna” gestione dei log per i server Apache2 e MySQL. Le modifiche necessarie ad uniformarsi alla diversa nomenclatura dei pin dei connettori di PcDuino rispetto al GPIO di Raspberry Pi. Le modifiche relative alla impossibilità di utilizzare la gestione degli eventi sui pin associati ai pulsanti ed agli interruttori. Questo semplicemente perché il driver che gestisce il GPIO per il sistema operativo di PcDuino è stato implementato con una logica differente rispetto a quello implementato per Raspberry Pi, Il signor Tauenbaum, creatore del sistema operativo Minix, uno dei progetiri di GNU/Linux, sostena che “gli standard sono belli perché sono tanti” …
Nei programmi xxx abbiamo sostituito le istruzioni che impostano i polling sui pin e ne gestiscono i relativi eventi con dei loop temporizzati che leggono lo stato dei pin e ne derivano se sono premuti o meno. Noterete un comportamento leggermente diverso rispetto alla implementazione per Raspberry Pi. Per “attivare” una funzione bisogna tenere premuto il pulsante un po’ più a lungo ed un minor effetto “bouncing”. Difficile valutare l’effetto sul consumo di CPU, perché le configurazioni e le caratteristiche hardware delle due schede sono notevolmente diverse.
IL PRIMO PROGRAMMA PYTHON
La prima parte del Capitolo 12 può essere seguita integralmente, sino a Pag. 95, quando si descrive la libreria di gestione del GPIO python-rpi.gpio. Come si evince dal nome, questa libreria interfaccia specificatamente il driver per il GPIO realizzato per Raspberry Pi. Nel caso di PcDuino, come abbiamo già descritto in precedenza, le cose stanno diversamente e il GPIO si utilizza direttamente con i file descrittori anche all’interno dei programmi. Il programma “prova” assume quindi il seguente listato, dove abbiamo usato il GPIO5 in modo da permettervi di fare le prove direttamente usando la scheda FT1060M:
#!/usr/bin/python
import time
import os
os.system(“echo ‘1’ > /sys/devices/virtual/misc/gpio/mode/gpio5”)
while True:
os.system(“echo ‘1’ > /sys/devices/virtual/misc/gpio/pin/gpio5”)
time.sleep(2)
os.system(“echo ‘0’ > /sys/devices/virtual/misc/gpio/pin/gpio5”)
time.sleep(2)
Di seguito alleghiamo il Listato 1 del programma TempLux.py. Rispetto alla versione originale abbiamo modificato i valori dei pin relativi ai LED RISC e COND ed al numero, “2”, del bus i2C. Possiamo provare il programma in questa fase del progetto impostando a “SI” la variabile “xTest”. Notare che tutti i programmi della nostra applicazione devono essere lanciati dall’utente “ubuntu”. Questo perché la gestione del GPIO, nel sistema operativo ubuntu per PcDuino, non richiede l’utente “root”, mentre “espeak” funziona più correttamente con lo stesso utente aperto sul desktop.
#!/usr/bin/env python # TempLux.py # Import librerie from smbus import SMBus import math import time import MySQLdb as mdb import requests # Definizione costanti DbServer = “localhost” DbUser = “RaspiUser” DbPasswd = “RaspiPwd” # Variabile per il controllo della esecuzione # della transazione di blocco # del test sul database per il controllo termostato # e per lo invio dei dati a emoncms (JSON) # SI = salta le istruzioni citate # NO = esegue tutto #xTest = “SI” xTest = “NO” # URL di chiamata JSON ad emoncms e APIKEY di scrittura # da reperire nella pagina Inputs nella applicazione di # amministrazione di emoncms URL_EMONCMS = ‘http://192.168.0.43/emoncms’ EMONCMS_API_KEY = ‘e4b81181b1038f3f59ceecf7f0c90214’ #bus = SMBus(0) # RaspberryPi modello A #bus = SMBus(1) # RaspberryPi modello B bus = SMBus(2) # PcDuino adc_address1 = 0x48 # Imposta indirizzo 000 ADC adc_channel1 = 0x40 # adc_channel2 = 0x41 # Imposta indirizzi canali adc_channel3 = 0x42 # con risoluzione di 8 bit adc_channel4 = 0x43 # R1 = 15000.0 # Resistenza R1 R2 = 15000.0 # Resistenza R2 R_th0 = 10000.0 # Resistenza riferimento termistore a 25 c R_fr0 = 70000.0 # Resistenza fotoresistore con illuminamento IL unitario V_IN = 3.3 # Tensione alimentazione partitori tensione V_REF = 3.3 # Tensione riferimento misura ADC A = 0.00335402 # Steinhart-Hart Costante A B = 0.000256985 # Steinhart-Hart Costante B C = 2.62013e-6 # Steinhart-Hart Costante C D = 6.38309e-8 # Steinhart-Hart Costante D pB = 4100.0 # Costante parametro B K = 6.0 # Fattore dissipazione K 6mV C Pend = 0.7 # Valore Gamma fotoresistenza # Inizio elaborazione if xTest == “NO”: # Connessione al database con = mdb.connect(DbServer, DbUser, DbPasswd, ‘RaspiBase’); con.commit # Inizio transazione MySQL per evitare confilitti su i2C con.begin() print “inizio” # Attivazione del blocco risorsa sul database # Altri programmi che usano bus i2C aspettano cur = con.cursor() cur.execute(“SELECT * FROM xBus WHERE xBus = ‘I2C1’ for update”) print “fine” # Lettura canale 0 ADC - un byte esadecimale # La prima istruzione imposta la richiesta di campionamento su ADC 0 # Si eseguino tre letture per evitare 0x80 all’accensione e per la precisone # incrementale del convertire bus.write_byte(adc_address1,adc_channel1) raw_val = bus.read_byte(adc_address1) raw_val = bus.read_byte(adc_address1) raw_val = bus.read_byte(adc_address1) print “Hex ADC_0 = “, print hex(raw_val) # Elimina i primi due caratteri 0x dal valore letto ed eventuale L finale # Trasforma il risultato in decimale hex_val = hex(raw_val)[2:].rstrip(‘L’) dec_val = int(hex_val,16) print “Dec ADC_0 = “, print dec_val # Trasformazione in tensione del valore letto V = (dec_val * V_REF) / 256.0 print “Volt NTC = “, print V # Calcolo della resistenza R_th = (R1 * V) / (V_IN - V) print “Resistenza NTC = “, print R_th # Calcolo dei gradi Kelvin con la formula di Steinhart-Hart logR = math.log(R_th / R_th0) logR2 = logR**2 logR3 = logR**3 Stein = 1.0 / (A + B * logR + C * logR2 + D * logR3) # Conversione in gradi Celsius e applicazione fattore di dispersione Celsius = round(Stein - 273.15 - V**2 / (K * R_th),2) # Stampa del risultato print “Steinhart - Celsius = “, print Celsius # Calcolo dei gradi Kelvin con la formula del parametro B RRo = (R_th / 10000.0) logRRo = math.log(RRo) parB = 1.0 / ((1.0 / 298.15) + (logRRo / pB)) # Conversione in gradi Celsius e applicazione fattore di dispersione Celsius2 = round(parB - 273.15 - V**2 / (K * R_th),2) # Stampa del risultato print “parametro B - Celsius = “, print Celsius2 # Lettura canale 1 ADC - un byte esadecimale # La prima istruzione imposta la richiesta di campionamento su ADC 1 # Si eseguino tre letture per evitare 0x80 all’accensione e per la precisone # incrementale del convertire bus.write_byte(adc_address1,adc_channel2) raw_val2 = bus.read_byte(adc_address1) print “Hex ADC_1 = “, print hex(raw_val2) raw_val2 = bus.read_byte(adc_address1) raw_val2 = bus.read_byte(adc_address1) # Elimina i primi due caratteri 0x dal valore letto ed eventuale L finale # Trasforma il risultato in decimale hex_val2 = hex(raw_val2)[2:].rstrip(‘L’) dec_val2 = int(hex_val2,16) print “Dec ADC_1 = “, print dec_val2 # Trasformazione in tensione del valore letto V2 = (dec_val2 * V_REF) / 256.0 print “Volt LUX = “, print V2 # Calcolo della resistenza R_lm = (R1 * V2) / (V_IN - V2) # Calcolo della luminosita con 2 decimali Lux = round((R_lm / R_fr0)**(1.0/-Pend),2) # Stampa del risultato print “Lux = “, print Lux if xTest == “NO”: # Ritardo per testare il funzionamento del blocco risorsa sul database #time.sleep (15) # Rilascio del blocco risorsa sul database con.commit() # Controllo se la temperatura compresa nei limiti oppure richiede # la accensione del riscldamento o del condizionamento cur1 = con.cursor(mdb.cursors.DictCursor) cur1.execute(“SELECT * FROM xTemp WHERE xLocale = 1”) row = cur1.fetchone() T_min = row [“xMin”] T_max = row [“xMax”] if Celsius <= T_min: x_LEDRISC = 1 else: x_LEDRISC = 0 if Celsius >= T_max: x_LEDCOND = 1 else: x_LEDCOND = 0 cur2 = con.cursor(mdb.cursors.DictCursor) cur2.execute (“””UPDATE pinStatus SET pinStatus=%s , pinMod=%s WHERE pinNumber=%s”””,(x_LEDRISC, “1”, “7”)) cur2.execute (“””UPDATE pinStatus SET pinStatus=%s , pinMod=%s WHERE pinNumber=%s”””,(x_LEDCOND, “1”, “6”)) # Chiusura connessione al database con.close() # Invio messaggio JSON verso emoncms con lo stato dei LED COND e RISC requests.post(URL_EMONCMS+”/api/post?apikey=” + EMONCMS_API_KEY +”&json={TEMP_1:”+str(Celsius)+”}”) requests.post(URL_EMONCMS+”/api/post?apikey=” + EMONCMS_API_KEY +”&json={LUX_1:”+str(Lux)+”}”) print (URL_EMONCMS+”/api/post?apikey=” + EMONCMS_API_KEY +”&json={LUX_1:”+str(Lux)+”}”) # Invio messaggio JSON verso emoncms con lo stato dei LED COND e RISC requests.post(URL_EMONCMS+”/api/post?apikey=” + EMONCMS_API_KEY +”&json={TEMP_1:”+str(Celsius)+”}”) requests.post(URL_EMONCMS+”/api/post?apikey=” + EMONCMS_API_KEY +”&json={LUX_1:”+str(Lux)+”}”) print (URL_EMONCMS+”/api/post?apikey=” + EMONCMS_API_KEY +”&json={LUX_1:”+str(Lux)+”}”)
Sempre nel Capitolo 14, saltiamo il paragrafo “Accendiamo un LED con il pulsante Flip-Flop”, in quanto non è possibile utilizzare la tecnica del polling con il GPIO di PcDuino. Anche nel programma GPIOInt_FF.py visibile nel Listato 3, a pagina 123, non viene utilizzata la tecnica di gestione degli eventi basata sul polling, in quanto, appunto, non gestita nel driver del GPIO per PcDuino. Abbiamo sostituito questa gestione con dei loop che interrogano ciclicamente lo stato del pin al quale è collegato il pulsante. Abbiamo ovviamente anche adattato il numero dei pin del GPIO ai valori utilizzati da PcDuino. Anche questo programma può essere provato in questa fase del progetto, come indicato nel libro, impostando a “SI” la variabile “xTest”.
Listato 3:
#!/usr/bin/python3 # GPIOInt_FF.py import time, sys, os import MySQLdb as mdb from subprocess import call DbServer = “localhost” DbUser = “RaspiUser” DbPasswd = “RaspiPwd” # Variabile per il controllo della esecuzione # della transazione di blocco # del test sul database per il controllo termostato # e per lo invio dei dati a emoncms (JSON) # SI = salta le istruzioni citate # NO = esegue tutto #xTest = “SI” xTest = “NO” # File descrittori per GPIO2 pin_base = ‘/sys/devices/virtual/misc/gpio/pin/gpio2’ # Inpostazione GPIO2 come ingresso os.system(“echo ‘0’ > /sys/devices/virtual/misc/gpio/mode/gpio2”) # Stampa su stdout lo stato attuale del pin f = open(pin_base, ‘r’) state_last = f.read(1) sys.stdout.write(‘Initial pin value = {}\n’.format(repr(state_last))) f.close() # Salva il tempo attuale t1 = time.time() # Ciclo loop di elaborazione while 1: # Attiva attesa evento Se non avviene entro 60 secondi genera un evento fasullo # giusto per segnalare di essere in vita f = open(pin_base, ‘r’) t2 = time.time() state_last = f.read() if state_last[0] == “0”: # Scarta successivi inneschi entro 1 secondo # per limitare il fenomeno di bouncing if (t2-t1) > 1.0: print “X” if xTest == “NO”: # Collegamento al database con = mdb.connect(DbServer, DbUser, DbPasswd, ‘RaspiBase’); # Legge lo stato del LED Flip Flop sulla tabella pinStatus cur1 = con.cursor(mdb.cursors.DictCursor) cur1.execute(“SELECT * FROM pinStatus WHERE pinNumber = 5”) row = cur1.fetchone() # Inverte lo stato del pin state_LED = row [“pinStatus”] #print state_LED if state_LED == “1”: state_LED = “0” else: state_LED = “1” # Imposta lo stato del pin sulla tabella pinStatus cur2 = con.cursor(mdb.cursors.DictCursor) cur2.execute (“””UPDATE pinStatus SET pinStatus=%s, pinMod=%s, pinMess=%s WHERE pinNumber=%s”””,(state_LED, 1, 0, 5)) #print state_LED # Chiusura connessione al database con.close() t1 = t2 f.close() # Mezzo secondo di sleep time.sleep (0.5) # Mezzo secondo di sleep time.sleep (0.5)
CREAZIONE DEL DATABASE RASPI BASE (CAPITOLO 15)
Il database RaspiBase ha la stessa struttura di quello utilizzato nel libro per Raspberry Pi, l’unica differenza sono i numeri dei pin GPIO usati nel progetto con PcDuino, che sono gioco forza diversi da quelli utilizzati per Raspberry Pi. Questo fatto non modifica le istruzioni contenute nel libro per la creazione del database. Semplicemente vi forniamo il listato corretto da sostituire a quello presente nel Capitolo 15 come Listato 1 per la creazione delle tabelle in automatico. La realizzazione “manuale” delle due tabelle proposte come “esercizio”, non subisce variazioni in quanto le due tabelle “xTemp” e “xBus” non contengono riferimenti ai pin del GPIO.
Nota importante. Per eseguire questo passo è necessario che i server Apache2 e MySQL siano attivi. Come vi abbiamo anticipato, per una stranezza di comportamento, che potrebbe essere risolta nelle successive release di Ubuntu, il sistema operativo cancella la cartella dei file di log per le due applicazioni ad ogni riavvio. Per ovviare a questo abbiamo inserito le istruzioni di creazione delle cartelle e di avvio dei server nello script che lancia tutti i programmi dell’applicazione. Per ora è necessario eseguire queste operazioni a linea di comando. Andiamo alla cartella dei log con il comando:
cd /var/log
ed eseguiamo
mkdir apache2
mkdir mysql
poi facciamo partire i server
sudo service apache2 start
sudo service mysql start
Ora, utilizzando lo script SQL incluso nel Listato 1, possiamo seguire le istruzioni del libro per la creazione del database RaspiBase.
-- phpMyAdmin SQL Dump -- version 3.5.8 -- http://www.phpmyadmin.net -- -- Host: localhost -- Generato il: Gen 01, 2010 alle 01:20 -- Versione del server: 5.5.32-0ubuntu0.12.04.1 -- Versione PHP: 5.3.10-1ubuntu3.7 SET SQL_MODE=”NO_AUTO_VALUE_ON_ZERO”; SET time_zone = “+00:00”; CREATE DATABASE `RaspiBase` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci; USE `RaspiBase`; -- -- Database: `RaspiBase` -- -- -------------------------------------------------------- -- -- Struttura della tabella `pinMsg` -- CREATE TABLE IF NOT EXISTS `pinMsg` ( `pinID` int(11) NOT NULL AUTO_INCREMENT, `pinNumber` varchar(2) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `pinMsgON` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `pinMsgOFF` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`pinID`), UNIQUE KEY `pinNumber` (`pinNumber`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ; -- -- Dump dei dati per la tabella `pinMsg` -- INSERT INTO `pinMsg` (`pinID`, `pinNumber`, `pinMsgON`, `pinMsgOFF`) VALUES (3, ‘5’, ‘flip flop acceso’, ‘flip flop spento’), (4, ‘8’, ‘nuovo messaggio in arrivo’, ‘’); -- -------------------------------------------------------- -- -- Struttura della tabella `pinStatus` -- CREATE TABLE IF NOT EXISTS `pinStatus` ( `pinID` int(11) NOT NULL AUTO_INCREMENT, `pinNumber` varchar(2) COLLATE utf8_unicode_ci NOT NULL, `pinDir` varchar(3) COLLATE utf8_unicode_ci NOT NULL, `pinStatus` varchar(1) COLLATE utf8_unicode_ci NOT NULL, `pinCms` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL, `pinMod` varchar(1) COLLATE utf8_unicode_ci NOT NULL, `pinMess` varchar(1) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`pinID`), UNIQUE KEY `pinNumber` (`pinNumber`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=10 ; -- -- Dump dei dati per la tabella `pinStatus` -- INSERT INTO `pinStatus` (`pinID`, `pinNumber`, `pinDir`, `pinStatus`, `pinCms`, `pinMod`, `pinMess`) VALUES (3, ‘5’, ‘out’, ‘1’, ‘FF_1’, ‘0’, ‘0’), (6, ‘6’, ‘out’, ‘0’, ‘COND_1’, ‘0’, ‘0’), (7, ‘7’, ‘out’, ‘0’, ‘RISC_1’, ‘0’, ‘0’), (8, ‘8’, ‘out’, ‘1’, ‘MESS_1’, ‘0’, ‘0’), (9, ‘9’, ‘out’, ‘1’, ‘AUX_1’, ‘0’, ‘0’); -- -------------------------------------------------------- -- -- Struttura della tabella `users` -- CREATE TABLE IF NOT EXISTS `users` ( `userID` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(28) COLLATE utf8_unicode_ci NOT NULL, `password` varchar(64) COLLATE utf8_unicode_ci NOT NULL, `salt` varchar(8) COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`userID`), UNIQUE KEY `username` (`username`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=4 ; -- -- Dump dei dati per la tabella `users` -- INSERT INTO `users` (`userID`, `username`, `password`, `salt`) VALUES (3, ‘admin’, ‘e86918044f5e77754c0b0fb0e52c335cc6df758ea0974b146ef49b646ac5e118’, ‘54f21ca8’); -- -------------------------------------------------------- -- -- Struttura della tabella `xDac` -- CREATE TABLE IF NOT EXISTS `xDac` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `xDac` int(1) NOT NULL, `xVal` int(3) NOT NULL, `xMod` int(1) NOT NULL, PRIMARY KEY (`ID`), UNIQUE KEY `xDac` (`xDac`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; -- -- Dump dei dati per la tabella `xDac` -- INSERT INTO `xDac` (`ID`, `xDac`, `xVal`, `xMod`) VALUES (1, 1, 190, 0); -- -------------------------------------------------------- -- -- Struttura della tabella `xMess` -- CREATE TABLE IF NOT EXISTS `xMess` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `xMessID` varchar(2) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `xMess` varchar(200) DEFAULT NULL, `xMod` varchar(1) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`ID`), UNIQUE KEY `xMessID` (`xMessID`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; -- -- Dump dei dati per la tabella `xMess` -- INSERT INTO `xMess` (`ID`, `xMessID`, `xMess`, `xMod`) VALUES (1, ‘1’, ‘ ‘, ‘0’);
Di seguito vi forniamo la rappresentazione del database in forma di mappa su due pagine affiancate che sostituisce quella presente nel libro, con i valori modificati per funzionare con PcDuino.
Schema di riferimento Database RaspiBase
COMPLETIAMO L’APPLICAZIONE (CAPITOLO 16)
Nel Capitolo 16 sono presentati i listati degli altri programmi che compongono l’applicazione. Vi forniamo i nuovi listai, nei quali sono stati sostituiti i metodi d’accesso ai file descrittori dei pin e la nomenclatura dei pin stessi. Nei programmi GPIOInt_MESS.py e GPIOInt_AUX.py sono anche state sostituite le istruzioni di gestione degli eventi con i loop per l’interrogazione dello stato, rispettivamente, del pulsante e dell’interruttore a intervalli regolari. Ricordiamo ancora una volta che il bus per la gestione dell’i2C è il numero “2”.
Listato 1
#!/usr/bin/python # LEDServer.py # Import librerie import time import MySQLdb as mdb import os import requests from smbus import SMBus # Definizione costanti DbServer = “localhost” DbUser = “RaspiUser” DbPasswd = “RaspiPwd” # URL di chiamata JSON ad emoncms e APIKEY di scrittura # da reperire nella pagina Inputs nella applicazione di # amministrazione di emoncms URL_EMONCMS = ‘http://192.168.0.43/emoncms’ EMONCMS_API_KEY = ‘e4b81181b1038f3f59ceecf7f0c90214’ #bus = SMBus(0) # RaspberryPi modello A #bus = SMBus(1) # RaspberryPi modello B bus = SMBus(2) # PcDuino adc_address1 = 0x48 # Imposta indirizzo 000 ADC adc_channel1 = 0x40 # Imposta indirizzi canale X_pinNumber = 99 X_pinStatus = 0 X_pinDirection = “zzz” X_pinMod = 0 X_pinZero = 0 # Ciclo di elaborazione principale while True: # Connessione al database con = mdb.connect(DbServer, DbUser, DbPasswd, ‘RaspiBase’); # Ciclo di impostazione fissica dei livelli sui pin dei LED # in accordo agli stati della tabella pinStatus with con: # Lettura di tutti i pin di uouput presenti nella tabella pinStatus cur1 = con.cursor(mdb.cursors.DictCursor) cur1.execute(“SELECT * FROM pinStatus WHERE pinDir = %s”, (“out”)) rows = cur1.fetchall() for row in rows: # Per ciascun pin si salvano i dati in apposite variabili X_pinNumber = int(row[“pinNumber”]) X_pinStatus = row [“pinStatus”] X_pinMod = row[“pinMod”] X_pinDirection = row[“pinDir”] X_pinCms = row[“pinCms”] X_pinMess = row[“pinMess”] #print X_pinNumber os.system(“echo ‘1’ > /sys/devices/virtual/misc/gpio/mode/gpio” + str(X_pinNumber)) # print str(X_pinNumber) # Impostazione del livello del GPIO fisico in base # al valore PinStatus della tabella pinStatus if X_pinStatus == “1”: os.system(“echo ‘1’ > /sys/devices/virtual/misc/gpio/pin/gpio” + str(X_pinNumber)) else: os.system(“echo ‘0’ > /sys/devices/virtual/misc/gpio/pin/gpio” + str(X_pinNumber)) # Se il campo pinCms contiene un nome di Input per emoncms # viene inviata la richiesta JSON con il nome del corrispondente LED # e lo sato del pin if X_pinCms is not None: if X_pinMod == “1”: a=1 requests.post(URL_EMONCMS+”/api/post?apikey=” + EMONCMS_API_KEY +”&json=”+str(X_pinCms)+”:”+str(X_pinStatus)+”}”) # Se il campo pinMess vale 1 viene letta la tabella pinMsg e viene sintetizzato # il messaggio associato aelezionando il caso che il LED corriepondente # sia stato acceso o spento if X_pinMess == “1”: cur3 = con.cursor(mdb.cursors.DictCursor) cur3.execute(“SELECT * FROM pinMsg WHERE pinNumber = %s”, (X_pinNumber)) row3 = cur3.fetchone() if X_pinStatus == “1”: parla=row3[“pinMsgON”] else: parla=row3[“pinMsgOFF”] os.system(‘espeak “’+ parla + ‘” -v it -p 40 -s 155 > /dev/null 2> /dev/null’) # Si azzerano i campi pinMod e pinMess sulla tabella pinStatus # per evitare di ripetere messaggi e inviare richieste JSON nei # cicli successivi del programma cur4 = con.cursor(mdb.cursors.DictCursor) cur4.execute (“””UPDATE pinStatus SET pinMod=%s, pinMess=%s WHERE pinNumber=%s”””,(X_pinZero, X_pinZero, X_pinNumber)) # print X_pinNumber, X_pinDirection, X_pinStatus, X_pinMod con.commit # Lettura tabella xDac per verifica se vi sono cambiamenti cur5 = con.cursor(mdb.cursors.DictCursor) cur5.execute(“SELECT * FROM xDac WHERE xDac = 1”) row5 = cur5.fetchone() xMod = row5 [“xMod”] xVal = row5 [“xVal”] # Se impostata una variazione if xMod == 1: # Inizio transazione MySQL per evitare conflitti su i2C con.begin() # print “inizio” cur6 = con.cursor() # Attivazione del blocco risorsa sul database # Altri programmi che usano bus i2C aspettano cur6.execute(“SELECT * FROM xBus WHERE xBus = ‘I2C1’ for update”) # print “fine” # Imposta il nuovo valore sulla uscita DAC del convertore # mediante chiamata i2C bus.write_byte_data(adc_address1,0x40,xVal) cur7 = con.cursor() cur7.execute (“UPDATE xDac SET xMod=0 WHERE xDac = 1”) # Invio messaggio JSON verso emoncms con il nuovo valore DAC requests.post(URL_EMONCMS+”/api/post?apikey=” + EMONCMS_API_KEY +”&json=DAC_1:”+str(xVal)+”}”) # Ritardo per testare il funzionamento del blocco risorsa sul database #time.sleep (15) # Rilascio del blocco risorsa sul database con.commit() # Chiusura connessione al database if con: con.close() # Intervallo tra due cicli del programma time.sleep (0.5)
Listato 3
#!/usr/bin/python3 # GPIOInt_AUX.py import time, sys, os import MySQLdb as mdb from subprocess import call DbServer = “localhost” DbUser = “RaspiUser” DbPasswd = “RaspiPwd” # file descrittori per GPIO4 pin_base = ‘/sys/devices/virtual/misc/gpio/pin/gpio4’ # Inpostazione GPIO4 come ingresso os.system(“echo ‘0’ > /sys/devices/virtual/misc/gpio/mode/gpio4”) # Stampa su stdout lo stato attuale del pin f = open(pin_base, ‘r’) state_last = f.read(1) sys.stdout.write(‘Initial pin value = {}\n’.format(repr(state_last))) f.close() state_old = state_last[0] # Salva il tempo attuale t1 = time.time() # Ciclo loop di elaborazione while 1: # Attiva attesa evento Se non avviene entro 60 secondi genera un evento fasullo # giusto per segnalare di essere in vita # print events f = open(pin_base, ‘r’) t2 = time.time() state_last = f.read() # Verifica se si tratta di una variazione allo stato dello interruttore if state_last[0] != state_old: # Collegamento al database con = mdb.connect(DbServer, DbUser, DbPasswd, ‘RaspiBase’); # Imposta lo stato del pin sulla tabella pinStus print state_last cur2 = con.cursor(mdb.cursors.DictCursor) cur2.execute (“””UPDATE pinStatus SET pinStatus=%s , pinMod=%s WHERE pinNumber=%s”””,(state_last[0], “1”, “9”)) # Chiusura connessione al database con.close() state_old = state_last[0] t1 = t2 f.close() # Mezzo secondo di sleep
Listato 4
#!/usr/bin/python3 # GPIOInt_MESS.py import time, sys, os import MySQLdb as mdb import os #from subprocess import call DbServer = “localhost” DbUser = “RaspiUser” DbPasswd = “RaspiPwd” # Inpostazione GPIO17 come ingresso os.system(“sudo echo ‘0’ > /sys/devices/virtual/misc/gpio/mode/gpio3”) # File descrittori per GPIO3 pin_base = ‘/sys/devices/virtual/misc/gpio/pin/gpio3’ # Stampa su stdout lo stato attuale del pin f = open(pin_base, ‘r’) state_last = f.read(1) sys.stdout.write(‘Initial pin value = {}\n’.format(repr(state_last))) f.close() # Salva il tempo attuale t1 = time.time() # Ciclo loop di elaborazione while 1: # Attiva attesa evento Se non avviene entro 60 secondi genera un evento fasullo # giusto per segnalare di essere in vita f = open(pin_base, ‘r’) t2 = time.time() # Si posiziona all inizio del file descrittore #f.seek(0) state_last = f.read() if state_last[0] == “0”: # Scarta successivi inneschi entro 1 secondo # per limitare il fenomeno di bouncing if (t2-t1) > 1.0: # Collegamento al database con = mdb.connect(DbServer, DbUser, DbPasswd, ‘RaspiBase’); # Legge il messaggio da leggere nella tabella xMess cur = con.cursor(mdb.cursors.DictCursor) cur.execute(“SELECT * FROM xMess WHERE xMessID = 1”) row = cur.fetchone() parla = row[“xMess”] print state_last #print parla + “a” #print len(parla) + 1 # Se messaggio non vuoto lo passa a espeak per sintetizzarlo if int(len(parla)) > 0: print 2 os.system(‘espeak “’+ parla + ‘” -v it -p 50 -s 155 > /dev/null 2> /dev/null’) # Legge lo stato del LED Flip Flop sulla tabella pinStatus cur1 = con.cursor(mdb.cursors.DictCursor) cur1.execute(“SELECT * FROM pinStatus WHERE pinNumber = 8”) row1 = cur1.fetchone() state_LED = row1[“pinStatus”] print state_LED # Se lo stato del pin = 1 - prima volta che viene letto il messaggio # porta lo stato del LED a 0 e aggiorna la tabella pinStatus if state_LED == “1”: state_LED = “0” #print state_LED cur2 = con.cursor(mdb.cursors.DictCursor) cur2.execute (“””UPDATE pinStatus SET pinStatus=%s , pinMod=%s WHERE pinNumber=%s”””,(state_LED, “1”, “8”)) # Chiusura connessione al database con.close() t1 = t2 f.close() # Mezzo secondo di sleep
SERVER EMONCMS (CAPITOLO 17)
Rispetto alla pubblicazione del libro, il server “emoncms” ha subito degli aggiornamenti, attualmente è alla versione 6. che hanno interessato particolarmente la memorizzazione e gestione dei feed. In particolare è stato introdotto l’utilizzo della tecnica di archiviazione “tempstore”, che invalida le istruzioni descritte nel libro. Infatti per far funzionare questa versione deve essere installato e configurato il server “tempstore”.
Per continuare a utilizzare le tabelle MySQL per la memorizzazione dei feed + necessario modificare il parametro di configurazione nel file:
settings.php in /var/www/emoncms
Il parametro da modificare è:
$default_engine = Engine::TIMESTORE;
da modificare in
$default_engine = Engine::MYSQL;
Salvare e chiudere il file ed eseguire un reboot, per sicurezza.
PROGRAMMI DI GESTIONE APPLICAZIONE WEB (CAPITOLO 18)
Anche i programmi presenti nel Capitolo 18 per la gestione lato server web restano pressoché identici, salvo le modifiche indicate di seguito per i soli programmi AJ_FF e AJ_MESS. Ovviamente le modifiche riguardano i valori dei pin da utilizzare per le modifiche al database. Fate riferimento in ogni caso al libro per la corretta configurazione ne impostazione della applicazione lato server.
AJ_FF.php (Listato 3)
Alla riga 36 sostituire il valore del pinNumber come segue:
# Scrittura del nuovo valore nella tabella pinStatus
mysql_query(“UPDATE pinStatus SET pinStatus=’$setting’, pinMod=’1’, pinMess=’1’ WHERE pinNumber = 5;”);
AJ_MESS.php (Listato 4)
Alla riga 30 sostituire i valori del pinNumber come segue:
if (strlen($Mess) == 0)
mysql_query(“UPDATE pinStatus SET pinStatus=’0’, pinMod=’1’ WHERE pinNumber=’8’;”);
else
mysql_query(“UPDATE pinStatus SET pinStatus=’1’, pinMod=’1’, pinMess=’1’ WHERE pinNumber=’8’;”);
ACCENDIAMO TUTTO (CAPITOLO 19)
Nel Capitolo 19 viene descritto come lanciare tutti i programmi che compongono l’applicazione. Per quanto riguarda lo script bash che abbiamo preparato per lanciare tutti i programmi, l’abbiamo modificato per … aggiustare i piccoli inconvenienti che abbiamo incontrato nel nostro progetto di “porting”. Innanzitutto lo script deve essere lanciato dall’utente “ubuntu”. Come abbiamo già detto in precedenza la gestione del GPIO non richiede l’utente root mentre la gestione text to speech con espeak richiede l’utente “ubuntu” aperto sul desktop per poter veicolare i messaggi via HDMI. Le modifiche allo script GPIO_start.sh possono essere così riassunte:
All’inizio la attivazione del driver per il GPIO; siccome lo script è lanciato dall’utente “ubuntu” e modprobe richiede l’utente “root” abbiamo utilizzato il comando sudo. Poi abbiamo creato le cartelle per i log di apache2 e mysql in modo da poter lanciare i due servizi in modo corretto. Infine copiamo il file resolv.conf, che contirnr gli indirizzi dei DNS a partire da un file con le configurazioni adatte alla nostra rete domestica, salvato nella cartella /home/LR. A questo punto, dopo un ritardo di due secondi per dare tempo ai comandi di avere effetto, lanciamo tutti i programmi come nel caso di Raspberry Pi.
Listato 4
#!/bin/bash sudo modprobe gpio cd /var/log mkdir apache2 mkdir mysql sudo service apache2 start sudo service mysql start sudo cp /home/LR/resolv.conf /etc/ sleep 2 cd /home/LR nohup python /home/LR/LEDServer.py > /dev/null & nohup python /home/LR/GPIOInt_FF.py > /dev/null & nohup python /home/LR/GPIOInt_AUX.py > /dev/null & nohup python /home/LR/GPIOInt_MESS.py > /dev/null &
Bene, abbiamo terminato.
Se non volete digitare e copiare i nuovi programmi, ecco lo zip che li contiene tutti.
Buona sperimentazione e buon divertimento.
1 Commento