CamiSCADA

Avevo iniziato con un precedente post su Processing e SCADA, ed ora la continuazione

L’INIZIO

Il progetto si chiama CamiSCADA perchè le prime righe di codice le ho scritte a Camignolo, presso la Scuola Media, in questa primavera.

In questo articolo descrivo più dettagliatamente il progetto, ma prima di tutto…a che serve?

Cosa si può fare con CamiSCADA

CamiSCADA è una applicazione scritta in linguaggio Java, o meglio in Processing, che si occupa di visualizzare l’andamento di controllori, quali PLC ed Arduini varii.

In pratica uno SCADA è una sorta di “cruscotto” che permette di avere la “visione d’insieme”.

La novità di CamiSCADA è…

CamiSCADA integra una interessante funzionalità: la modalità demo.

è possibile quindi simulare il funzionamento di un sistema facendolo apparire come se il tutto stesse funzionando: tank che si riempiono , valvole che si aprono e via dicendo.

Primo demo: birrificio

Il primo demo simula un birrificio ad una linea di maltatura e tre linee di fermentazione.

Per eseguire la demo “birrificio” basterà copiare (=sostituire) i due file “camiscada.dat” e “camiscada.ini” nella directory home di CamiSCADA.

Video esempio

Un video-esempio è stato caricato su Youtube: questo è il link.

Secondo demo: creazione filamenti

In questo caso si simula la produzione di filamenti polimerici per estrusione a bassa pressione.

Anche in questo caso per eseguire la demo basterà copiare (=sostituire) i due file “camiscada.dat” e “camiscada.ini” nella directory home di CamiSCADA.

Come installare

Scompattare il file zip ( cliccare qui per scaricarlo ) in una directory, per esempio “camiscada”. Verranno automaticamente create le sotto-directory relative.
Dopo l’installazione è già “in linea” la demo per il birrificio, quindi basterà avviare Processing e successivamente caricare lo script presente nella directory “som_lab50_10”: som_lab50_10.pde.

Requisiti

Processing richiede poche risorse, è parsimonioso. Unica nota è la versione di Processing che deve essere almeno la 5.3.

Codice

Il codice, o sorgente, di CamiSCADA, è diviso in due parti: oggetti e run-time.

Oggetti

Gli oggetti sono tipicamente delle macchine, per esempio un tank è un oggetto. allo stesso modo una saldatrice automatica è un oggetto, così come lo è una valvola.

Tra gli oggetti vi sono i diversi apparati che si possono incontrare in questi ambiti: tank, valvole e tubi.
Ogni oggetto è provvisto di “maniglie” per poter effettuare il legame con gli oggetti.

Struttura oggetti

Tutti gli oggetti di CamiSCADA, sono dotati di due tipi di attributi:

  • attuatori
  • sensori

I metodi principali sono:

  • mshow – per visualizzare graficamente
  • mgethole – per conoscere le coordinate delle “maniglie”
  • minfo – per visualizzare i testi

Sensori

I sensori inviano dei valori alla console SCADA. La tipologia ed il numero dei sensori possono variare da oggetto ad oggetto: per esempio un tank avrà tre tipi di sensori:

if ( match(wparm[0], "CAP") != null  ) {
  this.wfiller=float(wparm[1]);
}
if ( match(wparm[0], "TEM") != null  ) {
  this.wtempc=float(wparm[1]);
}
if ( match(wparm[0], "BAR") != null  ) {
  this.wpress=float(wparm[1]);

dove TEM è una sonda termica, BAR per la pressione e CAP per il livello.

Struttura camiscada.ini

è il file che contiene l’elenco degli oggetti e la loro disposizione (layout). Si tratta di un file di testo, strutturato e diviso in due sezioni.
Nella prima sezione troviamo gli oggetti, menre nella seconda i collegamenti.
Una riga della prima sezione ha la forma:


TANK;p1b1d1m1c1;90;50;HLT


dove “TANK” è il tipo di oggetto (ed è definito all’interno del programma), poi “p1b1d1m2c1” è il codice di questo tank. La coppia di numeri identifica il punto da dove verrà disegnato il tank, nel formato x e y. Ultimo “HLT” è il nome col quale verrà visualizzato il tank.

Per la seconda sezione, i raccordi la struttura è un po’ diversa:


PIPE;p1b1d1m4c6;p1b1d1m1c3;DX;p1b1d1m3c6;SX;to_pump3a

anche qui “PIPE” è il tipo di oggetto, “p1b1d1m4c6” è il nome del raccordo.
La coppia “p1b1d1m1c3;DX” indica che il raccordo partirà dalla maniglia DX dell’oggetto “p1b1d1m1c3” e si raccorderà alla SX di “p1b1d1m3c6”.
Infine “to_pump3a” è il nome che verrà visualizzato.

Denominazione dispositivi

Per assegnare un codice ai diversi dispositivi ho utilizzato una codifica già presente: la DNP3. In sintesi una stringa “p1b1d1m1c1” significa:

  • p1 = impianto
  • b1 = building, edificio
  • d1 = department, settore
  • m1= machine
  • c1 = component, parte della macchina, sensore o attuatore.

Ovviamente il numero è un progressivo quindi un nome possibile potrebbe essere: p1b4d2m21c5.

Struttura camiscada.dat

Questo file è opzionale in quanto contiene i comandi che l’applicazione riceve e che dovrà visualizzare.

La posizione di questo file è la stessa dalla quale viene avviata l’applicazione ovvero dove si trova il file som_lab50_10.pde.

è possibile inserire dei commenti all’interno del file, tramite il simbolo “#” posto all’inizio della riga.

# camiscada demo brewery
# 2019
 p1b1d1m1c1;CAP=10
 p1b1d1m1c1;CAP=20
 p1b1d1m1c1;CAP=30
 p1b1d1m1c1;CAP=40
 p1b1d1m1c1;CAP=50
 p1b1d1m1c1;CAP=60
 p1b1d1m1c1;CAP=70
 p1b1d1m1c1;CAP=80
 p1b1d1m1c1;CAP=90
# tank HLT al max

Collegamento con Arduino

Il collegamento con Arduino avviene attraverso porta USB. Il formato dell’informazione è quello già descritto in camiscada.dat, quindi il modulo Arduino dovrà rispettare il protocollo utilizzando la corretta sintassi:

Serial.println("p1b1d1m1c1;CAP=90");

In questo caso il codice del dispositivo (p1b1d1m1c1) è cablato nello sketch di Arduino. In alternativa è possibile associare il codice dispositivo ad una specifica porta USB.

Conclusione

Per usare Processing è necessaria una seppur minima conoscenza di Java e programmazione ad oggetti.

Il vantaggio di utilizzare una libreria consiste nel fatto che molto del lavoro è già stato fatto e si tratta solo di adattamenti.

Il discorso cambia quando è necessario creare un nuovo oggetto: in questo caso basterà duplicarne uno già esistente ed apportare le necessarie variazioni.

L’argomento sulla modifica degli oggetti verrà affrontato in un articolo successivo.

SCADA con Processing

Fare automazione con Arduino è possibile ed abbastanza facile.

Anche integrare Arduino con il PC è facile: Processing è lo strimento adatto.

E se volessimo realizzare un quadro sinottico? magari di un impianto idraulico? Certo, con Processing possiamo crare gli oggetti grafici, ma è tedioso!

Un sistema SCADA è un sistema che integra e riassume il funzionamento di diversi controller, tra i quali Arduino o simili.

SCADA

I dati di funzionamento vengono visualizzati ed è possibile anche inviarli a sistemi di controllo.

LIBRERIA

Cercando in Rete una libreria per SCADA su Processing, non ho trovato gran che, e quindi ho deciso di scriverne una direttamente. Da questo articolo vedremo come realizzare una libreria e un sistema SCADA con incluso il modulo PLANT-MGMT (che corrisponde al livello 5 della piramide CIM).

CLASSI

Il primo passo è descrivere le classi dibase che saranno utilizzate. Per farlo ho iniziato dal settore dei liquidi: tank e valvole.

CODICE

Questa è una prima versione che sarà estesa. Ecco la prima parte:

/*
fablabway.com
file: som_lab50_00.pde
progetto: lab50 - SCADA con Processing
descrizione: SCADA con Processing
author: Mauro Rossolato
licenza: Creative Commons BY-NC-ND
when who what

16.04.2019 mr creates
*/
// import
import processing.serial.*;
// global vars
short portIndex = 0;
// objects
Serial wport;
MTANK wtank1;
MTANK wtank2;
MVALVE wvalve1;
class MVALVE {
float wpx, wpy;
String wname, wdvcid;
MVALVE (String pdvcid, float ppx, float ppy, String pname) {
wdvcid = pdvcid;
wpx = ppx;
wpy = ppy;
wname = pname;
}
void mshow() {
stroke(127);
fill(200);
rect(wpx, wpy, ((20/1.41)2), 20); fill(0); fill(0x19BC0E); triangle(wpx, wpy, wpx+(20/1.41), wpy+(20/2), wpx, wpy+20); triangle( wpx+(20/1.41), wpy+(20/2), wpx+((20/1.41)2), wpy,
wpx+((20/1.41)*2), wpy+20);
textSize(18);
text(wname, wpx, wpy);
}
void maction (int pstatus) { // 0=chiusa
color wcolverde= color(43, 182, 8);
color wcolrosso= color(238, 29, 15);
if (pstatus==0) fill(wcolverde);
else fill(wcolrosso);
triangle(wpx, wpy, wpx+(20/1.41), wpy+(20/2), wpx, wpy+20);
triangle( wpx+(20/1.41), wpy+(20/2),
wpx+((20/1.41)2), wpy, wpx+((20/1.41)2), wpy+20);
}
}
class MTANK {
float wpx, wpy;
float wsizex = 50;
float wsizey = 100;
float wfiller;
float wplugxdx =wpx+wsizex;
float wplugydx= wpy+(wsizey/2);
String wname, wdvcid;
MTANK(String pdvcid, float ppx, float ppy, String pname) {
wpx = ppx;
wpy = ppy;
wdvcid = pdvcid;
wname = pname;
}
void mshow() {
stroke(255);
fill(0);
rect(wpx, wpy, wsizex, wsizey);
}
void minfo() {
fill(255);
textSize(14);
text(wname, wpx, wpy);
textSize(16);
text(wfiller+"%", wpx, wpy+wsizey+20);
}
void mfiller(float pfiller) {
color wcolblu= color(15, 32, 188);
wfiller=pfiller;
fill(wcolblu);
float wfilly = (wsizey*(1-(wfiller/100)));
fill(wcolblu);
rect(wpx, wpy+wfilly, wsizex, wsizey-wfilly);
}
}
void setup() {
colorMode(RGB);
background(51, 0, 0);
size(600, 300);
wtank1 = new MTANK("abc", 20, 30, "tank 1");
wvalve1 = new MVALVE("dec", 200, 70, "valve 1");
wtank2 = new MTANK("qwe", 360, 30, "tank 2");
}
void draw() {
// wport.readstring();
// while (wport.available() > 0) {
// String wbuffer = wport.readString();
// if (wbuffer != null) {
// println(wbuffer);
// }
// }
mrefresh();
delay(2000);
}
void mrefresh () {
wtank1.mshow();
wtank1.mfiller(70);
wvalve1.mshow();
wtank2.mshow();
wvalve1.maction(1);
wtank2.mfiller(20);
wtank1.minfo();
wtank2.minfo();
}
//}
/*
print (wfiller +";wpy=");
print (wpy);
print (";");
print ("wsizey=");
print (wsizey);
print (";");
println(wfilly);
*/

il risultato saranno due contenitori e una valvola. I tank hanno la gestione del riempimento e la valvola il controllo di apertura.


Arduino e i tipi di dati

Programmando con Sketching è inevitabile utilizzare delle variabili o costanti: senza questi elementi infatti nessun programma avrebbe senso.

 

LA MEMORIA

sensore CCD

Per poter lavorare Arduino (così come anche gli altri dispositivi simili) ha bisogno di utilizzare la memoria RAM. Possiamo immaginare la memoria come un foglio elettronico: ogni cella contiene delle informazioni e e ogni cella ha un indirizzo.

VARIABILI E COSTANTI

Una prima suddivisione del tipo di informazioni è tra variabili e costanti. Il nome parla chiaro: le prime possono cambiare e le seconde rimangono fisse. Prima domanda: a che servono le costanti se poi non cambiano? Risposta: perchè hanno un “nome” dal quale comprenderne il significato.

int mlivellopwm = 20;     // valore iniziale della potenza (VARIABILE)

const int kpinventola = 1;   // contatto di output e/ventola (COSTANTE)

Perchè differenziare tra costanti e variabili? Per sicurezza: se per sbaglio durante l’esecuzione, dovessi cambiare il valore di una variabile, potrei causare dei problemi, magari attivare erroneamente un motore, con tutti i danni che ne deriverebbero. Se invece è costante, quel valore è immodificabile.

DIVERSI TIPI

Sia le variabili e sia le costanti occupano della memoria, ma a seconda del tipo ne potranno occupare di più o di meno.

Facendo un paragone con un foglio elettronico  , a volte capita di allargare una colonna perchè non è in grado di contenere l’informazione.

Ancora, sempre nel foglio elettronico, capita di definire una o più celle come area “data ora”. Questa è una similitudine con i tipi di dato: diversi tipi per poter contenere e trattare adeguatamente il dato contenuto.

ELENCO DEI TIPI

TIPO DIMENSIONE (byte) FAMIGLIA/INTERVALLO
String  2K alfanumerico
array  limitato dalla memoria  alfanumerico/numerico
bool  1 byte  logico
boolean  deprecato, uguale a bool  logico
byte 1 byte  numerico, da 0 a 255
char 1 byte  numerico, da -127 a 128
double8 8 byte  numerico
float  4 byte  numerico,  da -3.4028235E38 a 3.4028235E38
int  2 byte  numerico, da -32768 a 32767
long  4 byte  numerico, no virgola, da -2147483648 a 2147483647
short  2 byte   numerico con segno
unsigned char  1 byte  alfanumerico, da 0 a 255
unsigned int  2 byte  numerico, da  0 a 65535
unsigned long  4 byte  numerico, da 0 a 4294967295
void  0  N.D.
word  2 byte  numerico, da  0 a 65535

FALSI AMICI

Anche Sketching ha i suoi false friends (cfr. wikipedia ).

kit comando luci (voolamp)

Mi riferisco a char, il cui nome lascerebbe intendere “carattere”, ovvero simbolo dell’alfabeto.
In realtà è un byte che contiene 2^8=256 valori. Peccato però char che abbia la gestione del segno, quindi i bit restanti diventano 7, e con 7 bit possiamo “mappare” solo i primi 128 simboli del codice ASCII. Infatti 2^7=128.

 

char mvalore = 66;     // identifica "B"

char mvalore2 = -66    // valido, ma *non* e' un simbolo ASCII

COSA SCEGLIERE

Tutto dipende da cosa dovrà contenere la variabile: numeri o caratteri?

Se abbiamo del testo possiamo usare:

  • serie di caratteri, ovvero char[]
  • String

Per quanto i numeri, la scelta è abbastanza ampia, ma il più delle volte il tutto si risolve in 2 o 3 tipi:

  • int
  • float
  • double

Con questi tipi è possibile gestire la quasi totalità delle variabili (o costanti).

E GLI ALTRI?

I diversi tipi, soddisfano due esigenze:

  • occupazione di memoria
  • velocità di elaborazione/calcolo

TEST DI VELOCITÀ

Qui di seguito uno script Sketching per provare la velocità di elaborazione delle differenti variabili: int, double e float.

I risultati appariranno sulla finestra di monitor seriale. Una possibile modifica potrebbe essere la “costante” MCICLI: l’importante è non superare il valore di 32000, pena una lunga attesa.

/*
FLW - www.fablabway.com

mauro rossolato

lab49 - test velocita' calcolo variabili

uses:

when who what
----------------------------
19.05.2016 mr creates

*/

//#define MCICLI 4096
#define MCICLI 16384


int moneshot = 1;
float mfloat = 3.0;
int mint = 3;
double mdouble = 3;
unsigned long mtmstart, mtmend;


void setup()
{
  Serial.begin(9600);
  Serial.println("FLW,2018 - test velocita' calcolo variabili, v.1.0");
}


void loop() {
  int mndx;
  if (moneshot == 1) {
    //-------------------------------------
    mtmstart = micros();
    for (mndx = 0; mndx < MCICLI; mndx++) {
      mdouble =  mdouble / 2;
    }
    mtmend = micros();
    Serial.print("durata ciclo double: ");
    Serial.print(mtmend - mtmstart );
    Serial.print(" microsecondi. Valore mdouble: ");
    Serial.println(mdouble);
    //-------------------------------------
    mtmstart = micros();
    for (mndx = 0; mndx < MCICLI; mndx++) {
      mint = mint / 2;
    }
    mtmend = micros();
    Serial.print("durata ciclo int: ");
    Serial.print(mtmend - mtmstart );
    Serial.print(" microsecondi. Valore mint: ");
    Serial.println(mint);
    //-------------------------------------
    mtmstart = micros();
    for (mndx = 0; mndx < MCICLI; mndx++) {
      mfloat = mfloat / 2.0;
    }
    mtmend = micros();
    Serial.print("durata ciclo float: ");
    Serial.print(mtmend - mtmstart );
    Serial.print(" microsecondi. Valore mfloat: ");
    Serial.println(mfloat);
    //-------------------------------------
    moneshot = 0;
  }
}

con questo risultato:

FLW,2018 - test velocita' calcolo variabili, v.1.0
... microsecondi

CONCLUSIONE

In Arduino, così come in altri linguaggi esistono diversi tipi di dati. Queste differenze servono per migliorare le prestazioni oppure l’occupazione di memoria. I tipi int, float e double sono quelli “universali”.

É possibile definire dei nuovi tipi custom? Si, ma lo vedremo prossimamente.

Software per Raspberry e Arduino

Per poter lavorare con Raspberry o Arduino, è indispensabile utilizzare alcuni software. Non tutte queste applicazioni sono disponibili per tutti sistemi operativi (Windows, MacOs o Linux).

Vediamo i più diffusi.

Putty

É un emulatore di terminale Unix per ambiente Windows: in pratica ci permette di usare un pc collegato ad un Linux (e non solo) come se fosse un terminale.

Installazione

Non richiede un setup di installazione, quindi basterà lanciare direttamente l’eseguibile “putty.exe”.

Configurazione

A parte le molte opzioni disponibili (colori, font, ecc.), gli  unici parametri essenziali sono:

  • il nome dell’host o il suo indirizzo IP
  • userid
  • password

 

Download

Il sito di riferimento è www.putty.org.

CygWin

Questa applicazione simula un ambiente Unix all’interno di un pc Windows.

L’utilità di questo strumento dipende se siamo o meno abituati al “prompt”: infatti CygWin è “testuale” e non grafico.  Qualche esempio: a volte modificare dei file di testo è una operazione complicata o ripetitiva, mentre con gli adeguati strumenti Unix il tutto si risolve in un istante. (Guarda qui).

Download

L’applicazione può essere scaricata da

http://www.cygwin.org/

Configurazione

Cygwin non richiede particolari configurazioni se non quelle solite dell’ambiente shell-Unix: prompt, path, ecc.

 

Winscp

Questo è un software, gratuito, per trasferire file o directory da e verso un host Unix. È grafico ed intuitivo.

Configurazione

Viene richiesto il nome della macchina o l’indirizzo IP:

e ovviamente l’account.

Download

è scaricabile all’URL

https://winscp.net/eng/download.php

 

App Terminale

Se dobbiamo collegarci tramite Bluetooth, ad una scheda Arduino, ci servirà

un emulatore di terminale per lo smartphone. Uno che consiglio è BT Simple Terminal.

 

Download

In questo caso dalla Play-Store, basterà cercare “BT Simple teminal” e chiedere l’installazione.

Una volta installata la app, bisognerà attivare il Bluetooth ed eseguire il solito giro del pairing. Al termine vedremo sul telefono i messaggi provenienti da Arduino/Bluetooth e allo stesso modo ne potremo inviare degli altri.

 

Etcher

Questa utile applicazione serve per creare delle immagini di disco avviabili (vedi precedente articolo). In pratica useremo Etcher ogni qualvolta dobbiamo installare una immagine ISO su una SD-card. È per l’appunto il caso di Raspbian.

 

Creare SD per Raspberry

Per poter utilizzare la nostra scheda Raspberry abbiamo bisogno di installare un sistema operativo.

Normalmente la scelta ricade su Raspbian, ma esistono anche altre opzioni. In ogni modo si tratta di fork di linux (Debian).

 

SCARICARE IL SISTEMA OPERATIVO

Il nostro percorso inizia con il download del file che conterrà Raspbian. Al termine, come consuetudine, troveremo il nostro file nella cartella destinata ai “download”. Possiamo anche lasciarlo lì. Per scaricare Raspbian, clicca qui.

FORMATO IMMAGINE

No, non si tratta di immagini vere e proprie (png, gif, ecc.), ma di immagine di memoria di massa, o meglio di CD-ROM. Questo perchè inizialmente le installazioni software avvenivano (ora un po’ meno) tramite cd-rom. Quindi il file scaricato non è un file compresso che normalmente scompattiamo (winrar, zip, ecc.), ma simula il modo di archiviazione del CD-ROM (ISO9660): ecco perchè si chiama anche “immagine ISO“. In pratica passeremo questa immagine su una SD-CARD.

In programma semplice e funzionale è, ad esempio, Etcher, ma ne esistono molti altri.Chi volesse lo può scaricare dal repository software: clicca qui.

Vediamo ora i passi in generale:

SEQUENZE

  • scaricare immagine ISO
  • scaricare software per creare immagini ISO
  • scrivere SD-CARD
    • selezionare ISO
    • selezionare drive (SD-CARD)
    • copia!
    • sganciare SD-CARD (da sistema operativo)
  • inserire in Raspberry

 

 

AVVIO E PROVA

 

Inserire la SD-CARD a scheda spenta. e poi connettere la rete (RJ45) e alimentazione. I più tecnologicamente dotati potranno collegare lo schermo tramite la porta HDMI, nonchè tastiera e mouse. Per gli altri basterà una connessione con emulatore di terminale.

Se abbiamo fatto tutto giusto il nostro sistema partirà subito!

 

 

 

 

Arduino chiude il garage

A volte il sistema di apertura e chiusura del garage non soddisfa le nostre esigenze, accade che vorremmo “quel qualcosa” in più ed ecco che Arduino ci può aiutare.

LA RICHIESTA

La richiesta è di Marco, partecipante al corso (primavera 2017) di Arduino a Bellinzona. Questa è la sua richiesta:

Ho una porta del garage motorizzata.
E’ possibile aprirla e chiuderla tramite:

    Telecomando
    Cordina da tirare al motore
    Interruttore a parete che manda un inpulso elettrico tramite due cavi.
    Via etere tramite la digitazione del corretto codice su una tastiera numerica (immagino Bluetooth, onda radio o altro segnale)

Ogni tanto mi dimentico di chiuderla ?
Mi piacerebbe che:

    Tramite un sensore (infrarosso) sentisse quando qualcuno entra o esce e dopo xx minuti provveda a chiudere automaticamente la porta
    Abbia un “bottone” per attivare  o disattivare questa funzione (nel caso voglia lasciare aperta la porta a lungo)
    Un domani mi avvisi via GSM o WiFi se la porta si dovesse aprire e io non sono in  casa
    Se via GSM, potrei anche poterla aprire e chiudere a distanza.

 

LA SOLUZIONE

Dividendo in due parti l’applicazione: la prima con il controllo locale e la seconda con il controllo remoto (GSM), ecco un esempio:

// lab26
// 27.03.2017 - m.r.
// 

#define MCOMANDO 5                // segnale in uscita verso attuale relais passo-passo
#define MPIR 7                        // sensore infrarossi
#define MBLOCCO 6                    // interuttore di blocco
#define MRITARDO 20                // ritardo prima di attivare "MCOMANDO"

int mritardo;
int mrunclock;                        // attiva/disattiva il conteggio per ritardo
int mpresenza;                        // flag impostato dal PIR, serve per capire quando la stanz è vuota (variazione)
int mblocco;

void setup() {
  Serial.begin(9600);
   pinMode(MCOMANDO,OUTPUT);
   pinMode(MBLOCCO,INPUT);
   pinMode(MPIR,INPUT);   
  mrunclock==0;
  mpresenza=0;
       mritardo = MRITARDO;
}

void loop() {
    if (digitalRead(MPIR) == HIGH) {
      Serial.println("PIR ON");
      mpresenza=1;
    }
    else {
      Serial.println("PIR OFF");
      if ((mpresenza==1) && (digitalRead(MBLOCCO) ==LOW)) mrunclock=1;
      else mrunclock=0;
    }
 
 if ((mrunclock==1)  && (digitalRead(MPIR) == LOW)) {
    Serial.println("decremento...");
    mritardo--;
    Serial.println(mritardo);
  }
  if (digitalRead(MBLOCCO)==HIGH) {                    // se è bloccato non deve contare x ritardo
    Serial.println("blocco inserito"); 
    mrunclock=0;                                                        // imposta il flag
  }
  if ((mritardo ==0) && (digitalRead(MBLOCCO) ==LOW)) {   // blocco NON attivo e finito il conteggio: AZIONE!
    Serial.println("finito di contare...");
    digitalWrite(MCOMANDO, HIGH);
    delay( 1000 );
    mrunclock=0;
    mritardo=MRITARDO;
    mpresenza=0;
  }
  digitalWrite(MCOMANDO, LOW);
  delay(500);
}

MATERIALE

Servono davvero pochi pezzi:

  • Arduino UNO (o Nano, …)
  • Interruttore
  • 2 resistenze 1K
  • sensore PIR
  • BC547

qualche jumper e 10 minuti!