LoRa meets Robofun IoT

Modulele radio LoRa oferă posibilitatea de a transmite date la distanță mare (sute de metri sau chiar kilometri) utilizând module electronice de cost redus și cu un consum de energie scăzut. Acest lucru constituie o metodă eficientă pentru a extinde aria de acoperire pentru rețelele IoT fără fir. Chiar dacă semnalul WiFi are o acoperire limitată fiind influențat de puterea dispozitivelor de tip AP și de mediul în care operează (câmp deschis, locuințe sau birouri) există posibilitatea să extindem aria de acoperire radio a unei rețele IoT prin intermediul comunicațiilor ISM iar soluțiile LoRa oferă o variantă foarte bună cost / arie de acoperire.

Pentru a implementa o soluție LoRa în vederea extinderii ariei de acoperire IoT vom implementa un sistem gateway ce va realiza transferul datelor provenite de la modulele IoT către un sistem specific IoT și anume Robofun IoT. Modulul gateway propus se bazează pe placa de dezvoltare NodeMCU ce oferă conectivitate WiFi și un modul LoRa RFM96W în bandă de 433MHz. Conexiuniile între placa de dezvoltare și modulul radio sunt prezentate în diagrama următoare:

2.png

Modulul radio RFM96W se interconectează cu placa de dezvoltare prin intermediul magistralei SPI:

  • Pinul SCK al modulului se conectează la pinul D5 (GPIO14 – HSCLK);
  • Pinul MISO se conectează la pinul D6 (GPIO12 – HMISO);
  • Pinul MOSI se conectează la pinul D7 (GPIO13 – HMOSI);
  • Pinul CS se conectează la pinul D2;
  • Pinul RST se conectează la pinul D3;
  • Pinul G0 (INT) se conectează la pinul D1;
  • Vin și GND la pinii 3.3V și GND ai plăcii de dezvoltare.

Pentru ca placa să poată transmite prin Internet datele către serviciul Robofun IoT este necesară înregistrarea gratuită pe platformă:

3

După înregistrare și conectare este necesară definirea (Adauga senzor) a trei senzori: Temperatura, Umiditate și Nivel baterie, pentru a putea transmite datele primite de la sistemul IoT către platforma online. După definirea fiecărui senzor este necesar să copiem cheia de autentificare (Token) pentru a fi utilizată în program.

4

5

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3 (pentru instalarea plăcii NodeMCU sub Arduino IDE se poate vedea materialul „Quick Start to Nodemcu (ESP8266) on Arduino IDE”), extensia esp8266 versiunea 2.3.0 și biblioteca RadioHead 1.7.9. În cadrul programului trebuie personalizate datele de conectare la rețeaua WiFi (ssid și password) precum și cheile de autentificare pentru cele trei canale IoT (SENSOR_TOKEN1, SENSOR_TOKEN2 și SENSOR_TOKEN3).

#include <SPI.h>

#include <RH_RF95.h>

#include <ESP8266WiFi.h>

#include <ESP8266HTTPClient.h>

const char* ssid = “…”;

const char* password = “…”;

#define RFM95_CS D2

#define RFM95_RST D3

#define RFM95_INT D1

#define RF95_FREQ 434.0

RH_RF95 rf95(RFM95_CS, RFM95_INT);

#define LED D0

void setup() {

  pinMode(LED, OUTPUT);

  digitalWrite(LED,HIGH);    

  pinMode(RFM95_RST, OUTPUT);

  digitalWrite(RFM95_RST, HIGH);

  Serial.begin(9600);

  delay(100);

  Serial.println();

  Serial.println();

  Serial.println(“Gateway Module starting…”);

  Serial.print(“Connecting to “);

  Serial.println(ssid);

  WiFi.begin(ssid, password);

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

      delay(500);

      Serial.print(“.”);

    }

    Serial.println(“”);

    Serial.println(“WiFi connected”);

  digitalWrite(RFM95_RST, LOW);

  delay(10);

  digitalWrite(RFM95_RST, HIGH);

  delay(10);

  while (!rf95.init()) {

    Serial.println(“LoRa radio init failed”);

    while (1);

  }

  Serial.println(“LoRa radio init OK!”);

  if (!rf95.setFrequency(RF95_FREQ)) {

    Serial.println(“setFrequency failed”);

    while (1);

  }

  Serial.print(“Set Freq to: “);

  Serial.println(RF95_FREQ);

}

typedef struct {float temperature; float humidity;

float bat_voltage;} ParametriiRX;

ParametriiRX parametrii;

Ledul de pe placa de dezvoltare (conectat pe pinul D0) se va aprinde pe perioada recepției de mesaje LoRa. Toate datele primite prin intermediul LoRa vor fi postate pe platforma Robofun IoT. Sistemul va raporta și în consola serială toate mesajele recepționate.

6

void loop() {

  if (rf95.available())  {

    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];

    uint8_t len = sizeof(buf);

    if (rf95.recv(buf, &len)){

      digitalWrite(LED, LOW);

      RH_RF95::printBuffer(“Received: “, buf, len);

      parametrii = *(ParametriiRX*)buf;

      Serial.print(“Temperature: “);

      Serial.println(parametrii.temperature);

      Serial.print(“Humidity: “);

      Serial.println(parametrii.humidity);

      Serial.print(“Battery Voltage: “);

      Serial.println(parametrii.bat_voltage);

      Serial.print(“RSSI: “);

      Serial.println(rf95.lastRssi(), DEC);

      digitalWrite(LED, HIGH);

      String SENSOR_TOKEN1=”…”;

      String SENSOR_TOKEN2=”…”;

      String SENSOR_TOKEN3=”…”;

      HTTPClient http;

      String data = String(“http://iot.robofun.ro/api/v1/senzor/&#8221;) + SENSOR_TOKEN1 + “/input?value=” + String(parametrii.temperature, DEC);

      http.begin(data);

      int httpCode = http.GET();

      http.end();

      data = String(“http://iot.robofun.ro/api/v1/senzor/&#8221;) + SENSOR_TOKEN2 + “/input?value=” + String(parametrii.humidity, DEC);

      http.begin(data);

      httpCode = http.GET();

      http.end();

      data = String(“http://iot.robofun.ro/api/v1/senzor/&#8221;) + SENSOR_TOKEN3 +  “/input?value=” + String(parametrii.bat_voltage, DEC);

      http.begin(data);

      httpCode = http.GET();

      http.end();    }

    else    {

      Serial.println(“Receive failed”);    }

  }

}

Modulul LoRa ce va beneficia de extinderea ariei de comunicație (se poate afla la sute de metri, sau chiar kilometri în spațiu deschis, de aria de acoperire WiFi) se bazează pe placa de dezvoltare Feather M0 RFM95 433MHz LoRa – placă ce combină puterea unui microcontroler ARM Cortex-M0+ ATSAMD21 (la fel ca și plăcile Arduino M0/Zero) cu conectivitatea unui modul radio LoRa. Placa de dezvoltare va transmite către modulul gateway date preluate de la un senzor digital I2C de temperatură și umiditate Si7021 precum și nivelul bateriei proprii (unul dintre avantajele majore ale plăcilor Feather este posibilitatea de alimentare mobilă de la un acumulator LiPo de 3.7V).

Pentru mai multe informații legate de utilizarea plăcii Feather M0 RFM95 puteți consulta și materialul: „Adafruit Feather M0 Radio with LoRa Radio Module”.

Schema de interconectare între senzor și placa de dezvoltare este specifică unei magistrale I2C (pinii SDA și SCL conectați între senzor și placa de dezvoltare, alimentarea senzorului se va face la 3.3V):

7

Programul a fost dezvoltat și testat utilizând Arduino IDE 1.8.3, extensia Adafruit SAMD Boards 1.0.19 și bibliotecile RadioHead 1.7.9, Adafruit Si7021.

Decomentarea directivei debug va permite observarea funcționării modulului în consola serială.

//#define debug

7.5

#include <SPI.h>

#include <RH_RF95.h>

#define VBATPIN A7

#include <Adafruit_Si7021.h>

Adafruit_Si7021 sensor = Adafruit_Si7021();

#define RFM95_CS 8

#define RFM95_RST 4

#define RFM95_INT 3

#define RF95_FREQ 434.0

RH_RF95 rf95(RFM95_CS, RFM95_INT);

void setup() {

  pinMode(RFM95_RST, OUTPUT);

  digitalWrite(RFM95_RST, HIGH);

  sensor.begin();

  #ifdef debug

    while (!Serial);

    Serial.begin(9600);

    delay(100);

    Serial.println(“LoRa Sensor Module starting…”);

  #endif

  digitalWrite(RFM95_RST, LOW);

  delay(10);

  digitalWrite(RFM95_RST, HIGH);

  delay(10);

  while (!rf95.init()) {

    #ifdef debug

      Serial.println(“LoRa radio init failed”);

    #endif

    while (1);

  }

  #ifdef debug

    Serial.println(“LoRa radio init OK!”);

  #endif

  if (!rf95.setFrequency(RF95_FREQ)) {

    #ifdef debug

      Serial.println(“setFrequency failed”);

    #endif

    while (1);

  }

  #ifdef debug

    Serial.print(“Set Freq to: “);

    Serial.println(RF95_FREQ);

  #endif

  rf95.setTxPower(23, false);

}

typedef struct {float temperature; float humidity;

float bat_voltage;} ParametriiTX;

ParametriiTX parametrii;

void loop() {

  float voltage = analogRead(VBATPIN);

  voltage *= 2;   

  voltage *= 3.3;

  voltage /= 1024;

  parametrii.bat_voltage = voltage;

  parametrii.temperature = sensor.readTemperature();

  parametrii.humidity = sensor.readHumidity();

  #ifdef debug

    Serial.print(“Sample OK: “);

    Serial.print(parametrii.temperature);

   Serial.print(” *C, “);

    Serial.print(parametrii.humidity);

    Serial.println(” %”);

    Serial.print(“VBat: ” ); Serial.println(voltage);

    Serial.println(“Sending to Gateway Module”);

    Serial.println(“Sending…”); delay(10);

  #endif

  RH_RF95::printBuffer(“Sending: “, (uint8_t*)&parametrii, sizeof parametrii);

  #ifdef debug

    Serial.println(“Sending…”); delay(10);

  #endif

  rf95.send((uint8_t *)&parametrii, sizeof parametrii);

  #ifdef debug

    Serial.print(“Waiting for packet to complete…”);

delay(10);

  #endif

  rf95.waitPacketSent();

  #ifdef debug

    Serial.println(“done.”); delay(10);

  #endif

  delay(100);

  rf95.sleep();

  delay(60000);

}

După programarea și punerea în funcțiune a celor două sisteme se pot observa datele înregistrate în cadrul platformei Robofun IoT (capturile de ecran de mai jos reprezintă date înregistrate de sistemul de test pentru temperatură și umiditate).

8

9

Bineînțeles, sistemul LoRa poate deservi atât sisteme de achiziție (temperatură, umiditate, presiunea în diverse conducte, consumul de energie electrică, nivelul radiației solare etc.) dar și sisteme de acționare (chiar dacă nu a fost exemplificată această parte este posibil să comandăm de la distanță diverse mecanisme de închidere / deschidere, motoare etc).

Proiect Termometru Simfonic

În cadrul proiectului de față vom prezenta o soluție de achiziție (ca exemplificare vom face achiziția temperaturii și umidității mediul ambiant) cu raportare IoT prin GPRS (rețea de telefonie mobilă). Soluția propusă este una simplă și vine în întâmpinarea unei probleme extrem de actuală: supravegherea de la distanță a unor parametrii de mediu în locații izolate unde nu dispunem de infrastructură de rețea Internet – în loc de temperatură și umiditate putem face achiziția unor parametrii ai solului (aplicații pentru agricultură inteligentă) sau achiziția unor parametrii de proximitate și integritate (aplicații de securitate).

Soluția propusă se bazează pe placa de dezvoltare Adafruit Feather 32U4 FONA, placă ce combină un microcontroler ATmega32U4 la 8MHz / 3.3V și un controler GSM SIM800 quad-band (850/900/1800/1900MHz). Placa necesită alimentarea de la un acumulator LiPo extern de minim 500mAh (se pot utiliza (*), (*), (*)) și o antenă GSM uFL.

2

Pentru achiziția parametrilor temperatură și umiditate vom utiliza un senzor digital I2C Si7021 ce are o precizie mare de măsurare și se poate interfața foarte ușor cu placa de dezvoltare utilizată.

3

Funcționarea sistemului necesită o cartelă GSM 2G cu capabilități de transfer de date. Pentru acest lucru vă propunem utilizarea unui SIM Simfony Mobile M2M – cartelă GSM ce oferă exclusiv servicii mobile de date.

4

Cartela este disponibilă gratuit prin comandă pe site-ul companiei Simfony Mobile SRL  sau împreună cu un produs din gama GSM pe site-ul Robofun. Cartela necesită înregistrarea și introducerea codului promoțional pentru activare și oferă gratuit 10MB de date mobile valabile 3 luni. Ulterior costurile de funcționare sunt de 0.25EURO, 0.5EURO, 1EURO pentru 1MB, 5MB respectiv 10MB trafic de date. Chiar dacă traficul inclus are valori modice pentru un sistem de raportare IoT este suficient iar costurile sunt rezonabile. O caracteristică importantă a cartelei SIM Simfony este indepența de un operator de telefonie anume, dispozitivul GSM ce utilizează cartela Simfony poate utiliza orice operator de telefonie mobilă în funcție de zona în care se află chiar și afara României.

 

Interconectarea componentelor

Interconectarea dintre senzorul Si7021 și placa Feather 32U4 FONA este reprezentată în diagrama următoare:

5

Pentru mai multe detalii despre operarea plăcii Adafruit Feather 32U4 FONA se recomandă parcurgerea materialului ”Adafruit Feather 32u4 FONA – Take your Feather anywhere in the world”.

 

Programarea sistemului

Pentru realizarea și testarea sistemului s-a utilizat Arduino IDE 1.8.1 cu extensia Adafruit AVR Boards 1.4.9 instalată precum și bibliotecile Adafruit FONA 1.3.2, Adafruit Si7021, Sleep_n0m1 1.1.1.

 

#include “Adafruit_FONA.h”

#define FONA_RX  9

#define FONA_TX  8

#define FONA_RST 4

#define FONA_RI  7

#define FONA_DTR 5

#define apn “internet.simfony.net”

#define apnusername “” 

#define apnpassword “” 

char replybuffer[255];

#include <SoftwareSerial.h>

SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);

SoftwareSerial *fonaSerial = &fonaSS;

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);

uint8_t type;

#include <Sleep_n0m1.h>

Sleep sleep;

#include <Adafruit_Si7021.h>

Adafruit_Si7021 sensor = Adafruit_Si7021();

 

Dacă se dorește supravegherea funcționării sistemului pe serială se va adăuga următoarea linie, în funcționarea propriu-zisă nu este necesară:

 

#define debug

 

În cadrul secțiunii setup() se va realiza inițializarea modulului GSM și a senzorului Si7021:

 

void setup() {

  #ifdef debug

    while (!Serial);

    Serial.begin(115200);

    Serial.println(“Initializing…”);

  #endif

  digitalWrite(FONA_DTR,LOW);

  fonaSerial->begin(4800);

  if (! fona.begin(*fonaSerial)) {

    #ifdef debug

      Serial.println(F(“Couldn’t find FONA”));

    #endif

    delay(1);

    while (1);

  }

  #ifdef debug

    type = fona.type();

    Serial.println(F(“FONA is OK”));

    Serial.print(F(“Found “));

    switch (type) {

      case FONA800L:

        Serial.println(F(“FONA 800L”)); break;

      case FONA800H:

        Serial.println(F(“FONA 800H”)); break;

      case FONA808_V1:

        Serial.println(F(“FONA 808 (v1)”)); break;

      case FONA808_V2:

        Serial.println(F(“FONA 808 (v2)”)); break;

      case FONA3G_A:

        Serial.println(F(“FONA 3G (American)”)); break;

      case FONA3G_E:

        Serial.println(F(“FONA 3G (European)”)); break;

      default:

        Serial.println(F(“???”)); break;

    }

   #endif

  #ifdef debug

    char imei[15] = {0};

    uint8_t imeiLen = fona.getIMEI(imei);

    if (imeiLen > 0) {

      Serial.print(“Module IMEI: “); Serial.println(imei);

    }

  #endif

  fona.getSIMCCID(replybuffer); 

  #ifdef debug

    Serial.print(F(“SIM CCID = “));

Serial.println(replybuffer);

  #endif

  if (!fona.enableNetworkTimeSync(true)) {

     #ifdef debug

      Serial.println(F(“Failed to enable NTS”));

     #else

      ;

     #endif

  }

  delay(5000);

  fona.setGPRSNetworkSettings(F(apn),F(apnusername),F(apnpassword));

  uint8_t n=0;

  #ifdef debug

    Serial.print(“Connecting to network.”);

  #endif

  while (n!=5) {

    n = fona.getNetworkStatus();

    #ifdef debug

      Serial.print(“.”);

    #endif

    delay(1000);

  }

  #ifdef debug

    Serial.println(“OK”);

  #endif

  #ifdef debug

    n = fona.getRSSI();

    int8_t r;

    if (n == 0) r = -115;

    if (n == 1) r = -111;

    if (n == 31) r = -52;

    if ((n >= 2) && (n <= 30)) { r = map(n, 2, 30, -110, -54); }

    Serial.print(r); Serial.println(F(“dBm”));

  #endif

  sensor.begin();

  delay(5000);

}

 

Sistemul va raporta către serviciul IoT ThingSpeak valorile achiziționate (temperatură și umiditate) precum și voltajul și procentul de încărcare a acumulatorului ce alimentează sistemul. Secțiunea loop() implementează atât partea de achiziție cât și partea de transmisie de rețea prin intermediul comunicației mobile. În cadrul codului trebuie personalizată valoarea parametrului key ce se obține în urma înregistrării gratuite pe site-ul ThingSpeak. Achiziția și raportarea se realizează la un interval de o oră (3600000ms), în intervalul de inactivitate atât modulul GSM cât și microcontrolerul 32u4 se află în mod de consum redus.

 

void loop() {

while (!fona.enableGPRS(true)) {

#ifdef debug

Serial.println(F(“Failed to turn on GPRS”));

#endif

delay(5000);

}

uint16_t vbat;

uint16_t pbat;

#ifdef debug

if (fona.getBattVoltage(&vbat)) { Serial.print(F(“VBat = “)); Serial.print(vbat);

Serial.println(F(” mV”)); }

if (fona.getBattPercent(&pbat)) { Serial.print(F(“VPct = “)); Serial.print(pbat);

Serial.println(F(“%”));   }

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

#else

fona.getBattVoltage(&vbat);

fona.getBattPercent(&pbat);

#endif

float temperature, humidity;

temperature = sensor.readTemperature();

humidity = sensor.readHumidity();

#ifdef debug

Serial.print(“Humidity:    “);

Serial.print(humidity, 2);

Serial.print(“\tTemperature: “);

Serial.println(temperature, 2);

#endif

String temp = “api.thingspeak.com/update?key=…&field1=” + String(vbat/1000.0F,2) + “&field2=” + String(pbat) + “&field3=” + String(temperature,2) + “&field4=” + String(humidity,2);

uint16_t statuscode;

int16_t length;

char url[100];

temp.toCharArray(url,temp.length()+1);

#ifdef debug

Serial.println(url);

if (!fona.HTTP_GET_start(url, &statuscode, (uint16_t *)&length)) Serial.println(“Failed

read HTTP!”);

#else

fona.HTTP_GET_start(url, &statuscode, (uint16_t *)&length);

#endif

while (length > 0) {

while (fona.available()) {

char c = fona.read();

#ifdef debug

Serial.write(c);

#endif

length–;

if (! length) break;

}

#ifdef debug

Serial.println();

#endif

break;

}

fona.HTTP_GET_end();

delay(100);

#ifdef debug

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

if (!fona.enableGPRS(false)) Serial.println(F(“Failed to turn off GPRS”));

#else

fona.enableGPRS(false);

#endif

delay(100);

digitalWrite(FONA_DTR,HIGH);

#ifdef debug

delay(3600000);

#else

sleep.pwrDownMode();

sleep.sleepDelay(3600000);

#endif

digitalWrite(FONA_DTR,LOW);

delay(100);

}

 

Configurarea sistemului de raportare IoT

Sistemul nostru este un sistem tipic IoT ce utilizează platforma on-line ThingSpeak. Utilizarea platformei necesită înregistrare dar aceasta este gratuită.

6

Platforma ThingSpeak este una dintre cele mai cunoscute platforme IoT ce oferă servicii de stocare, prelucrare și vizualizare a datelor. Unul dintre avantajele majore ale platformei este posibilitatea de execuție de programe scrise în limbajul Matlab.

După înregistrare se va defini un nou canal înregistrare a datelor (My Channels / New Channel). Definirea canalului va genera și cheia (Write API Key) ce trebuie utilizată în program.

7

În cadrul acestui canal vom defini patru câmpuri Vbat, Vperc, Temperature și Humidity ce vor stoca efectiv datele trimise de dispozitivul nostru.

8

După punerea în funcțiune a sistemului se vor putea vedea și datele trimise de dispozitiv (secțiunea PrivateView).

9