diff --git a/application/src/main/data/json/system/scada_symbols/3-phase-voltage-relay-hp.svg b/application/src/main/data/json/system/scada_symbols/3-phase-voltage-relay-hp.svg
new file mode 100644
index 0000000000..f6d881b172
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/3-phase-voltage-relay-hp.svg
@@ -0,0 +1,548 @@
+
+220 220 220 v
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/apartments-hp.svg b/application/src/main/data/json/system/scada_symbols/apartments-hp.svg
new file mode 100644
index 0000000000..9e2c965f79
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/apartments-hp.svg
@@ -0,0 +1,344 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/battery-hp.svg b/application/src/main/data/json/system/scada_symbols/battery-hp.svg
new file mode 100644
index 0000000000..8b63a9ab29
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/battery-hp.svg
@@ -0,0 +1,473 @@
+
+
+
+
+
+
+
+
+
+ ON
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/bottom-light-bulb-hp.svg b/application/src/main/data/json/system/scada_symbols/bottom-light-bulb-hp.svg
new file mode 100644
index 0000000000..4f0603b904
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/bottom-light-bulb-hp.svg
@@ -0,0 +1,346 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/consumers-hp.svg b/application/src/main/data/json/system/scada_symbols/consumers-hp.svg
new file mode 100644
index 0000000000..e4005d7ae2
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/consumers-hp.svg
@@ -0,0 +1,346 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/curcuit-breaker-hp.svg b/application/src/main/data/json/system/scada_symbols/curcuit-breaker-hp.svg
new file mode 100644
index 0000000000..12f8b4944f
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/curcuit-breaker-hp.svg
@@ -0,0 +1,444 @@
+ {\n ctx.api.setValue('initialState', !initial);\n }\n});"
+ }
+ }
+ },
+ {
+ "tag": "breaker-trigger",
+ "stateRenderFunction": "element.fill(ctx.properties.disabledColor);\nif (ctx.values.initialState) {\n element.transform({translateY: 0});\n} else {\n element.transform({translateY: 160});\n}",
+ "actions": null
+ },
+ {
+ "tag": "critical",
+ "stateRenderFunction": "element.attr({fill: ctx.properties.criticalColor});\nif (ctx.values.critical) {\n element.show();\n} else {\n element.hide();\n}\n\nvar elementCriticalAnimation = element.remember('criticalAnimation');\nvar criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\nif (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n}\n\n",
+ "actions": {
+ "click": {
+ "actionFunction": "ctx.api.callAction(event, 'criticalClick');"
+ }
+ }
+ },
+ {
+ "tag": "label",
+ "stateRenderFunction": "if (ctx.properties.label) {\n element.show();\n var label = ctx.values.initialState ? ctx.properties.onLabel : ctx.properties.offLabel;\n ctx.api.font(element, ctx.properties.labelFont, ctx.properties.labelColor);\n ctx.api.text(element, label);\n} else {\n element.hide();\n}",
+ "actions": null
+ },
+ {
+ "tag": "label-box",
+ "stateRenderFunction": "var color = ctx.properties.disabledColor;\nif (ctx.values.initialState) {\n color = ctx.properties.enabledColor;\n}\nelement.attr({fill: color});",
+ "actions": null
+ },
+ {
+ "tag": "warning",
+ "stateRenderFunction": "element.attr({fill: ctx.properties.warningColor});\nvar warning = ctx.values.warning && !(ctx.values.warning && ctx.values.critical)\nif (warning) {\n element.show();\n} else {\n element.hide();\n}\n\nvar elementCriticalAnimation = element.remember('criticalAnimation');\nvar criticalAnimation = warning && ctx.values.criticalAnimation;\n\nif (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n}\n",
+ "actions": {
+ "click": {
+ "actionFunction": "ctx.api.callAction(event, 'warningClick');"
+ }
+ }
+ }
+ ],
+ "behavior": [
+ {
+ "id": "initialState",
+ "name": "{i18n:scada.symbol.on-off-state}",
+ "hint": "{i18n:scada.symbol.on-off-state-hint}",
+ "group": null,
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": "{i18n:scada.symbol.on}",
+ "falseLabel": "{i18n:scada.symbol.off}",
+ "stateLabel": "",
+ "defaultGetValueSettings": {
+ "action": "GET_ATTRIBUTE",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": "SHARED_SCOPE",
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": null,
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "onUpdateState",
+ "name": "{i18n:scada.symbol.on-update-state}",
+ "hint": "{i18n:scada.symbol.on-update-state-hint}",
+ "group": null,
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "scope": "SERVER_SCOPE",
+ "key": "state"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": true,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "offUpdateState",
+ "name": "{i18n:scada.symbol.off-update-state}",
+ "hint": "{i18n:scada.symbol.off-update-state-hint}",
+ "group": null,
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "key": "state",
+ "scope": "SERVER_SCOPE"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": false,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "warning",
+ "name": "{i18n:scada.symbol.warning}",
+ "hint": "{i18n:scada.symbol.warning-state-hint}",
+ "group": "{i18n:scada.symbol.warning-state}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.warning}",
+ "defaultGetValueSettings": {
+ "action": "GET_ALARM_STATUS",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": null,
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": [
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "INDETERMINATE"
+ ],
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "warningClick",
+ "name": "{i18n:scada.symbol.warning-click}",
+ "hint": "{i18n:scada.symbol.on-click-hint}",
+ "group": "{i18n:scada.symbol.warning-state}",
+ "type": "widgetAction",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": {
+ "type": "doNothing",
+ "targetDashboardStateId": null,
+ "openRightLayout": false,
+ "setEntityId": false,
+ "stateEntityParamName": null
+ }
+ },
+ {
+ "id": "critical",
+ "name": "{i18n:scada.symbol.critical}",
+ "hint": "{i18n:scada.symbol.critical-state-hint}",
+ "group": "{i18n:scada.symbol.critical-state}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.critical}",
+ "defaultGetValueSettings": {
+ "action": "GET_ALARM_STATUS",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": null,
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": [
+ "CRITICAL"
+ ],
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "criticalClick",
+ "name": "{i18n:scada.symbol.critical-click}",
+ "hint": "{i18n:scada.symbol.on-click-hint}",
+ "group": "{i18n:scada.symbol.critical-state}",
+ "type": "widgetAction",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": {
+ "type": "doNothing",
+ "targetDashboardStateId": null,
+ "openRightLayout": false,
+ "setEntityId": false,
+ "stateEntityParamName": null
+ }
+ },
+ {
+ "id": "criticalAnimation",
+ "name": "{i18n:scada.symbol.warning-critical-state-animation}",
+ "hint": "{i18n:scada.symbol.warning-critical-state-animation-hint}",
+ "group": null,
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.animation}",
+ "defaultGetValueSettings": {
+ "action": "DO_NOTHING",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "key": "state",
+ "scope": null
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "compareToValue": true,
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;"
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ }
+ ],
+ "properties": [
+ {
+ "id": "label",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "switch",
+ "default": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "onLabel",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "text",
+ "default": "ON",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "offLabel",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "text",
+ "default": "OFF",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "labelFont",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "font",
+ "default": {
+ "size": 42,
+ "sizeUnit": "px",
+ "family": "Roboto",
+ "weight": "400",
+ "style": "normal"
+ },
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "labelColor",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "color",
+ "default": "#1A1A1A",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "backgroundColor",
+ "name": "{i18n:scada.symbol.background-color}",
+ "type": "color",
+ "default": "#FFFFFF",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "enabledColor",
+ "name": "{i18n:scada.symbol.colors}",
+ "type": "color",
+ "default": "#FFFFFF",
+ "subLabel": "{i18n:scada.symbol.enabled}",
+ "divider": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "disabledColor",
+ "name": "{i18n:scada.symbol.colors}",
+ "type": "color",
+ "default": "#666666",
+ "subLabel": "{i18n:scada.symbol.disabled}",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "warningColor",
+ "name": "{i18n:scada.symbol.alarm-colors}",
+ "type": "color",
+ "default": "#FAA405",
+ "subLabel": "{i18n:scada.symbol.warning}",
+ "divider": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "criticalColor",
+ "name": "{i18n:scada.symbol.alarm-colors}",
+ "type": "color",
+ "default": "#D12730",
+ "subLabel": "{i18n:scada.symbol.critical}",
+ "disabled": false,
+ "visible": true
+ }
+ ]
+}]]>
+
+
+
+ ON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/electrical-distribution-board-hp.svg b/application/src/main/data/json/system/scada_symbols/electrical-distribution-board-hp.svg
new file mode 100644
index 0000000000..0fcfe4dde0
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/electrical-distribution-board-hp.svg
@@ -0,0 +1,332 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/energy-meter-hp.svg b/application/src/main/data/json/system/scada_symbols/energy-meter-hp.svg
new file mode 100644
index 0000000000..606eb1153d
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/energy-meter-hp.svg
@@ -0,0 +1,482 @@
+
+000023 kWh T1
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/four-rate-energy-meter-hp.svg b/application/src/main/data/json/system/scada_symbols/four-rate-energy-meter-hp.svg
new file mode 100644
index 0000000000..de4fb13836
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/four-rate-energy-meter-hp.svg
@@ -0,0 +1,876 @@
+
+T1 T2 T3 Export 000223 000223 000223 000223 kWh
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/fuel-generator-hp.svg b/application/src/main/data/json/system/scada_symbols/fuel-generator-hp.svg
new file mode 100644
index 0000000000..52a3c70d6e
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/fuel-generator-hp.svg
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/high-voltage-tower-hp.svg b/application/src/main/data/json/system/scada_symbols/high-voltage-tower-hp.svg
new file mode 100644
index 0000000000..3aef3ff948
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/high-voltage-tower-hp.svg
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-curcuit-breaker-hp.svg b/application/src/main/data/json/system/scada_symbols/horizontal-curcuit-breaker-hp.svg
new file mode 100644
index 0000000000..17fd1ba69e
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/horizontal-curcuit-breaker-hp.svg
@@ -0,0 +1,439 @@
+ {\n ctx.api.setValue('initialState', !initial);\n }\n});"
+ }
+ }
+ },
+ {
+ "tag": "breaker-trigger",
+ "stateRenderFunction": "element.fill(ctx.properties.disabledColor);\nif (ctx.values.initialState) {\n element.transform({translateX: 0});\n} else {\n element.transform({translateX: -160});\n}",
+ "actions": null
+ },
+ {
+ "tag": "critical",
+ "stateRenderFunction": "element.attr({fill: ctx.properties.criticalColor});\nif (ctx.values.critical) {\n element.show();\n} else {\n element.hide();\n}\n\nvar elementCriticalAnimation = element.remember('criticalAnimation');\nvar criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\nif (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n}\n\n",
+ "actions": {
+ "click": {
+ "actionFunction": "ctx.api.callAction(event, 'criticalClick');"
+ }
+ }
+ },
+ {
+ "tag": "label",
+ "stateRenderFunction": "if (ctx.properties.label) {\n element.show();\n var label = ctx.values.initialState ? ctx.properties.onLabel : ctx.properties.offLabel;\n ctx.api.font(element, ctx.properties.labelFont, ctx.properties.labelColor);\n ctx.api.text(element, label);\n} else {\n element.hide();\n}",
+ "actions": null
+ },
+ {
+ "tag": "label-box",
+ "stateRenderFunction": "var color = ctx.properties.disabledColor;\nif (ctx.values.initialState) {\n color = ctx.properties.enabledColor;\n}\nelement.attr({fill: color});",
+ "actions": null
+ },
+ {
+ "tag": "warning",
+ "stateRenderFunction": "element.attr({fill: ctx.properties.warningColor});\nvar warning = ctx.values.warning && !(ctx.values.warning && ctx.values.critical)\nif (warning) {\n element.show();\n} else {\n element.hide();\n}\n\nvar elementCriticalAnimation = element.remember('criticalAnimation');\nvar criticalAnimation = warning && ctx.values.criticalAnimation;\n\nif (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n}\n",
+ "actions": {
+ "click": {
+ "actionFunction": "ctx.api.callAction(event, 'warningClick');"
+ }
+ }
+ }
+ ],
+ "behavior": [
+ {
+ "id": "initialState",
+ "name": "{i18n:scada.symbol.on-off-state}",
+ "hint": "{i18n:scada.symbol.on-off-state-hint}",
+ "group": null,
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": "{i18n:scada.symbol.on}",
+ "falseLabel": "{i18n:scada.symbol.off}",
+ "stateLabel": "",
+ "defaultGetValueSettings": {
+ "action": "GET_ATTRIBUTE",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": "SHARED_SCOPE",
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": null,
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "onUpdateState",
+ "name": "{i18n:scada.symbol.on-update-state}",
+ "hint": "{i18n:scada.symbol.on-update-state-hint}",
+ "group": null,
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "scope": "SERVER_SCOPE",
+ "key": "state"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": true,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "offUpdateState",
+ "name": "{i18n:scada.symbol.off-update-state}",
+ "hint": "{i18n:scada.symbol.off-update-state-hint}",
+ "group": null,
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "key": "state",
+ "scope": "SERVER_SCOPE"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": false,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "warning",
+ "name": "{i18n:scada.symbol.warning}",
+ "hint": "{i18n:scada.symbol.warning-state-hint}",
+ "group": "{i18n:scada.symbol.warning-state}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.warning}",
+ "defaultGetValueSettings": {
+ "action": "GET_ALARM_STATUS",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": null,
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": [
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "INDETERMINATE"
+ ],
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "warningClick",
+ "name": "{i18n:scada.symbol.warning-click}",
+ "hint": "{i18n:scada.symbol.on-click-hint}",
+ "group": "{i18n:scada.symbol.warning-state}",
+ "type": "widgetAction",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": {
+ "type": "doNothing",
+ "targetDashboardStateId": null,
+ "openRightLayout": false,
+ "setEntityId": false,
+ "stateEntityParamName": null
+ }
+ },
+ {
+ "id": "critical",
+ "name": "{i18n:scada.symbol.critical}",
+ "hint": "{i18n:scada.symbol.critical-state-hint}",
+ "group": "{i18n:scada.symbol.critical-state}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.critical}",
+ "defaultGetValueSettings": {
+ "action": "GET_ALARM_STATUS",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": null,
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": [
+ "CRITICAL"
+ ],
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "criticalClick",
+ "name": "{i18n:scada.symbol.critical-click}",
+ "hint": "{i18n:scada.symbol.on-click-hint}",
+ "group": "{i18n:scada.symbol.critical-state}",
+ "type": "widgetAction",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": {
+ "type": "doNothing",
+ "targetDashboardStateId": null,
+ "openRightLayout": false,
+ "setEntityId": false,
+ "stateEntityParamName": null
+ }
+ },
+ {
+ "id": "criticalAnimation",
+ "name": "{i18n:scada.symbol.warning-critical-state-animation}",
+ "hint": "{i18n:scada.symbol.warning-critical-state-animation-hint}",
+ "group": null,
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.animation}",
+ "defaultGetValueSettings": {
+ "action": "DO_NOTHING",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "key": "state",
+ "scope": null
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "compareToValue": true,
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;"
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ }
+ ],
+ "properties": [
+ {
+ "id": "label",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "switch",
+ "default": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "onLabel",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "text",
+ "default": "ON",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "offLabel",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "text",
+ "default": "OFF",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "labelFont",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "font",
+ "default": {
+ "size": 42,
+ "sizeUnit": "px",
+ "family": "Roboto",
+ "weight": "400",
+ "style": "normal"
+ },
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "labelColor",
+ "name": "{i18n:scada.symbol.label}",
+ "type": "color",
+ "default": "#1A1A1A",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "backgroundColor",
+ "name": "{i18n:scada.symbol.background-color}",
+ "type": "color",
+ "default": "#FFFFFF",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "enabledColor",
+ "name": "{i18n:scada.symbol.colors}",
+ "type": "color",
+ "default": "#FFFFFF",
+ "subLabel": "{i18n:scada.symbol.enabled}",
+ "divider": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "disabledColor",
+ "name": "{i18n:scada.symbol.colors}",
+ "type": "color",
+ "default": "#666666",
+ "subLabel": "{i18n:scada.symbol.disabled}",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "warningColor",
+ "name": "{i18n:scada.symbol.alarm-colors}",
+ "type": "color",
+ "default": "#FAA405",
+ "subLabel": "{i18n:scada.symbol.warning}",
+ "divider": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "criticalColor",
+ "name": "{i18n:scada.symbol.alarm-colors}",
+ "type": "color",
+ "default": "#D12730",
+ "subLabel": "{i18n:scada.symbol.critical}",
+ "disabled": false,
+ "visible": true
+ }
+ ]
+}]]>
+
+
+ ON
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-energy-system-controller-hp.svg b/application/src/main/data/json/system/scada_symbols/horizontal-energy-system-controller-hp.svg
new file mode 100644
index 0000000000..13ee85821b
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/horizontal-energy-system-controller-hp.svg
@@ -0,0 +1,378 @@
+
+Connected
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/house-hp.svg b/application/src/main/data/json/system/scada_symbols/house-hp.svg
new file mode 100644
index 0000000000..d95c47bb8b
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/house-hp.svg
@@ -0,0 +1,349 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/industrial-fuel-generator-hp.svg b/application/src/main/data/json/system/scada_symbols/industrial-fuel-generator-hp.svg
new file mode 100644
index 0000000000..2b7a476a92
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/industrial-fuel-generator-hp.svg
@@ -0,0 +1,358 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/inverter-hp.svg b/application/src/main/data/json/system/scada_symbols/inverter-hp.svg
new file mode 100644
index 0000000000..73f14c8e75
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/inverter-hp.svg
@@ -0,0 +1,578 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/large-inverter-hp.svg b/application/src/main/data/json/system/scada_symbols/large-inverter-hp.svg
new file mode 100644
index 0000000000..11bc5da0a6
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/large-inverter-hp.svg
@@ -0,0 +1,578 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/low-voltage-tower-hp.svg b/application/src/main/data/json/system/scada_symbols/low-voltage-tower-hp.svg
new file mode 100644
index 0000000000..812e616433
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/low-voltage-tower-hp.svg
@@ -0,0 +1,278 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/low-voltage-transformer-tower-hp.svg b/application/src/main/data/json/system/scada_symbols/low-voltage-transformer-tower-hp.svg
new file mode 100644
index 0000000000..2985dc600c
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/low-voltage-transformer-tower-hp.svg
@@ -0,0 +1,334 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/manufacture-hp.svg b/application/src/main/data/json/system/scada_symbols/manufacture-hp.svg
new file mode 100644
index 0000000000..5b35f2eaf2
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/manufacture-hp.svg
@@ -0,0 +1,344 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/power-socket-hp.svg b/application/src/main/data/json/system/scada_symbols/power-socket-hp.svg
new file mode 100644
index 0000000000..5524b3bb14
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/power-socket-hp.svg
@@ -0,0 +1,371 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/power-transformer-hp.svg b/application/src/main/data/json/system/scada_symbols/power-transformer-hp.svg
new file mode 100644
index 0000000000..67e75be827
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/power-transformer-hp.svg
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/single-key-switch-hp.svg b/application/src/main/data/json/system/scada_symbols/single-key-switch-hp.svg
new file mode 100644
index 0000000000..77d6e7f95d
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/single-key-switch-hp.svg
@@ -0,0 +1,373 @@
+ {\n ctx.api.setValue('initialState', !initial);\n }\n});"
+ }
+ }
+ },
+ {
+ "tag": "critical",
+ "stateRenderFunction": "element.attr({fill: ctx.properties.criticalColor});\nif (ctx.values.critical) {\n element.show();\n} else {\n element.hide();\n}\n\nvar elementCriticalAnimation = element.remember('criticalAnimation');\nvar criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\nif (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n}\n\n",
+ "actions": {
+ "click": {
+ "actionFunction": "ctx.api.callAction(event, 'criticalClick');"
+ }
+ }
+ },
+ {
+ "tag": "warning",
+ "stateRenderFunction": "element.attr({fill: ctx.properties.warningColor});\nvar warning = ctx.values.warning && !(ctx.values.warning && ctx.values.critical)\nif (warning) {\n element.show();\n} else {\n element.hide();\n}\n\nvar elementCriticalAnimation = element.remember('criticalAnimation');\nvar criticalAnimation = warning && ctx.values.criticalAnimation;\n\nif (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n}\n",
+ "actions": {
+ "click": {
+ "actionFunction": "ctx.api.callAction(event, 'warningClick');"
+ }
+ }
+ }
+ ],
+ "behavior": [
+ {
+ "id": "initialState",
+ "name": "{i18n:scada.symbol.on-off-state}",
+ "hint": "{i18n:scada.symbol.on-off-state-hint}",
+ "group": null,
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": "{i18n:scada.symbol.on}",
+ "falseLabel": "{i18n:scada.symbol.off}",
+ "stateLabel": "",
+ "defaultGetValueSettings": {
+ "action": "GET_ATTRIBUTE",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": "SHARED_SCOPE",
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": null,
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "onUpdateState",
+ "name": "{i18n:scada.symbol.on-update-state}",
+ "hint": "{i18n:scada.symbol.on-update-state-hint}",
+ "group": null,
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "scope": "SERVER_SCOPE",
+ "key": "state"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": true,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "offUpdateState",
+ "name": "{i18n:scada.symbol.off-update-state}",
+ "hint": "{i18n:scada.symbol.off-update-state-hint}",
+ "group": null,
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "key": "state",
+ "scope": "SERVER_SCOPE"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": false,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "warning",
+ "name": "{i18n:scada.symbol.warning}",
+ "hint": "{i18n:scada.symbol.warning-state-hint}",
+ "group": "{i18n:scada.symbol.warning-state}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.warning}",
+ "defaultGetValueSettings": {
+ "action": "GET_ALARM_STATUS",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": null,
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": [
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "INDETERMINATE"
+ ],
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "warningClick",
+ "name": "{i18n:scada.symbol.warning-click}",
+ "hint": "{i18n:scada.symbol.on-click-hint}",
+ "group": "{i18n:scada.symbol.warning-state}",
+ "type": "widgetAction",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": {
+ "type": "doNothing",
+ "targetDashboardStateId": null,
+ "openRightLayout": false,
+ "setEntityId": false,
+ "stateEntityParamName": null
+ }
+ },
+ {
+ "id": "critical",
+ "name": "{i18n:scada.symbol.critical}",
+ "hint": "{i18n:scada.symbol.critical-state-hint}",
+ "group": "{i18n:scada.symbol.critical-state}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.critical}",
+ "defaultGetValueSettings": {
+ "action": "GET_ALARM_STATUS",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": null,
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": [
+ "CRITICAL"
+ ],
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "criticalClick",
+ "name": "{i18n:scada.symbol.critical-click}",
+ "hint": "{i18n:scada.symbol.on-click-hint}",
+ "group": "{i18n:scada.symbol.critical-state}",
+ "type": "widgetAction",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": {
+ "type": "doNothing",
+ "targetDashboardStateId": null,
+ "openRightLayout": false,
+ "setEntityId": false,
+ "stateEntityParamName": null
+ }
+ },
+ {
+ "id": "criticalAnimation",
+ "name": "{i18n:scada.symbol.warning-critical-state-animation}",
+ "hint": "{i18n:scada.symbol.warning-critical-state-animation-hint}",
+ "group": null,
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.animation}",
+ "defaultGetValueSettings": {
+ "action": "DO_NOTHING",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "key": "state",
+ "scope": null
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "compareToValue": true,
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;"
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ }
+ ],
+ "properties": [
+ {
+ "id": "backgroundColor",
+ "name": "{i18n:scada.symbol.background-color}",
+ "type": "color",
+ "default": "#FFFFFF",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "enabledColor",
+ "name": "{i18n:scada.symbol.colors}",
+ "type": "color",
+ "default": "#FFFFFF",
+ "subLabel": "{i18n:scada.symbol.enabled}",
+ "divider": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "disabledColor",
+ "name": "{i18n:scada.symbol.colors}",
+ "type": "color",
+ "default": "#666666",
+ "subLabel": "{i18n:scada.symbol.disabled}",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "warningColor",
+ "name": "{i18n:scada.symbol.alarm-colors}",
+ "type": "color",
+ "default": "#FAA405",
+ "subLabel": "{i18n:scada.symbol.warning}",
+ "divider": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "criticalColor",
+ "name": "{i18n:scada.symbol.alarm-colors}",
+ "type": "color",
+ "default": "#D12730",
+ "subLabel": "{i18n:scada.symbol.critical}",
+ "disabled": false,
+ "visible": true
+ }
+ ]
+}]]>
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/small-power-transformer-hp.svg b/application/src/main/data/json/system/scada_symbols/small-power-transformer-hp.svg
new file mode 100644
index 0000000000..049c75ab58
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/small-power-transformer-hp.svg
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/solar-panel-hp.svg b/application/src/main/data/json/system/scada_symbols/solar-panel-hp.svg
new file mode 100644
index 0000000000..b7b7724f89
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/solar-panel-hp.svg
@@ -0,0 +1,353 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/stand-solar-panel-hp.svg b/application/src/main/data/json/system/scada_symbols/stand-solar-panel-hp.svg
new file mode 100644
index 0000000000..93e622a021
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/stand-solar-panel-hp.svg
@@ -0,0 +1,357 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/three-rate-energy-meter-hp.svg b/application/src/main/data/json/system/scada_symbols/three-rate-energy-meter-hp.svg
new file mode 100644
index 0000000000..f2b7bf4d54
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/three-rate-energy-meter-hp.svg
@@ -0,0 +1,747 @@
+
+T1 T2 T3 000223 000223 000223 kWh
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/top-light-bulb-hp.svg b/application/src/main/data/json/system/scada_symbols/top-light-bulb-hp.svg
new file mode 100644
index 0000000000..ed6855884a
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/top-light-bulb-hp.svg
@@ -0,0 +1,346 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/two-key-switch-hp.svg b/application/src/main/data/json/system/scada_symbols/two-key-switch-hp.svg
new file mode 100644
index 0000000000..40e04a3bf5
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/two-key-switch-hp.svg
@@ -0,0 +1,489 @@
+ {\n ctx.api.setValue('initialStateLeftButton', !initial);\n }\n});"
+ }
+ }
+ },
+ {
+ "tag": "right-button",
+ "stateRenderFunction": "var color = ctx.properties.disabledColor;\nif (ctx.values.initialStateRightButton) {\n color = ctx.properties.enabledColor;\n}\nelement.attr({fill: color});",
+ "actions": {
+ "click": {
+ "actionFunction": "var initial = ctx.values.initialStateRightButton;\nvar action = initial ? 'offUpdateStateRightButton' : 'onUpdateStateRightButton';\n\nctx.api.callAction(event, action, undefined, {\n next: () => {\n ctx.api.setValue('initialStateRightButton', !initial);\n }\n});"
+ }
+ }
+ },
+ {
+ "tag": "warning",
+ "stateRenderFunction": "element.attr({fill: ctx.properties.warningColor});\nvar warning = ctx.values.warning && !(ctx.values.warning && ctx.values.critical)\nif (warning) {\n element.show();\n} else {\n element.hide();\n}\n\nvar elementCriticalAnimation = element.remember('criticalAnimation');\nvar criticalAnimation = warning && ctx.values.criticalAnimation;\n\nif (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n}\n",
+ "actions": {
+ "click": {
+ "actionFunction": "ctx.api.callAction(event, 'warningClick');"
+ }
+ }
+ }
+ ],
+ "behavior": [
+ {
+ "id": "initialStateLeftButton",
+ "name": "{i18n:scada.symbol.on-off-state}",
+ "hint": "{i18n:scada.symbol.on-off-state-hint}",
+ "group": "{i18n:scada.symbol.left-button}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": "{i18n:scada.symbol.on}",
+ "falseLabel": "{i18n:scada.symbol.off}",
+ "stateLabel": "",
+ "defaultGetValueSettings": {
+ "action": "GET_ATTRIBUTE",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": "SHARED_SCOPE",
+ "key": "leftButton"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": null,
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "onUpdateStateLeftButton",
+ "name": "{i18n:scada.symbol.on-update-state}",
+ "hint": "{i18n:scada.symbol.on-update-state-hint}",
+ "group": "{i18n:scada.symbol.left-button}",
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "scope": "SERVER_SCOPE",
+ "key": "state"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": true,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "offUpdateStateLeftButton",
+ "name": "{i18n:scada.symbol.off-update-state}",
+ "hint": "{i18n:scada.symbol.off-update-state-hint}",
+ "group": "{i18n:scada.symbol.left-button}",
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "key": "state",
+ "scope": "SERVER_SCOPE"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": false,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "initialStateRightButton",
+ "name": "{i18n:scada.symbol.on-off-state}",
+ "hint": "{i18n:scada.symbol.on-off-state-hint}",
+ "group": "{i18n:scada.symbol.right-button}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": "{i18n:scada.symbol.on}",
+ "falseLabel": "{i18n:scada.symbol.off}",
+ "stateLabel": null,
+ "defaultGetValueSettings": {
+ "action": "GET_ATTRIBUTE",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": "SHARED_SCOPE",
+ "key": "rightButton"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": null,
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "onUpdateStateRightButton",
+ "name": "{i18n:scada.symbol.on-update-state}",
+ "hint": "{i18n:scada.symbol.on-update-state-hint}",
+ "group": "{i18n:scada.symbol.right-button}",
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "scope": "SERVER_SCOPE",
+ "key": "state"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": true,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "offUpdateStateRightButton",
+ "name": "{i18n:scada.symbol.off-update-state}",
+ "hint": "{i18n:scada.symbol.off-update-state-hint}",
+ "group": "{i18n:scada.symbol.right-button}",
+ "type": "action",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": {
+ "action": "EXECUTE_RPC",
+ "executeRpc": {
+ "method": "setState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "setAttribute": {
+ "key": "state",
+ "scope": "SERVER_SCOPE"
+ },
+ "putTimeSeries": {
+ "key": "state"
+ },
+ "valueToData": {
+ "type": "CONSTANT",
+ "constantValue": false,
+ "valueToDataFunction": "/* Convert input boolean value to RPC parameters or attribute/time-series value */\nreturn value;"
+ }
+ },
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "warning",
+ "name": "{i18n:scada.symbol.warning}",
+ "hint": "{i18n:scada.symbol.warning-state-hint}",
+ "group": "{i18n:scada.symbol.warning-state}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.warning}",
+ "defaultGetValueSettings": {
+ "action": "GET_ALARM_STATUS",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": null,
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": [
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "INDETERMINATE"
+ ],
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "warningClick",
+ "name": "{i18n:scada.symbol.warning-click}",
+ "hint": "{i18n:scada.symbol.on-click-hint}",
+ "group": "{i18n:scada.symbol.warning-state}",
+ "type": "widgetAction",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": {
+ "type": "doNothing",
+ "targetDashboardStateId": null,
+ "openRightLayout": false,
+ "setEntityId": false,
+ "stateEntityParamName": null
+ }
+ },
+ {
+ "id": "critical",
+ "name": "{i18n:scada.symbol.critical}",
+ "hint": "{i18n:scada.symbol.critical-state-hint}",
+ "group": "{i18n:scada.symbol.critical-state}",
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.critical}",
+ "defaultGetValueSettings": {
+ "action": "GET_ALARM_STATUS",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "scope": null,
+ "key": "state"
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "getAlarmStatus": {
+ "severityList": [
+ "CRITICAL"
+ ],
+ "typeList": null
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;",
+ "compareToValue": true
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ },
+ {
+ "id": "criticalClick",
+ "name": "{i18n:scada.symbol.critical-click}",
+ "hint": "{i18n:scada.symbol.on-click-hint}",
+ "group": "{i18n:scada.symbol.critical-state}",
+ "type": "widgetAction",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": null,
+ "defaultGetValueSettings": null,
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": {
+ "type": "doNothing",
+ "targetDashboardStateId": null,
+ "openRightLayout": false,
+ "setEntityId": false,
+ "stateEntityParamName": null
+ }
+ },
+ {
+ "id": "criticalAnimation",
+ "name": "{i18n:scada.symbol.warning-critical-state-animation}",
+ "hint": "{i18n:scada.symbol.warning-critical-state-animation-hint}",
+ "group": null,
+ "type": "value",
+ "valueType": "BOOLEAN",
+ "trueLabel": null,
+ "falseLabel": null,
+ "stateLabel": "{i18n:scada.symbol.animation}",
+ "defaultGetValueSettings": {
+ "action": "DO_NOTHING",
+ "defaultValue": false,
+ "executeRpc": {
+ "method": "getState",
+ "requestTimeout": 5000,
+ "requestPersistent": false,
+ "persistentPollingInterval": 1000
+ },
+ "getAttribute": {
+ "key": "state",
+ "scope": null
+ },
+ "getTimeSeries": {
+ "key": "state"
+ },
+ "dataToValue": {
+ "type": "NONE",
+ "compareToValue": true,
+ "dataToValueFunction": "/* Should return boolean value */\nreturn data;"
+ }
+ },
+ "defaultSetValueSettings": null,
+ "defaultWidgetActionSettings": null
+ }
+ ],
+ "properties": [
+ {
+ "id": "backgroundColor",
+ "name": "{i18n:scada.symbol.background-color}",
+ "type": "color",
+ "default": "#FFFFFF",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "enabledColor",
+ "name": "{i18n:scada.symbol.colors}",
+ "type": "color",
+ "default": "#FFFFFF",
+ "subLabel": "{i18n:scada.symbol.enabled}",
+ "divider": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "disabledColor",
+ "name": "{i18n:scada.symbol.colors}",
+ "type": "color",
+ "default": "#666666",
+ "subLabel": "{i18n:scada.symbol.disabled}",
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "warningColor",
+ "name": "{i18n:scada.symbol.alarm-colors}",
+ "type": "color",
+ "default": "#FAA405",
+ "subLabel": "{i18n:scada.symbol.warning}",
+ "divider": true,
+ "disabled": false,
+ "visible": true
+ },
+ {
+ "id": "criticalColor",
+ "name": "{i18n:scada.symbol.alarm-colors}",
+ "type": "color",
+ "default": "#D12730",
+ "subLabel": "{i18n:scada.symbol.critical}",
+ "disabled": false,
+ "visible": true
+ }
+ ]
+}]]>
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/two-rate-energy-meter-hp.svg b/application/src/main/data/json/system/scada_symbols/two-rate-energy-meter-hp.svg
new file mode 100644
index 0000000000..7adc401836
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/two-rate-energy-meter-hp.svg
@@ -0,0 +1,618 @@
+
+T1 T2 000023 000023 kWh
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/vertical-energy-system-controller-hp.svg b/application/src/main/data/json/system/scada_symbols/vertical-energy-system-controller-hp.svg
new file mode 100644
index 0000000000..cebe949c36
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/vertical-energy-system-controller-hp.svg
@@ -0,0 +1,378 @@
+
+Connected
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/voltage-relay-hp.svg b/application/src/main/data/json/system/scada_symbols/voltage-relay-hp.svg
new file mode 100644
index 0000000000..eaa0b02455
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/voltage-relay-hp.svg
@@ -0,0 +1,439 @@
+
+220 v
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/voltage-stabilizer-hp.svg b/application/src/main/data/json/system/scada_symbols/voltage-stabilizer-hp.svg
new file mode 100644
index 0000000000..aafc2af5a0
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/voltage-stabilizer-hp.svg
@@ -0,0 +1,584 @@
+
+220 230 in out
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/wind-turbine-cluster-hp.svg b/application/src/main/data/json/system/scada_symbols/wind-turbine-cluster-hp.svg
new file mode 100644
index 0000000000..74855dd35a
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/wind-turbine-cluster-hp.svg
@@ -0,0 +1,370 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/wind-turbine-hp.svg b/application/src/main/data/json/system/scada_symbols/wind-turbine-hp.svg
new file mode 100644
index 0000000000..a4282c16e7
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/wind-turbine-hp.svg
@@ -0,0 +1,360 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/widget_bundles/general_high_performance_scada_symbols.json b/application/src/main/data/json/system/widget_bundles/general_high_performance_scada_symbols.json
index 5083384432..33efaacc0c 100644
--- a/application/src/main/data/json/system/widget_bundles/general_high_performance_scada_symbols.json
+++ b/application/src/main/data/json/system/widget_bundles/general_high_performance_scada_symbols.json
@@ -28,6 +28,10 @@
"hp_left_tee_connector",
"hp_top_tee_connector",
"hp_drawwork",
- "hp_crane"
+ "hp_crane",
+ "hp_consumers",
+ "hp_house",
+ "hp_apartments",
+ "hp_manufacture"
]
}
\ No newline at end of file
diff --git a/application/src/main/data/json/system/widget_bundles/high_performance_scada_energy_system.json b/application/src/main/data/json/system/widget_bundles/high_performance_scada_energy_system.json
new file mode 100644
index 0000000000..a06ccc0819
--- /dev/null
+++ b/application/src/main/data/json/system/widget_bundles/high_performance_scada_energy_system.json
@@ -0,0 +1,48 @@
+{
+ "widgetsBundle": {
+ "alias": "high_performance_scada_energy_system",
+ "title": "High-performance SCADA energy system",
+ "image": "tb-image:aHBfc2NhZGFfZW5lcmd5X3N5c3RlbV9idW5kbGVfaW1hZ2UucG5n:IkhpZ2gtcGVyZm9ybWFuY2UgU0NBREEgZW5lcmd5IHN5c3RlbSIgc3lzdGVtIGJ1bmRsZSBpbWFnZQ==:SU1BR0U=;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAllBMVEXe3t7b29vf398AAADf39/e3t7e3t7////Gxsbj4+OpqanFxcW5ubmtra2xsbGVlZWlpaWhoaHS0tLx8fG2trbU1NTBwcGvr6+MjIybm5twcHC+vr6jo6OYmJizs7Orq6vExMSZmZnCwsKdnZ2ampqRkZE3Nze7u7t+fn6EhIRjY2NVVVVsbGx5eXmJiYlEREQvLy8aGhprAy3xAAAABnRSTlPvIK8Av79l/pT7AAAJyElEQVR42uzVXW/aMBiGYWin57VjmyRmNGFLKOWjQACt/P8/t7yJQVMPrE62KkBcR88ZuokTD56HPwa4dU/D58Hw9jNabcYT7sIdHKve4F5C8Ai5No+Qa/MIuTaPkGvzCLk2QSHKIB6rFAIEhayniCc9fVx2c2ou++OUwi88ZGEtYrHbfZOf9/59r9w2f963Fj7hIUaOK0SSWyKSS8s7461rsOmk3TMNj/CQKVGBOJSiTsJNkpjcACjHxOYWHsEhCyJhEYWW1FkDeKNeDcD0c2LgERpi+McrxFFqIYQeaQCqnshWrQAUL7zFGh7BIVNq5YjDJm1Jnfd7lySrnQLT23aX8AgPWbjTG0VFTHKJyohlXLKZ8xy/wiMwxB3rsUEwd0yZ+ecdyQCs+yk1PAJDMuokiMFmxMZl/9W6PJ2EOlrBIzAkp84IUahym6yOG7D0WCarXQE2Oq6Scm3gERoyJxbrA5wJfiCV4l3zljVPu5R8IW7gERZy+fKPC0SgJu4e+XS0Ss+/FSkkI2eKQJ8vxOx7L8RXcjaI4W3GF2KhAKhU8CXYbTHjrZfwCAz5Tc4LohA/pVy7nbZRqds7IVYaHqEhc3ImFgGKkZM1TVO6XR4Oh9rtX+2uRo4BYodYQY7UCCDofwggdoiRdJYDuOEQYuFXYjEqk68qqwKIHZJHCoGQ9FVSgcUNSe8lxNBFBXarIVrSmQG71ZC/1Jpdc6sgEIbv3AXRIB9VE2OStmN6mpnT8/9/3RlSbGTxzmFC9yYTfV14wrIsRLQk/f4ikHDhM+ANVSD6BSB/VLg39SbDJKCyBxFst1o0tkEOsEP2ID20q/nXEFH2IK+Aai1tVVSUOYgrrnYrsx0VEQ2Zg3A6HVq/rlNRkzlI7U/jouMgutsyKmuQEulpHMYHdKW9X8kapIl//hHcIK2Isgbp4zWDRznr9C3KGuQAzkSQorSf60R0zhnEb9G1WF77K7AvYxETm0HYJ0sEUuko2V6lu/Zax6JhM8j+a58IZIjqkav13uuoaum3gtgJJkwDYqJ6ZARvZ0VFm0Nr4oC3NCBv3teBhJGzHS2I240g3MXVjScBEXTzcVm0S0WHbSBsYsAY+6fTgJDJLtOBdB2wzn0kD62yMYdew2z94dSIbaFFB2T/9Ql6YglA5kh6UxUf7X0cwNu9J/b1VCk5izaB7J1nt470t2TpVwup5pGwc/q1P0Q73ymzBYRPrqF7KzdMMEcYAHK79CpHDaDNUcHDEHFraE0ffLaPKUGJYizqwGldnAQKcyyuNrjO0YotIN3+YX2CEbno0OelKCofRgMLb/WiyLZolBYijqKZy5GakbudyhOkbHXM4Yt2UayQgCxzBMER1jiK2oOskZzb/EDqgvqTi7Kx8SJLRcfcQI60oWLwd16W5Qi+RCR5gYQcwYuSPKgiSxkNXE4glEO3D2cYvi6gBNXKfEAoB17oDv1loZaGkuQCQji0sG/0Pyu+BGFIHjjmASKDNrTr+VmRHmB4GoSchTM+B5CWLSisQOKrYvQwnvtiSy9n/PNBSvUYC/7hO4enWswgofNyd+Je33Hxw2KvzwYpR991I6wG9L44ADNVXYYgqhGSwY8I70/5b+fyuSBKAjDRCaPBmX4HZ8a3ik1dDt/OK7VrEVZEWvB3YQFG9VQQ+b+9c1tuGwTCcI+wIJCEhK26suW2aafpRfv+j9ehIgtZuQk20QRn8t9kRP7Y+5nDamUUDfbzr1AzWT2oDTQ65G+YQfiPYPqmBxD3TU0jh9tnHlo74CgGzHLRH5gKqUJ6xGBSTM6mLxwl1NMNrc1FPdLxexzsZq6iFONegCDBdJxPWgBNzvDgwrVnG5GqDavPBemkIBxM+ewHd4Rq/lEtTYREHLvn2njmJnJQB/Nq64sPtcWhFf34AswXjcd/JkvqrGcAoSey3xR+iauiX4sdjrBwTjwG00RIngGk2vJIdcUwRuMNNecCZDTC9pFJn/w0/kfSwjlqk0Eoh5Cdb67ji7o7AA4IEkwu+AFNgpCsKQpCxsQ0YLvDq9FkcdUCrtoKTTEtM1MGSS4Ijoj5KiJDWceFpmiyyz4Eacm2pzrq3WlVEgrSIQeM97deWayiPGzlffFkBm8Kqs3msRm/AgherIaBvOsco41NNk6I+46aUFVtgKNpJVGQnYOo5bB8xw5wZZWzyUfXyhF6nz0ATm986IysnWnHVhIF+dMcW92xpXxhC7EJws0KejoOf5xJeNMJdXq6GRqWqfydDyDIWRvAcgOdciZYcyrkg2hBzqMdmZOKTb0zFQ5CN2doDwJdbLoSkF5HDf2ySDBzzchWUz6IX3JjECzbqKlskNpvckA1WAJSk2HrKR/kK90c5IKmw61N3BxUGQVBzdmTSis4XApiKUjLvczS9JgU+X4rHQE/RMgDORAQMtwkmlJeDCVU6HhtHtbXLhPkBrNfFAztgGPiBwycT7XXPl7nJH9UQw4IjgZJyHzcxJQCgn+lRQQCKRe38kA0TePqBIjhTscUkPoUCKSA6DyQAUEiMjrcRm9KAWmn7SwAsFsvmSA7HjJAfIyGkDntqEmngPzu+cXqf2eA1HRL2ci9FF3JhhQQyTMkM0C2y4TopalpLBrEcqeJBO00UFN7BSBb0kA6AGZT0SDw34TYLkwlg3RAJzbQ/zCAaUCWDOJvBAVCFncAVr9QNIjAcjAiIx2gPEhVMIgWpBxUgl7qx+pXFA1CT7h1jyBVMF0NSK/jBhq38Q26YJA9TeMmAqGmkkFqWg7uA4imJlMwyFdaDtYcpWn1uy8YxD5w20WzMF0ByCFuoHFLNKWCbCRKcREdrAZyQ9O4XILg/SNtMogA1Ib30cFqIIqm8SNHHRamgoeWpuWg4ihLl+RjwSADBTEcJWn1q9LnyGfUrTtArQWCMZq4gcY9XlFCHEMDStEleSgYZEtXqImjDDWNySC9QPXxgVg9j0xx0DRue/byC59Qkm8+Ba0Oso3zCI0b7kwFDy2gSy1w1LQwlQuCFbqKG0gHAKyYEDfKKlB9Jkio0CEOmsQNAk1PDvJ9RpAiF0TgjtWogcStEKR6ahDZI1AeiBakHNQxSEfKeJEAouQZ+o7939+6Y3U5CP26T5N9xdiWBGL5eUKOsDtXZYL0OjTQuA0tfk8LnelC8DAk9WUge1rXNjGIWpoeVqXhLH2KmMBJmeoCkP1u90Pe6dfOCRtCGzG17FE1QogmeYrSpf0CkJZfoG0CCNb7yVUE/1JdN0jV4s3nhYIYlkiigHMx/mQ5IKa5QIYlvTBLVqUbxU7p9Rk9heoVpDS9gpSmV5DS9ApSml7Mg3XffGAvQu9ezkO037+9/sdov/n49v1fKIFpFaO3gooAAAAASUVORK5CYII=",
+ "scada": true,
+ "description": "Bundle with high-performance SCADA symbols for energy system",
+ "order": 9410,
+ "name": "High-performance SCADA energy system"
+ },
+ "widgetTypeFqns": [
+ "hp_solar_panel",
+ "hp_stand_solar_panel",
+ "hp_wind_turbine",
+ "hp_wind_turbine_cluster",
+ "hp_fuel_generator",
+ "hp_industrial_fuel_generator",
+ "hp_circuit_breaker2",
+ "hp_horizontal_circuit_breaker",
+ "hp_voltage_relay",
+ "hp_3_phase_voltage_relay",
+ "hp_voltage_stabilizer",
+ "hp_energy_meter",
+ "hp_two_rate_energy_meter",
+ "hp_three_rate_energy_meter",
+ "hp_four_rate_energy_meter",
+ "hp_electrical_distribution_board",
+ "hp_power_socket",
+ "hp_single_key_switch",
+ "hp_two_key_switch",
+ "hp_top_light_bulb",
+ "hp_bottom_light_bulb",
+ "hp_battery",
+ "hp_inverter",
+ "hp_large_inverter",
+ "hp_horizontal_energy_systems_controller",
+ "hp_vertical_energy_systems_controller",
+ "hp_small_power_transformer",
+ "hp_power_transformer",
+ "hp_low_voltage_transformer_tower",
+ "hp_low_voltage_tower",
+ "hp_high_voltage_tower",
+ "hp_consumers",
+ "hp_house",
+ "hp_apartments",
+ "hp_manufacture"
+ ]
+}
\ No newline at end of file
diff --git a/application/src/main/data/json/system/widget_types/update_device_attribute.json b/application/src/main/data/json/system/widget_types/update_device_attribute.json
index 92111daf54..763ba93bc9 100644
--- a/application/src/main/data/json/system/widget_types/update_device_attribute.json
+++ b/application/src/main/data/json/system/widget_types/update_device_attribute.json
@@ -9,7 +9,7 @@
"sizeX": 4,
"sizeY": 2,
"resources": [],
- "templateHtml": "
",
+ "templateHtml": "",
"templateCss": ".tb-rpc-button {\n width: 100%;\n height: 100%;\n}\n\n.tb-rpc-button .title-container {\n font-weight: 500;\n white-space: nowrap;\n margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n min-width: 80%\n}\n\n.tb-rpc-button .button-container .mat-mdc-button{\n width: 100%;\n margin: 0;\n}\n\n.tb-rpc-button .error-container {\n position: absolute;\n top: 2%;\n right: 0;\n left: 0;\n z-index: 4;\n height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n color: #ff3315;\n white-space: nowrap;\n}",
"controllerScript": "self.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges();\n });\n};\n\nfunction init() {\n self.ctx.$scope.buttonLable = self.ctx.settings.buttonText;\n self.ctx.$scope.showTitle = self.ctx.settings.title &&\n self.ctx.settings.title.length ? true : false;\n self.ctx.$scope.title = self.ctx.settings.title;\n self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n let entityAttributeType = self.ctx.settings.entityAttributeType;\n let entityParameters = JSON.parse(self.ctx.settings.entityParameters);\n\n if (self.ctx.settings.styleButton.isPrimary ===\n false) {\n self.ctx.$scope.customStyle = {\n 'background-color': self.ctx.$scope.styleButton\n .bgColor,\n 'color': self.ctx.$scope.styleButton.textColor\n };\n }\n\n let attributeService = self.ctx.$scope.$injector.get(self.ctx.servicesMap.get('attributeService'));\n\n self.ctx.$scope.sendUpdate = function() {\n let attributes = [];\n for (let key in entityParameters) {\n attributes.push({\n \"key\": key,\n \"value\": entityParameters[key]\n });\n }\n \n let entityId = {\n entityType: \"DEVICE\",\n id: self.ctx.defaultSubscription.targetDeviceId\n };\n attributeService.saveEntityAttributes(entityId,\n entityAttributeType, attributes).subscribe(\n function success() {\n self.ctx.$scope.error = \"\";\n self.ctx.detectChanges();\n },\n function fail(rejection) {\n if (self.ctx.settings.showError) {\n self.ctx.$scope.error =\n rejection.status + \": \" +\n rejection.statusText;\n self.ctx.detectChanges();\n }\n }\n\n );\n };\n}\n",
"settingsSchema": "",
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/DefaultTransportMBeanConfiguration.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/DefaultTransportMBeanConfiguration.java
new file mode 100644
index 0000000000..0bf8fdeede
--- /dev/null
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/DefaultTransportMBeanConfiguration.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright © 2016-2024 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.transport.mqtt;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jmx.export.MBeanExporter;
+import org.thingsboard.server.common.transport.service.DefaultTransportService;
+import org.thingsboard.server.queue.util.TbTransportComponent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+@TbTransportComponent
+@RequiredArgsConstructor
+public class DefaultTransportMBeanConfiguration {
+
+ private final DefaultTransportService transportService;
+
+ @Bean
+ public HashMapObserver hashMapObserver() {
+ return new HashMapObserver(transportService.sessions);
+ }
+
+ @Bean
+ public MBeanExporter mBeanExporter() {
+ MBeanExporter exporter = new MBeanExporter();
+ Map beans = new HashMap<>();
+ beans.put("org.thingsboard:type=TransportSessionMapObserver", hashMapObserver());
+ exporter.setBeans(beans);
+ return exporter;
+ }
+
+}
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/HashMapObserver.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/HashMapObserver.java
new file mode 100644
index 0000000000..446ecb8aa4
--- /dev/null
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/HashMapObserver.java
@@ -0,0 +1,188 @@
+/**
+ * Copyright © 2016-2024 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.transport.mqtt;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.transport.service.SessionMetaData;
+import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
+import org.thingsboard.server.transport.mqtt.session.GatewayDeviceSessionContext;
+
+import java.util.Map;
+import java.util.UUID;
+
+@RequiredArgsConstructor
+@Slf4j
+public class HashMapObserver implements HashMapObserverMBean {
+ private final Map map;
+
+ @Override
+ public int getSize() {
+ return map.size();
+ }
+
+ @Override
+ public long getGatewayCount(String unused) {
+ return map.values().stream().filter(v-> v.getSessionInfo() != null && v.getSessionInfo().getIsGateway()).count();
+ }
+
+ @Override
+ public long getNonGatewayCount(String unused) {
+ return map.values().stream().filter(v-> v.getSessionInfo() != null && !v.getSessionInfo().getIsGateway()).count();
+ }
+
+ @Override
+ public String getSessionByUUID(String uuid) {
+ return String.valueOf(map.get(UUID.fromString(uuid)));
+ }
+
+ void addContent(Object entry, int count, StringBuilder content) {
+ String lineContent = String.valueOf(entry).replaceAll(System.lineSeparator()," ");
+ log.info("{} content = {}", count, lineContent);
+ content.append(lineContent).append(System.lineSeparator());
+ }
+
+ @Override
+ public String getAllSessions(String unused) {
+ log.info("getAllSessions()");
+ StringBuilder content = new StringBuilder();
+ try {
+ int count = 0;
+ for (Map.Entry entry : map.entrySet()) {
+ addContent(entry, ++count, content);
+ }
+ return content.toString();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ @Override
+ public String getSubscribedSessions(String unused) {
+ log.info("getSubscribedSessions()");
+ StringBuilder content = new StringBuilder();
+ try {
+ int count = 0;
+ for (Map.Entry entry : map.entrySet()) {
+ boolean hasSubscription = entry.getValue().isSubscribedToRPC() || entry.getValue().isSubscribedToAttributes();
+ if (hasSubscription) {
+ addContent(entry, ++count, content);
+ }
+ }
+ return content.toString();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ @Override
+ public String getNonActiveSessions(String unused) {
+ log.info("getNonActiveSessions()");
+ StringBuilder content = new StringBuilder();
+ try {
+ int count = 0;
+ for (Map.Entry entry : map.entrySet()) {
+ SessionMetaData sessionMetaData = entry.getValue();
+ if (sessionMetaData.getListener() instanceof MqttTransportHandler) {
+ MqttTransportHandler listener = (MqttTransportHandler) sessionMetaData.getListener();
+ if (!listener.deviceSessionCtx.getChannel().channel().isActive()) {
+ addContent(entry, ++count, content);
+ }
+ }
+ }
+ return content.toString();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ @Override
+ public String getActiveSessions(String unused) {
+ log.info("getActiveSessions()");
+ StringBuilder content = new StringBuilder();
+ try {
+ int count = 0;
+ for (Map.Entry entry : map.entrySet()) {
+ SessionMetaData sessionMetaData = entry.getValue();
+ if (sessionMetaData.getListener() instanceof MqttTransportHandler) {
+ MqttTransportHandler listener = (MqttTransportHandler) sessionMetaData.getListener();
+ if (listener.deviceSessionCtx.getChannel().channel().isActive()) {
+ addContent(entry, ++count, content);
+ }
+ } else {
+ addContent(sessionMetaData.getListener().getClass(), ++count, content);
+ }
+ }
+ return content.toString();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+
+ throw e;
+ }
+ }
+
+ @Override
+ public String getGatewayDeviceSessionContextConnectedSessions(String unused) {
+ log.info("getGatewayDeviceSessionContextConnectedSessions()");
+ StringBuilder content = new StringBuilder();
+ try {
+ int count = 0;
+ for (Map.Entry entry : map.entrySet()) {
+ SessionMetaData sessionMetaData = entry.getValue();
+ if (sessionMetaData.getListener() instanceof GatewayDeviceSessionContext) {
+ GatewayDeviceSessionContext listener = (GatewayDeviceSessionContext) sessionMetaData.getListener();
+ if (listener.isConnected()) {
+ addContent(entry, ++count, content);
+ }
+ }
+ }
+ addContent(count, count, content);
+ return content.toString();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ throw e;
+ }
+ }
+ @Override
+ public String getDeviceAwareSessionContextNotConnectedSessions(String unused) {
+ log.info("getDeviceAwareSessionContextNotConnectedSessions()");
+ StringBuilder content = new StringBuilder();
+ try {
+ int count = 0;
+ for (Map.Entry entry : map.entrySet()) {
+ SessionMetaData sessionMetaData = entry.getValue();
+ if (sessionMetaData.getListener() instanceof DeviceAwareSessionContext) {
+ DeviceAwareSessionContext listener = (DeviceAwareSessionContext) sessionMetaData.getListener();
+ if (!listener.isConnected()) {
+ addContent(entry, ++count, content);
+ }
+ }
+ }
+ addContent(count, count, content);
+ return content.toString();
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ throw e;
+ }
+ }
+
+}
+
+// 4a7d85c9-eb4b-4fbc-8f6c-deb158cc9ac7=SessionMetaData(sessionInfo=nodeId: "bestia.local" sessionIdMSB: 5367593433178001340 sessionIdLSB: -8111863975520724281 tenantIdMSB: -1954197196874116625 tenantIdLSB: -7022192637061768255 deviceIdMSB: -5222516332438875665 deviceIdLSB: -7338416368958642691 deviceName: "Demo Device" deviceType: "default" gwSessionIdMSB: 3730140660294699909 gwSessionIdLSB: -7918622346767288875 deviceProfileIdMSB: -1952135612572036625 deviceProfileIdLSB: -7022192637061768255 customerIdMSB: 1405474927960789426 customerIdLSB: -9187201950435737472 gatewayIdMSB: 164837549830312431 gatewayIdLSB: -7338416368958642691 , sessionType=ASYNC, listener=GatewayDeviceSessionContext(super=AbstractGatewayDeviceSessionContext(super=MqttDeviceAwareSessionContext(super=DeviceAwareSessionContext(sessionId=4a7d85c9-eb4b-4fbc-8f6c-deb158cc9ac7, deviceId=b785e510-d34e-11ef-9a28-b5316a4ee5fd, tenantId=e4e14c00-d341-11ef-9e8c-29007391dbc1, deviceInfo=TransportDeviceInfo(tenantId=e4e14c00-d341-11ef-9e8c-29007391dbc1, customerId=13814000-1dd2-11b2-8080-808080808080, deviceProfileId=e4e89f00-d341-11ef-9e8c-29007391dbc1, deviceId=b785e510-d34e-11ef-9a28-b5316a4ee5fd, deviceName=Demo Device, deviceType=default, powerMode=null, additionalInfo={"lastConnectedGateway":"02499ee0-d348-11ef-9a28-b5316a4ee5fd"}, edrxCycle=null, psmActivityTimer=null, pagingTransmissionWindow=null, gateway=false), deviceProfile=DeviceProfile(tenantId=e4e14c00-d341-11ef-9e8c-29007391dbc1, name=default, description=Default device profile, isDefault=true, type=DEFAULT, transportType=DEFAULT, provisionType=DISABLED, defaultRuleChainId=null, defaultDashboardId=null, defaultQueueName=null, profileData=DeviceProfileData(configuration=DefaultDeviceProfileConfiguration(), transportConfiguration=DefaultDeviceProfileTransportConfiguration(), provisionConfiguration=DisabledDeviceProfileProvisionConfiguration(provisionDeviceSecret=null), alarms=null), provisionDeviceKey=null, firmwareId=null, softwareId=null, defaultEdgeRuleChainId=null, externalId=null, version=1), sessionInfo=nodeId: "bestia.local" sessionIdMSB: 5367593433178001340 sessionIdLSB: -8111863975520724281 tenantIdMSB: -1954197196874116625 tenantIdLSB: -7022192637061768255 deviceIdMSB: -5222516332438875665 deviceIdLSB: -7338416368958642691 deviceName: "Demo Device" deviceType: "default" gwSessionIdMSB: 3730140660294699909 gwSessionIdLSB: -7918622346767288875 deviceProfileIdMSB: -1952135612572036625 deviceProfileIdLSB: -7022192637061768255 customerIdMSB: 1405474927960789426 customerIdLSB: -9187201950435737472 gatewayIdMSB: 164837549830312431 gatewayIdLSB: -7338416368958642691 , connected=true), mqttQoSMap={org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher@697a7658=1, org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher@d44c5be8=1, org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher@e3a8acd0=1, org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher@e3d2681a=1, org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher@a65b8616=1, org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher@133a8264=1, org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher@12e92606=1}), parent=org.thingsboard.server.transport.mqtt.session.GatewaySessionHandler@3d4885c2, transportService=org.thingsboard.server.common.transport.service.DefaultTransportService@77c16f87)), scheduledFuture=null, subscribedToAttributes=true, subscribedToRPC=true, overwriteActivityTime=false)
+//1
\ No newline at end of file
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/HashMapObserverMBean.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/HashMapObserverMBean.java
new file mode 100644
index 0000000000..3a70674aec
--- /dev/null
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/HashMapObserverMBean.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright © 2016-2024 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.transport.mqtt;
+
+public interface HashMapObserverMBean {
+ int getSize();
+
+ long getGatewayCount(String unused);
+
+ long getNonGatewayCount(String unused);
+
+ String getSessionByUUID(String key);
+
+ String getAllSessions(String key);
+
+ String getSubscribedSessions(String unused);
+
+ String getNonActiveSessions(String unused);
+
+ String getActiveSessions(String unused);
+
+ String getGatewayDeviceSessionContextConnectedSessions(String unused);
+
+ String getDeviceAwareSessionContextNotConnectedSessions(String unused);
+}
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewayDeviceSessionContext.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewayDeviceSessionContext.java
index e174ad86bd..1570bb4b7f 100644
--- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewayDeviceSessionContext.java
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewayDeviceSessionContext.java
@@ -17,6 +17,8 @@ package org.thingsboard.server.transport.mqtt.session;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.mqtt.MqttMessage;
+import lombok.Getter;
+import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.id.DeviceId;
@@ -34,9 +36,11 @@ import java.util.concurrent.ConcurrentMap;
/**
* Created by ashvayka on 19.01.17.
*/
+@ToString(callSuper = true)
@Slf4j
public abstract class AbstractGatewayDeviceSessionContext extends MqttDeviceAwareSessionContext implements SessionMsgListener {
+ @Getter
protected final T parent;
private final TransportService transportService;
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java
index 2e205ff840..8713e79988 100644
--- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java
@@ -16,8 +16,10 @@
package org.thingsboard.server.transport.mqtt.session;
import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -115,6 +117,7 @@ public abstract class AbstractGatewaySessionHandler devices;
private final ConcurrentMap> deviceFutures;
protected final ConcurrentMap mqttQoSMap;
+ @Getter
protected final ChannelHandlerContext channel;
protected final DeviceSessionCtx deviceSessionCtx;
protected final GatewayMetricsService gatewayMetricsService;
@@ -124,6 +127,7 @@ public abstract class AbstractGatewaySessionHandler {
+ Futures.addCallback(future, new FutureCallback() {
+ @Override
+ public void onSuccess(T result) {
+ log.debug("[{}] Gateway disconnect [{}] device deregister callback [{}]", gateway.getTenantId(), gateway.getDeviceId(), name);
+ deregisterSession(name, result);
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+
+ }
+ }, MoreExecutors.directExecutor());
+ });
+
+ devices.forEach(this::deregisterSession);
+ } catch (Exception e) {
+ log.error("Gateway disconnect failure", e);
+ }
}
public void onDeviceDeleted(String deviceName) {
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionContext.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionContext.java
index dff4245566..c5af48fadb 100644
--- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionContext.java
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionContext.java
@@ -15,6 +15,7 @@
*/
package org.thingsboard.server.transport.mqtt.session;
+import lombok.ToString;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.auth.TransportDeviceInfo;
@@ -24,6 +25,7 @@ import java.util.concurrent.ConcurrentMap;
/**
* Created by nickAS21 on 26.12.22
*/
+@ToString(callSuper = true)
public class GatewayDeviceSessionContext extends AbstractGatewayDeviceSessionContext {
public GatewayDeviceSessionContext(GatewaySessionHandler parent,
diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java
index 8ff3580753..ba8c8cb9fa 100644
--- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java
+++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/MqttDeviceAwareSessionContext.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.transport.mqtt.session;
import io.netty.handler.codec.mqtt.MqttQoS;
+import lombok.ToString;
import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
import java.util.List;
@@ -27,6 +28,7 @@ import java.util.stream.Collectors;
/**
* Created by ashvayka on 30.08.18.
*/
+@ToString(callSuper = true)
public abstract class MqttDeviceAwareSessionContext extends DeviceAwareSessionContext {
private final ConcurrentMap mqttQoSMap;
diff --git a/ui-ngx/src/app/core/api/entity-data-subscription.ts b/ui-ngx/src/app/core/api/entity-data-subscription.ts
index 46cd2af7ab..daeb6b8faf 100644
--- a/ui-ngx/src/app/core/api/entity-data-subscription.ts
+++ b/ui-ngx/src/app/core/api/entity-data-subscription.ts
@@ -685,7 +685,7 @@ export class EntityDataSubscription {
if (this.tsFields.length > 0) {
if (this.history) {
cmd.historyCmd = {
- keys: this.tsFields.map(key => key.key),
+ keys: [... new Set(this.tsFields.map(key => key.key))],
startTs: this.subsTw.fixedWindow.startTimeMs,
endTs: this.subsTw.fixedWindow.endTimeMs,
interval: 0,
@@ -702,7 +702,7 @@ export class EntityDataSubscription {
}
} else {
cmd.tsCmd = {
- keys: this.tsFields.map(key => key.key),
+ keys: [... new Set(this.tsFields.map(key => key.key))],
startTs: this.subsTw.startTs,
timeWindow: this.subsTw.aggregation.timeWindow,
interval: 0,
diff --git a/ui-ngx/src/app/core/http/rule-chain.service.ts b/ui-ngx/src/app/core/http/rule-chain.service.ts
index 749fb39e72..0e857c4570 100644
--- a/ui-ngx/src/app/core/http/rule-chain.service.ts
+++ b/ui-ngx/src/app/core/http/rule-chain.service.ts
@@ -33,6 +33,7 @@ import {
LinkLabel,
RuleNodeComponentDescriptor,
RuleNodeConfiguration,
+ RuleNodeConfigurationComponent,
ScriptLanguage,
TestScriptInputParams,
TestScriptResult
@@ -181,7 +182,7 @@ export class RuleChainService {
}
public registerSystemRuleNodeConfigModule(module: any) {
- Object.assign(this.ruleNodeConfigComponents, this.resourcesService.extractComponentsFromModule(module, true));
+ Object.assign(this.ruleNodeConfigComponents, this.resourcesService.extractComponentsFromModule(module, RuleNodeConfigurationComponent, true));
}
private loadRuleNodeComponents(ruleChainType: RuleChainType, config?: RequestConfig): Observable> {
diff --git a/ui-ngx/src/app/core/http/widget.service.ts b/ui-ngx/src/app/core/http/widget.service.ts
index ebf390866c..030d53de6f 100644
--- a/ui-ngx/src/app/core/http/widget.service.ts
+++ b/ui-ngx/src/app/core/http/widget.service.ts
@@ -14,7 +14,7 @@
/// limitations under the License.
///
-import { Injectable } from '@angular/core';
+import { Injectable, Type } from '@angular/core';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { Observable, of, ReplaySubject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
@@ -24,7 +24,10 @@ import { WidgetsBundle } from '@shared/models/widgets-bundle.model';
import {
BaseWidgetType,
DeprecatedFilter,
- fullWidgetTypeFqn, migrateWidgetTypeToDynamicForms,
+ fullWidgetTypeFqn,
+ IWidgetSettingsComponent,
+ migrateWidgetTypeToDynamicForms,
+ WidgetSettingsComponent,
WidgetType,
widgetType,
WidgetTypeDetails,
@@ -36,6 +39,11 @@ import { filter, map, mergeMap, tap } from 'rxjs/operators';
import { WidgetTypeId } from '@shared/models/id/widget-type-id';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { ActivationEnd, Router } from '@angular/router';
+import {
+ BasicWidgetConfigComponent,
+ IBasicWidgetConfigComponent
+} from '@home/components/widget/config/widget-config.component.models';
+import { ResourcesService } from '@core/services/resources.service';
@Injectable({
providedIn: 'root'
@@ -50,9 +58,13 @@ export class WidgetService {
private loadWidgetsBundleCacheSubject: ReplaySubject;
+ private basicWidgetSettingsComponentsMap: { [key: string]: Type } = {};
+ private widgetSettingsComponentsMap: { [key: string]: Type } = {};
+
constructor(
private http: HttpClient,
- private router: Router
+ private router: Router,
+ private resourcesService: ResourcesService,
) {
this.router.events.pipe(filter(event => event instanceof ActivationEnd)).subscribe(
() => {
@@ -287,6 +299,30 @@ export class WidgetService {
this.widgetsInfoInMemoryCache.set(widgetInfo.fullFqn, widgetInfo);
}
+ public registerBasicWidgetConfigComponents(module: any) {
+ Object.assign(this.basicWidgetSettingsComponentsMap, this.resourcesService.extractComponentsFromModule(module, BasicWidgetConfigComponent));
+ }
+
+ public getBasicWidgetSettingsComponentBySelector(selector: string): Type {
+ return this.basicWidgetSettingsComponentsMap[selector];
+ }
+
+ public putBasicWidgetSettingsComponentToMap(selector: string, compType: Type) {
+ this.basicWidgetSettingsComponentsMap[selector] = compType;
+ }
+
+ public registerWidgetSettingsComponents(module: any) {
+ Object.assign(this.widgetSettingsComponentsMap, this.resourcesService.extractComponentsFromModule(module, WidgetSettingsComponent));
+ }
+
+ public getWidgetSettingsComponentTypeBySelector(selector: string): Type {
+ return this.widgetSettingsComponentsMap[selector];
+ }
+
+ public putWidgetSettingsComponentToMap(selector: string, compType: Type) {
+ this.widgetSettingsComponentsMap[selector] = compType;
+ }
+
private widgetTypeUpdated(updatedWidgetType: BaseWidgetType): void {
this.deleteWidgetInfoFromCache(fullWidgetTypeFqn(updatedWidgetType));
}
diff --git a/ui-ngx/src/app/core/services/resources.service.ts b/ui-ngx/src/app/core/services/resources.service.ts
index 72cea30a1a..e2ee21c738 100644
--- a/ui-ngx/src/app/core/services/resources.service.ts
+++ b/ui-ngx/src/app/core/services/resources.service.ts
@@ -265,12 +265,15 @@ export class ResourcesService {
);
}
- public extractComponentsFromModule(module: any, isCamelCaseSelector = false): ComponentsSelectorMap {
+ public extractComponentsFromModule(module: any, instanceFilter?: any, isCamelCaseSelector = false): ComponentsSelectorMap {
const modulesWithComponents = this.extractModulesWithComponents(module);
const componentMap: ComponentsSelectorMap = {};
const processComponents = (components: Array<ɵComponentDef>) => {
components.forEach(item => {
+ if (instanceFilter && !(item.type.prototype instanceof instanceFilter)) {
+ return;
+ }
let selector = extractSelectorFromComponent(item);
if (isCamelCaseSelector) {
selector = camelCase(selector);
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts
index 800deec7e5..24cb04cca6 100644
--- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts
@@ -14,10 +14,10 @@
/// limitations under the License.
///
-import { NgModule, Type } from '@angular/core';
+import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
-import { IBasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
+import { WidgetService } from '@core/http/widget.service';
import { WidgetConfigComponentsModule } from '@home/components/widget/config/widget-config-components.module';
import {
SimpleCardBasicConfigComponent
@@ -251,47 +251,7 @@ import {
]
})
export class BasicWidgetConfigModule {
+ constructor(private widgetService: WidgetService) {
+ this.widgetService.registerBasicWidgetConfigComponents(this.constructor)
+ }
}
-
-export const basicWidgetConfigComponentsMap: {[key: string]: Type} = {
- 'tb-simple-card-basic-config': SimpleCardBasicConfigComponent,
- 'tb-entities-table-basic-config': EntitiesTableBasicConfigComponent,
- 'tb-timeseries-table-basic-config': TimeseriesTableBasicConfigComponent,
- 'tb-flot-basic-config': FlotBasicConfigComponent,
- 'tb-alarms-table-basic-config': AlarmsTableBasicConfigComponent,
- 'tb-value-card-basic-config': ValueCardBasicConfigComponent,
- 'tb-aggregated-value-card-basic-config': AggregatedValueCardBasicConfigComponent,
- 'tb-alarm-count-basic-config': AlarmCountBasicConfigComponent,
- 'tb-entity-count-basic-config': EntityCountBasicConfigComponent,
- 'tb-battery-level-basic-config': BatteryLevelBasicConfigComponent,
- 'tb-wind-speed-direction-basic-config': WindSpeedDirectionBasicConfigComponent,
- 'tb-signal-strength-basic-config': SignalStrengthBasicConfigComponent,
- 'tb-value-chart-card-basic-config': ValueChartCardBasicConfigComponent,
- 'tb-progress-bar-basic-config': ProgressBarBasicConfigComponent,
- 'tb-radial-gauge-basic-config': RadialGaugeBasicConfigComponent,
- 'tb-thermometer-scale-gauge-basic-config': ThermometerScaleGaugeBasicConfigComponent,
- 'tb-compass-gauge-basic-config': CompassGaugeBasicConfigComponent,
- 'tb-liquid-level-card-basic-config': LiquidLevelCardBasicConfigComponent,
- 'tb-doughnut-basic-config': DoughnutBasicConfigComponent,
- 'tb-range-chart-basic-config': RangeChartBasicConfigComponent,
- 'tb-bar-chart-with-labels-basic-config': BarChartWithLabelsBasicConfigComponent,
- 'tb-single-switch-basic-config': SingleSwitchBasicConfigComponent,
- 'tb-action-button-basic-config': ActionButtonBasicConfigComponent,
- 'tb-segmented-button-basic-config': SegmentedButtonBasicConfigComponent,
- 'tb-command-button-basic-config': CommandButtonBasicConfigComponent,
- 'tb-power-button-basic-config': PowerButtonBasicConfigComponent,
- 'tb-slider-basic-config': SliderBasicConfigComponent,
- 'tb-toggle-button-basic-config': ToggleButtonBasicConfigComponent,
- 'tb-time-series-chart-basic-config': TimeSeriesChartBasicConfigComponent,
- 'tb-status-widget-basic-config': StatusWidgetBasicConfigComponent,
- 'tb-pie-chart-basic-config': PieChartBasicConfigComponent,
- 'tb-bar-chart-basic-config': BarChartBasicConfigComponent,
- 'tb-polar-area-chart-basic-config': PolarAreaChartBasicConfigComponent,
- 'tb-radar-chart-basic-config': RadarChartBasicConfigComponent,
- 'tb-digital-simple-gauge-basic-config': DigitalSimpleGaugeBasicConfigComponent,
- 'tb-mobile-app-qr-code-basic-config': MobileAppQrCodeBasicConfigComponent,
- 'tb-label-card-basic-config': LabelCardBasicConfigComponent,
- 'tb-label-value-card-basic-config': LabelValueCardBasicConfigComponent,
- 'tb-unread-notification-basic-config': UnreadNotificationBasicConfigComponent,
- 'tb-scada-symbol-basic-config': ScadaSymbolBasicConfigComponent
-};
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts
index ab63e0e55d..1f3e9bcbc7 100644
--- a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts
@@ -39,7 +39,6 @@ import {
import { Subscription } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { DynamicFormData, IWidgetSettingsComponent, Widget, WidgetSettings } from '@shared/models/widget.models';
-import { widgetSettingsComponentsMap } from '@home/components/widget/lib/settings/widget-settings.module';
import { Dashboard } from '@shared/models/dashboard.models';
import { WidgetService } from '@core/http/widget.service';
import { IAliasController } from '@core/api/widget-api.models';
@@ -215,7 +214,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnDestroy,
this.definedSettingsComponent = null;
}
if (this.settingsDirective && this.settingsDirective.length) {
- const componentType = widgetSettingsComponentsMap[this.settingsDirective];
+ const componentType = this.widgetService.getWidgetSettingsComponentTypeBySelector(this.settingsDirective);
if (!componentType) {
this.definedDirectiveError = this.translate.instant('widget-config.settings-component-not-found',
{selector: this.settingsDirective});
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts
index 347782d210..46466985a3 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/polyline.ts
@@ -15,8 +15,8 @@
///
// @ts-ignore
-import L, { PolylineDecorator, PolylineDecoratorOptions, Symbol } from 'leaflet';
import 'leaflet-polylinedecorator';
+import L, { PolylineDecorator, PolylineDecoratorOptions, Symbol } from 'leaflet';
import { WidgetPolylineSettings } from './map-models';
import { functionValueCalculator } from '@home/components/widget/lib/maps/common-maps-utils';
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html
index 51d4ec22b1..3e1ca011fd 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html
@@ -138,6 +138,28 @@
{{ getErrorMessageText(key.settings, 'required') }}
+
+
+ {{key.label}}
+
+
+
+
+
+
+ {{ getCustomTranslationText(option.label ? option.label : option.value) }}
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss
index 4c8ffea030..b5e83a4925 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss
@@ -75,7 +75,7 @@
:host ::ng-deep {
.tb-multiple-input {
- .mat-mdc-slide-toggle, .mat-mdc-checkbox {
+ .mat-mdc-slide-toggle, .mat-mdc-checkbox, .mat-mdc-radio-button {
.mdc-form-field {
width: 100%;
& > label {
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts
index 7a80f4904a..94b33eb9d0 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts
@@ -54,7 +54,7 @@ type FieldAlignment = 'row' | 'column';
type MultipleInputWidgetDataKeyType = 'server' | 'shared' | 'timeseries';
export type MultipleInputWidgetDataKeyValueType = 'string' | 'double' | 'integer' |
'JSON' | 'booleanCheckbox' | 'booleanSwitch' |
- 'dateTime' | 'date' | 'time' | 'select' | 'color';
+ 'dateTime' | 'date' | 'time' | 'select' | 'radio' | 'color';
export type MultipleInputWidgetDataKeyEditableType = 'editable' | 'disabled' | 'readonly';
type ConvertGetValueFunction = (value: any, ctx: WidgetContext) => any;
@@ -86,6 +86,9 @@ interface MultipleInputWidgetDataKeySettings {
dataKeyValueType: MultipleInputWidgetDataKeyValueType;
slideToggleLabelPosition?: 'after' | 'before';
selectOptions: MultipleInputWidgetSelectOption[];
+ radioColor: string;
+ radioColumns: number;
+ radioLabelPosition?: 'after' | 'before';
required: boolean;
isEditable: MultipleInputWidgetDataKeyEditableType;
disabledOnDataKey: string;
@@ -300,7 +303,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
// For backward compatibility
- if (dataKey.settings.dataKeyValueType === 'select') {
+ if (dataKey.settings.dataKeyValueType === 'select' || dataKey.settings.dataKeyValueType === 'radio') {
dataKey.settings.selectOptions.forEach((option) => {
if (option.value.toLowerCase() === 'null') {
option.value = null;
@@ -444,6 +447,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
}
break;
case 'select':
+ case 'radio':
value = keyValue !== null ? keyValue.toString() : null;
break;
case 'JSON':
@@ -566,6 +570,12 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
return this.getTranslatedErrorText(errorMessage, defaultMessage, messageValues);
}
+ public radioButtonSelectedColor(radioColor: string) {
+ if (isDefinedAndNotNull(radioColor)) {
+ return `--mdc-radio-selected-icon-color: ${radioColor}; --mdc-radio-selected-focus-icon-color: ${radioColor}; --mdc-radio-selected-hover-icon-color: ${radioColor}; --mdc-radio-selected-pressed-icon-color: ${radioColor}; --mat-radio-checked-ripple-color: ${radioColor};`
+ }
+ }
+
public getTranslatedErrorText(errorMessage: string, defaultMessage: string, messageValues?: object): string {
let messageText;
if (errorMessage && errorMessage.length) {
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html
index 93c53c27ec..37a4dee4d5 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html
@@ -21,108 +21,113 @@
widgets.input-widgets.general-settings
-
-
- widgets.input-widgets.datakey-type
-
-
- {{ 'widgets.input-widgets.datakey-type-server' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-type-shared' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-type-timeseries' | translate }}
-
-
-
-
- widgets.input-widgets.datakey-value-type
-
-
- {{ 'widgets.input-widgets.datakey-value-type-string' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-double' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-integer' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-boolean-checkbox' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-boolean-switch' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-date-time' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-date' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-time' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-select' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-json' | translate }}
-
-
- {{ 'widgets.input-widgets.datakey-value-type-color' | translate }}
-
-
-
-
-
- {{ 'widgets.input-widgets.value-is-required' | translate }}
-
-
-
-
- widgets.input-widgets.field-appearance
-
-
- {{ 'widgets.input-widgets.appearance-fill' | translate }}
-
-
- {{ 'widgets.input-widgets.appearance-outline' | translate }}
-
-
-
-
- widgets.input-widgets.subscript-sizing
-
-
- {{ 'widgets.input-widgets.subscript-sizing-fixed' | translate }}
-
-
- {{ 'widgets.input-widgets.subscript-sizing-dynamic' | translate }}
-
-
-
-
+
+
+
+ widgets.input-widgets.datakey-type
+
+
+ {{ 'widgets.input-widgets.datakey-type-server' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-type-shared' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-type-timeseries' | translate }}
+
+
+
+
+ widgets.input-widgets.datakey-value-type
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-string' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-double' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-integer' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-boolean-checkbox' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-boolean-switch' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-date-time' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-date' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-time' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-select' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-radio' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-json' | translate }}
+
+
+ {{ 'widgets.input-widgets.datakey-value-type-color' | translate }}
+
+
+
+
+
+ {{ 'widgets.input-widgets.value-is-required' | translate }}
+
+
+
+
+ widgets.input-widgets.field-appearance
+
+
+ {{ 'widgets.input-widgets.appearance-fill' | translate }}
+
+
+ {{ 'widgets.input-widgets.appearance-outline' | translate }}
+
+
+
+
+ widgets.input-widgets.subscript-sizing
+
+
+ {{ 'widgets.input-widgets.subscript-sizing-fixed' | translate }}
+
+
+ {{ 'widgets.input-widgets.subscript-sizing-dynamic' | translate }}
+
+
+
+
+
@@ -140,8 +145,10 @@
- widgets.input-widgets.select-options
+ (updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'select' && updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value !== 'radio')" class="fields-group">
+
+ {{ (updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value === 'select' ? 'widgets.input-widgets.select-options' : 'widgets.input-widgets.radio-options') | translate }}
+
- widgets.input-widgets.no-select-options
+
+ {{ (updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value === 'select' ? 'widgets.input-widgets.no-select-options' : 'widgets.input-widgets.no-radio-options') | translate }}
+
- widgets.input-widgets.add-select-option
+
+ {{ (updateMultipleAttributesKeySettingsForm.get('dataKeyValueType').value === 'select' ? 'widgets.input-widgets.add-select-option' : 'widgets.input-widgets.add-radio-option') | translate }}
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.ts
index 24e0ac7072..378c2fdeab 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.ts
@@ -60,6 +60,9 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings
slideToggleLabelPosition: 'after',
selectOptions: [],
+ radioColor: null,
+ radioColumns: 1,
+ radioLabelPosition: 'after',
step: 1,
minValue: null,
maxValue: null,
@@ -104,10 +107,16 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings
slideToggleLabelPosition: [settings.slideToggleLabelPosition, []],
- // Select options
+ // Select/Radio options
selectOptions: this.prepareSelectOptionsFormArray(settings.selectOptions),
+ // Radio settings
+
+ radioColor: [settings.radioColor, []],
+ radioColumns: [settings.radioColumns, []],
+ radioLabelPosition: [settings.radioLabelPosition, []],
+
// Numeric field settings
step: [settings.step, [Validators.min(0)]],
@@ -183,6 +192,11 @@ export class UpdateMultipleAttributesKeySettingsComponent extends WidgetSettings
this.updateMultipleAttributesKeySettingsForm.get('slideToggleLabelPosition').enable({emitEvent: false});
} else if (dataKeyValueType === 'select') {
this.updateMultipleAttributesKeySettingsForm.get('selectOptions').enable({emitEvent: false});
+ } else if (dataKeyValueType === 'radio') {
+ this.updateMultipleAttributesKeySettingsForm.get('selectOptions').enable({emitEvent: false});
+ this.updateMultipleAttributesKeySettingsForm.get('radioColor').enable({emitEvent: false});
+ this.updateMultipleAttributesKeySettingsForm.get('radioColumns').enable({emitEvent: false});
+ this.updateMultipleAttributesKeySettingsForm.get('radioLabelPosition').enable({emitEvent: false});
} else if (dataKeyValueType === 'integer' || dataKeyValueType === 'double') {
this.updateMultipleAttributesKeySettingsForm.get('step').enable({emitEvent: false});
this.updateMultipleAttributesKeySettingsForm.get('minValue').enable({emitEvent: false});
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
index 4b5f3a1ad0..0aee57babb 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts
@@ -14,14 +14,14 @@
/// limitations under the License.
///
-import { NgModule, Type } from '@angular/core';
-import {
- QrCodeWidgetSettingsComponent
-} from '@home/components/widget/lib/settings/cards/qrcode-widget-settings.component';
+import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@shared/shared.module';
+import { WidgetService } from '@core/http/widget.service';
import { SharedHomeComponentsModule } from '@home/components/shared-home-components.module';
-import { IWidgetSettingsComponent } from '@shared/models/widget.models';
+import {
+ QrCodeWidgetSettingsComponent
+} from '@home/components/widget/lib/settings/cards/qrcode-widget-settings.component';
import {
TimeseriesTableWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component';
@@ -366,7 +366,7 @@ import {
UnreadNotificationWidgetSettingsComponent
} from '@home/components/widget/lib/settings/cards/unread-notification-widget-settings.component';
import {
-ScadaSymbolWidgetSettingsComponent
+ ScadaSymbolWidgetSettingsComponent
} from '@home/components/widget/lib/settings/scada/scada-symbol-widget-settings.component';
import {
SegmentedButtonWidgetSettingsComponent
@@ -643,105 +643,7 @@ import {
]
})
export class WidgetSettingsModule {
+ constructor(private widgetService: WidgetService) {
+ this.widgetService.registerWidgetSettingsComponents(this.constructor)
+ }
}
-
-export const widgetSettingsComponentsMap: {[key: string]: Type} = {
- 'tb-qrcode-widget-settings': QrCodeWidgetSettingsComponent,
- 'tb-mobile-app-qr-code-widget-settings': MobileAppQrCodeWidgetSettingsComponent,
- 'tb-timeseries-table-widget-settings': TimeseriesTableWidgetSettingsComponent,
- 'tb-timeseries-table-key-settings': TimeseriesTableKeySettingsComponent,
- 'tb-timeseries-table-latest-key-settings': TimeseriesTableLatestKeySettingsComponent,
- 'tb-markdown-widget-settings': MarkdownWidgetSettingsComponent,
- 'tb-label-widget-settings': LabelWidgetSettingsComponent,
- 'tb-simple-card-widget-settings': SimpleCardWidgetSettingsComponent,
- 'tb-dashboard-state-widget-settings': DashboardStateWidgetSettingsComponent,
- 'tb-entities-hierarchy-widget-settings': EntitiesHierarchyWidgetSettingsComponent,
- 'tb-html-card-widget-settings': HtmlCardWidgetSettingsComponent,
- 'tb-entities-table-widget-settings': EntitiesTableWidgetSettingsComponent,
- 'tb-entities-table-key-settings': EntitiesTableKeySettingsComponent,
- 'tb-alarms-table-widget-settings': AlarmsTableWidgetSettingsComponent,
- 'tb-alarms-table-key-settings': AlarmsTableKeySettingsComponent,
- 'tb-analogue-radial-gauge-widget-settings': AnalogueRadialGaugeWidgetSettingsComponent,
- 'tb-analogue-linear-gauge-widget-settings': AnalogueLinearGaugeWidgetSettingsComponent,
- 'tb-analogue-compass-widget-settings': AnalogueCompassWidgetSettingsComponent,
- 'tb-digital-gauge-widget-settings': DigitalGaugeWidgetSettingsComponent,
- 'tb-flot-line-widget-settings': FlotLineWidgetSettingsComponent,
- 'tb-flot-bar-widget-settings': FlotBarWidgetSettingsComponent,
- 'tb-flot-line-key-settings': FlotLineKeySettingsComponent,
- 'tb-flot-bar-key-settings': FlotBarKeySettingsComponent,
- 'tb-flot-latest-key-settings': FlotLatestKeySettingsComponent,
- 'tb-flot-pie-widget-settings': FlotPieWidgetSettingsComponent,
- 'tb-flot-pie-key-settings': FlotPieKeySettingsComponent,
- 'tb-chart-widget-settings': ChartWidgetSettingsComponent,
- 'tb-doughnut-chart-widget-settings': DoughnutChartWidgetSettingsComponent,
- 'tb-round-switch-widget-settings': RoundSwitchWidgetSettingsComponent,
- 'tb-switch-control-widget-settings': SwitchControlWidgetSettingsComponent,
- 'tb-slide-toggle-widget-settings': SlideToggleWidgetSettingsComponent,
- 'tb-persistent-table-widget-settings': PersistentTableWidgetSettingsComponent,
- 'tb-update-device-attribute-widget-settings': UpdateDeviceAttributeWidgetSettingsComponent,
- 'tb-send-rpc-widget-settings': SendRpcWidgetSettingsComponent,
- 'tb-led-indicator-widget-settings': LedIndicatorWidgetSettingsComponent,
- 'tb-knob-control-widget-settings': KnobControlWidgetSettingsComponent,
- 'tb-rpc-terminal-widget-settings': RpcTerminalWidgetSettingsComponent,
- 'tb-rpc-shell-widget-settings': RpcShellWidgetSettingsComponent,
- 'tb-date-range-navigator-widget-settings': DateRangeNavigatorWidgetSettingsComponent,
- 'tb-edge-quick-overview-widget-settings': EdgeQuickOverviewWidgetSettingsComponent,
- 'tb-gateway-config-widget-settings': GatewayConfigWidgetSettingsComponent,
- 'tb-gateway-config-single-device-widget-settings': GatewayConfigSingleDeviceWidgetSettingsComponent,
- 'tb-gateway-events-widget-settings': GatewayEventsWidgetSettingsComponent,
- 'tb-gpio-control-widget-settings': GpioControlWidgetSettingsComponent,
- 'tb-gpio-panel-widget-settings': GpioPanelWidgetSettingsComponent,
- 'tb-navigation-card-widget-settings': NavigationCardWidgetSettingsComponent,
- 'tb-navigation-cards-widget-settings': NavigationCardsWidgetSettingsComponent,
- 'tb-device-claiming-widget-settings': DeviceClaimingWidgetSettingsComponent,
- 'tb-update-integer-attribute-widget-settings': UpdateIntegerAttributeWidgetSettingsComponent,
- 'tb-update-double-attribute-widget-settings': UpdateDoubleAttributeWidgetSettingsComponent,
- 'tb-update-string-attribute-widget-settings': UpdateStringAttributeWidgetSettingsComponent,
- 'tb-update-boolean-attribute-widget-settings': UpdateBooleanAttributeWidgetSettingsComponent,
- 'tb-update-image-attribute-widget-settings': UpdateImageAttributeWidgetSettingsComponent,
- 'tb-update-date-attribute-widget-settings': UpdateDateAttributeWidgetSettingsComponent,
- 'tb-update-location-attribute-widget-settings': UpdateLocationAttributeWidgetSettingsComponent,
- 'tb-update-json-attribute-widget-settings': UpdateJsonAttributeWidgetSettingsComponent,
- 'tb-photo-camera-input-widget-settings': PhotoCameraInputWidgetSettingsComponent,
- 'tb-update-multiple-attributes-widget-settings': UpdateMultipleAttributesWidgetSettingsComponent,
- 'tb-update-multiple-attributes-key-settings': UpdateMultipleAttributesKeySettingsComponent,
- 'tb-map-widget-settings': MapWidgetSettingsComponent,
- 'tb-route-map-widget-settings': RouteMapWidgetSettingsComponent,
- 'tb-trip-animation-widget-settings': TripAnimationWidgetSettingsComponent,
- 'tb-gateway-logs-settings': GatewayLogsSettingsComponent,
- 'tb-gateway-service-rpc-settings':GatewayServiceRPCSettingsComponent,
- 'tb-doc-links-widget-settings': DocLinksWidgetSettingsComponent,
- 'tb-quick-links-widget-settings': QuickLinksWidgetSettingsComponent,
- 'tb-value-card-widget-settings': ValueCardWidgetSettingsComponent,
- 'tb-aggregated-value-card-key-settings': AggregatedValueCardKeySettingsComponent,
- 'tb-aggregated-value-card-widget-settings': AggregatedValueCardWidgetSettingsComponent,
- 'tb-alarm-count-widget-settings': AlarmCountWidgetSettingsComponent,
- 'tb-entity-count-widget-settings': EntityCountWidgetSettingsComponent,
- 'tb-battery-level-widget-settings': BatteryLevelWidgetSettingsComponent,
- 'tb-wind-speed-direction-widget-settings': WindSpeedDirectionWidgetSettingsComponent,
- 'tb-signal-strength-widget-settings': SignalStrengthWidgetSettingsComponent,
- 'tb-value-chart-card-widget-settings': ValueChartCardWidgetSettingsComponent,
- 'tb-progress-bar-widget-settings': ProgressBarWidgetSettingsComponent,
- 'tb-liquid-level-card-widget-settings': LiquidLevelCardWidgetSettingsComponent,
- 'tb-doughnut-widget-settings': DoughnutWidgetSettingsComponent,
- 'tb-range-chart-widget-settings': RangeChartWidgetSettingsComponent,
- 'tb-bar-chart-with-labels-widget-settings': BarChartWithLabelsWidgetSettingsComponent,
- 'tb-single-switch-widget-settings': SingleSwitchWidgetSettingsComponent,
- 'tb-action-button-widget-settings': ActionButtonWidgetSettingsComponent,
- 'tb-segmented-button-widget-settings': SegmentedButtonWidgetSettingsComponent,
- 'tb-command-button-widget-settings': CommandButtonWidgetSettingsComponent,
- 'tb-power-button-widget-settings': PowerButtonWidgetSettingsComponent,
- 'tb-slider-widget-settings': SliderWidgetSettingsComponent,
- 'tb-toggle-button-widget-settings': ToggleButtonWidgetSettingsComponent,
- 'tb-time-series-chart-key-settings': TimeSeriesChartKeySettingsComponent,
- 'tb-time-series-chart-widget-settings': TimeSeriesChartWidgetSettingsComponent,
- 'tb-status-widget-settings': StatusWidgetSettingsComponent,
- 'tb-pie-chart-widget-settings': PieChartWidgetSettingsComponent,
- 'tb-bar-chart-widget-settings': BarChartWidgetSettingsComponent,
- 'tb-polar-area-chart-widget-settings': PolarAreaChartWidgetSettingsComponent,
- 'tb-radar-chart-widget-settings': RadarChartWidgetSettingsComponent,
- 'tb-label-card-widget-settings': LabelCardWidgetSettingsComponent,
- 'tb-label-value-card-widget-settings': LabelValueCardWidgetSettingsComponent,
- 'tb-unread-notification-widget-settings': UnreadNotificationWidgetSettingsComponent,
- 'tb-scada-symbol-widget-settings': ScadaSymbolWidgetSettingsComponent
-};
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
index d9b18d896a..c044dca684 100644
--- a/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/widget-component.service.ts
@@ -36,7 +36,8 @@ import {
ResourcesService
} from '@core/services/resources.service';
import {
- IWidgetSettingsComponent, migrateWidgetTypeToDynamicForms,
+ IWidgetSettingsComponent,
+ migrateWidgetTypeToDynamicForms,
Widget,
widgetActionSources,
WidgetControllerDescriptor,
@@ -58,8 +59,6 @@ import tinycolor from 'tinycolor2';
import moment from 'moment';
import { IModulesMap } from '@modules/common/modules-map.models';
import { HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens';
-import { widgetSettingsComponentsMap } from '@home/components/widget/lib/settings/widget-settings.module';
-import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/basic/basic-widget-config.module';
import { IBasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { compileTbFunction, TbFunction } from '@shared/models/js-function.models';
import { HttpClient } from '@angular/common/http';
@@ -437,17 +436,17 @@ export class WidgetComponentService {
basicDirectives.push(widgetInfo.basicModeDirective);
}
- this.expandSettingComponentMap(widgetSettingsComponentsMap, directives, modulesWithComponents);
- this.expandSettingComponentMap(basicWidgetConfigComponentsMap, basicDirectives, modulesWithComponents);
+ this.expandSettingComponentMap(this.widgetService.putWidgetSettingsComponentToMap, directives, modulesWithComponents);
+ this.expandSettingComponentMap(this.widgetService.putBasicWidgetSettingsComponentToMap, basicDirectives, modulesWithComponents);
}
- private expandSettingComponentMap(settingsComponentsMap: {[key: string]: Type},
+ private expandSettingComponentMap(putComponentToMap: (selector: string, comp: Type) => void,
directives: string[], modulesWithComponents: ModulesWithComponents): void {
if (directives.length) {
directives.forEach(selector => {
const compType = componentTypeBySelector(modulesWithComponents, selector);
if (compType) {
- settingsComponentsMap[selector] = compType;
+ putComponentToMap(selector, compType);
}
});
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts
index 1721a7f068..595a8a2914 100644
--- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts
@@ -79,11 +79,11 @@ import { Filter, singleEntityFilterFromDeviceId } from '@shared/models/query/que
import { FilterDialogComponent, FilterDialogData } from '@home/components/filter/filter-dialog.component';
import { ToggleHeaderOption } from '@shared/components/toggle-header.component';
import { coerceBoolean } from '@shared/decorators/coercion';
-import { basicWidgetConfigComponentsMap } from '@home/components/widget/config/basic/basic-widget-config.module';
import { TimewindowConfigData } from '@home/components/widget/config/timewindow-config-panel.component';
import { DataKeySettingsFunction } from '@home/components/widget/config/data-keys.component.models';
import { defaultFormProperties, FormProperty } from '@shared/models/dynamic-form.models';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+import { WidgetService } from '@core/http/widget.service';
import Timeout = NodeJS.Timeout;
@Component({
@@ -205,6 +205,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
public translate: TranslateService,
private fb: UntypedFormBuilder,
private cd: ChangeDetectorRef,
+ private widgetService: WidgetService,
private destroyRef: DestroyRef) {
super(store);
}
@@ -435,7 +436,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe
}
private setupBasicModeConfig(isAdd = false) {
- const componentType = basicWidgetConfigComponentsMap[this.modelValue.basicModeDirective];
+ const componentType = this.widgetService.getBasicWidgetSettingsComponentBySelector(this.modelValue.basicModeDirective);
if (!componentType) {
this.basicModeDirectiveError = this.translate.instant('widget-config.settings-component-not-found',
{selector: this.modelValue.basicModeDirective});
diff --git a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.ts b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.ts
index 3075ae772b..e9576f313a 100644
--- a/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/mobile/bundes/layout/custom-mobile-page.component.ts
@@ -24,7 +24,12 @@ import {
Validator,
Validators
} from '@angular/forms';
-import { CustomMobilePage, MobilePageType, mobilePageTypeTranslations } from '@shared/models/mobile-app.models';
+import {
+ CustomMobilePage,
+ MobilePageType,
+ mobilePageTypeTranslations,
+ WEB_URL_REGEX
+} from '@shared/models/mobile-app.models';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { Authority } from '@shared/models/authority.enum';
@@ -63,8 +68,8 @@ export class CustomMobilePageComponent implements ControlValueAccessor, Validato
label: ['', [Validators.required, Validators.pattern(/\S/)]],
type: [MobilePageType.DASHBOARD],
dashboardId: this.fb.control(null, Validators.required),
- url: [{value:'', disabled: true}, [Validators.required, Validators.pattern(/^(https?:\/\/)?(localhost|([\w\-]+\.)+[\w\-]+)(:\d+)?(\/[\w\-._~:\/?#[\]@!$&'()*+,;=%]*)?$/)]],
- path: [{value:'', disabled: true}, [Validators.required, Validators.pattern(/^(\/[\w\-._~:\/?#[\]@!$&'()*+,;=%]*)?$/)]]
+ url: [{value:'', disabled: true}, [Validators.required, Validators.pattern(WEB_URL_REGEX)]],
+ path: [{value:'', disabled: true}, [Validators.required, Validators.pattern(/^(\/[\w\-._~:/?#[\]@!$&'()*+,;=%]*)?$/)]]
});
private propagateChange = (_val: any) => {};
diff --git a/ui-ngx/src/app/shared/models/mobile-app.models.ts b/ui-ngx/src/app/shared/models/mobile-app.models.ts
index acf609a637..7286910adc 100644
--- a/ui-ngx/src/app/shared/models/mobile-app.models.ts
+++ b/ui-ngx/src/app/shared/models/mobile-app.models.ts
@@ -21,6 +21,8 @@ import { OAuth2ClientInfo, PlatformType } from '@shared/models/oauth2.models';
import { MobileAppBundleId } from '@shared/models/id/mobile-app-bundle-id';
import { deepClone, isNotEmptyStr } from '@core/utils';
+export const WEB_URL_REGEX = /^(https?:\/\/)?(localhost|([\p{L}\p{M}\w-]+\.)+[\p{L}\p{M}\w-]+)(:\d+)?(\/[\w\-._~:/?#[\]@!$&'()*+,;=%\p{L}\p{N}]*)?$/u;
+
export interface QrCodeSettings extends HasTenantId {
useDefaultApp: boolean;
mobileAppBundleId: MobileAppBundleId
diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json
index 8e7e6deb7e..cd91f44b4b 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -3250,8 +3250,11 @@
"rotation-animation-speed-hint": "Double value indicating rotation animation speed. 1 - normal speed, 0 - no animation, < 1 - slower animation, > 1 - faster animation.",
"on-click": "On click",
"on-click-hint": "Action invoked when user clicks on the component.",
+ "connectors-positions": "Connectors positions",
+ "right-connector": "Right connector",
"right-top-connector": "Right top connector",
"right-bottom-connector": "Right bottom connector",
+ "left-connector": "Left connector",
"left-top-connector": "Left top connector",
"left-bottom-connector": "Left bottom connector",
"top-left-connector": "Top left connector",
@@ -3363,6 +3366,63 @@
"low-critical-state-hint": "Double value indicates a low critical range up to the min value scale.",
"filter-color": "Filter color",
"colors": "Colors",
+ "indicator-colors": "Indicator colors",
+ "enabled": "Enabled",
+ "disabled": "Disabled",
+ "on": "ON",
+ "off": "OFF",
+ "on-off-state": "On/Off state",
+ "on-off-state-hint": "Indicates whether the component is in the On or Off state.",
+ "on-update-state": "On update state",
+ "on-update-state-hint": "Action invoked when the user clicks to update the state to On.",
+ "off-update-state": "Off update state",
+ "off-update-state-hint": "Action invoked when the user clicks to update the state to Off.",
+ "voltage": "Voltage",
+ "input-voltage": "Input voltage",
+ "input-voltage-hint": "Double value indicates input voltage value.",
+ "output-voltage": "Output voltage",
+ "output-voltage-hint": "Double value indicates output voltage value.",
+ "first-phase-voltage": "First phase voltage",
+ "second-phase-voltage": "Second phase voltage",
+ "third-phase-voltage": "Third phase voltage",
+ "phase-voltage-hint": "Double value indicates voltage value for current phase",
+ "voltage-hint": "Double value indicates current voltage",
+ "current-voltage-color": "Current voltage color",
+ "phase-indicator-color": "Phase indicator color",
+ "measured": "Measured",
+ "measured-hint": "Double value indicates energy usage in kilowatt-hours",
+ "day-rate": "Day rate",
+ "night-rate": "Night rate",
+ "off-peak-rate": "Off-peak rate",
+ "peak-rate": "Peak rate",
+ "export-rate": "Export rate",
+ "operating-mode": "Operating mode",
+ "bypass-mode": "Bypass",
+ "operating-mode-hint": "Integer value indication the current operating mode (0 - OFF, 1 - ON, 2 - BYPASS)",
+ "connected": "Connected",
+ "connected-hint": "Indicates whether component is in connected state.",
+ "disconnected": "Disconnected",
+ "indicator": "Indicator",
+ "operation-mode": "Operation mode",
+ "operation-mode-hint": "Indicates whether inverter is in Mains or Inverter mode.",
+ "operation-mode-indicators-color": "Operation mode indicators color",
+ "mains-on-mode": "Mains on",
+ "inverter-on-mode": "Inverter on",
+ "charging-mode": "Charging mode",
+ "charging-mode-hint": "Integer value indication the current charging mode (1 - Bulk, 2 - Absorption, 3 - Float)",
+ "charging-mode-indicators-color": "Charging mode indicators color",
+ "inverter-faults": "Faults",
+ "inverter-fault-indicators-color": "Fault indicators color",
+ "overload-fault": "Overload",
+ "overload-fault-hint": "Indicates whether inverter is in overload condition.",
+ "low-battery-fault": "Low battery",
+ "low-battery-fault-hint": "Indicates whether battery is excessively discharged.",
+ "temperature-fault": "Temperature",
+ "temperature-fault-hint": "Indicates whether high temperature in an inverter.",
+ "triangle": "Triangle",
+ "socket": "Socket",
+ "left-button": "Left button",
+ "right-button": "Right button",
"alarm-colors": "Alarm colors",
"hook-color": "Hook color"
}
@@ -7340,6 +7400,7 @@
"datakey-value-type-date": "Date",
"datakey-value-type-time": "Time",
"datakey-value-type-select": "Select",
+ "datakey-value-type-radio": "Radio",
"datakey-value-type-color": "Color",
"value-is-required": "Value is required",
"ability-to-edit-attribute": "Ability to edit attribute",
@@ -7380,7 +7441,16 @@
"set-value-function": "setValue function",
"json-invalid": "JSON value has an invalid format",
"title": "Title",
- "cancel-button-label": "'Cancel' button label"
+ "cancel-button-label": "'Cancel' button label",
+ "radio-button-settings": "Radio button settings",
+ "color": "Color",
+ "columns": "Columns",
+ "radio-options": "Radio options",
+ "no-radio-options": "No radio options configured",
+ "add-radio-option": "Add radio option",
+ "radio-label-position": "Label position",
+ "radio-label-position-before": "Before",
+ "radio-label-position-after": "After"
},
"invalid-qr-code-text": "Invalid input text for QR code. Input should have a string type",
"qr-code": {