Indoor Ambient Monitoring

This sensor node is made to showcase a use-case of LoRaWAN for indoor ambience monitoring. For achieving this a multitude of sensors were used which can monitor the quality of the ambience. In this example we measure parameters such as temperature, humidity, air pressure, air quality, CO2, loudness, gas, PM2.5, and light.

../_images/hardware-setup.jpg

Hardware setup.

Wiring setup

First of all, the grove base shield was connected over the Seeeduino LoRaWAN board. The board was set at the 5V mode. Then, the sensor connections were made using the connector cables as following:

  • Loudness Sensor – Analog Pin A0
  • PM 2.5 Sensor – I2C pin
  • Digital Light Sensor – I2C pin
  • BME680 Sensor – I2C pin
  • MHZ19B CO2 Sensor – Digital Pin D4
  • Air Quality Sensor - A2

Apart from this, there is no need of any other wiring in this case.

../_images/hardware1.png

Hardware connections.

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 Seeeduino LoRaWAN device. First, install the Seeeduino LoRaWAN board board to your Arduino IDE and select the correct port. Then following libraries needs to be installed before compiling the code:

Apart from this LoRaWan.h library is also used but it is bundled within Seeeduino Board and is not required to be separately installed.

Now download and run the Arduino Sketch for Indoor Ambient Monitoring sensor node file in the Arduino IDE. This code was created by merging the example code of each of these attached sensor and the ttn-otaa example from the Seeeduino board. Some required changes were made while merging the example codes. For example, as there are multiple sensors each needs to be defined with a unique name. So, here HM330X was named as sensor while AirqualitySensor as sensors.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
AirQualitySensor sensors(A2);

SoftwareSerial ss(4,5);
MHZ19 mhz(&ss);

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10

#define IIC_ADDR  uint8_t(0x76)
Seeed_BME680 bme680(IIC_ADDR);

int loudness,a;

HM330X sensor;
u8 buf[30];

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 any other service providers.

Modify the keys in highlighted lines
1
2
3
4
5
6
7
8
9
    // The EUIs and the AppKey must be given in big-endian format, i.e. the
    // most-significant-byte comes first (as displayed in the TTN console).
    // For TTN issued AppEUIs the first bytes should be 0x70, 0xB3, 0xD5.
 
    // void setId(char *DevAddr, char *DevEUI, char *AppEUI);
    lora.setId(NULL, "00942FBXXXXXXXXX", "70B3D57XXXXXXXXX");   
 
    // setKey(char *NwkSKey, char *AppSKey, char *AppKey);
    lora.setKey(NULL, NULL, "CB89A0AA43F6C5XXXXXXXXXXXXXXXXXX");

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 Indoor Ambient 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(21)/Datastreams

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

The GRAFANA dash-board for visualizing the collected data is available at: https://iot.gis.bgu.tum.de:3050/d/jDJ1li1Wz/indoor-ambient-monitoring-with-seeeduino-lorawan-and-sensors?orgId=1

Code files

Arduino Sketch for Indoor Ambient 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
#include <Wire.h>
#include <Digital_Light_TSL2561.h>
#include "Air_Quality_Sensor.h"
#include "seeed_bme680.h"
#include "Seeed_HM330X.h"
#include <SoftwareSerial.h>
#include <MHZ19.h>
#include <RTCZero.h>
#include <LoRaWan.h>
#include <CayenneLPP.h>

RTCZero rtc;
char buffer[256];                       // buffer for text messages received from the LoRaWAN module for display
 
CayenneLPP lpp(51);

AirQualitySensor sensors(A2);

SoftwareSerial ss(4,5);
MHZ19 mhz(&ss);

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10

#define IIC_ADDR  uint8_t(0x76)
Seeed_BME680 bme680(IIC_ADDR);

int loudness,a;

HM330X sensor;
u8 buf[30];

const char *str[]={"sensor num: ","PM1.0 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
                    "PM2.5 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
                    "PM10 concentration(CF=1,Standard particulate matter,unit:ug/m3): ",
                    "PM1.0 concentration(Atmospheric environment,unit:ug/m3): ",
                    "PM2.5 concentration(Atmospheric environment,unit:ug/m3): ",
                    "PM10 concentration(Atmospheric environment,unit:ug/m3): ",
                    };

err_t print_result(const char* str,u16 value)
{
    if(NULL==str)
        return ERROR_PARAM;
    SerialUSB.print(str);
    SerialUSB.println(value);
    return NO_ERROR;
}

/*parse buf with 29 u8-data*/
err_t parse_result(u8 *data)
{
    u16 value=0;
    err_t NO_ERROR;
    if(NULL==data)
        return ERROR_PARAM;
    for(int i=1;i<8;i++)
    {
         value = (u16)data[i*2]<<8|data[i*2+1];
         print_result(str[i-1],value);
         if(i==6)
           {   a=value;
               SerialUSB.println(a);
           }
    }
}

err_t parse_result_value(u8 *data)
{
    if(NULL==data)
        return ERROR_PARAM;
    for(int i=0;i<28;i++)
    {
        SerialUSB.print(data[i],HEX);
        SerialUSB.print("  ");
        if((0==(i)%5)||(0==i))
        {
            SerialUSB.println(" ");
        }
    }
    u8 sum=0;
    for(int i=0;i<28;i++)
    {
        sum+=data[i];
    }
    if(sum!=data[28])
    {
        SerialUSB.println("wrong checkSum!!!!");
    }
    SerialUSB.println(" ");
    SerialUSB.println(" ");
    return NO_ERROR;
}


void setup()
{ 
  Wire.begin();
  
  for(int i = 0; i < 26; i ++)        // Set all pins to HIGH to save power (reduces the
    {                                   // current drawn during deep sleep by around 0.7mA).
        if (i!=13) {                    // Don't switch on the onboard user LED (pin 13).
          pinMode(i, OUTPUT);
          digitalWrite(i, HIGH);
        }
    }   
     
  delay(5000); 
  
  SerialUSB.begin(115200);
      delay(100);
  SerialUSB.println("SerialUSB start");

  lora.init();                        // Initialize the LoRaWAN module
    
    memset(buffer, 0, 256);             // clear text buffer
    lora.getVersion(buffer, 256, 1);   
    memset(buffer, 0, 256);             // We call getVersion() two times, because after a reset the LoRaWAN module can be
    lora.getVersion(buffer, 256, 1);    // in sleep mode and then the first call only wakes it up and will not be performed.
    SerialUSB.print(buffer);
     
    memset(buffer, 0, 256);
    lora.getId(buffer, 256, 1);
    SerialUSB.print(buffer);
 
    // The following three constants (AppEUI, DevEUI, AppKey) must be changed
    // for every new sensor node. We are using the LoRaWAN OTAA mode (over the
    // air activation). Each sensor node must be manually registered in the
    // TTN console at https://console.thethingsnetwork.org before it can be
    // started. In the TTN console create a new device with the DevEUI also
    // being automatically generated. After the registration of the device the
    // three values can be copied from the TTN console. A detailed explanation
    // of these steps is given in
    // https://learn.adafruit.com/the-things-network-for-feather?view=all
 
    // The EUIs and the AppKey must be given in big-endian format, i.e. the
    // most-significant-byte comes first (as displayed in the TTN console).
    // For TTN issued AppEUIs the first bytes should be 0x70, 0xB3, 0xD5.
 
    // void setId(char *DevAddr, char *DevEUI, char *AppEUI);
    lora.setId(NULL, "00942FBXXXXXXXXX", "70B3D57XXXXXXXXX");   
 
    // setKey(char *NwkSKey, char *AppSKey, char *AppKey);
    lora.setKey(NULL, NULL, "CB89A0AA43F6C5XXXXXXXXXXXXXXXXXX");
     
    lora.setDeciveMode(LWOTAA);           // select OTAA join mode (note that setDeciveMode is not a typo; it is misspelled in the library)
    // lora.setDataRate(DR5, EU868);         // SF7, 125 kbps (highest data rate)
    lora.setDataRate(DR3, EU868);         // SF9, 125 kbps (medium data rate and range)
    // lora.setDataRate(DR0, EU868);         // SF12, 125 kbps (lowest data rate, highest max. distance)
 
    // lora.setAdaptiveDataRate(false);   
    lora.setAdaptiveDataRate(true);       // automatically adapt the data rate
     
    lora.setChannel(0, 868.1);
    lora.setChannel(1, 868.3);
    lora.setChannel(2, 868.5);
    lora.setChannel(3, 867.1);
    lora.setChannel(4, 867.3);
    lora.setChannel(5, 867.5);
    lora.setChannel(6, 867.7);
    lora.setChannel(7, 867.9);
 
    // The following two commands can be left commented out;
    // TTN works with the default values. (It also works when
    // uncommenting the commands, though.)
    // lora.setReceiceWindowFirst(0, 868.1);
    // lora.setReceiceWindowSecond(869.525, DR0);
    
    lora.setDutyCycle(false);             // for debugging purposes only - should normally be activated
    lora.setJoinDutyCycle(false);         // for debugging purposes only - should normally be activated
     
    lora.setPower(14);                    // LoRa transceiver power (14 is the maximum for the 868 MHz band)
     
    // while(!lora.setOTAAJoin(JOIN));
    while(!lora.setOTAAJoin(JOIN,20));    // wait until the node has successfully joined TTN
 
    lora.setPort(33);   
    
    if(sensor.init())
    {
        SerialUSB.println("HM330X init failed!!!");
        while(1);
    }

  if (sensors.init()) {
    SerialUSB.println("Sensor ready.");
  }
  else {
    SerialUSB.println("Sensor ERROR!");
  }
  
  TSL2561.init();

    while (!bme680.init()) 
  {
    SerialUSB.println("bme680 init failed ! can't find device!");
  delay(10000);
  }

  ss.begin(9600);

}

void loop()
{
  bool result = false;
  float temperature,humidity,pressure,airquality,light,gas,CO2;
    
  loudness = analogRead(0);
  SerialUSB.print("The Loudness Sensor value is: ");
  SerialUSB.println(loudness);
  SerialUSB.println();
  delay(3000);
    
  int quality = sensors.slope();

  SerialUSB.print("Air Quality Sensor value is: ");
  SerialUSB.println(airquality=sensors.getValue());
  
  if (quality == AirQualitySensor::FORCE_SIGNAL) {
    SerialUSB.println("High pollution! Force signal active.");
  }
  else if (quality == AirQualitySensor::HIGH_POLLUTION) {
    SerialUSB.println("High pollution!");
  }
  else if (quality == AirQualitySensor::LOW_POLLUTION) {
    SerialUSB.println("Low pollution!");
  }
  else if (quality == AirQualitySensor::FRESH_AIR) {
    SerialUSB.println("Fresh air.");
  }
  SerialUSB.println();
  delay(3000);
  
  SerialUSB.print("The Light Sensor value is: ");
  SerialUSB.println(light=TSL2561.readVisibleLux());
  SerialUSB.println();
  delay(3000);
    
    if(sensor.read_sensor_value(buf,29))
    {
        SerialUSB.println("HM330X read result failed!!!");
    }
    parse_result_value(buf);
    parse_result(buf);
    SerialUSB.println(" ");
    delay(3000);

    if (bme680.read_sensor_data()) 
  {
    SerialUSB.println("Failed to perform reading :(");
    return;
  }
  SerialUSB.print("temperature ===>> ");
  SerialUSB.print(temperature = bme680.sensor_result_value.temperature);
  SerialUSB.println(" C");

  SerialUSB.print("pressure ===>> ");
  SerialUSB.print(pressure = bme680.sensor_result_value.pressure/ 1000.0);
  SerialUSB.println(" KPa");

  SerialUSB.print("humidity ===>> ");
  SerialUSB.print(humidity = bme680.sensor_result_value.humidity);
  SerialUSB.println(" %");

  SerialUSB.print("gas ===>> ");
  SerialUSB.print(gas = bme680.sensor_result_value.gas/ 1000.0);
  SerialUSB.println(" Kohms");

  SerialUSB.println();
  
  delay(3000);

  MHZ19_RESULT response = mhz.retrieveData();
  if (response == MHZ19_RESULT_OK)
  {
    SerialUSB.print(F("CO2: "));
    SerialUSB.println(CO2=mhz.getCO2());
    SerialUSB.print(F("Min CO2: "));
    SerialUSB.println(mhz.getMinCO2());
    SerialUSB.print(F("Temperature: "));
    SerialUSB.println(mhz.getTemperature());
    SerialUSB.print(F("Accuracy: "));
    SerialUSB.println(mhz.getAccuracy());
    SerialUSB.println();
  }
  else
  {
    SerialUSB.print(F("Error, code: "));
    SerialUSB.println(response);
  }
  
    lpp.reset();
    lpp.addTemperature(1, temperature);
    lpp.addRelativeHumidity(2, humidity);
    lpp.addAnalogInput(3, airquality);
    lpp.addLuminosity(4, light);
    lpp.addBarometricPressure(5, pressure);
    lpp.addLuminosity(6, CO2);
    lpp.addAnalogInput(7, gas);
    lpp.addLuminosity(8, loudness);
    lpp.addLuminosity(9, a);   
    result = lora.transferPacket(lpp.getBuffer(), lpp.getSize(), 5);   // send the data packet (n byts) with a default timeout of 5 secs

    if(result)
    {
        short length;
        short rssi;
         
        memset(buffer, 0, 256);
        length = lora.receivePacket(buffer, 256, &rssi);
         
        if(length)
        {
            SerialUSB.print("Length is: ");
            SerialUSB.println(length);
            SerialUSB.print("RSSI is: ");
            SerialUSB.println(rssi);
            SerialUSB.print("Data is: ");
            for(unsigned char i = 0; i < length; i ++)
            {
                SerialUSB.print("0x");
                SerialUSB.print(buffer[i], HEX);
                SerialUSB.print(" ");
            }
            SerialUSB.println();
        }
    }
     
    lora.setDeviceLowPower();     // bring the LoRaWAN module to sleep mode
    doSleep((5*60-8)*1000);       // deep sleep for 292 secs (+ 3 secs transmission time + 5 secs timeout = 300 secs period)
    lora.setPort(33);    

}

void doSleep(uint32_t millis) {
    if (!rtc.isConfigured()) {    // if called for the first time,
        rtc.begin(false);         // then initialize the real time clock (RTC)
    }
 
    uint32_t now = rtc.getEpoch();
    rtc.setAlarmEpoch(now + millis/1000);
    rtc.enableAlarm(rtc.MATCH_HHMMSS);
 
    rtc.standbyMode();            // bring CPU into deep sleep mode (until woken up by the RTC)
}
Node red flow for Indoor Ambient 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
[
    {
        "id": "7d5c6b14.d2af94",
        "type": "tab",
        "label": "Device3",
        "disabled": false,
        "info": ""
    },
    {
        "id": "4d581d8.f14c0e4",
        "type": "switch",
        "z": "7d5c6b14.d2af94",
        "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": "luminosity_4",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "barometric",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "luminosity_6",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "analog_in_7",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "luminosity_8",
                "vt": "str"
            },
            {
                "t": "cont",
                "v": "luminosity_9",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 9,
        "x": 220,
        "y": 180,
        "wires": [
            [
                "92425d9f.bca98"
            ],
            [
                "9b919750.d6fff8"
            ],
            [
                "620b1ab2.a69224"
            ],
            [
                "eee677bf.fe16d8"
            ],
            [
                "4b424590.139b4c"
            ],
            [
                "bc3f8433.7b89f8"
            ],
            [
                "13968bca.c2cd34"
            ],
            [
                "c7fcb372.4b2df"
            ],
            [
                "b52fa683.7c5fb8"
            ]
        ]
    },
    {
        "id": "9010a80d.dfcdb8",
        "type": "split",
        "z": "7d5c6b14.d2af94",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "key",
        "x": 90,
        "y": 180,
        "wires": [
            [
                "4d581d8.f14c0e4"
            ]
        ]
    },
    {
        "id": "a3b86e6f.56637",
        "type": "debug",
        "z": "7d5c6b14.d2af94",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 870,
        "y": 240,
        "wires": []
    },
    {
        "id": "9b919750.d6fff8",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "Humidity",
        "func": "var humValue = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": humValue, \"Datastream\": {\"@iot.id\": 113}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 440,
        "y": 200,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "c67491fc.f4755",
        "type": "http request",
        "z": "7d5c6b14.d2af94",
        "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": [
            [
                "a3b86e6f.56637"
            ]
        ]
    },
    {
        "id": "92425d9f.bca98",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "Temperature",
        "func": "var tempValue = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": tempValue, \"Datastream\": {\"@iot.id\": 112}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 450,
        "y": 160,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "a16b3beb.1a5028",
        "type": "debug",
        "z": "7d5c6b14.d2af94",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 490,
        "y": 60,
        "wires": []
    },
    {
        "id": "681442b7.1266ac",
        "type": "ttn uplink",
        "z": "7d5c6b14.d2af94",
        "name": "TTN Input",
        "app": "58ceff1f.8576a",
        "dev_id": "tum-gis-device3",
        "field": "",
        "x": 80,
        "y": 60,
        "wires": [
            [
                "531b0b35.751284"
            ]
        ]
    },
    {
        "id": "531b0b35.751284",
        "type": "cayennelpp-decoder",
        "z": "7d5c6b14.d2af94",
        "name": "",
        "x": 260,
        "y": 60,
        "wires": [
            [
                "9010a80d.dfcdb8",
                "a16b3beb.1a5028"
            ]
        ]
    },
    {
        "id": "620b1ab2.a69224",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "Air Quality",
        "func": "var quality = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": quality, \"Datastream\": {\"@iot.id\": 119}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 450,
        "y": 240,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "eee677bf.fe16d8",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "Light",
        "func": "var light = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": light, \"Datastream\": {\"@iot.id\": 117}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 430,
        "y": 280,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "4b424590.139b4c",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "Barometric Pressure",
        "func": "var pressure = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": pressure, \"Datastream\": {\"@iot.id\": 114}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 480,
        "y": 320,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "bc3f8433.7b89f8",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "co2",
        "func": "var co2 = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": co2, \"Datastream\": {\"@iot.id\": 118}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 430,
        "y": 360,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "13968bca.c2cd34",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "Gas",
        "func": "var gas = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": gas, \"Datastream\": {\"@iot.id\": 121}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 430,
        "y": 400,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "c7fcb372.4b2df",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "Loudness",
        "func": "var loudness = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": loudness, \"Datastream\": {\"@iot.id\": 120}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 440,
        "y": 440,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "b52fa683.7c5fb8",
        "type": "function",
        "z": "7d5c6b14.d2af94",
        "name": "Dust-PM2.5",
        "func": "var Dust = msg.payload.valueOf();\nvar newMessage =  { payload: {  \"result\": Dust, \"Datastream\": {\"@iot.id\": 128}} };\nnewMessage.headers = {\"Content-type\" : \"application/json\"}\nreturn newMessage;",
        "outputs": 1,
        "noerr": 0,
        "x": 450,
        "y": 480,
        "wires": [
            [
                "c67491fc.f4755"
            ]
        ]
    },
    {
        "id": "58ceff1f.8576a",
        "type": "ttn app",
        "z": "",
        "appId": "gis-tum-sensors",
        "accessKey": "ttn-account-ACCESSKEY_HERE",
        "discovery": "discovery.thethingsnetwork.org:1900"
    }
]