Feather M0 LoRa in TFA Housing

This sensor node is made to showcase a use-case of LoRaWAN technology for outdoor weather monitoring. For achieving this a Feather M0 LoRa module was used with temperature and pressure sensor. The entire setup was carefully placed in the TFA Housing which is an all-weather protective cover for outdoor transmitters. In this example we measure parameters such as temperature, humidity, altitude, and air pressure.

../_images/setup1.jpg

Sensor node in TFA Housing.

Hardware

To build this sensor node we have used following hardware components:

../_images/setup-insideview.jpg

Inside view of Sensor node in TFA Housing

Also, as the final hardware setup with antenna couldn’t completely fit into the casing, a small hole was made at the bottom of the casing to allow the remaining portion of antenna to stay outside.

../_images/setup-bottom.jpg

Bottom view of Sensor node in TFA Housing

Wiring setup

First of all, the Feather M0 LoRa board was prepared by soldering the board with the provided grid of pins. Then the board is connected with the sensors using a breadboard. The sensor connections were made using the connector cables as following:

DHT-22 Sensor connections:

  • Feather 3V to DHT22 pin 1
  • Feather GND to DHT22 pin 4
  • Feather pin 12 to DHT22 pin 2
  • Resistor between DHT pin 1 and DHT pin 2
../_images/feather_wiring_hero.png

Wiring with DHT-22 Sensor

Grove-Barometer Sensor connections:

  • Feather SCL to Barometer Sensor pin 1 (yellow)
  • Feather SDA to Barometer Sensor pin 2 (white)
  • Feather 3V to Barometer Sensor pin 3 (red)
  • Feather GND to Barometer Sensor pin 4 (black)

Apart from this, Feather pin 6 should be permanently wired with Feather pin io1 as shown in the figure above.

To ensure the durable connections, smaller jumper wires were used on the breadboard instead of longer connecting cables. Sensors and cables were also supported with an insulating duct tape.

Final hardware setup looked as following:

../_images/hardware.png

Final hardware wiring

Once all these connection were made, the board is connected with a computer using a USB cable. Further, steps of software part needs to be followed.

Software

To create this node, we use Arduino IDE for setting up the Feather M0 LoRa module. First, install the Feather M0 LoRa board to your Arduino IDE and select the correct port. Then following libraries needs to be installed before compiling the code:

  • lmic.h for implementing LoRaWAN on Arduino hardware.
  • hal/hal.h bundled with lmic library.
  • Adafruit_SleepyDog.h for controlling low power sleep mode.
  • Wire.h to communicate with I2C devices.
  • BMP085.h for Barometer sensor.
  • DHT.h for reading DHT-22 sensor.
  • CayenneLPP.h for Cayenne Protocol.

Apart from this, SPI.h library is also used for communicating with serial peripheral interface but it is already inbuilt in Arduino IDE and is not required to be separately installed.

Now download and run the Arduino Sketch for Outdoor Weather Monitoring sensor node file in the Arduino IDE. This code was created by merging the example code of both the sensors and the ttn-otaa example from the lmic library. Some required changes were made while merging the example codes. The user should change the network session key, app session key and device address in the code before compiling. These keys can be obtained from the TTN, SWM or other service providers.

Modify the keys in highlighted lines.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// LoRaWAN NwkSKey, network session key
// This should be in big-endian (aka msb).
static const PROGMEM u1_t NWKSKEY[16] = {NETWORK_SESSION_KEY_HERE_IN_MSB_FORMAT};

// LoRaWAN AppSKey, application session key
// This should also be in big-endian (aka msb).
static const u1_t PROGMEM APPSKEY[16] = {APPLICATION_SESSION_KEY_HERE_IN_MSB_FORMAT};

// LoRaWAN end-device address (DevAddr)
// See http://thethingsnetwork.org/wiki/AddressSpace
// The library converts the address to network byte order as needed, so this should be in big-endian (aka msb) too.
static const u4_t DEVADDR = 0x260XXXXX   ; // <-- Change this address for every node!

The pin mapping configured in the code should also be verified for the board that is being used. Current pin mapping is set as per the Feather M0 LoRa board.

Set the correct pin mapping for the board that is used.
1
2
3
4
5
6
// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 8,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = {3, 6, LMIC_UNUSED_PIN},

Following is the example code that can be used to measure the battery voltage of the Feather M0 LoRa board:

Code for measuring the battery voltage
1
2
3
4
5
6
7
            measuredvbat = analogRead(VBATPIN);
            measuredvbat *= 2;    // we divided by 2, so multiply back
            measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
            measuredvbat /= 1024; // convert to voltage

            SERIALDEBUG_PRINT(" %\t");
            SERIALDEBUG_PRINT("Battery Voltage: ");

Services

This node is connected using the TheThingsNetwork service. Further, a node-red work bench is used to forward this collected data from the TTN platform to the OGC Sensor Things API configured on the FROST Server. The node-red workbench that was used for forwarding the data is available at Node red flow for Outdoor Weather Monitoring sensor node. To use this node-red-workbench go to the node-red platform https://iot.gis.bgu.tum.de:1885/, login with the credentials, go to the options and select Import>Clipboard. Select the downloaded .json file with the given option and click on import. Make necessary changes and deploy the flow.

Datastreams setup for this sensor node on the FROST server can be seen at: http://iot.gis.bgu.tum.de:8081/FROST-Server-gi3/v1.0/Things(20)/Datastreams

The node-red workbench for this sensor node could be found at: https://iot.gis.bgu.tum.de:1885/#flow/f6f7a740.c6b338

The GRAFANA dash-board for visualizing the collected data is available at: https://iot.gis.bgu.tum.de:3050/d/sMJ3jAAWz/featherm0lora-in-tfa-housing?orgId=1

Code files

Arduino Sketch for Outdoor Weather Monitoring sensor node
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
 /*******************************************************************************
 * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
 *
 *
 *
 *
 * Permission is hereby granted, free of charge, to anyone
 * obtaining a copy of this document and accompanying files,
 * to do whatever they want with them without any restriction,
 * including, but not limited to, copying, modification and redistribution.
 * NO WARRANTY OF ANY KIND IS PROVIDED.
 *
 * This example sends a valid LoRaWAN packet with payload "Hello,
 * world!", using frequency and encryption settings matching those of
 * the The Things Network.
 *
 * This uses ABP (Activation-by-personalisation), where a DevAddr and
 * Session keys are preconfigured (unlike OTAA, where a DevEUI and
 * application key is configured, while the DevAddr and session keys are
 * assigned/generated in the over-the-air-activation procedure).
 *
 * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in
 * g1, 0.1% in g2), but not the TTN fair usage policy (which is probably
 * violated by this sketch when left running for longer)!
 *
 * To use this sketch, first register your application and device with
 * the things network, to set or generate a DevAddr, NwkSKey and
 * AppSKey. Each device should have their own unique values for these
 * fields.
 *
 * Do not forget to define the radio type correctly in config.h.
 *
 *******************************************************************************/
// #define SERIALDEBUG
 
#ifdef SERIALDEBUG
  #define SERIALDEBUG_PRINT(...) Serial.print(__VA_ARGS__)
  #define SERIALDEBUG_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
  #define SERIALDEBUG_PRINT(...)
  #define SERIALDEBUG_PRINTLN(...)
#endif
 
 
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <Adafruit_SleepyDog.h>
#include <DHT.h>
#include <CayenneLPP.h>
#include "BMP085.h"
#include <Wire.h>

CayenneLPP lpp(51);
 
#define DHTPIN            12        // Pin which is connected to the DHT sensor.
#define DHTTYPE           DHT22     // DHT 22 (AM2302)
 
// DHT_Unified dht(DHTPIN, DHTTYPE);
DHT dht(DHTPIN, DHTTYPE);
 
#define VBATPIN A7

float temperature2;
float pressure;
float atm;
float altitude;
BMP085 myBarometer;
 
// LoRaWAN NwkSKey, network session key
// This should be in big-endian (aka msb).
static const PROGMEM u1_t NWKSKEY[16] = {NETWORK_SESSION_KEY_HERE_IN_MSB_FORMAT};

// LoRaWAN AppSKey, application session key
// This should also be in big-endian (aka msb).
static const u1_t PROGMEM APPSKEY[16] = {APPLICATION_SESSION_KEY_HERE_IN_MSB_FORMAT};

// LoRaWAN end-device address (DevAddr)
// See http://thethingsnetwork.org/wiki/AddressSpace
// The library converts the address to network byte order as needed, so this should be in big-endian (aka msb) too.
static const u4_t DEVADDR = 0x260XXXXX   ; // <-- Change this address for every node!
 
// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }
 
static osjob_t sendjob;
 
// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 1;       // seconds transmit cycle plus ...
const unsigned SLEEP_TIME = 60*9+55;  // seconds sleep time plus ...
const unsigned MEASURE_TIME = 2;      // seconds measuring time should lead to ...
                                      // 5 minute(s) total cycle time
 
// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 8,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = {3, 6, LMIC_UNUSED_PIN},
};
 
 
void onEvent (ev_t ev) {
//    Serial.print(os_getTime());
//    Serial.print(": ");
    SERIALDEBUG_PRINT(os_getTime());
    SERIALDEBUG_PRINT(": ");
    switch(ev) {
        case EV_SCAN_TIMEOUT:
            SERIALDEBUG_PRINTLN(F("EV_SCAN_TIMEOUT"));
            break;
        case EV_BEACON_FOUND:
            SERIALDEBUG_PRINTLN(F("EV_BEACON_FOUND"));
            break;
        case EV_BEACON_MISSED:
            SERIALDEBUG_PRINTLN(F("EV_BEACON_MISSED"));
            break;
        case EV_BEACON_TRACKED:
            SERIALDEBUG_PRINTLN(F("EV_BEACON_TRACKED"));
            break;
        case EV_JOINING:
            SERIALDEBUG_PRINTLN(F("EV_JOINING"));
            break;
        case EV_JOINED:
            SERIALDEBUG_PRINTLN(F("EV_JOINED"));
            break;
        case EV_RFU1:
            SERIALDEBUG_PRINTLN(F("EV_RFU1"));
            break;
        case EV_JOIN_FAILED:
            SERIALDEBUG_PRINTLN(F("EV_JOIN_FAILED"));
            break;
        case EV_REJOIN_FAILED:
            SERIALDEBUG_PRINTLN(F("EV_REJOIN_FAILED"));
            break;
        case EV_TXCOMPLETE:
            digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
            SERIALDEBUG_PRINTLN(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
            if (LMIC.txrxFlags & TXRX_ACK)
              SERIALDEBUG_PRINTLN(F("Received ack"));
            if (LMIC.dataLen) {
              SERIALDEBUG_PRINT(F("Received "));
              SERIALDEBUG_PRINT(LMIC.dataLen);
              SERIALDEBUG_PRINTLN(F(" bytes of payload"));
            }
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
             
            SERIALDEBUG_PRINTLN("going to sleep now ... ");
            // lmic library sleeps automatically after transmission has been completed
            for(int i= 0; i < SLEEP_TIME / 16; i++) {
              Watchdog.sleep(16000); // maximum seems to be 16 seconds
              SERIALDEBUG_PRINT('.');
            }
            if (SLEEP_TIME % 16) {
              Watchdog.sleep((SLEEP_TIME % 16)*1000);
              SERIALDEBUG_PRINT('*');             
            }
            SERIALDEBUG_PRINTLN("... woke up again");
             
            break;
        case EV_LOST_TSYNC:
            SERIALDEBUG_PRINTLN(F("EV_LOST_TSYNC"));
            break;
        case EV_RESET:
            SERIALDEBUG_PRINTLN(F("EV_RESET"));
            break;
        case EV_RXCOMPLETE:
            // data received in ping slot
            SERIALDEBUG_PRINTLN(F("EV_RXCOMPLETE"));
            break;
        case EV_LINK_DEAD:
            SERIALDEBUG_PRINTLN(F("EV_LINK_DEAD"));
            break;
        case EV_LINK_ALIVE:
            SERIALDEBUG_PRINTLN(F("EV_LINK_ALIVE"));
            break;
         default:
            SERIALDEBUG_PRINTLN(F("Unknown event"));
            break;
    }
}
 
void do_send(osjob_t* j){
    // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
        SERIALDEBUG_PRINTLN(F("OP_TXRXPEND, not sending"));
    } else {
        // Prepare upstream data transmission at the next possible time.
 
        float temperature, humidity, measuredvbat;
        int16_t int16_temperature, int16_humidity, int16_vbat;
     
        // Start a measurement to update the sensor's internal temperature & humidity reading
        SERIALDEBUG_PRINTLN("Start measurement...");
        temperature = dht.readTemperature();
        // delay(2000);
        Watchdog.sleep(2000);
        // Now read the recently measured temperature (2 secs ago) as Celsius (the default)
        temperature = dht.readTemperature();
        // Read the recently measured humidity (2 secs ago)
        humidity = dht.readHumidity();
        SERIALDEBUG_PRINTLN("... finished!");
     
        // Check if any reads failed and exit early (to try again).
        if (isnan(humidity) || isnan(temperature)) {
            SERIALDEBUG_PRINTLN("Failed to read from DHT sensor!");
            for (int i=0; i<5; i++) {
              digitalWrite(LED_BUILTIN, HIGH);    // turn the LED on by making the voltage HIGH                   
              delay(150);
              digitalWrite(LED_BUILTIN, LOW);    // turn the LED on by making the voltage HIGH                   
              delay(150);
            }
            // ok, then wait for another period and try it again
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
        } else {
            SERIALDEBUG_PRINT("Humidity: ");
            SERIALDEBUG_PRINT(humidity);
            SERIALDEBUG_PRINT(" %\t");
            SERIALDEBUG_PRINT("Temperature: ");
            SERIALDEBUG_PRINT(temperature);
            SERIALDEBUG_PRINT(" *C ");
 
            measuredvbat = analogRead(VBATPIN);
            measuredvbat *= 2;    // we divided by 2, so multiply back
            measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
            measuredvbat /= 1024; // convert to voltage

            SERIALDEBUG_PRINT(" %\t");
            SERIALDEBUG_PRINT("Battery Voltage: ");
            SERIALDEBUG_PRINTLN(measuredvbat);

            temperature2 = myBarometer.bmp085GetTemperature(myBarometer.bmp085ReadUT()); //Get the temperature, bmp085ReadUT MUST be called first
            pressure = myBarometer.bmp085GetPressure(myBarometer.bmp085ReadUP());//Get the temperature
   
           /*
            To specify a more accurate altitude, enter the correct mean sea level
            pressure level.  For example, if the current pressure level is 1019.00 hPa
            enter 101900 since we include two decimal places in the integer value。
           */
           altitude = myBarometer.calcAltitude(pressure); 
           
           atm = pressure / 101325;
        
           lpp.reset();
           lpp.addTemperature(1, temperature);
           lpp.addRelativeHumidity(2, humidity);
           lpp.addAnalogInput(3, measuredvbat);
           lpp.addTemperature(4, temperature2);
           lpp.addBarometricPressure(5, pressure/100);
           lpp.addAnalogInput(6, atm);
           lpp.addAnalogInput(7, altitude);
            
//            LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
 
            // send the 6 bytes payload to LoRaWAN port 7
            LMIC_setTxData2(7, lpp.getBuffer(), lpp.getSize(), 0);
            SERIALDEBUG_PRINTLN(F("Packet queued")); 
            digitalWrite(LED_BUILTIN, HIGH);    // turn the LED on by making the voltage HIGH
        }
         
        // LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
        // Serial.println(F("Packet queued"));
    }
    // Next TX is scheduled after TX_COMPLETE event.
}
 
void setup() {
    delay(5000);
 
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
 
#ifdef SERIALDEBUG
    Serial.begin(9600);
    // while (!Serial);
#endif
 
    dht.begin();
    myBarometer.init(); 
    SERIALDEBUG_PRINTLN(F("Starting"));
 
    #ifdef VCC_ENABLE
    // For Pinoccio Scout boards
    pinMode(VCC_ENABLE, OUTPUT);
    digitalWrite(VCC_ENABLE, HIGH);
    delay(1000);
    #endif
 
    // LMIC init
    os_init();
    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_reset();
    LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
 
    // Set static session parameters. Instead of dynamically establishing a session
    // by joining the network, precomputed session parameters are be provided.
    #ifdef PROGMEM
    // On AVR, these values are stored in flash and only copied to RAM
    // once. Copy them to a temporary buffer here, LMIC_setSession will
    // copy them into a buffer of its own again.
    uint8_t appskey[sizeof(APPSKEY)];
    uint8_t nwkskey[sizeof(NWKSKEY)];
    memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
    memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
    LMIC_setSession (0x1, DEVADDR, nwkskey, appskey);
    #else
    // If not running an AVR with PROGMEM, just use the arrays directly
    LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);
    #endif
 
    #if defined(CFG_eu868)
    // Set up the channels used by the Things Network, which corresponds
    // to the defaults of most gateways. Without this, only three base
    // channels from the LoRaWAN specification are used, which certainly
    // works, so it is good for debugging, but can overload those
    // frequencies, so be sure to configure the full frequency range of
    // your network here (unless your network autoconfigures them).
    // Setting up channels should happen after LMIC_setSession, as that
    // configures the minimal channel set.
    // NA-US channels 0-71 are configured automatically
    LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
    LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
    // TTN defines an additional channel at 869.525Mhz using SF9 for class B
    // devices' ping slots. LMIC does not have an easy way to define set this
    // frequency and support for class B is spotty and untested, so this
    // frequency is not configured here.
    #elif defined(CFG_us915)
    // NA-US channels 0-71 are configured automatically
    // but only one group of 8 should (a subband) should be active
    // TTN recommends the second sub band, 1 in a zero based count.
    // https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json
    LMIC_selectSubBand(1);
    #endif
 
    // 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
    do_send(&sendjob);
}
 
void loop() {
    os_runloop_once();
}
Node red flow for Outdoor Weather Monitoring sensor node
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
[
    {
        "id": "f6f7a740.c6b338",
        "type": "tab",
        "label": "Device 2",
        "disabled": false,
        "info": ""
    },
    {
        "id": "fafe9ad3.9659e8",
        "type": "switch",
        "z": "f6f7a740.c6b338",
        "name": "Separate",
        "property": "key",
        "propertyType": "msg",
        "rules": [
            {
                "t": "cont",
                "v": "temperature_1",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "humidity",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "analog_in_3",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "temperature_4",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "barometric",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "analog_in_6",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "analog_in_7",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 7,
        "x": 220,
        "y": 180,
        "wires": [
            [
                "492a1844.49a228"
            ],
            [
                "b5be1839.3121a8"
            ],
            [
                "d7e35050.187eb"
            ],
            [
                "c5363ad1.5d3418"
            ],
            [
                "ee2891fa.0dbbe"
            ],
            [
                "71354cb4.e6af04"
            ],
            [
                "d48c0c97.4eb08"
            ]
        ]
    },
    {
        "id": "ccb2fb81.aacd58",
        "type": "split",
        "z": "f6f7a740.c6b338",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "key",
        "x": 90,
        "y": 180,
        "wires": [
            [
                "fafe9ad3.9659e8"
            ]
        ]
    },
    {
        "id": "657fd8a7.01c5e8",
        "type": "debug",
        "z": "f6f7a740.c6b338",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 870,
        "y": 240,
        "wires": []
    },
    {
        "id": "b5be1839.3121a8",
        "type": "function",
        "z": "f6f7a740.c6b338",
        "name": "Humidity",
        "func": "var humValue = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": humValue, \"Datastream\": {\"@iot.id\": 106}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 440,
        "y": 200,
        "wires": [
            [
                "dd5d521b.5c984"
            ]
        ]
    },
    {
        "id": "dd5d521b.5c984",
        "type": "http request",
        "z": "f6f7a740.c6b338",
        "name": "POST Observation",
        "method": "POST",
        "ret": "obj",
        "paytoqs": false,
        "url": "http://iot.gis.bgu.tum.de:8081/FROST-Server-gi3/v1.0/Observations",
        "tls": "",
        "proxy": "",
        "authType": "basic",
        "x": 690,
        "y": 240,
        "wires": [
            [
                "657fd8a7.01c5e8"
            ]
        ]
    },
    {
        "id": "492a1844.49a228",
        "type": "function",
        "z": "f6f7a740.c6b338",
        "name": "Temperature",
        "func": "var tempValue = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": tempValue, \"Datastream\": {\"@iot.id\": 105}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 450,
        "y": 160,
        "wires": [
            [
                "dd5d521b.5c984"
            ]
        ]
    },
    {
        "id": "739d03d0.606a6c",
        "type": "debug",
        "z": "f6f7a740.c6b338",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 490,
        "y": 60,
        "wires": []
    },
    {
        "id": "cb8ef1e2.a85f6",
        "type": "ttn uplink",
        "z": "f6f7a740.c6b338",
        "name": "TTN Input",
        "app": "58ceff1f.8576a",
        "dev_id": "tum-gis-device2",
        "field": "",
        "x": 80,
        "y": 60,
        "wires": [
            [
                "aae507e3.771c18"
            ]
        ]
    },
    {
        "id": "aae507e3.771c18",
        "type": "cayennelpp-decoder",
        "z": "f6f7a740.c6b338",
        "name": "",
        "x": 260,
        "y": 60,
        "wires": [
            [
                "ccb2fb81.aacd58",
                "739d03d0.606a6c"
            ]
        ]
    },
    {
        "id": "d7e35050.187eb",
        "type": "function",
        "z": "f6f7a740.c6b338",
        "name": "Battery Voltage",
        "func": "var Batteryvolt = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": Batteryvolt, \"Datastream\": {\"@iot.id\": 107}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 460,
        "y": 240,
        "wires": [
            [
                "dd5d521b.5c984"
            ]
        ]
    },
    {
        "id": "c5363ad1.5d3418",
        "type": "function",
        "z": "f6f7a740.c6b338",
        "name": "Temperature2",
        "func": "var tempValue = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": tempValue, \"Datastream\": {\"@iot.id\": 108}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 460,
        "y": 280,
        "wires": [
            [
                "dd5d521b.5c984"
            ]
        ]
    },
    {
        "id": "ee2891fa.0dbbe",
        "type": "function",
        "z": "f6f7a740.c6b338",
        "name": "Barometric Pressure",
        "func": "var pressure = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": pressure, \"Datastream\": {\"@iot.id\": 109}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 480,
        "y": 320,
        "wires": [
            [
                "dd5d521b.5c984"
            ]
        ]
    },
    {
        "id": "71354cb4.e6af04",
        "type": "function",
        "z": "f6f7a740.c6b338",
        "name": "Pressure atm",
        "func": "var atm = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": atm, \"Datastream\": {\"@iot.id\": 110}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 450,
        "y": 360,
        "wires": [
            [
                "dd5d521b.5c984"
            ]
        ]
    },
    {
        "id": "d48c0c97.4eb08",
        "type": "function",
        "z": "f6f7a740.c6b338",
        "name": "Altitude",
        "func": "var altitude = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": altitude, \"Datastream\": {\"@iot.id\": 111}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 440,
        "y": 400,
        "wires": [
            [
                "dd5d521b.5c984"
            ]
        ]
    },
    {
        "id": "58ceff1f.8576a",
        "type": "ttn app",
        "z": "",
        "appId": "gis-tum-sensors",
        "accessKey": "ttn-account-ACCESSKEY_HERE",
        "discovery": "discovery.thethingsnetwork.org:1900"
    }
]