Raccogli dati agricoli tramite The Things Network
Questo esempio mostra come impostare la raccolta dati da tre sensori collegati a una scheda a microprocessore con una radio LoRa®.
Questa configurazione consente di creare una rete di sensori distribuiti su un'area estesa. I sensori inviano i dati a The Things Network, che vengono poi inoltrati a ThingSpeak ™ per l'analisi e la visualizzazione. Nell'esempio, si costruisce un prototipo di dispositivo, ci si connette a The Things Network e si integra la raccolta dati con ThingSpeak. Il dispositivo mostrato qui raccoglie dati sulla temperatura, sull'umidità del suolo e sul GPS.

Panoramica
L'esempio è costituito da tre passaggi principali. L'integrazione di Things Network è ulteriormente suddivisa in diversi sotto-fasi. La fase più complessa è la costruzione del dispositivo. Per completare l'esempio, hai bisogno di un account ThingSpeak e di un account su The Things Network. Su ThingSpeak, crei un nuovo canale. Sulla Things Network, crei un'applicazione e registri un dispositivo. Quindi si crea un decodificatore del payload e si aggiunge l'integrazione che inoltra i dati a ThingSpeak.
1) Impostare un canale ThingSpeak per raccogliere dati
2) Configurare la rete Things
Crea applicazione
Registra dispositivo
Crea formato payload
Aggiungi integrazione
3) Crea dispositivo
Hardware utilizzato per creare il nodo sensore
Schema e connessioni
4) Dispositivo di programmazione
Impostazione della programmazione
Codice
Imposta un canale ThingSpeak per raccogliere dati
1) Creare un canale ThingSpeak, come mostrato in Raccogliere dati in un nuovo canale. Registra la chiave API di scrittura e l'ID del canale per il tuo nuovo canale.
2) Vai alla pagina Impostazioni canale. Impostare le etichette dei campi come segue.
Campo 1—
CounterCampo 2—
Soil MoistureCampo 3—
Temperature F
3) Fai clic su Salva canale in basso per salvare le impostazioni.
Configurare l'applicazione Things Network
Crea un account su The Things Network, e accedi a The Things Network Console.
Crea applicazione
1) Seleziona Applicazioni.

2) Selezionare Aggiungi applicazione.

3) Crea un ID applicazione, quindi aggiungi una Descrizione. Seleziona la registrazione del gestore in base alla tua posizione.

Registra un dispositivo
1) Fare clic sulla scheda Dispositivi e registrare un dispositivo. Per ulteriori informazioni, vedere Registrazione del dispositivo.
2) Creare un ID dispositivo. Inserisci l'EUI del dispositivo, se ne è dotato. In caso contrario, seleziona il pulsante a sinistra del campo EUI dispositivo per generare automaticamente l'EUI.

3) Fare clic su Registrati. Il browser ti riporta alla scheda Panoramica.
4) Selezionare la scheda Impostazioni.

5) Nelle impostazioni, seleziona ABP come metodo di attivazione. Per facilitare il debug, puoi facoltativamente disattivare i controlli del contatore dei frame nella parte inferiore della pagina.

6) Registrare l'Indirizzo del dispositivo, la Chiave di sessione di rete e la Chiave di sessione dell'app. Questa informazione è necessaria nel codice del tuo dispositivo.
Crea formattatore del payload
Il formattatore del payload utilizza i byte inviati all'applicazione dal gateway per assemblare un messaggio. In questo esempio, il messaggio di payload desiderato è un oggetto codificato in JSON che viene inviato a ThingSpeak.
1) Tornare alla visualizzazione dell'applicazione utilizzando il menu di navigazione in alto. Quindi fare clic sulla scheda Formati payload.

2) Nell'interfaccia decoder, crea il codice per convertire i byte inviati dal tuo dispositivo in un oggetto JSON da scrivere su ThingSpeak. Il codice condizionale per lat e lon gestisce la possibilità di valori positivi o negativi.
function Decoder(b, port) {
var counter = b[0] << 8) | b[1];
var moisture = b[2] | b[3] << 8;
var temp= ( b[4] | b[5] << 8 )/100;
var lat = ( b[6] | b[7] << 8 | b[8] << 16 | (b[8] & 0x80 ? 0xFF << 24 : 0)) / 10000;
var lon = ( b[9] | b[10] << 8 | b[11] << 16 | (b[11] & 0x80 ? 0xFF << 24 : 0)) / 10000;
return {
field1: counter,
field2: moisture,
field3: temp,
latitude: lat,
longitude: lon
}
}
Aggiungi integrazione
Per inoltrare i dati a ThingSpeak, è necessario disporre di un'applicazione sulla Things Network con un dispositivo registrato e un formattatore di payload. Creare un'integrazione ThingSpeak per inoltrare i dati.
1) Accedi alla tua The Things Network Console.
2) Seleziona Applicazioni e seleziona l'applicazione da cui desideri inoltrare i dati a ThingSpeak.

3) Fare clic sulla scheda Integrazioni.

4) Selezionare ThingSpeak.

5) Nel campo ID processo, assegna un nome all'integrazione.
6) Nel campo Autorizzazione, inserisci la chiave API di scrittura per il canale in cui desideri archiviare i tuoi dati. La chiave API è disponibile nella scheda Chiavi API del tuo canale ThingSpeak.
7) Nel campo ID canale, immettere l'ID del canale ThingSpeak in cui si desidera inoltrare i dati. L'ID del canale è disponibile sulla pagina del tuo canale ThingSpeak.

Crea dispositivo
Hardware utilizzato per creare il nodo sensore
È possibile utilizzare vari dispositivi LoRa che supportano i protocolli LoRaWan per connettersi a The Things Network. Questo esempio illustra la procedura utilizzando la seguente configurazione hardware.
Piuma di Adafruit M0
Adafruit Ultimate GPS FeatherWing
Monitor del terreno (ad esempio, il sensore di umidità Sparkfun SEN 13322)
DHT22
Intestazioni e fili
Antenna GPS W14Q5A-y
Interruttore a levetta
Batteria LiPo 500 mAh
Schema e connessioni
Collegare i sensori come mostrato nello schema. La fotografia mostra una possibile configurazione dei sensori in una scatola di progetto. In questa configurazione, il sensore di temperatura all'interno della scatola potrebbe non riflettere esattamente la temperatura esterna. È necessario aggiungere un'antenna alla radio LoRa.
1) Collegare i collegamenti di alimentazione e di terra per i sensori GPS e di temperatura. Non collegare l'alimentazione al sensore di umidità.
2) Collegare l'uscita del sensore di umidità del terreno all'ingresso analogico in A0.
3) Impostare il sistema in modo che il sensore di umidità si spenga quando non è in uso. Il pin di alimentazione del sensore di umidità è collegato al pin GPIO 11 sul connettore M0. Spegnere il sensore quando non è in uso prolunga la sua durata.
4) Collegare il pin dati del sensore DH-22 al PA-15 sul Feather M0, che è il pin 5 nello sketch Arduino®.
5) Per la scheda GPS, collegare TX a RX sul Feather M0 e RX a TX.
6) Abilitare la radio LoRa collegando PA20 (pin 29, GPIO 6) sul Feather M0 a terra.
7) Creare un interruttore di alimentazione collegando un interruttore dal pin En a terra.


Dispositivo di programma
Impostazione della programmazione
1) Scarica l'ultima versione di Arduino IDE.
2) Scarica la libreria Adafruit GPS o aggiungi la libreria Adafruit_GPS nel gestore delle librerie. Selezionare Sketch > Include Library > Manage Libraries. Cerca Adafruit_GPS per aggiungerlo alle librerie installate.
3) Scarica la libreria LoraWan-in-C per l'ambiente Arduino oppure aggiungi le librerie lmic e hal/hal nel gestore delle librerie. Selezionare Sketch > Include Library > Manage Libraries. Cerca lmic e seleziona MCCI LoRaWAN LMIC library per aggiungerlo alle librerie installate. Aggiungere anche MCCI Arduino LoRaWan Library to the library manager.
4) Creare l'applicazione. Apri una nuova finestra nell'IDE di Arduino e salva il file. Aggiungere il codice fornito nella sezione Codice.
Codice
1) Iniziare includendo le librerie appropriate e inizializzando le variabili.
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include "DHT.h"
#include <Adafruit_GPS.h>
#define DHTPIN 5
#define GPSSerial Serial1
#define SOIL_PIN 14
#define SOIL_POWER_PIN 11
#define GPSECHO false // Set to 'true' if you want to debug and listen to the raw GPS sentences
#define PAYLOAD_SIZE 13 // Number of bytes sent plus 2
// LoRaWAN NwkSKey, network session key
static const PROGMEM u1_t NWKSKEY[16] = {0x98, 0xEB, 0x1A, 0xC5, 0xF9, 0x20, 0x15, 0xCD, 0x12, 0xE5, 0x72, 0xFF, 0xCD, 0xE2, 0x94, 0x46};
// LoRaWAN AppSKey, application session key
static const u1_t PROGMEM APPSKEY[16] = {0x50, 0x28, 0x4D, 0xAE, 0xEA, 0x41, 0x53, 0x7E, 0xCA, 0x70, 0xD2, 0x26, 0xCC, 0x14, 0x66, 0x19};
// LoRaWAN end-device address (DevAddr)
static const u4_t DEVADDR = 0x26021115;
// Callbacks are only used in over-the-air activation. Leave these variables empty unless you use over the air activation.
void os_getArtEui(u1_t *buf) {}
void os_getDevEui(u1_t *buf) {}
void os_getDevKey(u1_t *buf) {}
// Payload to send to TTN gateway
static uint8_t payload[PAYLOAD_SIZE];
static osjob_t sendjob;
// Schedule TX at least this many seconds
const unsigned TX_INTERVAL = 60; //was 30
// Pin mapping for Adafruit Feather M0 LoRa
const lmic_pinmap lmic_pins = {
.nss = 8,
.rxtx = LMIC_UNUSED_PIN,
.rst = 4,
.dio = {3, 6, LMIC_UNUSED_PIN},
.rxtx_rx_active = 0,
.rssi_cal = 8, // LBT cal for the Adafruit Feather M0 LoRa, in dB.
.spi_freq = 8000000,
};
Adafruit_GPS GPS(&GPSSerial); // Connect to the GPS on the hardware port.
DHT dht(DHTPIN, DHT22); // Connect to the temperature sensor.
uint16_t counter = 0;
int32_t myLatitude = -12345; // Initialize for testing before GPS finds a lock.
int32_t myLongitude = 54321; // Initialize for testing.
int myMoisture = 0; // 10 bit ADC value.
float temperatureF = 1111;
2) Utilizzare la funzione setup per avviare il sensore di temperatura, il GPS e la radio LoRa.
void setup()
{
Serial.begin(115200);
dht.begin();
Serial.println("Start");
// Set the power pin for the moisture sensor
pinMode(SOIL_POWER_PIN,OUTPUT);
digitalWrite(SOIL_POWER_PIN, LOW);
GPS.begin(9600); // 9600 NMEA is the default baud rate.
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // Set a 1 Hz update rate.
delay(1000); // Wait for GPS to initialize.
// Ask for firmware version
GPSSerial.println(PMTK_Q_RELEASE);
// Initialize the LMIC.
os_init();
// Reset the MAC state. Resetting discards the session and pending data transfers.
LMIC_reset();
// Set static session parameters.
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession(0x13, DEVADDR, nwkskey, appskey);
LMIC_selectSubBand(1);
// Only use the correct The Things Network channels, disable the others.
for (int c = 0; c < 72; c++)
{
if ((c < 8) || (c > 15))
{
LMIC_disableChannel(c);
}
}
LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
// Disable link check validation
LMIC_setLinkCheckMode(0);
// TTN uses SF9 for its RX2 window.
LMIC.dn2Dr = DR_SF9;
// Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
LMIC_setDrTxpow(DR_SF7, 14);
// Start job.
processJob(&sendjob);
}
3) Utilizzare la funzione loop per avviare il processo LoRa e analizzare i dati GPS.
void loop() // Run over and over again
{
os_runloop_once();
char c = GPS.read();
if (GPSECHO)
{
if (c){
Serial.print(c);
}
}
// If a sentence is received, parse it
if (GPS.newNMEAreceived())
{
if (!GPS.parse(GPS.lastNMEA())) // Also sets the newNMEAreceived() flag to false
return;
}
}
4) La funzione GetSensorData accende il sensore di umidità e ne legge i dati, quindi spegne l'alimentazione. Legge anche il sensore della temperatura e controlla le informazioni provenienti dal dispositivo GPS. Se è presente un segnale GPS, questa funzione aggiorna le informazioni sulla posizione.
void GetSensorData()
{
digitalWrite(SOIL_POWER_PIN, HIGH);
delay(1000);
myMoisture = analogRead(SOIL_PIN);
digitalWrite(SOIL_POWER_PIN, LOW);
temperatureF = dht.readTemperature( true );
Serial.println("moisture " + String( myMoisture ) + " temp " + String( temperatureF ));
if (GPS.fix)
{
Serial.print( "Location: " );
Serial.print( GPS.latitudeDegrees * 100, 4 );
Serial.print( " break " );
Serial.print( GPS.lat );
Serial.print( ", " );
Serial.print( GPS.longitudeDegrees * 100 , 4 );
Serial.println( GPS.lon );
myLatitude = GPS.latitudeDegrees * 10000;
myLongitude = GPS.longitudeDegrees * 10000;
}
}
5) Utilizzare la funzione onEvent per elaborare gli eventi provenienti dalla radio LoRa. La funzione aggiorna il monitor seriale, pianifica la trasmissione successiva e riceve i messaggi.
void onEvent(ev_t ev)
{
Serial.print(os_getTime());
Serial.print(": ");
switch (ev)
{
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
break;
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen)
{
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
default:
Serial.print(F("Unknown event: "));
Serial.println((unsigned)ev);
break;
}
}
6) La funzione processJob converte i dati del sensore in bit da inviare tramite la radio LoRa.
void processJob(osjob_t *j)
{
getSensorData();
if (LMIC.opmode & OP_TXRXPEND) // Check if there is a current TX/RX job running.
{
Serial.println(F("OP_TXRXPEND, not sending"));
}
else
{
payload[0] = byte(counter);
payload[1] = counter >>8;
payload[2] = byte(myMoisture);
payload[3] = myMoisture >> 8;
int shiftTemp = int(temperatureF * 100); // Convert temperature float to integer for sending and save two places.
payload[4] = byte(shiftTemp);
payload[5] = shiftTemp >> 8;
payload[6] = byte(myLatitude);
payload[7] = myLatitude >> 8;
payload[8] = myLatitude >> 16;
payload[9] = byte(myLongitude);
payload[10] = myLongitude >> 8;
payload[11] = myLongitude >> 16;
LMIC_setTxData2(1, payload, sizeof(payload) - 1, 0); // Prepare upstream data transmission at the next possible time.
counter++;
Serial.println(String(counter));
}
// Next TX is scheduled after TX_COMPLETE event.
Per scoprire come creare una dashboard di visualizzazione dettagliata nel tuo canale ThingSpeak, consulta Creare una vista canale ThingSpeak personalizzata.