diff --git a/milesight-iot-em300-mld/plugin.json b/milesight-iot-em300-mld/plugin.json
index 9b6a85eb0..c7873fffd 100644
--- a/milesight-iot-em300-mld/plugin.json
+++ b/milesight-iot-em300-mld/plugin.json
@@ -1,425 +1,425 @@
{
- "name": "milesight_iot_em300_mld",
- "version": "1.0.0",
- "description": "The EM300-MLD is an innovative LoRaWAN leak sensor that incorporates a flexible printed membrane",
- "author": "Thinger.io",
- "license": "MIT",
- "repository": {
- "type": "git",
- "url": "https://github.com/thinger-io/plugins.git",
- "directory": "milesight-iot-em300-mld"
- },
- "metadata": {
- "name": "Milesight-Iot EM300-MLD",
+ "name": "milesight-iot-em300-mld",
+ "version": "1.0.0",
"description": "The EM300-MLD is an innovative LoRaWAN leak sensor that incorporates a flexible printed membrane",
- "image": "assets/em300-mld.png",
- "category": "devices",
- "vendor": "milesight-iot"
- },
- "resources": {
- "products": [
- {
- "description": "The EM300-MLD is an innovative LoRaWAN leak sensor that incorporates a flexible printed membrane",
- "enabled": true,
+ "author": "Thinger.io",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/thinger-io/plugins.git",
+ "directory": "milesight-iot-em300-mld"
+ },
+ "metadata": {
"name": "Milesight-Iot EM300-MLD",
- "product": "milesight_iot_em300_mld",
- "profile": {
- "api": {
- "downlink": {
- "enabled": true,
- "handle_connectivity": false,
- "request": {
- "data": {
- "path": "/downlink",
- "payload": "{\r\n \"data\" : \"{{payload.data=\"\"}}\",\r\n \"port\" : {{payload.port=2}},\r\n \"priority\": {{payload.priority=3}},\r\n \"confirmed\" : {{payload.confirmed=false}},\r\n \"uplink\" : {{property.uplink}} \r\n}",
- "payload_function": "",
- "payload_type": "",
- "plugin": "{{property.uplink.source}}",
- "target": "plugin_endpoint"
- }
- }
- },
- "uplink": {
- "enabled": true,
- "handle_connectivity": true,
- "request": {
- "data": {
- "payload": "{{payload}}",
- "payload_function": "",
- "payload_type": "source_payload",
- "resource_stream": "uplink",
- "target": "resource_stream"
- }
- }
- }
- },
- "autoprovisions": {
- "device_autoprovisioning": {
- "config": {
- "mode": "pattern",
- "pattern": "em300_mld_.*"
- },
- "enabled": true
- }
- },
- "buckets": {
- "milesight_em300_mld_data": {
- "backend": "mongodb",
- "data": {
- "payload": "{{payload}}",
- "payload_function": "",
- "payload_type": "source_payload",
- "resource_stream": "uplink_decoded",
- "target": "resource_stream"
- },
- "enabled": true,
- "retention": {
- "period": 3,
- "unit": "months"
- },
- "tags": []
- }
- },
- "code": {
- "code": "function decodeThingerUplink(thingerData) {\n // 0. If data has already been decoded, we will return it\n if (thingerData.decodedPayload) return thingerData.decodedPayload;\n \n // 1. Extract and Validate Input\n // We need 'payload' (hex string) and 'fPort' (integer)\n const hexPayload = thingerData.payload || \"\";\n const port = thingerData.fPort || 1;\n\n // 2. Convert Hex String to Byte Array\n const bytes = [];\n for (let i = 0; i < hexPayload.length; i += 2) {\n bytes.push(parseInt(hexPayload.substr(i, 2), 16));\n }\n\n // 3. Dynamic Function Detection and Execution\n \n // CASE A: (The Things Stack v3)\n if (typeof decodeUplink === 'function') {\n try {\n const input = {\n bytes: bytes,\n fPort: port\n };\n var result = decodeUplink(input);\n \n if (result.data) return result.data;\n\n return result; \n } catch (e) {\n console.error(\"Error inside decodeUplink:\", e);\n throw e;\n }\n }\n\n // CASE B: Legacy TTN (v2)\n else if (typeof Decoder === 'function') {\n try {\n return Decoder(bytes, port);\n } catch (e) {\n console.error(\"Error inside Decoder:\", e);\n throw e;\n }\n }\n\n // CASE C: No decoder found\n else {\n throw new Error(\"No compatible TTN decoder function (decodeUplink or Decoder) found in scope.\");\n }\n}\n\n\n// TTN decoder\nfunction decodeUplink(input) {\n var res = Decoder(input.bytes, input.fPort);\n if (res.error) {\n return {\n errors: [res.error],\n };\n }\n return {\n data: res,\n };\n}\n\n/**\n * Payload Decoder for The Things Network\n *\n * Copyright 2023 Milesight IoT\n *\n * @product EM300-MLD\n */\nfunction Decoder(bytes, port) {\n return milesight(bytes);\n}\n\nfunction milesight(bytes) {\n var decoded = {};\n\n for (var i = 0; i < bytes.length;) {\n var channel_id = bytes[i++];\n var channel_type = bytes[i++];\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = bytes[i];\n i += 1;\n }\n // LEAKAGE STATUS\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.leakage_status = bytes[i] === 0 ? \"normal\" : \"leak\";\n i += 1;\n }\n // TEMPERATURE, HUMIDITY & LEAKAGE STATUS HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var point = {};\n point.timestamp = readUInt32LE(bytes.slice(i, i + 4));\n point.leakage_status = bytes[i + 7] === 0 ? \"normal\" : \"leak\";\n\n decoded.history = decoded.history || [];\n decoded.history.push(point);\n i += 8;\n } else {\n break;\n }\n }\n\n return decoded;\n}\n\n/* ******************************************\n * bytes to number\n ********************************************/\nfunction readUInt16LE(bytes) {\n var value = (bytes[1] << 8) + bytes[0];\n return value & 0xffff;\n}\n\nfunction readInt16LE(bytes) {\n var ref = readUInt16LE(bytes);\n return ref > 0x7fff ? ref - 0x10000 : ref;\n}\n\nfunction readUInt32LE(bytes) {\n var value = (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];\n return (value & 0xffffffff) >>> 0;\n}\n",
- "environment": "javascript",
- "storage": "",
- "version": "1.0"
- },
- "flows": {
- "milesight_em300_mld_decoder": {
- "data": {
- "payload": "{{payload}}",
- "payload_function": "decodeThingerUplink",
- "payload_type": "source_payload",
- "resource": "uplink",
- "source": "resource",
- "update": "events"
- },
- "enabled": true,
- "sink": {
- "payload": "{{payload}}",
- "payload_function": "",
- "payload_type": "source_payload",
- "resource_stream": "uplink_decoded",
- "target": "resource_stream"
- },
- "split_data": false
- }
- },
- "properties": {
- "uplink": {
- "data": {
- "payload": "{{payload}}",
- "payload_function": "",
- "payload_type": "source_payload",
- "resource": "uplink",
- "source": "resource",
- "update": "events"
- },
- "default": {
- "source": "value"
- },
- "enabled": true
- }
- }
- },
- "_resources": {
- "properties": [
+ "description": "The EM300-MLD is an innovative LoRaWAN leak sensor that incorporates a flexible printed membrane",
+ "image": "assets/em300-mld.png",
+ "category": "devices",
+ "vendor": "milesight-iot"
+ },
+ "resources": {
+ "products": [
{
- "property": "dashboard",
- "value": {
- "tabs": [
- {
- "name": "EM300-MLD Overview",
- "widgets": [
- {
- "layout": {
- "col": 0,
- "row": 0,
- "sizeX": 2,
- "sizeY": 5
- },
- "panel": {
- "color": "#ffffff",
- "currentColor": "#ffffff",
- "showOffline": {
- "type": "none"
- },
- "title": "Leakage Status"
- },
- "properties": {
- "decimalPlaces": 2,
- "enableExtraTextColor": false,
- "enableIconColor": false,
- "enableIconSize": false,
- "extraText": "",
- "extraTextColor": "#1E313E",
- "extraTextColorConditions": [],
- "extraTextConditions": [],
- "extraTextPosition": "above-value",
- "extraTextSize": "20px",
- "extraTextWeight": "font-light",
- "icon": "",
- "iconColor": "#1E313E",
- "iconColorConditions": [],
- "iconConditions": [],
- "iconGap": "8px",
- "iconPosition": "before-value",
- "iconSize": "75px",
- "iconVerticalOffset": "0px",
- "link": "",
- "textAlign": "center",
- "textColor": "#1E313E",
- "textColorConditions": [
- {
- "color": "#e74c3c",
- "id": "leak",
- "max": "",
- "min": "",
- "text": "leak"
- },
- {
- "color": "#2ecc71",
- "id": "normal",
- "max": "",
- "min": "",
- "text": "normal"
+ "description": "The EM300-MLD is an innovative LoRaWAN leak sensor that incorporates a flexible printed membrane",
+ "enabled": true,
+ "name": "Milesight-Iot EM300-MLD",
+ "product": "milesight_iot_em300_mld",
+ "profile": {
+ "api": {
+ "downlink": {
+ "enabled": true,
+ "handle_connectivity": false,
+ "request": {
+ "data": {
+ "path": "/downlink",
+ "payload": "{\r\n \"data\" : \"{{payload.data=\"\"}}\",\r\n \"port\" : {{payload.port=2}},\r\n \"priority\": {{payload.priority=3}},\r\n \"confirmed\" : {{payload.confirmed=false}},\r\n \"uplink\" : {{property.uplink}} \r\n}",
+ "payload_function": "",
+ "payload_type": "",
+ "plugin": "{{property.uplink.source}}",
+ "target": "plugin_endpoint"
+ }
}
- ],
- "textSize": "65px",
- "textWeight": "font-light",
- "unit": "",
- "unitSize": "20px"
},
- "sources": [
- {
- "bucket": {
- "backend": "mongodb",
- "id": "milesight_em300_mld_data",
- "mapping": "leakage_status",
- "tags": {
- "device": [],
- "group": []
- }
- },
- "color": "#1abc9c",
- "name": "Leakage Status",
- "source": "bucket",
- "timespan": {
- "mode": "latest"
+ "uplink": {
+ "enabled": true,
+ "handle_connectivity": true,
+ "request": {
+ "data": {
+ "payload": "{{payload}}",
+ "payload_function": "",
+ "payload_type": "source_payload",
+ "resource_stream": "uplink",
+ "target": "resource_stream"
+ }
}
- }
- ],
- "type": "text"
- },
- {
- "layout": {
- "col": 0,
- "row": 5,
- "sizeX": 2,
- "sizeY": 5
- },
- "panel": {
- "color": "#ffffff",
- "currentColor": "#ffffff",
- "showOffline": {
- "type": "none"
- },
- "title": "Battery"
- },
- "properties": {
- "color": "#2ebd59",
- "gradient": false,
- "max": 100,
- "min": 0,
- "unit": "%"
- },
- "sources": [
- {
- "bucket": {
- "backend": "mongodb",
- "id": "milesight_em300_mld_data",
- "mapping": "battery",
- "tags": {
- "device": [],
- "group": []
- }
+ }
+ },
+ "autoprovisions": {
+ "device_autoprovisioning": {
+ "config": {
+ "mode": "pattern",
+ "pattern": "em300_mld_.*"
},
- "color": "#2ebd59",
- "name": "Battery",
- "source": "bucket",
- "timespan": {
- "mode": "latest"
- }
- }
- ],
- "type": "gauge"
- },
- {
- "layout": {
- "col": 2,
- "row": 0,
- "sizeX": 4,
- "sizeY": 10
- },
- "panel": {
- "color": "#ffffff",
- "currentColor": "#ffffff",
- "showOffline": {
- "type": "none"
- },
- "title": "Leakage Detection (7 days)"
- },
- "properties": {
- "alignTimeSeries": false,
- "dataAppend": false,
- "options": "var options = {\n chart: {\n type: 'line',\n stacked: false\n },\n dataLabels: {\n enabled: false\n },\n stroke: {\n curve: 'smooth',\n width: 2\n },\n xaxis: {\n type: 'datetime',\n labels: {\n datetimeUTC: false\n },\n tooltip: {\n enabled: false\n }\n },\n yaxis: [\n {\n seriesName: 'Leakage Events',\n title: {\n text: 'Status'\n },\n labels: {\n formatter: function(val) {\n if (val === 1) return 'Leak';\n if (val === 0) return 'Normal';\n return val;\n }\n }\n }\n ],\n tooltip: {\n x: {\n format: 'dd/MM/yyyy HH:mm:ss'\n }\n },\n colors: ['#e74c3c']\n};\n",
- "realTimeUpdate": true
- },
- "sources": [
- {
- "bucket": {
- "backend": "mongodb",
- "id": "milesight_em300_mld_data",
- "mapping": "leakage_status",
- "tags": {
- "device": [],
- "group": []
- }
+ "enabled": true
+ }
+ },
+ "buckets": {
+ "milesight_em300_mld_data": {
+ "backend": "mongodb",
+ "data": {
+ "payload": "{{payload}}",
+ "payload_function": "",
+ "payload_type": "source_payload",
+ "resource_stream": "uplink_decoded",
+ "source": "resource_stream"
},
- "color": "#e74c3c",
- "name": "Leakage Status",
- "processing": {
- "output": "function(value) { return value === 'leak' ? 1 : 0; }"
+ "enabled": true,
+ "retention": {
+ "period": 3,
+ "unit": "months"
},
- "source": "bucket",
- "timespan": {
- "magnitude": "day",
- "mode": "relative",
- "period": "latest",
- "value": 7
- }
- }
- ],
- "type": "apex_charts"
- },
- {
- "layout": {
- "col": 2,
- "row": 10,
- "sizeX": 4,
- "sizeY": 5
- },
- "panel": {
- "color": "#ffffff",
- "currentColor": "#ffffff",
- "showOffline": {
- "type": "none"
- },
- "title": "Battery Level (7 days)"
- },
- "properties": {
- "alignTimeSeries": false,
- "dataAppend": false,
- "options": "var options = {\n chart: {\n type: 'area'\n },\n dataLabels: {\n enabled: false\n },\n stroke: {\n curve: 'smooth'\n },\n xaxis: {\n type: 'datetime',\n labels: {\n datetimeUTC: false\n },\n tooltip: {\n enabled: false\n }\n },\n yaxis: {\n labels: {\n formatter: function (val) {\n if (val !== null && typeof val !== 'undefined')\n return val.toFixed(0) + '%';\n }\n }\n },\n tooltip: {\n x: {\n format: 'dd/MM/yyyy HH:mm:ss'\n }\n }\n};\n",
- "realTimeUpdate": true
- },
- "sources": [
- {
- "bucket": {
- "backend": "mongodb",
- "id": "milesight_em300_mld_data",
- "mapping": "battery",
- "tags": {
- "device": [],
- "group": []
- }
+ "tags": []
+ }
+ },
+ "code": {
+ "code": "function decodeThingerUplink(thingerData) {\n // 0. If data has already been decoded, we will return it\n if (thingerData.decodedPayload) return thingerData.decodedPayload;\n \n // 1. Extract and Validate Input\n // We need 'payload' (hex string) and 'fPort' (integer)\n const hexPayload = thingerData.payload || \"\";\n const port = thingerData.fPort || 1;\n\n // 2. Convert Hex String to Byte Array\n const bytes = [];\n for (let i = 0; i < hexPayload.length; i += 2) {\n bytes.push(parseInt(hexPayload.substr(i, 2), 16));\n }\n\n // 3. Dynamic Function Detection and Execution\n \n // CASE A: (The Things Stack v3)\n if (typeof decodeUplink === 'function') {\n try {\n const input = {\n bytes: bytes,\n fPort: port\n };\n var result = decodeUplink(input);\n \n if (result.data) return result.data;\n\n return result; \n } catch (e) {\n console.error(\"Error inside decodeUplink:\", e);\n throw e;\n }\n }\n\n // CASE B: Legacy TTN (v2)\n else if (typeof Decoder === 'function') {\n try {\n return Decoder(bytes, port);\n } catch (e) {\n console.error(\"Error inside Decoder:\", e);\n throw e;\n }\n }\n\n // CASE C: No decoder found\n else {\n throw new Error(\"No compatible TTN decoder function (decodeUplink or Decoder) found in scope.\");\n }\n}\n\n\n// TTN decoder\nfunction decodeUplink(input) {\n var res = Decoder(input.bytes, input.fPort);\n if (res.error) {\n return {\n errors: [res.error],\n };\n }\n return {\n data: res,\n };\n}\n\n/**\n * Payload Decoder for The Things Network\n *\n * Copyright 2023 Milesight IoT\n *\n * @product EM300-MLD\n */\nfunction Decoder(bytes, port) {\n return milesight(bytes);\n}\n\nfunction milesight(bytes) {\n var decoded = {};\n\n for (var i = 0; i < bytes.length;) {\n var channel_id = bytes[i++];\n var channel_type = bytes[i++];\n // BATTERY\n if (channel_id === 0x01 && channel_type === 0x75) {\n decoded.battery = bytes[i];\n i += 1;\n }\n // LEAKAGE STATUS\n else if (channel_id === 0x05 && channel_type === 0x00) {\n decoded.leakage_status = bytes[i] === 0 ? \"normal\" : \"leak\";\n i += 1;\n }\n // TEMPERATURE, HUMIDITY & LEAKAGE STATUS HISTROY\n else if (channel_id === 0x20 && channel_type === 0xce) {\n var point = {};\n point.timestamp = readUInt32LE(bytes.slice(i, i + 4));\n point.leakage_status = bytes[i + 7] === 0 ? \"normal\" : \"leak\";\n\n decoded.history = decoded.history || [];\n decoded.history.push(point);\n i += 8;\n } else {\n break;\n }\n }\n\n return decoded;\n}\n\n/* ******************************************\n * bytes to number\n ********************************************/\nfunction readUInt16LE(bytes) {\n var value = (bytes[1] << 8) + bytes[0];\n return value & 0xffff;\n}\n\nfunction readInt16LE(bytes) {\n var ref = readUInt16LE(bytes);\n return ref > 0x7fff ? ref - 0x10000 : ref;\n}\n\nfunction readUInt32LE(bytes) {\n var value = (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];\n return (value & 0xffffffff) >>> 0;\n}\n",
+ "environment": "javascript",
+ "storage": "",
+ "version": "1.0"
+ },
+ "flows": {
+ "milesight_em300_mld_decoder": {
+ "data": {
+ "payload": "{{payload}}",
+ "payload_function": "decodeThingerUplink",
+ "payload_type": "source_payload",
+ "resource": "uplink",
+ "source": "resource",
+ "update": "events"
},
- "color": "#2ebd59",
- "name": "Battery",
- "source": "bucket",
- "timespan": {
- "magnitude": "day",
- "mode": "relative",
- "period": "latest",
- "value": 7
- }
- }
- ],
- "type": "apex_charts"
- },
- {
- "layout": {
- "col": 0,
- "row": 10,
- "sizeX": 2,
- "sizeY": 5
- },
- "panel": {
- "color": "#ffffff",
- "currentColor": "#ffffff",
- "showOffline": {
- "type": "none"
- },
- "title": "Recent Events"
- },
- "properties": {
- "source": "code",
- "template": "
\n
\n \n \n | Date | \n Status | \n
\n \n \n \n | {{ entry.ts | date:'short' }} | \n \n LEAK\n Normal\n | \n
\n \n
\n
"
- },
- "sources": [
- {
- "bucket": {
- "backend": "mongodb",
- "id": "milesight_em300_mld_data",
- "mapping": "ts",
- "tags": {
- "device": [],
- "group": []
- }
+ "enabled": true,
+ "sink": {
+ "payload": "{{payload}}",
+ "payload_function": "",
+ "payload_type": "source_payload",
+ "resource_stream": "uplink_decoded",
+ "target": "resource_stream"
},
- "color": "#1abc9c",
- "name": "ts",
- "source": "bucket",
- "timespan": {
- "magnitude": "day",
- "mode": "relative",
- "period": "latest",
- "value": 7
- }
- },
- {
- "bucket": {
- "backend": "mongodb",
- "id": "milesight_em300_mld_data",
- "mapping": "leakage_status",
- "tags": {
- "device": [],
- "group": []
- }
+ "split_data": false
+ }
+ },
+ "properties": {
+ "uplink": {
+ "data": {
+ "payload": "{{payload}}",
+ "payload_function": "",
+ "payload_type": "source_payload",
+ "resource": "uplink",
+ "source": "resource",
+ "update": "events"
+ },
+ "default": {
+ "source": "value"
},
- "color": "#e74c3c",
- "name": "leakage_status",
- "source": "bucket",
- "timespan": {
- "magnitude": "day",
- "mode": "relative",
- "period": "latest",
- "value": 7
+ "enabled": true
+ }
+ }
+ },
+ "_resources": {
+ "properties": [
+ {
+ "property": "dashboard",
+ "value": {
+ "tabs": [
+ {
+ "name": "EM300-MLD Overview",
+ "widgets": [
+ {
+ "layout": {
+ "col": 0,
+ "row": 0,
+ "sizeX": 2,
+ "sizeY": 5
+ },
+ "panel": {
+ "color": "#ffffff",
+ "currentColor": "#ffffff",
+ "showOffline": {
+ "type": "none"
+ },
+ "title": "Leakage Status"
+ },
+ "properties": {
+ "decimalPlaces": 2,
+ "enableExtraTextColor": false,
+ "enableIconColor": false,
+ "enableIconSize": false,
+ "extraText": "",
+ "extraTextColor": "#1E313E",
+ "extraTextColorConditions": [],
+ "extraTextConditions": [],
+ "extraTextPosition": "above-value",
+ "extraTextSize": "20px",
+ "extraTextWeight": "font-light",
+ "icon": "",
+ "iconColor": "#1E313E",
+ "iconColorConditions": [],
+ "iconConditions": [],
+ "iconGap": "8px",
+ "iconPosition": "before-value",
+ "iconSize": "75px",
+ "iconVerticalOffset": "0px",
+ "link": "",
+ "textAlign": "center",
+ "textColor": "#1E313E",
+ "textColorConditions": [
+ {
+ "color": "#e74c3c",
+ "id": "leak",
+ "max": "",
+ "min": "",
+ "text": "leak"
+ },
+ {
+ "color": "#2ecc71",
+ "id": "normal",
+ "max": "",
+ "min": "",
+ "text": "normal"
+ }
+ ],
+ "textSize": "65px",
+ "textWeight": "font-light",
+ "unit": "",
+ "unitSize": "20px"
+ },
+ "sources": [
+ {
+ "bucket": {
+ "backend": "mongodb",
+ "id": "milesight_em300_mld_data",
+ "mapping": "leakage_status",
+ "tags": {
+ "device": [],
+ "group": []
+ }
+ },
+ "color": "#1abc9c",
+ "name": "Leakage Status",
+ "source": "bucket",
+ "timespan": {
+ "mode": "latest"
+ }
+ }
+ ],
+ "type": "text"
+ },
+ {
+ "layout": {
+ "col": 0,
+ "row": 5,
+ "sizeX": 2,
+ "sizeY": 5
+ },
+ "panel": {
+ "color": "#ffffff",
+ "currentColor": "#ffffff",
+ "showOffline": {
+ "type": "none"
+ },
+ "title": "Battery"
+ },
+ "properties": {
+ "color": "#2ebd59",
+ "gradient": false,
+ "max": 100,
+ "min": 0,
+ "unit": "%"
+ },
+ "sources": [
+ {
+ "bucket": {
+ "backend": "mongodb",
+ "id": "milesight_em300_mld_data",
+ "mapping": "battery",
+ "tags": {
+ "device": [],
+ "group": []
+ }
+ },
+ "color": "#2ebd59",
+ "name": "Battery",
+ "source": "bucket",
+ "timespan": {
+ "mode": "latest"
+ }
+ }
+ ],
+ "type": "gauge"
+ },
+ {
+ "layout": {
+ "col": 2,
+ "row": 0,
+ "sizeX": 4,
+ "sizeY": 10
+ },
+ "panel": {
+ "color": "#ffffff",
+ "currentColor": "#ffffff",
+ "showOffline": {
+ "type": "none"
+ },
+ "title": "Leakage Detection (7 days)"
+ },
+ "properties": {
+ "alignTimeSeries": false,
+ "dataAppend": false,
+ "options": "var options = {\n chart: {\n type: 'line',\n stacked: false\n },\n dataLabels: {\n enabled: false\n },\n stroke: {\n curve: 'smooth',\n width: 2\n },\n xaxis: {\n type: 'datetime',\n labels: {\n datetimeUTC: false\n },\n tooltip: {\n enabled: false\n }\n },\n yaxis: [\n {\n seriesName: 'Leakage Events',\n title: {\n text: 'Status'\n },\n labels: {\n formatter: function(val) {\n if (val === 1) return 'Leak';\n if (val === 0) return 'Normal';\n return val;\n }\n }\n }\n ],\n tooltip: {\n x: {\n format: 'dd/MM/yyyy HH:mm:ss'\n }\n },\n colors: ['#e74c3c']\n};\n",
+ "realTimeUpdate": true
+ },
+ "sources": [
+ {
+ "bucket": {
+ "backend": "mongodb",
+ "id": "milesight_em300_mld_data",
+ "mapping": "leakage_status",
+ "tags": {
+ "device": [],
+ "group": []
+ }
+ },
+ "color": "#e74c3c",
+ "name": "Leakage Status",
+ "processing": {
+ "output": "function(value) { return value === 'leak' ? 1 : 0; }"
+ },
+ "source": "bucket",
+ "timespan": {
+ "magnitude": "day",
+ "mode": "relative",
+ "period": "latest",
+ "value": 7
+ }
+ }
+ ],
+ "type": "apex_charts"
+ },
+ {
+ "layout": {
+ "col": 2,
+ "row": 10,
+ "sizeX": 4,
+ "sizeY": 5
+ },
+ "panel": {
+ "color": "#ffffff",
+ "currentColor": "#ffffff",
+ "showOffline": {
+ "type": "none"
+ },
+ "title": "Battery Level (7 days)"
+ },
+ "properties": {
+ "alignTimeSeries": false,
+ "dataAppend": false,
+ "options": "var options = {\n chart: {\n type: 'area'\n },\n dataLabels: {\n enabled: false\n },\n stroke: {\n curve: 'smooth'\n },\n xaxis: {\n type: 'datetime',\n labels: {\n datetimeUTC: false\n },\n tooltip: {\n enabled: false\n }\n },\n yaxis: {\n labels: {\n formatter: function (val) {\n if (val !== null && typeof val !== 'undefined')\n return val.toFixed(0) + '%';\n }\n }\n },\n tooltip: {\n x: {\n format: 'dd/MM/yyyy HH:mm:ss'\n }\n }\n};\n",
+ "realTimeUpdate": true
+ },
+ "sources": [
+ {
+ "bucket": {
+ "backend": "mongodb",
+ "id": "milesight_em300_mld_data",
+ "mapping": "battery",
+ "tags": {
+ "device": [],
+ "group": []
+ }
+ },
+ "color": "#2ebd59",
+ "name": "Battery",
+ "source": "bucket",
+ "timespan": {
+ "magnitude": "day",
+ "mode": "relative",
+ "period": "latest",
+ "value": 7
+ }
+ }
+ ],
+ "type": "apex_charts"
+ },
+ {
+ "layout": {
+ "col": 0,
+ "row": 10,
+ "sizeX": 2,
+ "sizeY": 5
+ },
+ "panel": {
+ "color": "#ffffff",
+ "currentColor": "#ffffff",
+ "showOffline": {
+ "type": "none"
+ },
+ "title": "Recent Events"
+ },
+ "properties": {
+ "source": "code",
+ "template": "\n
\n \n \n | Date | \n Status | \n
\n \n \n \n | {{ entry.ts | date:'short' }} | \n \n LEAK\n Normal\n | \n
\n \n
\n
"
+ },
+ "sources": [
+ {
+ "bucket": {
+ "backend": "mongodb",
+ "id": "milesight_em300_mld_data",
+ "mapping": "ts",
+ "tags": {
+ "device": [],
+ "group": []
+ }
+ },
+ "color": "#1abc9c",
+ "name": "ts",
+ "source": "bucket",
+ "timespan": {
+ "magnitude": "day",
+ "mode": "relative",
+ "period": "latest",
+ "value": 7
+ }
+ },
+ {
+ "bucket": {
+ "backend": "mongodb",
+ "id": "milesight_em300_mld_data",
+ "mapping": "leakage_status",
+ "tags": {
+ "device": [],
+ "group": []
+ }
+ },
+ "color": "#e74c3c",
+ "name": "leakage_status",
+ "source": "bucket",
+ "timespan": {
+ "magnitude": "day",
+ "mode": "relative",
+ "period": "latest",
+ "value": 7
+ }
+ }
+ ],
+ "type": "html_time"
+ }
+ ]
+ }
+ ]
}
- }
- ],
- "type": "html_time"
- }
+ }
]
- }
- ]
- }
+ }
}
- ]
- }
- }
- ]
- }
-}
\ No newline at end of file
+ ]
+ }
+}