Linux Embedded, riproviamoci con PcDuino

Apertura


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

Fig_001


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.

Figura 2
Fig_002

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
Fig_004


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

Fig_005

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 6
Fig_006

Figura 7
Fig_007
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
Fig_008

Figura 9

Fig_009


(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):

Fig_010


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):

Figura 11
Fig_011


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.

 

Mappa-di-riferimento


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

Fig_012



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

Tabella1a

Tabella1b

Tabella1c

Tabella2a

Tabella2b

Tabella2c

 


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

  1. Io mi sto esercitando con il Rapberry PI mod B ma, nonostante sia riuscito a superare alcune difficoltà, adesso sono fermo e non arrivando al bandolo della matassa: quando GPIOInt_FF.py è in esecuzione in moidalità xTest = "NO" se premo il pulsante mi dà l'errore 'NoneType' object has no attribute '__getitem__', mentre, nel caso xTest = "SI", tutto funziona correttamente.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Menu