Summary
When trying to collect air quality data via an SDS011 connected to an ESP32 Pax Counter, I get the following error:
TypeError: Value is not an object: undefined at apply (native)
I have already logged an issue in the Pax Counter git repo, however I’m posting here as well because I believe that this is an issue that the community may be able to help me with around the decoder rather than a fault with the Pax Counter itself.
Logs
No real logs as such in the console, but this is the event message:
{
"name": "as.up.data.decode.fail",
"time": "2024-11-30T10:25:43.662694741Z",
"identifiers": [
{
"device_ids": {
"device_id": "<STRING>",
"application_ids": {
"application_id": "<STRING>"
},
"dev_eui": "<STRING>",
"join_eui": "<STRING>"
}
}
],
"data": {
"@type": "type.googleapis.com/ttn.lorawan.v3.ErrorDetails",
"namespace": "pkg/scripting/javascript",
"name": "script",
"message_format": "{message}",
"attributes": {
"message": "TypeError: Value is not an object: undefined at apply (native)"
},
"correlation_id": "<STRING>",
"code": 10
},
"correlation_ids": [
"gs:uplink:<STRING>"
],
"origin": "ip-10-100-15-66.eu-west-1.compute.internal",
"context": {
"tenant-id": "<STRING>"
},
"visibility": {
"rights": [
"RIGHT_APPLICATION_TRAFFIC_READ"
]
},
"unique_id": "<STRING>"
}
Decoder is as follows:
// Decoder for device payload encoder "PLAIN"
// copy&paste to TTN Console V3 -> Applications -> Payload formatters -> Uplink -> Javascript
// modified for The Things Stack V3 by Caspar Armster, dasdigidings e.V.
function decodeUplink(input) {
var data = {};
if (input.fPort === 1) {
var i = 0;
if (input.bytes.length >= 2) {
data.wifi = (input.bytes[i++] << 8) | input.bytes[i++];
}
if (input.bytes.length === 4 || input.bytes.length > 15) {
data.ble = (input.bytes[i++] << 8) | input.bytes[i++];
}
if (input.bytes.length > 4) {
data.latitude = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
data.longitude = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
data.sats = input.bytes[i++];
data.hdop = (input.bytes[i++] << 8) | (input.bytes[i++]);
data.altitude = ((input.bytes[i++] << 8) | (input.bytes[i++]));
}
// Add after the "if (bytes.length > 4)" block
if (input.bytes.length >= 15) {
data.sds011 = String.fromCharCode.apply(null, input.bytes[i]);
i+=11;
}
data.pax = 0;
if ('wifi' in data) {
data.pax += data.wifi;
}
if ('ble' in data) {
data.pax += data.ble;
}
}
if (input.fPort === 2) {
var i = 0;
data.voltage = ((input.bytes[i++] << 8) | input.bytes[i++]);
data.uptime = ((input.bytes[i++] << 56) | (input.bytes[i++] << 48) | (input.bytes[i++] << 40) | (input.bytes[i++] << 32) | (input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
data.cputemp = input.bytes[i++];
data.memory = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
data.reset0 = input.bytes[i++];
data.restarts = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
}
if (input.fPort === 4) {
var i = 0;
data.latitude = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
data.longitude = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
data.sats = input.bytes[i++];
data.hdop = (input.bytes[i++] << 8) | (input.bytes[i++]);
data.altitude = ((input.bytes[i++] << 8) | (input.bytes[i++]));
}
if (input.fPort === 5) {
var i = 0;
data.button = input.bytes[i++];
}
if (input.fPort === 7) {
var i = 0;
data.temperature = ((input.bytes[i++] << 8) | input.bytes[i++]);
data.pressure = ((input.bytes[i++] << 8) | input.bytes[i++]);
data.humidity = ((input.bytes[i++] << 8) | input.bytes[i++]);
data.air = ((input.bytes[i++] << 8) | input.bytes[i++]);
}
if (input.fPort === 8) {
var i = 0;
if (input.bytes.length >= 2) {
data.voltage = (input.bytes[i++] << 8) | input.bytes[i++];
}
}
if (input.fPort === 9) {
// timesync request
if (input.bytes.length === 1) {
data.timesync_seqno = input.bytes[0];
}
// epoch time answer
if (input.bytes.length === 5) {
var i = 0;
data.time = ((input.bytes[i++] << 24) | (input.bytes[i++] << 16) | (input.bytes[i++] << 8) | input.bytes[i++]);
data.timestatus = input.bytes[i++];
}
}
if (data.hdop) {
data.hdop /= 100;
data.latitude /= 1000000;
data.longitude /= 1000000;
}
data.bytes = input.bytes; // comment out if you do not want to include the original payload
data.port = input.fPort; // comment out if you do not want to include the port
return {
data: data,
warnings: [],
errors: []
};
}
This comment contains the details of what I’ve changed over the basic decoder
Hardware
Device is an ESP32-PaxCounter sending data to an original TTIG and a RAK 7258.