Skip to content

Plugin file

Plugin configuration file
{
  "name": "EM2101",
  "version": "1.0.0",
  "description": "The YOBIIQ iQ Electricity EM2101 is a smart electricity meter with LoRaWAN® connectivity",
  "author": "Thinger.io",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/thinger-io/plugins.git",
    "directory": "EM2101"
  },
  "metadata": {
    "name": "Yobiiq EM2101",
    "description": "The YOBIIQ iQ Electricity EM2101 is a smart electricity meter with LoRaWAN® connectivity",
    "category": "devices",
    "image": "assets/EM2101.png"
  },
  "resources": {
    "products": [
      {
        "enabled": true,
        "name": "EM2101",
        "product": "EM2101",
        "profile": {
          "api": {
            "downlink": {
              "enabled": true,
              "handle_connectivity": false,
              "request": {
                "data": {}
              },
              "response": {
                "data": {}
              }
            },
            "uplink": {
              "device_id_resolver": "getId",
              "enabled": true,
              "handle_connectivity": true,
              "request": {
                "data": {
                  "payload": "{{payload}}",
                  "payload_function": "",
                  "payload_type": "source_payload",
                  "target": "resource_stream"
                }
              },
              "response": {
                "data": {}
              }
            }
          },
          "autoprovisions": {
            "em2101_autoprovision": {
              "config": {
                "mode": "pattern",
                "pattern": "yobiiq_em2101_.*"
              },
              "enabled": true
            }
          },
          "buckets": {
            "em2101_data_bucket": {
              "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": []
            },
            "em2101_energy_data_bucket": {
              "backend": "mongodb",
              "data": {
                "payload": "{{payload}}",
                "payload_function": "validateEnergyMeterPayload",
                "payload_type": "source_payload",
                "resource": "uplink",
                "source": "resource",
                "update": "events"
              },
              "enabled": true,
              "retention": {
                "period": 3,
                "unit": "months"
              },
              "tags": []
            },
            "em2101_power_data_bucket": {
              "backend": "mongodb",
              "data": {
                "payload": "{{payload}}",
                "payload_function": "validatePowerMeterPayload",
                "payload_type": "source_payload",
                "resource": "uplink",
                "source": "resource",
                "update": "events"
              },
              "enabled": true,
              "retention": {
                "period": 3,
                "unit": "months"
              },
              "tags": []
            }
          },
          "code": {
            "code": "\n// Returns device ID from an uplink payload\n// This function assumes it is receiving its argument \n// following the standardized format of LoRaWAN Thinger plugins.\nfunction getId(payload)\n{\n    return payload.deviceId;\n}\n\n// Returns device properties from an uplink payload\n// This function assumes it is receiving its argument \n// following the standardized format of LoRaWAN Thinger plugins.\nfunction decodeThingerProperties(payload)\n{\n    var decoded = {};\n    decoded.devEui = payload.deviceEui;\n    decoded.appName = payload.appId;\n    decoded[VERSION_CONTROL.CODEC.NAME] = VERSION_CONTROL.CODEC.VERSION;\n    decoded[VERSION_CONTROL.DEVICE.NAME] = VERSION_CONTROL.DEVICE.MODEL;\n    decoded[VERSION_CONTROL.PRODUCT.NAME] = VERSION_CONTROL.PRODUCT.CODE;\n    decoded[VERSION_CONTROL.MANUFACTURER.NAME] = VERSION_CONTROL.MANUFACTURER.COMPANY;\n    return decoded;\n}\n\n// Prepare payload from a LoRaWAN - Thinger plugin \n// to be decoded in a YOBIIQ custom decoder. \n// This function assumes it is receiving its argument \n// following the standardized format of LoRaWAN Thinger plugins.\nfunction decodeThingerUplink(payload) {\n    \n    // If the payload comes from TTN and IT HAS ALREADY BEEN DECODED, we can just return\n    // the already-decoded data\n    // if (payload.decodedPayload && Object.keys(payload.decodedPayload).length > 0) {\n    //     return payload.decodedPayload;\n    // }\n\n    // The \"decodeUplink\" function from YOBIIQ's decoders expects\n    // as input a JSON object with fPort, bytes, and variables.\n    var arg = {\n        \"fPort\": payload.fPort,\n        \"bytes\": hexToByteArray(payload.payload),\n        \"variables\": \"dummy\" // TODO\n    };\n\n    let decoded = decodeUplink(arg).data;\n    if(typeof decoded.timestamp == 'number')\n    {\n        decoded.ts = decoded.timestamp * 1000; // ms\n        delete decoded.timestamp;\n    }\n    // Use dataloggerTimestamp if available\n    if(typeof decoded.dataloggerTimestamp == 'number')\n    {\n        decoded.ts = decoded.dataloggerTimestamp * 1000; // ms\n        delete decoded.dataloggerTimestamp;\n    }\n\n    return decoded;\n}\n\n// HELPER: converts hex string to byte array\nfunction hexToByteArray(hexString) {\n  hexString = hexString.replace(/^0x/, '').replace(/\\s+/g, '');\n\n  if (hexString.length % 2 !== 0) {\n    return null;\n  }\n\n  const byteArray = new Uint8Array(hexString.length / 2);\n\n  for (let i = 0; i < hexString.length; i += 2) {\n    byteArray[i / 2] = parseInt(hexString.substr(i, 2), 16);\n  }\n\n  return byteArray;\n}\n\n// The following functions are used inside data-buckets decoders\nfunction validateEnergyMeterPayload(payload) {\n\n    const decoded = decodeThingerUplink(payload);\n\n    // The following fields are required to be all present in the payload.\n    // If any of them is missing, this function will return null and the data\n    // bucket won't store any data.\n    const requiredFields = [\n        'activeEnergyImportL1T1',\n        'activeEnergyImportL1T2',\n        'modbusErrorCode'\n    ];\n\n    const allFieldsPresent = requiredFields.every(field => \n        decoded.hasOwnProperty(field)\n    );\n\n    return allFieldsPresent ? decoded : null;\n}\n\nfunction validatePowerMeterPayload(payload) {\n\n    const decoded = decodeThingerUplink(payload);\n\n    // The following fields are required to be all present in the payload.\n    // If any of them is missing, this function will return null and the data\n    // bucket won't store any data.\n    const requiredFields = [\n        'activePowerL1',\n        'currentL1',\n        'frequency',\n        'phaseAngleL1',\n        'powerFactorL1',\n        'voltageL1N'\n    ];\n\n    const allFieldsPresent = requiredFields.every(field => \n        decoded.hasOwnProperty(field)\n    );\n\n    return allFieldsPresent ? decoded : null;\n}\n\n\n// ####################################### PASTE HERE YOBIIQ DECODER #######################################\n\n/**\n * Codec for EM2101 device : compatible with TTN, ChirpStack v4 and v3, etc...\n * Release Date : 16 June 2023\n * Update  Date : 18 November 2024\n */\n\n// Version Control\nvar VERSION_CONTROL = {\n    CODEC : {VERSION: \"1.0.1\", NAME: \"codecVersion\"},\n    DEVICE: {MODEL : \"EM2101\", NAME: \"genericModel\"},\n    PRODUCT: {CODE : \"P1002009\", NAME: \"productCode\"},\n    MANUFACTURER: {COMPANY : \"YOBIIQ B.V.\", NAME: \"manufacturer\"},\n}\n\n// Configuration constants for device basic info and current settings\nvar CONFIG_INFO = {\n    FPORT     : 50,\n    CHANNEL  : parseInt(\"0xFF\", 16),\n    TYPES    : {\n        \"0x09\" : {SIZE : 2, NAME : \"hardwareVersion\", DIGIT: false},\n        \"0x0A\" : {SIZE : 2, NAME : \"firmwareVersion\", DIGIT: false},\n        \"0x16\" : {SIZE : 4, NAME : \"deviceSerialNumber\"},\n        \"0x0F\" : {SIZE : 1, NAME : \"deviceClass\",\n            VALUES     : {\n                \"0x00\" : \"Class A\",\n                \"0x01\" : \"Class B\",\n                \"0x02\" : \"Class C\",\n            },\n        },\n        \"0x0B\" : {SIZE : 1, NAME : \"powerEvent\",\n            VALUES     : {\n                \"0x00\" : \"AC Power Off\",\n                \"0x01\" : \"AC Power On\",\n            },\n        },\n        \"0x00\" : {SIZE : 1, NAME : \"relayStatus\",\n            VALUES     : {\n                \"0x00\" : \"LOW\",\n                \"0x01\" : \"HIGH\"\n            },\n        },\n        \"0x1E\" : {SIZE : 2, NAME : \"primaryCurrentTransformerRatio\",},\n        \"0x1F\" : {SIZE : 1, NAME : \"secondaryCurrentTransformerRatio\",},\n        \"0x20\" : {SIZE : 4, NAME : \"primaryVoltageTransformerRatio\",},\n        \"0x21\" : {SIZE : 2, NAME : \"secondaryVoltageTransformerRatio\",},\n        \"0x28\" : {SIZE : 0, NAME : \"deviceModel\",},\n        \"0x3C\" : {SIZE : 2, NAME : \"currentLimitFallback\", UNIT : \"A\", RESOLUTION : 0.1,},\n        \"0x3D\" : {SIZE : 2, NAME : \"voltageLimitFallback\", UNIT : \"V\",},\n        \"0x3E\" : {SIZE : 2, NAME : \"powerLimitFallback\", UNIT : \"W\",},\n        \"0x3F\" : {SIZE : 2, NAME : \"deactivationDelayFallback\", UNIT : \"s\",},\n        \"0x40\" : {SIZE : 2, NAME : \"activationDelayFallback\", UNIT : \"s\",},\n        \"0x41\" : {SIZE : 2, NAME : \"offsetCurrentFallback\", UNIT : \"A\", RESOLUTION : 0.1,},\n        \"0x42\" : {SIZE : 2, NAME : \"offsetDelayFallback\", UNIT : \"s\",},\n        \"0x43\" : {SIZE : 2, NAME : \"resetTimeFallback\", UNIT : \"s\",},\n        \"0x44\" : {SIZE : 1, NAME : \"resetAmountFallback\",},\n        \"0x50\" : {SIZE : 2, NAME : \"currentLimitDynamic\", UNIT : \"A\", RESOLUTION : 0.1},\n        \"0x51\" : {SIZE : 2, NAME : \"voltageLimitDynamic\", UNIT : \"V\",},\n        \"0x52\" : {SIZE : 2, NAME : \"powerLimitDynamic\", UNIT : \"W\",},\n        \"0x53\" : {SIZE : 2, NAME : \"deactivationDelayDynamic\", UNIT : \"s\",},\n        \"0x54\" : {SIZE : 2, NAME : \"activationDelayDynamic\", UNIT : \"s\",},\n        \"0x55\" : {SIZE : 2, NAME : \"offsetCurrentDynamic\", UNIT : \"A\", RESOLUTION : 0.1},\n        \"0x56\" : {SIZE : 2, NAME : \"offsetDelayDynamic\", UNIT : \"s\",},\n        \"0x57\" : {SIZE : 2, NAME : \"resetTimeDynamic\", UNIT : \"s\",},\n        \"0x58\" : {SIZE : 1, NAME : \"resetAmountDynamic\",},\n    },\n    WARNING_NAME   : \"warning\",\n    ERROR_NAME     : \"error\",\n    INFO_NAME      : \"info\"\n}\n\n// Configuration constants for measurement registers\n var CONFIG_MEASUREMENT = {\n    FPORT_MIN : 1,\n    FPORT_MAX : 10,\n    TYPES : {\n        \"0x00\" : {SIZE : 4, NAME : \"index\",},\n        \"0x01\" : {SIZE : 4, NAME : \"timestamp\",},\n        \"0x03\" : {SIZE : 4, NAME : \"dataloggerTimestamp\",},\n        \"0x04\" : {SIZE : 4, NAME : \"activeEnergyImportL1T1\", UNIT : \"Wh\",},\n        \"0x05\" : {SIZE : 4, NAME : \"activeEnergyImportL1T2\", UNIT : \"Wh\",},\n        \"0x06\" : {SIZE : 4, NAME : \"activeEnergyExportL1T1\", UNIT : \"Wh\",},\n        \"0x07\" : {SIZE : 4, NAME : \"activeEnergyExportL1T2\", UNIT : \"Wh\",},\n        \"0x08\" : {SIZE : 4, NAME : \"reactiveEnergyImportL1T1\", UNIT : \"varh\",},\n        \"0x09\" : {SIZE : 4, NAME : \"reactiveEnergyImportL1T2\", UNIT : \"varh\",},\n        \"0x0A\" : {SIZE : 4, NAME : \"reactiveEnergyExportL1T1\", UNIT : \"varh\",},\n        \"0x0B\" : {SIZE : 4, NAME : \"reactiveEnergyExportL1T2\", UNIT : \"varh\",},\n        \"0x0C\" : {SIZE : 4, NAME : \"voltageL1N\", UNIT : \"V\", RESOLUTION : 0.1, SIGNED : true,},\n        \"0x10\" : {SIZE : 4, NAME : \"currentL1\", UNIT : \"mA\", SIGNED : true,},\n        \"0x14\" : {SIZE : 4, NAME : \"activePowerL1\", UNIT : \"W\", SIGNED : true,},\n        \"0x17\" : {SIZE : 4, NAME : \"reactivePowerL1\", UNIT : \"kvar\", RESOLUTION : 0.001, SIGNED : true,},\n        \"0x1A\" : {SIZE : 4, NAME : \"apparentPowerL1\", UNIT : \"kVA\", RESOLUTION : 0.001, SIGNED : true,},\n        \"0x1D\" : {SIZE : 1, NAME : \"powerFactorL1\", RESOLUTION : 0.01, SIGNED : true,},\n        \"0x20\" : {SIZE : 2, NAME : \"phaseAngleL1\", UNIT : \"degree\", RESOLUTION : 0.01, SIGNED : true,},\n        \"0x23\" : {SIZE : 2, NAME : \"frequency\", UNIT : \"Hz\", RESOLUTION : 0.01, SIGNED : true,},\n        \"0x24\" : {SIZE : 4, NAME : \"totalSystemActivePower\", UNIT : \"kW\",},\n        \"0x25\" : {SIZE : 4, NAME : \"totalSystemReactivePower\", UNIT : \"kvar\", RESOLUTION : 0.001,},\n        \"0x26\" : {SIZE : 4, NAME : \"totalSystemApparentPower\", UNIT : \"kVA\", RESOLUTION : 0.001,},\n        \"0x27\" : {SIZE : 4, NAME : \"maximumL1CurrentDemand\", UNIT : \"mA\", SIGNED : true,},\n        \"0x2A\" : {SIZE : 4, NAME : \"averagePower\", UNIT : \"W\", SIGNED : true,},\n        \"0x2B\" : {SIZE : 4, NAME : \"midYearOfCertification\",},\n        \"0xF0\" : {SIZE : 2, NAME : \"manufacturedYear\", DIGIT: true,},\n        \"0xF1\" : {SIZE : 2, NAME : \"firmwareVersion\", DIGIT: false,},\n        \"0xF2\" : {SIZE : 2, NAME : \"hardwareVersion\", DIGIT: false,},\n    },\n    WARNING_NAME   : \"warning\",\n    ERROR_NAME     : \"error\",\n    INFO_NAME      : \"info\"\n}\n\n// Configuration constants for change of state\nvar CONFIG_STATE = {\n    FPORT : 11,\n    TYPES : {\n        \"0x01\" : {SIZE : 1, NAME : \"relayStatus\",\n            VALUES     : {\n                \"0x00\" : \"OPEN\",\n                \"0x01\" : \"CLOSED\"\n            },\n        },\n        \"0x02\" : {SIZE : 1, NAME : \"digitalInputStatus\",\n            VALUES     : {\n                \"0x00\" : \"OPEN\",\n                \"0x01\" : \"CLOSED\"\n            },\n        },\n    },\n    WARNING_NAME   : \"warning\",\n    ERROR_NAME     : \"error\",\n    INFO_NAME      : \"info\"\n}\n\n// Configuration constants for event logging\nvar CONFIG_LOGGING = {\n    FPORT : 60,\n    CHANNEL  : parseInt(\"0xFD\", 16),\n    TYPES : {\n        \"0x01\" : {SIZE : 1, NAME : \"relaySwitchingOffReason\",\n            VALUES     : {\n                \"0x00\" : \"Invalid\",\n                \"0x01\" : \"Due to too high current limit\",\n                \"0x02\" : \"By control from the Lora network\",\n                \"0x03\" : \"By operation via display\"\n            },\n        },\n        \"0x02\" : {SIZE : 1, NAME : \"relayEnableReason\",\n            VALUES     : {\n                \"0x00\" : \"Invalid\",\n                \"0x01\" : \"By reset based on time\",\n                \"0x02\" : \"By reset from the Lora network\",\n                \"0x03\" : \"By operation via display\",\n                \"0x04\" : \"By control from the Lora network\"\n            },\n        },\n        \"0x03\" : {SIZE : 4, NAME : \"relaySwitchOffTime\",},\n        \"0x04\" : {SIZE : 4, NAME : \"relayEnableTime\",},\n        \"0x05\" : {SIZE : 4, NAME : \"currentWhenRelaySwitchingOff\",},\n        \"0x06\" : {SIZE : 4, NAME : \"voltageWhenRelaySwitchingOff\",},\n        \"0x07\" : {SIZE : 4, NAME : \"activePowerWhenRelaySwitchingOff\",},\n        \"0x08\" : {SIZE : 1, NAME : \"resetAmountStatus\",\n            VALUES     : {\n                \"0x01\" : \"Current reset count is less than the reset amount\",\n                \"0x02\" : \"Current reset count exceeds the reset amount\",\n            },\n        },\n    },\n    WARNING_NAME   : \"warning\",\n    ERROR_NAME     : \"error\",\n    INFO_NAME      : \"info\"\n}\n\nfunction decodeBasicInformation(bytes)\n{\n    var LENGTH = bytes.length;\n    var decoded = {};\n    var index = 0;\n    var channel = 0;\n    var type = \"\";\n    var size = 0;\n    if(LENGTH == 1)\n    {\n        if(bytes[0] == 0)\n        {\n            decoded[CONFIG_INFO.INFO_NAME] = \"Downlink command succeeded\";\n\n        } else if(bytes[0] == 1)\n        {\n            decoded[CONFIG_INFO.WARNING_NAME] = \"Downlink command failed\";\n        }\n        return decoded;\n    }\n    try\n    {\n        while(index < LENGTH)\n        {\n            channel = bytes[index];\n            index = index + 1;\n            // No channel checking\n            // Type of basic information\n            type = \"0x\" + toEvenHEX(bytes[index].toString(16).toUpperCase());\n            index = index + 1;\n            var info = CONFIG_INFO.TYPES[type];\n            size = info.SIZE;\n            // Decoding\n            var value = 0;\n            if(size != 0)\n            {\n                if(info.DIGIT || info.DIGIT == false)\n                {\n                    if(info.DIGIT == false)\n                    {\n                        // Decode into \"V\" + DIGIT STRING + \".\" DIGIT STRING format\n                        value = getDigitStringArrayNoFormat(bytes, index, size);\n                        value = \"V\" + value[0] + \".\" + value[1];\n                    }else\n                    {\n                        // Decode into DIGIT STRING format\n                        value = getDigitStringArrayEvenFormat(bytes, index, size);\n                        value = value.toString();\n                    }\n                }\n                else if(info.VALUES)\n                {\n                    // Decode into STRING (VALUES specified in CONFIG_INFO)\n                    value = \"0x\" + toEvenHEX(bytes[index].toString(16).toUpperCase());\n                    value = info.VALUES[value];\n                }else\n                {\n                    // Decode into DECIMAL format\n                    value = getValueFromBytesBigEndianFormat(bytes, index, size);\n                }\n                if(info.RESOLUTION)\n                {\n                    value = value * info.RESOLUTION;\n                    value = parseFloat(value.toFixed(2));\n                }\n                if(info.UNIT)\n                {\n                    // decoded[info.NAME] = {};\n                    // decoded[info.NAME][\"data\"] = value;\n                    // decoded[info.NAME][\"unit\"] = info.UNIT;\n                    decoded[info.NAME] = value;\n                }else\n                {\n                    decoded[info.NAME] = value;\n                }\n                index = index + size;\n            }else\n            {\n                // Device Model (End of decoding)\n                size = LENGTH - index;\n                decoded[info.NAME] = getStringFromBytesBigEndianFormat(bytes, index, size);\n                index = index + size;\n            }\n        }\n    }catch(error)\n    {\n        decoded[CONFIG_INFO.ERROR_NAME] = error.message;\n    }\n\n    return decoded;\n}\n\nfunction decodeDeviceData(bytes)\n{\n    var LENGTH = bytes.length;\n    var decoded = {};\n    var index = 0;\n    var channel = 0;\n    var type = \"\";\n    var size = 0;\n    if(LENGTH == 1)\n    {\n        if(bytes[0] == 0)\n        {\n            decoded[CONFIG_MEASUREMENT.INFO_NAME] = \"Downlink command succeeded\";\n\n        } else if(bytes[0] == 1)\n        {\n            decoded[CONFIG_MEASUREMENT.WARNING_NAME] = \"Downlink command failed\";\n        }\n        return decoded;\n    }\n    try\n    {\n        while(index < LENGTH)\n        {\n            channel = bytes[index];\n            index = index + 1;\n            // Type of device measurement\n            type = \"0x\" + toEvenHEX(bytes[index].toString(16).toUpperCase());\n            index = index + 1;\n            \n            // channel checking\n            if(channel == 11 && type == \"0x0A\")\n            {\n                // Modbus error code decoding\n                decoded.modbusErrorCode = bytes[index];\n                index = index + 1;\n                continue; // next channel\n            }\n\n            var measurement = CONFIG_MEASUREMENT.TYPES[type];\n            size = measurement.SIZE;\n            // Decoding\n            var value = 0;\n            if(measurement.DIGIT || measurement.DIGIT == false)\n            {\n                if(measurement.DIGIT == false)\n                {\n                    // Decode into \"V\" + DIGIT STRING + \".\" DIGIT STRING format\n                    value = getDigitStringArrayNoFormat(bytes, index, size);\n                    value = \"V\" + value[0] + \".\" + value[1];\n                }else\n                {\n                    // Decode into DIGIT NUMBER format\n                    value = getDigitStringArrayEvenFormat(bytes, index, size);\n                    value = parseInt(value.join(\"\"));\n                }\n            }else\n            {\n                // Decode into DECIMAL format\n                value = getValueFromBytesBigEndianFormat(bytes, index, size);\n            }\n            if(measurement.SIGNED)\n            {\n                value = getSignedIntegerFromInteger(value, size);\n            }\n            if(measurement.RESOLUTION)\n            {\n                value = value * measurement.RESOLUTION;\n                value = parseFloat(value.toFixed(2));\n            }\n            if(measurement.UNIT)\n            {\n                // decoded[measurement.NAME] = {};\n                // decoded[measurement.NAME][\"data\"] = value;\n                // decoded[measurement.NAME][\"unit\"] = measurement.UNIT;\n                decoded[measurement.NAME] = value;\n            }else\n            {\n                decoded[measurement.NAME] = value;\n            }\n            index = index + size;\n\n        }\n    }catch(error)\n    {\n        decoded[CONFIG_MEASUREMENT.ERROR_NAME] = error.message;\n    }\n    return decoded;\n}\n\nfunction decodeChangeState(bytes)\n{\n    var LENGTH = bytes.length;\n    var decoded = {};\n    var index = 0;\n    var channel = 0;\n    var type = \"\";\n    var size = 0;\n    if(LENGTH == 1)\n    {\n        if(bytes[0] == 0)\n        {\n            decoded[CONFIG_STATE.INFO_NAME] = \"Downlink command succeeded\";\n\n        } else if(bytes[0] == 1)\n        {\n            decoded[CONFIG_STATE.WARNING_NAME] = \"Downlink command failed\";\n        }\n        return decoded;\n    }\n    try\n    {\n        while(index < LENGTH)\n        {\n            channel = bytes[index];\n            index = index + 1;\n            // Type of change of state\n            type = \"0x\" + toEvenHEX(bytes[index].toString(16).toUpperCase());\n            index = index + 1;\n            // No channel checking\n            var state = CONFIG_STATE.TYPES[type];\n            size = state.SIZE;\n            // Decoding\n            var value = 0;\n            if(size != 0)\n            {\n                if(state.VALUES)\n                {\n                    // Decode into STRING (VALUES specified in CONFIG_STATE)\n                    value = \"0x\" + toEvenHEX(bytes[index].toString(16).toUpperCase());\n                    value = state.VALUES[value];\n                }\n                index = index + size;\n            }\n            decoded[state.NAME] = value;\n        }\n    }catch(error)\n    {\n        decoded[CONFIG_STATE.ERROR_NAME] = error.message;\n    }\n\n    return decoded;\n}\n\nfunction decodeEventLogging(bytes)\n{\n    var LENGTH = bytes.length;\n    var decoded = {};\n    var index = 0;\n    var channel = 0;\n    var type = \"\";\n    var size = 0;\n    if(LENGTH == 1)\n    {\n        if(bytes[0] == 0)\n        {\n            decoded[CONFIG_LOGGING.INFO_NAME] = \"Downlink command succeeded\";\n\n        } else if(bytes[0] == 1)\n        {\n            decoded[CONFIG_LOGGING.WARNING_NAME] = \"Downlink command failed\";\n        }\n        return decoded;\n    }\n    try\n    {\n        while(index < LENGTH)\n        {\n            channel = bytes[index];\n            index = index + 1;\n            // Type of change of state\n            type = \"0x\" + toEvenHEX(bytes[index].toString(16).toUpperCase());\n            index = index + 1;\n            // No channel checking\n            var logging = CONFIG_LOGGING.TYPES[type];\n            size = logging.SIZE;\n            // Decoding\n            var value = 0;\n            if(size != 0)\n            {\n                if(logging.VALUES)\n                {\n                    // Decode into STRING (VALUES specified in CONFIG_LOGGING)\n                    value = \"0x\" + toEvenHEX(bytes[index].toString(16).toUpperCase());\n                    value = logging.VALUES[value];\n                }else\n                {\n                    // Decode into DECIMAL format\n                    value = getValueFromBytesBigEndianFormat(bytes, index, size);\n                }\n                index = index + size;\n            }\n            decoded[logging.NAME] = value;\n        }\n    }catch(error)\n    {\n        decoded[CONFIG_LOGGING.ERROR_NAME] = error.message;\n    }\n\n    return decoded;\n}\n\nfunction getStringFromBytesBigEndianFormat(bytes, index, size)\n{\n    var value = \"\";\n    for(var i=0; i<size; i=i+1)\n    {\n        value = value + String.fromCharCode(bytes[index+i]);\n    }\n    return value;\n}\n\nfunction getStringFromBytesLittleEndianFormat(bytes, index, size)\n{\n    var value = \"\";\n    for(var i=(size - 1); i>=0; i=i-1)\n    {\n        value = value + String.fromCharCode(bytes[index+i]);\n    }\n    return value;\n}\n\nfunction getValueFromBytesBigEndianFormat(bytes, index, size)\n{\n    var value = 0;\n    for(var i=0; i<(size-1); i=i+1)\n    {\n        value = (value | bytes[index+i]) << 8; \n    }\n    value = value | bytes[index+size-1]\n    return (value >>> 0); // to unsigned\n}\n\nfunction getValueFromBytesLittleEndianFormat(bytes, index, size)\n{\n    var value = 0;\n    for(var i=(size-1); i>0; i=i-1)\n    {\n        value = (value | bytes[index+i]) << 8; \n    }\n    value = value | bytes[index]\n    return (value >>> 0); // to unsigned\n}\n\nfunction getDigitStringArrayNoFormat(bytes, index, size)\n{\n  var hexString = []\n  for(var i=0; i<size; i=i+1)\n  {\n    hexString.push(bytes[index+i].toString(16));\n  }\n  return hexString\n}\n\nfunction getDigitStringArrayEvenFormat(bytes, index, size)\n{\n  var hexString = []\n  for(var i=0; i<size; i=i+1)\n  {\n    hexString.push(bytes[index+i].toString(16));\n  }\n  return hexString.map(toEvenHEX)\n}\n\nfunction toEvenHEX(hex)\n{\n  if(hex.length == 1)\n  {\n    return \"0\"+hex;\n  }\n  return hex;\n}\n\nfunction getSignedIntegerFromInteger(integer, size) \n{\n    var signMask = 1 << (size * 8 - 1);\n    var dataMask = (1 << (size * 8 - 1)) - 1;\n    if(integer & signMask) \n    {\n        return -(~integer & dataMask) - 1;\n    }else \n    {\n        return integer & dataMask;\n    }\n}\n\n/************************************************************************************************************/\n\n// Decode decodes an array of bytes into an object. (ChirpStack v3)\n//  - fPort contains the LoRaWAN fPort number\n//  - bytes is an array of bytes, e.g. [225, 230, 255, 0]\n//  - variables contains the device variables e.g. {\"calibration\": \"3.5\"} (both the key / value are of type string)\n// The function must return an object, e.g. {\"temperature\": 22.5}\nfunction Decode(fPort, bytes, variables) \n{\n    var decoded = {};\n    if(fPort == 0)\n    {\n        decoded = {mac: \"MAC command received\", fPort: fPort};\n    }\n    else if(fPort == CONFIG_INFO.FPORT)\n    {\n        decoded = decodeBasicInformation(bytes);\n    }else if(fPort >= CONFIG_MEASUREMENT.FPORT_MIN && fPort <= CONFIG_MEASUREMENT.FPORT_MAX)\n    {\n        decoded = decodeDeviceData(bytes);\n    }else if(fPort == CONFIG_STATE.FPORT)\n    {\n        decoded = decodeChangeState(bytes);\n    }else if(fPort == CONFIG_LOGGING.FPORT)\n    {\n        decoded = decodeEventLogging(bytes);\n    }else\n    {\n        decoded = {error: \"Incorrect fPort\", fPort : fPort};\n    }\n    // decoded[VERSION_CONTROL.CODEC.NAME] = VERSION_CONTROL.CODEC.VERSION;\n    // decoded[VERSION_CONTROL.DEVICE.NAME] = VERSION_CONTROL.DEVICE.MODEL;\n    // decoded[VERSION_CONTROL.PRODUCT.NAME] = VERSION_CONTROL.PRODUCT.CODE;\n    // decoded[VERSION_CONTROL.MANUFACTURER.NAME] = VERSION_CONTROL.MANUFACTURER.COMPANY;\n    return decoded;\n}\n\n// Decode uplink function. (ChirpStack v4 , TTN)\n//\n// Input is an object with the following fields:\n// - bytes = Byte array containing the uplink payload, e.g. [255, 230, 255, 0]\n// - fPort = Uplink fPort.\n// - variables = Object containing the configured device variables.\n//\n// Output must be an object with the following fields:\n// - data = Object representing the decoded payload.\nfunction decodeUplink(input) {\n    return {\n        data: Decode(input.fPort, input.bytes, input.variables)\n    };\n}\n\n/************************************************************************************************************/\n\n// Encode encodes the given object into an array of bytes. (ChirpStack v3)\n//  - fPort contains the LoRaWAN fPort number\n//  - obj is an object, e.g. {\"temperature\": 22.5}\n//  - variables contains the device variables e.g. {\"calibration\": \"3.5\"} (both the key / value are of type string)\n// The function must return an array of bytes, e.g. [225, 230, 255, 0]\nfunction Encode(fPort, obj, variables) {\n    try\n    {\n        if(obj[CONFIG_DOWNLINK.TYPE] == CONFIG_DOWNLINK.CONFIG)\n        {\n            return encodeDeviceConfiguration(obj[CONFIG_DOWNLINK.CONFIG], variables);\n        }\n        else if(obj[CONFIG_DOWNLINK.TYPE] == CONFIG_DOWNLINK.DYNAMIC)\n        {\n            return encodeDynamicLimitControl(obj[CONFIG_DOWNLINK.DYNAMIC], variables);\n        }\n        else if(obj[CONFIG_DOWNLINK.TYPE] == CONFIG_DOWNLINK.RELAY)\n        {\n            return encodeRelayControl(obj[CONFIG_DOWNLINK.RELAY], variables);\n        }\n        else if(obj[CONFIG_DOWNLINK.TYPE] == CONFIG_DOWNLINK.MEASURE)\n        {\n            return encodePeriodicPackage(obj[CONFIG_DOWNLINK.MEASURE], variables);\n        }\n        else if(obj[CONFIG_DOWNLINK.TYPE] == CONFIG_DOWNLINK.REQUEST)\n        {\n            return encodeRequestSettings(obj[CONFIG_DOWNLINK.REQUEST], variables);\n        }\n    }catch(error)\n    {\n\n    }\n    return [];\n}\n\n// Encode downlink function. (ChirpStack v4 , TTN)\n//\n// Input is an object with the following fields:\n// - data = Object representing the payload that must be encoded.\n// - variables = Object containing the configured device variables.\n//\n// Output must be an object with the following fields:\n// - bytes = Byte array containing the downlink payload.\nfunction encodeDownlink(input) {\n    return {\n        bytes: Encode(null, input.data, input.variables)\n    };\n}\n\n/************************************************************************************************************/\n\n// Constants for device configuration \nvar CONFIG_DEVICE = {\n    FPORT : 50,\n    CHANNEL : parseInt(\"0xFF\", 16),\n    TYPES : {\n        \"restart\" : {TYPE : parseInt(\"0x0B\", 16), SIZE : 1, MIN : 1, MAX : 1,},\n        \"digitalInput\" : {TYPE : parseInt(\"0x47\", 16), SIZE : 1, MIN : 0, MAX : 1, CHANNEL : parseInt(\"0x08\", 16),},\n        \"currentLimitFallback\" : {TYPE : parseInt(\"0x32\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"voltageLimitFallback\" : {TYPE : parseInt(\"0x33\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"powerLimitFallback\" : {TYPE : parseInt(\"0x34\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"deactivationDelayFallback\" : {TYPE : parseInt(\"0x35\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"activationDelayFallback\" : {TYPE : parseInt(\"0x36\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"offsetCurrentFallback\" : {TYPE : parseInt(\"0x37\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"offsetDelayFallback\" : {TYPE : parseInt(\"0x38\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"resetTimeFallback\" : {TYPE : parseInt(\"0x39\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"resetAmountFallback\" : {TYPE : parseInt(\"0x3A\", 16), SIZE : 1, MIN : 0, MAX : 255,}\n    }\n}\n\n// Constants for Dynamic limit control\nvar CONFIG_DYNAMIC = {\n    FPORT : 50,\n    CHANNEL : parseInt(\"0x01\", 16),\n    TYPES : {\n        \"currentLimit\" : {TYPE : parseInt(\"0x32\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"voltageLimit\" : {TYPE : parseInt(\"0x33\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"powerLimit\" : {TYPE : parseInt(\"0x34\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"deactivationDelay\" : {TYPE : parseInt(\"0x35\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"activationDelay\" : {TYPE : parseInt(\"0x36\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"offsetCurrent\" : {TYPE : parseInt(\"0x37\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"offsetDelay\" : {TYPE : parseInt(\"0x38\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"resetTime\" : {TYPE : parseInt(\"0x39\", 16), SIZE : 2, MIN : 0, MAX : 9999,},\n        \"resetAmount\" : {TYPE : parseInt(\"0x3A\", 16), SIZE : 1, MIN : 0, MAX : 255,}\n    }\n}\n\n// Constants for Relay control\nvar CONFIG_RELAY = {\n    FPORT : 50,\n    CHANNEL : parseInt(\"0x07\", 16),\n    TYPES : {\n        \"reset\" : {TYPE : parseInt(\"0x46\", 16), SIZE : 1, MIN : 1, MAX : 1,},\n        \"controlMode\" : {TYPE : parseInt(\"0x47\", 16), SIZE : 1, MIN : 0, MAX : 1,},\n        \"relayCommand\" : {TYPE : parseInt(\"0x48\", 16), SIZE : 1, MIN : 0, MAX : 1,}\n    }\n}\n\n// Constants for device periodic package \nvar CONFIG_PERIODIC = {\n    CHANNEL : parseInt(\"0xFF\", 16),\n    TYPES : {\n        \"Interval\" : {TYPE : parseInt(\"0x14\", 16), SIZE : 1, MIN : 1, MAX : 255,},\n        \"Mode\" : {TYPE : parseInt(\"0x15\", 16), SIZE : 1, MIN : 0, MAX : 1,},\n        \"Status\" : {TYPE : parseInt(\"0x16\", 16), SIZE : 1, MIN : 0, MAX : 1,},\n        \"Measurement\" : {TYPE : parseInt(\"0x17\", 16), SIZE : 1, MIN : 0, MAX : 10,},\n    },\n    MEASUREMENTS : {\n        index : \"0x00\",\n        timestamp : \"0x01\",\n        dataloggerTimestamp : \"0x03\",\n        activeEnergyImportL1T1 : \"0x04\",\n        activeEnergyImportL1T2 : \"0x05\",\n        activeEnergyExportL1T1 : \"0x06\",\n        activeEnergyExportL1T2 : \"0x07\",\n        reactiveEnergyImportL1T1 : \"0x08\",\n        reactiveEnergyImportL1T2 : \"0x09\",\n        reactiveEnergyExportL1T1 : \"0x0A\",\n        reactiveEnergyExportL1T2 : \"0x0B\",\n        voltageL1N : \"0x0C\",\n        currentL1 : \"0x10\",\n        activePowerL1 : \"0x14\",\n        reactivePowerL1 : \"0x17\",\n        apparentPowerL1 : \"0x1A\",\n        powerFactorL1 : \"0x1d\",\n        phaseAngleL1 : \"0x20\",\n        frequency : \"0x23\",\n        totalSystemActivePower : \"0x24\",\n        totalSystemReactivePower : \"0x25\",\n        totalSystemApparentPower : \"0x26\",\n        maximumL1CurrentDemand : \"0x27\",\n        AveragePower : \"0x2A\",\n        midYearOfCertification : \"0x2B\",\n        manufacturedYear : \"0xF0\",\n        firmwareVersion : \"0xF1\",\n        hardwareVersion : \"0xF2\",\n    }\n}\n\n// Constants for request settings\nvar CONFIG_REQUEST = {\n    FPORT: 50,\n    CHANNEL : parseInt(\"0x02\", 16),\n    TYPE : parseInt(\"0x0B\", 16),\n    MIN: 1,\n    MAX: 10,\n    SETTINGS : {\n        currentLimitFallback : \"0x3C\",\n        voltageLimitFallback : \"0x3D\",\n        powerLimitFallback : \"0x3E\",\n        deactivationDelayFallback : \"0x3F\",\n        activationDelayFallback : \"0x40\",\n        offsetCurrentFallback : \"0x41\",\n        offsetDelayFallback : \"0x42\",\n        resetTimeFallback : \"0x43\",\n        resetAmountFallback : \"0x44\",\n        currentLimitDynamic : \"0x50\",\n        voltageLimitDynamic : \"0x51\",\n        powerLimitDynamic : \"0x52\",\n        deactivationDelayDynamic : \"0x53\",\n        activationDelayDynamic : \"0x54\",\n        offsetCurrentDynamic : \"0x55\",\n        offsetDelayDynamic : \"0x56\",\n        resetTimeDynamic : \"0x57\",\n        resetAmountDynamic : \"0x58\",\n    }\n\n}\n\n// Constants for downlink type (Config or Measure)\nvar CONFIG_DOWNLINK = {\n    TYPE    : \"Type\",\n    CONFIG  : \"Config\",\n    DYNAMIC : \"Dynamic\",\n    RELAY   : \"Relay\",\n    MEASURE : \"Measure\",\n    REQUEST : \"RequestSettings\"\n}\n\nfunction encodeDeviceConfiguration(obj, variables)\n{\n    var encoded = []\n    var index = 0;\n    var field = [\"Param\", \"Value\"];\n    try\n    {\n        var config = CONFIG_DEVICE.TYPES[obj[field[0]]];\n        var value = obj[field[1]];\n        if(obj[field[1]] >= config.MIN && obj[field[1]] <= config.MAX)\n        {\n            if(\"CHANNEL\" in config)\n            {\n                encoded[index] = config.CHANNEL;\n            }else\n            {\n                encoded[index] = CONFIG_DEVICE.CHANNEL;\n            }\n            index = index + 1;\n            encoded[index] = config.TYPE;\n            index = index + 1;\n            for(var i=1; i<=config.SIZE; i=i+1)\n            {\n                encoded[index] = (value >> 8*(config.SIZE - i)) % 256;\n                index = index + 1;\n            }\n        }else\n        {\n            // Error\n            return [];\n        }\n    }catch(error)\n    {\n        // Error\n        return [];\n    }\n    return encoded;\n}\n\nfunction encodeDynamicLimitControl(obj, variables)\n{\n    var encoded = []\n    var index = 0;\n    var field = [\"Param\", \"Value\"];\n    try\n    {\n        var config = CONFIG_DYNAMIC.TYPES[obj[field[0]]];\n        var value = obj[field[1]];\n        if(obj[field[1]] >= config.MIN && obj[field[1]] <= config.MAX)\n        {\n            encoded[index] = CONFIG_DYNAMIC.CHANNEL;\n            index = index + 1;\n            encoded[index] = config.TYPE;\n            index = index + 1;\n            for(var i=1; i<=config.SIZE; i=i+1)\n            {\n                encoded[index] = (value >> 8*(config.SIZE - i)) % 256;\n                index = index + 1;\n            }\n        }else\n        {\n            // Error\n            return [];\n        }\n    }catch(error)\n    {\n        // Error\n        return [];\n    }\n    return encoded;\n}\n\nfunction encodeRelayControl(obj, variables)\n{\n    var encoded = []\n    var index = 0;\n    var field = [\"Param\", \"Value\"];\n    try\n    {\n        var config = CONFIG_RELAY.TYPES[obj[field[0]]];\n        var value = obj[field[1]];\n        if(obj[field[1]] >= config.MIN && obj[field[1]] <= config.MAX)\n        {\n            encoded[index] = CONFIG_RELAY.CHANNEL;\n            index = index + 1;\n            encoded[index] = config.TYPE;\n            index = index + 1;\n            for(var i=1; i<=config.SIZE; i=i+1)\n            {\n                encoded[index] = (value >> 8*(config.SIZE - i)) % 256;\n                index = index + 1;\n            }\n        }else\n        {\n            // Error\n            return [];\n        }\n    }catch(error)\n    {\n        // Error\n        return [];\n    }\n    return encoded;\n}\n\nfunction encodePeriodicPackage(obj, variables)\n{\n    var encoded = []\n    var index = 0;\n    var field = [\"Interval\", \"Mode\", \"Status\", \"Measurement\"];\n    try \n    {\n        // Encode Interval, Mode, Status\n        for(var i=0; i<3; i=i+1)\n        {\n            if(field[i] in obj)\n            {\n                var config = CONFIG_PERIODIC.TYPES[field[i]];\n                if(obj[field[i]] >= config.MIN && obj[field[i]] <= config.MAX)\n                {\n                    encoded[index] = CONFIG_PERIODIC.CHANNEL;\n                    index = index + 1;\n                    encoded[index] = config.TYPE;\n                    index = index + 1;\n                    encoded[index] = obj[field[i]];\n                    index = index + 1;\n                }else\n                {\n                    // Error\n                    return [];\n                }\n            }\n        }\n        // Encode Measurement\n        if(field[3] in obj)\n        {\n            var measurements = obj[field[3]];\n            var LENGTH = measurements.length;\n            var config = CONFIG_PERIODIC.TYPES[field[3]];\n            if(LENGTH > config.MAX)\n            {\n                // Error\n                return [];\n            }\n            var measurement = \"\";\n            if(LENGTH > 0)\n            {\n                encoded[index] = CONFIG_PERIODIC.CHANNEL;\n                index = index + 1;\n                encoded[index] = config.TYPE;\n                index = index + 1;\n            }\n            for(var i=0; i<LENGTH; i=i+1)\n            {\n                measurement = measurements[i];\n                if(measurement in CONFIG_PERIODIC.MEASUREMENTS)\n                {\n                    encoded[index] = parseInt(CONFIG_PERIODIC.MEASUREMENTS[measurement], 16);\n                    index = index + 1;\n                }else\n                {\n                    // Error\n                    return [];\n                }\n            }\n        }\n\n    }catch(error)\n    {\n        // Error\n        return [];\n    }\n\n    return encoded;\n}\n\nfunction encodeRequestSettings(obj, variables){\n    var encoded = []\n    var index = 0;\n    var LENGTH = obj.length;\n    try \n    {\n        // Encode each request setting\n        for(var i=0; i<LENGTH; i=i+1)\n        {\n            if(obj[i] in CONFIG_REQUEST.SETTINGS)\n            {\n                encoded[index] = CONFIG_REQUEST.CHANNEL;\n                index = index + 1;\n                encoded[index] = CONFIG_REQUEST.TYPE;\n                index = index + 1;\n                encoded[index] = parseInt(CONFIG_REQUEST.SETTINGS[obj[i]], 16);\n                index = index + 1;\n            }\n        }       \n    }catch(error)\n    {\n        // Error\n        return [];\n    }\n\n    return encoded;\n}\n",
            "environment": "javascript",
            "storage": "",
            "version": "1.0"
          },
          "properties": {
            "uplink": {
              "data": {
                "payload": "{{payload}}",
                "payload_function": "decodeThingerProperties",
                "payload_type": "source_payload",
                "resource": "uplink",
                "source": "resource",
                "update": "events"
              },
              "default": {
                "source": "value"
              },
              "enabled": true
            }
          }
        },
        "project": [
          "yobiiq@yobiiq_em2101_project"
        ],
        "_resources": {
          "properties": [
            {
              "property": "dashboard",
              "value": {
                "controls": {
                  "aggregation": {
                    "auto": true,
                    "period": "1m"
                  },
                  "timespan": {
                    "magnitude": "hour",
                    "mode": "relative",
                    "period": "latest",
                    "value": 24
                  }
                },
                "description": "Rele Varimétrico",
                "name": "Demo Rele Varimetrico",
                "placeholders": {
                  "sources": []
                },
                "properties": {
                  "background_image": "#13234c",
                  "columns": 24,
                  "hide_header": false,
                  "row_height": 20,
                  "show_template": false
                },
                "tabs": [
                  {
                    "name": "Main",
                    "widgets": [
                      {
                        "layout": {
                          "col": 3,
                          "row": 0,
                          "sizeX": 3,
                          "sizeY": 4
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Current"
                        },
                        "properties": {
                          "color": "#ffffff",
                          "decimal_places": 2,
                          "icon": "",
                          "size": "25px",
                          "unit": "A",
                          "unit_size": "20px",
                          "weight": "font-thin"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "currentL1",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "name": "V31",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "text"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 0,
                          "row": 4,
                          "sizeX": 9,
                          "sizeY": 15
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showFullscreen": true,
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "VOLTAGE",
                          "updateTs": 1760693400000
                        },
                        "properties": {
                          "options": "var options = {\n    series: series,\nchart: {\n   background:'#162756',\n    toolbar: {\n      show: true,\n      offsetX: 0,\n      offsetY: 0,\n      tools: {\n        download: true,\n        selection: true,\n        zoom: true,\n        zoomin: true,\n        zoomout: true,\n        pan: true,\n        reset: true | '<img src=\"/static/icons/reset.png\" width=\"20\">',\n        customIcons: []\n      },\n      export: {\n        csv: {\n          filename: undefined,\n          columnDelimiter: ',',\n          headerCategory: 'ts',\n          headerValue: 'value',\n          dateFormatter(timestamp) {\n            return new Date(timestamp).toString()\n          }\n        },\n        svg: {\n          filename: undefined,\n        },\n        png: {\n          filename: undefined,\n        }\n      },\n      autoSelected: 'zoom' \n    },\n zoom: {\n          enabled: true,\n          type: 'x',  \n          autoScaleYaxis: true,  \n          zoomedArea: {\n            fill: {\n              color: '#90CAF9',\n              opacity: 0.7\n            },\n            stroke: {\n              color: '#0D47A1',\n              opacity: 0.4,\n              width: 1\n            }\n          }\n      }\n},\n\n    toolbar: {\n        autoSelected: 'zoom'\n\n    },\n    stroke: {\n        curve: 'smooth',\n        width: 1.7\n    },\n    grid: {\n        row: {\n            colors: ['#233e87', 'transparent'],\n            opacity: 0.3\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        },\n          shared: true\n    },\n    legend: {\n        position: 'bottom',\n        labels: {\n          colors: '#FFFFFF',\n          useSeriesColors: false\n        }\n        \n    }\n    \n    \n \n};"
                        },
                        "sources": [
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "voltageL1N",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "color": "#2E93fA",
                            "name": "Ph1-N",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "V2",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#66DA26",
                            "name": "Ph2-N",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "V3",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#ff8800",
                            "name": "Ph3-N",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 0,
                          "row": 19,
                          "sizeX": 9,
                          "sizeY": 15
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showFullscreen": true,
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "PHASE-ANGLE",
                          "updateTs": 1755273607689
                        },
                        "properties": {
                          "options": "var options = {\n    series: series,\nchart: {\n   background:'#162756',\n    toolbar: {\n      show: true,\n      offsetX: 0,\n      offsetY: 0,\n      tools: {\n        download: true,\n        selection: true,\n        zoom: true,\n        zoomin: true,\n        zoomout: true,\n        pan: true,\n        reset: true | '<img src=\"/static/icons/reset.png\" width=\"20\">',\n        customIcons: []\n      },\n      export: {\n        csv: {\n          filename: undefined,\n          columnDelimiter: ',',\n          headerCategory: 'ts',\n          headerValue: 'value',\n          dateFormatter(timestamp) {\n            return new Date(timestamp).toString()\n          }\n        },\n        svg: {\n          filename: undefined,\n        },\n        png: {\n          filename: undefined,\n        }\n      },\n      autoSelected: 'zoom' \n    },\n zoom: {\n          enabled: true,\n          type: 'x',  \n          autoScaleYaxis: true,  \n          zoomedArea: {\n            fill: {\n              color: '#90CAF9',\n              opacity: 0.7\n            },\n            stroke: {\n              color: '#0D47A1',\n              opacity: 0.4,\n              width: 1\n            }\n          }\n      }\n},\n\n    toolbar: {\n        autoSelected: 'zoom'\n\n    },\n    stroke: {\n        curve: 'smooth',\n        width: 1.7\n    },\n    grid: {\n        row: {\n            colors: ['#233e87', 'transparent'],\n            opacity: 0.3\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        },\n          shared: true\n    },\n    legend: {\n        position: 'bottom',\n        labels: {\n          colors: '#FFFFFF',\n          useSeriesColors: false\n        }\n        \n    }\n    \n    \n \n};"
                        },
                        "sources": [
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "phaseAngleL1",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "color": "#2E93fA",
                            "device_bucket": {},
                            "name": "Ph1-Ph2",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "V23",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#66DA26",
                            "name": "Ph2-Ph3",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "V31",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#ff8800",
                            "name": "Ph3-Ph1",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "layout": {
                          "col": 0,
                          "row": 0,
                          "sizeX": 3,
                          "sizeY": 4
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "showTs": false,
                          "subtitle": "",
                          "title": "Voltaje"
                        },
                        "properties": {
                          "color": "#ffffff",
                          "decimal_places": 2,
                          "icon": "",
                          "size": "25px",
                          "unit": "V",
                          "unit_size": "20px",
                          "weight": "font-thin"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "voltageL1N",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "name": "V1",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "text"
                      },
                      {
                        "layout": {
                          "col": 9,
                          "row": 0,
                          "sizeX": 3,
                          "sizeY": 4
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "PhaseAngle"
                        },
                        "properties": {
                          "color": "#ffffff",
                          "decimal_places": 2,
                          "icon": "",
                          "size": "25px",
                          "unit": "Hz",
                          "unit_size": "20px",
                          "weight": "font-thin"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "phaseAngleL1",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "name": "V31",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "text"
                      },
                      {
                        "layout": {
                          "col": 12,
                          "row": 0,
                          "sizeX": 3,
                          "sizeY": 4
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "ActiveEnergy L1T1"
                        },
                        "properties": {
                          "color": "#ffffff",
                          "decimal_places": 2,
                          "icon": "",
                          "size": "25px",
                          "unit": "kWh",
                          "unit_size": "20px",
                          "weight": "font-thin"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "activePowerL1",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "name": "V31",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "text"
                      },
                      {
                        "layout": {
                          "col": 15,
                          "row": 0,
                          "sizeX": 3,
                          "sizeY": 4
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Power Factor L1"
                        },
                        "properties": {
                          "color": "#ffffff",
                          "decimal_places": 2,
                          "icon": "",
                          "size": "25px",
                          "unit": "kVA",
                          "unit_size": "20px",
                          "weight": "font-thin"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "powerFactorL1",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "name": "V31",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "text"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 9,
                          "row": 19,
                          "sizeX": 15,
                          "sizeY": 15
                        },
                        "panel": {
                          "color": "#162756",
                          "colors": [],
                          "currentColor": "#162756",
                          "showFullscreen": true,
                          "showOffline": {
                            "type": "none"
                          },
                          "showTs": false,
                          "subtitle": "",
                          "title": "POWER FACTOR",
                          "updateTs": 1755273607689
                        },
                        "properties": {
                          "options": "var options = {\n    series: series,\nchart: {\n   background:'#162756',\n    toolbar: {\n      show: true,\n      offsetX: 0,\n      offsetY: 0,\n      tools: {\n        download: true,\n        selection: true,\n        zoom: true,\n        zoomin: true,\n        zoomout: true,\n        pan: true,\n        reset: true | '<img src=\"/static/icons/reset.png\" width=\"20\">',\n        customIcons: []\n      },\n      export: {\n        csv: {\n          filename: undefined,\n          columnDelimiter: ',',\n          headerCategory: 'ts',\n          headerValue: 'value',\n          dateFormatter(timestamp) {\n            return new Date(timestamp).toString()\n          }\n        },\n        svg: {\n          filename: undefined,\n        },\n        png: {\n          filename: undefined,\n        }\n      },\n      autoSelected: 'zoom' \n    },\n zoom: {\n          enabled: true,\n          type: 'x',  \n          autoScaleYaxis: true,  \n          zoomedArea: {\n            fill: {\n              color: '#90CAF9',\n              opacity: 0.7\n            },\n            stroke: {\n              color: '#0D47A1',\n              opacity: 0.4,\n              width: 1\n            }\n          }\n      }\n},\n\n    toolbar: {\n        autoSelected: 'zoom'\n\n    },\n    stroke: {\n        curve: 'smooth',\n        width: 1.7\n    },\n    grid: {\n        row: {\n            colors: ['#233e87', 'transparent'],\n            opacity: 0.3\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        },\n          shared: true\n    },\n    legend: {\n        position: 'bottom',\n        labels: {\n          colors: '#FFFFFF',\n          useSeriesColors: false\n        }\n        \n    }\n    \n    \n \n};"
                        },
                        "sources": [
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "powerFactorL1",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "color": "#2E93fA",
                            "name": "PF1",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "PF2",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#66DA26",
                            "name": "PF2",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "PF3",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#ff8800",
                            "name": "PF3",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "PFT",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#fb00ff",
                            "name": "PFT",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 9,
                          "row": 4,
                          "sizeX": 9,
                          "sizeY": 15
                        },
                        "panel": {
                          "color": "#162756",
                          "colors": [],
                          "currentColor": "#162756",
                          "showFullscreen": true,
                          "showOffline": {
                            "type": "none"
                          },
                          "showTs": false,
                          "subtitle": "",
                          "title": "AMPS",
                          "updateTs": 1755273607689
                        },
                        "properties": {
                          "options": "var options = {\n    series: series,\nchart: {\n   background:'#162756',\n    toolbar: {\n      show: true,\n      offsetX: 0,\n      offsetY: 0,\n      tools: {\n        download: true,\n        selection: true,\n        zoom: true,\n        zoomin: true,\n        zoomout: true,\n        pan: true,\n        reset: true | '<img src=\"/static/icons/reset.png\" width=\"20\">',\n        customIcons: []\n      },\n      export: {\n        csv: {\n          filename: undefined,\n          columnDelimiter: ',',\n          headerCategory: 'ts',\n          headerValue: 'value',\n          dateFormatter(timestamp) {\n            return new Date(timestamp).toString()\n          }\n        },\n        svg: {\n          filename: undefined,\n        },\n        png: {\n          filename: undefined,\n        }\n      },\n      autoSelected: 'zoom' \n    },\n zoom: {\n          enabled: true,\n          type: 'x',  \n          autoScaleYaxis: true,  \n          zoomedArea: {\n            fill: {\n              color: '#90CAF9',\n              opacity: 0.7\n            },\n            stroke: {\n              color: '#0D47A1',\n              opacity: 0.4,\n              width: 1\n            }\n          }\n      }\n},\n\n    toolbar: {\n        autoSelected: 'zoom'\n\n    },\n    stroke: {\n        curve: 'monotoneCubic',\n        width: 1.7\n    },\n    grid: {\n        row: {\n            colors: ['#233e87', 'transparent'],\n            opacity: 0.3\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        },\n          shared: true\n    },\n    legend: {\n        position: 'bottom',\n        labels: {\n          colors: '#FFFFFF',\n          useSeriesColors: false\n        }\n        \n    }\n    \n    \n \n};"
                        },
                        "sources": [
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "currentL1",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "color": "#2E93fA",
                            "device_bucket": {},
                            "name": "I1",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "I2",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#66DA26",
                            "name": "I2",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "$timespan": {
                              "magnitude": "day",
                              "mode": "configurable",
                              "period": "latest",
                              "value": 1
                            },
                            "bucket": {
                              "backend": "influxdb",
                              "id": "Dispro_PSP",
                              "mapping": "I3",
                              "tags": {
                                "Day": [],
                                "Hour": [],
                                "Slave": [
                                  "GWMD01HFCB4673B517C_1"
                                ],
                                "tag1": [],
                                "tag2": []
                              },
                              "user": "ega"
                            },
                            "color": "#ff8800",
                            "name": "I3",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "layout": {
                          "col": 6,
                          "row": 0,
                          "sizeX": 3,
                          "sizeY": 4
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Frequency"
                        },
                        "properties": {
                          "color": "#ffffff",
                          "decimal_places": 2,
                          "icon": "",
                          "size": "25px",
                          "unit": "Hz",
                          "unit_size": "20px",
                          "weight": "font-thin"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "frequency",
                              "tags": {
                                "device": [],
                                "group": []
                              },
                              "user": "ega"
                            },
                            "name": "V31",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "text"
                      },
                      {
                        "layout": {
                          "col": 18,
                          "row": 0,
                          "sizeX": 6,
                          "sizeY": 19
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          }
                        },
                        "properties": {
                          "center": true,
                          "hideControls": false,
                          "latitude": 0,
                          "longitude": 0,
                          "mapType": "roadmap",
                          "waypoints": true,
                          "zoom": 8
                        },
                        "sources": [
                          {
                            "color": "#1abc9c",
                            "device_property": {
                              "device": "yobiiq_em2101_FC48C900000001C5",
                              "mapping": {
                                "latitude": "latitude",
                                "longitude": "longitude"
                              },
                              "property": "location"
                            },
                            "name": "Source 1",
                            "source": "device_property",
                            "timespan": {
                              "magnitude": "minute",
                              "value": 30
                            }
                          }
                        ],
                        "type": "map"
                      }
                    ]
                  },
                  {
                    "icon": "",
                    "name": "Energy",
                    "widgets": [
                      {
                        "api": {},
                        "layout": {
                          "col": 0,
                          "row": 0,
                          "sizeX": 12,
                          "sizeY": 14
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Hourly Active Energy KWh",
                          "updateTs": 1760954400000
                        },
                        "properties": {
                          "alignTimeSeries": false,
                          "options": "var options = {\n    chart: {\n        type: 'line',\n        zoom: {\n            type: 'x',\n            enabled: true,\n            autoScaleYaxis: true,\n            allowMouseWheelZoom: false\n        },\n        toolbar: {\n            autoSelected: 'zoom'\n        }\n    },\n    stroke: {\n        curve: 'straight',\n        width: 4\n    },\n    grid: {\n        row: {\n            colors: ['#f3f3f3', 'transparent'],\n            opacity: 0.5\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                if ( val !== null && typeof val !== 'undefined' )\n                    return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        }\n    }\n};\n"
                        },
                        "sources": [
                          {
                            "$aggregation": {
                              "period": "1h",
                              "type": "sum"
                            },
                            "$timespan": {
                              "mode": "configurable"
                            },
                            "aggregation": {
                              "period": "1h",
                              "type": "sum"
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_energy_data_bucket",
                              "mapping": "activeEnergyImportL1T1",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#00ff00",
                            "name": "Hourly kWh",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 12,
                          "row": 0,
                          "sizeX": 12,
                          "sizeY": 14
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Daily Active Energy KWh",
                          "updateTs": 1760911200000
                        },
                        "properties": {
                          "alignTimeSeries": false,
                          "options": "var options = {\n    chart: {\n        type: 'line',\n        zoom: {\n            type: 'x',\n            enabled: true,\n            autoScaleYaxis: true,\n            allowMouseWheelZoom: false\n        },\n        toolbar: {\n            autoSelected: 'zoom'\n        }\n    },\n    stroke: {\n        curve: 'straight',\n        width: 4\n    },\n    grid: {\n        row: {\n            colors: ['#f3f3f3', 'transparent'],\n            opacity: 0.5\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                if ( val !== null && typeof val !== 'undefined' )\n                    return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        }\n    }\n};\n"
                        },
                        "sources": [
                          {
                            "aggregation": {
                              "period": "1d",
                              "type": "sum"
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_energy_data_bucket",
                              "mapping": "activeEnergyImportL1T1",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#00ff00",
                            "name": "Daily kWh",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "day",
                              "mode": "relative",
                              "period": "latest",
                              "value": 30
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 0,
                          "row": 14,
                          "sizeX": 12,
                          "sizeY": 14
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Hourly Inductive Energy (KVARh)",
                          "updateTs": 1760954400000
                        },
                        "properties": {
                          "alignTimeSeries": false,
                          "options": "var options = {\n    chart: {\n        type: 'line',\n        zoom: {\n            type: 'x',\n            enabled: true,\n            autoScaleYaxis: true,\n            allowMouseWheelZoom: false\n        },\n        toolbar: {\n            autoSelected: 'zoom'\n        }\n    },\n    stroke: {\n        curve: 'straight',\n        width: 4\n    },\n    grid: {\n        row: {\n            colors: ['#f3f3f3', 'transparent'],\n            opacity: 0.5\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                if ( val !== null && typeof val !== 'undefined' )\n                    return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        }\n    }\n};\n"
                        },
                        "sources": [
                          {
                            "$aggregation": {
                              "period": "1h",
                              "type": "sum"
                            },
                            "$timespan": {
                              "mode": "configurable"
                            },
                            "aggregation": {
                              "period": "1h",
                              "type": "sum"
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_energy_data_bucket",
                              "mapping": "activeEnergyImportL1T2",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#ffff00",
                            "name": "Hourly KVARh",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 12,
                          "row": 14,
                          "sizeX": 12,
                          "sizeY": 14
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Daily Inductive Energy (KVARh)",
                          "updateTs": 1760911200000
                        },
                        "properties": {
                          "alignTimeSeries": false,
                          "options": "var options = {\n    chart: {\n        type: 'line',\n        zoom: {\n            type: 'x',\n            enabled: true,\n            autoScaleYaxis: true,\n            allowMouseWheelZoom: false\n        },\n        toolbar: {\n            autoSelected: 'zoom'\n        }\n    },\n    stroke: {\n        curve: 'straight',\n        width: 4\n    },\n    grid: {\n        row: {\n            colors: ['#f3f3f3', 'transparent'],\n            opacity: 0.5\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                if ( val !== null && typeof val !== 'undefined' )\n                    return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        }\n    }\n};\n"
                        },
                        "sources": [
                          {
                            "aggregation": {
                              "period": "1d",
                              "type": "sum"
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_energy_data_bucket",
                              "mapping": "activeEnergyImportL1T2",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#ffff00",
                            "name": "Daily KVARh",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "day",
                              "mode": "relative",
                              "period": "latest",
                              "value": 30
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 0,
                          "row": 28,
                          "sizeX": 12,
                          "sizeY": 14
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Hourly Capacitive Energy",
                          "updateTs": 1760954400000
                        },
                        "properties": {
                          "alignTimeSeries": false,
                          "options": "var options = {\n    chart: {\n        type: 'line',\n        zoom: {\n            type: 'x',\n            enabled: true,\n            autoScaleYaxis: true,\n            allowMouseWheelZoom: false\n        },\n        toolbar: {\n            autoSelected: 'zoom'\n        }\n    },\n    stroke: {\n        curve: 'straight',\n        width: 4\n    },\n    grid: {\n        row: {\n            colors: ['#f3f3f3', 'transparent'],\n            opacity: 0.5\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                if ( val !== null && typeof val !== 'undefined' )\n                    return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        }\n    }\n};\n"
                        },
                        "sources": [
                          {
                            "$aggregation": {
                              "period": "1h",
                              "type": "sum"
                            },
                            "$timespan": {
                              "mode": "configurable"
                            },
                            "aggregation": {
                              "period": "1h",
                              "type": "sum"
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "activePowerL1",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#ff0000",
                            "name": "Hourly KVARh",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "apex_charts"
                      },
                      {
                        "api": {},
                        "layout": {
                          "col": 12,
                          "row": 28,
                          "sizeX": 12,
                          "sizeY": 14
                        },
                        "panel": {
                          "color": "#162756",
                          "currentColor": "#162756",
                          "showOffline": {
                            "type": "none"
                          },
                          "subtitle": "",
                          "title": "Daily Capacitive Energy",
                          "updateTs": 1760911200000
                        },
                        "properties": {
                          "alignTimeSeries": false,
                          "options": "var options = {\n    chart: {\n        type: 'line',\n        zoom: {\n            type: 'x',\n            enabled: true,\n            autoScaleYaxis: true,\n            allowMouseWheelZoom: false\n        },\n        toolbar: {\n            autoSelected: 'zoom'\n        }\n    },\n    stroke: {\n        curve: 'straight',\n        width: 4\n    },\n    grid: {\n        row: {\n            colors: ['#f3f3f3', 'transparent'],\n            opacity: 0.5\n        },\n    },\n    xaxis: {\n        type: 'datetime',\n        tooltip: {\n            enabled: false\n        },\n        labels: {\n            datetimeUTC: false\n        }\n    },\n    yaxis: {\n        labels: {\n            \"formatter\": function (val) {\n                if ( val !== null && typeof val !== 'undefined' )\n                    return val.toFixed(2);\n            }\n        }\n    },\n    tooltip: {\n        x: {\n            format: 'dd/MM/yyyy HH:mm:ss'\n        }\n    }\n};\n"
                        },
                        "sources": [
                          {
                            "aggregation": {
                              "period": "1d",
                              "type": "sum"
                            },
                            "bucket": {
                              "backend": "mongodb",
                              "id": "em2101_data_bucket",
                              "mapping": "activePowerL1",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#ff0000",
                            "name": "Daily KVARh",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "day",
                              "mode": "relative",
                              "period": "latest",
                              "value": 30
                            }
                          }
                        ],
                        "type": "apex_charts"
                      }
                    ]
                  }
                ]
              }
            }
          ]
        }
      }
    ]
  }
}