Skip to content

Plugin file

Plugin configuration file
{
    "name": "abeeway-geolocation-module",
    "version": "1.0.0",
    "description": "The Abeeway Geolocation module for outdoor geolocation contains a high-performance multi-constellation GNSS receiver and supports a patented ultra Low-Power GPS mode.",
    "author": "Thinger.io",
    "license": "MIT",
    "repository": {
        "type": "git",
        "url": "https://github.com/thinger-io/plugins.git",
        "directory": "abeeway-geolocation-module"
    },
    "metadata": {
        "name": "ABEEWAY-GEOLOCATION-MODULE",
        "description": "The Abeeway Geolocation module for outdoor geolocation contains a high-performance multi-constellation GNSS receiver and supports a patented ultra Low-Power GPS mode.",
        "image": "assets/abeeway-geolocation-module.png",
        "category": "devices",
        "vendor": "abeeway"
    },
    "resources": {
        "products": [
            {
                "config": {
                    "icons": []
                },
                "description": "The Abeeway Geolocation module for outdoor geolocation contains a high-performance multi-constellation GNSS receiver and supports a patented ultra Low-Power GPS mode.",
                "enabled": true,
                "name": "ABEEWAY-GEOLOCATION-MODULE",
                "product": "abeeway_geolocation_module",
                "profile": {
                    "api": {
                        "downlink": {
                            "enabled": true,
                            "handle_connectivity": false,
                            "request": {
                                "data": {
                                    "path": "/downlink",
                                    "payload": "{\n    \"data\"    : \"{{payload.data=\"\"}}\",\n    \"port\"    :  {{payload.port=85}},\n    \"priority\":  {{payload.priority=3}},\n    \"confirmed\" :  {{payload.confirmed=false}},\n    \"uplink\"  :  {{property.uplink}} \n}",
                                    "payload_function": "",
                                    "payload_type": "",
                                    "plugin": "{{property.uplink.source}}",
                                    "target": "plugin_endpoint"
                                }
                            }
                        },
                        "uplink": {
                            "device_id_resolver": "getId",
                            "enabled": true,
                            "handle_connectivity": true,
                            "request": {
                                "data": {
                                    "payload": "{{payload}}",
                                    "payload_function": "",
                                    "payload_type": "source_payload",
                                    "resource_stream": "uplink",
                                    "target": "resource_stream"
                                }
                            }
                        }
                    },
                    "autoprovisions": {
                        "abeeway_device_autoprovisioning": {
                            "config": {
                                "mode": "pattern",
                                "pattern": "abeeway-.*"
                            },
                            "enabled": true
                        }
                    },
                    "buckets": {
                        "abeeway_geolocation_module_data": {
                            "backend": "mongodb",
                            "data": {
                                "payload": "{{payload}}",
                                "payload_function": "decodeThingerUplink",
                                "payload_type": "source_payload",
                                "resource": "uplink",
                                "source": "resource",
                                "update": "events"
                            },
                            "enabled": true,
                            "retention": {
                                "period": 3,
                                "unit": "months"
                            },
                            "tags": []
                        }
                    },
                    "code": {
                        "code": "function decodeThingerUplink(thingerData) {\r\n    // 0. If data has already been decoded, we will return it\r\n    if (thingerData.decodedPayload) return thingerData.decodedPayload;\r\n    \r\n    // 1. Extract and Validate Input\r\n    // We need 'payload' (hex string) and 'fPort' (integer)\r\n    const hexPayload = thingerData.payload || \"\";\r\n    const port = thingerData.fPort || 1;\r\n\r\n    // 2. Convert Hex String to Byte Array\r\n    const bytes = [];\r\n    for (let i = 0; i < hexPayload.length; i += 2) {\r\n        bytes.push(parseInt(hexPayload.substr(i, 2), 16));\r\n    }\r\n\r\n    // 3. Dynamic Function Detection and Execution\r\n    \r\n    // CASE A: (The Things Stack v3)\r\n    if (typeof decodeUplink === 'function') {\r\n        try {\r\n            const input = {\r\n                bytes: bytes,\r\n                fPort: port\r\n            };\r\n            var result = decodeUplink(input);\r\n            \r\n            if (result.data) return result.data;\r\n\r\n            return result; \r\n        } catch (e) {\r\n            console.error(\"Error inside decodeUplink:\", e);\r\n            throw e;\r\n        }\r\n    }\r\n\r\n    // CASE B: Legacy TTN (v2)\r\n    else if (typeof Decoder === 'function') {\r\n        try {\r\n            return Decoder(bytes, port);\r\n        } catch (e) {\r\n            console.error(\"Error inside Decoder:\", e);\r\n            throw e;\r\n        }\r\n    }\r\n\r\n    // CASE C: No decoder found\r\n    else {\r\n        throw new Error(\"No compatible TTN decoder function (decodeUplink or Decoder) found in scope.\");\r\n    }\r\n}\r\n\r\n\r\n// TTN decoder\r\n\r\n(function webpackUniversalModuleDefinition(root, factory) {\r\n\tif(typeof exports === 'object' && typeof module === 'object')\r\n\t\tmodule.exports = factory();\r\n\telse if(typeof define === 'function' && define.amd)\r\n\t\tdefine([], factory);\r\n\telse {\r\n\t\tvar a = factory();\r\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\r\n\t}\r\n})(this, () => {\r\nreturn /******/ (() => { // webpackBootstrap\r\n/******/ \tvar __webpack_modules__ = ({\r\n\r\n/***/ 44:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet abeewayUplinkPayloadClass = __webpack_require__(962);\r\nlet abeewayDownlinkPayloadClass = __webpack_require__(522);\r\nlet basicHeadeClass = __webpack_require__(592);\r\nlet extendedHeaderClass = __webpack_require__(271);\r\nlet notificationClass = __webpack_require__(977);\r\nlet positionClass = __webpack_require__(457);\r\nlet responseClass = __webpack_require__(289);\r\nlet queryClass = __webpack_require__(220);\r\nlet util = __webpack_require__(94);\r\nlet commandClass = __webpack_require__(851);\r\nlet requestClass = __webpack_require__(788);\r\nlet telemetryClass = __webpack_require__(560);\r\n\r\nconst DOWNLINK_PORT_NUMBER = 3;\r\n\r\nconst removeEmpty = (obj) => {\r\n    Object.keys(obj).forEach(k =>\r\n      (obj[k] && typeof obj[k] === 'object') && removeEmpty(obj[k]) ||\r\n      (!obj[k] && (obj[k] === null || obj[k] === undefined)) && delete obj[k] \r\n    );\r\n    return obj;\r\n  };\r\n\r\n\r\n\r\nfunction decodeUplink(input) {\r\n    let result = {\r\n        data: {},\r\n        errors: [],\r\n        warnings: []\r\n    }\r\n    try{\r\n        var decodedData = new abeewayUplinkPayloadClass.AbeewayUplinkPayload();\r\n        var payload = input.bytes;\r\n        var receivedTime = input.recvTime;\r\n\r\n        //header decoding\r\n        decodedData.header = basicHeadeClass.determineHeader(payload,receivedTime);\r\n\r\n        //if multiframe is true\r\n        var multiFrame = !!(payload[0]>>7 & 0x01);\r\n        if (multiFrame){\r\n            decodedData.extendedHeader = extendedHeaderClass.determineExtendedHeader(payload);\r\n        }\r\n        decodedData.payload = util.convertBytesToString(payload);\r\n        switch (decodedData.header.type){\r\n            case abeewayUplinkPayloadClass.messageType.NOTIFICATION:\r\n                decodedData.notification = notificationClass.determineNotification(payload);\r\n                break;\r\n            case abeewayUplinkPayloadClass.messageType.POSITION:\r\n                decodedData.position = positionClass.determinePosition(payload, multiFrame);\r\n                break;\r\n            case abeewayUplinkPayloadClass.messageType.QUERY:\r\n                decodedData.query = queryClass.determineQuery(payload);\r\n                break;\r\n            case abeewayUplinkPayloadClass.messageType.RESPONSE:\r\n                decodedData.response = responseClass.determineResponse(payload, multiFrame);\r\n                break;\r\n            case abeewayUplinkPayloadClass.messageType.TELEMETRY:\r\n                decodedData.telemetry = telemetryClass.decodeTelemetry(payload);\r\n                break;\r\n        }\r\n        decodedData = removeEmpty(decodedData);\r\n        result.data = decodedData;\r\n    } catch (e){\r\n        result.errors.push(e.message);\r\n        delete result.data;\r\n        return result;\r\n    }\r\n    return result;\r\n}\r\n\r\nfunction decodeDownlink(input){\r\n    let result = {\r\n        data: {},\r\n        errors: [],\r\n        warnings: []\r\n    }\r\n    try{\r\n        var payload = input.bytes;\r\n        var decodedData = new abeewayDownlinkPayloadClass.determineDownlinkHeader(payload);\r\n        decodedData.payload = util.convertBytesToString(payload);\r\n        switch (decodedData.downMessageType){\r\n            case abeewayDownlinkPayloadClass.MessageType.COMMAND:\r\n                decodedData.command = commandClass.decodeCommand(payload.slice(1))\r\n                break;\r\n            case abeewayDownlinkPayloadClass.MessageType.REQUEST:\r\n                decodedData.request = requestClass.decodeRequest(payload)\r\n                break;\r\n            case abeewayDownlinkPayloadClass.MessageType.ANSWER:\r\n                decodedData.response = responseClass.determineResponse(payload, multiFrame);\r\n                break;\r\n        }\r\n        decodedData = removeEmpty(decodedData);\r\n        result.data= decodedData;\r\n    }\r\n    catch (e){\r\n        result.errors.push(e.message);\r\n        delete result.data;\r\n        return result;\r\n    }\r\n    return result;\r\n}\r\n\r\nfunction encodeDownlink(input){\r\n    let result = {\r\n        errors: [],\r\n        warnings: []\r\n    };\r\n\r\n    try{\r\n        if (input == null) {\r\n            throw new Error(\"No data to encode\");\r\n        }\r\n\r\n        let data = input;\r\n        if(input.data != null) {\r\n            data = input.data;\r\n        }\r\n\r\n        var bytes = [];\r\n\r\n        if(data.downMessageType == null){\r\n            throw new Error(\"No downlink message type\");\r\n        }\r\n        switch (data.downMessageType){\r\n            case abeewayDownlinkPayloadClass.MessageType.COMMAND:\r\n                bytes = commandClass.encodeCommand(data);\r\n                break;\r\n            case abeewayDownlinkPayloadClass.MessageType.REQUEST:\r\n                bytes = requestClass.encodeRequest(data);\r\n                break;\r\n            case abeewayDownlinkPayloadClass.MessageType.ANSWER:\r\n\r\n                break;\r\n            \r\n        }\r\n\r\n        result.bytes = bytes;\r\n        result.fPort = DOWNLINK_PORT_NUMBER;\r\n    } catch (e){\r\n        result.errors.push(e.message);\r\n        delete result.bytes;\r\n        delete result.fPort;\r\n        return result;\r\n    }\r\n    return result;\r\n}\r\n\r\nmodule.exports = {\r\n    decodeUplink: decodeUplink,\r\n    decodeDownlink: decodeDownlink,\r\n    encodeDownlink: encodeDownlink\r\n}\r\n\r\n//console.log(decodeUplink({recvTime: \"2025-03-01T13:04:27.000+02:00\", bytes: \"2864871d80010000003c050091010384003c050ea2010000003c050e\", \"fPort\":3}));\r\n\r\n/***/ }),\r\n\r\n/***/ 69:\r\n/***/ ((module) => {\r\n\r\nfunction BssidInfo(mac,\r\n    rssi\r\n){\r\n    this.mac = mac;\r\n    this.rssi = rssi;\r\n}\r\n\r\nmodule.exports = {\r\n    BssidInfo: BssidInfo, \t\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 94:\r\n/***/ ((module) => {\r\n\r\nfunction convertToByteArray(payload){\r\n    var bytes = [];\r\n    var length = payload.length/2;\r\n    for(var i = 0; i < payload.length; i+=2){\r\n        bytes[i/2] = parseInt(payload.substring(i, i+2),16)&0xFF;\r\n    }\r\n    \r\n    return bytes;\r\n}\r\nfunction isValueInRange(value, min, max) {\r\n    return value >= min && value <= max;\r\n}\r\n\r\nfunction camelToSnake(string) {\r\n       return string.replace(/[\\w]([A-Z1-9])/g, function(m) {\r\n           return m[0] + \"_\" + m[1];\r\n       }).toUpperCase();\r\n   }\r\n\r\nfunction twoComplement(num) {\r\n    if (num > 0x7FFFFFFF) {\r\n        num -= 0x100000000;\r\n    }\r\n    return num\r\n}\r\nfunction convertBytesToString(bytes){\r\n    var payload = \"\";\r\n    var hex;\r\n    for(var i = 0; i < bytes.length; i++){\r\n        hex = convertByteToString(bytes[i]);\r\n        payload += hex;\r\n    }\r\n    return payload;\r\n}\r\n\r\nfunction convertByteToString(byte){\r\n    let hex = byte.toString(16);\r\n    if (hex.length < 2){\r\n        hex = \"0\" + hex;\r\n    }\r\n    return hex;\r\n}\r\n\r\nfunction decodeCondensed(value, lo, hi, nbits, nresv) {\r\n    return ((value - nresv / 2) / ( (((1 << nbits) - 1) - nresv) / (hi - lo)) + lo);\r\n}\r\n\r\nfunction convertNegativeInt(value, length) {\r\n    if (value > (0x7F << 8*(length-1))){\r\n        value -= 0x01<< 8*length;\r\n\t}\r\n\treturn value;\r\n}\r\n\r\nfunction hexStringToInt(hexString) {\r\n    if (hexString.startsWith(\"0x\")) {\r\n        hexString = hexString.slice(2);\r\n    }\r\n    return parseInt(hexString, 16);\r\n}\r\n// It allows to check the range validity of the parameter value \r\nfunction checkParamValueRange (givenValue, minimum, maximum, exclusiveMinimum, exclusiveMaximum, additionalValues, additionalRanges) {\r\n\tif (additionalValues != undefined)\r\n\t{\r\n\t\tif (additionalValues.includes(givenValue))\r\n\t\t\treturn true;\r\n\t}\r\n    if (additionalRanges != undefined && additionalRanges.length >0)\r\n    {\r\n        for (let additionalRange of additionalRanges)\r\n        {\r\n\t\t\tif (givenValue>= additionalRange.minimum && givenValue <= additionalRange.maximum)\r\n    \t\t\treturn true;\r\n    \t}\r\n    }\r\n    if (maximum== undefined && minimum== undefined){\r\n        return true\r\n    }\r\n    if (((minimum == undefined || (exclusiveMinimum!=undefined && exclusiveMinimum == true && givenValue > minimum) ||\r\n    givenValue>=minimum)) && (maximum == undefined || (exclusiveMaximum!=undefined && exclusiveMaximum == true && givenValue < maximum || (givenValue <=maximum))))\r\n\t    return true;\r\n    return false;\r\n}\r\nfunction hasNegativeNumber(additionalValues) {\r\n\tif (additionalValues == undefined) \r\n        return false;\r\n\tfor (let el of additionalValues){\r\n        if (typeof(el)==\"number\"){\r\n            if (el < 0)\r\n\t\t\t    return true;\r\n        }\r\n        else if (typeof(el)==\"object\"){\r\n            if (el.minimum < 0)\r\n                return true;\r\n        }\r\n\t}\r\n\treturn false;\r\n}\r\nfunction lengthToHex(length){  \r\n    let hex =0;\r\n\tfor (let i  =0; i<length; i++)\r\n\t{\r\n\t\thex = hex + Math.pow(2,i)\r\n\t}\r\n\t//return parseInt(hex,16)\r\n    return hex\r\n}\r\nmodule.exports = {\r\n    convertToByteArray: convertToByteArray,\r\n    camelToSnake: camelToSnake,\r\n    convertBytesToString: convertBytesToString,\r\n    convertByteToString: convertByteToString,\r\n    decodeCondensed: decodeCondensed,\r\n    convertNegativeInt: convertNegativeInt,\r\n    twoComplement: twoComplement,\r\n    isValueInRange: isValueInRange,\r\n    hexStringToInt: hexStringToInt,\r\n    checkParamValueRange: checkParamValueRange,\r\n    hasNegativeNumber: hasNegativeNumber,\r\n    lengthToHex: lengthToHex\r\n\r\n    \r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 142:\r\n/***/ ((module) => {\r\n\r\nfunction Network(activeNetwork, mainNetwork, backupNetwork){\r\n    this.activeNetwork = activeNetwork;\r\n    this.mainNetwork = mainNetwork;\r\n    this.backupNetwork = backupNetwork;\r\n}\r\nconst NetworkType = Object.freeze({\r\n    MAIN_UP: \"MAIN_UP\",\r\n    BACKUP_UP: \"BACKUP_UP\"\r\n})\r\n\r\nconst NetworkInfo = Object.freeze({\r\n    NO_NETWORK: \"NO_NETWORK\",\r\n    LORA_NETWORK: \"LORA_NETWORK\",\r\n    CELLULAR_NETWORK_IN_LOW_POWER_MODE: \"CELLULAR_NETWORK_IN_LOW_POWER_MODE\",\r\n    CELLULAR_NETWORK_IN_HIGH_POWER_MODE: \"CELLULAR_NETWORK_IN_HIGH_POWER_MODE\"\r\n\r\n})\r\n\r\nfunction determineNetwork(value){\r\n    switch(value){\r\n        case 0:\r\n            return NetworkInfo.NO_NETWORK;\r\n        case 1:\r\n            return NetworkInfo.LORA_NETWORK;\r\n        case 2:\r\n            return NetworkInfo.CELLULAR_NETWORK_IN_LOW_POWER_MODE;\r\n        case 3:\r\n            return NetworkInfo.CELLULAR_NETWORK_IN_HIGH_POWER_MODE;\r\n        default:\r\n            throw new Error(\"Unknown Network Information\");\r\n    }\r\n\r\n}\r\nfunction determineNetworkInfo(payload){\r\n    let activeNetwork = determineNetwork(payload[5])\r\n    let mainNetwork =  determineNetwork(payload[6])\r\n    let backupNetwork = determineNetwork(payload[7])\r\n    return new Network(activeNetwork, mainNetwork, backupNetwork);\r\n}\r\n\r\nmodule.exports = {\r\n    Network: Network,\r\n    determineNetworkInfo: determineNetworkInfo,\r\n    NetworkType: NetworkType\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 187:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet util = __webpack_require__(94);\r\n\r\nfunction System(status,\r\n    lowBattery, bleStatus, tamperDetection, heartbeat){\r\n    this.status = status;\r\n    this.lowBattery = lowBattery;\r\n    this.bleStatus = bleStatus;\r\n    this.tamperDetection = tamperDetection;\r\n    this.heartbeat = heartbeat;\r\n}\r\nconst SystemType = Object.freeze({\r\n    STATUS: \"STATUS\",\r\n    LOW_BATTERY: \"LOW_BATTERY\",\r\n    BLE_STATUS: \"BLE_STATUS\",\r\n    TAMPER_DETECTION: \"TAMPER_DETECTION\",\r\n    HEARTBEAT : \"HEARTBEAT\"\r\n})\r\nconst ResetCause = Object.freeze({\r\n    AOS_ERROR_NONE: \"AOS_ERROR_NONE\",\r\n    AOS_ERROR_HW_NMI: \"AOS_ERROR_HW_NMI\",\r\n    AOS_ERROR_HW_FAULT: \"AOS_ERROR_HW_FAULT\",\r\n    AOS_ERROR_HW_MPU: \"AOS_ERROR_HW_MPU\",\r\n    AOS_ERROR_HW_BUS: \"AOS_ERROR_HW_BUS\",\r\n    AOS_ERROR_HW_USAGE: \"AOS_ERROR_HW_USAGE\",\r\n    AOS_ERROR_HW_IRQ: \"AOS_ERROR_HW_IRQ\",\r\n    AOS_ERROR_HW_WDOG: \"AOS_ERROR_HW_WDOG\",\r\n    AOS_ERROR_HW_BOR: \"AOS_ERROR_HW_BOR\",\r\n    AOS_ERROR_SW_ST_HAL_ERROR: \"AOS_ERROR_SW_ST_HAL_ERROR\",\r\n    AOS_ERROR_SW_FREERTOS_ASSERT: \"AOS_ERROR_SW_FREERTOS_ASSERT\",\r\n    AOS_ERROR_SW_FREERTOS_TASK_OVF: \"AOS_ERROR_SW_FREERTOS_TASK_OVF\",\r\n    AOS_ERROR_SW_BLE_ASSERT: \"AOS_ERROR_SW_BLE_ASSERT\",\r\n    AOS_ERROR_SW_RTC_FAIL: \"AOS_ERROR_SW_RTC_FAIL\",\r\n    AOS_ERROR_SW_LORA_FAIL: \"AOS_ERROR_SW_LORA_FAIL\",\r\n    AOS_ERROR_SW_DEBUG: \"AOS_ERROR_SW_DEBUG\",\r\n    AOS_ERROR_SW_APP_START: \"AOS_ERROR_SW_APP_START\",\r\n})\r\n\r\nfunction Status(currentTemperature, resetCause, pageId, AT3Version,\r\n    configurationVersion,\r\n    lrHwVersion,\r\n    hwBatchId,\r\n    hwBomId,\r\n    maxTemperature,\r\n    minTemperature,\r\n    motionPercent,\r\n    batteryVoltage,\r\n    totalConsumption,\r\n    cellularConsumption,\r\n    gnssConsumption,\r\n    wifiConsumption,\r\n    lrGnssConsumption,\r\n    bleConsumption,\r\n    mcuConsumption,\r\n    globalCrc,\r\n    lr11xxGpsDate, \r\n    lr11xxGpsOutdated,\r\n    lr11xxGpsGood,\r\n    lr11xxBeidouDate,\r\n    lr11xxBeidouOutdated,\r\n    lr11xxBeidouGood,\r\n    gnssGpsDate, \r\n    gnssGpsOutdated,\r\n    gnssGpsGood,\r\n    gnssBeidouDate,\r\n    gnssBeidouOutdated,\r\n    gnssBeidouGood,\r\n    cellVersion,\r\n    ICCID,\r\n    IMSI,\r\n    EUICCID,\r\n    IMEISV\r\n    ){\r\n    this.currentTemperature = currentTemperature;\r\n    this.resetCause = resetCause;\r\n    this.pageId = pageId;\r\n    this.AT3Version = AT3Version;\r\n    this.configurationVersion = configurationVersion;\r\n    this.lrHwVersion = lrHwVersion;\r\n    this.hwBatchId = hwBatchId;\r\n    this.hwBomId = hwBomId;\r\n    this.maxTemperature = maxTemperature;\r\n    this.minTemperature = minTemperature;\r\n    this.motionPercent = motionPercent;\r\n    this.batteryVoltage = batteryVoltage;\r\n    this.totalConsumption = totalConsumption;\r\n    this.cellularConsumption = cellularConsumption;\r\n    this.gnssConsumption = gnssConsumption;\r\n    this.wifiConsumption = wifiConsumption;\r\n    this.lrGnssConsumption = lrGnssConsumption;\r\n    this.bleConsumption = bleConsumption;\r\n    this.mcuConsumption =mcuConsumption;\r\n    this.globalCrc = globalCrc;\r\n    this.lr11xxGpsDate = lr11xxGpsDate;\r\n    this.lr11xxGpsOutdated = lr11xxGpsOutdated;\r\n    this.lr11xxGpsGood = lr11xxGpsGood;\r\n    this.lr11xxBeidouDate = lr11xxBeidouDate;\r\n    this.lr11xxBeidouOutdated = lr11xxBeidouOutdated;\r\n    this.lr11xxBeidouGood = lr11xxBeidouGood;\r\n    this.gnssGpsDate = gnssGpsDate;\r\n    this.gnssGpsOutdated = gnssGpsOutdated;\r\n    this.gnssGpsGood = gnssGpsGood;\r\n    this.gnssBeidouDate = gnssBeidouDate;\r\n    this.gnssBeidouOutdated = gnssBeidouOutdated;\r\n    this.gnssBeidouGood = gnssBeidouGood;   \r\n    this.cellVersion = cellVersion;\r\n    this.ICCID = ICCID;\r\n    this.IMSI = IMSI;\r\n    this.EUICCID = EUICCID;\r\n    this.IMEISV = IMEISV;\r\n\r\n\r\n}\r\n\r\n\r\nfunction LowBattery(consumption, batteryVoltage){\r\n    this.consumption = consumption;\r\n    this.batteryVoltage = batteryVoltage;\r\n}\r\nfunction BleStatus(state){\r\n    this.state = state\r\n}\r\nfunction TamperDetection(state){\r\n    this.state = state\r\n}\r\nfunction Heartbeat(currentTemperature, resetCause, globalCrc){\r\n    this.currentTemperature = currentTemperature;\r\n    this.resetCause = resetCause;\r\n    this.globalCrc = globalCrc;\r\n}\r\n\r\nfunction determineHeartbeat(payload) {\r\n    var currentTemperature = util.convertNegativeInt(payload[5],1);\r\n    var resetCause = determineResetCause(((payload[6]>>3)& 0x1F));\r\n    // Extract the n bytes of the CRC (big-endian)\r\n    const crcBytes = payload.slice(7, 11);\r\n    // Convert each byte to a 2-digit hexadecimal string and concatenate\r\n    const crc = crcBytes.map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\r\n    return new Heartbeat(currentTemperature, resetCause, crc)\r\n}\r\nfunction determineLowBattery(payload){\r\n    var consumption = (payload[5] << 8) + payload[6];\r\n    var batteryVoltage = (payload[7] << 8) + payload[8];\r\n    return new LowBattery(consumption, batteryVoltage\r\n\r\n    )}\r\n\r\nfunction determineStatus(payload){\r\n    var currentTemperature = util.convertNegativeInt(payload[5],1);\r\n    var resetCause = determineResetCause(((payload[6]>>3)& 0x1F));\r\n    var pageId = payload[6] & 0x07\r\n    var decodedStatus = new Status(currentTemperature, resetCause, pageId)\r\n    switch (pageId){\r\n        case 0:\r\n            determinePage0(payload, decodedStatus)\r\n            break;\r\n        case 1: \r\n            determinePage1(payload, decodedStatus)\r\n            break;\r\n        case 2:\r\n            determinePage2(payload, decodedStatus)\r\n            break;\r\n        case 3:\r\n            determinePage3(payload, decodedStatus)\r\n            break;\r\n        default:\r\n            throw new Error(\"Unknown page identifier\");\r\n    }\r\n    return decodedStatus\r\n}\r\nfunction determineBleStatus(payload){\r\n    switch (payload[5] & 0x01){\r\n        case 0:\r\n            return new BleStatus(\"BLE_DISCONNECTED\")\r\n        case 1:\r\n            return new BleStatus(\"BLE_CONNECTED\")\r\n\r\n    }\r\n}\r\nfunction determineTamperDetection(payload){\r\n    switch (payload[5] & 0x01){\r\n        case 0:\r\n            return new TamperDetection(\"CASING_CLOSED\")\r\n        case 1:\r\n            return new TamperDetection(\"CASING_OPEN\")\r\n\r\n    }\r\n}\r\nfunction determinePage0(payload, decodedStatus){\r\n    decodedStatus.AT3Version = payload[7].toString()+\".\"+payload[8].toString()+\".\"+payload[9].toString();\r\n    decodedStatus.configurationVersion = payload[10].toString()+\".\"+payload[11].toString()+\".\"+payload[12].toString()+\".\"+payload[13].toString();\r\n    decodedStatus.lrHwVersion = {\"hardwareVersion\": payload[14].toString(),\"hardwareType\": payload[15].toString(), \"firmwareVersion\":payload[16].toString()}\r\n    decodedStatus.hwBatchId = (payload[17] <<8) + payload[18]\r\n    decodedStatus.hwBomId = (payload[19] <<8) + payload[20]\r\n    decodedStatus.maxTemperature = util.convertNegativeInt(payload[21],1);\r\n    decodedStatus.minTemperature = util.convertNegativeInt(payload[22],1);\r\n    decodedStatus.motionPercent = payload[23]\r\n    decodedStatus.batteryVoltage = (payload[24] << 8) + payload[25];\r\n    decodedStatus.totalConsumption = (payload[26] << 8) + payload[27];\r\n    decodedStatus.cellularConsumption = (payload[28] << 8) + payload[29];\r\n    decodedStatus.gnssConsumption = (payload[30] << 8) + payload[31];\r\n    decodedStatus.wifiConsumption = (payload[32] << 8) + payload[33];\r\n    decodedStatus.lrGnssConsumption = (payload[34] << 8) + payload[35];\r\n    decodedStatus.bleConsumption = (payload[36] << 8) + payload[37];\r\n    decodedStatus.mcuConsumption = (payload[38] << 8) + payload[39];\r\n    const crcBytes = payload.slice(40, 44);\r\n    // Convert each byte to a 2-digit hexadecimal string and concatenate\r\n    decodedStatus.globalCrc = crcBytes.map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\r\n}\r\n\r\nfunction determinePage1(payload, decodedStatus){\r\n    decodedStatus.lr11xxGpsDate = (payload[7] << 8) + payload[8];\r\n    let value = (payload[9] << 24) + (payload[10] << 16) + (payload[11] << 8) + payload[12];\r\n    decodedStatus.lr11xxGpsOutdated = gpsSatelliteField\r\n        .filter(bit => getBit(value, bit.position))\r\n        .map(bit => bit.position+1);\r\n    decodedStatus.lr11xxGpsGood = payload[13]\r\n    decodedStatus.lr11xxBeidouDate = (payload[14] << 8) + payload[15];\r\n    let valueB = payload.slice(16,21)\r\n    decodedStatus.lr11xxBeidouOutdated = beidouSatelliteField\r\n        .filter(bit => getBitFromPayload(valueB, bit.position))\r\n        .map(bit => bit.position+1);\r\n    decodedStatus.lr11xxBeidouGood = payload[21]\r\n    decodedStatus.gnssGpsDate = (payload[22] << 8) + payload[23];\r\n    let valueG = (payload[24] << 24) + (payload[25] << 16) + (payload[26] << 8) + payload[27];\r\n    decodedStatus.gnssGpsOutdated = gpsSatelliteField\r\n        .filter(bit => getBit(valueG, bit.position))\r\n        .map(bit => bit.position+1);\r\n    decodedStatus.gnssGpsGood = payload[28]\r\n    decodedStatus.gnssBeidouDate = (payload[29] << 8) + payload[30];\r\n    let valueGB = payload.slice(31,36);\r\n    decodedStatus.gnssBeidouOutdated = beidouSatelliteField\r\n        .filter(bit => getBitFromPayload(valueGB, bit.position))\r\n        .map(bit => bit.position+1);\r\n    decodedStatus.gnssBeidouGood = payload[36];  \r\n}\r\nfunction determinePage2(payload, decodedStatus){\r\n    decodedStatus.cellVersion = {\"branch\": payload[7].toString(),\"mode\": payload[8].toString(), \"image\":payload[9].toString(), \"delivery\": payload[10].toString(), \"release\": parseInt(util.convertBytesToString(payload.slice(11,13)),16).toString() }\r\n    decodedStatus.ICCID = buildAscciString(payload.slice(13,33))\r\n    decodedStatus.IMSI = buildAscciString(payload.slice(33))\r\n}\r\nfunction determinePage3(payload, decodedStatus){\r\n    decodedStatus.EUICCID = buildAscciString(payload.slice(7,40))\r\n    decodedStatus.IMEISV = buildAscciString(payload.slice(40))\r\n}\r\n\r\nfunction buildAscciString(value){\r\n    // Find the position of the last non-zero element\r\n    let endIndex = value.length;\r\n    let allZero = true;  // Variable to check if all elements are zero\r\n    for (let i = value.length - 1; i >= 0; i--) {\r\n        if (value[i] !== 0) {\r\n            endIndex = i + 1;\r\n            allZero = false;   // Mark as not all zeros\r\n            break;\r\n        }\r\n    }\r\n    // If all elements are zero, return an empty string\r\n    if (allZero) {\r\n         return \"\";\r\n    }\r\n    // Create the ASCII string up to the last non-zero element\r\n    var asciiString = \"\"\r\n    for (var i = 0; i < endIndex; i ++)\r\n        asciiString += String.fromCharCode(value[i]);\r\n    return asciiString\r\n}\r\nfunction determineResetCause(value){\r\n    switch(value){\r\n        case 0:\r\n            return ResetCause.AOS_ERROR_NONE;\r\n        case 1:\r\n            return ResetCause.AOS_ERROR_HW_NMI;\r\n        case 2:\r\n            return ResetCause.AOS_ERROR_HW_FAULT;\r\n        case 3:\r\n            return ResetCause.AOS_ERROR_HW_MPU;\r\n        case 4:\r\n            return ResetCause.AOS_ERROR_HW_BUS;\r\n        case 5:\r\n            return ResetCause.AOS_ERROR_HW_USAGE;\r\n        case 6:\r\n            return ResetCause.AOS_ERROR_HW_IRQ;\r\n        case 7:\r\n            return ResetCause.AOS_ERROR_HW_WDOG;\r\n        case 8:\r\n            return ResetCause.AOS_ERROR_HW_BOR;\r\n        case 9:\r\n            return ResetCause.AOS_ERROR_SW_ST_HAL_ERROR;\r\n        case 10:\r\n            return ResetCause.AOS_ERROR_SW_FREERTOS_ASSERT;\r\n        case 11:\r\n            return ResetCause.AOS_ERROR_SW_FREERTOS_TASK_OVF;\r\n        case 12:\r\n            return ResetCause.AOS_ERROR_SW_BLE_ASSERT;\r\n        case 13:\r\n            return ResetCause.AOS_ERROR_SW_RTC_FAIL;\r\n        case 14:\r\n            return ResetCause.AOS_ERROR_SW_LORA_FAIL;\r\n        case 15:\r\n            return ResetCause.AOS_ERROR_SW_DEBUG;\r\n        case 16:\r\n            return ResetCause.AOS_ERROR_SW_APP_START;\r\n        default:\r\n            throw new Error(\"Unknown Reset Cause\");\r\n    }\r\n}\r\n    \r\nfunction getBit(value, position) {\r\n    return (value >> position) & 1;\r\n}\r\n// Define a function to extract the bit value at a specific position from a byte\r\nfunction getBitFromByte(byte, position) {\r\n    return (byte & (1 << position)) !== 0 ? 1 : 0;\r\n}\r\n\r\n// Define a function to extract the bit value at a specific position from the payload\r\nfunction getBitFromPayload(payload, position) {\r\n    const byteIndex = Math.floor(position / 8);\r\n    const bitIndex = position % 8;\r\n    return getBitFromByte(payload[byteIndex], bitIndex);\r\n}\r\n\r\n// Define a bit gps field structure with positions only\r\nlet gpsSatelliteField = Array.from({ length: 32 }, (_, i) => ({\r\n    position: i\r\n}));\r\n// Define a bit beidou field structure with positions only\r\nlet beidouSatelliteField = Array.from({ length: 40 }, (_, i) => ({\r\n    position: i\r\n}));\r\n\r\nmodule.exports = {\r\n    System: System,\r\n    determineStatus: determineStatus,\r\n    determineLowBattery: determineLowBattery,\r\n    determineBleStatus: determineBleStatus,\r\n    determineTamperDetection: determineTamperDetection,\r\n    determineHeartbeat : determineHeartbeat,\r\n    SystemType: SystemType\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 220:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet util = __webpack_require__(94);\r\nconst QueryType = Object.freeze({\r\n    AIDING_POSITION: \"AIDING_POSITION\",\r\n    ECHO_REQUEST: \"ECHO_REQUEST\",\r\n    UPDATE_GPS_ALMANAC: \"UPDATE_GPS_ALMANAC\",\r\n    UPDATE_BEIDOU_ALMANAC: \"UPDATE_BEIDOU_ALMANAC\"\r\n})\r\n\r\nfunction Query(queryType,\r\n    gpsSvid, beidouSvid, sequenceNumber){\r\n        this.queryType = queryType;\r\n        this.gpsSvid = gpsSvid;\r\n        this.beidouSvid = beidouSvid;\r\n        this.sequenceNumber = sequenceNumber;\r\n}\r\n\r\nfunction determineQuery(payload){\r\n    let query = new Query();\r\n    let typeValue = payload[4] & 0x1F;\r\n    switch (typeValue){\r\n        case 0:\r\n            query.queryType = QueryType.AIDING_POSITION\r\n            break;\r\n        case 1:\r\n            query.queryType = QueryType.ECHO_REQUEST\r\n            query.sequenceNumber = payload.slice(5)\r\n            break;\r\n        case 2:\r\n            query.queryType = QueryType.UPDATE_GPS_ALMANAC\r\n            query.gpsSvid = determineSvId(payload.slice(5), 0, 31, \"GPS\")\r\n            break;\r\n        case 3:\r\n            query.queryType = QueryType.UPDATE_BEIDOU_ALMANAC\r\n            query.beidouSvid = determineSvId(payload.slice(5), 0, 34, \"BEIDOU\")\r\n            break;\r\n        default:\r\n            throw new Error(\"Query Type Unknown\");\r\n    }\r\n    return query;\r\n}\r\n\r\nfunction determineSvId(payload, min, max , constellation){\r\n    let svid = [];\r\n    for (let i = 0; i < payload.length; i++) {\r\n        if (!util.isValueInRange(payload[i], min, max))\r\n            throw new Error(\"Invalid \"+constellation+\" SVID Number\");\r\n        svid.push(payload[i]);\r\n    }\r\n    return svid\r\n} \r\nmodule.exports = {\r\n    Query: Query,\r\n    determineQuery: determineQuery\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 271:\r\n/***/ ((module) => {\r\n\r\nfunction ExtendedHeader(groupId,\r\n    last,\r\n    frameNumber){\r\n    this.groupId = groupId;\r\n    this.last = last;\r\n    this.frameNumber = frameNumber;\r\n}\r\n\r\nfunction determineExtendedHeader(payload){\r\n    if (payload.length < 5)\r\n        throw new Error(\"The payload is not valid to determine multi frame header\");\r\n    let extendedHeader = new ExtendedHeader(payload[4]>>5 & 0x07, \r\n        payload[4]>>4 & 0x01, \r\n        payload[4] & 0x07);\r\n    return extendedHeader;\r\n    \r\n}\r\n\r\nmodule.exports = {\r\n    ExtendedHeader: ExtendedHeader,\r\n    determineExtendedHeader: determineExtendedHeader\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 289:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\n/* let requestClass = require(\"../../downlink/requests/request\");\r\n//response type is the same as request type\r\nconst responseType = requestClass.RequestType; */\r\n\r\nlet util = __webpack_require__(94);\r\nlet jsonParameters = __webpack_require__(635);\r\nlet accelerometer = __webpack_require__(925)\r\n\r\nconst ResponseType = Object.freeze({\r\n    GENERIC_CONFIGURATION_SET: \"GENERIC_CONFIGURATION_SET\",\r\n    PARAM_CLASS_CONFIGURATION_SET: \"PARAM_CLASS_CONFIGURATION_SET\",\r\n    GENERIC_CONFIGURATION_GET: \"GENERIC_CONFIGURATION_GET\",\r\n    PARAM_CLASS_CONFIGURATION_GET: \"PARAM_CLASS_CONFIGURATION_GET\",\r\n    BLE_STATUS_CONNECTIVITY: \"BLE_STATUS_CONNECTIVITY\",\r\n    CRC_CONFIGURATION_REQUEST : \"CRC_CONFIGURATION_REQUEST\",\r\n    SENSOR_REQUEST: \"SENSOR_REQUEST\"\r\n   \r\n})\r\nconst StatusType = Object.freeze({\r\n   SUCCESS: \"SUCCESS\",\r\n   NOT_FOUND: \"NOT_FOUND\",\r\n   BELOW_LOWER_BOUND: \"BELOW_LOWER_BOUND\",\r\n   ABOVE_HIGHER_BOUND: \"ABOVE_HIGHER_BOUND\",\r\n   BAD_VALUE: \"BAD_VALUE\",\r\n   TYPE_MISMATCH: \"TYPE_MISMATCH\",\r\n   OPERATION_ERROR : \"OPERATION_ERROR\",\r\n   READ_ONLY: \"READ_ONLY\"\r\n})\r\n\r\nconst GroupType = Object.freeze({\r\n    INTERNAL: \"INTERNAL\",\r\n    SYSTEM_CORE: \"SYSTEM_CORE\",\r\n    GEOLOC: \"GEOLOC\",\r\n    GNSS: \"GNSS\",\r\n    LR11xx: \"LR11xx\",\r\n    BLE_SCAN1: \"BLE_SCAN1\",\r\n    BLE_SCAN2: \"BLE_SCAN2\",\r\n    ACCELEROMETER : \"ACCELEROMETER\",\r\n    NETWORK: \"NETWORK\",\r\n    LORAWAN: \"LORAWAN\",\r\n    CELLULAR: \"CELLULAR\",\r\n    BLE : \"BLE\"\r\n })\r\nconst ParameterType = Object.freeze({\r\n    DEPREACTED: \"DEPREACTED\",\r\n    INTEGER: \"INTEGER\",\r\n    FLOATING_POINT: \"FLOATING_POINT\",\r\n    ASCCII_STRING: \"ASCCII_STRING\",\r\n    BYTE_ARRAY: \"BYTE_ARRAY\"\r\n})\r\nfunction Response(responseType,\r\n    genericConfigurationSet,\r\n    parameterClassConfigurationSet,\r\n    genericConfigurationGet,\r\n    parameterClassConfigurationGet,\r\n    bleStatusConnectivity,\r\n    configurationCrcRequest,\r\n    sensorRequest,\r\n    globalCrc,\r\n    localCrc\r\n    ){\r\n        this.responseType = responseType;\r\n        this.genericConfigurationSet = genericConfigurationSet;\r\n        this.parameterClassConfigurationSet = parameterClassConfigurationSet;\r\n        this.genericConfigurationGet = genericConfigurationGet;\r\n        this.parameterClassConfigurationGet = parameterClassConfigurationGet;\r\n        this.bleStatusConnectivity= bleStatusConnectivity;\r\n        this.configurationCrcRequest = configurationCrcRequest;\r\n        this.sensorRequest = sensorRequest;\r\n        this.globalCrc = globalCrc;\r\n        this.localCrc = localCrc;\r\n}\r\nfunction ParameterClassConfigurationSet(group, parameters){\r\n    this.group = group\r\n    this.parameters = parameters\r\n}\r\n\r\nfunction determineResponse(payload, multiFrame){\r\n    let response = new Response();\r\n    let startingByte = 4;\r\n    if (multiFrame){\r\n        startingByte = 5;\r\n    }\r\n    let typeValue  = payload[startingByte] & 0x1F;\r\n    switch (typeValue){\r\n        case 0:\r\n            response.responseType = ResponseType.GENERIC_CONFIGURATION_SET\r\n            response.globalCrc =  decodeCrc(payload, startingByte+1,4)\r\n            response.genericConfigurationSet = determineResponseGenericConfigurationSet(payload.slice(startingByte+5))\r\n            break;\r\n        case 1:\r\n            response.responseType = ResponseType.PARAM_CLASS_CONFIGURATION_SET\r\n            response.localCrc =  decodeCrc(payload, startingByte+2,3)\r\n            response.parameterClassConfigurationSet = determineResponseParameterClassConfigurationSet(payload.slice(startingByte+1))\r\n            break;\r\n        case 2:\r\n            response.responseType = ResponseType.GENERIC_CONFIGURATION_GET\r\n            response.genericConfigurationGet = determineResponseGenericConfigurationGet(payload.slice(startingByte+1))\r\n            break;\r\n        case 3:\r\n            response.responseType = ResponseType.PARAM_CLASS_CONFIGURATION_GET\r\n            response.parameterClassConfigurationGet = determineResponseParameterClassConfigurationGet(payload.slice(startingByte+1))\r\n            break;\r\n        case 4:\r\n            response.responseType = ResponseType.BLE_STATUS_CONNECTIVITY\r\n            response.bleStatusConnectivity = decodeBLEStatus(payload.slice(startingByte+1))\r\n            break;\r\n        case 5:\r\n            response.responseType = ResponseType.CRC_CONFIGURATION_REQUEST\r\n            response.crc = decodeBitmapAndCRC(payload.slice(startingByte+1,startingByte+3),payload.slice(startingByte+3))\r\n            break;\r\n        case 6:\r\n            response.responseType = ResponseType.SENSOR_REQUEST\r\n            response.sensors = decodeSensorResponse(payload.slice(startingByte+1))\r\n            break;\r\n        default:\r\n            throw new Error(\"Response Type Unknown\");\r\n    }\r\n    return response\r\n\r\n}\r\nfunction decodeSensorResponse(data) {\r\n    let offset = 0;\r\n    const sensors = [];\r\n\r\n    while (offset < data.length) {\r\n        // Read the sensor ID (1 byte)\r\n        const sensorId = data[offset];\r\n        offset += 1;\r\n\r\n        // Determine the sensor type and decode its value\r\n        switch (sensorId) {\r\n            case 1: // Accelerometer\r\n                if (offset + 6 > data.length) {\r\n                    throw new Error(\"Incomplete accelerometer data\");\r\n                }\r\n                // Pass the correct offsets for X, Y, Z values\r\n                const accelerationVector = accelerometer.determineAccelerationVector(\r\n                    data.slice(offset - 1, offset + 6), // Payload slice\r\n                    1, // X starts at byte 1 (relative to the slice)\r\n                    3, // Y starts at byte 3 (relative to the slice)\r\n                    5  // Z starts at byte 5 (relative to the slice)\r\n                );\r\n                sensors.push({\r\n                    sensorId,\r\n                    type: \"ACCELEROMETER\",\r\n                    accelerationVector: [\r\n                        accelerationVector[0],\r\n                        accelerationVector[1],\r\n                        accelerationVector[2]\r\n                    ]\r\n                });\r\n                offset += 6; // Move offset by 6 bytes (X, Y, Z values)\r\n                break;\r\n\r\n            // Add cases for other sensor types here\r\n            // Example:\r\n            // case 2: // Another sensor type\r\n            //     ...\r\n\r\n            case 0: // Do not use\r\n                break;\r\n\r\n            default:\r\n                throw new Error(`Unknown sensor ID: ${sensorId}`);\r\n        }\r\n    }\r\n\r\n    return sensors;\r\n}\r\n\r\nfunction decodeBitmapAndCRC(bitmap, crcBytes) {\r\n    // Helper function to decode group type\r\n    function decodeGroupType(groupIdentifier) {\r\n        switch (groupIdentifier) {\r\n            case 0: return \"INTERNAL\";\r\n            case 1: return \"SYSTEM_CORE\";\r\n            case 2: return \"GEOLOC\";\r\n            case 3: return \"GNSS\";\r\n            case 4: return \"LR11xx\";\r\n            case 5: return \"BLE_SCAN1\";\r\n            case 6: return \"BLE_SCAN2\";\r\n            case 7: return \"ACCELEROMETER\";\r\n            case 8: return \"NETWORK\";\r\n            case 9: return \"LORAWAN\";\r\n            case 10: return \"CELLULAR\";\r\n            case 11: return \"BLE\";\r\n            default: throw new Error(\"Unknown group identifier\");\r\n        }\r\n    }\r\n    // Check if the bitmap is null or [0, 0]\r\n    const isGlobalCRC = (Array.isArray(bitmap) && bitmap.length === 2 && bitmap[0] === 0 && bitmap[1] === 0);\r\n    if (isGlobalCRC) {\r\n        // Global CRC case (4 bytes)\r\n        if (crcBytes.length !== 4) {\r\n            throw new Error(\"Invalid global CRC length. Expected 4 bytes.\");\r\n        }\r\n        const crcHex = Buffer.from(crcBytes).toString('hex').toUpperCase();\r\n        return [`Global CRC: 0x${crcHex}`];\r\n    } else {\r\n        // Group CRC case (bitmap is not null)\r\n        // Extract requested groups from the bitmap\r\n        const requestedGroups = [];\r\n           // Convert 2-byte array into an integer\r\n        bitmap = (bitmap[0] << 8) | bitmap[1];\r\n        for (let i = 0; i < 32; i++) { // Assuming up to 32 groups\r\n            if (bitmap & (1 << i)) {\r\n                requestedGroups.push(i);\r\n            }\r\n        }\r\n        // Check if the number of CRCs matches the number of requested groups\r\n        if (crcBytes.length !== requestedGroups.length * 3) {\r\n            throw new Error(\"CRC bytes length does not match the number of requested groups.\");\r\n        }\r\n\r\n        // Map CRCs to groups\r\n        const result = [];\r\n        for (let i = 0; i < requestedGroups.length; i++) {\r\n            const groupIdentifier = requestedGroups[i];\r\n            const groupName = decodeGroupType(groupIdentifier);\r\n            const crcStartIndex = i * 3;\r\n            const crcHex = Buffer.from(crcBytes.slice(crcStartIndex, crcStartIndex + 3)).toString('hex').toUpperCase();\r\n            result.push(`${groupName}: 0x${crcHex}`);\r\n        }\r\n\r\n        return result;\r\n    }\r\n}\r\n\r\nfunction decodeBLEStatus(bleStatusConnectivity) {\r\n    switch (bleStatusConnectivity) {\r\n        case 0:\r\n            return \"IDLE\";\r\n        case 1:\r\n            return \"ADVERTISING\";\r\n        case 2:\r\n            return \"CONNECTED\";\r\n        case 3:\r\n            return \"BONDED\";\r\n        default:\r\n            return \"UNKNOWN\";\r\n    }\r\n}\r\nfunction decodeCrc(payload, startingByte, byteNumber) {\r\n    // Ensure the payload has enough bytes for the CRC\r\n    if (payload.length < startingByte + byteNumber) {\r\n        throw new Error(\"Payload is too short to contain a valid CRC.\");\r\n    }\r\n\r\n    // Extract the n bytes of the CRC (big-endian)\r\n    const crcBytes = payload.slice(startingByte, startingByte + byteNumber);\r\n    // Convert each byte to a 2-digit hexadecimal string and concatenate\r\n    const crc = crcBytes.map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\r\n    return crc;\r\n}\r\n\r\nfunction determineResponseGenericConfigurationSet(payload){\r\n\r\n    let i = 0;\r\n    const step = 3;\r\n    let response = []\r\n    while (payload.length >= step * (i + 1)) {\r\n        let groupId = payload[i*step]\r\n        let localId = payload[1+i*step]\r\n        let parameter = getParameterByGroupIdAndLocalId(parametersByGroupIdAndLocalId, groupId, localId)\r\n        let status = determineStatusType(payload[2+i*step])\r\n        let group = determineGroupType(groupId)\r\n        // Find the group in the response object or create a new one if it doesn't exist\r\n        let groupObject = response.find(g => g.group === group);\r\n        if (!groupObject) {\r\n            groupObject = { group: group, parameters: [] };\r\n            response.push(groupObject);\r\n        }\r\n\r\n        // Add the parameter to the group's parameters array\r\n        groupObject.parameters.push({\r\n            parameterName: parameter.driverParameterName,\r\n            status: status\r\n        });\r\n\r\n    i++;\r\n    }\r\n    return response\r\n}\r\nfunction determineResponseGenericConfigurationGet(payload){\r\n    let i = 0;\r\n    let response = []\r\n    while (payload.length > i) {\r\n        let groupId = payload[i]\r\n        let localId = payload[1+i]\r\n        let size = payload[2+i]>>3 & 0x1F;\r\n        let dataType = payload[2+i] & 0x07;\r\n        let parameter = getParameterByGroupIdAndLocalId(parametersByGroupIdAndLocalId, groupId, localId)\r\n        switch(dataType){\r\n            case 0: \r\n                determineDeprecatedResponse(response, parameter,groupId)\r\n                break;\r\n            case 1:\r\n                determineConfiguration(response, parameter,  parseInt(util.convertBytesToString(payload.slice(3+i,3+i+size)),16), groupId, size)\r\n                break;\r\n            case 2:\r\n                //TO BE COMPLTED\r\n                break;\r\n            case 3:\r\n                determineConfiguration(response, parameter,  payload.slice(3+i,3+i+size), groupId, size)\r\n                break;\r\n            case 4:\r\n                determineConfiguration(response, parameter,  payload.slice(3+i,3+i+size), groupId, size)\r\n                break; \r\n            case 5:\r\n                determineErrorResponse(response, parameter,groupId)\r\n                break;\r\n        }\r\n        i = i + size + 3 \r\n    }\r\n    return response\r\n}\r\nfunction determineErrorResponse(response, parameter, groupId) {\r\n    let group = determineGroupType(groupId)\r\n    let paramName = parameter.driverParameterName\r\n    // Find the group in the response object or create a new one if it doesn't exist\r\n    let groupObject = response.find(g => g.group === group);\r\n    if (!groupObject) {\r\n        groupObject = { group: group, parameters: [] };\r\n        response.push(groupObject);\r\n    }\r\n\r\n    // Add the parameter to the group's parameters array\r\n    groupObject.parameters.push({\r\n        parameterName: paramName,\r\n        parameterValue: \"ERROR\"\r\n    });\r\n}\r\nfunction determineDeprecatedResponse(response, parameter, groupId) {\r\n    let group = determineGroupType(groupId)\r\n    let paramName = parameter.driverParameterName\r\n    // Find the group in the response object or create a new one if it doesn't exist\r\n    let groupObject = response.find(g => g.group === group);\r\n    if (!groupObject) {\r\n        groupObject = { group: group, parameters: [] };\r\n        response.push(groupObject);\r\n    }\r\n\r\n    // Add the parameter to the group's parameters array\r\n    groupObject.parameters.push({\r\n        parameterName: paramName,\r\n        parameterValue: \"DEPRECATED\"\r\n    });\r\n}\r\nfunction determineConfiguration(response, parameter, paramValue, groupId, parameterSize){\r\n    let group = determineGroupType(groupId)\r\n    let groupObject\r\n    let paramName = parameter.driverParameterName\r\n    let paramType = parameter.parameterType.type\r\n    switch (paramType)\r\n    {\r\n    // it can be integer or float\r\n    case \"ParameterTypeNumber\":{\r\n        let range = parameter.parameterType.range\r\n        let multiply = parameter.parameterType.multiply\r\n        let additionalValues = parameter.parameterType.additionalValues\r\n        let additionalRanges = parameter.parameterType.additionalRanges\r\n        // check negative number\r\n        if ((range.minimum < 0 ) || util.hasNegativeNumber(additionalValues) || util.hasNegativeNumber(additionalRanges)){\r\n            if (paramValue > 0x7FFFFFFF) {\r\n             paramValue -= 0x100000000;\r\n         }\r\n        }\r\n        if (util.checkParamValueRange(paramValue, range.minimum, range.maximum, range.exclusiveMinimum, range.exclusiveMaximum, additionalValues, additionalRanges)){\r\n            if (multiply != undefined){\r\n                paramValue = paramValue * multiply\r\n            }\r\n             \r\n        }\r\n        else {\r\n            throw new Error(paramName+ \" parameter value is out of range\");\r\n        }\r\n        \r\n        // Find the group in the response object or create a new one if it doesn't exist\r\n        groupObject = response.find(g => g.group === group);\r\n        if (!groupObject) {\r\n            groupObject = { group: group, parameters: [] };\r\n            response.push(groupObject);\r\n        }\r\n\r\n        // Add the parameter to the group's parameters array\r\n        groupObject.parameters.push({\r\n            parameterName: paramName,\r\n            parameterValue: paramValue\r\n        });}\r\n        break;\r\n    // A mapping between the firmware values and the possible string values\r\n    case \"ParameterTypeString\":\r\n        if ((parameter.parameterType.firmwareValues).indexOf(paramValue) != -1){\r\n            // Find the group in the response object or create a new one if it doesn't exist\r\n            groupObject = response.find(g => g.group === group);\r\n            if (!groupObject) {\r\n                groupObject = { group: group, parameters: [] };\r\n                response.push(groupObject);\r\n            }\r\n\r\n            // Add the parameter to the group's parameters array\r\n            groupObject.parameters.push({\r\n                parameterName: paramName,\r\n                parameterValue: parameter.parameterType.possibleValues[((parameter.parameterType.firmwareValues).indexOf(paramValue))]\r\n            });\r\n     }\r\n        else {\r\n            throw new Error(paramName+ \" parameter value is unknown\");\r\n        }\r\n        \r\n        break;\r\n    case \"ParameterTypeBitMask\":{\r\n        let properties = parameter.parameterType.properties\r\n        let bitMask = parameter.parameterType.bitMask\r\n        let length = parseInt(1,16)\r\n        let parameterValue ={}\r\n        for (let property  of properties) {\r\n            let propertyName = property.name\r\n            let propertyType = property.type\r\n            let bit = bitMask.find(el => el.valueFor === propertyName)\r\n            switch (propertyType)\r\n            {\r\n                case \"PropertyBoolean\":\r\n                    if ((bit.length)!= undefined ) {\r\n                        length = util.lengthToHex(bit.length)\r\n                    }\r\n                    var b =  Boolean((paramValue >>bit.bitShift & length ))\r\n                    if ((bit.inverted != undefined) && (bit.inverted)){\r\n                        b =!b;\r\n                    }\r\n                    parameterValue[property.name] = b\r\n                    break;\r\n                case \"PropertyString\":{\r\n                    if ((bit.length)!= undefined ) {\r\n                        length = util.lengthToHex(bit.length)\r\n                    }\r\n                    let value = (paramValue >>bit.bitShift & length)\r\n                        let possibleValues = property.possibleValues\r\n                    if (property.firmwareValues.indexOf(value) != -1){\r\n                        parameterValue[property.name] = possibleValues[(property.firmwareValues.indexOf(value))]\r\n                    }\r\n                    else {\r\n                        throw new Error(property.name+ \" parameter value is not among possible values\");\r\n                    }       \r\n                }break;\r\n                case \"PropertyNumber\":\r\n                    if ((bit.length)!= undefined ) {\r\n                        length = util.lengthToHex(bit.length)\r\n                    }\r\n                    parameterValue[property.name] = paramValue >>bit.bitShift & length ;\t\r\n\r\n                    break;\r\n                case \"PropertyObject\":{\r\n                    let bitValue ={}\r\n                    for (let value of bit.values)\r\n                        {\r\n                        if (value.type == \"BitMaskValue\")\r\n                            {\t\r\n                                let length = parseInt(1,16)\r\n                                if ((value.length)!= undefined ) {length = (util.lengthToHex(value.length))}\r\n                                var b = Boolean(paramValue >>value.bitShift & length)\r\n                                if ((value.inverted != undefined) && (value.inverted)){\r\n                                    b =!b;\r\n                                }\r\n                                bitValue[value.valueFor] = b\r\n                            }\r\n                        }\r\n                    parameterValue[property.name] = bitValue\r\n                }break;\r\n                default:\r\n                    throw new Error(\"Property type is unknown\");\r\n                    \r\n                }\r\n            }\r\n \r\n           // Find the group in the response object or create a new one if it doesn't exist\r\n        groupObject = response.find(g => g.group === group);\r\n        if (!groupObject) {\r\n            groupObject = { group: group, parameters: [] };\r\n            response.push(groupObject);\r\n        }\r\n\r\n        // Add the parameter to the group's parameters array\r\n        groupObject.parameters.push({\r\n            parameterName: paramName,\r\n            parameterValue: parameterValue\r\n        });}\r\n        break;\r\n    case \"ParameterTypeByteArray\":{\r\n        if (parameter.parameterType.size != undefined && parameter.parameterType.size != parameterSize) {\r\n            throw new Error(\"The value of \"+ paramName + \" must have \"+ parameter.parameterType.size.toString() +\" bytes in the array\");\r\n        }\r\n        var bytesValue\r\n        if  (parameter.parameterType.properties == undefined){\r\n            // Convert the array values to hexadecimal and store them in a string format\r\n            bytesValue = '{' + paramValue.map(value => {\r\n            // Convert each value to hexadecimal and ensure it has two digits\r\n            return value.toString(16).padStart(2, '0');\r\n            }).join(',') + '}';\r\n\r\n        }else{\r\n            let arrayProperties = parameter.parameterType.properties;\r\n            let byteMap = parameter.parameterType.byteMask;\r\n           \r\n            let arrayLength = parseInt(1, 16);\r\n            \r\n            bytesValue = [];\r\n            for (let i = 0; i < parameterSize; i++) {\r\n                let currentParamValue = paramValue[i];\r\n                if (parameter.parameterType.distinctValues !== undefined && parameter.parameterType.distinctValues === true) {\r\n                    // Handling distinct values of byte array\r\n                    let property = arrayProperties[i];\r\n                    let propertyName = property.name;\r\n                    let propertyValues = {}; // Store values for the current property\r\n                    let bitMapping = byteMap.find(el => el.valueFor === propertyName);\r\n                    if (!bitMapping) continue; // Skip if no bit mapping exists for this property\r\n                    for (let subProperty of property.properties) {\r\n                        let subPropertyName = subProperty.name;\r\n                        let subPropertyType = subProperty.type;\r\n                        let bitValueMapping = bitMapping.values.find(val => val.valueFor === subPropertyName);\r\n                        if (!bitValueMapping) continue; // Skip if no bit mapping exists for this sub-property\r\n                        let bitShift = bitValueMapping.bitShift;\r\n                        let lengthMask = (1 << bitValueMapping.length) - 1;\r\n                        let extractedValue = (currentParamValue >> bitShift) & lengthMask;\r\n                        switch (subPropertyType) {\r\n                            case \"PropertyBoolean\":{\r\n                                let booleanValue = Boolean(extractedValue);\r\n                                if (bitValueMapping.inverted) booleanValue = !booleanValue;\r\n                                propertyValues[subPropertyName] = booleanValue;\r\n                            }break;\r\n                            case \"PropertyString\":{\r\n                                let strIndex = subProperty.firmwareValues.indexOf(extractedValue);\r\n                                if (strIndex !== -1) {\r\n                                    propertyValues[subPropertyName] = subProperty.possibleValues[strIndex];\r\n                                } else {\r\n                                    throw new Error(`${subPropertyName} value not among possible values`);\r\n                                }\r\n                            }break;\r\n                            case \"PropertyNumber\":\r\n                                propertyValues[subPropertyName] = extractedValue;\r\n                                break;\r\n                            default:\r\n                                throw new Error(\"Unknown sub-property type\");\r\n                        }\r\n                    }\r\n                    bytesValue.push({ [propertyName]: propertyValues });\r\n\r\n                } else {\r\n                    // Handling non-distinct values of byte array\r\n                    let arrayParameterValue = {};\r\n                    for (let py of arrayProperties) {\r\n                        let propertyName = py.name;\r\n                        let propertyType = py.type;\r\n                        let bit = byteMap.find(el => el.valueFor === propertyName);\r\n                        if (!bit) continue; // Skip if no bit mapping exists for this property\r\n                        if (bit.length !== undefined) {\r\n                            arrayLength = util.lengthToHex(bit.length);\r\n                        }\r\n                        switch (propertyType) {\r\n                            case \"PropertyBoolean\":\r\n                                let booleanValue = Boolean((currentParamValue >> bit.bitShift) & arrayLength);\r\n                                if (bit.inverted) booleanValue = !booleanValue;\r\n                                arrayParameterValue[propertyName] = booleanValue;\r\n                                break;\r\n                            case \"PropertyString\":{\r\n                                let stringValue = (currentParamValue >> bit.bitShift) & arrayLength;\r\n                                let possibleValues = py.possibleValues;\r\n                                if (py.firmwareValues.indexOf(stringValue) !== -1) {\r\n                                    arrayParameterValue[propertyName] = possibleValues[py.firmwareValues.indexOf(stringValue)];\r\n                                } else {\r\n                                    throw new Error(`${propertyName} value not among possible values`);\r\n                                }\r\n                            }break;\r\n                            case \"PropertyNumber\":\r\n                                arrayParameterValue[propertyName] = (currentParamValue >> bit.bitShift) & arrayLength;\r\n                                break;\r\n                            case \"PropertyObject\":{\r\n                                let bitValue = {};\r\n                                for (let value of bit.values) {\r\n                                    if (value.type === \"BitMapValue\") {\r\n                                        let subArrayLength = parseInt(1, 16);\r\n                                        if (value.length !== undefined) {\r\n                                            subArrayLength = util.lengthToHex(value.length);\r\n                                        }\r\n                                        let subBooleanValue = Boolean((currentParamValue >> value.bitShift) & subArrayLength);\r\n                                        if (value.inverted) subBooleanValue = !subBooleanValue;\r\n                                        bitValue[value.valueFor] = subBooleanValue;\r\n                                    }\r\n                                }\r\n                                arrayParameterValue[propertyName] = bitValue;\r\n                            }break;\r\n                            case \"PropertByteArray\":{\r\n                                let byteMask = py.bitMask;\r\n                                if (py.size && py.size > 0) {\r\n                                    let  currentParamArrayValue = [];\r\n                                    for (let j = 0; j < py.size; j++) {\r\n                                        if (i + j >= paramValue.length) {\r\n                                            throw new Error(\"Parameter size exceeds available data\");\r\n                                        }\r\n                                        currentParamArrayValue.push(paramValue[i + j]);\r\n                                    }\r\n                                \r\n                                let decodedValues = {};\r\n                                decodedValues = handleArrayProperties(py.properties,byteMask, currentParamArrayValue)\r\n                                arrayParameterValue[propertyName] = decodedValues;\r\n                                i += py.size - 1;\r\n                                } else {\r\n                                    throw new Error(`Invalid size for PropertyByteArray in property ${propertyName}`);\r\n                                }\r\n                            }break;\r\n                            default:\r\n                                throw new Error(\"Unknown property type\");\r\n                        }\r\n                    }\r\n                    bytesValue.push(arrayParameterValue);\r\n                }\r\n            }\r\n        }\r\n        // Find the group in the response object or create a new one if it doesn't exist\r\n    groupObject = response.find(g => g.group === group);\r\n    if (!groupObject) {\r\n        groupObject = { group: group, parameters: [] };\r\n        response.push(groupObject);\r\n    }\r\n\r\n    // Add the parameter to the group's parameters array\r\n    groupObject.parameters.push({\r\n        parameterName: paramName,\r\n        parameterValue: bytesValue\r\n    });}break;\r\n    case \"ParameterTypeAsciiString\":\r\n        var paramAsciiString = \"\";\r\n    \r\n\t    for (var i = 0; i < paramValue.length; i ++)\r\n            paramAsciiString += String.fromCharCode(paramValue[i]);\r\n    \r\n        // Find the group in the response object or create a new one if it doesn't exist\r\n    groupObject = response.find(g => g.group === group);\r\n    if (!groupObject) {\r\n        groupObject = { group: group, parameters: [] };\r\n        response.push(groupObject);\r\n    }\r\n\r\n    // Add the parameter to the group's parameters array\r\n    groupObject.parameters.push({\r\n        parameterName: paramName,\r\n        parameterValue: paramAsciiString\r\n    });\r\n    break;\r\n    default:\r\n     throw new Error(\"Parameter type is unknown\");\r\n    }\r\n}\r\nfunction handleArrayProperties(properties, bitMask, paramValueArray) {\r\n    let parameterValue = {};\r\n    for (let property of properties) {\r\n      let propertyName = property.name;\r\n      let propertyType = property.type;\r\n      let bit = bitMask.find((el) => el.valueFor === propertyName);\r\n  \r\n      if (!bit) {\r\n        continue;\r\n      }\r\n      const mask = (1 << bit.length) - 1; \r\n  \r\n      // Extract the value by shifting and masking\r\n      let paramValue = extractSingleByte(paramValueArray, bit.bitShift);\r\n      const value = (paramValue >> bit.bitShift % 8) & mask;\r\n  \r\n      switch (propertyType) {\r\n        case \"PropertyBoolean\":\r\n          let booleanValue = Boolean(value);\r\n          if (bit.inverted) booleanValue = !booleanValue;\r\n          parameterValue[propertyName] = booleanValue;\r\n          break;\r\n  \r\n        case \"PropertyString\":{\r\n          const possibleValues = property.possibleValues || [];\r\n          const firmwareValues = property.firmwareValues || [];\r\n          const index = firmwareValues.indexOf(value);\r\n          if (index !== -1) {\r\n            parameterValue[propertyName] = possibleValues[index];\r\n          } else {\r\n            throw new Error(\r\n              `${propertyName} value (${value}) is not among possible values`,\r\n            );\r\n          }\r\n        }break;\r\n  \r\n        case \"PropertyNumber\":\r\n          parameterValue[propertyName] = value; // Directly assign the extracted value\r\n          break;\r\n  \r\n        default:\r\n            throw new Error(\r\n                `Unsupported property type: ${propertyType}`);\r\n      }\r\n    }\r\n    return parameterValue;\r\n  }\r\n  \r\n  function extractSingleByte(paramValueArray, bitLength) {\r\n    let byteIndex = 0;\r\n  \r\n    // Si la longueur des bits est plus grande que 8, il faut extraire le ou les octets nécessaires\r\n    if (bitLength >= 8) {\r\n      // Calculer l'index de l'octet à extraire\r\n      byteIndex = Math.floor(bitLength / 8); // Chaque octet fait 8 bits, donc on choisit l'indice en fonction de la longueur des bits\r\n    }\r\n  \r\n    // Extraire l'octet spécifique\r\n    return paramValueArray[byteIndex];\r\n  } \r\nfunction determineResponseParameterClassConfigurationGet(payload){\r\n    let groupId = payload[0]\r\n    let i = 1;\r\n    let response = []\r\n    while (payload.length > i) {\r\n        let localId = payload[i]\r\n        let size = payload[1+i]>>3 & 0x1F;\r\n        let dataType = payload[1+i] & 0x07;\r\n        let parameter = getParameterByGroupIdAndLocalId(parametersByGroupIdAndLocalId, groupId, localId)\r\n        switch(dataType){\r\n            case 0: \r\n                determineDeprecatedResponse(response, parameter,groupId)\r\n                break;\r\n            case 1:\r\n                determineConfiguration(response, parameter,  parseInt(util.convertBytesToString(payload.slice(2+i,2+i+size)),16), groupId)\r\n                break;\r\n            case 2:\r\n                //TO be complted\r\n                break;\r\n            case 3:\r\n                determineConfiguration(response, parameter,  payload.slice(2+i,2+i+size), groupId, size)\r\n                break; \r\n            case 4:\r\n                determineConfiguration(response, parameter,  payload.slice(2+i,2+i+size), groupId, size)\r\n                break; \r\n            case 5:\r\n                determineErrorResponse(response, parameter,groupId)\r\n                break;\r\n\r\n        }\r\n        i = i + size + 2\r\n        }\r\n        return response\r\n}\r\nfunction determineResponseParameterClassConfigurationSet(payload){\r\n    let groupId = payload[0]\r\n    payload = payload.slice(4)\r\n    let i = 0;\r\n    const step = 2;\r\n    let parameters = [];\r\n    while (payload.length >= step * (i + 1)) {\r\n        let parameter = getParameterByGroupIdAndLocalId(parametersByGroupIdAndLocalId, groupId, payload[i*step])\r\n        parameters.push({\r\n            parameterName : parameter.driverParameterName,\r\n            status: determineStatusType(payload[1+i*step])\r\n        })\r\n        i++;\r\n    }\r\n    return new ParameterClassConfigurationSet(determineGroupType(groupId), parameters)\r\n}\r\n\r\nfunction determineStatusType(value){\r\n    switch(value){\r\n        case 0 :\r\n            return StatusType.SUCCESS\r\n        case 1:\r\n            return StatusType.NOT_FOUND\r\n        case 2:\r\n            return StatusType.BELOW_LOWER_BOUND\r\n        case 3:\r\n            return StatusType.ABOVE_HIGHER_BOUND\r\n        case 4:\r\n            return StatusType.BAD_VALUE\r\n        case 5:\r\n            return StatusType.TYPE_MISMATCH\r\n        case 6:\r\n            return StatusType.OPERATION_ERROR\r\n        default:\r\n          throw new Error(\"Status Type Unknown\");\r\n    }\r\n}\r\n\r\nfunction determineGroupType(value)\r\n{  \r\n    switch(value){\r\n        case 0: \r\n            return GroupType.INTERNAL\r\n        case 1:\r\n            return GroupType.SYSTEM_CORE\r\n        case 2:\r\n            return GroupType.GEOLOC\r\n        case 3:\r\n            return GroupType.GNSS\r\n        case 4:\r\n            return GroupType.LR11xx\r\n        case 5:\r\n            return GroupType.BLE_SCAN1\r\n        case 6: \r\n            return GroupType.BLE_SCAN2\r\n        case 7:\r\n            return GroupType.ACCELEROMETER\r\n        case 8:\r\n            return GroupType.NETWORK\r\n        case 9:\r\n            return GroupType.LORAWAN\r\n        case 10: \r\n            return GroupType.CELLULAR\r\n        case 11:\r\n            return GroupType.BLE\r\n        default:\r\n            throw new Error(\"Unknown group\")\r\n    }\r\n}\r\n// Function to create the nested data structure\r\nfunction jsonParametersByGroupIdAndLocalId() {\r\n    // Initialize an empty object to store parameters grouped by groupId and localId\r\n    let parametersByGroupIdAndLocalId = {};\r\n\r\n    // Iterate over each entry in the JSON parameters array\r\n    jsonParameters.forEach(entry => {\r\n        // Iterate over each firmware parameter within the entry\r\n        entry.firmwareParameters.forEach(parameter => {\r\n            // Convert hexadecimal strings to integers for groupId and localId\r\n            let groupId = parseInt(parameter.groupId, 16);\r\n            let localId = parseInt(parameter.localId, 16);\r\n\r\n            // Check if the groupId exists in the parametersByGroupIdAndLocalId object\r\n            if (!parametersByGroupIdAndLocalId[groupId]) {\r\n                // If not, create an empty object for the groupId\r\n                parametersByGroupIdAndLocalId[groupId] = {};\r\n            }\r\n\r\n            // Check if the localId exists within the groupId object\r\n            if (!parametersByGroupIdAndLocalId[groupId][localId]) {\r\n                // If not, create an empty object for the localId\r\n                parametersByGroupIdAndLocalId[groupId][localId] = {};\r\n            }\r\n\r\n            // Store the parameter object within the groupId and localId\r\n            parametersByGroupIdAndLocalId[groupId][localId] = parameter;\r\n        });\r\n    });\r\n\r\n    // Return the nested data structure\r\n    return parametersByGroupIdAndLocalId;\r\n}\r\n\r\n// Function to get a parameter by groupId and localId\r\nfunction getParameterByGroupIdAndLocalId(parameters, groupId, localId) {\r\n    // Check if the parameters object contains the groupId\r\n    // and if the groupId object contains the localId\r\n    if (parameters[groupId] && parameters[groupId][localId]) {\r\n        return parameters[groupId][localId];\r\n    } else {\r\n        return null;\r\n    }\r\n}\r\n\r\n//create the nested data structure\r\nconst parametersByGroupIdAndLocalId = jsonParametersByGroupIdAndLocalId();\r\n\r\nmodule.exports = {\r\n    Response: Response,\r\n    ResponseType : ResponseType,\r\n    determineResponse: determineResponse,\r\n    determineConfiguration: determineConfiguration,\r\n    parametersByGroupIdAndLocalId: parametersByGroupIdAndLocalId,\r\n    getParameterByGroupIdAndLocalId: getParameterByGroupIdAndLocalId,\r\n    determineGroupType:determineGroupType,\r\n    GroupType: GroupType\r\n\r\n}\r\n\r\n\r\n/***/ }),\r\n\r\n/***/ 320:\r\n/***/ ((module) => {\r\n\r\nfunction BeaconIdInfo(id,\r\n    rssi\r\n){\r\n    this.id = id;\r\n    this.rssi = rssi;\r\n}\r\nfunction BeaconMacInfo(mac,\r\n    rssi\r\n){\r\n    this.mac = mac;\r\n    this.rssi = rssi;\r\n}\r\n\r\n\r\n\r\nmodule.exports = {\r\n    BeaconIdInfo: BeaconIdInfo, \t\r\n    BeaconMacInfo: BeaconMacInfo\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 343:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet util = __webpack_require__(94);\r\n\r\nconst TelemetryType = Object.freeze({\r\n    TELEMETRY: \"TELEMETRY\",\r\n    TELEMETRY_MODE_BATCH: \"TELEMETRY_MODE_BATCH\"\r\n})\r\n// for more details to telemetry refer to https://github.com/actility/device-catalog/blob/main/template/sample-vendor/drivers/ONTOLOGY.md\r\nconst OntologyConstants = Object.freeze({\r\n    RESISTANCE: {\r\n        id: 1,\r\n        ontology: \"resistance\",\r\n        type: \"int16\",\r\n        unit: \"Ohm\"\r\n    },\r\n    TEMPERATURE: {\r\n        id: 2,\r\n        ontology: \"temperature\",\r\n        type: \"float\",\r\n        unit: \"Cel\"\r\n    },\r\n    HUMIDITY: {\r\n        id: 3,\r\n        ontology: \"humidity\",\r\n        type: \"int16\",\r\n        unit: \"%RH\", \r\n        factor: 10\r\n    }\r\n});\r\n\r\n// Construct counters based on OntologyConstants\r\nconst counters = Object.keys(OntologyConstants).reduce((acc, key) => {\r\n    const ontology = OntologyConstants[key];\r\n    acc[ontology.ontology] = 0;\r\n    return acc;\r\n}, {});\r\n\r\nfunction floatFromBytes(bytes) {\r\n    const buffer = new ArrayBuffer(4);\r\n    const view = new DataView(buffer);\r\n    for (let i = 0; i < 4; i++) {\r\n        view.setUint8(i, bytes[i]);\r\n    }\r\n    return view.getFloat32(0, false); // true for little-endian\r\n}\r\nfunction formatFloat(float, decimals = 2) {\r\n    return Number(float.toFixed(decimals));\r\n}\r\n\r\nfunction determineTelemetryMeasurements(data) {\r\n    let index = 0;\r\n    const ontologies = {};\r\n    const dataLength = data.length;\r\n    while (index < dataLength) {\r\n        if (index >= dataLength) {\r\n            throw new Error(\"Unexpected end of data.\");\r\n        }\r\n        let ontology = determineOntology(data[index] & 0x7F);\r\n        let valueSize = (data[index] >> 7) & 0x01;\r\n        let value;\r\n        if (ontology.type === 'float') {\r\n            if (valueSize === 1) {\r\n                if (index + 4 >= dataLength) {\r\n                    throw new Error(\"Not enough data for a 4-byte float.\");\r\n                }\r\n                value = floatFromBytes(data.slice(index + 1, index + 5));\r\n                value = formatFloat(value);\r\n                index += 5; // Move to the next data element\r\n            } else {\r\n                throw new Error(\"Unexpected value size for float.\");\r\n            }\r\n            \r\n        } else {\r\n            if (valueSize === 1) {\r\n                throw new Error(\"Unexpected value size for int.\");\r\n            }\r\n            if (index + 2 >= dataLength) {\r\n                throw new Error(\"Not enough data for a 2-byte value.\");\r\n            }\r\n            value = util.convertNegativeInt((data[index + 1] << 8) + data[index + 2],2);\r\n            index += 3; // Move to the next data element\r\n        }\r\n\r\n        const ontologyName = ontology.ontology;\r\n        const unit = ontology.unit;\r\n        const counter = counters[ontologyName];\r\n        const key = `${ontologyName}:${counter}`;\r\n\r\n        // Add the telemetry measurement to the result\r\n        ontologies[key] = { unitId: unit, record: value };\r\n\r\n        // Update the counter\r\n        counters[ontologyName]++;\r\n    }\r\n    Object.keys(ontologies).forEach(key => {\r\n        const baseKey = key.split(':')[0];\r\n        if (counters[baseKey] === 1) {\r\n            const value = ontologies[key];\r\n            delete ontologies[key];\r\n            ontologies[baseKey] = value;\r\n        }\r\n    });\r\n    return ontologies;\r\n}\r\n\r\nfunction determineOntology(value) {\r\n    const ontology = Object.values(OntologyConstants).find(o => o.id === value);\r\n    if (ontology) {\r\n        return ontology;\r\n    } else {\r\n        throw new Error(\"Ontology Unknown\");\r\n    }\r\n}\r\n\r\n\r\nmodule.exports = {\r\n    TelemetryType: TelemetryType,\r\n    determineTelemetryMeasurements: determineTelemetryMeasurements\r\n}\r\n\r\n\r\n/***/ }),\r\n\r\n/***/ 351:\r\n/***/ ((module) => {\r\n\r\nconst Constellation = Object.freeze({\r\n    GPS: \"GPS\",\r\n    BEIDOU: \"BEIDOU\"\r\n})\r\n\r\nconst CN = Object.freeze({\r\n    0: \">45dB\",\r\n    1: \"[41..45]dB\",\r\n    2: \"[37..41]dB\",\r\n    3: \"<37dB\"\r\n})\r\n\r\nfunction SatelliteInfo(constellation,\r\n    id,\r\n    cn,\r\n    pseudoRangeValue\r\n){\r\n    this.constellation = constellation;\r\n    this.id = id;\r\n    this.cn = cn;\r\n    this.pseudoRangeValue = pseudoRangeValue;\r\n}\r\n\r\nmodule.exports = {\r\n    SatelliteInfo: SatelliteInfo, \r\n    Constellation: Constellation,\r\n    CN: CN\t\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 406:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet util = __webpack_require__(94);\r\n\r\nconst TempType = Object.freeze({\r\n    TEMP_HIGH: \"TEMP_HIGH\",\r\n    TEMP_LOW: \"TEMP_LOW\",\r\n    TEMP_NORMAL: \"TEMP_NORMAL\"\r\n})\r\n\r\n\r\nfunction determineTemperature(payload){\r\n    return util.convertNegativeInt(payload[5],1)\r\n}\r\nmodule.exports = {\r\n    determineTemperature: determineTemperature,\r\n    TempType: TempType\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 457:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet TriggerBitMapClass = __webpack_require__(483);\r\nlet bleClass = __webpack_require__(504);\r\nlet util = __webpack_require__(94);\r\nlet SatelliteInfoClass = __webpack_require__(351);\r\nlet gnssFixClass = __webpack_require__(792)\r\nlet gnssFailureClass = __webpack_require__(541)\r\nlet wifiClass = __webpack_require__(508);\r\nconst gnssFailure = __webpack_require__(541);\r\n//let bssidInfoClass = require(\"./wifi/bssidInfo\")\r\n\r\nconst PositionStatus = Object.freeze({\r\n    SUCCESS: \"SUCCESS\",\r\n    TIMEOUT: \"TIMEOUT\",\r\n    FAILURE: \"FAILURE\",\r\n    NOT_SOLVABLE : \"NOT_SOLVABLE\"\r\n})\r\n\r\nconst PositionType = Object.freeze({\r\n    LR11xx_A_GNSS: \"LR11xx_A_GNSS\",\r\n    LR11xx_GNSS_NAV1: \"LR11xx_GNSS_NAV1\",\r\n    LR11xx_GNSS_NAV2: \"LR11xx_GNSS_NAV2\",\r\n    WIFI: \"WIFI\",\r\n    BLE_SCAN1_MAC: \"BLE_SCAN1_MAC\",\r\n    BLE_SCAN1_SHORT: \"BLE_SCAN1_SHORT\",\r\n    BLE_SCAN1_LONG: \"BLE_SCAN1_LONG\",\r\n    BLE_SCAN2_MAC: \"BLE_SCAN2_MAC\",\r\n    BLE_SCAN2_SHORT: \"BLE_SCAN12_SHORT\",\r\n    BLE_SCAN2_LONG: \"BLE_SCAN2_LONG\",\r\n    GNSS: \"GNSS\",\r\n    AIDED_GNSS: \"AIDED_GNSS\"\r\n})\r\n\r\nfunction Position(motion, motionCounter,\r\n    status,\r\n    positionType,\r\n    triggers,\r\n    lr11xxAGnss,\r\n    lr11xxGnssNav1, \r\n    lr11xxGnssNav2, \r\n    wifiBssids, \r\n    bleBeaconMacs,\r\n    bleBeaconIds,\r\n    gnssFix,\r\n    gnssFailure,\r\n    aidedGnss,\r\n    coordinates){\r\n        this.motion = motion;\r\n        this.motionCounter = motionCounter;\r\n        this.status = status;\r\n        this.positionType = positionType;\r\n        this.triggers = triggers;\r\n        this.lr11xxAGnss = lr11xxAGnss;\r\n        this.lr11xxGnssNav1 = lr11xxGnssNav1;\r\n        this.lr11xxGnssNav2 = lr11xxGnssNav2;\r\n        this.wifiBssids = wifiBssids;\r\n        this.bleBeaconMacs =bleBeaconMacs;\r\n        this.bleBeaconIds = bleBeaconIds;\r\n        this.gnssFix = gnssFix;\r\n        this.gnssFailure = gnssFailure;\r\n        this.aidedGnss = aidedGnss;\r\n        this.coordinates = coordinates;\r\n}\r\n\r\n/************************ Header position decodage *************************/\r\n/********************************************************************/\r\nfunction determinePositionHeader(payload, startingByte){\r\n    let positionMessage = new Position();\r\n    positionMessage.motion = payload[startingByte]>>7 & 0x01;\r\n    var statusValue = payload[startingByte]>>5 & 0x03;\r\n    switch (statusValue){\r\n        case 0:\r\n            positionMessage.status = PositionStatus.SUCCESS;\r\n            break;\r\n        case 1:\r\n            positionMessage.status = PositionStatus.TIMEOUT;\r\n            break;\r\n        case 2:\r\n            positionMessage.status = PositionStatus.FAILURE;\r\n            break;\r\n        case 3:\r\n            positionMessage.status = PositionStatus.NOT_SOLVABLE;\r\n            break;\r\n    }\r\n\r\n    var typeValue = payload[startingByte] & 0x0F;\r\n    switch (typeValue){\r\n        case 0:\r\n            positionMessage.positionType = PositionType.LR11xx_A_GNSS;\r\n            break;\r\n        case 1:\r\n            positionMessage.positionType = PositionType.LR11xx_GNSS_NAV1;\r\n            break;\r\n        case 2:\r\n            positionMessage.positionType = PositionType.LR11xx_GNSS_NAV2;\r\n            break;\r\n        case 3:\r\n            positionMessage.positionType = PositionType.WIFI;\r\n            break;\r\n        case 4:\r\n            positionMessage.positionType = PositionType.BLE_SCAN1_MAC;\r\n            break;\r\n        case 5:\r\n            positionMessage.positionType = PositionType.BLE_SCAN1_SHORT;\r\n            break;\r\n        case 6:\r\n            positionMessage.positionType = PositionType.BLE_SCAN1_LONG;\r\n            break;\r\n        case 7:\r\n            positionMessage.positionType = PositionType.BLE_SCAN2_MAC;\r\n            break;\r\n        case 8:\r\n            positionMessage.positionType = PositionType.BLE_SCAN2_SHORT;\r\n            break;\r\n        case 9:\r\n            positionMessage.positionType = PositionType.BLE_SCAN2_LONG;\r\n            break;\r\n        case 10:\r\n            positionMessage.positionType = PositionType.GNSS;\r\n            break;\r\n        case 11:\r\n            positionMessage.positionType = PositionType.AIDED_GNSS;\r\n            break;\r\n    }\r\n    positionMessage.motionCounter =  payload[startingByte+1]&0x0F;\r\n    positionMessage.triggers = new TriggerBitMapClass.TriggerBitMap(payload[startingByte+3] & 0x01,\r\n        payload[startingByte+3]>>1 & 0x01,\r\n        payload[startingByte+3]>>2 & 0x01,\r\n        payload[startingByte+3]>>3 & 0x01,\r\n        payload[startingByte+3]>>4 & 0x01,\r\n        payload[startingByte+3]>>5 & 0x01,\r\n        payload[startingByte+3]>>6 & 0x01,\r\n        payload[startingByte+3]>>7 & 0x01,\r\n        payload[startingByte+2] & 0x01,\r\n        payload[startingByte+2]>>1 & 0x01\r\n    )\r\n   \r\n    return positionMessage;\r\n}\r\n\r\n\r\n\r\nfunction determineLR1110GnssPositionMessage(payload){\r\n    let lr1110gnss = {};\r\n    lr1110gnss.time = (payload[0] << 8 + payload[1]) * 16;\r\n    var i = 0;\r\n    let satelliteInfos = [];\r\n    while (payload.length >= 2+4*(i+1)){\r\n        var satelliteInfo = new SatelliteInfoClass.SatelliteInfo();\r\n        var c = payload[2+4*i]>>6 & 0x03;\r\n        switch (c){\r\n            case 0:\r\n                satelliteInfo.constellation = SatelliteInfoClass.Constellation.GPS;\r\n                break;\r\n            case 1:\r\n                satelliteInfo.constellation = SatelliteInfoClass.Constellation.BEIDOU;\r\n                break;\r\n        }\r\n        var id = payload[2+4*i] & 0x3F;\r\n        var cnValue = payload[3+4*i]>>6 & 0x03;\r\n        switch (cnValue){\r\n            case 0:\r\n                satelliteInfo.cn = SatelliteInfoClass.CN[0];\r\n                break;\r\n            case 1:\r\n                satelliteInfo.cn = SatelliteInfoClass.CN[1];\r\n                break;\r\n            case 2:\r\n                satelliteInfo.cn = SatelliteInfoClass.CN[2];\r\n                break;\r\n            case 3:\r\n                satelliteInfo.cn = SatelliteInfoClass.CN[3];\r\n                break;\r\n        }\r\n        satelliteInfo.pseudoRangeValue = (payload[3+4*i] & 0x07) << 16 + payload[4+4*i] << 8 + payload[5+4*i];\r\n        \r\n        satelliteInfos.push(satelliteInfo);\r\n        i++;\r\n    }\r\n    lr1110gnss.satelliteInfos = satelliteInfos;\r\n    return lr1110gnss;\r\n}\r\n/************************ Position decodage *************************/\r\n/********************************************************************/\r\nfunction determinePosition(payload, multiFrame){\r\n\r\n    var startingByte = 4;\r\n    if (multiFrame){\r\n        startingByte = 5;\r\n    }\r\n    let positionMessage = determinePositionHeader(payload, startingByte);\r\n    // position status success\r\n    if (positionMessage.status == PositionStatus.SUCCESS || positionMessage.status == PositionStatus.NOT_SOLVABLE){\r\n        switch (positionMessage.positionType){\r\n            case PositionType.LR11xx_A_GNSS:\r\n                positionMessage.lr11xxAGnss = determineLR1110GnssPositionMessage(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.LR11xx_GNSS_NAV1:\r\n                positionMessage.lr11xxGnssNav1 = util.convertBytesToString(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.LR11xx_GNSS_NAV2:\r\n                positionMessage.lr11xxGnssNav2 = util.convertBytesToString(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.WIFI:\r\n                positionMessage.wifiBssids = wifiClass.determineWifiPositionMessage(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.BLE_SCAN1_MAC:\r\n                positionMessage.bleBeaconMacs = bleClass.determineBleMacPositionMessage(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.BLE_SCAN1_SHORT:\r\n                positionMessage.bleBeaconIds = bleClass.determineBleIdShortPositionMessage(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.BLE_SCAN1_LONG:\r\n                positionMessage.bleBeaconIds = bleClass.determineBleIdLongPositionMessage(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.BLE_SCAN2_MAC:\r\n                positionMessage.bleBeaconMacs = bleClass.determineBleMacPositionMessage(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.BLE_SCAN2_SHORT:\r\n                positionMessage.bleBeaconIds = bleClass.determineBleIdShortPositionMessage(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.BLE_SCAN2_LONG:\r\n                positionMessage.bleBeaconIds = bleClass.determineBleIdLongPositionMessage(payload.slice(startingByte+4));\r\n                break;\r\n            case PositionType.GNSS:\r\n                positionMessage.gnssFix = gnssFixClass.determineGnssFix(payload.slice(startingByte+4));\r\n                positionMessage.coordinates = [positionMessage.gnssFix.longitude, positionMessage.gnssFix.latitude, positionMessage.gnssFix.altitude]\r\n                break;\r\n            case PositionType.AIDED_GNSS:\r\n                break;    \r\n        }       \r\n    }else if ((positionMessage.status == PositionStatus.TIMEOUT)||(positionMessage.status == PositionStatus.FAILURE)){\r\n        //only for GNSS\r\n        if (positionMessage.positionType == PositionType.GNSS){\r\n            positionMessage.gnssFailure = gnssFailureClass.determineGnssFailure(payload.slice(startingByte+4))\r\n        }\r\n    }\r\n    return positionMessage;\r\n\r\n}\r\n\r\nmodule.exports = {\r\n    Position: Position,\r\n    determinePosition: determinePosition\r\n \t\r\n}\r\n\r\n\r\n/***/ }),\r\n\r\n/***/ 483:\r\n/***/ ((module) => {\r\n\r\nfunction TriggerBitMap(geoTriggerPod,\r\n    geoTriggerSos,\r\n    geoTriggerMotionStart,\r\n    geoTriggerMotionStop,\r\n    geoTriggerInMotion,\r\n    geoTriggerInStatic,\r\n    geoTriggerShock,\r\n    geoTriggerTempHighThreshold,\r\n    geoTriggerTempLowThreshold,\r\n    geoTriggerGeozoning\r\n){\r\n    this.geoTriggerPod = geoTriggerPod;\r\n    this.geoTriggerSos = geoTriggerSos;\r\n    this.geoTriggerMotionStart = geoTriggerMotionStart;\r\n    this.geoTriggerMotionStop = geoTriggerMotionStop;\r\n    this.geoTriggerInMotion = geoTriggerInMotion;\r\n    this.geoTriggerInStatic = geoTriggerInStatic;\r\n    this.geoTriggerShock = geoTriggerShock;\r\n    this.geoTriggerTempHighThreshold = geoTriggerTempHighThreshold;\r\n    this.geoTriggerTempLowThreshold = geoTriggerTempLowThreshold;\r\n    this.geoTriggerGeozoning = geoTriggerGeozoning;\r\n}\r\n\r\nmodule.exports = {\r\n    TriggerBitMap: TriggerBitMap, \t\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 504:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\n\r\nlet util = __webpack_require__(94);\r\nlet BeaconInfoClass = __webpack_require__(320);\r\n\r\nfunction determineBleIdShortPositionMessage(payload) {\r\n    return extractBeaconInfos(payload, 3, (payload, index) => {\r\n        let key = `${util.convertByteToString(payload[index * 3])}-${util.convertByteToString(payload[1 + index * 3])}`;\r\n        let value = util.convertNegativeInt(payload[2 + index * 3], 1);\r\n        return new BeaconInfoClass.BeaconIdInfo(key, value);\r\n    });\r\n}\r\n\r\nfunction determineBleIdLongPositionMessage(payload) {\r\n    return extractBeaconInfos(payload, 17, (payload, index) => {\r\n        let key = Array.from({ length: 16 }, (_, i) => util.convertByteToString(payload[i + index * 17])).join('-');\r\n        let value = util.convertNegativeInt(payload[16 + index * 17], 1);\r\n        return new BeaconInfoClass.BeaconIdInfo(key, value);\r\n    });\r\n}\r\n\r\nfunction determineBleMacPositionMessage(payload) {\r\n    return extractBeaconInfos(payload, 7, (payload, index) => {\r\n        let key = Array.from({ length: 6 }, (_, i) => util.convertByteToString(payload[i + index * 7])).join(':');\r\n        let value = util.convertNegativeInt(payload[6 + index * 7], 1);\r\n        return new BeaconInfoClass.BeaconMacInfo(key, value);\r\n    });\r\n}\r\n\r\nfunction extractBeaconInfos(payload, chunkSize, createBeaconInfo) {\r\n    const beaconInfos = [];\r\n    const count = Math.floor(payload.length / chunkSize);\r\n    for (let i = 0; i < count; i++) {\r\n        beaconInfos.push(createBeaconInfo(payload, i));\r\n    }\r\n    return beaconInfos;\r\n}\r\n\r\nmodule.exports = {\r\n    determineBleMacPositionMessage,\r\n    determineBleIdShortPositionMessage,\r\n    determineBleIdLongPositionMessage\r\n};\r\n\r\n/***/ }),\r\n\r\n/***/ 508:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet BssidInfoClass = __webpack_require__(69);\r\nlet util = __webpack_require__(94);\r\n\r\nfunction determineWifiPositionMessage(payload){\r\n  \r\n    const wifiBssids = [];\r\n    var i = 0;\r\n    while (payload.length >= 7*(i+1)){\r\n        let key = util.convertByteToString(payload[i*7]) + \":\" \r\n                    + util.convertByteToString(payload[1+i*7]) + \":\"\r\n                    + util.convertByteToString(payload[2+i*7]) + \":\"\r\n                    + util.convertByteToString(payload[3+i*7]) + \":\"\r\n                    + util.convertByteToString(payload[4+i*7]) + \":\"\r\n                    + util.convertByteToString(payload[5+i*7]);\r\n        let value = util.convertNegativeInt(payload[6+i*7],1);\r\n        \r\n        wifiBssids.push(new BssidInfoClass.BssidInfo(key, value));\r\n        i++;\r\n    }\r\n\r\n    return wifiBssids;\r\n}\r\n\r\nmodule.exports = {\r\n    determineWifiPositionMessage : determineWifiPositionMessage\t\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 522:\r\n/***/ ((module) => {\r\n\r\nconst MessageType = Object.freeze({\r\n    COMMAND: \"COMMAND\",\r\n    REQUEST: \"REQUEST\",\r\n    ANSWER: \"ANSWER\"\r\n});\r\n\r\nfunction AbeewayDownlinkPayload(downMessageType, \r\n        ackToken,\r\n        command,\r\n        request,\r\n        payload) {\r\n        this.downMessageType = downMessageType;\r\n        this.ackToken = ackToken;\r\n        this.command = command;\r\n        this.request = request;\r\n        this.payload = payload;\r\n}\r\n\r\nfunction determineDownlinkHeader(payload){\r\n    if (payload.length < 1)\r\n        throw new Error(\"The payload is not valid to determine header\");\r\n    var ackToken = payload[0] & 0x07;\r\n    var type = determineMessageType(payload);\r\n    return new AbeewayDownlinkPayload(type, ackToken)\r\n}\r\n\r\nfunction determineMessageType(payload){\r\n    var messageType = payload[0]>>3 & 0x07;\r\n    \r\n    switch (messageType){\r\n        case 1:\r\n            return MessageType.COMMAND;\r\n        case 2:\r\n            return MessageType.REQUEST;\r\n        case 3:\r\n            return MessageType.ANSWER;\r\n    }\r\n}\r\n\r\nmodule.exports = {\r\n    AbeewayDownlinkPayload: AbeewayDownlinkPayload,\r\n    MessageType: MessageType,\r\n    determineDownlinkHeader: determineDownlinkHeader\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 541:\r\n/***/ ((module) => {\r\n\r\nfunction GnssFailure(timeoutCause,\r\n    satelliteSeen){\r\n    this.timeoutCause = timeoutCause;\r\n    this.satellitesSeen = satelliteSeen\r\n}\r\nconst timeoutCause = Object.freeze({\r\n    T0_TIMEOUT: \"T0_TIMEOUT\",\r\n    T1_TIMEOUT: \"T1_TIMEOUT\",\r\n    ACQUISITION_TIMEOUT: \"ACQUISITION_TIMEOUT\"\r\n});\r\nconst constellation = Object.freeze({\r\n    GPS: \"GPS\",\r\n    GLONASS: \"GLONASS\",\r\n    BEIDOU: \"BEIDOU\",\r\n    GALILEO: \"GALILEO\"\r\n});\r\nfunction determineTimeoutCause(timeoutCause){\r\n    switch (timeoutCause){\r\n\t    case 0:\r\n\t        return timeoutCause.T0_TIMEOUT;\r\n\t    case 1:\r\n\t        return timeoutCause.T1_TIMEOUT;\r\n\t    case 2:\r\n\t    \treturn timeoutCause.ACQUISITION_TIMEOUT;\r\n\t    default:\r\n\t    \tthrow new Error(\"The timeout cause is unknown\");\r\n    }\r\n}\r\nfunction determineConstellation(cons){\r\n\r\n    switch (cons){\r\n\t    case 0:\r\n\t        return constellation.GPS;\r\n        case 1:\r\n            return constellation.GLONASS;\r\n        case 2:\r\n            return constellation.BEIDOU;\r\n        case 3:\r\n            return constellation.GALILEO;\r\n        default:\r\n            throw new Error(\"The constellation is unknown\" )\r\n}}\r\n\r\nfunction determineGnssFailure(payload){\r\n    let timeoutCause = determineTimeoutCause(payload[0]>>5 & 0x07)\r\n    let nbSatSeen = payload[0] & 0x0F\r\n    payload = payload.slice(1)\r\n    let satelliteSeen = []\r\n    for (let i = 0; i < nbSatSeen*2; i += 2) {\r\n        let svId = payload[i]\r\n        let constellation = determineConstellation(payload[i]+1>>6 & 0x03)\r\n        let CN = payload[i+1] & 0x3F\r\n        satelliteSeen.push({svId, constellation, CN})\r\n    } \r\n   \r\n    return new GnssFailure(timeoutCause, satelliteSeen)\r\n}\r\n\r\nmodule.exports = {\r\n    GnssFailure: GnssFailure,\r\n    determineGnssFailure: determineGnssFailure\r\n}\r\n\r\n\r\n/***/ }),\r\n\r\n/***/ 548:\r\n/***/ ((module) => {\r\n\r\n\r\nconst GeozoningType = Object.freeze({\r\n    ENTRY: \"ENTRY\",\r\n    EXIT: \"EXIT\",\r\n    IN_HAZARD: \"IN_HAZARD\",\r\n    OUT_HAZARD: \"OUT_HAZARD\",\r\n    MEETING_POINT: \"MEETING_POINT\"\r\n})\r\n\r\nmodule.exports = {\r\n    GeozoningType: GeozoningType\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 560:\r\n/***/ ((module) => {\r\n\r\nlet telemetryMetadataStore = {};\r\n\r\nconst CodingPolicy = Object.freeze({\r\n    NO_COMPRESSION: \"NO_COMPRESSION\",\r\n    DELTA_COMPRESSION: \"DELTA_COMPRESSION\",\r\n    HUFFMAN_COMPRESSION: \"HUFFMAN_COMPRESSION\",\r\n})\r\n\r\nconst DataTypes = Object.freeze({\r\n    _8_BIT_UNSIGNED: \"8_BIT_UNSIGNED\",\r\n    _16_BIT_SIGNED: \"16_BIT_SIGNED\"\r\n})\r\n\r\nconst RecordingPolicy = Object.freeze({\r\n    INSTANT: \"INSTANT\",\r\n    MIN: \"MIN\",\r\n    MAX: \"MAX\",\r\n    CHANGE_OF_VALUE: \"CHANGE_OF_VALUE\"\r\n});\r\n\r\nfunction convert3BitToSigned(val) {\r\n    return (val & 0x04) ? val - 8 : val;\r\n}\r\n\r\nfunction decodeMetadataPayload(telemetryPayload) {\r\n    const errors = [];\r\n    let offset = 0;\r\n    while (offset + 8 <= telemetryPayload.length) {\r\n        const block = telemetryPayload.slice(offset, offset + 8);\r\n        const payloadType = (block[0] & 0x80) >> 7;\r\n        if (payloadType !== 1) break;\r\n        const telemetryId = (block[0] >> 4) & 0x07;\r\n        const cyclicVersion = block[0] & 0x07;\r\n\r\n        const fixedTimeInterval = (block[1] >> 3) & 0x03;\r\n        const numMeasurements = block[1] & 0x07;\r\n\r\n        const telemetryIDMaxInterval = telemetryPayload.readUInt16BE(offset + 2);\r\n        const measurementNMaxInterval = telemetryPayload.readUInt16BE(offset + 4);\r\n\r\n        const measurementConfigByte1 = block[6];\r\n        const measurementConfigByte2 = block[7];\r\n\r\n        const measurementConfig = decodeMeasurementConfigBytes(measurementConfigByte1, measurementConfigByte2);\r\n        telemetryMetadataStore[telemetryId] = {\r\n            telemetryId,\r\n            cyclicVersion,\r\n            fixedTimeInterval,\r\n            numMeasurements,\r\n            telemetryIDMaxInterval,\r\n            measurementNMaxInterval,\r\n            measurementConfig: measurementConfig,\r\n        };\r\n        offset += 8;\r\n    }\r\n\r\n    if(errors.length > 0) return { errors: errors, warnings: [] };\r\n    context.push(telemetryMetadataStore);\r\n    return { context: context, data: telemetryMetadataStore, errors: errors, warnings: [] };\r\n}\r\n\r\nfunction decodeMeasurementConfigBytes(byte1, byte2) {\r\n    const measurementId = (byte1 >> 6) & 0x03;\r\n    let codingPolicy = (byte1 >> 2) & 0x03;\r\n    let dataType = byte1 & 0x03;\r\n    let recordingPolicy = (byte2 >> 5) & 0x07;\r\n    let scalingFactor = (byte2 >> 1) & 0x07;\r\n    scalingFactor =  Math.pow(10, convert3BitToSigned(scalingFactor));\r\n    let sampleCompression = byte2 & 0x01;\r\n\r\n    switch (dataType) {\r\n        case 0:\r\n            dataType = DataTypes._8_BIT_UNSIGNED;\r\n            break;\r\n        case 1:\r\n            dataType = DataTypes._16_BIT_SIGNED;\r\n            break;\r\n        default:\r\n            throw new Error(`Unsupported data type \"${dataType}\"`);\r\n    }\r\n\r\n    switch (codingPolicy) {\r\n        case 0:\r\n            codingPolicy = CodingPolicy.NO_COMPRESSION;\r\n            break;\r\n        case 1:\r\n            codingPolicy = CodingPolicy.DELTA_COMPRESSION;\r\n            break;\r\n        case 2:\r\n            codingPolicy = CodingPolicy.HUFFMAN_COMPRESSION;\r\n            break;\r\n        default:\r\n            throw new Error(`Unsupported coding policy \"${codingPolicy}\"`);\r\n    }\r\n\r\n    switch (recordingPolicy) {\r\n        case 0:\r\n            recordingPolicy = RecordingPolicy.INSTANT;\r\n            break;\r\n        case 1:\r\n            recordingPolicy = RecordingPolicy.MIN;\r\n            break;\r\n        case 2:\r\n            recordingPolicy = RecordingPolicy.MAX;\r\n            break;\r\n        default:\r\n            recordingPolicy = RecordingPolicy.CHANGE_OF_VALUE;\r\n    }\r\n\r\n    sampleCompression = sampleCompression === 0 ? \"LINEAR\" : \"LOGARITHMIC\";\r\n\r\n    return {\r\n        measurementId,\r\n        codingPolicy,\r\n        dataType,\r\n        recordingPolicy,\r\n        scalingFactor,\r\n        sampleCompression\r\n    };\r\n}\r\n\r\nfunction decodeTimeseriesPayload(telemetryPayload) {\r\n    const errors = [];\r\n\r\n    if (telemetryPayload.length < 4) {\r\n        errors.push(\"Telemetry payload too short for timeseries decoding\");\r\n        return { errors };\r\n    }\r\n\r\n    const byte0 = telemetryPayload[0];\r\n    const telemetryId = (byte0 >> 4) & 0x07;\r\n    const alarmTrigger = (byte0 & 0x01) === 1;\r\n\r\n    const byte1 = telemetryPayload[1];\r\n    const cyclicVersion = (byte1 >> 4) & 0x0F;\r\n    const cyclicCounter = byte1 & 0x0F;\r\n\r\n    const metadataHistory = context.shift();\r\n    let metadata = Object.values(metadataHistory).find(t => t.telemetryId === telemetryId);\r\n\r\n    if (!metadata || metadata.cyclicVersion !== cyclicVersion) {\r\n        errors.push(`Missing or mismatched metadata for TelemetryID=${telemetryId}, CyclicVersion=${cyclicVersion}`);\r\n        return { errors };\r\n    }\r\n\r\n    const { codingPolicy, dataType, scalingFactor } = metadata.measurementConfig;\r\n    const measurementData = telemetryPayload.slice(2);\r\n    let measurements = [];\r\n\r\n        if (codingPolicy === CodingPolicy.DELTA_COMPRESSION && dataType === DataTypes._16_BIT_SIGNED) {\r\n            const buffer = Buffer.from(measurementData);\r\n            let i = buffer.length - 1;\r\n            let result = [];\r\n            let currentValue = 0;\r\n\r\n            while (i >= 0) {\r\n                const byte = buffer[i];\r\n                const isDelta = (byte >> 7 & 0x01) !== 0;\r\n\r\n                if (!isDelta) {\r\n                    currentValue = buffer[i - 1];\r\n                    result.push(currentValue);\r\n                    i -= 2;\r\n                } else {\r\n                    const signBit = byte >> 6 & 0x11;\r\n                    const num = byte & 0x3F;\r\n\r\n                    let delta = (signBit) ? (64 - num) * -1 : num ;\r\n                    currentValue += delta;\r\n                    result.push(currentValue);\r\n                }\r\n                i--\r\n            }\r\n            measurements = result;\r\n        } else {\r\n            errors.push(\"Unsupported coding policy or data type for delta decoding\");\r\n        }\r\n\r\n    const scaledMeasurements = measurements.map(m => parseFloat((m * scalingFactor).toFixed(2)));\r\n\r\n    if (errors.length > 0) {\r\n        return { errors: errors, warnings: [] };\r\n    }\r\n\r\n    return {\r\n        type: \"timeseries\",\r\n        telemetryId,\r\n        alarmTrigger,\r\n        cyclicVersion,\r\n        cyclicCounter,\r\n        measurements: scaledMeasurements,\r\n        measurementConfig: metadata.measurementConfig,\r\n    };\r\n}\r\n\r\nfunction decodeTelemetry(payload) {\r\n    if (!(payload instanceof Buffer)) {\r\n        try {\r\n            payload = Buffer.from(payload, typeof payload === \"string\" ? \"hex\" : undefined);\r\n        } catch (e) {\r\n            return { errors: [\"Invalid payload format\"], warnings: [] };\r\n        }\r\n    }\r\n\r\n    if (payload.length < 5) {\r\n        return { errors: [\"Payload too short\"], warnings: [] };\r\n    }\r\n\r\n    const headerLength = 4;\r\n    const telemetryPayload = payload.slice(headerLength);\r\n    if (telemetryPayload.length < 1) {\r\n        return { errors: [\"No telemetry payload\"], warnings: [] };\r\n    }\r\n\r\n    const payloadTypeByte = telemetryPayload[0];\r\n    const isMetadata = (payloadTypeByte & 0x80) !== 0;\r\n    if (isMetadata) {\r\n        const result = decodeMetadataPayload(telemetryPayload);\r\n        if (result.data === undefined) {\r\n            return {\r\n                errors: result.errors,\r\n                warnings: result.warnings || []\r\n            };\r\n        }\r\n        return {\r\n            type: \"metadata\",\r\n            TelemetryIDs: [result.data],\r\n            context: result.context\r\n        };\r\n    } else {\r\n        const telemetryResult = decodeTimeseriesPayload(telemetryPayload);\r\n        if (telemetryResult.measurementConfig === undefined) {\r\n            return {\r\n                errors: telemetryResult.errors,\r\n                warnings: telemetryResult.warnings || []\r\n            };\r\n        }\r\n        return telemetryResult\r\n    }\r\n}\r\n\r\nmodule.exports = {\r\n    decodeTelemetry,\r\n};\r\n\r\n\r\n/***/ }),\r\n\r\n/***/ 592:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet abeewayUplinkPayloadClass = __webpack_require__(962);\r\nconst batteryStatus = Object.freeze({\r\n    CHARGING: \"CHARGING\",\r\n    OPERATING: \"OPERATING\",\r\n    UNKNOWN: \"UNKNOWN\"\r\n});\r\n\r\nfunction Header(sos, type, ackToken, multiFrame, batteryLevel, timestamp) {\r\n    this.sos = sos;\r\n    this.type = type;\r\n    this.ackToken = ackToken;\r\n    this.multiFrame = multiFrame;\r\n    this.batteryLevel = batteryLevel;\r\n    this.timestamp = timestamp;\r\n}\r\n\r\nfunction determineHeader(payload, receivedTime) {\r\n    if (payload.length < 3)\r\n        throw new Error(\"The payload is not valid to determine header\");\r\n    var sos = !!(payload[0] >> 6 & 0x01);\r\n    var ackToken = payload[0] & 0x07;\r\n    var type = determineMessageType(payload);\r\n    var multiFrame = !!(payload[0] >> 7 & 0x01);\r\n    var batteryLevel = determineBatteryLevel(payload);\r\n    var timestamp = rebuildTime(receivedTime, ((payload[2] << 8) + payload[3]));\r\n    return new Header(sos, type, ackToken, multiFrame, batteryLevel, timestamp);\r\n}\r\n\r\nfunction rebuildTime(receivedTime, seconds) {\r\n    // Parse the timestamp using native Date object\r\n    const timestamp = new Date(receivedTime);\r\n\r\n    // In the case where the tracker hasn't had time yet...\r\n    if (seconds === 65535) {\r\n        return timestamp.toISOString();\r\n    }\r\n\r\n    // Create a Date object set to the start of the UTC day\r\n    const utcDate = new Date(Date.UTC(timestamp.getFullYear(), timestamp.getMonth(), timestamp.getDate(), 0, 0, 0));\r\n\r\n    // Calculate the total seconds since the start of the day for the received time\r\n    const referenceTotalSeconds = (timestamp.getUTCHours() * 3600) + (timestamp.getUTCMinutes() * 60) + timestamp.getUTCSeconds();\r\n\r\n    // Determine if the reference time is closer to midnight or noon\r\n    let referenceTime;\r\n    if (referenceTotalSeconds < 43200) { // 43200 seconds is 12 hours\r\n        referenceTime = utcDate; // Midnight\r\n    } else {\r\n        referenceTime = new Date(utcDate.getTime() + 43200 * 1000); // Noon\r\n    }\r\n\r\n    // Add the given number of seconds to the reference time\r\n    let exactTime = new Date(referenceTime.getTime() + seconds * 1000);\r\n\r\n    // Check if the rebuilt time is after the original timestamp (rollover)\r\n    if (exactTime > timestamp) {\r\n        // Rebuilt time is after the received time, so subtract 43200 seconds (12 hours)\r\n        exactTime = new Date(exactTime.getTime() - 43200 * 1000);\r\n    }\r\n\r\n    return exactTime.toISOString(); // Return the exact time in ISO 8601 format\r\n}\r\nfunction determineMessageType(payload){\r\n    if (payload.length < 4)\r\n        throw new Error(\"The payload is not valid to determine Message Type\");\r\n    var messageType = payload[0]>>3 & 0x07\r\n    switch (messageType){\r\n        case 1:\r\n            return abeewayUplinkPayloadClass.messageType.NOTIFICATION;\r\n        case 2:\r\n            return abeewayUplinkPayloadClass.messageType.POSITION;\r\n        case 3:\r\n            return abeewayUplinkPayloadClass.messageType.QUERY;\r\n        case 4:\r\n            return abeewayUplinkPayloadClass.messageType.RESPONSE;\r\n        case 5:\r\n            return abeewayUplinkPayloadClass.messageType.TELEMETRY;\r\n        default:\r\n            return abeewayUplinkPayloadClass.messageType.UNKNOWN;\r\n    }\r\n}\r\n\r\nfunction determineBatteryLevel(payload){\r\n    if (payload.length < 4)\r\n        throw new Error(\"The payload is not valid to determine Battery Level\");\r\n    var value = payload[1] & 0x7F;\r\n    if (value == 0)\r\n        return batteryStatus.CHARGING;\r\n    else if (value == 127)\r\n        return batteryStatus.UNKNOWN; \r\n    return value;\r\n}\r\n\r\nmodule.exports = {\r\n    Header: Header,\r\n    determineHeader: determineHeader\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 635:\r\n/***/ ((module) => {\r\n\r\n\"use strict\";\r\nmodule.exports = /*#__PURE__*/JSON.parse('[{\"firmwareVersion\":\"3.0\",\"uplinkPort\":\"19\",\"firmwareParameters\":[{\"driverParameterName\":\"sysHighestTemperature\",\"groupId\":\"0x00\",\"localId\":\"0x00\",\"defaultValue\":0,\"unit\":\"Cel\",\"description\":\"Highest temperature reached\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":-100,\"maximum\":100}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"sysLowestTemperature\",\"groupId\":\"0x00\",\"localId\":\"0x01\",\"defaultValue\":0,\"unit\":\"Cel\",\"description\":\"Lowest temperature reached\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":-100,\"maximum\":100}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"sysPowerConsumption\",\"groupId\":\"0x00\",\"localId\":\"0x02\",\"defaultValue\":0,\"unit\":\"mAH\",\"description\":\"Total power consumed\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreMonitoringPeriod\",\"groupId\":\"0x01\",\"localId\":\"0x00\",\"defaultValue\":300,\"unit\":\"s\",\"description\":\"Device monitoring period\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":15}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreStatusPeriod\",\"groupId\":\"0x01\",\"localId\":\"0x01\",\"defaultValue\":3600,\"unit\":\"s\",\"description\":\"Status monitoring period\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreNotifEnable\",\"groupId\":\"0x01\",\"localId\":\"0x02\",\"defaultValue\":\"{0B,00,00,00,00,00}\",\"description\":\"Enables core notifications for various events.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":6,\"distinctValues\":true,\"properties\":[{\"name\":\"systemClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"status\",\"type\":\"PropertyBoolean\",\"description\":\"System status Versions, temperature, reset cause.\"},{\"name\":\"lowBattery\",\"type\":\"PropertyBoolean\",\"description\":\"Low battery alert.\"},{\"name\":\"bleStatus\",\"type\":\"PropertyBoolean\",\"description\":\"Bluetooth Low Energy status\"},{\"name\":\"tamperDetection\",\"type\":\"PropertyBoolean\",\"description\":\"Tamper detection alert.\"},{\"name\":\"heartbeat\",\"type\":\"PropertyBoolean\",\"description\":\"Heartbeat message.\"}]},{\"name\":\"sosClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"sosOn\",\"type\":\"PropertyBoolean\",\"description\":\"SOS activated.\"},{\"name\":\"sosOff\",\"type\":\"PropertyBoolean\",\"description\":\"SOS deactivated.\"}]},{\"name\":\"temperatureClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"tempHigh\",\"type\":\"PropertyBoolean\",\"description\":\"Critical high temperature reached\"},{\"name\":\"tempLow\",\"type\":\"PropertyBoolean\",\"description\":\"Critical low temperature reached\"},{\"name\":\"tempNormal\",\"type\":\"PropertyBoolean\",\"description\":\"Temperature back to normal\"}]},{\"name\":\"accelerometerClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"motionStart\",\"type\":\"PropertyBoolean\",\"description\":\"Motion start detected.\"},{\"name\":\"motionEnd\",\"type\":\"PropertyBoolean\",\"description\":\"Motion end detected.\"},{\"name\":\"shock\",\"type\":\"PropertyBoolean\",\"description\":\"Shock detected.\"}]},{\"name\":\"networkingClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"mainUp\",\"type\":\"PropertyBoolean\",\"description\":\"Main network is up.\"},{\"name\":\"backupUp\",\"type\":\"PropertyBoolean\",\"description\":\"Main network down. Backup is up.\"}]},{\"name\":\"geozoningClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"geozoningOn\",\"type\":\"PropertyBoolean\",\"description\":\"Geozoning is on.\"}]}],\"byteMask\":[{\"valueFor\":\"systemClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"status\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"lowBattery\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"bleStatus\",\"bitShift\":2,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"tamperDetection\",\"bitShift\":3,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"heartbeat\",\"bitShift\":4,\"length\":1}]},{\"valueFor\":\"sosClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"sosOn\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"sosOff\",\"bitShift\":1,\"length\":1}]},{\"valueFor\":\"temperatureClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"tempHigh\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"tempLow\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"tempNormal\",\"bitShift\":2,\"length\":1}]},{\"valueFor\":\"accelerometerClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"motionStart\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"motionEnd\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"shock\",\"bitShift\":2,\"length\":1}]},{\"valueFor\":\"networkingClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"mainUp\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"backupUp\",\"bitShift\":1,\"length\":1}]},{\"valueFor\":\"geozoningClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"geozoningOn\",\"bitShift\":0,\"length\":1}]}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreTempHighThreshold\",\"groupId\":\"0x01\",\"localId\":\"0x03\",\"defaultValue\":60,\"unit\":\"Cel\",\"description\":\"Highest temperature detection threshold\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":-100,\"maximum\":100}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreTempLowThreshold\",\"groupId\":\"0x01\",\"localId\":\"0x04\",\"defaultValue\":0,\"unit\":\"Cel\",\"description\":\"Lowest temperature detection threshold\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":-100,\"maximum\":100}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreTempHysteresis\",\"groupId\":\"0x01\",\"localId\":\"0x05\",\"defaultValue\":5,\"unit\":\"Cel\",\"description\":\"Temperature hysteresis\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":-100,\"maximum\":100}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreButton1Map\",\"groupId\":\"0x01\",\"localId\":\"0x06\",\"description\":\"Button 1 mapping\",\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"buttonPress\",\"type\":\"PropertyString\",\"description\":\"Event to execute with a button press.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonLongPress\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button long press.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonSingleClick\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button single click.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonDoubleClicks\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button double clicks.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonTripleClicksOrAbove\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button triple clicks or above.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonSimpleSequence\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button simple sequence.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonPress\",\"bitShift\":0,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonLongPress\",\"bitShift\":4,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonSingleClick\",\"bitShift\":8,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonDoubleClicks\",\"bitShift\":12,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonTripleClicksOrAbove\",\"bitShift\":16,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonSimpleSequence\",\"bitShift\":20,\"length\":4}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreButton2Map\",\"groupId\":\"0x01\",\"localId\":\"0x07\",\"description\":\"Button 2 mapping\",\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"buttonPress\",\"type\":\"PropertyString\",\"description\":\"Event to execute with a button press.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonLongPress\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button long press.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonSingleClick\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button single click.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonDoubleClicks\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button double clicks.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonTripleClicksOrAbove\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button triple clicks or above.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]},{\"name\":\"buttonSimpleSequence\",\"type\":\"PropertyString\",\"description\":\"Event generated on a button simple sequence.\",\"possibleValues\":[\"NO_ACTION\",\"DISPLAY_BATTERY_LEVEL_ON_THE_LED\",\"START_STOP_SOS\",\"REQUEST_A_POSITION_ON_DEMAND\",\"FORCE_AN_UPLINK_SYSTEM_STATUS_NOTIFICATION_TRANSMISSION\",\"START_DEVICE\",\"STOP_DEVICE\",\"START_ONLY_SOS\",\"START_BLE_ADVERTISING_FOR_CONNECTIVITY\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8]}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonPress\",\"bitShift\":0,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonLongPress\",\"bitShift\":4,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonSingleClick\",\"bitShift\":8,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonDoubleClicks\",\"bitShift\":12,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonTripleClicksOrAbove\",\"bitShift\":16,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"buttonSimpleSequence\",\"bitShift\":20,\"length\":4}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreButtonsTiming\",\"groupId\":\"0x01\",\"localId\":\"0x08\",\"description\":\"Define the buttons timing parameters.\",\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"durationButtonPress\",\"type\":\"PropertyNumber\",\"description\":\"Duration of the button press in seconds.\"},{\"name\":\"durationButtonLongPress\",\"type\":\"PropertyNumber\",\"description\":\"Duration of the button long press in seconds.\"},{\"name\":\"debounceDurationOnButton1\",\"type\":\"PropertyNumber\",\"description\":\"Debounce duration on button 1 in milliseconds.\"},{\"name\":\"debounceDurationOnButton2\",\"type\":\"PropertyNumber\",\"description\":\"Debounce duration on button 2 in milliseconds.\"}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"durationButtonPress\",\"bitShift\":0,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"durationButtonLongPress\",\"bitShift\":4,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"debounceDurationOnButton1\",\"bitShift\":8,\"length\":8},{\"type\":\"BitMaskValue\",\"valueFor\":\"debounceDurationOnButton2\",\"bitShift\":16,\"length\":8}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreLed0Map\",\"groupId\":\"0x01\",\"localId\":\"0x09\",\"defaultValue\":\"{00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00}\",\"description\":\"Defines LED patterns for system events. Configurable as 10 slices of 3 bytes each.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":30,\"distinctValues\":false,\"properties\":[{\"name\":\"slice\",\"type\":\"PropertByteArray\",\"size\":3,\"distinctValues\":true,\"properties\":[{\"name\":\"systemEventClass\",\"type\":\"PropertyString\",\"description\":\"System event class.\",\"possibleValues\":[\"BUTTON1\",\"BUTTON2\",\"BUZZER\",\"ACCELEROMETER\",\"POWER\",\"TEMPERATURE\",\"GEOLOCATION\",\"CONFIGURATION\",\"NETWORK\",\"CORE\",\"BLE_CONNECTIVITY\",\"USER\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8,9,10,11]},{\"name\":\"patternLoopExtension\",\"type\":\"PropertyNumber\",\"description\":\"Pattern loop extension.\"},{\"name\":\"patternInversion\",\"type\":\"PropertyBoolean\",\"description\":\"Indicates whether the pattern is inverted.\"},{\"name\":\"type\",\"type\":\"PropertyNumber\",\"description\":\"System event type.\"},{\"name\":\"patternIdentifier\",\"type\":\"PropertyString\",\"description\":\"Defines the LED behavior.\",\"possibleValues\":[\"NOT_CONFIGURED\",\"LED_OFF\",\"LED_ON\",\"FADE_IN\",\"FADE_OUT\",\"BLINK_SLOW\",\"BLINK_MEDIUM\",\"BLINK_FAST\",\"FLASH_SLOW\",\"FLASH_FAST\",\"HEART_ON\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8,9,10]},{\"name\":\"patternLoop\",\"type\":\"PropertyNumber\",\"description\":\"Number of times the pattern is displayed.\"}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"systemEventClass\",\"bitShift\":0,\"length\":5},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternLoopExtension\",\"bitShift\":5,\"length\":2},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternInversion\",\"bitShift\":7,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"type\",\"bitShift\":8,\"length\":8},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternIdentifier\",\"bitShift\":16,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternLoop\",\"bitShift\":20,\"length\":4}]}],\"byteMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"slice\",\"bitShift\":0,\"length\":24}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreLed1Map\",\"groupId\":\"0x01\",\"localId\":\"0x0A\",\"defaultValue\":\"{00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00}\",\"description\":\"Defines LED patterns for system events. Configurable as 10 slices of 3 bytes each.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":30,\"distinctValues\":false,\"properties\":[{\"name\":\"slice\",\"type\":\"PropertByteArray\",\"size\":3,\"distinctValues\":true,\"properties\":[{\"name\":\"systemEventClass\",\"type\":\"PropertyString\",\"description\":\"System event class.\",\"possibleValues\":[\"BUTTON1\",\"BUTTON2\",\"BUZZER\",\"ACCELEROMETER\",\"POWER\",\"TEMPERATURE\",\"GEOLOCATION\",\"CONFIGURATION\",\"NETWORK\",\"CORE\",\"BLE_CONNECTIVITY\",\"USER\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8,9,10,11]},{\"name\":\"patternLoopExtension\",\"type\":\"PropertyNumber\",\"description\":\"Pattern loop extension.\"},{\"name\":\"patternInversion\",\"type\":\"PropertyBoolean\",\"description\":\"Indicates whether the pattern is inverted.\"},{\"name\":\"type\",\"type\":\"PropertyNumber\",\"description\":\"System event type.\"},{\"name\":\"patternIdentifier\",\"type\":\"PropertyString\",\"description\":\"Defines the LED behavior.\",\"possibleValues\":[\"NOT_CONFIGURED\",\"LED_OFF\",\"LED_ON\",\"FADE_IN\",\"FADE_OUT\",\"BLINK_SLOW\",\"BLINK_MEDIUM\",\"BLINK_FAST\",\"FLASH_SLOW\",\"FLASH_FAST\",\"HEART_ON\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8,9,10]},{\"name\":\"patternLoop\",\"type\":\"PropertyNumber\",\"description\":\"Number of times the pattern is displayed.\"}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"systemEventClass\",\"bitShift\":0,\"length\":5},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternLoopExtension\",\"bitShift\":5,\"length\":2},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternInversion\",\"bitShift\":7,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"type\",\"bitShift\":8,\"length\":8},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternIdentifier\",\"bitShift\":16,\"length\":4},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternLoop\",\"bitShift\":20,\"length\":4}]}],\"byteMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"slice\",\"bitShift\":0,\"length\":24}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreBuzzerMap\",\"groupId\":\"0x01\",\"localId\":\"0x0B\",\"defaultValue\":\"{00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00}\",\"description\":\"Defines LED patterns for system events. Configurable as 10 slices of 3 bytes each.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":30,\"distinctValues\":false,\"properties\":[{\"name\":\"slice\",\"type\":\"PropertByteArray\",\"size\":3,\"distinctValues\":true,\"properties\":[{\"name\":\"systemEventClass\",\"type\":\"PropertyString\",\"description\":\"System event class.\",\"possibleValues\":[\"BUTTON1\",\"BUTTON2\",\"BUZZER\",\"ACCELEROMETER\",\"POWER\",\"TEMPERATURE\",\"GEOLOCATION\",\"CONFIGURATION\",\"NETWORK\",\"CORE\",\"BLE_CONNECTIVITY\",\"USER\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8,9,10,11]},{\"name\":\"melodyCountExtension\",\"type\":\"PropertyNumber\",\"description\":\"Melody count extension\"},{\"name\":\"type\",\"type\":\"PropertyNumber\",\"description\":\"System event type.\"},{\"name\":\"melodyIdentifier\",\"type\":\"PropertyString\",\"description\":\"Defines the LED behavior.\",\"possibleValues\":[\"NOT_CONFIGURED\",\"OFF\",\"MELODY_1\",\"MELODY_2\",\"MELODY_3\"],\"firmwareValues\":[0,1,2,3,4]},{\"name\":\"melodyCount\",\"type\":\"PropertyNumber\",\"description\":\"Number of times the melody is displayed.\"}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"systemEventClass\",\"bitShift\":0,\"length\":5},{\"type\":\"BitMaskValue\",\"valueFor\":\"melodyCountExtension\",\"bitShift\":5,\"length\":3},{\"type\":\"BitMaskValue\",\"valueFor\":\"type\",\"bitShift\":8,\"length\":8},{\"type\":\"BitMaskValue\",\"valueFor\":\"melodyIdentifier\",\"bitShift\":16,\"length\":5},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternLoop\",\"bitShift\":21,\"length\":3}]}],\"byteMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"slice\",\"bitShift\":0,\"length\":24}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreBuzzerMap\",\"groupId\":\"0x01\",\"localId\":\"0x0B\",\"defaultValue\":\"{00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00}\",\"description\":\"Defines LED patterns for system events. Configurable as 10 slices of 3 bytes each.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":30,\"distinctValues\":false,\"properties\":[{\"name\":\"slice\",\"type\":\"PropertByteArray\",\"size\":3,\"distinctValues\":true,\"properties\":[{\"name\":\"systemEventClass\",\"type\":\"PropertyString\",\"description\":\"System event class.\",\"possibleValues\":[\"BUTTON1\",\"BUTTON2\",\"BUZZER\",\"ACCELEROMETER\",\"POWER\",\"TEMPERATURE\",\"GEOLOCATION\",\"CONFIGURATION\",\"NETWORK\",\"CORE\",\"BLE_CONNECTIVITY\",\"USER\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8,9,10,11]},{\"name\":\"melodyCountExtension\",\"type\":\"PropertyNumber\",\"description\":\"Melody count extension\"},{\"name\":\"type\",\"type\":\"PropertyNumber\",\"description\":\"System event type.\"},{\"name\":\"melodyIdentifier\",\"type\":\"PropertyString\",\"description\":\"Defines the LED behavior.\",\"possibleValues\":[\"NOT_CONFIGURED\",\"OFF\",\"MELODY_2\",\"MELODY_3\",\"MELODY_4\",\"MELODY_5\",\"MELODY_6\",\"MELODY_7\",\"MELODY_8\",\"MELODY_9\",\"MELODY_10\",\"MELODY_11\",\"MELODY_12\",\"MELODY_13\",\"MELODY_14\",\"MELODY_15\",\"MELODY_16\",\"MELODY_17\",\"MELODY_18\",\"MELODY_19\",\"MELODY_20\",\"MELODY_21\"],\"firmwareValues\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},{\"name\":\"melodyCount\",\"type\":\"PropertyNumber\",\"description\":\"Number of times the melody is displayed.\"}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"systemEventClass\",\"bitShift\":0,\"length\":5},{\"type\":\"BitMaskValue\",\"valueFor\":\"melodyCountExtension\",\"bitShift\":5,\"length\":3},{\"type\":\"BitMaskValue\",\"valueFor\":\"type\",\"bitShift\":8,\"length\":8},{\"type\":\"BitMaskValue\",\"valueFor\":\"melodyIdentifier\",\"bitShift\":16,\"length\":5},{\"type\":\"BitMaskValue\",\"valueFor\":\"patternLoop\",\"bitShift\":21,\"length\":3}]}],\"byteMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"slice\",\"bitShift\":0,\"length\":24}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreAlmanacValidity\",\"groupId\":\"0x01\",\"localId\":\"0x0C\",\"defaultValue\":120,\"unit\":\"days\",\"description\":\"Number of days for which the GNSS almanac is considered as valid.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":7,\"maximum\":365}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreAlmanacOutdatedRatio\",\"groupId\":\"0x01\",\"localId\":\"0x0D\",\"defaultValue\":100,\"unit\":\"%\",\"description\":\"Percentage of outdated GNSS almanac entries which will trigger network update requests. A value of 100% disable the network requests. Applicable for both GNSS devices\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":100}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"coreCliPassword\",\"groupId\":\"0x01\",\"localId\":\"0x0E\",\"defaultValue\":123,\"description\":\"User cli password\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocMotionPeriod\",\"groupId\":\"0x02\",\"localId\":\"0x00\",\"defaultValue\":300,\"unit\":\"s\",\"description\":\"Position acquisition period while in motion\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":10,\"maximum\":86400}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocStaticPeriod\",\"groupId\":\"0x02\",\"localId\":\"0x01\",\"defaultValue\":3600,\"unit\":\"s\",\"description\":\"Position acquisition period while static\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":10,\"maximum\":86400}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocSosPeriod\",\"groupId\":\"0x02\",\"localId\":\"0x02\",\"defaultValue\":60,\"unit\":\"s\",\"description\":\"Position acquisition period while in sos\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":10,\"maximum\":86400}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocMotionNbStart\",\"groupId\":\"0x02\",\"localId\":\"0x03\",\"defaultValue\":1,\"description\":\"Number of acquisitions on motion start event\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":10}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocMotionNbStop\",\"groupId\":\"0x02\",\"localId\":\"0x04\",\"defaultValue\":1,\"description\":\"Number of acquisitions on motion stop event\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":10}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocStartStopPeriod\",\"groupId\":\"0x02\",\"localId\":\"0x05\",\"defaultValue\":120,\"unit\":\"s\",\"description\":\"Position acquisition period while acquiring consecutive positions on motion start or stop\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":10,\"maximum\":86400}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocGnssHoldOnMode\",\"groupId\":\"0x02\",\"localId\":\"0x06\",\"description\":\"Select the GNSS hold on mode. Possible Values are:\\\\n0: Disabled\\\\n1: Always. Hold-on mode always set. Only controlled by the timer.\\\\n2: techno: If the gnss is actually used (meaning GNSS techno not skipped).\\\\n3: moving: Hold-mode set while moving.\\\\n4: techno and moving: if the gnss is actually used (meaning GNSS techno not skipped) and tracker is moving.\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"DISABLED\",\"ALWAYS\",\"TECHNO\",\"MOVING\",\"STATIC\",\"TECHNO_AND_MOVING\"],\"firmwareValues\":[0,1,2,3,4,5]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocGnssHoldOnTimeout\",\"groupId\":\"0x02\",\"localId\":\"0x07\",\"defaultValue\":0,\"unit\":\"s\",\"description\":\"GNSS hold on mode timeout.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":86400}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocProfile0Triggers\",\"groupId\":\"0x02\",\"localId\":\"0x08\",\"description\":\"Geolocation event triggers 0\",\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"geoTriggerPod\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on Position-on-demand via downlink or via button.\"},{\"name\":\"geoTriggerSos\",\"type\":\"PropertyBoolean\",\"description\":\"SOS started\"},{\"name\":\"geoTriggerMotionStart\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on motion start event\"},{\"name\":\"geoTriggerMotionStop\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on motion stop event\"},{\"name\":\"geoTriggerInMotion\",\"type\":\"PropertyBoolean\",\"description\":\"Periodic geoloc while the tracker is in motion\"},{\"name\":\"geoTriggerInStatic\",\"type\":\"PropertyBoolean\",\"description\":\"Periodic geoloc running while the tracker is static\"},{\"name\":\"geoTriggerShock\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on shock action\"},{\"name\":\"geoTriggerTempHighThreshold\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on temperature high.\"},{\"name\":\"geoTriggerTempLowThreshold\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on temperature high.\"},{\"name\":\"geoTriggerGeozoning\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on geoTriggerGeozoning\"}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerPod\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerSos\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerMotionStart\",\"bitShift\":2,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerMotionStop\",\"bitShift\":3,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerInMotion\",\"bitShift\":4,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerInStatic\",\"bitShift\":5,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerShock\",\"bitShift\":6,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerTempHighThreshold\",\"bitShift\":7,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerTempLowThreshold\",\"bitShift\":8,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerGeozoning\",\"bitShift\":9,\"length\":1}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocProfile1Triggers\",\"groupId\":\"0x02\",\"localId\":\"0x09\",\"description\":\"Geolocation event triggers 1\",\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"geoTriggerPod\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on Position-on-demand via downlink or via button.\"},{\"name\":\"geoTriggerSos\",\"type\":\"PropertyBoolean\",\"description\":\"SOS started\"},{\"name\":\"geoTriggerMotionStart\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on motion start event\"},{\"name\":\"geoTriggerMotionStop\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on motion stop event\"},{\"name\":\"geoTriggerInMotion\",\"type\":\"PropertyBoolean\",\"description\":\"Periodic geoloc while the tracker is in motion\"},{\"name\":\"geoTriggerInStatic\",\"type\":\"PropertyBoolean\",\"description\":\"Periodic geoloc running while the tracker is static\"},{\"name\":\"geoTriggerShock\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on shock action\"},{\"name\":\"geoTriggerTempHighThreshold\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on temperature high.\"},{\"name\":\"geoTriggerTempLowThreshold\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on temperature high.\"},{\"name\":\"geoTriggerGeozoning\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on temperature low.\"}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerPod\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerSos\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerMotionStart\",\"bitShift\":2,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerMotionStop\",\"bitShift\":3,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerInMotion\",\"bitShift\":4,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerInStatic\",\"bitShift\":5,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerShock\",\"bitShift\":6,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerTempHighThreshold\",\"bitShift\":7,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerTempLowThreshold\",\"bitShift\":8,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerGeozoning\",\"bitShift\":9,\"length\":1}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocProfile2Triggers\",\"groupId\":\"0x02\",\"localId\":\"0x0A\",\"description\":\"Geolocation event triggers 2\",\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"geoTriggerPod\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on Position-on-demand via downlink or via button.\"},{\"name\":\"geoTriggerSos\",\"type\":\"PropertyBoolean\",\"description\":\"SOS started\"},{\"name\":\"geoTriggerMotionStart\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on motion start event\"},{\"name\":\"geoTriggerMotionStop\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on motion stop event\"},{\"name\":\"geoTriggerInMotion\",\"type\":\"PropertyBoolean\",\"description\":\"Periodic geoloc while the tracker is in motion\"},{\"name\":\"geoTriggerInStatic\",\"type\":\"PropertyBoolean\",\"description\":\"Periodic geoloc running while the tracker is static\"},{\"name\":\"geoTriggerShock\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on shock action\"},{\"name\":\"geoTriggerTempHighThreshold\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on temperature high.\"},{\"name\":\"geoTriggerTempLowThreshold\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on temperature high.\"},{\"name\":\"geoTriggerGeozoning\",\"type\":\"PropertyBoolean\",\"description\":\"Geoloc triggered on temperature low.\"}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerPod\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerSos\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerMotionStart\",\"bitShift\":2,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerMotionStop\",\"bitShift\":3,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerInMotion\",\"bitShift\":4,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerInStatic\",\"bitShift\":5,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerShock\",\"bitShift\":6,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerTempHighThreshold\",\"bitShift\":7,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerTempLowThreshold\",\"bitShift\":8,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"geoTriggerGeozoning\",\"bitShift\":9,\"length\":1}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocGbeProfile0Techno\",\"groupId\":\"0x02\",\"localId\":\"0x0B\",\"description\":\"Technologies to schedule using the basic engine for events in triggers 0\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":6,\"properties\":[{\"name\":\"Action\",\"type\":\"PropertyString\",\"possibleValues\":[\"SKIP_ON_SUCCESS\",\"ALWAYS_DONE\"],\"firmwareValues\":[0,1]},{\"name\":\"Technology\",\"type\":\"PropertyString\",\"possibleValues\":[\"NONE\",\"LR11xx_A_GNSS\",\"WIFI\",\"BLE_SCAN1\",\"BLE_SCAN2\",\"AIDED_GNSS\",\"GNSS\"],\"firmwareValues\":[0,1,2,3,4,5,6]}],\"byteMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"Technology\",\"bitShift\":0,\"length\":7},{\"type\":\"BitMaskValue\",\"valueFor\":\"Action\",\"bitShift\":7,\"length\":1}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocGbeProfile1Techno\",\"groupId\":\"0x02\",\"localId\":\"0x0C\",\"description\":\"Technologies to schedule using the basic engine for events in triggers 1\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":6,\"properties\":[{\"name\":\"Action\",\"type\":\"PropertyString\",\"possibleValues\":[\"SKIP_ON_SUCCESS\",\"ALWAYS_DONE\"],\"firmwareValues\":[0,1]},{\"name\":\"Technology\",\"type\":\"PropertyString\",\"possibleValues\":[\"NONE\",\"LR11xx_A_GNSS\",\"WIFI\",\"BLE_SCAN1\",\"BLE_SCAN2\",\"AIDED_GNSS\",\"GNSS\"],\"firmwareValues\":[0,1,2,3,4,5,6]}],\"byteMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"Technology\",\"bitShift\":0,\"length\":7},{\"type\":\"BitMaskValue\",\"valueFor\":\"Action\",\"bitShift\":7,\"length\":1}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"geolocGbeProfile2Techno\",\"groupId\":\"0x02\",\"localId\":\"0x0D\",\"description\":\"Technologies to schedule using the basic engine for events in triggers 2\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":6,\"properties\":[{\"name\":\"Action\",\"type\":\"PropertyString\",\"possibleValues\":[\"SKIP_ON_SUCCESS\",\"ALWAYS_DONE\"],\"firmwareValues\":[0,1]},{\"name\":\"Technology\",\"type\":\"PropertyString\",\"possibleValues\":[\"NONE\",\"LR11xx_A_GNSS\",\"WIFI\",\"BLE_SCAN1\",\"BLE_SCAN2\",\"AIDED_GNSS\",\"GNSS\"],\"firmwareValues\":[0,1,2,3,4,5,6]}],\"byteMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"Technology\",\"bitShift\":0,\"length\":7},{\"type\":\"BitMaskValue\",\"valueFor\":\"Action\",\"bitShift\":7,\"length\":1}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssConstellation\",\"groupId\":\"0x03\",\"localId\":\"0x00\",\"defaultValue\":2,\"description\":\"GNSS constellations to be used\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"GPS_ONLY\",\"GLONASS_ONLY\",\"GPS_GLONASS\",\"GPS_GALILEO\",\"GPS_GLONASS_GALILEO\",\"BEIDOU_ONLY\",\"BEIDOU_GPS\"],\"firmwareValues\":[0,1,2,3,4,5,6]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssMaxTime\",\"groupId\":\"0x03\",\"localId\":\"0x01\",\"defaultValue\":300,\"unit\":\"s\",\"description\":\"GNSS max acquisition time.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":30,\"maximum\":300}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssT0TimeoutStatic\",\"groupId\":\"0x03\",\"localId\":\"0x02\",\"defaultValue\":30,\"unit\":\"s\",\"description\":\"Max time to acquire at least one satellite when tracker is static\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":300}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssEhpeStatic\",\"groupId\":\"0x03\",\"localId\":\"0x03\",\"defaultValue\":30,\"unit\":\"m\",\"description\":\"Expected estimated horizontal position error when the tracker is static\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":100}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssConvergenceStatic\",\"groupId\":\"0x03\",\"localId\":\"0x04\",\"defaultValue\":20,\"unit\":\"s\",\"description\":\"Extra-time after a first fix to refine the fix\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":300}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssT0TimeoutMotion\",\"groupId\":\"0x03\",\"localId\":\"0x05\",\"defaultValue\":30,\"unit\":\"s\",\"description\":\"Max time to acquire at least one satellite when tracker is moving\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":300}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssEhpeMotion\",\"groupId\":\"0x03\",\"localId\":\"0x06\",\"defaultValue\":30,\"unit\":\"m\",\"description\":\"Expected estimated horizontal position error when the tracker is moving\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":100}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssConvergenceMotion\",\"groupId\":\"0x03\",\"localId\":\"0x07\",\"defaultValue\":20,\"unit\":\"s\",\"description\":\"Extra-time after a first fix to refine the fix when the tracker is moving\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":300}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssStandby\",\"groupId\":\"0x03\",\"localId\":\"0x08\",\"defaultValue\":604800,\"unit\":\"s\",\"description\":\"Max time to let the device in standby mode.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssAgnssMaxTime\",\"groupId\":\"0x03\",\"localId\":\"0x09\",\"defaultValue\":45,\"unit\":\"s\",\"description\":\"Aided GNSS max acquisition time.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":15,\"maximum\":240}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"gnssT1Timeout\",\"groupId\":\"0x03\",\"localId\":\"0x0A\",\"defaultValue\":0,\"unit\":\"s\",\"description\":\"Extra time let in Aided GNSS mode to try doing a fix.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":300}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lrConstellation\",\"groupId\":\"0x04\",\"localId\":\"0x00\",\"description\":\"GNSS constellations to be used\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"GPS_ONLY\",\"BEIDOU_ONLY\",\"BEIDOU_GPS\"],\"firmwareValues\":[0,5,6]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lrScanMode\",\"groupId\":\"0x04\",\"localId\":\"0x01\",\"description\":\"Scan mode (NAV1 / NAV2)\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"NAV1_SCAN\",\"NAV2_SCAN\"],\"firmwareValues\":[1,2]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lrNbScans\",\"groupId\":\"0x04\",\"localId\":\"0x02\",\"defaultValue\":2,\"description\":\"Number of scans for one position acquisition\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":4}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lrInterScanTime\",\"groupId\":\"0x04\",\"localId\":\"0x03\",\"defaultValue\":5,\"unit\":\"s\",\"description\":\"Time to wait between the scans for a position\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":15}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lrWifiReportNbBssid\",\"groupId\":\"0x04\",\"localId\":\"0x04\",\"defaultValue\":4,\"description\":\"Max number of WIFI BSSID per scan\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":32}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lrWifiMinNbBssid\",\"groupId\":\"0x04\",\"localId\":\"0x05\",\"defaultValue\":3,\"description\":\"Minimum number of BSSID to consider the scan as success (solvable)\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":10}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lrWifiMinRssi\",\"groupId\":\"0x04\",\"localId\":\"0x06\",\"defaultValue\":3,\"description\":\"Minimum number of BSSID to consider the scan as success (solvable)\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":-100,\"maximum\":0}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lrWifiBssidMacType\",\"groupId\":\"0x04\",\"localId\":\"0x07\",\"defaultValue\":1,\"description\":\"MAC administration type of the BSSID to report.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":2}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanDuration\",\"groupId\":\"0x05\",\"localId\":\"0x00\",\"defaultValue\":3000,\"unit\":\"ms\",\"description\":\"Total time for a BLE scan\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":50,\"maximum\":61440}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanWindow\",\"groupId\":\"0x05\",\"localId\":\"0x01\",\"defaultValue\":120,\"unit\":\"ms\",\"description\":\"Scan window\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":3,\"maximum\":10240}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanInterval\",\"groupId\":\"0x05\",\"localId\":\"0x02\",\"defaultValue\":130,\"unit\":\"ms\",\"description\":\"Scan interval\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":10240}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanType\",\"groupId\":\"0x05\",\"localId\":\"0x03\",\"defaultValue\":0,\"description\":\"Type of beacons to scan\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"ALL_BEACONS\",\"EDDYSTONE_UUID\",\"EDDYSTONE_URL\",\"ALL_EDDYSTONE\",\"IBEACON_ONLY\",\"ALTBEACON_ONLY\",\"CUSTOM\",\"EXPOSURE_ADVERTISEMENT\"],\"firmwareValues\":[0,1,2,3,4,5,6,7]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanMinRssi\",\"groupId\":\"0x05\",\"localId\":\"0x04\",\"defaultValue\":-80,\"unit\":\"dB\",\"description\":\"Min RSSI to consider the beacon\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":-120,\"maximum\":0}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanMinNbBeacons\",\"groupId\":\"0x05\",\"localId\":\"0x05\",\"defaultValue\":1,\"description\":\"Min number of beacons to consider the scan as success (solvable).\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":20}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter1Mask\",\"groupId\":\"0x05\",\"localId\":\"0x06\",\"defaultValue\":[0],\"description\":\"Mask (10 bytes) to be applied to the ADV frame.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":10},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter1Value\",\"groupId\":\"0x05\",\"localId\":\"0x07\",\"defaultValue\":[0],\"description\":\"Comparison value (10 bytes) belonging to filter1\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":10},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter1Offset\",\"groupId\":\"0x05\",\"localId\":\"0x08\",\"defaultValue\":0,\"description\":\"Offset in the ADV from which we apply the filter1\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":256}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter2Mask\",\"groupId\":\"0x05\",\"localId\":\"0x09\",\"defaultValue\":[0],\"description\":\"Mask (10 bytes) to be applied to the ADV frame.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":10},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter2Value\",\"groupId\":\"0x05\",\"localId\":\"0x0A\",\"defaultValue\":[0],\"description\":\"Comparison value (10 bytes) belonging to filter2\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":10},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter2Offset\",\"groupId\":\"0x05\",\"localId\":\"0x0B\",\"defaultValue\":0,\"description\":\"Offset in the ADV from which we apply the filter2\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":256}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanNbBeacons\",\"groupId\":\"0x05\",\"localId\":\"0x0C\",\"defaultValue\":4,\"description\":\"Number of beacons to report\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":20}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanReportType\",\"groupId\":\"0x05\",\"localId\":\"0x0D\",\"defaultValue\":0,\"description\":\"Scan report type\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"MAC_ADDRESS\",\"SHORT_IDENTIFIER\",\"LONG_IDENTIFIER\"],\"firmwareValues\":[0,1,2]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanReportIdOfs\",\"groupId\":\"0x05\",\"localId\":\"0x0E\",\"defaultValue\":4,\"description\":\"Offset in ADV to extract the beacon identifier\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":256}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanDuration\",\"groupId\":\"0x06\",\"localId\":\"0x00\",\"defaultValue\":3000,\"unit\":\"ms\",\"description\":\"Total time for a BLE scan\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":50,\"maximum\":61440}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanWindow\",\"groupId\":\"0x06\",\"localId\":\"0x01\",\"defaultValue\":120,\"unit\":\"ms\",\"description\":\"Scan window\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":3,\"maximum\":10240}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanInterval\",\"groupId\":\"0x06\",\"localId\":\"0x02\",\"defaultValue\":130,\"unit\":\"ms\",\"description\":\"Scan interval\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":10240}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanType\",\"groupId\":\"0x06\",\"localId\":\"0x03\",\"defaultValue\":0,\"description\":\"Type of beacons to scan\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"ALL_BEACONS\",\"EDDYSTONE_UUID\",\"EDDYSTONE_URL\",\"ALL_EDDYSTONE\",\"IBEACON_ONLY\",\"ALTBEACON_ONLY\",\"CUSTOM\",\"EXPOSURE_ADVERTISEMENT\"],\"firmwareValues\":[0,1,2,3,4,5,6,7]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanMinRssi\",\"groupId\":\"0x06\",\"localId\":\"0x04\",\"defaultValue\":-100,\"unit\":\"dB\",\"description\":\"Min RSSI to consider the beacon\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":-120,\"maximum\":0}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanMinNbBeacons\",\"groupId\":\"0x06\",\"localId\":\"0x05\",\"defaultValue\":1,\"description\":\"Min number of beacons to consider the scan as success (solvable).\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":20}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter1Mask\",\"groupId\":\"0x06\",\"localId\":\"0x06\",\"defaultValue\":[0],\"description\":\"Mask (10 bytes) to be applied to the ADV frame.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":10},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter1Value\",\"groupId\":\"0x06\",\"localId\":\"0x07\",\"defaultValue\":[0],\"description\":\"Comparison value (10 bytes) belonging to filter1\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":10},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter1Offset\",\"groupId\":\"0x06\",\"localId\":\"0x08\",\"defaultValue\":0,\"description\":\"Offset in the ADV from which we apply the filter1\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":256}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter2Mask\",\"groupId\":\"0x06\",\"localId\":\"0x09\",\"defaultValue\":[0],\"description\":\"Mask (10 bytes) to be applied to the ADV frame.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":10},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter2Value\",\"groupId\":\"0x06\",\"localId\":\"0x0A\",\"defaultValue\":[0],\"description\":\"Comparison value (10 bytes) belonging to filter2\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":10},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanFilter2Offset\",\"groupId\":\"0x06\",\"localId\":\"0x0B\",\"defaultValue\":0,\"description\":\"Offset in the ADV from which we apply the filter2\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":256}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanNbBeacons\",\"groupId\":\"0x06\",\"localId\":\"0x0C\",\"defaultValue\":4,\"description\":\"Number of beacons to report\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":20}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanReportType\",\"groupId\":\"0x06\",\"localId\":\"0x0D\",\"defaultValue\":0,\"description\":\"Scan report type\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"MAC_ADDRESS\",\"SHORT_IDENTIFIER\",\"LONG_IDENTIFIER\"],\"firmwareValues\":[0,1,2]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleScanReportIdOfs\",\"groupId\":\"0x06\",\"localId\":\"0x0E\",\"defaultValue\":4,\"description\":\"Offset in ADV to extract the beacon identifier\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":256}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"acceleroMotionSensi\",\"groupId\":\"0x07\",\"localId\":\"0x00\",\"defaultValue\":1,\"unit\":\"mg\",\"description\":\"Motion sensitivity. Step 31 mg.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":96},\"multiply\":31},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"acceleroMotionDuration\",\"groupId\":\"0x07\",\"localId\":\"0x01\",\"defaultValue\":120,\"unit\":\"s\",\"description\":\"Motion duration\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":10,\"maximum\":3600}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"acceleroFullScale\",\"groupId\":\"0x07\",\"localId\":\"0x02\",\"defaultValue\":3,\"description\":\"Scale use (2,4,8,16 g).\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"2_G\",\"4_G\",\"8_G\",\"16_G\"],\"firmwareValues\":[0,1,2,3]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"acceleroOutputDataRate\",\"groupId\":\"0x07\",\"localId\":\"0x03\",\"defaultValue\":0,\"description\":\"Output data rate (12.5, 25, 50, 100, 200 Hz).\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"12_5_HZ\",\"25_HZ\",\"50_HZ\",\"100_HZ\",\"200_HZ\"],\"firmwareValues\":[0,1,2,3,4]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"acceleroShockThreshold\",\"groupId\":\"0x07\",\"localId\":\"0x04\",\"defaultValue\":0,\"description\":\"Shock threshold. Step 63 mg\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":128},\"multiply\":63},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"netSelection\",\"groupId\":\"0x08\",\"localId\":\"0x00\",\"defaultValue\":0,\"description\":\"Define the networking type\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"LORA_ONLY\",\"CELLULAR_ONLY\",\"LORA_FALLBACK_CELLULAR\",\"CELLULAR_FALLBACK_LORA\"],\"firmwareValues\":[0,1,2,3]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"netReconnectionSpacing\",\"groupId\":\"0x08\",\"localId\":\"0x01\",\"defaultValue\":600,\"description\":\"Time to wait before retrying to connect the main network\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":2147483647}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"netMainProbeTimeout\",\"groupId\":\"0x08\",\"localId\":\"0x02\",\"defaultValue\":600,\"description\":\"Duration between each attempts reconnect the main network.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":120,\"maximum\":2147483647}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanCnxTimeout\",\"groupId\":\"0x09\",\"localId\":\"0x00\",\"defaultValue\":0,\"description\":\"Max time to wait for joining the network. The value 0 disables the timer.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":2147483647}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanDlTriggerPeriod\",\"groupId\":\"0x09\",\"localId\":\"0x01\",\"defaultValue\":3600,\"unit\":\"s\",\"description\":\"Period at which an empty uplink is sent to trigger a downlink. 0 disable the function.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":2147483647}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanProbeMaxAttempts\",\"groupId\":\"0x09\",\"localId\":\"0x02\",\"defaultValue\":4,\"description\":\"Number of link-check sent declaring the network as lost\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":10}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanProbePeriod\",\"groupId\":\"0x09\",\"localId\":\"0x03\",\"defaultValue\":43200,\"description\":\"Time between link-check requests\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":120,\"maximum\":2147483647}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanConfirmNotifMap\",\"groupId\":\"0x09\",\"localId\":\"0x04\",\"defaultValue\":\"{00}\",\"description\":\"Map enabling the LoRaWAN confirmed message for notifications.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":6,\"distinctValues\":true,\"properties\":[{\"name\":\"systemClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"status\",\"type\":\"PropertyBoolean\",\"description\":\"System status Versions, temperature, reset cause.\"},{\"name\":\"lowBattery\",\"type\":\"PropertyBoolean\",\"description\":\"Low battery alert.\"},{\"name\":\"bleStatus\",\"type\":\"PropertyBoolean\",\"description\":\"Bluetooth Low Energy status\"},{\"name\":\"tamperDetection\",\"type\":\"PropertyBoolean\",\"description\":\"Tamper detection alert.\"}]},{\"name\":\"sosClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"sosOn\",\"type\":\"PropertyBoolean\",\"description\":\"SOS activated.\"},{\"name\":\"sosOff\",\"type\":\"PropertyBoolean\",\"description\":\"SOS deactivated.\"}]},{\"name\":\"temperatureClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"tempHigh\",\"type\":\"PropertyBoolean\",\"description\":\"Critical high temperature reached\"},{\"name\":\"tempLow\",\"type\":\"PropertyBoolean\",\"description\":\"Critical low temperature reached\"},{\"name\":\"tempNormal\",\"type\":\"PropertyBoolean\",\"description\":\"Temperature back to normal\"}]},{\"name\":\"accelerometerClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"motionStart\",\"type\":\"PropertyBoolean\",\"description\":\"Motion start detected.\"},{\"name\":\"motionEnd\",\"type\":\"PropertyBoolean\",\"description\":\"Motion end detected.\"},{\"name\":\"shock\",\"type\":\"PropertyBoolean\",\"description\":\"Shock detected.\"}]},{\"name\":\"networkingClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"mainUp\",\"type\":\"PropertyBoolean\",\"description\":\"Main network is up.\"},{\"name\":\"backupUp\",\"type\":\"PropertyBoolean\",\"description\":\"Main network down. Backup is up.\"}]},{\"name\":\"geozoningClass\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"geozoningOn\",\"type\":\"PropertyBoolean\",\"description\":\"Geozoning is on.\"}]}],\"byteMask\":[{\"valueFor\":\"systemClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"status\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"lowBattery\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"bleStatus\",\"bitShift\":2,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"tamperDetection\",\"bitShift\":3,\"length\":1}]},{\"valueFor\":\"sosClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"sosOn\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"sosOff\",\"bitShift\":1,\"length\":1}]},{\"valueFor\":\"temperatureClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"tempHigh\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"tempLow\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"tempNormal\",\"bitShift\":2,\"length\":1}]},{\"valueFor\":\"accelerometerClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"motionStart\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"motionEnd\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"shock\",\"bitShift\":2,\"length\":1}]},{\"valueFor\":\"networkingClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"mainUp\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"backupUp\",\"bitShift\":1,\"length\":1}]},{\"valueFor\":\"geozoningClass\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"geozoningOn\",\"bitShift\":0,\"length\":1}]}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanConfirmNotifRetry\",\"groupId\":\"0x09\",\"localId\":\"0x05\",\"defaultValue\":0,\"description\":\"Time between link-check requests\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":15}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanS1TxStrategy\",\"groupId\":\"0x09\",\"localId\":\"0x06\",\"defaultValue\":473102,\"description\":\"Socket 1. Transmission strategy\",\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"ADREnabled\",\"type\":\"PropertyBoolean\",\"description\":\"true: to enable the LoRa network ADR if the tracker is static. false: to disable the network ADR regardless the motion state of the tracker\"},{\"name\":\"dualTransmissionInStaticEnabled\",\"type\":\"PropertyBoolean\",\"description\":\"Control the dual transmission when the tracker is static. true: to enable the dual transmission in static state. false: to disable it\"},{\"name\":\"dualTransmissionInMotionEnabled\",\"type\":\"PropertyBoolean\",\"description\":\"Control the dual transmission when the tracker is in motion. true: to enable the dual transmission in motion state. false: to disable it in motion state.\"},{\"name\":\"dataRateModification\",\"type\":\"PropertyBoolean\",\"description\":\"Control the DR (Datarate) modification for over-sized messages. true: to allow AOS to adapt the DR for messages not fitting the allowed size for a given datarate.false: to prevent sending of over-sized messages\"},{\"name\":\"firstTransmissionDatarate\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"dr0\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr0 is disabled. true: dr0 is enabled.\"},{\"name\":\"dr1\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr1 is disabled. true: dr1 is enabled.\"},{\"name\":\"dr2\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr2 is disabled. true: dr2 is enabled.\"},{\"name\":\"dr3\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr3 is disabled. true: dr3 is enabled.\"},{\"name\":\"dr4\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr4 is disabled. true: dr4 is enabled.\"},{\"name\":\"dr5\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr5 is disabled. true: dr5 is enabled.\"},{\"name\":\"dr6\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr6 is disabled. true: dr6 is enabled.\"},{\"name\":\"dr7\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr7 is disabled. true: dr7 is enabled.\"}]},{\"name\":\"secondTransmissionDatarate\",\"type\":\"PropertyObject\",\"properties\":[{\"name\":\"dr0\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr0 is disabled. true: dr0 is enabled.\"},{\"name\":\"dr1\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr1 is disabled. true: dr1 is enabled.\"},{\"name\":\"dr2\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr2 is disabled. true: dr2 is enabled.\"},{\"name\":\"dr3\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr3 is disabled. true: dr3 is enabled.\"},{\"name\":\"dr4\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr4 is disabled. true: dr4 is enabled.\"},{\"name\":\"dr5\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr5 is disabled. true: dr5 is enabled.\"},{\"name\":\"dr6\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr6 is disabled. true: dr6 is enabled.\"},{\"name\":\"dr7\",\"type\":\"PropertyBoolean\",\"description\":\"false: dr7 is disabled. true: dr7 is enabled.\"}]}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"ADREnabled\",\"bitShift\":0,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dualTransmissionInStaticEnabled\",\"bitShift\":1,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dualTransmissionInMotionEnabled\",\"bitShift\":2,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dataRateModification\",\"bitShift\":3,\"length\":1},{\"valueFor\":\"firstTransmissionDatarate\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"dr0\",\"bitShift\":8,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr1\",\"bitShift\":9,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr2\",\"bitShift\":10,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr3\",\"bitShift\":11,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr4\",\"bitShift\":12,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr5\",\"bitShift\":13,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr6\",\"bitShift\":14,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr7\",\"bitShift\":15,\"length\":1}]},{\"valueFor\":\"secondTransmissionDatarate\",\"type\":\"BitMaskObject\",\"values\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"dr0\",\"bitShift\":16,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr1\",\"bitShift\":17,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr2\",\"bitShift\":18,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr3\",\"bitShift\":19,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr4\",\"bitShift\":20,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr5\",\"bitShift\":21,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr6\",\"bitShift\":22,\"length\":1},{\"type\":\"BitMaskValue\",\"valueFor\":\"dr7\",\"bitShift\":23,\"length\":1}]}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanS1UlPort\",\"groupId\":\"0x09\",\"localId\":\"0x07\",\"defaultValue\":19,\"description\":\"Socket 1. Uplink port\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":252}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"lorawanS1DlPort\",\"groupId\":\"0x09\",\"localId\":\"0x08\",\"defaultValue\":3,\"description\":\"Socket 1. Downlink port\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":252}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellSimInterface\",\"groupId\":\"0x0A\",\"localId\":\"0x00\",\"description\":\"Sim interface.\",\"defaultValue\":\"\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"SIM0\",\"E_SIM\"],\"firmwareValues\":[0,1]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellNetworkType\",\"groupId\":\"0x0A\",\"localId\":\"0x01\",\"description\":\"Network type\",\"defaultValue\":\"\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"CELLULAR_NOT_USED\",\"LTE_M\",\"NB_IOT\"],\"firmwareValues\":[0,1,2]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellSearchBands\",\"groupId\":\"0x0A\",\"localId\":\"0x02\",\"defaultValue\":\"{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00}\",\"description\":\"Radio frequency bands scanned to search a cell.\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\",\"size\":19},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellCnxTimeoutStatic\",\"groupId\":\"0x0A\",\"localId\":\"0x03\",\"defaultValue\":180,\"unit\":\"s\",\"description\":\"Duration during which the modem searches for a cellular network. Applicable when the tracker is static.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":180,\"maximum\":900}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellCnxTimeoutMotion\",\"groupId\":\"0x0A\",\"localId\":\"0x04\",\"defaultValue\":300,\"unit\":\"s\",\"description\":\"Duration during which the modem searches for a cellular network. Applicable when the tracker is motion.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":180,\"maximum\":900}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellCnxNwLostTimeout\",\"groupId\":\"0x0A\",\"localId\":\"0x05\",\"defaultValue\":60,\"unit\":\"s\",\"description\":\"Duration let to the modem to automatically recover the network after a network lost.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":900}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellCnxMaxAttempts\",\"groupId\":\"0x0A\",\"localId\":\"0x06\",\"defaultValue\":3,\"description\":\"Number of times the network search is repeated before shutting down the modem.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":1,\"maximum\":10}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellAccessPointName\",\"groupId\":\"0x0A\",\"localId\":\"0x07\",\"description\":\"String providing the service access point name. If not provided, this information is retrieve from the SIM.\",\"defaultValue\":\"\",\"parameterType\":{\"type\":\"ParameterTypeAsciiString\",\"maxSize\":32},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellOperatorSimSlot0\",\"groupId\":\"0x0A\",\"localId\":\"0x08\",\"description\":\"Cellular operator name when using the SIM0\",\"defaultValue\":\"\",\"parameterType\":{\"type\":\"ParameterTypeAsciiString\",\"maxSize\":32},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellOperatorSimSlot1\",\"groupId\":\"0x0A\",\"localId\":\"0x09\",\"description\":\"Cellular operator name when using the SIM1 (E.SIM).\",\"defaultValue\":\"\",\"parameterType\":{\"type\":\"ParameterTypeAsciiString\",\"maxSize\":32},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellLowPowerMode\",\"groupId\":\"0x0A\",\"localId\":\"0x0A\",\"description\":\"Low power mode\",\"defaultValue\":\"\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"DISABLED\",\"PSM\",\"EDRX\",\"PSM_EDRX\"],\"firmwareValues\":[0,1,2,3]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellPsmTauPeriod\",\"groupId\":\"0x0A\",\"localId\":\"0x0B\",\"description\":\"Bit-field giving the requested TAU period.\",\"defaultValue\":254,\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"timerValue\",\"type\":\"PropertyNumber\"},{\"name\":\"timerValueUnit\",\"type\":\"PropertyString\",\"possibleValues\":[\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_10_MINUTES\",\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_1_HOUR\",\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_10_HOURS\",\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_2_SECONDS\",\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_30_SECONDS\",\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_1_MINUTE\",\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_320_HOURS\",\"THE_TIMER_IS_DEACTIVATED\"],\"firmwareValues\":[0,1,2,3,4,5,6,7]}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"timerValue\",\"bitShift\":0,\"length\":5},{\"type\":\"BitMaskValue\",\"valueFor\":\"timerValueUnit\",\"bitShift\":5,\"length\":3}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellPsmActiveTime\",\"groupId\":\"0x0A\",\"localId\":\"0x0C\",\"description\":\"Bit-field giving the requested active time.\",\"defaultValue\":2,\"parameterType\":{\"type\":\"ParameterTypeBitMask\",\"properties\":[{\"name\":\"timerValue\",\"type\":\"PropertyNumber\"},{\"name\":\"timerValueUnit\",\"type\":\"PropertyString\",\"possibleValues\":[\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_2_SECONDS\",\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_1_MINUTE\",\"VALUE_IS_INCREMENTED_IN_MULTIPLES_OF_DECI_HOURS\",\"THE_TIMER_IS_DEACTIVATED\"],\"firmwareValues\":[0,1,2,7]}],\"bitMask\":[{\"type\":\"BitMaskValue\",\"valueFor\":\"timerValue\",\"bitShift\":0,\"length\":5},{\"type\":\"BitMaskValue\",\"valueFor\":\"timerValueUnit\",\"bitShift\":5,\"length\":3}]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellEdrxPcl\",\"groupId\":\"0x0A\",\"localId\":\"0x0D\",\"description\":\"Requested paging cycle length\",\"defaultValue\":15,\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":15}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellEdrxPtw\",\"groupId\":\"0x0A\",\"localId\":\"0x0E\",\"description\":\"Requested paging time window\",\"defaultValue\":3,\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":15}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellRaiTimeout\",\"groupId\":\"0x0A\",\"localId\":\"0x0F\",\"description\":\"RAI (Release Assistance Indication) timeout. A null value disables the feature. Use only with UDP protocol.\",\"defaultValue\":500,\"unit\":\"ms\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":10000}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellProbeMaxAttempts\",\"groupId\":\"0x0A\",\"localId\":\"0x10\",\"description\":\"Number of echo-request sent before declaring the network as lost. Set 0 to disable the feature.\",\"defaultValue\":0,\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":10}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellProbePeriod\",\"groupId\":\"0x0A\",\"localId\":\"0x11\",\"description\":\"Time between echo-request, or since the last downlink activity.\",\"defaultValue\":120,\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":120}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellS1TransportProto\",\"groupId\":\"0x0A\",\"localId\":\"0x12\",\"description\":\"Socket 1 transport protocol\",\"defaultValue\":1,\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"TCP\",\"UDP\"],\"firmwareValues\":[0,1]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellS1IpUrlAddr\",\"groupId\":\"0x0A\",\"localId\":\"0x13\",\"description\":\"Socket 1 remote IP address or URL in string format (max 32 bytes)\",\"defaultValue\":\"\",\"parameterType\":{\"type\":\"ParameterTypeAsciiString\",\"maxSize\":32},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellS1DstIpPort\",\"groupId\":\"0x0A\",\"localId\":\"0x14\",\"description\":\"Socket 1 destination UDP/TCP port\",\"defaultValue\":0,\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":65535}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellS1SrcIpPort\",\"groupId\":\"0x0A\",\"localId\":\"0x15\",\"description\":\"Socket 1 local UDP/TCP port number. Value 0 means that the modem will choose one.\",\"defaultValue\":0,\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":65535}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"cellS1TxAggrTime\",\"groupId\":\"0x0A\",\"localId\":\"0x16\",\"description\":\"Duration in second for which the messages are hold in the socket 1 transmit queue before being transmitted\",\"defaultValue\":120,\"unit\":\"s\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":3600}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleCnxTxPower\",\"groupId\":\"0x0B\",\"localId\":\"0x00\",\"defaultValue\":19,\"description\":\"BLE Tx power level.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":31}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleCnxAdvDuration\",\"groupId\":\"0x0B\",\"localId\":\"0x01\",\"defaultValue\":60,\"description\":\"Time to wait before stopping advertising or switching to slow advertising\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":30}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleCnxBehavior\",\"groupId\":\"0x0B\",\"localId\":\"0x02\",\"defaultValue\":1,\"description\":\"The connectivity configuration.\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"DISABLE\",\"ENABLE_NO_PASSKEY\",\"ENABLE_PASSKEY\",\"ENABLE_NO_PASSKEY_NO_SLOW_ADV\",\"ENABLE_PASSKEY_NO_SLOW_ADV\"],\"firmwareValues\":[0,1,2,3,4]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleBeaconTxPower\",\"groupId\":\"0x0B\",\"localId\":\"0x03\",\"defaultValue\":19,\"description\":\"Time to wait before stopping advertising or switching to slow advertising\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":0,\"maximum\":31}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleBeaconType\",\"groupId\":\"0x0B\",\"localId\":\"0x04\",\"defaultValue\":1,\"description\":\"The connectivity configuration.\",\"parameterType\":{\"type\":\"ParameterTypeString\",\"possibleValues\":[\"DISABLE\",\"EDDYSTONE_UID\",\"IBEACON\",\"ALTBEACON\",\"QUUPPA\",\"EXPOSURE_ADVERTISEMENT\"],\"firmwareValues\":[0,1,2,3,4,5,6,7]},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleBeaconIdentifier\",\"groupId\":\"0x0B\",\"localId\":\"0x05\",\"description\":\"BLE beaconing ID parameter\",\"parameterType\":{\"type\":\"ParameterTypeByteArray\"},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleBeaconFastAdvInterval\",\"groupId\":\"0x0B\",\"localId\":\"0x06\",\"defaultValue\":333,\"description\":\"BLE beacon fast advertising interval.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":20,\"maximum\":10240}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]},{\"driverParameterName\":\"bleBeaconFastSlowInterval\",\"groupId\":\"0x0B\",\"localId\":\"0x07\",\"defaultValue\":1000,\"description\":\"BLE beacon slow advertising interval.\",\"parameterType\":{\"type\":\"ParameterTypeNumber\",\"range\":{\"minimum\":20,\"maximum\":10240}},\"compatibleTrackerModels\":[{\"producerId\":\"abeeway\",\"moduleId\":\"compact-tracker\",\"version\":\"2.0\"},{\"producerId\":\"abeeway\",\"moduleId\":\"combo-compact-tracker\",\"version\":\"1.0\"}]}]}]');\r\n\r\n/***/ }),\r\n\r\n/***/ 788:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet responseClass = __webpack_require__(289);\r\nlet util = __webpack_require__(94);\r\n\r\nlet RequestType = responseClass.ResponseType\r\nconst SENSOR_TYPES = {\r\n   \"DO_NOT_USE\" :0,\r\n    \"ACCELEROMETER\": 1\r\n};\r\nfunction Request(requestType,\r\n    genericConfigurationSet,\r\n    parameterClassConfigurationSet,\r\n    genericConfigurationGet,\r\n    parameterClassConfigurationGet,\r\n    bleStatusConnectivity,\r\n    crc,\r\n    sensorIds\r\n    ){\r\n        this.requestType = requestType;\r\n        this.genericConfigurationSet = genericConfigurationSet;\r\n        this.parameterClassConfigurationSet = parameterClassConfigurationSet;\r\n        this.genericConfigurationGet = genericConfigurationGet;\r\n        this.parameterClassConfigurationGet = parameterClassConfigurationGet;\r\n        this.bleStatusConnectivity = bleStatusConnectivity;\r\n        this.crc = crc;\r\n        this.sensorIds = sensorIds;\r\n}\r\nfunction ParameterClassConfigurationGet(group, parameters){\r\n    this.group = group\r\n    this.parameters = parameters\r\n}\r\nfunction encodeRequest(data){\r\n    let encData = [] \r\n    // encode type and ackToken\r\n    encData[0] = (0x02 <<3) | data.ackToken\r\n    let requestType = encodeRequestType(data.requestType)\r\n    encData[1] = requestType\r\n    switch (requestType){\r\n        case 0:\r\n            encData = encodeRequestGenericConfigurationSet(data.setGenericParameters, encData)\r\n            break;\r\n        case 1:\r\n            encData = encodeRequestParameterClassConfigurationSet(data.setParameterClass, encData)\r\n            break;\r\n        case 2:\r\n            encData = encodeRequestGenericConfigurationGet(data.getGenericParameters, encData)\r\n            break;\r\n        case 3:\r\n            encData = encodeRequestParameterClassConfigurationGet(data.getParameterClass, encData)\r\n            break;\r\n        case 5:\r\n            encData = encodeCrc(data.crc, encData)\r\n            break;\r\n        case 6:\r\n            encData = encodeSensorRequest(data.sensorIds, encData)\r\n            break;\r\n        default:\r\n            throw new Error(\"Unknown request type\")\r\n\r\n    }\r\n    return encData\r\n}\r\nfunction encodeRequestType(value){\r\n    switch (value){\r\n        case \"GENERIC_CONFIGURATION_SET\":\r\n            return 0;\r\n        case \"PARAM_CLASS_CONFIGURATION_SET\":\r\n            return 1;\r\n        case \"GENERIC_CONFIGURATION_GET\":\r\n            return 2;\r\n        case \"PARAM_CLASS_CONFIGURATION_GET\":\r\n            return 3;\r\n        case \"BLE_STATUS_CONNECTIVITY\":\r\n            return 4;\r\n        case \"CRC_CONFIGURATION_REQUEST\":\r\n            return 5;\r\n        case \"SENSOR_REQUEST\":\r\n            return 6;\r\n        default:\r\n            throw new Error(\"Unknown request type\")\r\n\r\n    }\r\n}\r\nfunction decodeRequest(payload){\r\n    let request = new Request();\r\n\r\n    let typeValue  = payload[1]\r\n    switch (typeValue){\r\n        case 0:\r\n            request.requestType = RequestType.GENERIC_CONFIGURATION_SET\r\n            request.genericConfigurationSet = determineRequestGenericConfigurationSet(payload.slice(2))\r\n            break;\r\n        case 1:\r\n            request.requestType = RequestType.PARAM_CLASS_CONFIGURATION_SET\r\n            request.parameterClassConfigurationSet = determineRequestParameterClassConfigurationSet(payload.slice(2))\r\n            break;\r\n        case 2:\r\n            request.requestType = RequestType.GENERIC_CONFIGURATION_GET\r\n            request.genericConfigurationGet = determineRequestGenericConfigurationGet(payload.slice(2))\r\n            break;\r\n        case 3:\r\n            request.requestType = RequestType.PARAM_CLASS_CONFIGURATION_GET\r\n            request.parameterClassConfigurationGet = determineRequestParameterClassConfigurationGet(payload.slice(2))\r\n            break;\r\n        case 4:\r\n            request.requestType = RequestType.BLE_STATUS_CONNECTIVITY\r\n            //TO BE defined\r\n            break;\r\n        case 5:\r\n            request.requestType = RequestType.CRC_CONFIGURATION_REQUEST\r\n            request.crc = decodeCrc(payload.slice(2))\r\n            break;\r\n        case 6:\r\n            request.requestType = RequestType.SENSOR_REQUEST\r\n            request.sensorIds = decodeSensorRequest(payload.slice(2))\r\n           break;\r\n        default:\r\n            throw new Error(\"Request Type Unknown\");\r\n    }\r\n    return request\r\n\r\n}\r\n\r\nfunction determineRequestGenericConfigurationSet(payload){\r\n    let i = 0;\r\n    let request = []\r\n    while (payload.length > i) {\r\n        let groupId = payload[i]\r\n        let localId = payload[1+i]\r\n        let size = payload[2+i]>>3 & 0x1F;\r\n        let dataType = payload[2+i] & 0x07;\r\n        let parameter = responseClass.getParameterByGroupIdAndLocalId(responseClass.parametersByGroupIdAndLocalId, groupId, localId)\r\n        switch(dataType){\r\n            case 0: \r\n                determineDeprecatedRequest(request, parameter,groupId)\r\n                break;\r\n            case 1:\r\n                responseClass.determineConfiguration(request, parameter,  parseInt(util.convertBytesToString(payload.slice(3+i,3+i+size)),16), groupId, size)\r\n                break;\r\n            case 2:\r\n                //we don't have a float parameter now\r\n                break;\r\n            case 3:\r\n                responseClass.determineConfiguration(request, parameter,  payload.slice(3+i,3+i+size), groupId, size)\r\n                break;\r\n            case 4:\r\n                responseClass.determineConfiguration(request, parameter,  payload.slice(3+i,3+i+size), groupId, size)\r\n                break; \r\n            default:\r\n                throw new Error(\"Unknown parameter type\");\r\n            \r\n        }\r\n        i = i + size + 3 \r\n    }\r\n    return request\r\n}\r\nfunction encodeCrc(groupNames, encData) {\r\n    // Ensure groupNames is an array and not empty\r\n    if (!Array.isArray(groupNames) || groupNames.length === 0) {\r\n        throw new Error(\"Group names array is required and cannot be empty\");\r\n    }\r\n\r\n    let bitmap = 0;\r\n\r\n    // Loop through all group names and set the corresponding bit if the group is selected\r\n    groupNames.forEach(group => {\r\n        // Find the index of the group name in the GroupType object\r\n        let index = Object.values(responseClass.GroupType).indexOf(group);\r\n        \r\n        // If the group is valid, set the corresponding bit in the bitmap\r\n        if (index !== -1) {\r\n            bitmap |= (1 << index);\r\n        } else {\r\n            console.warn(`Group name \"${group}\" not found in GroupType. Skipping.`);\r\n        }\r\n    });\r\n\r\n    // Convert the bitmap into a 2-byte array (high byte and low byte)\r\n    // Add the result to encData\r\n    encData.push(bitmap >> 8, bitmap & 0xFF);\r\n\r\n    return encData;\r\n}\r\n\r\n// Convert bitmap back to group names\r\nfunction decodeCrc(bitmapArray) {\r\n    // Check if the bitmapArray is [0, 0], meaning all groups are requested\r\n    if (bitmapArray[0] === 0 && bitmapArray[1] === 0) {\r\n        return Object.values(responseClass.GroupType);  // Return all groups if crc is empty\r\n    }\r\n    if (bitmapArray.length < 2) return []; // Avoid out-of-bounds errors\r\n\r\n    // Convert 2-byte array into an integer\r\n    let bitmap = (bitmapArray[0] << 8) | bitmapArray[1];\r\n\r\n    let result = [];\r\n    Object.keys(responseClass.GroupType).forEach((key, index) => {\r\n        if ((bitmap & (1 << index)) !== 0) {  // Corrected bitwise check\r\n            result.push(responseClass.GroupType[key]);\r\n        }\r\n    });\r\n    return result;\r\n}\r\nfunction decodeSensorRequest(buffer) {\r\n    return Array.from(buffer).map(id => {\r\n        // Find the type corresponding to the numeric id\r\n        let type = Object.keys(SENSOR_TYPES).find(key => SENSOR_TYPES[key] === id);\r\n        return {\r\n            id,\r\n            type: type || \"Unknown\"  // If no match, set it to \"Unknown\"\r\n        };\r\n    });\r\n}\r\n\r\n// Encode: Convert sensor objects to binary format and fill encData\r\nfunction encodeSensorRequest(sensorIds, encData) {\r\n\r\n    if (!Array.isArray(sensorIds)) {\r\n        throw new Error(\"sensorIds must be an array.\");\r\n    }\r\n    if (!Array.isArray(encData)) {\r\n        throw new Error(\"encData must be an array.\");\r\n    }\r\n\r\n    sensorIds.forEach((sensor, index) => {\r\n        if (!(sensor.type in SENSOR_TYPES)) {\r\n            throw new Error(`Unknown sensor type: ${sensor.type}`);\r\n        }\r\n        let encodedValue = SENSOR_TYPES[sensor.type];\r\n        encData.push(encodedValue);\r\n    });\r\n    return encData;\r\n}\r\n\r\n\r\nfunction determineRequestParameterClassConfigurationSet(payload){\r\n    let groupId = payload[0]\r\n    let i = 1;\r\n    let request = []\r\n    while (payload.length > i) {\r\n        let localId = payload[i]\r\n        let size = payload[1+i]>>3 & 0x1F;\r\n        let dataType = payload[1+i] & 0x07;\r\n        let parameter = responseClass.getParameterByGroupIdAndLocalId(responseClass.parametersByGroupIdAndLocalId, groupId, localId)\r\n        if (payload.slice(i).length < size){\r\n            throw new Error(parameter.driverParameterName + \" has a wrong type\")\r\n        } \r\n        switch(dataType){\r\n            case 0: \r\n                determineDeprecatedRequest(request, parameter,groupId)\r\n                break;\r\n            case 1:\r\n                responseClass.determineConfiguration(request, parameter,  parseInt(util.convertBytesToString(payload.slice(2+i,2+i+size)),16), groupId)\r\n                break;\r\n            case 2:\r\n                //TO be complted\r\n                break;\r\n            case 3:\r\n                responseClass.determineConfiguration(request, parameter,  payload.slice(2+i,2+i+size), groupId, size)\r\n                break; \r\n            case 4:\r\n                responseClass.determineConfiguration(request, parameter,  payload.slice(2+i,2+i+size), groupId, size)\r\n                break; \r\n            default:\r\n                throw new Error(\"Unknown parameter type\");\r\n\r\n        }\r\n        i = i + size + 2\r\n        }\r\n        return request\r\n}\r\n\r\nfunction determineDeprecatedRequest(request, parameter, groupId) {\r\n    let group = responseClass.determineGroupType(groupId)\r\n    let paramName = parameter.driverParameterName\r\n    // Find the group in the request object or create a new one if it doesn't exist\r\n    let groupObject = request.find(g => g.group === group);\r\n    if (!groupObject) {\r\n        groupObject = { group: group, parameters: [] };\r\n        request.push(groupObject);\r\n    }\r\n\r\n    // Add the parameter to the group's parameters array\r\n    groupObject.parameters.push({\r\n        parameterName: paramName,\r\n        parameterValue: \"DEPRECATED\"\r\n    });\r\n}\r\n\r\nfunction determineRequestGenericConfigurationGet(payload){\r\n    let i = 0;\r\n    const step = 2;\r\n    if (payload % 2 === 0){\r\n        throw new Error(\"Invalid payload\")\r\n    }\r\n    let request = []\r\n    while (payload.length >= step * (i + 1)) {\r\n        let groupId = payload[i*step]\r\n        let localId = payload[1+i*step]\r\n        let parameter = responseClass.getParameterByGroupIdAndLocalId(responseClass.parametersByGroupIdAndLocalId, groupId, localId)\r\n        let group = responseClass.determineGroupType(groupId)\r\n        // Find the group in the response object or create a new one if it doesn't exist\r\n        let groupObject = request.find(g => g.group === group);\r\n        if (!groupObject) {\r\n            groupObject = { group: group, parameters: [] };\r\n            request.push(groupObject);\r\n        }\r\n\r\n        // Add the parameter to the group's parameters array\r\n        groupObject.parameters.push(\r\n            parameter.driverParameterName\r\n        );\r\n\r\n    i++;\r\n    }\r\n    return request\r\n}\r\n\r\nfunction determineRequestParameterClassConfigurationGet(payload){\r\n    if (payload.length < 2){\r\n        throw new Error(\"The payload must contain at least one local identifier\");\r\n    }\r\n    let groupId = payload[0]\r\n    payload = payload.slice(1)\r\n    let i = 0;\r\n    const step = 1;\r\n    let parameters = [];\r\n    while (payload.length >= step * (i + 1)) {\r\n        let parameter = responseClass.getParameterByGroupIdAndLocalId(responseClass.parametersByGroupIdAndLocalId, groupId, payload[i*step])\r\n        parameters.push(parameter.driverParameterName)\r\n        i++;\r\n    }\r\n    return new ParameterClassConfigurationGet(responseClass.determineGroupType(groupId), parameters)\r\n}\r\nfunction encodeRequestGenericConfigurationSet (setGenericParameters, encData){\r\n    var i = 2\r\n    for (let [index, entry] of setGenericParameters.entries()) {\r\n        let groupId = determineValueFromGroupType(entry.group)\r\n        for (let param of entry.parameters) {\r\n            let parameter = getParametersByGroupIdAndDriverParameterName(responseClass.parametersByGroupIdAndLocalId, groupId, param.parameterName)\r\n            encData[i] = groupId\r\n            encData[i+1] = parseInt(parameter.localId, 16);\r\n            i = encodeSetParameter(parameter, param.parameterValue, encData, i+2)\r\n        }\r\n    }\r\n    return encData\r\n}\r\nfunction encodeRequestParameterClassConfigurationSet (setParameterClass, encData){\r\n    let groupId = determineValueFromGroupType(setParameterClass.group);\r\n    encData[2] = groupId;\r\n    var i = 3\r\n    for (let param of setParameterClass.parameters) {\r\n        let parameter = getParametersByGroupIdAndDriverParameterName(responseClass.parametersByGroupIdAndLocalId, groupId, param.parameterName);\r\n        encData[i] = parseInt(parameter.localId, 16);\r\n        i = encodeSetParameter(parameter, param.parameterValue, encData, i + 1);\r\n    }\r\n    return encData;\r\n}\r\nfunction encodeRequestGenericConfigurationGet(getGenericParameters, encData){\r\n    var i = 2\r\n    for (let [index,entry] of getGenericParameters.entries()) {\r\n        let groupId = determineValueFromGroupType(entry.group)\r\n        for (let param of entry.parameters) {\r\n            let parameter = getParametersByGroupIdAndDriverParameterName(responseClass.parametersByGroupIdAndLocalId, groupId, param)\r\n            encData[i] = groupId\r\n            encData[i+1] = parseInt(parameter.localId, 16);\r\n            i = i + 2\r\n        }\r\n    }\r\n    return encData\r\n}\r\nfunction encodeRequestParameterClassConfigurationGet (getParameterClass, encData){\r\n    let groupId = determineValueFromGroupType(getParameterClass.group);\r\n    encData[2] = groupId;\r\n    var i = 3\r\n    for (let param of getParameterClass.parameters) {\r\n        let parameter = getParametersByGroupIdAndDriverParameterName(responseClass.parametersByGroupIdAndLocalId, groupId, param);\r\n        encData[i] = parseInt(parameter.localId, 16);\r\n        i++\r\n     }\r\n    return encData;\r\n}\r\n\r\n/* function encodeSetParameter( parameter, paramValue, encData , i){\r\n    let size\r\n    let paramType = parameter.parameterType.type\r\n    switch (paramType){ \r\n\r\n    case \"ParameterTypeNumber\":\r\n        size = 4\r\n        encData[i] = encodeSizeAndType(size, 1)\r\n        let range = parameter.parameterType.range\r\n        let multiply = parameter.parameterType.multiply\r\n        let additionalValues = parameter.parameterType.additionalValues\r\n        let additionalRanges = parameter.parameterType.additionalRanges\r\n        // negative number\r\n    \r\n        if (util.checkParamValueRange(paramValue, range.minimum, range.maximum, range.exclusiveMinimum, range.exclusiveMaximum, additionalValues, additionalRanges)){\r\n            if (multiply != undefined){\r\n                paramValue = paramValue/multiply\r\n            }\r\n            if (paramValue < 0) {\r\n                paramValue += 0x100000000;\r\n            }\r\n            encData[i+1] = (paramValue >> 24) & 0xFF;\r\n            encData[i+2] = (paramValue >> 16) & 0xFF;\r\n            encData[i+3] = (paramValue >> 8) & 0xFF;\r\n            encData[i+4] = paramValue & 0xFF;\r\n            return i + size + 1\r\n        }\r\n        else{\r\n\r\n                throw new Error(parameter.driverParameterName +\" parameter value is out of range\");\r\n        }\r\n    case \"ParameterTypeString\":\r\n        size = 4\r\n        encData[i] = encodeSizeAndType(size, 1)\r\n        if (((parameter.parameterType.possibleValues).indexOf(paramValue)) != -1)\r\n            {\r\n                encData[i+1] = 0;\r\n                encData[i+2] = 0;\r\n                encData[i+3] = 0;\r\n                encData[i+4]  = (parameter.parameterType.firmwareValues[((parameter.parameterType.possibleValues).indexOf(paramValue))])\r\n                return i + size + 1\r\n            }\r\n        else{\r\n            \r\n            throw new Error(parameter.driverParameterName+\" parameter value is unknown\");\r\n        }\r\n    case \"ParameterTypeBitMask\":\r\n        size = 4\r\n        encData[i] = encodeSizeAndType(size, 1)\r\n        let flags =0 \r\n        let properties = parameter.parameterType.properties\r\n        let bitMap = parameter.parameterType.bitMask\r\n        for (let bit of bitMap){\r\n            let flagName = bit.valueFor\r\n            let flagValue = paramValue[flagName]\r\n            if (flagValue == undefined){\r\n                throw new Error(\"Bit \"+ flagName +\" is missing\");\r\n            }\r\n            let  property = (properties.find(el => el.name === flagName))\r\n            let propertyType = property.type\r\n            switch (propertyType)\r\n            {\r\n                case \"PropertyBoolean\":\r\n                    if ((bit.inverted != undefined) && (bit.inverted)){\r\n                        flagValue =! flagValue;\r\n                    } \r\n                    flags |= Number(flagValue) << bit.bitShift\r\n                    break;\r\n                case \"PropertyString\":\r\n                    if (property.possibleValues.indexOf(flagValue) != -1){\r\n                        flags |= (property.firmwareValues[property.possibleValues.indexOf(flagValue)]) << bit.bitShift\r\n                    }\r\n                    else {\r\n                        throw new Error(property.name+ \" parameter value is not among possible values\");\r\n                    }\r\n                    \r\n                    break;\r\n                case \"PropertyNumber\":\r\n                    if (property.range){ \r\n                        if (util.checkParamValueRange(flagValue, property.range.minimum, property.range.maximum, property.range.exclusiveMinimum, property.range.exclusiveMaximum, property.additionalValues, property.additionalRanges)){\r\n                            flags |= flagValue << bit.bitShift    \r\n                        }\r\n                        else {\r\n                            throw new Error(\"Value out of range for \"+ parameter.driverParameterName+\".\"+flagName);\r\n                        }\r\n                    }\r\n                    else{\r\n                        flags |= flagValue << bit.bitShift  \r\n                    }\r\n                    break;\r\n                case \"PropertyObject\":\r\n                    let bitValues = Object.entries(flagValue)\r\n                    for (let b of bit.values){\r\n                        let fValue = flagValue[b.valueFor]\r\n                        if (fValue == undefined){\r\n                            throw new Error(\"Bit \"+ flagName +\".\"+ b.valueFor+\" is missing\");\r\n                        }\r\n                        if ((b.inverted != undefined) && (b.inverted)){\r\n                            fValue =! fValue;\r\n                        }\r\n                        flags |= Number(fValue) <<  b.bitShift \r\n\r\n                    }\r\n                    break;\r\n                default:\r\n                    throw new Error(\"Property type is unknown\");\r\n            }\r\n        }\r\n        \r\n        encData[i+1] = (flags >> 24) & 0xFF;\r\n        encData[i+2] = (flags >> 16) & 0xFF;\r\n        encData[i+3] = (flags >> 8) & 0xFF;\r\n        encData[i+4] = flags & 0xFF;\r\n        return i + size + 1 ;\r\n        \r\n    case \"ParameterTypeAsciiString\":\r\n        size = paramValue.length\r\n        encData[i] = encodeSizeAndType(size, 3)\r\n        for (let j = 0; j < paramValue.length; j++)\r\n            encData[i + j + 1] =paramValue.charCodeAt(j) & 0xFF;\r\n\r\n        return i + size + 1 ;\r\n    case \"ParameterTypeByteArray\":\r\n        size = parameter.parameterType.size\r\n        encData[i] = encodeSizeAndType(size, 4)\r\n        if  (parameter.parameterType.properties == undefined){\r\n            let paramValueHex = paramValue.toString().replace(/[{}]/g, '').replace(/,/g, ''); // Remove braces and commas\r\n            for (let j = 0; j < size; j++) {\r\n                encData[i + j + 1] = parseInt(paramValueHex.slice(j * 2, j * 2 + 2), 16);\r\n            }\r\n            return i + size + 1;\r\n        }else{\r\n            let arrayProperties = parameter.parameterType.properties\r\n            let byteMask = parameter.parameterType.byteMask\r\n            for (let j = 0; j < size; j++) {\r\n                let flags =0 \r\n\r\n                for (let bit of byteMask){\r\n                    let flagName = bit.valueFor\r\n                    let flagValue = paramValue[j][flagName]\r\n                    if (flagValue == undefined){\r\n                        throw new Error(\"byte \"+ flagName +\" is missing\");\r\n                    }\r\n                    let  property = (arrayProperties.find(el => el.name === flagName))\r\n                    let propertyType = property.type\r\n                    switch (propertyType)\r\n                    {\r\n                        case \"PropertyBoolean\":\r\n                            if ((bit.inverted != undefined) && (bit.inverted)){\r\n                                flagValue =! flagValue;\r\n                            } \r\n                            flags |= Number(flagValue) << bit.bitShift\r\n                            break;\r\n                        case \"PropertyString\":\r\n                            if (property.possibleValues.indexOf(flagValue) != -1){\r\n                                flags |= (property.firmwareValues[property.possibleValues.indexOf(flagValue)]) << bit.bitShift\r\n                            }\r\n                            else {\r\n                                throw new Error(property.name+ \" parameter value is not among possible values\");\r\n                            }\r\n                            \r\n                            break;\r\n                        case \"PropertyNumber\":\r\n                            if (property.range){ \r\n                                if (util.checkParamValueRange(flagValue, property.range.minimum, property.range.maximum, property.range.exclusiveMinimum, property.range.exclusiveMaximum, property.additionalValues, property.additionalRanges)){\r\n                                    flags |= flagValue << bit.bitShift    \r\n                                }\r\n                                else {\r\n                                    throw new Error(\"Value out of range for \"+ parameter.driverParameterName+\".\"+flagName);\r\n                                }\r\n                            }\r\n                            else{\r\n                                flags |= flagValue << bit.bitShift  \r\n                            }\r\n                            break;\r\n                        case \"PropertyObject\":\r\n                            for (let b of bit.values){\r\n                                let fValue = flagValue[b.valueFor]\r\n                                if (fValue == undefined){\r\n                                    throw new Error(\"Bit \"+ flagName +\".\"+ b.valueFor+\" is missing\");\r\n                                }\r\n                                if ((b.inverted != undefined) && (b.inverted)){\r\n                                    fValue =! fValue;\r\n                                }\r\n                                flags |= Number(fValue) <<  b.bitShift \r\n\r\n                            }\r\n                            break;\r\n                        default:\r\n                            throw new Error(\"Property type is unknown\");\r\n                    }\r\n                }\r\n        \r\n                encData[i + j + 1] = flags & 0xFF\r\n        \r\n        }\r\n        return i + size + 1 ;\r\n    }\r\n    case \"ParameterTypeByteArray\":\r\n        size = parameter.parameterType.size;\r\n        encData[i] = encodeSizeAndType(size, 4);\r\n    \r\n        if (!parameter.parameterType.properties) {\r\n            // Handle raw byte array (no properties)\r\n            encodeRawByteArray(paramValue, size, encData, i);\r\n            return i + size + 1;\r\n        } else {\r\n            // Handle byte array with properties\r\n            encodeByteArrayWithProperties(parameter, paramValue, size, encData, i);\r\n            return i + size + 1;\r\n        }\r\n            \r\n    default:\r\n        throw new Error(\"Parameter type is unknown\");\r\n        \r\n    }\r\n} */\r\n// Function encode size and type for a parameter\r\n\r\nfunction encodeSetParameter(parameter, paramValue, encData, i) {\r\n    const paramType = parameter.parameterType.type;\r\n\r\n    switch (paramType) {\r\n        case \"ParameterTypeNumber\":\r\n            return encodeNumberParameter(parameter, paramValue, encData, i);\r\n        case \"ParameterTypeString\":\r\n            return encodeStringParameter(parameter, paramValue, encData, i);\r\n        case \"ParameterTypeBitMask\":\r\n            return encodeBitMaskParameter(parameter, paramValue, encData, i);\r\n        case \"ParameterTypeAsciiString\":\r\n            return encodeAsciiStringParameter(parameter, paramValue, encData, i);\r\n        case \"ParameterTypeByteArray\":\r\n            return encodeByteArrayParameter(parameter, paramValue, encData, i);\r\n        default:\r\n            throw new Error(\"Parameter type is unknown\");\r\n    }\r\n}\r\n\r\n// Helper Functions\r\n\r\n/**\r\n * Encodes a number parameter.\r\n */\r\nfunction encodeNumberParameter(parameter, paramValue, encData, startIndex) {\r\n    const size = 4;\r\n    encData[startIndex] = encodeSizeAndType(size, 1);\r\n\r\n    const range = parameter.parameterType.range;\r\n    const multiply = parameter.parameterType.multiply;\r\n    const additionalValues = parameter.parameterType.additionalValues;\r\n    const additionalRanges = parameter.parameterType.additionalRanges;\r\n\r\n    if (!util.checkParamValueRange(paramValue, range.minimum, range.maximum, range.exclusiveMinimum, range.exclusiveMaximum, additionalValues, additionalRanges)) {\r\n        throw new Error(`${parameter.driverParameterName} parameter value is out of range`);\r\n    }\r\n\r\n    let value = paramValue;\r\n    if (multiply !== undefined) {\r\n        value /= multiply;\r\n    }\r\n    if (value < 0) {\r\n        value += 0x100000000;\r\n    }\r\n\r\n    encData[startIndex + 1] = (value >> 24) & 0xFF;\r\n    encData[startIndex + 2] = (value >> 16) & 0xFF;\r\n    encData[startIndex + 3] = (value >> 8) & 0xFF;\r\n    encData[startIndex + 4] = value & 0xFF;\r\n\r\n    return startIndex + size + 1;\r\n}\r\n\r\n/**\r\n * Encodes a string parameter.\r\n */\r\nfunction encodeStringParameter(parameter, paramValue, encData, startIndex) {\r\n    const size = 4;\r\n    encData[startIndex] = encodeSizeAndType(size, 1);\r\n\r\n    const possibleValues = parameter.parameterType.possibleValues;\r\n    const firmwareValues = parameter.parameterType.firmwareValues;\r\n\r\n    const index = possibleValues.indexOf(paramValue);\r\n    if (index === -1) {\r\n        throw new Error(`${parameter.driverParameterName} parameter value is unknown`);\r\n    }\r\n\r\n    encData[startIndex + 1] = 0;\r\n    encData[startIndex + 2] = 0;\r\n    encData[startIndex + 3] = 0;\r\n    encData[startIndex + 4] = firmwareValues[index];\r\n\r\n    return startIndex + size + 1;\r\n}\r\n\r\n/**\r\n * Encodes a bitmask parameter.\r\n */\r\nfunction encodeBitMaskParameter(parameter, paramValue, encData, startIndex) {\r\n    const size = 4;\r\n    encData[startIndex] = encodeSizeAndType(size, 1);\r\n\r\n    const properties = parameter.parameterType.properties;\r\n    const bitMap = parameter.parameterType.bitMask;\r\n\r\n    let flags = 0;\r\n    for (let bit of bitMap) {\r\n        const flagName = bit.valueFor;\r\n        const flagValue = paramValue[flagName];\r\n\r\n        if (flagValue === undefined) {\r\n            throw new Error(`Bit ${flagName} is missing`);\r\n        }\r\n\r\n        const property = properties.find(el => el.name === flagName);\r\n        if (!property) {\r\n            throw new Error(`Property ${flagName} not found`);\r\n        }\r\n\r\n        flags = encodeProperty(property, bit, flagValue, flags);\r\n    }\r\n\r\n    encData[startIndex + 1] = (flags >> 24) & 0xFF;\r\n    encData[startIndex + 2] = (flags >> 16) & 0xFF;\r\n    encData[startIndex + 3] = (flags >> 8) & 0xFF;\r\n    encData[startIndex + 4] = flags & 0xFF;\r\n\r\n    return startIndex + size + 1;\r\n}\r\n\r\n/**\r\n * Encodes an ASCII string parameter.\r\n */\r\nfunction encodeAsciiStringParameter(parameter, paramValue, encData, startIndex) {\r\n    const size = paramValue.length;\r\n    encData[startIndex] = encodeSizeAndType(size, 3);\r\n\r\n    for (let j = 0; j < paramValue.length; j++) {\r\n        encData[startIndex + j + 1] = paramValue.charCodeAt(j) & 0xFF;\r\n    }\r\n\r\n    return startIndex + size + 1;\r\n}\r\n\r\n/**\r\n * Encodes a byte array parameter.\r\n */\r\nfunction encodeByteArrayParameter(parameter, paramValue, encData, startIndex) {\r\n    const size = parameter.parameterType.size;\r\n    encData[startIndex] = encodeSizeAndType(size, 4);\r\n\r\n    if (!parameter.parameterType.properties) {\r\n        encodeRawByteArray(paramValue, size, encData, startIndex);\r\n    } else {\r\n        encodeByteArrayWithProperties(parameter, paramValue, size, encData, startIndex);\r\n    }\r\n\r\n    return startIndex + size + 1;\r\n}\r\n\r\n/**\r\n * Encodes a raw byte array (no properties).\r\n */\r\nfunction encodeRawByteArray(paramValue, size, encData, startIndex) {\r\n    const paramValueHex = paramValue.toString().replace(/[{}]/g, '').replace(/,/g, ''); // Remove braces and commas\r\n    for (let j = 0; j < size; j++) {\r\n        encData[startIndex + j + 1] = parseInt(paramValueHex.slice(j * 2, j * 2 + 2), 16);\r\n    }\r\n}\r\n\r\n/**\r\n * Encodes a byte array with properties.\r\n */\r\nfunction encodeByteArrayWithProperties(parameter, paramValue, size, encData, startIndex) {\r\n    const arrayProperties = parameter.parameterType.properties;\r\n    const byteMask = parameter.parameterType.byteMask;\r\n\r\n    for (let j = 0; j < size; j++) {\r\n        let flags = 0;\r\n        flags = encodeProperties(arrayProperties, byteMask, paramValue[j], flags);\r\n        encData[startIndex + j + 1] = flags & 0xFF;\r\n    }\r\n}\r\n\r\n/**\r\n * Encodes properties for a single byte in the byte array.\r\n */\r\nfunction encodeProperties(arrayProperties, byteMask, paramValue, flags) {\r\n    for (let bit of byteMask) {\r\n        const flagName = bit.valueFor;\r\n        const flagValue = paramValue[flagName];\r\n\r\n        if (flagValue === undefined) {\r\n            throw new Error(`Byte ${flagName} is missing`);\r\n        }\r\n\r\n        const property = arrayProperties.find(el => el.name === flagName);\r\n        if (!property) {\r\n            throw new Error(`Property ${flagName} not found`);\r\n        }\r\n\r\n        flags = encodeProperty(property, bit, flagValue, flags);\r\n    }\r\n    return flags;\r\n}\r\n\r\n/**\r\n * Encodes a single property based on its type.\r\n */\r\nfunction encodeProperty(property, bit, flagValue, flags) {\r\n    switch (property.type) {\r\n        case \"PropertyBoolean\":\r\n            return encodeBooleanProperty(bit, flagValue, flags);\r\n        case \"PropertyString\":\r\n            return encodeStringProperty(property, bit, flagValue, flags);\r\n        case \"PropertyNumber\":\r\n            return encodeNumberProperty(property, bit, flagValue, flags);\r\n        case \"PropertyObject\":\r\n            return encodeObjectProperty(bit, flagValue, flags);\r\n        default:\r\n            throw new Error(`Unknown property type: ${property.type}`);\r\n    }\r\n}\r\n\r\n/**\r\n * Encodes a boolean property.\r\n */\r\nfunction encodeBooleanProperty(bit, flagValue, flags) {\r\n    let value = flagValue;\r\n    if (bit.inverted) {\r\n        value = !value;\r\n    }\r\n    return flags | (Number(value) << bit.bitShift);\r\n}\r\n\r\n/**\r\n * Encodes a string property.\r\n */\r\nfunction encodeStringProperty(property, bit, flagValue, flags) {\r\n    const index = property.possibleValues.indexOf(flagValue);\r\n    if (index === -1) {\r\n        throw new Error(`${property.name} value is not among possible values`);\r\n    }\r\n    return flags | (property.firmwareValues[index] << bit.bitShift);\r\n}\r\n\r\n/**\r\n * Encodes a number property.\r\n */\r\nfunction encodeNumberProperty(property, bit, flagValue, flags) {\r\n    if (property.range) {\r\n        if (!util.checkParamValueRange(flagValue, property.range.minimum, property.range.maximum, property.range.exclusiveMinimum, property.range.exclusiveMaximum, property.additionalValues, property.additionalRanges)) {\r\n            throw new Error(`Value out of range for ${property.name}`);\r\n        }\r\n    }\r\n    return flags | (flagValue << bit.bitShift);\r\n}\r\n\r\n/**\r\n * Encodes an object property.\r\n */\r\nfunction encodeObjectProperty(bit, flagValue, flags) {\r\n    for (let b of bit.values) {\r\n        const fValue = flagValue[b.valueFor];\r\n        if (fValue === undefined) {\r\n            throw new Error(`Bit ${bit.valueFor}.${b.valueFor} is missing`);\r\n        }\r\n        let value = fValue;\r\n        if (b.inverted) {\r\n            value = !value;\r\n        }\r\n        flags |= Number(value) << b.bitShift;\r\n    }\r\n    return flags;\r\n}\r\nfunction encodeSizeAndType(size, type){\r\n    return ((size << 0x03)| type)\r\n\r\n}\r\n// Function to get parameters by groupId and driverParameterName\r\nfunction getParametersByGroupIdAndDriverParameterName(parameters, groupId, driverParameterName) {\r\n    // Check if the parameters object contains the groupId\r\n    if (parameters[groupId]) {\r\n        // Iterate over each localId within the groupId\r\n        for (let localId in parameters[groupId]) {\r\n            // Check if the current parameter's driverParameterName matches the provided name\r\n            if (parameters[groupId][localId].driverParameterName === driverParameterName) {\r\n                return parameters[groupId][localId];\r\n            }\r\n        }\r\n    }\r\n\r\n    // Return null if no matching parameter is found\r\n    return null;\r\n}\r\n// give the group as string \r\nfunction determineValueFromGroupType(groupType) {\r\n    switch(groupType) {\r\n        case responseClass.GroupType.INTERNAL:\r\n            return 0;\r\n        case responseClass.GroupType.SYSTEM_CORE:\r\n            return 1;\r\n        case responseClass.GroupType.GEOLOC:\r\n            return 2;\r\n        case responseClass.GroupType.GNSS:\r\n            return 3;\r\n        case responseClass.GroupType.LR11xx:\r\n            return 4;\r\n        case responseClass.GroupType.BLE_SCAN1:\r\n            return 5;\r\n        case responseClass.GroupType.BLE_SCAN2:\r\n            return 6;\r\n        case responseClass.GroupType.ACCELEROMETER:\r\n            return 7;\r\n        case responseClass.GroupType.NETWORK:\r\n            return 8;\r\n        case responseClass.GroupType.LORAWAN:\r\n            return 9;\r\n        case responseClass.GroupType.CELLULAR:\r\n            return 10;\r\n        case responseClass.GroupType.BLE:\r\n            return 11;\r\n        default:\r\n            throw new Error(\"Unknown group type\");\r\n    }\r\n}\r\n\r\nmodule.exports = {\r\n    RequestType: RequestType,\r\n    encodeRequest: encodeRequest,\r\n    decodeRequest: decodeRequest\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 792:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\n\r\nlet util = __webpack_require__(94);\r\n\r\nfunction GnssFix(latitude,\r\n    longitude,\r\n    altitude,\r\n    COG,\r\n    SOG,\r\n    EHPE,\r\n    quality){\r\n    this.latitude = latitude;\r\n    this.longitude = longitude;\r\n    this.altitude = altitude;\r\n    this.COG = COG;\r\n    this.SOG = SOG;\r\n    this.EHPE = EHPE;\r\n    this.quality = quality;\r\n}\r\n\r\nconst fixQuality = Object.freeze({\r\n    INVALID: \"INVALID\",\r\n    VALID: \"VALID\",\r\n    FIX_2D: \"FIX_2D\",\r\n    FIX_3D: \"FIX_3D\",\r\n});\r\n\r\nfunction QualityInfo(fixQuality,\r\n    numberSatelliteUsed\r\n){\r\n    this.fixQuality = fixQuality;\r\n    this.numberSatelliteUsed = numberSatelliteUsed;\r\n}\r\n\r\n/****** decoded MT3333 GPS position *******/\r\n/*****************************************/\r\nfunction determineGnssFix (payload){\r\n    let mt3333GnssFixInfo = new GnssFix();\r\n    mt3333GnssFixInfo.latitude = util.twoComplement(parseInt(util.convertBytesToString(payload.slice(0,4)),16)) /  Math.pow(10, 7) \r\n    mt3333GnssFixInfo.longitude = util.twoComplement(parseInt(util.convertBytesToString(payload.slice(4,8)),16)) /  Math.pow(10, 7)\r\n    mt3333GnssFixInfo.altitude = determineAltitude(payload)\r\n    mt3333GnssFixInfo.COG = determineCourseOverGround(payload)\r\n    mt3333GnssFixInfo.SOG = determineSpeedOverGround(payload)\r\n    mt3333GnssFixInfo.EHPE = determineEstimatedHorizontalPositionError(payload)\r\n    mt3333GnssFixInfo.quality = determineFixQuality(payload)\r\n return mt3333GnssFixInfo\r\n\r\n}\r\nfunction determineAltitude(payload){\r\n    if (payload.length < 10)\r\n        throw new Error(\"The payload is not valid to determine GPS altitude\");\r\n    return (payload[8]<<8)+payload[9];\r\n}\r\nfunction determineCourseOverGround(payload){\r\n    if (payload.length < 12)\r\n        throw new Error(\"The payload is not valid to determine GPS course over ground\");\r\n    // expressed in 1/100 degree\r\n    return ((payload[10]<<8)+payload[11]);\r\n}\r\n\r\nfunction determineSpeedOverGround(payload){\r\n    if (payload.length < 14)\r\n        throw new Error(\"The payload is not valid to determine GPS speed over ground\");\r\n    // expressed in cm/s\r\n    return ((payload[12]<<8)+payload[13]);\r\n}\r\nfunction determineEstimatedHorizontalPositionError(payload){\r\n        if (payload.length < 15)\r\n            throw new Error(\"The payload is not valid to determine horizontal accuracy\");\r\n        var ehpeValue = payload[14]\r\n        if (ehpeValue > 250){\r\n            switch (ehpeValue){\r\n                case 251:\r\n                    ehpeValue = \"(250,500]\"\r\n                    break\r\n                case 252:\r\n                    ehpeValue = \"(500,1000]\"\r\n                    break\r\n                case 253:\r\n                    ehpeValue = \"(1000,2000]\"\r\n                    break;\r\n                case 254:\r\n                    ehpeValue = \"(2000,4000]\"\r\n                    break;\r\n                case 255:\r\n                    ehpeValue = \">4000\"\r\n                    break;\r\n            }\r\n        }\r\n       \r\n        return ehpeValue;\r\n    }\t\r\n    \r\nfunction determineFixQuality(payload){\r\n    let quality = payload[15]>>5 & 0x07\r\n    let qualityInfo = new QualityInfo()\r\n    \r\n    switch(quality){\r\n        case 0:\r\n            qualityInfo.fixQuality = fixQuality.INVALID\r\n            break\r\n        case 1:\r\n            qualityInfo.fixQuality = fixQuality.VALID\r\n            break\r\n        case 2:\r\n            qualityInfo.fixQuality = fixQuality.FIX_2D\r\n            break\r\n        case 3:\r\n            qualityInfo.fixQuality = fixQuality.FIX_3D\r\n            break\r\n    }\r\n    qualityInfo.numberSatellitesUsed = payload[15] & 0x0F\r\n    return qualityInfo\r\n    \r\n\r\n}\r\n\r\nmodule.exports = {\r\n    GnssFix: GnssFix,\r\n    determineGnssFix: determineGnssFix\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 851:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet eventClass = __webpack_require__(977)\r\nconst CommandType = Object.freeze({\r\n    CLEAR_AND_RESET: \"CLEAR_AND_RESET\",\r\n    RESET: \"RESET\",\r\n    START_SOS: \"START_SOS\",\r\n    STOP_SOS: \"STOP_SOS\",\r\n    SYSTEM_STATUS_REQUEST: \"SYSTEM_STATUS_REQUEST\",\r\n    POSITION_ON_DEMAND: \"POSITION_ON_DEMAND\",\r\n    SET_GPS_ALMANAC: \"SET_GPS_ALMANAC\",\r\n    SET_BEIDOU_ALMANAC: \"SET_BEIDOU_ALMANAC\",\r\n    START_BLE_CONNECTIVITY: \"START_BLE_CONNECTIVITY\",\r\n    STOP_BLE_CONNECTIVITY: \"STOP_BLE_CONNECTIVITY\",\r\n    SYSTEM_EVENT: \"SYSTEM_EVENT\",\r\n    CLEAR_MOTION_PERCENTAGE: \"CLEAR_MOTION_PERCENTAGE\"\r\n\r\n});\r\nfunction Command(command,classId,eventType){\r\n    this.commandType = command;\r\n    this.classId = classId;\r\n    this.eventType = eventType;\r\n}\r\nfunction determineCommand(value) {\r\n    const commands = [\r\n        CommandType.CLEAR_AND_RESET,\r\n        CommandType.RESET,\r\n        CommandType.START_SOS,\r\n        CommandType.STOP_SOS,\r\n        CommandType.SYSTEM_STATUS_REQUEST,\r\n        CommandType.POSITION_ON_DEMAND,\r\n        CommandType.SET_GPS_ALMANAC,\r\n        CommandType.SET_BEIDOU_ALMANAC,\r\n        CommandType.START_BLE_CONNECTIVITY,\r\n        CommandType.STOP_BLE_CONNECTIVITY,\r\n        CommandType.SYSTEM_EVENT,\r\n        CommandType.CLEAR_MOTION_PERCENTAGE\r\n    ];\r\n    return commands[value] || null; // Returns null if the command is unknown\r\n}\r\n\r\nfunction encodeCommand(data) {\r\n    let encode = [];\r\n    encode[0] = (0x01 << 3) | data.ackToken;\r\n\r\n    let command = Object.values(CommandType).indexOf(data.commandType);\r\n    if (command === -1) {\r\n        throw new Error(\"Unknown command\");\r\n    }\r\n\r\n    encode[1] = command;\r\n\r\n    if (command === 10) { // SYSTEM_EVENT\r\n        let classId = getClassId(data.classId);\r\n        encode[2] = classId;\r\n        encode[3] = data.eventType;\r\n    }\r\n\r\n    return encode;\r\n}\r\n\r\nfunction decodeCommand(bytes) {\r\n    let decoded = new Command();\r\n    let command = determineCommand(bytes[0]);\r\n\r\n    if (!command) {\r\n        throw new Error(\"Unknown command received\");\r\n    }\r\n\r\n    decoded.commandType = command\r\n    if (command === Command.SYSTEM_EVENT) {\r\n        if (bytes.length < 4) {\r\n            throw new Error(\"Invalid SYSTEM_EVENT byte array length\");\r\n        }\r\n        decoded.classId = getClassName(bytes[1]);\r\n        decoded.eventType = bytes[2];\r\n    }\r\n   \r\n    return decoded;\r\n}\r\n\r\n// Convert classId to integer\r\nfunction getClassId(className) {\r\n    const classes = {\r\n        [eventClass.Class.SYSTEM]: 0,\r\n        [eventClass.Class.SOS]: 1,\r\n        [eventClass.Class.TEMPERATURE]: 2,\r\n        [eventClass.Class.ACCELEROMETER]: 3,\r\n        [eventClass.Class.NETWORK]: 4,\r\n        [eventClass.Class.GEOZONING]: 5\r\n    };\r\n    if (className in classes) {\r\n        return classes[className];\r\n    }\r\n    throw new Error(\"Unknown class id\");\r\n}\r\n\r\n//  Convert classId integer to class name\r\nfunction getClassName(classId) {\r\n    const classMap = {\r\n        0: eventClass.Class.SYSTEM,\r\n        1: eventClass.Class.SOS,\r\n        2: eventClass.Class.TEMPERATURE,\r\n        3: eventClass.Class.ACCELEROMETER,\r\n        4: eventClass.Class.NETWORK,\r\n        5: eventClass.Class.GEOZONING\r\n    };\r\n    return classMap[classId] || \"UNKNOWN_CLASS\";\r\n}\r\n\r\n\r\nmodule.exports = {\r\n    Command: Command,\r\n    decodeCommand: decodeCommand,\r\n    encodeCommand: encodeCommand\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 925:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\n\r\nlet util = __webpack_require__(94);\r\n\r\nfunction Accelerometer (accelerationVector, motionPercent, gaddIndex, numberShocks){\r\n\r\n    this.accelerationVector = accelerationVector;\r\n    this.motionPercent = motionPercent;\r\n    this.gaddIndex = gaddIndex;\r\n    this.numberShocks = numberShocks;\r\n}\r\nfunction determineAxis(payload, byteNumber){\r\n    if (payload.length < (byteNumber + 2)){\r\n        throw new Error(\"The payload is not valid to determine axis value\");\r\n    }\r\n    let value = (payload[byteNumber]<<8)+payload[byteNumber+1];\r\n    value = util.convertNegativeInt(value, 2)\r\n    return value\r\n}\r\n\r\nfunction determineAccelerationVector(payload, xOffset, yOffset, zOffset){\r\n    let x = determineAxis(payload, xOffset);\r\n    let y = determineAxis(payload, yOffset);\r\n    let z = determineAxis(payload, zOffset);\r\n    return [x,y,z];\r\n}\r\nfunction determineGaddIndex(payload){\r\n    if (payload.length < 11){\r\n        throw new Error(\"The payload is not valid to determine GADD index\");\r\n    }\r\nreturn payload[11]\r\n}  \r\nfunction determineMotion(payload){\r\n    if (payload.length < 11){\r\n        throw new Error(\"The payload is not valid to determine Motion\");\r\n    }\r\nreturn payload[11]\r\n}  \r\nfunction determineNumberShocks(payload){\r\n    if (payload.length < 12){\r\n        throw new Error(\"The payload is not valid to determine number of shocks\");\r\n    }\r\nreturn payload[12]\r\n}   \r\n\r\nconst AcceleroType = Object.freeze({\r\n    MOTION_START: \"MOTION_START\",\r\n    MOTION_END: \"MOTION_END\",\r\n    SHOCK: \"SHOCK\"\r\n})\r\n\r\nmodule.exports = {\r\n    Accelerometer: Accelerometer,\r\n    determineAccelerationVector: determineAccelerationVector,\r\n    determineGaddIndex : determineGaddIndex,\r\n    determineNumberShocks : determineNumberShocks,\r\n    determineMotion: determineMotion, \r\n    AcceleroType: AcceleroType,\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 962:\r\n/***/ ((module) => {\r\n\r\nconst messageType = Object.freeze({\r\n    NOTIFICATION: \"NOTIFICATION\",\r\n    POSITION: \"POSITION\",\r\n    QUERY: \"QUERY\",\r\n    RESPONSE: \"RESPONSE\",\r\n    TELEMETRY: \"TELEMETRY\",\r\n    UNKNOWN: \"UNKNOWN\"\r\n});\r\n\r\nfunction AbeewayUplinkPayload(header,\r\n    extendedHeader,\r\n    notification,\r\n    position,\r\n    query,\r\n    response,\r\n    telemetry,\r\n    payload\r\n    ) {\r\n    this.header = header;\r\n    this.extendedHeader = extendedHeader;\r\n    this.notification = notification;\r\n    this.position = position;\r\n    this.query = query;\r\n    this.response = response;\r\n    this.telemetry = telemetry;\r\n    this.telemetry = telemetry;\r\n    this.payload = payload\r\n}\r\n\r\nmodule.exports = {\r\n    AbeewayUplinkPayload: AbeewayUplinkPayload,\r\n    messageType: messageType\r\n}\r\n\r\n/***/ }),\r\n\r\n/***/ 977:\r\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\r\n\r\nlet systemClass = __webpack_require__(187);\r\nlet temperatureClass = __webpack_require__ (406)\r\nlet accelerometerClass = __webpack_require__(925)\r\nlet networkClass = __webpack_require__(142)\r\nlet geozoningClass = __webpack_require__(548)\r\nlet telemetryClass = __webpack_require__(343)\r\n\r\nconst Class = Object.freeze({\r\n    SYSTEM: \"SYSTEM\",\r\n    SOS: \"SOS\",\r\n    TEMPERATURE: \"TEMPERATURE\",\r\n    ACCELEROMETER: \"ACCELEROMETER\",\r\n    NETWORK: \"NETWORK\",\r\n    GEOZONING: \"GEOZONING\",\r\n    TELEMETRY: \"TELEMETRY\"\r\n})\r\n\r\nconst SosType = Object.freeze({\r\n    SOS_ON: \"SOS_ON\",\r\n    SOS_OFF: \"SOS_OFF\"\r\n})\r\n\r\n\r\n\r\nfunction Notification(notificationClass,\r\n    notificationType,\r\n    system,\r\n    sos,\r\n    temperature,\r\n    accelerometer,\r\n    network,\r\n    geozoning,\r\n    telemetryMeasurements){\r\n    this.notificationClass = notificationClass;\r\n    this.notificationType = notificationType;\r\n    this.system = system;\r\n    this.sos = sos;\r\n    this.temperature = temperature;\r\n    this.accelerometer = accelerometer;\r\n    this.network = network;\r\n    this.geozoning = geozoning;\r\n    this.telemetryMeasurements = telemetryMeasurements;\r\n}\r\n\r\nfunction decodeCrc(payload) {\r\n    // Ensure the payload has enough bytes for the CRC\r\n    if (payload.length < startingByte + byteNumber) {\r\n        throw new Error(\"Payload is too short to contain a valid CRC.\");\r\n    }\r\n\r\n    // Extract the n bytes of the CRC (big-endian)\r\n    const crcBytes = payload.slice(startingByte, startingByte + byteNumber);\r\n    // Convert each byte to a 2-digit hexadecimal string and concatenate\r\n    const crc = crcBytes.map(b => b.toString(16).padStart(2, \"0\")).join(\"\");\r\n    return crc;\r\n}\r\nfunction determineNotification(payload){\r\n    if (payload.length < 5)\r\n        throw new Error(\"The payload is not valid to determine notification message\");\r\n    let notificationMessage = new Notification();\r\n    let classValue = payload[4]>>4 & 0x0F;\r\n    let typeValue = payload[4] & 0x0F;\r\n    switch(classValue){\r\n        case 0:\r\n            notificationMessage.notificationClass = Class.SYSTEM;\r\n            switch (typeValue){\r\n                case 0:\r\n                    notificationMessage.notificationType = systemClass.SystemType.STATUS\r\n                    notificationMessage.system = new systemClass.System(systemClass.determineStatus(payload),null, null, null, null);\r\n                    break;\r\n                case 1:\r\n                    notificationMessage.notificationType = systemClass.SystemType.LOW_BATTERY\r\n                    notificationMessage.system = new systemClass.System( null, systemClass.determineLowBattery(payload), null, null);\r\n                    break;\r\n                case 2:\r\n                    notificationMessage.notificationType = systemClass.SystemType.BLE_STATUS;\r\n                    notificationMessage.system = new systemClass.System( null, null, systemClass.determineBleStatus(payload), null, null);\r\n                    break;\r\n                case 3:\r\n                    notificationMessage.notificationType = systemClass.SystemType.TAMPER_DETECTION;\r\n                    notificationMessage.system = new systemClass.System( null, null, null, systemClass.determineTamperDetection(payload),null);\r\n                    break;\r\n                case 4:\r\n                    notificationMessage.notificationType = systemClass.SystemType.HEARTBEAT;\r\n                    notificationMessage.system = new systemClass.System(null, null, null, null, systemClass.determineHeartbeat(payload))\r\n                    break;\r\n                default:\r\n                    throw new Error(\"System Notification Type Unknown\");\r\n            }\r\n            break;\r\n        case 1:\r\n            notificationMessage.notificationClass = Class.SOS\r\n            switch (typeValue){\r\n                case 0:\r\n                    notificationMessage.notificationType = SosType.SOS_ON\r\n                    break;\r\n                case 1:\r\n                    notificationMessage.notificationType = SosType.SOS_OFF\r\n                    break;\r\n                default:\r\n                    throw new Error(\"SOS Notification Type Unknown\");\r\n            }\r\n            break;\r\n        case 2:\r\n            notificationMessage.notificationClass = Class.TEMPERATURE\r\n            switch (typeValue){\r\n                case 0:\r\n                    notificationMessage.notificationType = temperatureClass.TempType.TEMP_HIGH\r\n                    notificationMessage.temperature = temperatureClass.determineTemperature(payload);\r\n                    break;\r\n                case 1:\r\n                    notificationMessage.notificationType = temperatureClass.TempType.TEMP_LOW\r\n                    notificationMessage.temperature = temperatureClass.determineTemperature(payload);\r\n                    break;\r\n                case 2:\r\n                    notificationMessage.notificationType = temperatureClass.TempType.TEMP_NORMAL\r\n                    notificationMessage.temperature = temperatureClass.determineTemperature(payload);\r\n                    break;\r\n                default:\r\n                    throw new Error(\"Temperature Notification Type Unknown\");\r\n            }\r\n            break;\r\n        case 3:\r\n            notificationMessage.notificationClass = Class.ACCELEROMETER\r\n            switch (typeValue){\r\n                case 0: \r\n                    notificationMessage.notificationType = accelerometerClass.AcceleroType.MOTION_START\r\n                    break;\r\n                case 1:\r\n                    notificationMessage.notificationType = accelerometerClass.AcceleroType.MOTION_END\r\n                    notificationMessage.accelerometer = new accelerometerClass.Accelerometer(accelerometerClass.determineAccelerationVector(payload,5, 7, 9), accelerometerClass.determineMotion(payload), null, null)\r\n                    break;\r\n                case 2:\r\n                    notificationMessage.notificationType = accelerometerClass.AcceleroType.SHOCK\r\n                    notificationMessage.accelerometer = new accelerometerClass.Accelerometer(accelerometerClass.determineAccelerationVector(payload, 5, 7, 9), null, accelerometerClass.determineGaddIndex(payload), accelerometerClass.determineNumberShocks(payload))\r\n                    break;\r\n                default:\r\n                    throw new Error(\"Accelerometer Notification Type Unknown\");\r\n            }\r\n            break;\r\n        case 4:\r\n            notificationMessage.notificationClass = Class.NETWORK\r\n            switch (typeValue){\r\n                case 0: \r\n                    notificationMessage.notificationType = networkClass.NetworkType.MAIN_UP\r\n                    notificationMessage.network = networkClass.determineNetworkInfo(payload)\r\n                    break;\r\n                case 1:\r\n                    notificationMessage.notificationType = networkClass.NetworkType.BACKUP_UP\r\n                    notificationMessage.network = networkClass.determineNetworkInfo(payload)\r\n                    break;\r\n                default:\r\n                    throw new Error(\"Network Notification Type Unknown\");\r\n            }\r\n            break;\r\n        case 5:\r\n            notificationMessage.notificationClass = Class.GEOZONING\r\n            switch (typeValue){\r\n                case 0: \r\n                    notificationMessage.notificationType = geozoningClass.GeozoningType.ENTRY;\r\n                    break;\r\n                case 1:\r\n                    notificationMessage.notificationType = geozoningClass.GeozoningType.EXIT;\r\n                    break;\r\n                case 2:\r\n                    notificationMessage.notificationType = geozoningClass.GeozoningType.IN_HAZARD;\r\n                    break;\r\n                case 3:\r\n                    notificationMessage.notificationType = geozoningClass.GeozoningType.OUT_HAZARD;\r\n                    break;\r\n                case 4:\r\n                    notificationMessage.notificationType = geozoningClass.GeozoningType.MEETING_POINT;\r\n                    break;\r\n                default:\r\n                    throw new Error(\"Geozoning Notification Type Unknown\");\r\n            }\r\n\r\n            break;\r\n        case 6:\r\n            notificationMessage.notificationClass = Class.TELEMETRY\r\n            switch (typeValue){\r\n                case 0: \r\n                    notificationMessage.notificationType = telemetryClass.TelemetryType.TELEMETRY;\r\n                    notificationMessage.telemetryMeasurements = telemetryClass.determineTelemetryMeasurements(payload.slice(5));\r\n                    break;\r\n                case 1:\r\n                    notificationMessage.notificationType = telemetryClass.TelemetryType.TELEMETRY_MODE_BATCH;\r\n                    break;\r\n                default:\r\n                    throw new Error(\"Telemetry Notification Type Unknown\");\r\n            }\r\n\r\n            break;\r\n        default:\r\n            throw new Error(\"Notification Class Unknown\");\r\n    }\r\n    return notificationMessage;\r\n\r\n\r\n}\r\n\r\n\r\nmodule.exports = {\r\n    Notification: Notification,\r\n    determineNotification: determineNotification,\r\n    Class : Class\r\n}\r\n\r\n/***/ })\r\n\r\n/******/ \t});\r\n/************************************************************************/\r\n/******/ \t// The module cache\r\n/******/ \tvar __webpack_module_cache__ = {};\r\n/******/ \t\r\n/******/ \t// The require function\r\n/******/ \tfunction __webpack_require__(moduleId) {\r\n/******/ \t\t// Check if module is in cache\r\n/******/ \t\tvar cachedModule = __webpack_module_cache__[moduleId];\r\n/******/ \t\tif (cachedModule !== undefined) {\r\n/******/ \t\t\treturn cachedModule.exports;\r\n/******/ \t\t}\r\n/******/ \t\t// Create a new module (and put it into the cache)\r\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\r\n/******/ \t\t\t// no module.id needed\r\n/******/ \t\t\t// no module.loaded needed\r\n/******/ \t\t\texports: {}\r\n/******/ \t\t};\r\n/******/ \t\r\n/******/ \t\t// Execute the module function\r\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\r\n/******/ \t\r\n/******/ \t\t// Return the exports of the module\r\n/******/ \t\treturn module.exports;\r\n/******/ \t}\r\n/******/ \t\r\n/************************************************************************/\r\n/******/ \t\r\n/******/ \t// startup\r\n/******/ \t// Load entry module and return exports\r\n/******/ \t// This entry module is referenced by other modules so it can't be inlined\r\n/******/ \tvar __webpack_exports__ = __webpack_require__(44);\r\n/******/ \t\r\n/******/ \treturn __webpack_exports__;\r\n/******/ })()\r\n;\r\n});",
                        "environment": "javascript",
                        "storage": "",
                        "version": "1.0"
                    },
                    "properties": {
                        "uplink": {
                            "data": {
                                "payload": "{{payload}}",
                                "payload_function": "",
                                "payload_type": "source_payload",
                                "resource": "uplink",
                                "source": "resource",
                                "update": "events"
                            },
                            "default": {
                                "source": "value"
                            },
                            "enabled": true
                        }
                    }
                },
                "_resources": {
                    "properties": [
                        {
                            "property": "dashboard",
                            "value": {
                                "tabs": [
                                    {
                                        "name": "Location",
                                        "widgets": [
                                            {
                                                "layout": {
                                                    "col": 0,
                                                    "row": 0,
                                                    "sizeX": 4,
                                                    "sizeY": 15
                                                },
                                                "panel": {
                                                    "color": "#ffffff",
                                                    "currentColor": "#ffffff",
                                                    "showOffline": {
                                                        "type": "none"
                                                    },
                                                    "title": "Device Location"
                                                },
                                                "properties": {
                                                    "center": {
                                                        "lat": 0,
                                                        "lng": 0
                                                    },
                                                    "zoom": 15
                                                },
                                                "sources": [
                                                    {
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "latitude",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#1abc9c",
                                                        "name": "latitude",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "mode": "latest"
                                                        }
                                                    },
                                                    {
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "longitude",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#e74c3c",
                                                        "name": "longitude",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "mode": "latest"
                                                        }
                                                    }
                                                ],
                                                "type": "map"
                                            },
                                            {
                                                "layout": {
                                                    "col": 4,
                                                    "row": 0,
                                                    "sizeX": 2,
                                                    "sizeY": 8
                                                },
                                                "panel": {
                                                    "color": "#ffffff",
                                                    "currentColor": "#ffffff",
                                                    "showOffline": {
                                                        "type": "none"
                                                    },
                                                    "title": "Battery Level"
                                                },
                                                "properties": {
                                                    "color": "#f39c12",
                                                    "max": 100,
                                                    "min": 0,
                                                    "unit": "V"
                                                },
                                                "sources": [
                                                    {
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "batteryVoltage",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#f39c12",
                                                        "name": "Battery",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "mode": "latest"
                                                        }
                                                    }
                                                ],
                                                "type": "donutchart"
                                            },
                                            {
                                                "layout": {
                                                    "col": 4,
                                                    "row": 8,
                                                    "sizeX": 2,
                                                    "sizeY": 7
                                                },
                                                "panel": {
                                                    "color": "#ffffff",
                                                    "currentColor": "#ffffff",
                                                    "showOffline": {
                                                        "type": "none"
                                                    },
                                                    "title": "Temperature"
                                                },
                                                "properties": {
                                                    "color": "#e74c3c",
                                                    "max": 50,
                                                    "min": -20,
                                                    "unit": "°C"
                                                },
                                                "sources": [
                                                    {
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "temperature",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#e74c3c",
                                                        "name": "Temperature",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "mode": "latest"
                                                        }
                                                    }
                                                ],
                                                "type": "donutchart"
                                            },
                                            {
                                                "layout": {
                                                    "col": 0,
                                                    "row": 21,
                                                    "sizeX": 6,
                                                    "sizeY": 12
                                                },
                                                "panel": {
                                                    "color": "#ffffff",
                                                    "currentColor": "#ffffff",
                                                    "showOffline": {
                                                        "type": "none"
                                                    },
                                                    "title": "Recent Positions"
                                                },
                                                "properties": {
                                                    "source": "code",
                                                    "template": "<div style=\"width:100%; height:100%; overflow-y:auto\">\n  <table class=\"table table-striped table-condensed\">\n    <thead>\n      <tr>\n        <th>Date</th>\n        <th>Latitude</th>\n        <th>Longitude</th>\n        <th>Temperature (m)</th>\n        <th>Battery (V)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr ng-repeat=\"entry in value\">\n        <td>{{ entry.ts | date:'medium' }}</td>\n        <td>{{ entry.latitude || '—' }}</td>\n        <td>{{ entry.longitude || '—' }}</td>\n        <td>{{ entry.temperature || '—' }}</td>\n        <td>{{ entry.batteryVoltage || '—' }}</td>\n      </tr>\n    </tbody>\n  </table>\n</div>\n"
                                                },
                                                "sources": [
                                                    {
                                                        "aggregation": {},
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "ts",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#1abc9c",
                                                        "name": "timestamp",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "magnitude": "hour",
                                                            "mode": "relative",
                                                            "period": "latest",
                                                            "value": 24
                                                        }
                                                    },
                                                    {
                                                        "aggregation": {},
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "latitude",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#3498db",
                                                        "name": "latitude",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "magnitude": "hour",
                                                            "mode": "relative",
                                                            "period": "latest",
                                                            "value": 24
                                                        }
                                                    },
                                                    {
                                                        "aggregation": {},
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "longitude",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#e74c3c",
                                                        "name": "longitude",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "magnitude": "hour",
                                                            "mode": "relative",
                                                            "period": "latest",
                                                            "value": 24
                                                        }
                                                    },
                                                    {
                                                        "aggregation": {},
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "temperature",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#9b59b6",
                                                        "name": "temperature",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "magnitude": "hour",
                                                            "mode": "relative",
                                                            "period": "latest",
                                                            "value": 24
                                                        }
                                                    },
                                                    {
                                                        "aggregation": {},
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "batteryVoltage",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#f39c12",
                                                        "name": "battery",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "magnitude": "hour",
                                                            "mode": "relative",
                                                            "period": "latest",
                                                            "value": 24
                                                        }
                                                    }
                                                ],
                                                "type": "html_time"
                                            },
                                            {
                                                "layout": {
                                                    "col": 0,
                                                    "row": 15,
                                                    "sizeX": 3,
                                                    "sizeY": 6
                                                },
                                                "panel": {
                                                    "color": "#ffffff",
                                                    "currentColor": "#ffffff",
                                                    "showOffline": {
                                                        "type": "none"
                                                    },
                                                    "title": "Battery History"
                                                },
                                                "properties": {
                                                    "axis": true,
                                                    "fill": false,
                                                    "legend": true,
                                                    "multiple_axes": false
                                                },
                                                "sources": [
                                                    {
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "batteryVoltage",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#f39c12",
                                                        "name": "Battery",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "magnitude": "day",
                                                            "mode": "relative",
                                                            "period": "latest",
                                                            "value": 7
                                                        }
                                                    }
                                                ],
                                                "type": "chart"
                                            },
                                            {
                                                "layout": {
                                                    "col": 3,
                                                    "row": 15,
                                                    "sizeX": 3,
                                                    "sizeY": 6
                                                },
                                                "panel": {
                                                    "color": "#ffffff",
                                                    "currentColor": "#ffffff",
                                                    "showOffline": {
                                                        "type": "none"
                                                    },
                                                    "title": "Temperature History"
                                                },
                                                "properties": {
                                                    "axis": true,
                                                    "fill": false,
                                                    "legend": true,
                                                    "multiple_axes": false
                                                },
                                                "sources": [
                                                    {
                                                        "bucket": {
                                                            "backend": "mongodb",
                                                            "id": "abeeway_geolocation_module_data",
                                                            "mapping": "temperature",
                                                            "tags": {
                                                                "device": [],
                                                                "group": []
                                                            }
                                                        },
                                                        "color": "#ff0000",
                                                        "name": "Temperature",
                                                        "source": "bucket",
                                                        "timespan": {
                                                            "magnitude": "day",
                                                            "mode": "relative",
                                                            "period": "latest",
                                                            "value": 7
                                                        }
                                                    }
                                                ],
                                                "type": "chart"
                                            }
                                        ]
                                    }
                                ]
                            }
                        }
                    ]
                }
            }
        ]
    }
}