SeeeD SenseCAP LoRaWAN CO2 Sensor function to emoncms

Hello,
I am not a programmer and am having lots of problems getting this sensor data into my emoncms server. The sensor seems to be working correctly and sending LoRa data to my RAK7244 server/gateway. I have four LoRa temp/hum (LHT65) sensors doing this (MQTT) and are working correctly (I had much help in setting up the function on node-red).
I'm sure the problem must be my "function" syntax and construction as I'm getting errors of CO2_Value_PPM "undefined."
I have attached what I think will give you enough information but will be happy to send more. Thanks in advance.
Bob

> Data From LoRa gateway
> 
> Applications/CO2app/Devices/CO2device
> 
> applicationID:"18"
> applicationName:"CO2app"
> deviceName:"CO2device"
> devEUI:"2cf7f12122500013"
> rxInfo:
> frequency:904700000
> modulation:"LORA"
>     bandwidth:125
>     spreadingFactor:10
>     codeRate:"4/5"
>     polarizationInversion:false
> adr:true
> dr:0
> fCnt:44
> fPort:2
> data:"AQQQeMIGAFZv"
> 
> err:0
>         CO2_Value_PPM:443  <<--this is the data I need sent
>         measurementId:4100
>         type:"report_telemetry"
>     payload:"01041078C20600566F"
>     valid:true
> tags:
>         confirmedUplink:true
>         devAddr:"01686a36"
>         publishedAt:"2021-11-14T21:56:48.345702362Z"
> 
> =======================================================
> 
> debug message
> 
> 11/14/2021, 4:56:48 PMnode: 64d043922a280e22
> msg.payload : Object
> object
> CO2_Value_PPM: undefined
> 
> =======================================================
> 
> emoncms node
> 
> 
> Emoncms server   emonpi
> Node              CO2
> Data Type       valid JSON object
> Name             CO2
> 
> =======================================================
> 
> From Node-Red Function Node
> 
> On Message
> input = msg.payload
> var CO2_Value_PPM = input.object.CO2_Value_PPM
> msg2 = {payload:{"CO2_Value_PPM":realDataValue}};
> return msg2;
> 
> =====================================================
> 
> From Json Node
> 
> 
> Action  Always convery to JavaScript Object
> Property  msg payload
> Name  CO2
> 
> ====================================================
> 
> MQTT in node
> 
> 
> Server   RAK7244
> Topic    application/18/device/2cf7f12122500013/rx
> QoS       1
> Output    auto-detect (string or buffer)
> Name     CO2
> 
> ==================================================

Welcome Bob to the Node-red forum.

What LORAWAN server are you using?

Put a debug node and connect it to the MQTT node, what do you see there? Post that json please.

The first part looks like the "Live Device Data" view from RAK GW
So your setup

[end-device] -- [RAK GW] -- [MQTT] -- [ Node-RED -- { Function Node} -- (emoncms) ] ?

Could you share your flow as it's not clear where you are doing your decode
in RAK GW using CayenneLPP ?
in Node-RED using javascript for Dragaino payload decoder??

First of all, thanks to @ScheepersJohan and @iiLaw for answering my plea for help.
Here is some additional information you requested. Much appreciated.
Cheers,
Bob (Ashland, VA)

My system is a RAK7244 LoRa server/gateway on an RPI4 (buster) running chirpstack.
I have another RPI4 running emoncms (an energy monitoring system) which can receive MQTT data from other brokers to post on its web page (locally on the RPI4).
I already have 4 LHT65 temp/hum sensors configured with a node-red flow which are
working and sending data through the LoRa server to the emoncms server.

The problem is that my new Seeed CO2 sensor is sending data through the LoRa
system but my node-red configuration isn't getting the data to the emoncms server.
The path seems to be connected (a node has been created on emoncms) but the
data isn't beeing parsed correctly and sent to emoncms. I need to extract the
portion "CO2_Value_PPM" with data and send it to emoncms.

My error:

> 11/20/2021, 10:07:41 AM node: CO2 
> function : (error)
> "TypeError: Cannot read property 
> 
> 'CO2_Value_PPM' of undefined"

**My function which isn't working:**

> input = msg.payload
> var CO2_Value_PPM = input.object.CO2_Value_PPM
> msg2 = {payload:{"CO2_Value_PPM":realDataValue}};
> return msg2;

Data being sent from sensor to LoRa server and decoded:

> ChirpStack.io
> Applications/CO2app/Devices/CO2device
> 
> applicationID:"18"
> applicationName:"CO2app"
> deviceName:"CO2device"
> devEUI:"2cf7f12122500013"
> rxInfo:
> frequency:903900000
> modulation:"LORA"
>     bandwidth:125
>     spreadingFactor:10
>     codeRate:"4/5"
>     polarizationInversion:false
> adr:true
> dr:0
> fCnt:33
> fPort:2
> data:"AQQQqLoGADTR"
> err:0
>         CO2_Value_PPM:441  <--[the data I need]
>         measurementId:4100
>         type:"report_telemetry"
>     payload:"010410A8BA060034D1"
>     valid:true
> tags:
>         confirmedUplink:true
>         devAddr:"00d0e7c1"
>         publishedAt:"2021-11-20T14:06:28.062161582Z"

My node-red flow:

Section from CO2 sensor decoder on chirpstack server:

>  if (checkDataIdIsMeasureUpload(dataID)) {
>             // if telemetry.
>             decoded.messages.push({
>                 type: "report_telemetry",
>                 measurementId: dataID,
>                // measurementValue: realDataValue
>                CO2_Value_PPM: realDataValue
>             });

make sure the MQTT node is set to output a parsed JSON object.
image

1 Like

Thanks @dceejay, I made the change but nothing seemed to change. See below:

Ok Dave is pointing you the right direction your issue I believe your still passing a string to the function node. Can you try wiring from MQTT-in to {CO2} function node pls.
Can you copy the debgug output from each debug node pls an post to this thread.

It would help if name your debug nodes so we can see what is emitted as it's not clear from your screen shots "MQTT-uplink" for example for LoRaWAN uplinks.

Ok, hope I have done what you need. Flow 2 has been relabeled for clarity:

I created flow3 and connected the MQTT uplink directly to function. There was no connection success to emoncms:

One thing I did notice was that the sensor doesn't always send CO2 data with each upload. Normally it sends data every 60 minutes which always includes the CO2 information "CO2_Value_PPM" However, the last screen shots resulted in me resetting the device to make it send something before the hour was up. Anyway, flow 3 never seemed to make it to the emoncms server.

Copy each debugs payload and past in between 3 ```

image

copy payload

Hi think until you give us what we've asked for,
there is not much we can do more at the moment to help.

BTW what is the make & model of your CO2 sensor.

11/20/2021, 3:51:38 PMnode: RAK7244-MQTTup
application/18/device/2cf7f12122500013/rx : msg.payload : Object
object
applicationID: "18"
applicationName: "CO2app"
deviceName: "CO2device"
devEUI: "2cf7f12122500013"
txInfo: object
frequency: 905300000
dr: 0
adr: true
fCnt: 16
fPort: 2
data: "AQQQOCYGACET"
object: object
err: 0
messages: array[1]
0: object
CO2_Value_PPM: 403
measurementId: 4100
type: "report_telemetry"
payload: "010410382606002113"
valid: true
11/20/2021, 3:51:39 PMnode: CO2function : (error)
"TypeError: Cannot read property 'CO2_Value_PPM' of undefined"
11/20/2021, 3:51:39 PMnode: JSON parser
application/18/device/2cf7f12122500013/rx : msg.payload : string[560]
string[560]

{
    "applicationID": "18",
    "applicationName": "CO2app",
    "deviceName": "CO2device",
    "devEUI": "2cf7f12122500013",
    "txInfo": {
        "frequency": 905300000,
        "dr": 0
    },
    "adr": true,
    "fCnt": 16,
    "fPort": 2,
    "data": "AQQQOCYGACET",
    "object": {
        "err": 0,
        "messages": [
            {
                "CO2_Value_PPM": 403,
                "measurementId": 4100,
                "type": "report_telemetry"
            }
        ],
        "payload": "010410382606002113",
        "valid": true
    }
}

Sorry, I'm new at this.
Seeed SenseCAP SOLO CO2 5000

From flow 3 where MQTTin is connected directly to function:

11/20/2021, 4:52:52 PMnode: CO2function : (error)
"ReferenceError: realDataValue is not defined (line 3, col 34)"
11/20/2021, 4:52:52 PMnode: RAK7244-MQTTin
application/18/device/2cf7f12122500013/rx : msg.payload : Object
object
applicationID: "18"
applicationName: "CO2app"
deviceName: "CO2device"
devEUI: "2cf7f12122500013"
txInfo: object
frequency: 904100000
dr: 0
adr: true
fCnt: 17
fPort: 2
data: "AQQQWHQGAJ68"
object: object
err: 0
messages: array[1]
0: object
CO2_Value_PPM: 423
measurementId: 4100
type: "report_telemetry"
payload: "010410587406009EBC"
valid: true

Function code:

input = msg.payload
var CO2_Value_PPM = input.object.CO2_Value_PPM
msg2 = {payload:{"CO2_Value_PPM":realDataValue}};
return msg2;

Hi - have a look at Working with messages : Node-RED - especially the understanding the structure of a message section - It shows how to use the debug window to find the path to the property you want.
If you follow that you should find it is in msg.payload.object.messages[0].CO2_Value_PPM

ok what are the settings of the JSON node it's looking like payload is a string not a object.
So from have you tried dropping the JSON node and wiring the MQTT to function node

I don't know that device but many devices send a "settings" msg after joining which is different form from a periodic measurement.

What would help is an export of your flow with that we can copy it on to our NR instances to take look.
But your not far away from sorting it.

Ok, I'll work on an export. I'll need to read up how to do it.
In the meantime here is some info from a sensor I have working on this system. It may give you a clue.

Maybe this will help

Example of an LHT65 temp/hum sensor which is working correctly:

11/20/2021, 4:56:45 PMnode: MQTTin from RAK7244
application/7/device/a84041ce918279c4/rx : msg.payload : string[316]
"{"applicationID":"7","applicationName":"LHT65","deviceName":"LHT65w","devEUI":"a84041ce918279c4","txInfo":{"frequency":904500000,"dr":0},"adr":true,"fCnt":2527,"fPort":2,"data":"y78H4gGYAQfDf/8=","object":{"BatV":3.007,"Ext_sensor":"Temperature Sensor LHT65","Hum_SHT":"40.8","TempF_DS":"67.77","TempF_SHT":"68.32"}}"
11/20/2021, 4:56:45 PMnode: 16fb5469bd0c1de1
application/7/device/a84041ce918279c4/rx : msg.payload : Object
object
applicationID: "7"
applicationName: "LHT65"
deviceName: "LHT65w"
devEUI: "a84041ce918279c4"
txInfo: object
frequency: 904500000
dr: 0
adr: true
fCnt: 2527
fPort: 2
data: "y78H4gGYAQfDf/8="
object: object
BatV: 3.007
Ext_sensor: "Temperature Sensor LHT65"
Hum_SHT: "40.8"
TempF_DS: "67.77"
TempF_SHT: "68.32"
11/20/2021, 4:56:45 PMnode: LHT65W
msg.payload : Object
object
BatV: 3.007
Hum_SHT: "40.8"
TempF_DS: "67.77"
TempF_SHT: "68.32"

function coding for LHT65

input = msg.payload
var BatV = input.object.BatV
var Hum_SHT = input.object.Hum_SHT
var TempF_DS= input.object.TempF_DS
var TempF_SHT= input.object.TempF_SHT
msg2 = {payload:{"BatV":BatV, "Hum_SHT":Hum_SHT, "TempF_DS":TempF_DS,"TempF_SHT":TempF_SHT}};
return msg2;

flows.json (3.8 KB)

Export of flow 2

Thanks for your patience and help.

Ok it was your JS code in function node
I've take the liberty of re-writing it

// Test to see if CO2 measurement is present in uplink
// Assumption is msg.payload.object.messages[] array is always present
// if not then we need to test in different way
// why do we do this to ensure we don't send rubbish to emoncms

if ("CO2_Value_PPM" in msg.payload.object.messages[0]){
    msg = {payload:{"CO2_Value_PPM":msg.payload.object.messages[0].CO2_Value_PPM}};
    return msg;
}

Modified flow

[
    {
        "id": "e21fb0fe83c49f5b",
        "type": "mqtt in",
        "z": "7db6160ca3e53565",
        "name": "RAK7244",
        "topic": "application/18/device/2cf7f12122500013/rx",
        "qos": "1",
        "datatype": "json",
        "broker": "dc0cfbd7.ba7858",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 121,
        "y": 100,
        "wires": [
            [
                "3042098831fd60d9",
                "483e91506c5bcd77"
            ]
        ]
    },
    {
        "id": "64d043922a280e22",
        "type": "debug",
        "z": "7db6160ca3e53565",
        "name": "function-on message",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 600,
        "y": 160,
        "wires": []
    },
    {
        "id": "3042098831fd60d9",
        "type": "debug",
        "z": "7db6160ca3e53565",
        "name": "RAK7244-MQTTup",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 350,
        "y": 160,
        "wires": []
    },
    {
        "id": "721ea6847b236a6a",
        "type": "inject",
        "z": "7db6160ca3e53565",
        "name": "Test JSON",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "{\"applicationID\":\"18\",\"applicationName\":\"CO2app\",\"deviceName\":\"CO2device\",\"devEUI\":\"2cf7f12122500013\",\"txInfo\":{\"frequency\":905300000,\"dr\":0},\"adr\":true,\"fCnt\":16,\"fPort\":2,\"data\":\"AQQQOCYGACET\",\"object\":{\"err\":0,\"messages\":[{\"CO2_Value_PPM\":403,\"measurementId\":4100,\"type\":\"report_telemetry\"}],\"payload\":\"010410382606002113\",\"valid\":true}}",
        "payloadType": "json",
        "x": 120,
        "y": 40,
        "wires": [
            [
                "483e91506c5bcd77"
            ]
        ]
    },
    {
        "id": "483e91506c5bcd77",
        "type": "function",
        "z": "7db6160ca3e53565",
        "name": "CO2 to emoncms",
        "func": "// Test to see if CO2 measurment is present in uplink\n// Assumtion is msg.payload.object.messages[] array is always present\n// if not then we need to test in diffrent way\n// why do we do this to ensure we don't send rubish to emoncms\n\nif (\"CO2_Value_PPM\" in msg.payload.object.messages[0]){\n    msg = {payload:{\"CO2_Value_PPM\":msg.payload.object.messages[0].CO2_Value_PPM}};\n    return msg;\n}",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 356,
        "y": 100,
        "wires": [
            [
                "64d043922a280e22"
            ]
        ]
    },
    {
        "id": "dc0cfbd7.ba7858",
        "type": "mqtt-broker",
        "name": "RAK7244",
        "broker": "192.168.1.10",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "sessionExpiry": ""
    }
]
1 Like

It's as I thought when sensor joins the LNS it sends an Initial packet. Then send what Seed calls "Measurement data packets" e.g. CO2 measurement

Initial packets(no need to learn about these initial packets)
- One packet with device info including hardware version, software version, battery level, sensor
hardware & software version, sensor EUI, power, and sensor power time counter at each channel.

Hi Lawrence,
It seems to be working! I have dropped the JSON node and added your code to the function. I'll wait a day or so to be sure all is well. At least the first hour's data went to and was recorded in the emoncms database. My webpage is N4MRV-1 --- Ashland, Virginia Current Weather Conditions where I plan to display CO2 PPM readings. I now will have a front row seat to watch our planet circling the drain...
Thank you @iiLaw, @dceejay, and @ScheepersJohan -- very much appreciated!
Cheers,
Bob

2 Likes