Page cover image

TRP ERW700

Product Datasheet

Device Profile for Tesenso IoT Cloud

Decoder/Payload Converter for Tesenso IoT Cloud

https://github.com/Tesenso-GmbH/Device-Decoder/blob/main/METRA_TRP_ERW700.js
// V1.0, 29.09.2021, DS


if (msg.data) {
    var decoded = decodeFromHex(msg.data);
    decoded.ts = msg.ts;
    decoded.rssi = msg.rssi;
    decoded.snr = msg.snr;
    decoded.toa = msg.toa;
    decoded.frequency = msg.frequency;
    decoded.dr = msg.dr;
    decoded.bat = decodeBattery(msg.bat);
    decoded.hex = msg.data;

    return {
        msg: decoded,
        metadata: metadata,
        msgType: msgType
    };
} else {
    return {
        msg: msg,
        metadata: metadata,
        msgType: msgType
    };
}


function decodeFromHex(data) {
    // Decode an uplink message from a buffer
    // (array) of bytes to an object of fields.

    var telemetry = {};
    
    if (data.substr(30,2) == "81")
    {
        var hexString = "0x" + data.substr(32,8);
        var heatMeterEnergy = parseFloat(hexString);
        telemetry.heatMeterEnergy = heatMeterEnergy;
    }
    
    if (data.substr(40,2) == "9b")
    {
        var hexString = "0x" + data.substr(42,8);
        var waterMeter = parseFloat(hexString);
        telemetry.waterMeter = waterMeter;
    }
    
    if (data.substr(50,2) == "8d")
    {
        var hexString = "0x" + data.substr(52,8);
        var flowRate = parseFloat(hexString);
        telemetry.flowRate = flowRate;
    }
    
    if (data.substr(60,2) == "8a")
    {
        var hexString = "0x" + data.substr(62,8);
        var power = parseFloat(hexString);
        telemetry.power = power;
    }

    return telemetry;
}

function decodeBattery(byte) {
    if (byte == 0) {
        return 'External power source';
    } else if (byte > 0 && byte < 255) {
        return byte / 254 * 100;
    } else {
        return 'Unknown battery state'
    }
}

function parseHexString(hex) {
    for (var bytes = [], c = 0; c < hex.length; c += 2)
        bytes.push(parseInt(hex.substr(c, 2), 16));
    return bytes;
}


function decodeToString(payload) {
    return String.fromCharCode.apply(String, payload);
}

function decodeToJson(payload) {
    // covert payload to string.
    var str = decodeToString(payload);
    // parse string to JSON
    var data = JSON.parse(str);
    return data;
}

function twos_complement(input_value, num_bits) {
    var mask = Math.pow(2, num_bits - 1);
    return -(input_value & mask) + (input_value & ~mask);
}

function get_int(bytes) {
    var length = bytes.length;
    var int = 0;
    var i;

    for (i = 0; i < length; i++) {
        int += bytes[length - i - 1] << (i * 8);
    }

    return int;
}

function get_float(bytes) {
    var length = bytes.length;
    var float = 0;
    var int = get_int(bytes);

    if (length == 4) {
        var sign = (int & 0x80000000) ? -1 : 1;
        var exponent = ((int >> 23) & 0xFF) - 127;
        var significand = (int & ~(-1 << 23));

        if (exponent == 128) {
            float = sign * ((significand) ? Number.NaN :
                Number.POSITIVE_INFINITY);
        } else if (exponent == -127) {
            if (significand == 0) {
                float = sign * 0.0;
            } else {
                exponent = -126;
                significand /= (1 << 22);
                float = sign * significand * Math.pow(2,
                    exponent);
            }
        } else {
            significand = (significand | (1 << 23)) / (1 <<
                23);
            float = sign * significand * Math.pow(2,
                exponent);
        }
    } else if (length == 2) {
        var left = (int >> 14) & 0x03;
        var value0 = int & 0x3FFF;
        float = value0;
        if (left == 0) {
            float = float * 0.001;
        } else if (left == 1) {
            float = float * 0.02;
            float = float + 16.38;
        } else if (left == 3) {
            float = float * 5;
            float = float + 16725;
        } else if (left == 2) {
            float = float + 344;
        }
    } else {
        throw "Undefined floating point size";
    }
    return float;
}

function parseChunkTypeA(bytes) {
    var telemetry = {};
    var dataHeader = bytes[0];
    var dataValue = get_int(bytes.slice(1));
    if (dataHeader ==
        1
        ) { // 1 = 0x01 Temperature. signed integer 16bits. 1 LSB = 0.01°C.   0: 0°C; 1: +0.01°C; 0xFFFF : -0.01°C
        telemetry.temperature = twos_complement(dataValue,
            16) / 100;
    } else if (dataHeader ==
        2
        ) { // 2 = 0x02 Relative Humidity. unsigned integer 16bits. 1 LSB = 0.01°RH
        telemetry.humidity = twos_complement(dataValue,
            16) / 100;
    } else if (dataHeader ==
        3
        ) { // 3 = 0x03 Oxygen concentration. 1 LSB = 0.001%
        telemetry.oxygen = dataValue / 1000;
    } else if (dataHeader ==
        4) { // 4 = 0x04 CO2 concentration. 1 LSB = 0.001%
        telemetry.co2 = dataValue / 1000;
    } else if (dataHeader ==
        5
        ) { // 5 = 0x05 Second temperature. signed integer 16bits. 1 LSB = 0.01°C.   0: 0°C; 1: +0.01°C; 0xFFFF : -0.01°C
        telemetry.temperature2 = twos_complement(dataValue,
            16) / 100;
    } else if (dataHeader ==
        6
        ) { // 6 = 0x06 Pressure. unsigned integer 16bits. 1 LSB = 0.5mbar
        telemetry.pressure = dataValue / 2;
    } else if (dataHeader ==
        7) { // 7 = 0x07 analog channel #0. 1 LSB = 1 uA
        telemetry.analogCurrent0 = dataValue;
    } else if (dataHeader ==
        8) { // 8 = 0x08 analog channel #1. 1 LSB = 1 uA
        telemetry.analogCurrent1 = dataValue;
    } else if (dataHeader ==
        9) { // 9 = 0x09 analog channel #2. 1 LSB = 1 uA
        telemetry.analogCurrent2 = dataValue;
    } else if (dataHeader ==
        10) { // 10 = 0x0A analog channel #3. 1 LSB = 1 uA
        telemetry.analogCurrent3 = dataValue;
    } else if (dataHeader ==
        11) { // 11 = 0x0B digital inputs state
        telemetry.digitalInputsState = dataValue;
    } else if (dataHeader ==
        12) { // 12 = 0x0C relative pulse counter 0
        telemetry.relativePulseCounter0 = dataValue;
    } else if (dataHeader ==
        13) { // 13 = 0x0D relative pulse counter 1
        telemetry.relativePulseCounter1 = dataValue;
    } else if (dataHeader ==
        14) { // 14 = 0x0E relative pulse counter 2
        telemetry.relativePulseCounter2 = dataValue;
    } else if (dataHeader ==
        16) { // 16 = 0x10 analog channel #0. 1 LSB = 1 mV
        telemetry.analogVoltage0 = dataValue;
    } else if (dataHeader ==
        17) { // 17 = 0x11 analog channel #1. 1 LSB = 1 mV
        telemetry.analogVoltage1 = dataValue;
    } else if (dataHeader ==
        18) { // 18 = 0x12 analog channel #2. 1 LSB = 1 mV
        telemetry.analogVoltage2 = dataValue;
    } else if (dataHeader ==
        19) { // 19 = 0x12 analog channel #3. 1 LSB = 1 mV
        telemetry.analogVoltage3 = dataValue;
    }
    return telemetry;
}

function parseChunkTypeB(bytes) {
    var telemetry = {};
    var dataHeader = bytes[0];
    var dataValue = bytes.slice(1);
    // console.log(dataHeader)
    if (dataHeader ==
        128
        ) { // 128 = 0x80 timestamp of the measurement. unsigned integer 32 bits. UNIX timestamp
        // console.log(dataValue)
        // console.log(get_int(dataValue))
        //telemetry.ts = twos_complement(get_int(dataValue), 32) *1000; // calculate it in miliseconds
    } else if (dataHeader ==
        129
        ) { // 129 = 0x81 Main energy index. IEEE754 floating point. Unit : kWh for electricity meters (register 1.8.0)
        telemetry.electricityMeterEnergy = get_float(
            dataValue);
    } else if (dataHeader ==
        133
        ) { // 133 = 0x85 Main energy index. IEEE754 floating point. Unit : m3 for water meter
        telemetry.waterMeterVolume = get_float(dataValue);
    } else if (dataHeader ==
        134
        ) { // 134 = 0x86 Main energy index. IEEE754 floating point. Unit : m3 for uncorrected gas meter
        telemetry.gasMeterVolume = get_float(dataValue);
    } else if (dataHeader ==
        135
        ) { // 135 = 0x87 Flow temperature. IEEE754 floating point. Unit : °C
        telemetry.flowTemperature = get_float(dataValue);
    } else if (dataHeader ==
        138
        ) { // 138 = 0x8a Power register. IEEE754 floating point. Unit W.
        telemetry.power = get_float(dataValue);
    } else if (dataHeader ==
        139
        ) { // 139 = 0x8b Volume index. IEEE754 floating point. Unit: m3 for heat meter
        telemetry.heatMeterVolume = get_float(dataValue);
    } else if (dataHeader ==
        140
        ) { // 140 = 0x8c Return flow temperature. IEEE754 floating point. Unit: °C
        telemetry.returnFlowTemperature = get_float(
            dataValue);
    } else if (dataHeader ==
        141
        ) { // 141 = 0x8d Volume flow. IEEE754 floating point. Unit: m3/h
        telemetry.volumeFlow = get_float(dataValue);
    } else if (dataHeader ==
        154
        ) { // 154 = 0x9A IEEE754 floating point. Unit : kWh for heat meters (register 1.8.0)
        telemetry.heatMeterEnergy = get_float(dataValue);
    }
    return telemetry;
}

function parseChunkTypeC(bytes, timestamp) {
    var telemetry = [];
    var size = bytes.length;
    var dataHeader = bytes[0];
    var snr = get_int(bytes.slice(1, 5));
    var status = bytes.slice(5, 6);
    var interval =
        900000; // accumulation interval in milliseconds
    var lastReadIndex = get_float(bytes.slice(6, 10));
    var idx = 10;
    var counter = 1;

    // Get the interval from the status
    if ((status & 0x1c) == 0) {
        interval = 3600000;
    } else if ((status & 0x1c) == 0x4) {
        interval = 900000;
    } else if ((status & 0x1c) == 0x8) {
        interval = 38400000;
    }
    // Loop through the deltas and change the timestamp accordingly
    if (dataHeader ==
        201
        ) { // 140 = 0x8c Return flow temperature. IEEE754 floating point. Unit: °C
        telemetry.push({
            //'ts': timestamp,
            'waterMeterSNR': snr,
            'waterMeterCounter': lastReadIndex,
            'batteryError': Boolean(status &
                0x2),
            'otherError': Boolean(status & 1)
        })
        while (idx <= size) {
            var slice = bytes.slice(idx, idx + 2);
            if (!(get_int(slice) == 0xffff)) {
                telemetry.push({
                    //'ts': timestamp - counter * interval,
                    'waterMeterCounter': lastReadIndex + get_float(slice)
                    })
            }
            idx += 2;
            counter++;
        }
    } else if (dataHeader ==
        202
        ) { // 141 = 0x8d Volume flow. IEEE754 floating point. Unit: m3/h
        telemetry.push({
            //'ts': timestamp,
            'gasMeterSNR': snr,
                'gasMeterCounter': lastReadIndex,
                'batteryError': Boolean(status &
                    0x2),
                'otherError': Boolean(status & 1)
            })
        while (idx <= size) {
            var slice = bytes.slice(idx, idx + 2);
            if (!(get_int(slice) == 0xffff)) {
                telemetry.push({
                    //'ts': timestamp - counter * interval,
                    'gasMeterCounter': lastReadIndex +
                            get_float(slice)
                    })
            }
            idx += 2;
            counter++;
        }
    }
    return telemetry;
}

function parseChunkTypeD(bytes) {
    var telemetry = {};
    var dataHeader = bytes[0];
    var dataValue = get_int(bytes.slice(1));

    if (dataHeader == 96) { // 96 = 0x60 Battery voltage
        var volt = 0;
        if (dataValue >= 81) {
            volt = 4.2 + (dataValue - 80) * 0.1
        } else {
            volt = 1.8 + dataValue * 0.03
        }
        telemetry.batteryVoltage = volt;
    } else if (dataHeader ==
        97) { // 97 = 0x61 M-BUS meter status byte
        telemetry.mBusMeterStatus = dataValue;
    }
    return telemetry;
}

function decodeBattery(byte) {
    if (byte == 0) {
        return 'External power source';
    } else if (byte > 0 && byte < 255) {
        return byte / 254 * 100;
    } else {
        return 'Unknown battery state';
    }
}

function parseFloat(str) {
    var float = 0, sign, order, mantissa, exp,
    int = 0, multi = 1;
    if (/^0x/.exec(str)) {
        int = parseInt(str, 16);
    }
    else {
        for (var i = str.length -1; i >=0; i -= 1) {
            if (str.charCodeAt(i) > 255) {
                console.log('Wrong string parameter');
                return false;
            }
            int += str.charCodeAt(i) * multi;
            multi *= 256;
        }
    }
    sign = (int >>> 31) ? -1 : 1;
    exp = (int >>> 23 & 0xff) - 127;
    mantissa = ((int & 0x7fffff) + 0x800000).toString(2);
    for (i=0; i<mantissa.length; i+=1) {
        float += parseInt(mantissa[i]) ? Math.pow(2, exp) : 0;
        exp--;
    }
    return float*sign;
}

Device Labels

in manual
dataKey
dataType
dataFormat

ZLW Energie 1

heatMeterEnergy

telemetry

long

ZLW Energie 2

heatMeterEnergy

telemetry

long

ZLW Masse 1

waterMeter

telemetry

long

ZLW Volumen 1

waterMeterVolume

telemetry

long

ZLW Volumen 2

gasMeterVolume

telemetry

long

ZLW Volumen 3

heatMeterVolume

telemetry

long

Massefluss Qm 1

flowRate

telemetry

float

Volumen Durchfluss Qb 2

vB (Betriebsvolumen in m3)

telemetry

float

WarmTemp

flowTemperature

telemetry

float

KaltTemp

returnFlowTemperature

telemetry

float

Stromeingang 1

electricityMeterEnergy

telemetry

float

Last updated