# Adeunis TIC

## Linky Monophasé

{% hint style="info" %}
Il faut au préalable configurer le Adeunis TIC avec le profil de configuration adapté au Linky Monophasé : <https://www.adeunis.com/wp-content/uploads/2019/09/TIC_LoRa_appl_CbeLinkyMono.config.zip>
{% endhint %}

### Codec

{% code title="adeunis-tic\_cbe\_linky\_mono.codec.js" lineNumbers="true" expandable="true" %}

```js
"use strict";
Object.prototype.readInt8 = function (offset) {
    var buffer = this;
    var a = buffer[offset];
    if ((a & 0x80) > 0) {
        return a - 0x100;
    }
    return a;
};
Object.prototype.readUInt8 = function (offset) {
    var buffer = this;
    return buffer[offset];
};
Object.prototype.readInt16BE = function (offset) {
    var buffer = this;
    var a = (buffer[offset] << 8) | buffer[offset + 1];
    if ((a & 0x8000) > 0) {
        return a - 0x10000;
    }
    return a;
};
Object.prototype.readUInt16BE = function (offset) {
    var buffer = this;
    return (buffer[offset] << 8) | buffer[offset + 1];
};
Object.prototype.readInt32BE = function (offset) {
    var buffer = this;
    return (buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3];
};
Object.prototype.readUInt32BE = function (offset) {
    var buffer = this;
    return ((buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3]) >>> 0;
};
Object.prototype.readFloatBE = function (offset) {
    var buffer = this;
    var value = ((buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3]) >>> 0;
    return new Float32Array(new Uint32Array([value]).buffer)[0];
};
if (typeof module !== 'undefined') {
    module.exports = codec;
}
if (typeof process !== 'undefined' && process.env['NODE_ENV'] === 'test') {
    global.codec = codec;
}
var codec;
(function (codec) {
    var PartialDecodingReason;
    (function (PartialDecodingReason) {
        PartialDecodingReason[PartialDecodingReason["NONE"] = 0] = "NONE";
        PartialDecodingReason[PartialDecodingReason["MISSING_NETWORK"] = 1] = "MISSING_NETWORK";
        PartialDecodingReason[PartialDecodingReason["MISSING_CONFIGURATION"] = 2] = "MISSING_CONFIGURATION";
    })(PartialDecodingReason = codec.PartialDecodingReason || (codec.PartialDecodingReason = {}));
})(codec || (codec = {}));
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
var codec;
(function (codec) {
    var ContentImpl = (function () {
        function ContentImpl(type) {
            if (type === void 0) { type = 'Unknown'; }
            this.type = type;
            this.partialDecoding = codec.PartialDecodingReason.NONE;
        }
        ContentImpl.merge = function () {
            var contents = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                contents[_i] = arguments[_i];
            }
            if (!contents || contents.length === 0) {
                return null;
            }
            return Object.assign.apply(Object, __spreadArray([new ContentImpl(contents[0].type)], contents, false));
        };
        ContentImpl.prototype.merge = function () {
            var contents = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                contents[_i] = arguments[_i];
            }
            return ContentImpl.merge.apply(ContentImpl, __spreadArray([this], contents, false));
        };
        return ContentImpl;
    }());
    codec.ContentImpl = ContentImpl;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var PlateformCommonUtils = (function () {
        function PlateformCommonUtils() {
        }
        PlateformCommonUtils.getProductModeText = function (value) {
            switch (value) {
                case 0:
                    return 'PARK';
                case 1:
                    return 'PRODUCTION';
                case 2:
                    return 'TEST';
                case 3:
                    return 'DEAD';
                default:
                    return '';
            }
        };
        return PlateformCommonUtils;
    }());
    codec.PlateformCommonUtils = PlateformCommonUtils;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var GenericStatusByteParser = (function () {
        function GenericStatusByteParser() {
            this.deviceType = 'any';
            this.frameCode = 0;
        }
        GenericStatusByteParser.prototype.parseFrame = function (payload, configuration) {
            var statusContent = {};
            statusContent['frameCounter'] = (payload[1] & 0xe0) >> 5;
            statusContent['hardwareError'] = false;
            statusContent['lowBattery'] = Boolean(payload[1] & 0x02);
            statusContent['configurationDone'] = Boolean(payload[1] & 0x01);
            return statusContent;
        };
        return GenericStatusByteParser;
    }());
    codec.GenericStatusByteParser = GenericStatusByteParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Generic0x20Parser = (function (frame = '0x20 Configuration') {
        function Generic0x20Parser() {
            this.deviceType = 'any';
            this.frameCode = 0x20;
        }
        Generic0x20Parser.prototype.parseFrame = function (payload, configuration, network, deviceType) {
            var appContent = { type: frame };
            switch (payload.length) {
                case 4:
                    appContent['loraAdr'] = Boolean(payload[2] & 0x01);
                    appContent['loraProvisioningMode'] = payload[3] === 0 ? 'ABP' : 'OTAA';
                    if (deviceType !== 'analog' && deviceType !== 'drycontacts' && deviceType !== 'pulse' && deviceType !== 'temp') {
                        appContent['loraDutycyle'] = payload[2] & 0x04 ? 'activated' : 'deactivated';
                        appContent['loraClassMode'] = payload[2] & 0x20 ? 'CLASS C' : 'CLASS A';
                    }
                    break;
                case 3:
                case 5:
                    appContent['sigfoxRetry'] = payload[2] & 0x03;
                    if (payload.length === 5) {
                        appContent['sigfoxDownlinkPeriod'] = { unit: 'm', value: payload.readInt16BE(3) };
                    }
                    break;
                default:
                    appContent.partialDecoding = codec.PartialDecodingReason.MISSING_NETWORK;
                    break;
            }
            return appContent;
        };
        return Generic0x20Parser;
    }());
    codec.Generic0x20Parser = Generic0x20Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Generic0x30Parser = (function () {
        function Generic0x30Parser() {
            this.deviceType = 'any';
            this.frameCode = 0x30;
        }
        Generic0x30Parser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x30 Keep alive' };
            return appContent;
        };
        return Generic0x30Parser;
    }());
    codec.Generic0x30Parser = Generic0x30Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x10Parser = (function () {
        function Tic0x10Parser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x10;
        }
        Tic0x10Parser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x10 TIC configuration' };
            if (payload[5] === 2) {
                appContent['transmissionPeriodKeepAlive'] = { unit: 's', value: payload[2] * 20 };
                appContent['samplingPeriod'] = { unit: 's', value: payload.readUInt16BE(6) * 20 };
            }
            else {
                appContent['transmissionPeriodKeepAlive'] = { unit: 'm', value: payload[2] * 10 };
                appContent['samplingPeriod'] = { unit: 'm', value: payload.readUInt16BE(6) };
            }
            appContent['transmissionPeriodData'] = payload.readUInt16BE(3);
            appContent['productMode'] = codec.PlateformCommonUtils.getProductModeText(payload[5]);
            return appContent;
        };
        return Tic0x10Parser;
    }());
    codec.Tic0x10Parser = Tic0x10Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x49Parser = (function () {
        function Tic0x49Parser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x49;
        }
        Tic0x49Parser.prototype.parseFrame = function (payload, configuration, network, deviceType) {
            var appContent = { type: '0x49 TIC data' };
            if (deviceType === 'ticCbeLinkyMono') {
                appContent = this.payloadToString(payload, 2, 2 + 12, appContent, 'ADCO');
                appContent = this.payloadToString(payload, 14, 14 + 4, appContent, 'OPTARIF');
                appContent = this.payloadToValue(payload, 18, 'Wh', appContent, 'BASE');
                appContent = this.payloadToValue(payload, 22, 'A', appContent, 'ISOUSC');
                appContent = this.payloadToValue(payload, 26, 'A', appContent, 'IINST');
                appContent = this.payloadToValue(payload, 30, 'A', appContent, 'IMAX');
                appContent = this.payloadToValue(payload, 34, 'VA', appContent, 'PAPP');
                appContent = this.payloadToValue(payload, 38, 'Wh', appContent, 'HCHC');
                appContent = this.payloadToValue(payload, 42, 'Wh', appContent, 'HCHP');
                appContent = this.payloadToString(payload, 46, 46 + 4, appContent, 'PTEC');
            }
            else if (deviceType === 'ticCbeLinkyTri') {
                appContent = this.payloadToString(payload, 2, 2 + 12, appContent, 'ADCO');
                appContent = this.payloadToValue(payload, 14, 'Wh', appContent, 'BASE');
                appContent = this.payloadToValue(payload, 18, 'A', appContent, 'IINST1');
                appContent = this.payloadToValue(payload, 22, 'A', appContent, 'IINST2');
                appContent = this.payloadToValue(payload, 26, 'A', appContent, 'IINST3');
                appContent = this.payloadToValue(payload, 30, 'A', appContent, 'IMAX1');
                appContent = this.payloadToValue(payload, 34, 'A', appContent, 'IMAX2');
                appContent = this.payloadToValue(payload, 38, 'A', appContent, 'IMAX3');
                appContent = this.payloadToValue(payload, 42, 'W', appContent, 'PMAX');
                appContent = this.payloadToValue(payload, 46, 'VA', appContent, 'PAPP');
            }
            else if (deviceType === 'ticPmePmi') {
                appContent = this.payloadToDate(payload, 2, deviceType, appContent, 'DATE');
                appContent = this.payloadToValue(payload, 8, 'Wh', appContent, 'EA_s');
                appContent = this.payloadToValue(payload, 12, 'varh', appContent, 'ER+_s');
                appContent = this.payloadToValue(payload, 16, 'varh', appContent, 'ER-_s');
                appContent = this.payloadToValue(payload, 20, 'VAh', appContent, 'EAPP_s');
                appContent = this.payloadToString(payload, 24, 24 + 3, appContent, 'PTCOUR1');
                appContent = this.payloadToValue(payload, 27, 'kWh', appContent, 'EAP_s');
                appContent = this.payloadToValue(payload, 31, 'kvarh', appContent, 'ER+P_s');
                appContent = this.payloadToValue(payload, 35, 'kvarh', appContent, 'ER-P_s');
                appContent = this.payloadToValue(payload, 39, 'kWh', appContent, 'EaP0_s');
                appContent = this.payloadToValue(payload, 43, 'kvarh', appContent, 'ER+P0_s');
                appContent = this.payloadToValue(payload, 47, 'kvarh', appContent, 'ER-P0_s');
            }
            return appContent;
        };
        Tic0x49Parser.prototype.payloadToString = function (payload, start, end, appContent, label) {
            var charCode = [];
            for (var i = start; i < end; i++) {
                if (payload[i] !== 0x00) {
                    charCode.push(payload[i]);
                }
            }
            var str = String.fromCharCode.apply(String, charCode);
            if (str.length > 0) {
                appContent["".concat(label)] = str;
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        Tic0x49Parser.prototype.payloadToValue = function (payload, start, unit, appContent, label) {
            var val = payload.readUInt32BE(start);
            if (val !== 0x80000000) {
                appContent["".concat(label)] = { unit: unit, value: val };
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        Tic0x49Parser.prototype.p2d = function (val) {
            return ('0' + val).slice(-2);
        };
        Tic0x49Parser.prototype.payloadToDate = function (payload, start, deviceType, appContent, label) {
            var str = '2000-01-01T00:00:00';
            if (deviceType === 'ticPmePmi') {
                str =
                    2000 +
                    payload[start + 2] +
                    '-' +
                    this.p2d(payload[start + 1]) +
                    '-' +
                    this.p2d(payload[start + 0]) +
                    'T' +
                    this.p2d(payload[start + 3]) +
                    ':' +
                    this.p2d(payload[start + 4]) +
                    ':' +
                    this.p2d(payload[start + 5]);
            }
            if (str !== '2000-01-01T00:00:00') {
                appContent["".concat(label)] = str;
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        return Tic0x49Parser;
    }());
    codec.Tic0x49Parser = Tic0x49Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x4aParser = (function () {
        function Tic0x4aParser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x4a;
        }
        Tic0x4aParser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x4a TIC alarm' };
            appContent['label'] = this.payloadToString(payload, 2, 12);
            appContent['alarmType'] = this.getAlarmTypeText(payload[12]);
            appContent['value'] = this.payloadToString(payload, 13, payload.length);
            return appContent;
        };
        Tic0x4aParser.prototype.getAlarmTypeText = function (value) {
            switch (value) {
                case 0:
                    return 'manualTrigger';
                case 1:
                    return 'labelAppearance';
                case 2:
                    return 'labelDisappearance';
                case 3:
                    return 'highTreshold';
                case 4:
                    return 'lowTreshold';
                case 5:
                    return 'endThresholdAlarm';
                case 6:
                    return 'deltaPositive';
                case 7:
                    return 'deltaNegative';
                default:
                    return '';
            }
        };
        Tic0x4aParser.prototype.payloadToString = function (payload, start, end) {
            var charCode = [];
            for (var i = start; i < end; i++) {
                if (payload[i] !== 0x00) {
                    charCode.push(payload[i]);
                }
            }
            var str = String.fromCharCode.apply(String, charCode);
            return str.length > 0 ? str : 'notFound';
        };
        return Tic0x4aParser;
    }());
    codec.Tic0x4aParser = Tic0x4aParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var TicStatusByteParser = (function () {
        function TicStatusByteParser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0;
        }
        TicStatusByteParser.prototype.parseFrame = function (payload, configuration, network) {
            var parser = new codec.GenericStatusByteParser();
            var statusContent = parser.parseFrame(payload, configuration);
            statusContent['configurationInconsistency'] = Boolean(payload[1] & 0x08);
            statusContent['readError'] = Boolean(payload[1] & 0x10);
            return { status: statusContent };
        };
        return TicStatusByteParser;
    }());
    codec.TicStatusByteParser = TicStatusByteParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var CommonDecoder = (function () {
        function CommonDecoder() {
        }
        CommonDecoder.prototype.decode = function (payload) {
            var _this = this;
            var frameCode = payload[0];
            var configuration;
            if (frameCode === 0x10) {
                configuration = payload;
            }
            var activeParsers = this.getActiveParsers(frameCode);
            var partialContents = activeParsers.map(function (p) {
                var partialContent;
                try {
                    partialContent = p.parseFrame(payload, configuration, 'unknown', _this.deviceType);
                }
                catch (error) {
                    partialContent = { error: error.toString() };
                }
                return partialContent;
            });
            if (activeParsers.every(function (p) { return p.frameCode < 0; })) {
                partialContents.push({ type: 'Unsupported' });
            }
            var content = Object.assign.apply(Object, __spreadArray([{}], partialContents, false));
            var typestr = content['type'];
            delete content['type'];
            content = Object.assign({ type: typestr }, content);
            return content;
        };
        CommonDecoder.prototype.getActiveParsers = function (frameCode) {
            var activeParsers = [];
            return activeParsers;
        };
        return CommonDecoder;
    }());
    codec.CommonDecoder = CommonDecoder;
})(codec || (codec = {}));
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var codec;
(function (codec) {
    var Decoder = (function (_super) {
        __extends(Decoder, _super);
        function Decoder() {
            var _this = _super.call(this) || this;
            _this.deviceType = 'ticCbeLinkyMono';
            return _this;
        }
        Decoder.prototype.getActiveParsers = function (frameCode) {
            var activeParsers = [];
            var statusByteParsers = new codec.TicStatusByteParser();
            var dataParser;
            switch (frameCode) {
                case 0x10:
                    dataParser = new codec.Tic0x10Parser();
                    break;
                case 0x49:
                    dataParser = new codec.Tic0x49Parser();
                    break;
                case 0x4a:
                    dataParser = new codec.Tic0x4aParser();
                    break;
                case 0x20:
                    dataParser = new codec.Generic0x20Parser();
                    break;
                case 0x30:
                    dataParser = new codec.Generic0x20Parser('0x30 Keep alive');
                    break;
                default:
                    return activeParsers;
            }
            activeParsers = activeParsers.concat(statusByteParsers);
            activeParsers = activeParsers.concat(dataParser);
            return activeParsers;
        };
        return Decoder;
    }(codec.CommonDecoder));
    codec.Decoder = Decoder;
})(codec || (codec = {}));

function decodeUplink(input) {
    const decoder = new codec.Decoder();
    const payload = decoder.decode(input.bytes);
    const data = {};

    if (payload.status !== undefined) {
        const status = payload.status;

        if (status.frameCounter !== undefined) {
            data.frameCounter = status.frameCounter;
        }
        const booleanFields = ['lowBattery', 'hardwareError', 'readError'];
        
        booleanFields.forEach(field => {
            if (status[field] !== undefined) {
                data[field] = status[field] ? 1 : 0;
            }
        });
    }

    const metrics = ['HCHC', 'HCHP', 'PAPP', 'IMAX', 'IINST', 'ISOUSC', 'BASE'];

    metrics.forEach(metric => {
        if (payload[`${metric}status`] !== undefined) {
            data[metric] = 0;
        } 
        // Sinon, on récupère la valeur si elle existe
        else if (payload[metric] !== undefined) {
            data[metric] = payload[metric].value;
        }
    });

    return { data };
}
```

{% endcode %}

### Mapping

{% code title="adeunis-tic\_cbe\_linky\_mono.mapping.json" lineNumbers="true" expandable="true" %}

```json
{
  "uplink": {
    "fields": [
      {
        "name": "frameCounter",
        "description": "Frame counter, from 0 to 7 (ex : ..., 6, 7, 0, 1, ...",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": {
            "register_type": "input",
            "factor": 1
          }
        }
      },
      {
        "name": "lowBattery",
        "description": "Low battery (0: battery ok, 1: battery low)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "hardwareError",
        "description": "Hardware error (0: no error, 1: error)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "readError",
        "description": "Read TIC error (0: no error, 1: error)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "BASE",
        "description": "Index base",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "Wh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "ISOUSC",
        "description": "Intensité souscrite",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "A",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "IINST",
        "description": "Intensité instantanée",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "A",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "IMAX",
        "description": "Intensité Maximale appelée",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "A",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "PAPP",
        "description": "Puissante apparente",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "VA",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "HCHC",
        "description": "Index Heures Creuses",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "Wh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "HCHP",
        "description": "Index Heures Pleines",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "Wh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      }
    ]
  },
  "lns_metadata":{
    "fields":[
      {
        "name":"rssi",
        "description":"Received RSSI",
        "data_type":"NUMBER",
        "numeric_type":"INT16",
        "access_mode":"R",
        "unit":"dBm",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":1,
            "factor":1
          }
        }
      },
      {
        "name":"snr",
        "description":"Received SNR",
        "data_type":"NUMBER",
        "numeric_type":"INT16",
        "access_mode":"R",
        "unit":"dB",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":2,
            "factor":1
          }
        }
      },
      {
        "name":"sf",
        "description":"Spreading Factor",
        "data_type":"NUMBER",
        "numeric_type":"UINT8",
        "access_mode":"R",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":3,
            "factor":1
          }
        }
      },
      {
        "name":"minutesSinceLastRx",
        "description":"Minutes since last reception",
        "data_type":"NUMBER",
        "numeric_type":"UINT16",
        "access_mode":"R",
        "unit":"min",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":4,
            "factor":1
          }
        }
      }
    ]
  }
}
```

{% endcode %}

## Linky Triphasé

{% hint style="info" %}
Il faut au préalable configurer le Adeunis TIC avec le profil de configuration adapté au Linky Triphasé : <https://www.adeunis.com/wp-content/uploads/2019/09/TIC_LoRa_appl_CbeLinkyTri.config.zip>
{% endhint %}

### Codec

{% code title="adeunis-tic\_cbe\_linky\_tri.codec.js" lineNumbers="true" expandable="true" %}

```js
"use strict";
Object.prototype.readInt8 = function (offset) {
    var buffer = this;
    var a = buffer[offset];
    if ((a & 0x80) > 0) {
        return a - 0x100;
    }
    return a;
};
Object.prototype.readUInt8 = function (offset) {
    var buffer = this;
    return buffer[offset];
};
Object.prototype.readInt16BE = function (offset) {
    var buffer = this;
    var a = (buffer[offset] << 8) | buffer[offset + 1];
    if ((a & 0x8000) > 0) {
        return a - 0x10000;
    }
    return a;
};
Object.prototype.readUInt16BE = function (offset) {
    var buffer = this;
    return (buffer[offset] << 8) | buffer[offset + 1];
};
Object.prototype.readInt32BE = function (offset) {
    var buffer = this;
    return (buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3];
};
Object.prototype.readUInt32BE = function (offset) {
    var buffer = this;
    return ((buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3]) >>> 0;
};
Object.prototype.readFloatBE = function (offset) {
    var buffer = this;
    var value = ((buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3]) >>> 0;
    return new Float32Array(new Uint32Array([value]).buffer)[0];
};
if (typeof module !== 'undefined') {
    module.exports = codec;
}
if (typeof process !== 'undefined' && process.env['NODE_ENV'] === 'test') {
    global.codec = codec;
}
var codec;
(function (codec) {
    var PartialDecodingReason;
    (function (PartialDecodingReason) {
        PartialDecodingReason[PartialDecodingReason["NONE"] = 0] = "NONE";
        PartialDecodingReason[PartialDecodingReason["MISSING_NETWORK"] = 1] = "MISSING_NETWORK";
        PartialDecodingReason[PartialDecodingReason["MISSING_CONFIGURATION"] = 2] = "MISSING_CONFIGURATION";
    })(PartialDecodingReason = codec.PartialDecodingReason || (codec.PartialDecodingReason = {}));
})(codec || (codec = {}));
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
var codec;
(function (codec) {
    var ContentImpl = (function () {
        function ContentImpl(type) {
            if (type === void 0) { type = 'Unknown'; }
            this.type = type;
            this.partialDecoding = codec.PartialDecodingReason.NONE;
        }
        ContentImpl.merge = function () {
            var contents = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                contents[_i] = arguments[_i];
            }
            if (!contents || contents.length === 0) {
                return null;
            }
            return Object.assign.apply(Object, __spreadArray([new ContentImpl(contents[0].type)], contents, false));
        };
        ContentImpl.prototype.merge = function () {
            var contents = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                contents[_i] = arguments[_i];
            }
            return ContentImpl.merge.apply(ContentImpl, __spreadArray([this], contents, false));
        };
        return ContentImpl;
    }());
    codec.ContentImpl = ContentImpl;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var PlateformCommonUtils = (function () {
        function PlateformCommonUtils() {
        }
        PlateformCommonUtils.getProductModeText = function (value) {
            switch (value) {
                case 0:
                    return 'PARK';
                case 1:
                    return 'PRODUCTION';
                case 2:
                    return 'TEST';
                case 3:
                    return 'DEAD';
                default:
                    return '';
            }
        };
        return PlateformCommonUtils;
    }());
    codec.PlateformCommonUtils = PlateformCommonUtils;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var GenericStatusByteParser = (function () {
        function GenericStatusByteParser() {
            this.deviceType = 'any';
            this.frameCode = 0;
        }
        GenericStatusByteParser.prototype.parseFrame = function (payload, configuration) {
            var statusContent = {};
            statusContent['frameCounter'] = (payload[1] & 0xe0) >> 5;
            statusContent['hardwareError'] = false;
            statusContent['lowBattery'] = Boolean(payload[1] & 0x02);
            statusContent['configurationDone'] = Boolean(payload[1] & 0x01);
            return statusContent;
        };
        return GenericStatusByteParser;
    }());
    codec.GenericStatusByteParser = GenericStatusByteParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Generic0x20Parser = (function () {
        function Generic0x20Parser() {
            this.deviceType = 'any';
            this.frameCode = 0x20;
        }
        Generic0x20Parser.prototype.parseFrame = function (payload, configuration, network, deviceType) {
            var appContent = { type: '0x20 Configuration' };
            switch (payload.length) {
                case 4:
                    appContent['loraAdr'] = Boolean(payload[2] & 0x01);
                    appContent['loraProvisioningMode'] = payload[3] === 0 ? 'ABP' : 'OTAA';
                    if (deviceType !== 'analog' && deviceType !== 'drycontacts' && deviceType !== 'pulse' && deviceType !== 'temp') {
                        appContent['loraDutycyle'] = payload[2] & 0x04 ? 'activated' : 'deactivated';
                        appContent['loraClassMode'] = payload[2] & 0x20 ? 'CLASS C' : 'CLASS A';
                    }
                    break;
                case 3:
                case 5:
                    appContent['sigfoxRetry'] = payload[2] & 0x03;
                    if (payload.length === 5) {
                        appContent['sigfoxDownlinkPeriod'] = { unit: 'm', value: payload.readInt16BE(3) };
                    }
                    break;
                default:
                    appContent.partialDecoding = codec.PartialDecodingReason.MISSING_NETWORK;
                    break;
            }
            return appContent;
        };
        return Generic0x20Parser;
    }());
    codec.Generic0x20Parser = Generic0x20Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Generic0x30Parser = (function () {
        function Generic0x30Parser() {
            this.deviceType = 'any';
            this.frameCode = 0x30;
        }
        Generic0x30Parser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x30 Keep alive' };
            return appContent;
        };
        return Generic0x30Parser;
    }());
    codec.Generic0x30Parser = Generic0x30Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x10Parser = (function () {
        function Tic0x10Parser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x10;
        }
        Tic0x10Parser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x10 TIC configuration' };
            if (payload[5] === 2) {
                appContent['transmissionPeriodKeepAlive'] = { unit: 's', value: payload[2] * 20 };
                appContent['samplingPeriod'] = { unit: 's', value: payload.readUInt16BE(6) * 20 };
            }
            else {
                appContent['transmissionPeriodKeepAlive'] = { unit: 'm', value: payload[2] * 10 };
                appContent['samplingPeriod'] = { unit: 'm', value: payload.readUInt16BE(6) };
            }
            appContent['transmissionPeriodData'] = payload.readUInt16BE(3);
            appContent['productMode'] = codec.PlateformCommonUtils.getProductModeText(payload[5]);
            return appContent;
        };
        return Tic0x10Parser;
    }());
    codec.Tic0x10Parser = Tic0x10Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x49Parser = (function () {
        function Tic0x49Parser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x49;
        }
        Tic0x49Parser.prototype.parseFrame = function (payload, configuration, network, deviceType) {
            var appContent = { type: '0x49 TIC data' };
            if (deviceType === 'ticCbeLinkyMono') {
                appContent = this.payloadToString(payload, 2, 2 + 12, appContent, 'ADCO');
                appContent = this.payloadToString(payload, 14, 14 + 4, appContent, 'OPTARIF');
                appContent = this.payloadToValue(payload, 18, 'Wh', appContent, 'BASE');
                appContent = this.payloadToValue(payload, 22, 'A', appContent, 'ISOUSC');
                appContent = this.payloadToValue(payload, 26, 'A', appContent, 'IINST');
                appContent = this.payloadToValue(payload, 30, 'A', appContent, 'IMAX');
                appContent = this.payloadToValue(payload, 34, 'VA', appContent, 'PAPP');
                appContent = this.payloadToValue(payload, 38, 'Wh', appContent, 'HCHC');
                appContent = this.payloadToValue(payload, 42, 'Wh', appContent, 'HCHP');
                appContent = this.payloadToString(payload, 46, 46 + 4, appContent, 'PTEC');
            }
            else if (deviceType === 'ticCbeLinkyTri') {
                appContent = this.payloadToString(payload, 2, 2 + 12, appContent, 'ADCO');
                appContent = this.payloadToValue(payload, 14, 'Wh', appContent, 'BASE');
                appContent = this.payloadToValue(payload, 18, 'A', appContent, 'IINST1');
                appContent = this.payloadToValue(payload, 22, 'A', appContent, 'IINST2');
                appContent = this.payloadToValue(payload, 26, 'A', appContent, 'IINST3');
                appContent = this.payloadToValue(payload, 30, 'A', appContent, 'IMAX1');
                appContent = this.payloadToValue(payload, 34, 'A', appContent, 'IMAX2');
                appContent = this.payloadToValue(payload, 38, 'A', appContent, 'IMAX3');
                appContent = this.payloadToValue(payload, 42, 'W', appContent, 'PMAX');
                appContent = this.payloadToValue(payload, 46, 'VA', appContent, 'PAPP');
            }
            else if (deviceType === 'ticPmePmi') {
                appContent = this.payloadToDate(payload, 2, deviceType, appContent, 'DATE');
                appContent = this.payloadToValue(payload, 8, 'Wh', appContent, 'EA_s');
                appContent = this.payloadToValue(payload, 12, 'varh', appContent, 'ER+_s');
                appContent = this.payloadToValue(payload, 16, 'varh', appContent, 'ER-_s');
                appContent = this.payloadToValue(payload, 20, 'VAh', appContent, 'EAPP_s');
                appContent = this.payloadToString(payload, 24, 24 + 3, appContent, 'PTCOUR1');
                appContent = this.payloadToValue(payload, 27, 'kWh', appContent, 'EAP_s');
                appContent = this.payloadToValue(payload, 31, 'kvarh', appContent, 'ER+P_s');
                appContent = this.payloadToValue(payload, 35, 'kvarh', appContent, 'ER-P_s');
                appContent = this.payloadToValue(payload, 39, 'kWh', appContent, 'EaP-1_s');
                appContent = this.payloadToValue(payload, 43, 'kvarh', appContent, 'ER+P-1_s');
                appContent = this.payloadToValue(payload, 47, 'kvarh', appContent, 'ER-P-1_s');
            }
            return appContent;
        };
        Tic0x49Parser.prototype.payloadToString = function (payload, start, end, appContent, label) {
            var charCode = [];
            for (var i = start; i < end; i++) {
                if (payload[i] !== 0x00) {
                    charCode.push(payload[i]);
                }
            }
            var str = String.fromCharCode.apply(String, charCode);
            if (str.length > 0) {
                appContent["".concat(label)] = str;
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        Tic0x49Parser.prototype.payloadToValue = function (payload, start, unit, appContent, label) {
            var val = payload.readUInt32BE(start);
            if (val !== 0x80000000) {
                appContent["".concat(label)] = { unit: unit, value: val };
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        Tic0x49Parser.prototype.p2d = function (val) {
            return ('0' + val).slice(-2);
        };
        Tic0x49Parser.prototype.payloadToDate = function (payload, start, deviceType, appContent, label) {
            var str = '2000-01-01T00:00:00';
            if (deviceType === 'ticPmePmi') {
                str =
                    2000 +
                        payload[start + 2] +
                        '-' +
                        this.p2d(payload[start + 1]) +
                        '-' +
                        this.p2d(payload[start + 0]) +
                        'T' +
                        this.p2d(payload[start + 3]) +
                        ':' +
                        this.p2d(payload[start + 4]) +
                        ':' +
                        this.p2d(payload[start + 5]);
            }
            if (str !== '2000-01-01T00:00:00') {
                appContent["".concat(label)] = str;
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        return Tic0x49Parser;
    }());
    codec.Tic0x49Parser = Tic0x49Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x4aParser = (function () {
        function Tic0x4aParser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x4a;
        }
        Tic0x4aParser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x4a TIC alarm' };
            appContent['label'] = this.payloadToString(payload, 2, 12);
            appContent['alarmType'] = this.getAlarmTypeText(payload[12]);
            appContent['value'] = this.payloadToString(payload, 13, payload.length);
            return appContent;
        };
        Tic0x4aParser.prototype.getAlarmTypeText = function (value) {
            switch (value) {
                case 0:
                    return 'manualTrigger';
                case 1:
                    return 'labelAppearance';
                case 2:
                    return 'labelDisappearance';
                case 3:
                    return 'highTreshold';
                case 4:
                    return 'lowTreshold';
                case 5:
                    return 'endThresholdAlarm';
                case 6:
                    return 'deltaPositive';
                case 7:
                    return 'deltaNegative';
                default:
                    return '';
            }
        };
        Tic0x4aParser.prototype.payloadToString = function (payload, start, end) {
            var charCode = [];
            for (var i = start; i < end; i++) {
                if (payload[i] !== 0x00) {
                    charCode.push(payload[i]);
                }
            }
            var str = String.fromCharCode.apply(String, charCode);
            return str.length > 0 ? str : 'notFound';
        };
        return Tic0x4aParser;
    }());
    codec.Tic0x4aParser = Tic0x4aParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var TicStatusByteParser = (function () {
        function TicStatusByteParser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0;
        }
        TicStatusByteParser.prototype.parseFrame = function (payload, configuration, network) {
            var parser = new codec.GenericStatusByteParser();
            var statusContent = parser.parseFrame(payload, configuration);
            statusContent['configurationInconsistency'] = Boolean(payload[1] & 0x08);
            statusContent['readError'] = Boolean(payload[1] & 0x10);
            return { status: statusContent };
        };
        return TicStatusByteParser;
    }());
    codec.TicStatusByteParser = TicStatusByteParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var CommonDecoder = (function () {
        function CommonDecoder() {
        }
        CommonDecoder.prototype.decode = function (payload) {
            var _this = this;
            var frameCode = payload[0];
            var configuration;
            if (frameCode === 0x10) {
                configuration = payload;
            }
            var activeParsers = this.getActiveParsers(frameCode);
            var partialContents = activeParsers.map(function (p) {
                var partialContent;
                try {
                    partialContent = p.parseFrame(payload, configuration, 'unknown', _this.deviceType);
                }
                catch (error) {
                    partialContent = { error: error.toString() };
                }
                return partialContent;
            });
            if (activeParsers.every(function (p) { return p.frameCode < 0; })) {
                partialContents.push({ type: 'Unsupported' });
            }
            var content = Object.assign.apply(Object, __spreadArray([{}], partialContents, false));
            var typestr = content['type'];
            delete content['type'];
            content = Object.assign({ type: typestr }, content);
            return content;
        };
        CommonDecoder.prototype.getActiveParsers = function (frameCode) {
            var activeParsers = [];
            return activeParsers;
        };
        return CommonDecoder;
    }());
    codec.CommonDecoder = CommonDecoder;
})(codec || (codec = {}));
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var codec;
(function (codec) {
    var Decoder = (function (_super) {
        __extends(Decoder, _super);
        function Decoder() {
            var _this = _super.call(this) || this;
            _this.deviceType = 'ticCbeLinkyTri';
            return _this;
        }
        Decoder.prototype.getActiveParsers = function (frameCode) {
            var activeParsers = [];
            var statusByteParsers = new codec.TicStatusByteParser();
            var dataParser;
            switch (frameCode) {
                case 0x10:
                    dataParser = new codec.Tic0x10Parser();
                    break;
                case 0x49:
                    dataParser = new codec.Tic0x49Parser();
                    break;
                case 0x4a:
                    dataParser = new codec.Tic0x4aParser();
                    break;
                case 0x20:
                    dataParser = new codec.Generic0x20Parser();
                    break;
                case 0x30:
                    dataParser = new codec.Generic0x20Parser();
                    break;
                default:
                    return activeParsers;
            }
            activeParsers = activeParsers.concat(statusByteParsers);
            activeParsers = activeParsers.concat(dataParser);
            return activeParsers;
        };
        return Decoder;
    }(codec.CommonDecoder));
    codec.Decoder = Decoder;
})(codec || (codec = {}));

function decodeUplink(input) {
    const decoder = new codec.Decoder();
    const payload = decoder.decode(input.bytes);
    const data = {};

    if (payload.status !== undefined) {
        const status = payload.status;

        if (status.frameCounter !== undefined) {
            data.frameCounter = status.frameCounter;
        }
        const booleanFields = ['lowBattery', 'hardwareError', 'readError'];
        
        booleanFields.forEach(field => {
            if (status[field] !== undefined) {
                data[field] = status[field] ? 1 : 0;
            }
        });
    }

    const metrics = ['BASE', 'IINST1', 'IINST2', 'IINST3', 'IMAX1', 'IMAX2', 'IMAX3', 'PMAX', 'PAPP'];

    metrics.forEach(metric => {
        if (payload[`${metric}status`] !== undefined) {
            data[metric] = 0;
        } 
        // Sinon, on récupère la valeur si elle existe
        else if (payload[metric] !== undefined) {
            data[metric] = payload[metric].value;
        }
    });

    return { data };
}
```

{% endcode %}

### Mapping

{% code title="adeunis-tic\_cbe\_linky\_tri.mapping.json" lineNumbers="true" expandable="true" %}

```json
{
  "uplink": {
    "fields": [
      {
        "name": "frameCounter",
        "description": "Frame counter, from 0 to 7 (ex : ..., 6, 7, 0, 1, ...",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "lowBattery",
        "description": "Low battery (0: battery ok, 1: battery low)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "hardwareError",
        "description": "Hardware error (0: no error, 1: error)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "readError",
        "description": "Read TIC error (0: no error, 1: error)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "BASE",
        "description": "Index option base",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "Wh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "IINST1",
        "description": "Intensité instantanée phase 1",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "A",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "IINST2",
        "description": "Intensité instantanée phase 2",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "A",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "IINST3",
        "description": "Intensité instantanée phase 3",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "A",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "IMAX1",
        "description": "Intensité Maximale appelée phase 1",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "A",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "IMAX2",
        "description": "Intensité Maximale appelée phase 2",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "Wh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "IMAX3",
        "description": "Intensité Maximale appelée phase 3",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "Wh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "PMAX",
        "description": "Puissance Maximale atteinte",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "W",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "PAPP",
        "description": "Puissante apparente",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "VA",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      }
    ]
  },
  "lns_metadata":{
    "fields":[
      {
        "name":"rssi",
        "description":"Received RSSI",
        "data_type":"NUMBER",
        "numeric_type":"INT16",
        "access_mode":"R",
        "unit":"dBm",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":1,
            "factor":1
          }
        }
      },
      {
        "name":"snr",
        "description":"Received SNR",
        "data_type":"NUMBER",
        "numeric_type":"INT16",
        "access_mode":"R",
        "unit":"dB",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":2,
            "factor":1
          }
        }
      },
      {
        "name":"sf",
        "description":"Spreading Factor",
        "data_type":"NUMBER",
        "numeric_type":"UINT8",
        "access_mode":"R",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":3,
            "factor":1
          }
        }
      },
      {
        "name":"minutesSinceLastRx",
        "description":"Minutes since last reception",
        "data_type":"NUMBER",
        "numeric_type":"UINT16",
        "access_mode":"R",
        "unit":"min",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":4,
            "factor":1
          }
        }
      }
    ]
  }
}
```

{% endcode %}

## Compteur PME-PMI

{% hint style="info" %}
Il faut au préalable configurer le Adeunis TIC avec le profil de configuration adapté au PME-PMI : <https://www.adeunis.com/wp-content/uploads/2019/09/TIC_LoRa_appl_PME_PMI_Adeunis.config.zip>
{% endhint %}

### Codec

{% code title="adeunis-tic\_pme\_pmi.codec.js" lineNumbers="true" expandable="true" %}

```js
"use strict";
Object.prototype.readInt8 = function (offset) {
    var buffer = this;
    var a = buffer[offset];
    if ((a & 0x80) > 0) {
        return a - 0x100;
    }
    return a;
};
Object.prototype.readUInt8 = function (offset) {
    var buffer = this;
    return buffer[offset];
};
Object.prototype.readInt16BE = function (offset) {
    var buffer = this;
    var a = (buffer[offset] << 8) | buffer[offset + 1];
    if ((a & 0x8000) > 0) {
        return a - 0x10000;
    }
    return a;
};
Object.prototype.readUInt16BE = function (offset) {
    var buffer = this;
    return (buffer[offset] << 8) | buffer[offset + 1];
};
Object.prototype.readInt32BE = function (offset) {
    var buffer = this;
    return (buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3];
};
Object.prototype.readUInt32BE = function (offset) {
    var buffer = this;
    return ((buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3]) >>> 0;
};
Object.prototype.readFloatBE = function (offset) {
    var buffer = this;
    var value = ((buffer[offset] << 24) | (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3]) >>> 0;
    return new Float32Array(new Uint32Array([value]).buffer)[0];
};
if (typeof module !== 'undefined') {
    module.exports = codec;
}
if (typeof process !== 'undefined' && process.env['NODE_ENV'] === 'test') {
    global.codec = codec;
}
var codec;
(function (codec) {
    var PartialDecodingReason;
    (function (PartialDecodingReason) {
        PartialDecodingReason[PartialDecodingReason["NONE"] = 0] = "NONE";
        PartialDecodingReason[PartialDecodingReason["MISSING_NETWORK"] = 1] = "MISSING_NETWORK";
        PartialDecodingReason[PartialDecodingReason["MISSING_CONFIGURATION"] = 2] = "MISSING_CONFIGURATION";
    })(PartialDecodingReason = codec.PartialDecodingReason || (codec.PartialDecodingReason = {}));
})(codec || (codec = {}));
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
var codec;
(function (codec) {
    var ContentImpl = (function () {
        function ContentImpl(type) {
            if (type === void 0) { type = 'Unknown'; }
            this.type = type;
            this.partialDecoding = codec.PartialDecodingReason.NONE;
        }
        ContentImpl.merge = function () {
            var contents = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                contents[_i] = arguments[_i];
            }
            if (!contents || contents.length === 0) {
                return null;
            }
            return Object.assign.apply(Object, __spreadArray([new ContentImpl(contents[0].type)], contents, false));
        };
        ContentImpl.prototype.merge = function () {
            var contents = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                contents[_i] = arguments[_i];
            }
            return ContentImpl.merge.apply(ContentImpl, __spreadArray([this], contents, false));
        };
        return ContentImpl;
    }());
    codec.ContentImpl = ContentImpl;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var PlateformCommonUtils = (function () {
        function PlateformCommonUtils() {
        }
        PlateformCommonUtils.getProductModeText = function (value) {
            switch (value) {
                case 0:
                    return 'PARK';
                case 1:
                    return 'PRODUCTION';
                case 2:
                    return 'TEST';
                case 3:
                    return 'DEAD';
                default:
                    return '';
            }
        };
        return PlateformCommonUtils;
    }());
    codec.PlateformCommonUtils = PlateformCommonUtils;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var GenericStatusByteParser = (function () {
        function GenericStatusByteParser() {
            this.deviceType = 'any';
            this.frameCode = 0;
        }
        GenericStatusByteParser.prototype.parseFrame = function (payload, configuration) {
            var statusContent = {};
            statusContent['frameCounter'] = (payload[1] & 0xe0) >> 5;
            statusContent['hardwareError'] = false;
            statusContent['lowBattery'] = Boolean(payload[1] & 0x02);
            statusContent['configurationDone'] = Boolean(payload[1] & 0x01);
            return statusContent;
        };
        return GenericStatusByteParser;
    }());
    codec.GenericStatusByteParser = GenericStatusByteParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Generic0x20Parser = (function () {
        function Generic0x20Parser() {
            this.deviceType = 'any';
            this.frameCode = 0x20;
        }
        Generic0x20Parser.prototype.parseFrame = function (payload, configuration, network, deviceType) {
            var appContent = { type: '0x20 Configuration' };
            switch (payload.length) {
                case 4:
                    appContent['loraAdr'] = Boolean(payload[2] & 0x01);
                    appContent['loraProvisioningMode'] = payload[3] === 0 ? 'ABP' : 'OTAA';
                    if (deviceType !== 'analog' && deviceType !== 'drycontacts' && deviceType !== 'pulse' && deviceType !== 'temp') {
                        appContent['loraDutycyle'] = payload[2] & 0x04 ? 'activated' : 'deactivated';
                        appContent['loraClassMode'] = payload[2] & 0x20 ? 'CLASS C' : 'CLASS A';
                    }
                    break;
                case 3:
                case 5:
                    appContent['sigfoxRetry'] = payload[2] & 0x03;
                    if (payload.length === 5) {
                        appContent['sigfoxDownlinkPeriod'] = { unit: 'm', value: payload.readInt16BE(3) };
                    }
                    break;
                default:
                    appContent.partialDecoding = codec.PartialDecodingReason.MISSING_NETWORK;
                    break;
            }
            return appContent;
        };
        return Generic0x20Parser;
    }());
    codec.Generic0x20Parser = Generic0x20Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Generic0x30Parser = (function () {
        function Generic0x30Parser() {
            this.deviceType = 'any';
            this.frameCode = 0x30;
        }
        Generic0x30Parser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x30 Keep alive' };
            return appContent;
        };
        return Generic0x30Parser;
    }());
    codec.Generic0x30Parser = Generic0x30Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x10Parser = (function () {
        function Tic0x10Parser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x10;
        }
        Tic0x10Parser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x10 TIC configuration' };
            if (payload[5] === 2) {
                appContent['transmissionPeriodKeepAlive'] = { unit: 's', value: payload[2] * 20 };
                appContent['samplingPeriod'] = { unit: 's', value: payload.readUInt16BE(6) * 20 };
            }
            else {
                appContent['transmissionPeriodKeepAlive'] = { unit: 'm', value: payload[2] * 10 };
                appContent['samplingPeriod'] = { unit: 'm', value: payload.readUInt16BE(6) };
            }
            appContent['transmissionPeriodData'] = payload.readUInt16BE(3);
            appContent['productMode'] = codec.PlateformCommonUtils.getProductModeText(payload[5]);
            return appContent;
        };
        return Tic0x10Parser;
    }());
    codec.Tic0x10Parser = Tic0x10Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x49Parser = (function () {
        function Tic0x49Parser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x49;
        }
        Tic0x49Parser.prototype.parseFrame = function (payload, configuration, network, deviceType) {
            var appContent = { type: '0x49 TIC data' };
            if (deviceType === 'ticCbeLinkyMono') {
                appContent = this.payloadToString(payload, 2, 2 + 12, appContent, 'ADCO');
                appContent = this.payloadToString(payload, 14, 14 + 4, appContent, 'OPTARIF');
                appContent = this.payloadToValue(payload, 18, 'Wh', appContent, 'BASE');
                appContent = this.payloadToValue(payload, 22, 'A', appContent, 'ISOUSC');
                appContent = this.payloadToValue(payload, 26, 'A', appContent, 'IINST');
                appContent = this.payloadToValue(payload, 30, 'A', appContent, 'IMAX');
                appContent = this.payloadToValue(payload, 34, 'VA', appContent, 'PAPP');
                appContent = this.payloadToValue(payload, 38, 'Wh', appContent, 'HCHC');
                appContent = this.payloadToValue(payload, 42, 'Wh', appContent, 'HCHP');
                appContent = this.payloadToString(payload, 46, 46 + 4, appContent, 'PTEC');
            }
            else if (deviceType === 'ticCbeLinkyTri') {
                appContent = this.payloadToString(payload, 2, 2 + 12, appContent, 'ADCO');
                appContent = this.payloadToValue(payload, 14, 'Wh', appContent, 'BASE');
                appContent = this.payloadToValue(payload, 18, 'A', appContent, 'IINST1');
                appContent = this.payloadToValue(payload, 22, 'A', appContent, 'IINST2');
                appContent = this.payloadToValue(payload, 26, 'A', appContent, 'IINST3');
                appContent = this.payloadToValue(payload, 30, 'A', appContent, 'IMAX1');
                appContent = this.payloadToValue(payload, 34, 'A', appContent, 'IMAX2');
                appContent = this.payloadToValue(payload, 38, 'A', appContent, 'IMAX3');
                appContent = this.payloadToValue(payload, 42, 'W', appContent, 'PMAX');
                appContent = this.payloadToValue(payload, 46, 'VA', appContent, 'PAPP');
            }
            else if (deviceType === 'ticPmePmi') {
                appContent = this.payloadToDate(payload, 2, deviceType, appContent, 'DATE');
                appContent = this.payloadToValue(payload, 8, 'Wh', appContent, 'EA_s');
                appContent = this.payloadToValue(payload, 12, 'varh', appContent, 'ER+_s');
                appContent = this.payloadToValue(payload, 16, 'varh', appContent, 'ER-_s');
                appContent = this.payloadToValue(payload, 20, 'VAh', appContent, 'EAPP_s');
                appContent = this.payloadToString(payload, 24, 24 + 3, appContent, 'PTCOUR1');
                appContent = this.payloadToValue(payload, 27, 'kWh', appContent, 'EAP_s');
                appContent = this.payloadToValue(payload, 31, 'kvarh', appContent, 'ER+P_s');
                appContent = this.payloadToValue(payload, 35, 'kvarh', appContent, 'ER-P_s');
                appContent = this.payloadToValue(payload, 39, 'kWh', appContent, 'EaP-1_s');
                appContent = this.payloadToValue(payload, 43, 'kvarh', appContent, 'ER+P-1_s');
                appContent = this.payloadToValue(payload, 47, 'kvarh', appContent, 'ER-P-1_s');
            }
            return appContent;
        };
        Tic0x49Parser.prototype.payloadToString = function (payload, start, end, appContent, label) {
            var charCode = [];
            for (var i = start; i < end; i++) {
                if (payload[i] !== 0x00) {
                    charCode.push(payload[i]);
                }
            }
            var str = String.fromCharCode.apply(String, charCode);
            if (str.length > 0) {
                appContent["".concat(label)] = str;
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        Tic0x49Parser.prototype.payloadToValue = function (payload, start, unit, appContent, label) {
            var val = payload.readUInt32BE(start);
            if (val !== 0x80000000) {
                appContent["".concat(label)] = { unit: unit, value: val };
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        Tic0x49Parser.prototype.p2d = function (val) {
            return ('0' + val).slice(-2);
        };
        Tic0x49Parser.prototype.payloadToDate = function (payload, start, deviceType, appContent, label) {
            var str = '2000-01-01T00:00:00';
            if (deviceType === 'ticPmePmi') {
                str =
                    2000 +
                        payload[start + 2] +
                        '-' +
                        this.p2d(payload[start + 1]) +
                        '-' +
                        this.p2d(payload[start + 0]) +
                        'T' +
                        this.p2d(payload[start + 3]) +
                        ':' +
                        this.p2d(payload[start + 4]) +
                        ':' +
                        this.p2d(payload[start + 5]);
            }
            if (str !== '2000-01-01T00:00:00') {
                appContent["".concat(label)] = str;
            }
            else {
                appContent["".concat(label, "status")] = 'notFound';
            }
            return appContent;
        };
        return Tic0x49Parser;
    }());
    codec.Tic0x49Parser = Tic0x49Parser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var Tic0x4aParser = (function () {
        function Tic0x4aParser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0x4a;
        }
        Tic0x4aParser.prototype.parseFrame = function (payload, configuration, network) {
            var appContent = { type: '0x4a TIC alarm' };
            appContent['label'] = this.payloadToString(payload, 2, 12);
            appContent['alarmType'] = this.getAlarmTypeText(payload[12]);
            appContent['value'] = this.payloadToString(payload, 13, payload.length);
            return appContent;
        };
        Tic0x4aParser.prototype.getAlarmTypeText = function (value) {
            switch (value) {
                case 0:
                    return 'manualTrigger';
                case 1:
                    return 'labelAppearance';
                case 2:
                    return 'labelDisappearance';
                case 3:
                    return 'highTreshold';
                case 4:
                    return 'lowTreshold';
                case 5:
                    return 'endThresholdAlarm';
                case 6:
                    return 'deltaPositive';
                case 7:
                    return 'deltaNegative';
                default:
                    return '';
            }
        };
        Tic0x4aParser.prototype.payloadToString = function (payload, start, end) {
            var charCode = [];
            for (var i = start; i < end; i++) {
                if (payload[i] !== 0x00) {
                    charCode.push(payload[i]);
                }
            }
            var str = String.fromCharCode.apply(String, charCode);
            return str.length > 0 ? str : 'notFound';
        };
        return Tic0x4aParser;
    }());
    codec.Tic0x4aParser = Tic0x4aParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var TicStatusByteParser = (function () {
        function TicStatusByteParser() {
            this.deviceType = 'ticPmePmi|ticCbeLinkyMono|ticCbeLinkyTri';
            this.frameCode = 0;
        }
        TicStatusByteParser.prototype.parseFrame = function (payload, configuration, network) {
            var parser = new codec.GenericStatusByteParser();
            var statusContent = parser.parseFrame(payload, configuration);
            statusContent['configurationInconsistency'] = Boolean(payload[1] & 0x08);
            statusContent['readError'] = Boolean(payload[1] & 0x10);
            return { status: statusContent };
        };
        return TicStatusByteParser;
    }());
    codec.TicStatusByteParser = TicStatusByteParser;
})(codec || (codec = {}));
var codec;
(function (codec) {
    var CommonDecoder = (function () {
        function CommonDecoder() {
        }
        CommonDecoder.prototype.decode = function (payload) {
            var _this = this;
            var frameCode = payload[0];
            var configuration;
            if (frameCode === 0x10) {
                configuration = payload;
            }
            var activeParsers = this.getActiveParsers(frameCode);
            var partialContents = activeParsers.map(function (p) {
                var partialContent;
                try {
                    partialContent = p.parseFrame(payload, configuration, 'unknown', _this.deviceType);
                }
                catch (error) {
                    partialContent = { error: error.toString() };
                }
                return partialContent;
            });
            if (activeParsers.every(function (p) { return p.frameCode < 0; })) {
                partialContents.push({ type: 'Unsupported' });
            }
            var content = Object.assign.apply(Object, __spreadArray([{}], partialContents, false));
            var typestr = content['type'];
            delete content['type'];
            content = Object.assign({ type: typestr }, content);
            return content;
        };
        CommonDecoder.prototype.getActiveParsers = function (frameCode) {
            var activeParsers = [];
            return activeParsers;
        };
        return CommonDecoder;
    }());
    codec.CommonDecoder = CommonDecoder;
})(codec || (codec = {}));
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var codec;
(function (codec) {
    var Decoder = (function (_super) {
        __extends(Decoder, _super);
        function Decoder() {
            var _this = _super.call(this) || this;
            _this.deviceType = 'ticPmePmi';
            return _this;
        }
        Decoder.prototype.getActiveParsers = function (frameCode) {
            var activeParsers = [];
            var statusByteParsers = new codec.TicStatusByteParser();
            var dataParser;
            switch (frameCode) {
                case 0x10:
                    dataParser = new codec.Tic0x10Parser();
                    break;
                case 0x49:
                    dataParser = new codec.Tic0x49Parser();
                    break;
                case 0x4a:
                    dataParser = new codec.Tic0x4aParser();
                    break;
                case 0x20:
                    dataParser = new codec.Generic0x20Parser();
                    break;
                case 0x30:
                    dataParser = new codec.Generic0x20Parser();
                    break;
                default:
                    return activeParsers;
            }
            activeParsers = activeParsers.concat(statusByteParsers);
            activeParsers = activeParsers.concat(dataParser);
            return activeParsers;
        };
        return Decoder;
    }(codec.CommonDecoder));
    codec.Decoder = Decoder;
})(codec || (codec = {}));

function decodeUplink(input) {
    const decoder = new codec.Decoder();
    const payload = decoder.decode(input.bytes);
    const data = {};

    if (payload.status !== undefined) {
        const status = payload.status;

        if (status.frameCounter !== undefined) {
            data.frameCounter = status.frameCounter;
        }
        const booleanFields = ['lowBattery', 'hardwareError', 'readError'];
        
        booleanFields.forEach(field => {
            if (status[field] !== undefined) {
                data[field] = status[field] ? 1 : 0;
            }
        });
    }

    const metrics = ["EA_s", "ER+_s", "ER-_s", "EAPP_s", "EAP_s", "EAP_s", "EAP_s", "ER+P_s", "ER-P_s", "EaP-1_s", "ER+P-1_s", "ER-P-1_s"];

    metrics.forEach(metric => {
        if (payload[`${metric}status`] !== undefined) {
            data[metric] = 0;
        } 
        // Sinon, on récupère la valeur si elle existe
        else if (payload[metric] !== undefined) {
            data[metric] = payload[metric].value;
        }
    });

    return { data };
}
```

{% endcode %}

### Mapping

{% code title="adeunis-tic\_pme\_pmi.mapping.json" lineNumbers="true" expandable="true" %}

```json
{
  "uplink": {
    "fields": [
      {
        "name": "frameCounter",
        "description": "Frame counter, from 0 to 7 (ex : ..., 6, 7, 0, 1, ...",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "lowBattery",
        "description": "Low battery (0: battery ok, 1: battery low)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "hardwareError",
        "description": "Hardware error (0: no error, 1: error)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "readError",
        "description": "Read TIC error (0: no error, 1: error)",
        "data_type": "NUMBER",
        "numeric_type": "UINT8",
        "access_mode": "R",
        "unit": "",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "EA_s",
        "description": "Énergie Active soutirée",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "Wh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "ER+_s",
        "description": "Énergie Réactive fournie",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "varh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "ER-_s",
        "description": "Énergie Réactive absorbée",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "varh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "EAPP_s",
        "description": "Énergie Active Produite (période en cours)",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "VAh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "EAP_s",
        "description": "Énergie Active soutirée (période en cours)",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "kWh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "ER+P_s",
        "description": "Énergie Réactive fournie (période en cours)",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "kvarh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "ER-P_s",
        "description": "Énergie Réactive absorbée (période en cours)",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "kvarh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "EaP-1_s",
        "description": "Énergie Active soutirée (période précédente)",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "kWh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "ER+P-1_s",
        "description": "Énergie réactive fournie (période précédente)",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "kvarh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      },
      {
        "name": "ER-P-1_s",
        "description": "Énergie Réactive absorbée (période précédente)",
        "data_type": "NUMBER",
        "numeric_type": "INT32",
        "access_mode": "R",
        "unit": "kvarh",
        "protocol_specific": {
          "modbus": { "register_type": "input", "factor": 1 }
        }
      }
    ]
  },
  "lns_metadata":{
    "fields":[
      {
        "name":"rssi",
        "description":"Received RSSI",
        "data_type":"NUMBER",
        "numeric_type":"INT16",
        "access_mode":"R",
        "unit":"dBm",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":1,
            "factor":1
          }
        }
      },
      {
        "name":"snr",
        "description":"Received SNR",
        "data_type":"NUMBER",
        "numeric_type":"INT16",
        "access_mode":"R",
        "unit":"dB",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":2,
            "factor":1
          }
        }
      },
      {
        "name":"sf",
        "description":"Spreading Factor",
        "data_type":"NUMBER",
        "numeric_type":"UINT8",
        "access_mode":"R",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":3,
            "factor":1
          }
        }
      },
      {
        "name":"minutesSinceLastRx",
        "description":"Minutes since last reception",
        "data_type":"NUMBER",
        "numeric_type":"UINT16",
        "access_mode":"R",
        "unit":"min",
        "protocol_specific":{
          "modbus":{
            "register_type":"input",
            "offset":4,
            "factor":1
          }
        }
      }
    ]
  }
}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://enless.gitbook.io/centre-aide/ressources/gateway-lorawan/decodeurs-capteurs-tiers/adeunis-tic.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
