Skip to content

Conversation

Copy link

Copilot AI commented Jan 29, 2026

The EM320-TH decoder treats temperature values as unsigned integers, causing incorrect readings for sub-zero temperatures. A value like -5°C (encoded as 0xFFCE in two's complement) was decoded as a large positive number.

Changes

  • Add parseTemperature(byteLow, byteHigh) function to handle signed 16-bit temperature values
  • Replace unsigned parsing in current temperature reading and historical data sections
  • Fix historical temperature offset bug (ii+4 for temp bytes after 4-byte timestamp)

Applied to all 5 integrations: CHIRPSTACK, TTN, LORIOT, TTI, HTTP

Implementation

function parseTemperature(byteLow, byteHigh) {
    var raw = (byteHigh & 0xFF) * 256 + (byteLow & 0xFF);
    if (raw >= 32768) {
        raw = raw - 65536;
    }
    return raw / 10;
}

Before: parseBytesToInt(input, i, 2, false) / 10
After: parseTemperature(input[i], input[i+1])

Original prompt

I got a request from a customer:

"During our follow-up testing, we found that the current EM320-TH decoder does not correctly handle temperatures below 0°C. To resolve this issue, the decoder on the platform needs to be updated.
I’ve attached the updated decoder content for your reference. Could you please ask your technical team to assist with applying this update?"

Here is the attached decoder they sent:

var data = decodeToJson(payload);
var deviceName = data.deviceName;
var deviceType = "EM320-TH";
var groupName = null; // If groupName is not null - created device will be added to the entity group with such name.
var customerName = null; // If customerName is not null - created devices will be assigned to customer with such name.

// use assetName and assetType instead of deviceName and deviceType
// to automatically create assets instead of devices.
// var assetName = 'Asset A';
// var assetType = 'building';

// If you want to parse incoming data somehow, you can add your code to this function.
// input: bytes
// expected output:
// {
// "attributes": {"attributeKey": "attributeValue"},
// "telemetry": [{"ts": 1...1, "values": {"telemetryKey":"telemetryValue"}, {"ts": 1...2, "values": {"telemetryKey":"telemetryValue"}}]
// }

function decodePayload(input) {
var output = {
attributes: {},
telemetry: []
};

// --- Decoding code --- //
var decoded = {};
var fPort = data.fPort;
var historyDataList = [];
if(fPort == 85) {
    for (var i = 0; i < input.length - 2;) {
        var channel_id = input[i++] & 0xff;
        var channel_type = input[i++] & 0xff;
        
        // IPSO VERSION
        if (channel_id === 0xff && channel_type === 0x01) {
            output.attributes.ipso_version = readProtocolVersion(bytes[i]);
            i += 1;
        }
        // HARDWARE VERSION
        else if (channel_id === 0xff && channel_type === 0x09) {
            output.attributes.hardware_version = readHardwareVersion(bytes.slice(i, i + 2));
            i += 2;
        }
        // FIRMWARE VERSION
        else if (channel_id === 0xff && channel_type === 0x0a) {
            output.attributes.firmware_version = readFirmwareVersion(bytes.slice(i, i + 2));
            i += 2;
        }
        // DEVICE STATUS
        else if (channel_id === 0xff && channel_type === 0x0b) {
            output.attributes.device_status = "on";
            i += 1;
        }
        // LORAWAN CLASS TYPE
        else if (channel_id === 0xff && channel_type === 0x0f) {
            output.attributes.lorawan_class = readLoRaWANType(bytes[i]);
            i += 1;
        }
        // SERIAL NUMBER
        else if (channel_id === 0xff && channel_type === 0x16) {
            output.attributes.sn = readSerialNumber(bytes.slice(i, i + 8));
            i += 8;
        }
        // TSL VERSION
        else if (channel_id === 0xff && channel_type === 0xff) {
            output.attributes.tsl_version = readTslVersion(bytes.slice(i, i + 2));
            i += 2;
        }
        // BATTERY
        if (channel_id === 0x01 && channel_type === 0x75) {
            decoded.battery = input[i];
            i += 1;
        }
        // TEMPERATURE
        else if (channel_id === 0x03 && channel_type === 0x67) {
            // ℃
            // decoded.temperature = parseBytesToInt(input, i, 2, true) / 10;
            // i += 2;
            
            decoded.temperature = parseTemperature(input[i], input[i+1]);
            i += 2;

            

            // ℉
            // decoded.temperature = parseBytesToInt(input, i, 2, false) / 10 * 1.8 + 32;
            // i +=2;
        }
        // HUMIDITY
        else if (channel_id === 0x04 && channel_type === 0x68) {
            decoded.humidity = parseBytesToInt(input, i, 1, false) / 2;
            i += 1;
        }
        // TEMPERATURE & HUMIDITY HISTROY
        else if (channel_id === 0x20 && channel_type === 0xce) {
            var historyData = {
                ts: parseBytesToInt(input, i, 4, false)*1000,
                values: {
                    // temperature: parseBytesToInt(input, i+4, 2, true) / 10,
                    temperature: parseTemperature(input[i+4], input[i+5]),
                    humidity: input[i + 6] /2
                }
            };
            
            historyDataList.add(historyData);
            i += 8;
        }
    }
}


// output.telemetry = [{
//     ts: timestamp,
//     values: decoded
// }];
output.telemetry = [];

// 1. Only add if valid data is parsed from the current package.
if (decoded != null && decoded.size() > 0) {
output.tel...

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

- Add parseTemperature function to properly decode signed 16-bit temperatures
- Update temperature parsing in both current reading and history sections
- Fix history temperature offset (use i+4 for temp bytes after timestamp)
- Apply fix to all 5 converters: CHIRPSTACK, TTN, LORIOT, TTI, HTTP

Co-authored-by: ViacheslavKlimov <56742475+ViacheslavKlimov@users.noreply.github.com>
Copilot AI changed the title [WIP] Update EM320-TH decoder for handling temperatures below 0°C Fix EM320-TH decoder to handle negative temperatures Jan 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants