Senzor IoT temperatura cu transmisie GSM

Construieste-ti sezorul tau de temperatura IoT cu stocare de date in CLOUD. In acest proiect folosim senzorul 1 Wire 18B20 de la Dallas/Maxim si shieldul GSM dual SIM  a-gsmII sau shieldul GSM GNSS dual SIM b-gsmgnss  de la itbrainpower.net. Serviciul CLOUD este oferit gratuit de Robofun.

Necesar timp: 30-45 minute – pregatire hardware si aproximativ 30-60 minutes partea de software si setarile contului cloud.

Nivel de dificultate: intermediar.

Materiale necesare hardware IOT

Despre shieldurile GSM folosite
In acest proiect am folosit, pentru exemplificare, shieldul a-gsmII v2.105, dar exact aceleasi setari hardware se aplica pentru b-gsmgnss v2.105 (interfetele si jumperii sunt plasati in aceleasi pozitii). Mai multe informatii:
documentatie a-gsmII
documentatie b-gsmgnss

Detaliere senzor 18DS20
Lipiti rezistorul de 8.2Kb intre terminalele Vdd (pin3) si DQ (pin2) ale 18B20 ca in imaginea de mai jos. Vezi referinta DALLAS/MAXIM 18B20.

Conectare hardware (toate componentele conectate in poza de mai jos)
Pasi de urmat:

  • lipiti headere (pini) ARDUINO la shieldul GSM a-gsmII
  • plug-in (conectati) sieldul a-gsmII in Arduino UNO
  • plasati jumperul a-gsmII “Power selector” in pozitia “Vin” (referinta)
  • inserati the SIM cardul in SIM socketul primar (slotul SIM aflat in proximitatea PCB). SIM-ul trebuie sa aiba dezactivata procedura de verificare a codului PIN (vezi cum se dezactiveaza verificarea PIN, aici).
  • Lipiti rezistorul de 8.2Kb intre terminalele Vdd (pin3) si DQ (pin2) ale 18B20. Lipiti firele la terminalele senzorului 18B20.
  • Conectati firele 18B20 dupa cum urmeaza: 18B20 Vdd (pin3) la Arduino 5V, 18B20 DQ (pin2) la Arduino D8  si 18B20 GND (pin1) la Arduino GND.
  • conecteaza portul USB al Arduino UNO  la PCul tau

Alimentarea senzorului IOT va fi efectuata centralizat, prin intermediul conectorului de alimentare Arduino UNO.

SOFTWARE
a. Downloadeaza itbpGSMclass library [beta]: “a-gsmII series software IoT REST support for ARDUINO” de la a-gsmII download section, sau “b-gsmgnss series software IoT REST support for ARDUINO” de la b-gsmgnss download section. Pentru a efectua download-ul clasei va trebui sa introduci IMEI-ul (se afla marcat pe modem, sau poate fi citit folosind comanda “AT+CGSN”) si adresa ta de email.

b. Expandati archiva si instalati clasa. Pe scurt, copiati folderul “itbpGSMclass” in “Arduino local user folder” [la mine se afla in: “C:\Users\dragos\Documents\Arduino\libraries”], dupa care restartati mediul Arduino. Mai multe detalii despre intalarea manala de librarii Arduino: Arduino library manual installation.

c. Creaza un folder numit “agsmII_temperature_Robofun_cloud_logger”.

d. Salveaza codul din linkul de mai jos sub denumirea de “agsmII_temperature_Robofun_cloud_logger.ino” in folderul creat mai devreme: Temperature GSM IOT main Arduino code

e. Setari variabile in “agsmII_temperature_Robofun_cloud_logger.ino”:
– tempToken [linia 19] – inlocuieste cu tokenul senzorului tau generat in cloud Robofun
– samplingPeriod [line 29]

f. Setari variabile in “itbpGSMclass library”:
– seteaza SERVER_ADDRESS si SERVER_PORT in itbpGPRSIPdefinition.h pentru ROBOFUN CLOUD, ca mai jos
#define SERVER_ADDRESS “iot.robofun.ro”
#define SERVER_PORT “80”
– seteaza APN, USERNAME si PASSWORD, corespunzator SIM-ului tau, in itbpGPRSIPdefinition.h (pentru ORANGE RO, de exemplu, APN este “INTERNET” sau “NET”, USERNAME este “” si PASSWORD este “”)
– alege modemul itbrainpower folosit in itbpGSMdefinition.h, in acest caz:
#define __itbpModem__ agsmII
– nu uita sa salvezi setarile! 😉

g. alte setari utile >> itbpGSMClassDebug, atDebug on / off si MAX_BUFFER_SIZE… in itbpGSMdefinition.h

CLOUD ROBOFUN. CONT NOU, SENZORI si SETARI
CLOUDul Robofun este un serviciu extrem de simplu de utilizat si este disponibil in mod gratuit. Acesta este disponibil la adresa: https://iot.robofun.ro. Nu intru in detalii – creaza un cont nou si defineste un senzor nou. In interfata senzor, fa scroll down pana la paragraful “TOKEN”.

Copiaza acest cod si  foloseste-l pentru tempToken [linia 19 din “agsmII_…._logger.ino”]. Salveaza. Compileaza.

GATA!

Acest tutorial se bazeaza pe articolul “IoT temperature CLOUD logger with GSM and 1wire sensor howto” care a fost publicat original pe site-ul https://itbrainpower.net

 

Touchless Heart

În cadrul acestui proiect vom exemplifica utilizarea senzorului APDS-9960. Acest senzor poate fi utilizat în aplicații diverse de detecție a luminii, a culorilor, a proximității dar și a gesturilor. Detecția gesturilor utilizatorului este funcționalitatea inedită oferită de senzorul APDS-9960. Această funcționalitate o vom utiliza pentru a controla prin gesturi o inimă de hârtie semitransparentă în care vom introduce un LED brick RGB. La pornirea sistemului LED-ul va pulsa roșu. Dacă vom apropria mâna de montaj LED-ul va pulsa din ce în ce mai rapid sugerând  emoție. Dacă vom depărta mâna LED-ul își va schima culoare din roșu în verde sugerând dezamăgire. Există 6 gesturi ce pot fi captate de senzor: apropierea și depărtarea mâinii, mișcare la dreapta, stânga, sus și jos. Având în vedere acest lucru, sistemul propus poate fi complicat mai ales că LED-ul utilizat poate genera o multitudine de culori și moduri de funcționare. Puteți crea o poveste proprie în care să îmbinați gesturi, culori și o „inimă de neatins”.

Pentru implementarea algoritmului de funcționare vom utiliza o placă de dezvoltare Arduino Uno dar poate fi utilizată orice placă Arduino. Conectarea dintre senzor și placa de dezvoltare se va face utilizând magistrala I2C, schema de interconectare este următoarea:

3

Pinul INT al senzorului se va conecta la pinul D2 al plăcii de dezvoltare, SCL la A5, SDA la A4, VCC la 3.3V și GND la GND. Pentru mai multe informații despre funcționarea senzorului APDS-9960 puteți consulta: „APDS-9960 RGB and Gesture Sensor Hookup Guide”.

Brick-ul LED RGB se conectează la placa de dezvoltare prin intermediul pinilor D5 (red), D6 (green) și D9 (blue) – toți cei trei pini ai plăcii de dezvoltare au capabilitatea de a genera semnal PWM adică puteți folosi și efecte de aprindere parțială a oricărei dintre cele trei culori (roșu, verde, albastru).

Programul sistemului este derivat din exemplul GestureTest.ino al bibliotecii Sparkfun APDS-9960 RGB and Gesture Sensor. Programul a fost testat utilizând Arduino IDE 1.8.5 și biblioteca Sparkfun APDS-9960 RGB and Gesture Sensor 1.4.2. În consola serială se va afișa interpretarea gesturilor recunoscute de senzor (FAR, NEAR, UP, DOWN, LEFT, RIGHT) chiar dacă pentru comanda inimii sunt folosite doar două (FAR și NEAR). NONE semnifică nerecunoaștere gestului.

4

#include <Wire.h>

#include <SparkFun_APDS9960.h>

#define APDS9960_INT    2

#define redPin   5

#define greenPin 6

#define bluePin 9

SparkFun_APDS9960 apds = SparkFun_APDS9960();

int isr_flag = 0;

byte r,g,b;

int beat;

void setup() {

  pinMode(APDS9960_INT, INPUT);

  pinMode(redPin, OUTPUT);

  pinMode(greenPin, OUTPUT);

  pinMode(bluePin, OUTPUT);

  Serial.begin(9600);

  Serial.println();

  Serial.println(F(“——————————–“));

  Serial.println(F(“Touchless Heart – Start beating…”));

  Serial.println(F(“——————————–“));

  attachInterrupt(0, interruptRoutine, FALLING);

  if ( apds.init() ) {

    Serial.println(F(“APDS-9960 initialization

complete”));

  } else {

    Serial.println(F(“Something went wrong during APDS-

9960 init!”));

  }

  if ( apds.enableGestureSensor(true) ) {

    Serial.println(F(“Gesture sensor is now running”));

  } else {

    Serial.println(F(“Something went wrong during gesture

sensor init!”));

  }

  r=255;

  g=0;

  b=0;

  beat = 1000;

}

Programul pornește cu un beat (interval de timp aprins / stins) de 1000 ms (1 secundă). La fiecare semn de apropriere (NEAR) recunoscut din acesta se scade 100 ms. La semnul de îndepărtare (FAR) intervalul revine la 1000 ms.

void loop() {

  if( isr_flag == 1 ) {

    detachInterrupt(0);

    handleGesture();

    isr_flag = 0;

    attachInterrupt(0, interruptRoutine, FALLING);

  }

  color(r,g,b);

  delay(beat);

  color(0,0,0);

  delay(beat);

}

void color(byte red, byte green, byte blue) {

  analogWrite(redPin, red);

  analogWrite(greenPin, green);

  analogWrite(bluePin, blue);

}

void interruptRoutine() { isr_flag = 1; }

void handleGesture() {

    if ( apds.isGestureAvailable() ) {

    switch ( apds.readGesture() ) {

      case DIR_UP:

        Serial.println(“UP”);

           break;

      case DIR_DOWN:

        Serial.println(“DOWN”);

        break;

      case DIR_LEFT:

        Serial.println(“LEFT”);

        break;

      case DIR_RIGHT:

        Serial.println(“RIGHT”);

        break;

      case DIR_NEAR:

        Serial.println(“NEAR”);

        r=255;

        g=0;

        beat-=100;

        break;

      case DIR_FAR:

        Serial.println(“FAR”);

        r=0;

        g=255;

        beat = 1000;

        break;

      default:

        Serial.println(“NONE”);

    }

  }

}

Vă recomandăm și un proiect interesant ce utilizează senzorul APDS-9960 pentru a detecta culorile: „Arduino Color Differentiate /with Apds-9960”.

Utilizarea limbajului de asamblare în Arduino IDE

Ce este ”Inline Assembler”?

Facilitatea de ”Inline Assembler” permite inserarea de cod în limbaj de asamblare în cadrul programelor de C/C++ compilate cu ajutorul GCC (compilatorul utilizat de mediul Arduino IDE). Utilizarea de cod în limbaj de asamblare permite optimizarea unor porțiuni de cod și obținerea unor programe mai mici ca dimensiune (în format binar). Pentru mai multe informații se recomandă consultarea materialului „Inline Assembler Cookbook”.

Inserarea de cod în limbaj de asamblare se face utilizând directiva asm (sau ___asm___) direct în program. De exemplu (instrucțiunea NOP în limbaj de asamblare nu are nici un efect):

asm ( “nop \n”);

Bineînțeles, în cadrul secțiunii de cod în limbaj de asamblare nu vom beneficia de aceleași avantaje și înlesniri ca într-un program obișnuit în limbaj de nivel înalt. Pentru a înțelege mai bine vom reface exemplul clasic din Arduino IDE – programul Blink:

void setup() {

  pinMode(13, OUTPUT);

}

void loop() {

  digitalWrite(13, HIGH);

  delay(1000);

  digitalWrite(13, LOW);  

  delay(1000);     

}

O variantă a acestui program utilizând directiva asm este:

void setup() {

 asm(“sbi  0x04, 0x5 \n”);

}

void loop() {

 asm(“cbi  0x05, 0x5 \n”);  

 delay(1000);                

 asm(“sbi  0x05, 0x5 \n”); 

 delay(1000);           

}

După cum se poate observa instrucțiunile pinMode și digitalWrite, specifice mediului Arduino IDE, au fost înlocuite cu instrucțiuni în limbaj de asamblare: sbi și cbi ce permit setarea sau ștergerea unui bit de la o anumită adresă din memorie. Mai mult decât atâta, nu am mai folosit referința la pinul plăcii Arduino așa cum suntem obișnuiți (pinul 13) ci adrese de memorie la care se află registrele interne de configurare ale pinului (registrul de sens DDRB – adresa 0x04 și registrul de ieșire PORTB – adresa 0x05, în ambele registre am manipulat bitul 5 corespondent pinului PB5 adică pinul 13 al plăcii Arduino). Comparați memoria program ocupată de exemplul original și cel care utilizează directiva asm.

2

Registre interne și echivalarea pinilor între mediul Arduino și arhitectura microcontrolerului ATmega328P

Pentru a ușura lucrul cu pinii I/O mediul Arduino IDE are propria modalitate de identificare a acestora (D0-D13, A0-A5) dar în realitate aceștia sunt organizați în trei porturi a câte 8 pini (PB0-PB7, PC0-PC7, PD0-PD7), echivalența între cele două organizări este reprezentată în diagrama următoare (nu toți pinii sunt prezenți la varianta THT a circuitului ATmega328P):

3

Pentru a putea manipula pinii microcontrolerului (la nivel de limbaj de asamblare) este nevoie să cunoaștem adresele registrelor DDRx (registrul de sens) și PORTx (registrul de ieșire) al portului din care face parte pinul. Pentru mai multe informații despre organizarea internă a registrelor interne este utilă consultarea manualului circuitului ATmega328P.

4 

Exemplu de program: joc de lumini

Presupunem următoarea schemă de interconectare a 8 leduri cu placa de dezvoltare Arduino Uno în mod individual – fiecare led este comandat în mod direct de câte un pin al plăcii de dezvoltare (led 1 – pin 2, led 2 – pin 3…. led 8 – pin 9):

5

Funcționalitatea sistemului va consta în realizarea a două jocuri de lumini. Secțiunea setup a programului va trebui să configureze toți cei opt pini utilizați ca fiind pini de ieșire. Varianta inițială ce utilizează instrucțiunea pinMode este:

void setup() {               

  pinMode(2, OUTPUT);

  pinMode(3, OUTPUT);  

  pinMode(4, OUTPUT); 

  pinMode(5, OUTPUT);   

  pinMode(6, OUTPUT); 

  pinMode(7, OUTPUT); 

  pinMode(8, OUTPUT); 

  pinMode(9, OUTPUT);

  Serial.begin(9600);

}

Prima variantă propusă utilizează instrucțiunea sbi ca și în exemplul precedent (adresa 0x0a este adresa registrului DDRD iar adresa 0x04 adresa registrului DDRB):

asm (

  “sbi 0x0a, 2 \n”

  “sbi 0x0a, 3 \n”

  “sbi 0x0a, 4 \n”

  “sbi 0x0a, 5 \n”

  “sbi 0x0a, 6 \n”

  “sbi 0x0a, 7 \n”

  “sbi 0x04, 0 \n”

  “sbi 0x04, 1 \n”

 );

O variantă mai scurtă este configurarea biților din cele două registre (DDRD și DDRB) simultan utilizând registrul de uz general R26 ca intermediar pentru transmiterea valorii către cele două registre:

asm (

    “ldi r26, 0b11111100 \n”

    “out 0x0a, r26 \n”

    “ldi r26, 0b00000011 \n”

    “out 0x04, r26 \n”

    : : : “r26”

    );

Utilizarea unui registru de uz general trebuie semnalizată compilatorului pentru a nu apărea suprapuneri în utilizarea registrelor – ultima linie din cod, a se vedea și materialul „Arduino Inline Assembly Tutorial #3 (Clobbers)”.

Prima variantă de joc de lumini va aprinde alternativ la un interval de 1 secundă ledurile de rang impar și ledurile de rang par (led 1, led 3, led 5, led 7 – led 2, led 4, led 6, led 8). Secțiunea loop (utilizând cod Arduino) este:

void loop() {

  for (int i=2; i<10; i++) {

      if ((i%2)==0) digitalWrite(i,HIGH);

      else digitalWrite(i,LOW);

   }

   delay(1000); 

   for (int i=2; i<10; i++) {

      if ((i%2)==0) digitalWrite(i,LOW);

      else digitalWrite(i,HIGH);

   }

   delay(1000);

}

Transpunerea în limbaj de asamblare este:

void loop() {

asm (

      “sbi 0x0b,2 \n”

      “cbi 0x0b,3 \n”

      “sbi 0x0b,4 \n”

      “cbi 0x0b,5 \n”     

      “sbi 0x0b,6 \n”

      “cbi 0x0b,7 \n”

      “sbi 0x05,0 \n”

      “cbi 0x05,1 \n”

      “ldi r25, 0x7F \n”

      “wait1: ldi r26, 0xFF \n”

      “wait2: ldi r27, 0xFF \n”

      “wait3: dec r27 \n”

      “nop \n”

      “brne wait3 \n”

      “dec r26 \n”

      “brne wait2 \n”

      “dec r25 \n”

      “brne wait1 \n”     

      “cbi 0x0b,2 \n”

      “sbi 0x0b,3 \n”

      “cbi 0x0b,4 \n”

      “sbi 0x0b,5 \n”     

      “cbi 0x0b,6 \n”

      “sbi 0x0b,7 \n”

      “cbi 0x05,0 \n”

      “sbi 0x05,1 \n”

      “ldi r25, 0x7F \n”

      “wait1b: ldi r26, 0xFF \n”

      “wait2b: ldi r27, 0xFF \n”

      “wait3b: dec r27 \n”

      “nop \n”

      “brne wait3b \n”

      “dec r26 \n”

      “brne wait2b \n”

      “dec r25 \n”

      “brne wait1b \n”

      : : : “r25” , “r26”, “r27”

  ); 

Cea de a doua variantă de joc de lumini va aprinde unul câte unul (pornind de la led-ul 1 până la led-ul 8) toate led-urile și apoi le va stinge în mod similar (în ordine inversă). Operația de aprindere sau stingere a unui led se va efectua la un interval de 500 milisecunde. Secțiunea loop (utilizând cod Arduino) este:

void loop() {

   for (int i=2;i<10;i++) {

     digitalWrite(i,HIGH);

     delay(500); }

   for (int i=9;i>1;i–) {

     digitalWrite(i,LOW);

     delay(500);

   }

  }

Transpunerea în limbaj de asamblare este:

void loop() {

asm (

      “start: sbi 0x0b,2 \n”

      “rcall wait \n”

      “sbi 0x0b,3 \n”

      “rcall wait \n”

      “sbi 0x0b,4 \n”

      “rcall wait \n”

      “sbi 0x0b,5 \n”

      “rcall wait \n”     

      “sbi 0x0b,6 \n”

      “rcall wait \n”

      “sbi 0x0b,7 \n”

      “rcall wait \n”

      “sbi 0x05,0 \n”

      “rcall wait \n”

      “sbi 0x05,1 \n”

      “rcall wait \n”     

      “cbi 0x0b,2 \n”

      “rcall wait \n”

      “cbi 0x0b,3 \n”

      “rcall wait \n”

      “cbi 0x0b,4 \n”

      “rcall wait \n”

      “cbi 0x0b,5 \n”

      “rcall wait \n”     

      “cbi 0x0b,6 \n”

      “rcall wait \n”

      “cbi 0x0b,7 \n”

      “rcall wait \n”

      “cbi 0x05,0 \n”

      “rcall wait \n”

      “cbi 0x05,1 \n”

      “rcall wait \n”     

      “rjmp start \n”

      “wait: ldi r25, 0x3F \n”

      “wait12: ldi r26, 0xFF \n”

      “wait22: ldi r27, 0xFF \n”

      “wait32: dec r27 \n”

      “nop \n”

      “brne wait32 \n”

      “dec r26 \n”

      “brne wait22 \n”

      “dec r25 \n”

      “brne wait12 \n”

      “ret \n”

      : : : “r25” , “r26”, “r27”

  );

}

Ambele jocuri de lumini utilizează instrucțiunile sbi și cbi pentru manipularea pinilor I/0 (pentru o listă completă a instrucțiunilor în limbaj de asamblare se recomandă parcurgerea materialului „AVR Instruction Set Manual”). Funcția de temporizare delay din mediul Arduino IDE este înlocuită cu o succesiune de bucle ce realizează o întârziere aproximativă (în a doua variantă această succesiune este implementată ca o subrutină).

Sistem antifurt pentru cadourile de Crăciun

Securitatea cadourilor de Crăciun este o problemă care ar trebui să preocupe pe toți părinții responsabili. Hoți, persoane răuvoitoare și mai ales personajul malefic Grinch abia așteaptă să distrugă bucuria copiilor din dimineața zilei de Crăciun.

2

Pentru a împiedica acest lucru este absolut necesar ca toate cadourile să fie dotate cu sisteme de siguranță pentru a preveni furtul de sub bradul de Crăciun. În cadrul acestui proiect vă propunem realizarea unui sistem sofisticat care permite declanșarea unei alarme sonore când un cadou este sustras de sub brad.

Sistemul antifurt este bazat pe o placă de dezvoltare Arduino Uno ce are conectate un mini difuzor brick și un senzor magnetic brick. Mini difuzorul este utilizat pentru a genera sunetul de alarmă iar senzorul magnetic pentru a sesiza dacă cadoul a fost mișcat. Pentru a sesiza mișcarea / mutarea cadoului acesta trebuia să aibă integrat un mic magnet. Mișcarea magnetului este sesizată de senzorul magnetic Hall și semnalizată plăcii de dezvoltare ce declanșează alarma sonoră.

3

Mini difuzorul se va conecta la pinul digital 8 al plăcii de dezvoltare și la pinul de GND. Generarea sunetului de alarmă se va face utilizând funcția tone() din mediul Arduino IDE.

Senzorul magnetic brick se conecta la 5V și GND iar ieșirea (OUT) se va conecta la pinul digital 2 al plăcii de dezvoltare. Ieșirea senzorului va fi ”1” (adică 5V) dacă nu detectează un magnet în apropiere sau ”0” (adică 0V) dacă un magnet se află în imediata apropiere.

4

Schema de interconectare între cele trei componente este următoarea:

5

Programul a fost dezvoltat și testat utilizând mediul Arduino IDE 1.8.3.

#define hallPin 2

#define buzzerPin 8

void setup() {

  pinMode(hallPin,INPUT);

  pinMode(buzzerPin, OUTPUT);

}

void loop() {

  boolean alarma;

  alarma = digitalRead(hallPin);

  if (!alarma) tone(buzzerPin,1000);

  else noTone(buzzerPin);

  delay(5000);

}

După încărcarea programului pe placa de dezvoltare și instalarea sistemului antifurt sub cadou, în cazul în care se îndepărtează cadoul de pe sistemul antifurt se va declanșa alarma sonoră ce va zădărnici tentativa de furt.

În cazul în care dorim să micșorăm dimensiunea sistemului antifurt putem înlocui placa de dezvoltare Arduino Uno cu o placă Arduino Pro Mini. În plus putem alimenta sistemul de la o baterie de 9V și pentru a prelungi durata de funcționare vom configura microcontrolerul să funcționeze în regim de consum redus. Noua schemă de interconectare este:

6

Programul a fost realizat și testa utilizând mediul Arduino IDE 1.8.3 și biblioteca LowPower.

#include “LowPower.h”

#define wakeUpPin 2

#define buzzerPin 8

void setup() {

  pinMode(wakeUpPin,INPUT);

  pinMode(buzzerPin, OUTPUT);

}

void wakeUp(){ }

void loop() {

  attachInterrupt(0, wakeUp, HIGH);

  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);

  detachInterrupt(0);

  while (digitalRead(wakeUpPin)==1) {

    tone(buzzerPin,1000);

    delay(1000);

  }

  noTone(buzzerPin);

}

Spre deosebire de programul anterior, sistemul antifurt va funcționa în mod de consum redus. Declanșarea senzorului magnetic (mișcarea cadoului de pe sistemul antifurt) va declanșa o întrerupere ce va trezi microcontrolerul și va porni alarma sonoră. Dacă cadoul este pus la loc alarma va înceta.

Cum să realizăm un sistem IoT LoRaWAN

În cadrul proiectului ”LoRa meets Robofun IoT” am văzut cum putem realiza un sistem IoT utilizând comunicația radio LoRa. Utilizând module radio LoRa putem transmite date la mare distanță dar pentru implementarea unui sistem IoT este necesară implementarea atât a modulului de achiziție (sau acționare) cât și a sistemului de tip gateway ce face legătura cu rețeaua Internet și cu serviciile cloud IoT. Specificațiile LoRaWAN permit implementare unor rețele radio LoRa standardizate astfel încât sistemele gateway să permită conectarea dispozitivelor IoT după un set de reguli larg acceptate. Realizarea unui sistem IoT LoRaWAN presupune realizare unui sistem de achiziție / acționare care respectă acest set de reguli și se conectează la o infrastructură de gateway-uri deja existentă (nu mai este nevoie să realizăm și să operăm sistemul gateway). Există mai multe rețele de gateway-uri LoRaWAN dar în cadrul acestui proiect vom arăta cum putem realiza un sistem ce folosește rețeaua TTN (The Things Network). Accesul în rețeaua TTN este gratuit deoarece se bazează pe gateway-uri particulare partajate între utilizatorii rețelei. Tot ce trebuie să faceți este să verificați dacă vă aflați în aria de acoperire a unui sistem gateway TTN.

Pentru sistemul IoT vom utiliza o placă de dezvoltare Arduino Uno și un shield Dragino LoRa echipat cu un modul radio LoRa în frecvență de 868MHz. Pentru partea de achiziție vom exemplifica măsurarea temperaturii utilizând un senzor brick conectat la pinul analogic A0 al plăcii de dezvoltare.

3

Pentru implementarea comunicației LoRaWAN vom utiliza biblioteca Arduino-LMIC. Testele au fost realizate utilizând Arduino IDE 1.8.3 și versiunea 1.5.0+arduino-1 a bibliotecii. Programul pleacă de la exemplul ttn-abp al bibliotecii în care vom efectua o serie de mici modificări. În primul rând trebuie să înregistrăm sistemul pe platforma TTN pentru a obține datele de autentificare în rețea:

static const PROGMEM u1_t NWKSKEY[16] = { … };

static const u1_t PROGMEM APPSKEY[16] = { … };

static const u4_t DEVADDR = … ;

Înregistrarea presupune crearea unui cont de utilizator, definirea unei aplicații (Applications) și, în cadrul aplicației, definirea unui dispozitiv (Device). În secțiunea se setări (Settings) a noului dispozitiv trebuie aleasă metoda ABP de activare și debifată opțiunea Frame Counter Checks. Tot în cadrul acestei secțiuni se regăsesc datele de autentificare în rețeua TTN. Pentru mai multe detalii legate de definirea aplicației și dispozitivului în rețeua TTN se poate consulta și materialul „LoRaWAN IoT with Arduino Uno, Dragino v1.3 & TheThingsNetwork”.

4

Tot în secțiunea de inițializare a exemplului se va șterge declarația mesajului mydata (se va defini din nou în program sub o altă formă) și se va modifica intervalul de postare a mesajelor (postarea la 1 minut este destul de agresivă pentru politica de utilizare a rețelei TTN).

const unsigned TX_INTERVAL = 3600;

Shield-ul Dragino LoRa necesită următoarea modificare în structura de definire a pinilor utilizați:

const lmic_pinmap lmic_pins = {

    .nss = 10,

    .rxtx = LMIC_UNUSED_PIN,

    .rst = 9,

    .dio = {2, 6, 7},

};

Ultima modificare adusă exemplului ttn-abp este rescrierea procedurii do_send pentru a trasmite valoare achiziționată de la brick-ul de temperatură în locul mesajului text predefinit. După cum se poate observa se va transmite valoarea returnată de funcția analogRead, prelucrarea numerică pentru a obține valoarea temperaturii se va face în sistemul cloud TTN.

void do_send(osjob_t* j){

    static uint8_t mydata[2];

    int reading = analogRead(A0);

    mydata[0] = highByte(reading);

    mydata[1] = lowByte(reading);

    if (LMIC.opmode & OP_TXRXPEND) {

        Serial.println(F(“OP_TXRXPEND, not sending”));

    } else {

        LMIC_setTxData2(1, mydata, sizeof(mydata), 0);

        Serial.println(F(“Packet queued”));

    }

}

După punerea în funcțiune a sistemului, și dacă vă aflați în aria de acoperire a unui gateway TTN, în consola TTN vor începe să apară valorile transmise de acesta (secțiunea Application Data). După cum se poate observa datele transmise sunt sub forma unui șir de valori în hexazecimal (2 octeți – 16 biți).

5

Pentru a transforma datele primite într-o formă mai ușor de înțeles se va scrie o funcție de decodare (în secțiunea Payload Formats / decoder). Această funcție va avea și rolul de a calcula temperatura echivalentă valorii achiziționate. După implementarea acestei funcții vom putea vedea în secțiunea de Application Data valoarea efectivă a temperaturii.

function Decoder(bytes, port) {

  var decoded = (((((bytes[0]<<8)|bytes[1])*5.0)/1024.0)-0.5)*100;

  return { value:decoded };

}

6

Atenție!!! Platforma TTN nu este o platformă IoT – nu stochează datele preluate de la sistemele LoRaWAN. Datele se pot observa în consolă doar dacă sunt transmise atunci când consola este deschisă. Platforma TTN permite în schimb transmiterea datelor primite prin rețeaua LoRaWAN către alte platforme online inclusiv platforme IoT. În secțiunea Integrations se pot defini diverse mecanisme automate de redirectare a datelor către sisteme precum Cayenne, OpenSensors sau IFTTT. Vom explica în cele ce urmează cum putem transmite datele către serviciul IFTTT care ne va trimite apoi valoarea temperaturii prin email. Bineînțeles, multitudinea de opțiuni oferite de platforma IFTTT permite redirectarea datelor către un serviciu IoT, postarea pe o rețea de socializare sau interacțiunea directă cu alte dispozitive IoT.

Definirea mecanismului automat de trimitere a datelor către serviciului IFTTT presupune adăugarea unui integrator de tipul IFTTT Maker (add integration / secțiunea Integrations). Conexiunea între cele două servicii (TTN și IFTTT) se realizează pe baza Event Name (trebuie să fie identic cu numele declanșatorului IFTTT) și Key (cheie de autentificare oferită de obiectul IFTTT Webhooks).

7

În cadrul platformei IFTTT se va realiza o regulă ce va avea declanșator serviciul Webhooks (Event Name trebuie să fie identic cu cel definit în platforma TTN) și ca efect transmiterea unui email.

8

La fiecare valoare a temperaturii transmisă de sistemul nostru vom primi un email de forma:

9

Pentru mai multe variante de realizare a unui sistem IoT LoRaWAN se pot consulta și următoarele materiale:

Norul udă ghivecele cu flori

Chiar dacă un sistem automat de menținere a umidității pentru ghivecelor cu flori rezolvă problema ”am uitat să ud florile” nu rezolvă și problema monitorizării exacte a umidității (necesare pentru diverse tipuri de plante mai pretențioase). Adăugarea unui sistem de jurnalizare a umidității permite vizualizarea și determinarea punctului de umiditate optimă pentru diverse astfel de tipuri de plante. În cadrul proiectului de față ne propunem să completăm sistemul prezentat în proiectul precedent (Arduino udă ghivecele cu flori) cu un sistem de monitorizare și comandă online. Pentru acest lucru vom utiliza serviciul online (de tip ”nor”) Adafruit IO. Serviciul Adafruit IO este un serviciu specializat IoT, gratuit, ce pune la dispoziția utilizatorilor atât posibilitatea jurnalizării valorilor preluate de la diverși senzori dar și transmiterea de comenzi către dispozitivele IoT și chiar legătura automată între partea de achiziție și comandă (reguli de conducere automată).

Pentru implementarea sistemului prezentat în această lecție este necesară crearea unui cont pe platforma Adafruit IO. După conectare trebuie să navigăm în meniul Settings și să ne notăm AIO Keys (cheia de autentificare) care va fi folosită, împreună cu denumirea contului creat, în programul sistemului.

Din punct de vedere hardware sistemul va avea în plus un modul Adafruit HUZZAH ESP8266 ce va asigura conectivitatea de rețea necesară accesării serviciului cloud.

2Astfel componentele necesare implementării sistemului sunt: Arduino Uno, shield drivere de motoare L298, senzor umiditate sol, pompă de apă micro, ecran LCD grafic Nokia (opțional) și modul Adafruit HUZZAH ESP8266. Alimentarea sistemului se va face de la un alimentator de rețea de 9V conectat la placa de dezvoltare Arduino Uno. Alimentatorul va alimenta atât componentele de comandă (placă de dezvoltare, modul WiFi, ecran LCD, senzor de umiditate sol) cât și pompa de apă (prin intermediul shield-ului L298 ce trebuie să aibă jumperul de alimentare comună conectat).

Conexiunile între componentele sistemului sunt următoarele:

  • Pompa de apă se conectează la shield-ul L298 pe canalul MOTOR2:

3

  • Senzorul de umiditate sol va utiliza pinul A0 pentru a transmite valoarea achiziționată către placa de dezvoltare, pinul A2 pentru alimentare și un pin de GND.

4

  • Ecranul LCD va utiliza următorii pini pentru conectare: LED – 5V (prin intermediul unei rezistențe de 220ohm), SCLK – D13, D/C – D8, RST – D7, SCE – A3 (nu mai putem folosi pinul D4 ca în cazul lecției precedente deoarece acest pin va fi utilizat de modul WiFi), GND – GND, Vcc – 3.3V.
  • Modulul WiFi Adafruit HUZZAH ESP8266 se va monta în soclul shield-ului L298 (soclu gândit pentru modul bluetooth dar compatibil și cu modulul WiFi utilizat de noi) – ATENȚIE la polaritate – conectați pinul de GND al modului la pinul de GND al soclului.

5

Înainte de asamblarea sistemului modulul WiFi trebuie programat separat de programarea plăcii Arduino Uno. Pentru programare este necesară utilizarea unui cablu USB to TTL sau a unui conector FTDI. Pentru programarea și utilizarea modulului Adafruit HUZZAH este recomandată parcurgerea materialului următor: Adafruit HUZZAH ESP8266 breakout .

Programul pentru modulul WiFi are rolul de a transforma comunicația serială (de la placa Arduino Uno) în mesaje MQTT pentru platforma Adafruit IO. Programul a fost dezvoltat și testat cu Arduino IDE 1.8.1 având instalată extensia ESP8266 Community 2.3.0 și utilizează biblioteca Adafruit MQTT 0.17.0. În program trebuie personalizate datele de conectare la rețeaua WiFi locală (WLAN_SSID și WLAN_PASS) precum și datele de conectare la serviciul cloud Adafruit IO (AIO_USERNAME și AIO_KEY).

#include <ESP8266WiFi.h>

#include “Adafruit_MQTT.h”

#include “Adafruit_MQTT_Client.h”

#define WLAN_SSID       “

#define WLAN_PASS       “

#define AIO_SERVER      “io.adafruit.com”

#define AIO_SERVERPORT  1883

#define AIO_USERNAME    “

#define AIO_KEY         “

WiFiClient client;

Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_USERNAME, AIO_KEY);

Adafruit_MQTT_Publish soilhumidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME “/feeds/soilhumidity”);

Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME “/feeds/onoff”);

void onoffcallback(char *data, uint16_t len) {

  String onoff_state = String(data);

  if (onoff_state==”ON”) Serial.println(“1”);

  else if (onoff_state==”OFF”) Serial.println(“0”);

}

void setup() {

  Serial.begin(115200);

  delay(10);

  Serial.println(F(“Adafruit MQTT NOR”));

  WiFi.begin(WLAN_SSID, WLAN_PASS);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);  }

  onoffbutton.setCallback(onoffcallback);

  mqtt.subscribe(&onoffbutton);

}

uint32_t x;

void loop() {

  MQTT_connect();

  mqtt.processPackets(100);

  if(Serial.available()){

    x=Serial.parseInt();

    soilhumidity.publish(x);

    }

  if(! mqtt.ping()) {

    mqtt.disconnect();

  }

}

void MQTT_connect() {

  int8_t ret;

  if (mqtt.connected()) {

    return;

  }

  uint8_t retries = 3;

  while ((ret = mqtt.connect()) != 0) {

        mqtt.disconnect();

       delay(10000);

       retries–;

       if (retries == 0) { while (1); }

  }

}

Programul pentru placa de dezvoltare Arduino Uno nu diferă foarte mult de varianta prezentată în proiectul precedent. Este necesară modificarea declarării obiectului LCD:

Adafruit_PCD8544 display = Adafruit_PCD8544(8, A3, 7);

declararea și configurarea comunicației seriale cu modulul WiFi:

#include “SoftwareSerial.h”

SoftwareSerial mySerial(2,4);

void setup()

{

  mySerial.begin(115200);

și de câteva completări în secțiunea loop():

void loop()

  int command = 0;

  int soilhumidity;

  digitalWrite(SOIL_VCC,LOW);

  mySerial.println(soilhumidity);

  display.println(millis()/1000);

  if(mySerial.available()){

    command = mySerial.parseInt();

  }

  if ((soilhumidity<500)||(command==1)) {

Programul ce rulează pe placa Arduino raportează serial către modulul WiFi valoarea umidității solului iar acesta raportează mai departe către serviciul cloud prin intermediul canalului soilhumidity. După prima execuție acest canal va apărea automat în interfața Adafruit IO.

6

În plus, sistemul va permite și comanda de la distanță a procesului de udare. Pentru acest lucru este nevoie să creăm manul în interfața Adafruit IO un canal denumit onoff. Acest canal va transmite către modulul WiFi comenzi de tipul ON / OFF, acestea vor fi retransmise către placa Arduino Uno ca și comenzi seriale de tip 1 / 0 și vor permite pornirea procesului de udare independent de valoarea umidității solului.

Pentru a putea transmite comenzile din interfața Adafruit IO putem crea o nouă consolă de comandă în secțiunea Dashboards. În această consolă de comandă putem plasa graficul de evoluție (Line Chart) a parametrului măsurat (umiditate sol) și un buton (Toggle) pentru comanda de udare.

7

În acest moment avem un sistem complet de urmărire și control la distanță a sistemului de udare – interfața web a serviciului Adafruit IO se poate accesa de oriunde de pe Internet.

Bineînțeles, sistemul propus poate fi îmbunătățit prin adăugarea mai multor parametrii de supravegheat (putem adăuga senzori de temperatură și umiditate a aerului, senzori de intensitate a luminii solare) completând astfel procesul de urmărire și control. Mai mult decât atât, serviciul Adafruit IO permite definirea de alarme de urmărire (avertizarea prin email când un parametru urmărit atinge un anume prag) sau chiar definirea de acțiuni asupra elementelor de comandă (putem implementa pragul de declanșare a procesului de udare la nivel de serviciu cloud).

Pentru mai multe detalii legate de funcționarea serviciului Adafruit IO puteți vedea și următoarele proiecte:

Monitor temperature & humidity from anywhere!

ESP8266 Power Meter Measure the DC power consumption of your devices!

Remote Control with the Huzzah + Adafruit.io

Log Light Levels to Adafruit IO

Track Your Treats: Halloween Candy GPS Tracker

Arduino udă ghivecele cu flori

Se dau: o problemă cotidiană foarte des întâlnită și o mulțime de soluții parțiale ce nu rezolvă niciodată problema propriu-zisă. Cam așa se poate rezuma problema implementării unui sistem bazat pe placa de dezvoltare Arduino Uno ce permite automatizarea procesului de udare a ghivecelor cu flori. Majoritatea exemplelor existente permit măsurarea umidității din sol dar nu implementează și partea de acționare propriu-zisă mulțumindu-se să ”te tragă de mânecă” când trebuie să uzi florile sau să-ți trimită un email de atenționare. Proiectul de față își propune să implementeze o soluție completă (achiziție plus acționare) ajutând astfel pe oricine să-și permită să uite să ude florile fără a le pune în pericol.

Componentele utilizate de sistem sunt foarte comune facilitând astfel implementarea la un cost rezonabil: placă de dezvoltare Arduino Uno, shield drivere de motoare L298, senzor umiditate sol, pompă de apă micro și ecran LCD Nokia (opțional).

23

Shield-ul de motoare L298 este utilizat deobicei în construcția platformelor robotice telecomandate (a se vedea seria de roboți FlexyBot) dar se poate utiliza și în cazul nostru – pompa de apă nu este altceva decât un motor de curent continuu. Se poate utiliza și un releu pentru comanda pompei dar se pierde capabilitatea de control al turației (debitului). Shield-ul este capabil să comande două motoare, sistemul propus folosește o singură ieșire de comandă dar permite o extindere simplă ulterioară.

Conectarea pompei de apă la shield se va face pe canalul Motor2 având grijă la pinul marcat cu bulină roșie al pompei. Shield-ul va fi utilizat cu jumper-ul de alimentare comună pus, astfel vom putea alimenta și placa de dezvoltare și pompa de la un singur alimentator de 9V conectat la placa de dezvoltare (mufa de alimentare a plăcii de dezvoltare).

4

Dacă se respectă conectarea indicată sensul de udare al pompei va fi următorul:5

Pentru conectarea pompei de apă la un recipient cu apă (pompa nu este proiectată să fie conectată la o sursă de apă cu presiune proprie!!!) și la ghivecele cu flori ce urmează a fi udate se poate folosi tub de silicon cu diametrul interior de 3mm (sunt utilizate de obicei la acvarii). În plus se pot utiliza diverși conectori specifici pentru a realiza o instalație care să permită udarea mai multor ghivece simultan:

6

7

Este recomandat ca recipientul (rezervorul) de apă să nu fie mai jos ca sistemul de udare pentru a nu forța pompa să ridice apa.

Senzorul de umiditate sol (pinul SIG) se va conecta la placa de dezvoltare (prin intermediul shield-ului) la pinul analogic A0. Pinul de alimentare al senzorului se va conecta la pinul A2, senzorul va fi alimentat doar când se va efectua citirea. Alimentarea continuă a senzorului poate duce la deterioarea rapidă a acestuia din cauza efectului de electroliză. Ieșirea senzorului nu este calibrată, nu putem calcula precis cantitatea de apă din sol pe baza acestui senzor. Citirile sunt afectate destul de mult și de tipul de sol din ghiveciul cu flori. Având în vedere că citirile analogice se alfă în plaja 0 – 1023 vom stabili un prag sub care vom considera că ghiveciul are nevoie de apă (pragul stabilit în program va fi 500).

8

Este recomandată parcurgerea următorului material pentru a înțelege mai bine funcționarea senzorului de umiditate a solului: Soil Moisture Sensor Hookup Guide.

Ecranul LCD va permite urmărirea funcționării sistemului dar sistemul poate îndeplini sarcina stabilită și fără conectarea acestuia. Ecranul grafic LCD Nokia funcționează la 3.3V, conectarea linilor la pinii Arduino de 5V scade durata de viață a afișajului. Este recomandată adăugarea unui circuit de translatare a nivelurilor logice, a se vedea și materialul: Graphic LCD Hookup Guide.

Conexiunile necesare afișajului LCD sunt următoarele:

9

  • Pinul LED al LCD-ului, prin intermediul unei rezistențe de 220ohm, se va conecta la 5V (sau un un pin PWM dacă se dorește variația intensității luminii de fundal);
  • Pinul SCLK al LCD-ului se va conecta la pinul 13 al plăcii de dezvoltare;
  • Pinu DIN (MOSI) al LCD-ului se va conecta la pinul 11 al plăcii de dezvoltare;
  • Pinul D/C la pinul 8;
  • Pinul RST la pinul 7;
  • Pinul SCE la pinul 4;
  • Pinul GND la GND;
  • Pinul Vcc la 3.3V.

Pentru a putea lucra cu LCD-ul programul va utiliza biblioteciile Adafruit GFX și Adafruit PCD8544.

#include <SPI.h>

#include <Adafruit_GFX.h>

#include <Adafruit_PCD8544.h>

Adafruit_PCD8544 display = Adafruit_PCD8544(8, 4, 7);

#define MOTOR2_PIN1 3

#define MOTOR2_PIN2 5

#define SOIL_PIN    A0

#define SOIL_VCC    A2

void setup() {

  display.begin();

  display.setContrast(50);

  delay(1000);

  display.clearDisplay();

  display.display();

  pinMode(MOTOR2_PIN1, OUTPUT);

  pinMode(MOTOR2_PIN2, OUTPUT);

  digitalWrite(MOTOR2_PIN2, LOW);

  pinMode(SOIL_VCC, OUTPUT);

  digitalWrite(SOIL_VCC, LOW); 

  delay(1000);

}

În cadrul secțiunii loop() a programului se va efectua citirea senzorului de umiditate a solului (cu activarea prealabilă a pinul A2 pentru a alimenta senzorul) și în funcție de valoarea citită (dacă valoarea citită este mai mică de 500) se pornește un ciclu de udare format din trei perioade de 1 secundă alternate cu trei perioadă de pauză de 1 secundă. Pompa este comandată la jumătatea puterii maxime (125 din 255). În funcție de dimensiunea ghiveciului sau / și de numărul de ghivece udate ciclul de udare poate fi ajustat ca durată și putere comandată pompei de apă.

unsigned long lasttime = 0;

void loop()

  int soilhumidity;

  digitalWrite(SOIL_VCC,HIGH);

  delay(1000);

  soilhumidity = analogRead(SOIL_PIN);

  digitalWrite(SOIL_VCC,LOW);

  display.clearDisplay();

  display.display();

  display.setTextSize(1);

  display.setTextColor(BLACK);

  display.setCursor(0,0);

  display.print(“Soil hum:”);

  display.println(soilhumidity);

  display.print(“Time:”);

  display.println(millis()/1000);

  if (soilhumidity<500) {

        display.println(“Status: ON”);

        display.display();

        delay(100);

        analogWrite(MOTOR2_PIN1, 125);

        delay(1000);

        analogWrite(MOTOR2_PIN1, 0);

        delay(1000);

        analogWrite(MOTOR2_PIN1, 125);

        delay(1000);

        analogWrite(MOTOR2_PIN1, 0);

        delay(1000);

        analogWrite(MOTOR2_PIN1, 125);

        delay(1000);

        analogWrite(MOTOR2_PIN1, 0);

        lasttime = millis()/1000;

  }

  else {

        display.println(“Status: OFF”);

  }

  display.print(“LastTime:”);

  display.println(lasttime);

  display.display();

  delay(100);

}

Afișajul LCD va afișa în permanență valoarea citită de la senzorul de umiditate sol, timpul în secunde de la pornirea sistemului: Time, starea sistemului de comandă (ON/OFF – udă/nu udă) și timpul la care s-a efectuat ultimul ciclu de udare: LastTime (estimat în secunde de la pornirea sistemului). Afișarea timpului poate fi rafinată prin transformarea valorii afișate în HH:MM:SS nu doar în secunde.

10

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.1 și bibliotecile Adafruit GFX 1.1.8 și Adafruit PCD8544 1.0.0.

Sistemul prezentat poate fi îmbunătățit prin adăugarea unor elemente suplimentare de achiziție (temperatură, umiditate aer, putere lumină solară) pentru a realiza un sistem de automatizare care să țină seama de mai mulți factori în alegerea momentului optim de udare. Pentru inspirație se pot studia și următoarele proiecte: