Page cover image

MTKcoder

The MTKcoder measures even the smallest flow rates. Perfect areas of application are measuring points that are difficult to access, such as in manholes or in the automation of fixed network readout.

Product Datasheet

Device Profile for Tesenso IoT Cloud

Device Labels

in manual
dataKey
dataType
dataFormat

Hauswasserzähler

waterMeter

telemetry

float

Decoder/Payload Converter for Tesenso IoT Cloud

https://github.com/Tesenso-GmbH/Device-Decoder/blob/main/GWF_MTKcoder.js
//V1.0, 20.12.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) {

    var telemetry = {};

    //var batteryStatus = BatteryStatus.CalculateBatterStatus((int) rawMessageSection.bat);

    // Unstring input payload according to the specification
    //string protocolType = sensorData.Substring(0, 2);
    //string meterManufacturerID = sensorData.Substring(2, 4);
    //string meterID = sensorData.Substring(6, 8);
    var meterMedium = data.substr(14, 2);
    //telemetry.meterMedium = meterMedium;
    var stateMbus = data.substr(16, 2);
    //telemetry.stateMbus = stateMbus;
    //string actualityDuration = sensorData.Substring(18, 4);
    var volumeVIF = data.substr(22, 2);
    //telemetry.volumeVIF = volumeVIF;
    var volumeValue = data.substr(24, 8);
    //telemetry.volumeValue = volumeValue;
    //string additionalFunctions = sensorData.Substring(32, 2);
    //string batteryLifetime = sensorData.Substring(34, 2);
    //string checksum = sensorData.Substring(36, 4);

    telemetry.unit = "m3";

    if (meterMedium == "07" && (stateMbus == "00" |
            stateMbus == "04")) {
        telemetry.waterMeter =
            GetMeterReadingWarmWater(volumeVIF,
            volumeValue);
    }


    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';
    }
}

// Decode Payload for the meter reading warm water
function GetMeterReadingWarmWater(volumeVIF, volumeValue) {

    
    var volumeValueLSB = volumeValue.substr(6, 2) +
        volumeValue.substr(4, 2) + volumeValue.substr(2,
            2) + volumeValue.substr(0, 2);

    var measurementResult = parseInt(volumeValueLSB,
        16);

    switch (volumeVIF) {
        case "10":
            measurementResult *=
                0.000001; // (10 ^ (-6));
            break;
        case "11":
            measurementResult *=
                0.00001; // (10 ^ (-5));
            break;
        case "12":
            measurementResult *= 0.0001; // (10 ^ (-4));
            break;
        case "13":
            measurementResult *= 0.001; // (10 ^ (-3));
            break;
        case "14":
            measurementResult *= 0.01; // (10 ^ (-2));
            break;
        case "15":
            measurementResult *= 0.1; // (10 ^ (-1));
            break;
        default:
            break;
    }

    return measurementResult;
}
https://github.com/Tesenso-GmbH/Device-Decoder/blob/main/Tesenso_M-Bus_GWF_Wasser.js
// V3.0 10.05.2022, DS
// V4.0, 06.07.2022, FU
// V5.0 , 11.07.2022, PA
//var medium_table = {
//   "Gas": "03",
//   "Electricity": "02",
//   "Heat: Outlet": "04",
//  "Heat: Inlet": "0C",
//   "Water": "07",
//   "Cold water": "16",
//   "Other": "00",
//   "Warm water (30-90°C)": "06",
//};
//Code entry
if (msg.data) {
    var decoded = decodeFromHex(msg.data.toString());
    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 uplink message
    var decoded = {};

    //Parse string as bytes
    var bytes = parseHexString(data);
    //scale to manage the different scales with none, one or more decimals on the meter.
    var scale = metadata.ss_scale;

    //various info that can be extracted
    var length = bytes[0];
    var msgType = bytes[1];
    var slaveCount = bytes[2];
    var startCharacter1 = bytes[3];
    var length1 = bytes[4];
    var length2 = bytes[5];
    var startCharacter2 = bytes[6];
    var c = bytes[7];
    var a = bytes[8];
    //72 or 76 -> variable; 73 or 77 -> fixed
    var ciField = bytes[9];
    var medium = data.substr(34, 2);
    var checkSum = bytes[36];


    //Different medium IDs, register positions vary
    if (medium == "02") {
        var volume = data.substr(72, 2) + data.substr(70,
            2) + data.substr(68, 2) + data.substr(66, 2);
        decoded.electricityMeterEnergyHt = parseInt(volume,
            16) * scale;
        volume = data.substr(88, 2) + data.substr(86, 2) +
            data.substr(84, 2) + data.substr(82, 2);
        decoded.electricityMeterEnergyNt = parseInt(volume,
            16) * scale;
    }
    if (medium == "03") {
        var volume = data.substr(66, 2) + data.substr(64,
            2) + data.substr(62, 2) + data.substr(60, 2);
        decoded.gasMeterVolume = parseInt(volume) * scale;
    }
    if (medium == "16") {
        var volume = data.substr(54, 2) + data.substr(52,
            2) + data.substr(50, 2) + data.substr(48, 2);
        decoded.waterMeter = parseInt(volume, 16) * scale;
    }
    /* PA
        if (medium == "07") {
            var volume = data.substr(54, 2) + data.substr(52,
                2) + data.substr(50, 2) + data.substr(48, 2);
            decoded.waterMeter = parseInt(volume, 16) * scale;
        }
        */
    if (medium == "07") {
        var volume = data.substr(66, 2) + data.substr(64,
            2) + data.substr(62, 2) + data.substr(60, 2);
        var gwf_scale = 1;
        switch (data.substr(58, 2)) {
            case "13":
                gwf_scale = 0.001;
                break;
            case "14":
                gwf_scale = 0.01;
                break;
            case "15":
                gwf_scale = 0.1;
                break;
            case "16":
                gwf_scale = 1;
                break;
            case "17":
                gwf_scale = 10;
                break;
            default:
                break;
        }

        decoded.waterMeter = volume * gwf_scale;
    }

    if (medium == "04") {
        var volume = data.substr(54, 2) + data.substr(52,
            2) + data.substr(50, 2) + data.substr(48, 2);
        decoded.waterMeter = parseInt(volume, 16) * scale;
    }

    return decoded;
}

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

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;
}

ThingsBoard Converter Export

{
    "cmd": "gw",
    "seqno": 114935,
    "EUI": "10CE45FFFE00AAAD",
    "ts": 1660726181716,
    "fcnt": 4198,
    "port": 2,
    "freq": 867300000,
    "toa": 97,
    "dr": "SF7 BW125 4/5",
    "ack": false,
    "gws": [{
        "rssi": -41,
        "snr": 9.8,
        "ts": 1660726181716,
        "time": "2022-08-17T08:49:41.585149Z",
        "gweui": "9C65F9FFFF386C4F",
        "ant": 0,
        "lat": 46.8076885,
        "lon": 7.100528
    }],
    "bat": 0,
    "data": "230400681b1b6808007200375316e61e3c07040000000c78003753160c13580319173316",
    "_id": "62fcaba53184c84733df3296"
}

Last updated