Merge branch 'master' into fix/4785-codeblocks-size
@ -548,7 +548,7 @@
|
||||
"id": "units",
|
||||
"name": "{i18n:scada.symbol.units}",
|
||||
"type": "units",
|
||||
"default": "°C",
|
||||
"default": "°C",
|
||||
"required": null,
|
||||
"subLabel": null,
|
||||
"divider": null,
|
||||
|
||||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
@ -548,7 +548,7 @@
|
||||
"id": "units",
|
||||
"name": "{i18n:scada.symbol.units}",
|
||||
"type": "units",
|
||||
"default": "°C",
|
||||
"default": "°C",
|
||||
"required": null,
|
||||
"subLabel": null,
|
||||
"divider": null,
|
||||
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
@ -540,7 +540,7 @@
|
||||
"id": "units",
|
||||
"name": "{i18n:scada.symbol.units}",
|
||||
"type": "units",
|
||||
"default": "°C",
|
||||
"default": "°C",
|
||||
"required": null,
|
||||
"subLabel": null,
|
||||
"divider": null,
|
||||
|
||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
@ -540,7 +540,7 @@
|
||||
"id": "units",
|
||||
"name": "{i18n:scada.symbol.units}",
|
||||
"type": "units",
|
||||
"default": "°C",
|
||||
"default": "°C",
|
||||
"required": null,
|
||||
"subLabel": null,
|
||||
"divider": null,
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
@ -1,5 +1,4 @@
|
||||
<svg width="600" height="1e3" fill="none" version="1.1" viewBox="0 0 600 1e3" xmlns="http://www.w3.org/2000/svg" xmlns:tb="https://thingsboard.io/svg">
|
||||
<tb:metadata><![CDATA[{
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:tb="https://thingsboard.io/svg" width="600" height="1e3" fill="none" version="1.1" viewBox="0 0 600 1e3"><tb:metadata xmlns=""><![CDATA[{
|
||||
"title": "HP Vertical tank",
|
||||
"description": "Vertical tank",
|
||||
"searchTags": [
|
||||
@ -33,12 +32,12 @@
|
||||
},
|
||||
{
|
||||
"tag": "fluid-background",
|
||||
"stateRenderFunction": " var color = ctx.properties.fluidColor;\n element.attr({fill: color, 'fill-opacity': 1});\n \n var valueSet = element.remember('valueSet');\n if (!valueSet) {\n element.remember('valueSet', true);\n element.attr({height: 0});\n }\n \n var currentVolume = ctx.values.currentVolume; \n var tankCapacity = ctx.values.tankCapacity; \n\n var height = currentVolume / tankCapacity;\n height = Math.max(0, Math.min(1, height))*970; \n \n var elementHeight = element.remember('height');\n if (height !== elementHeight) {\n element.remember('height', height);\n element.attr({height: height});\n }",
|
||||
"stateRenderFunction": " var color = ctx.properties.fluidColor;\n element.attr({fill: color, 'fill-opacity': 1});\n \n var valueSet = element.remember('valueSet');\n if (!valueSet) {\n element.remember('valueSet', true);\n element.attr({height: 0});\n }\n \n var currentVolume = ctx.values.currentVolume; \n var tankCapacity = ctx.values.tankCapacity; \n\n var height = currentVolume / tankCapacity;\n height = Math.max(0, Math.min(1, height))*994; \n \n var elementHeight = element.remember('height');\n if (height !== elementHeight) {\n element.remember('height', height);\n element.attr({height: height});\n }",
|
||||
"actions": null
|
||||
},
|
||||
{
|
||||
"tag": "scale",
|
||||
"stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 15;\n var majorIntervalLength = 970 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(160, y, 192, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 150, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(172, minorY, 192, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}",
|
||||
"stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 994 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(160, y, 192, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 150, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 150, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 150, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(172, minorY, 192, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}",
|
||||
"actions": null
|
||||
},
|
||||
{
|
||||
@ -455,16 +454,12 @@
|
||||
}
|
||||
]
|
||||
}]]></tb:metadata>
|
||||
<path d="m0 120s0-120 140-120c129 3.4657e-5 200.5-1.0591e-4 320 0 140 1.2408e-4 140 120 140 120v760s0 120-140 120h-320c-140 0-140-120-140-120v-760z" fill="#EBEBEB" tb:tag="background"/>
|
||||
<path d="m0.936 120h0.064l1e-5 -3e-3 5e-5 -0.014 4.3e-4 -0.061c5.1e-4 -0.054 0.00153-0.137 0.00361-0.247 0.00415-0.221 0.0125-0.551 0.02932-0.984 0.03365-0.865 0.10115-2.139 0.23656-3.764 0.27086-3.25 0.81325-7.902 1.8991-13.486 2.1725-11.173 6.5161-26.06 15.195-40.937 17.319-29.69 51.988-59.504 121.64-59.504l141.99-2e-5 178.01 2e-5c69.648 6e-5 104.32 29.814 121.64 59.504 8.679 14.878 13.022 29.764 15.195 40.937 1.086 5.585 1.628 10.236 1.899 13.486 0.135 1.625 0.203 2.899 0.237 3.764 0.016 0.433 0.025 0.763 0.029 0.984 1e-3 0.047 1e-3 0.09 2e-3 0.127 1e-3 0.049 1e-3 0.089 2e-3 0.12v0.078h0.064-0.064v760h0.064-0.064v0.078c-1e-3 0.054-2e-3 0.137-4e-3 0.247-4e-3 0.221-0.013 0.551-0.029 0.984-0.034 0.865-0.102 2.139-0.237 3.764-0.271 3.25-0.813 7.902-1.899 13.486-2.173 11.173-6.516 26.06-15.195 40.937-17.319 29.69-51.988 59.504-121.64 59.504h-320c-69.648 0-104.32-29.814-121.64-59.504-8.6786-14.877-13.022-29.764-15.195-40.937-1.0859-5.584-1.6283-10.236-1.8991-13.486-0.13541-1.625-0.20291-2.899-0.23656-3.764-0.01682-0.433-0.02517-0.763-0.02932-0.984-0.00208-0.11-0.0031-0.193-0.00361-0.247l-4.3e-4 -0.061-5e-5 -0.014-1e-5 -3e-3h-0.064 0.064v-760h-0.064z" stroke="#000" stroke-opacity=".87" stroke-width="2"/>
|
||||
<mask id="mask0_3610_179351" x="2" y="2" width="596" height="996" style="mask-type:alpha" maskUnits="userSpaceOnUse">
|
||||
<path d="m0 120s0-120 140-120c129 3.4657e-5 200.5-1.0591e-4 320 0 140 1.2408e-4 140 120 140 120v760s0 120-140 120h-320c-140 0-140-120-140-120v-760z" fill="#EBEBEB" tb:tag="background"/><path d="m0.936 120h0.064l1e-5 -3e-3 5e-5 -0.014 4.3e-4 -0.061c5.1e-4 -0.054 0.00153-0.137 0.00361-0.247 0.00415-0.221 0.0125-0.551 0.02932-0.984 0.03365-0.865 0.10115-2.139 0.23656-3.764 0.27086-3.25 0.81325-7.902 1.8991-13.486 2.1725-11.173 6.5161-26.06 15.195-40.937 17.319-29.69 51.988-59.504 121.64-59.504l141.99-2e-5 178.01 2e-5c69.648 6e-5 104.32 29.814 121.64 59.504 8.679 14.878 13.022 29.764 15.195 40.937 1.086 5.585 1.628 10.236 1.899 13.486 0.135 1.625 0.203 2.899 0.237 3.764 0.016 0.433 0.025 0.763 0.029 0.984 1e-3 0.047 1e-3 0.09 2e-3 0.127 1e-3 0.049 1e-3 0.089 2e-3 0.12v0.078h0.064-0.064v760h0.064-0.064v0.078c-1e-3 0.054-2e-3 0.137-4e-3 0.247-4e-3 0.221-0.013 0.551-0.029 0.984-0.034 0.865-0.102 2.139-0.237 3.764-0.271 3.25-0.813 7.902-1.899 13.486-2.173 11.173-6.516 26.06-15.195 40.937-17.319 29.69-51.988 59.504-121.64 59.504h-320c-69.648 0-104.32-29.814-121.64-59.504-8.6786-14.877-13.022-29.764-15.195-40.937-1.0859-5.584-1.6283-10.236-1.8991-13.486-0.13541-1.625-0.20291-2.899-0.23656-3.764-0.01682-0.433-0.02517-0.763-0.02932-0.984-0.00208-0.11-0.0031-0.193-0.00361-0.247l-4.3e-4 -0.061-5e-5 -0.014-1e-5 -3e-3h-0.064 0.064v-760h-0.064z" stroke="#000" stroke-opacity=".87" stroke-width="2"/><mask id="mask0_3610_179351" x="2" y="2" width="596" height="996" style="mask-type:alpha" maskUnits="userSpaceOnUse">
|
||||
<path d="m2 121.52s0-119.52 139.07-119.52c128.14 3e-5 199.16-1.1e-4 317.87 0 139.07 1.2e-4 139.07 119.52 139.07 119.52v756.96s0 119.52-139.07 119.52h-317.87c-139.07 0-139.07-119.52-139.07-119.52v-756.96z" fill="#EBEBEB"/>
|
||||
<path d="m2.936 121.52h0.064l1e-5 -3e-3 5e-5 -0.014 4.3e-4 -0.06c5e-4 -0.055 0.00152-0.137 0.00358-0.247 0.00412-0.22 0.01242-0.549 0.02913-0.979 0.03342-0.862 0.10047-2.131 0.23498-3.75 0.26905-3.237 0.80781-7.869 1.8864-13.432 2.158-11.128 6.4726-25.954 15.093-40.772 17.203-29.57 51.639-59.263 120.82-59.263l141.05-2e-5 176.82 2e-5c69.18 6e-5 103.62 29.693 120.82 59.263 8.621 14.818 12.935 29.644 15.093 40.772 1.079 5.563 1.618 10.195 1.887 13.432 0.134 1.619 0.201 2.888 0.235 3.75 0.017 0.43 0.025 0.759 0.029 0.979 2e-3 0.11 3e-3 0.192 4e-3 0.247v0.077h0.064-0.064v756.96h0.122-0.122v0.077c-1e-3 0.055-2e-3 0.137-4e-3 0.247-4e-3 0.22-0.012 0.549-0.029 0.979-0.034 0.862-0.101 2.131-0.235 3.75-0.269 3.237-0.808 7.869-1.887 13.432-2.158 11.128-6.472 25.954-15.093 40.772-17.203 29.57-51.639 59.263-120.82 59.263h-317.87c-69.18 0-103.62-29.693-120.82-59.263-8.6205-14.818-12.935-29.644-15.093-40.772-1.0786-5.563-1.6174-10.195-1.8864-13.432-0.13451-1.619-0.20156-2.888-0.23498-3.75-0.01671-0.43-0.02501-0.759-0.02913-0.979-0.00206-0.11-0.00308-0.192-0.00358-0.247l-4.3e-4 -0.06-5e-5 -0.014-1e-5 -3e-3h-0.064 0.064v-756.96h-0.064z" stroke="#000" stroke-opacity=".87" stroke-width="2"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_3610_179351)">
|
||||
</mask><g mask="url(#mask0_3610_179351)">
|
||||
<rect transform="scale(1,-1)" x="2" y="-995" width="600" height="419" fill="#c8dff7" tb:tag="fluid-background"/>
|
||||
</g>
|
||||
<g tb:tag="scale">
|
||||
</g><g tb:tag="scale">
|
||||
<line x1="162" x2="194" y1="3.5" y2="3.5" stroke="#000" stroke-opacity=".38" stroke-width="3"/>
|
||||
<line x1="174" x2="194" y1="23.359" y2="23.359" stroke="#000" stroke-opacity=".12" stroke-width="3"/>
|
||||
<line x1="174" x2="194" y1="43.221" y2="43.221" stroke="#000" stroke-opacity=".12" stroke-width="3"/>
|
||||
@ -527,18 +522,15 @@
|
||||
<path d="m139.2 798.95v2.25h-11.437v-1.933l5.554-6.059c0.61-0.687 1.09-1.281 1.442-1.781 0.351-0.5 0.598-0.949 0.738-1.348 0.149-0.406 0.223-0.801 0.223-1.183 0-0.54-0.102-1.012-0.305-1.418-0.195-0.415-0.484-0.739-0.867-0.973-0.383-0.242-0.848-0.363-1.395-0.363-0.632 0-1.164 0.136-1.593 0.41-0.43 0.273-0.754 0.652-0.973 1.137-0.219 0.476-0.328 1.023-0.328 1.64h-2.824c0-0.992 0.226-1.898 0.679-2.719 0.453-0.828 1.11-1.484 1.969-1.968 0.86-0.493 1.895-0.739 3.106-0.739 1.14 0 2.109 0.192 2.906 0.575 0.797 0.382 1.402 0.925 1.816 1.628 0.422 0.704 0.633 1.536 0.633 2.497 0 0.531-0.086 1.058-0.258 1.582-0.172 0.523-0.418 1.046-0.738 1.57-0.313 0.516-0.684 1.035-1.113 1.558-0.43 0.516-0.903 1.04-1.418 1.571l-3.692 4.066zm13.575-7.711v2.789c0 1.336-0.133 2.477-0.399 3.422-0.258 0.938-0.633 1.699-1.125 2.285s-1.082 1.016-1.769 1.289c-0.68 0.274-1.442 0.411-2.286 0.411-0.671 0-1.296-0.086-1.875-0.258-0.57-0.172-1.086-0.442-1.546-0.809-0.461-0.367-0.856-0.84-1.184-1.418-0.32-0.586-0.57-1.285-0.75-2.097-0.172-0.813-0.258-1.754-0.258-2.825v-2.789c0-1.343 0.133-2.476 0.399-3.398 0.265-0.93 0.644-1.684 1.136-2.262 0.492-0.586 1.078-1.012 1.758-1.277 0.688-0.266 1.453-0.399 2.297-0.399 0.68 0 1.305 0.086 1.875 0.258 0.578 0.164 1.094 0.426 1.547 0.785 0.461 0.36 0.851 0.828 1.172 1.407 0.328 0.57 0.578 1.261 0.75 2.074 0.172 0.804 0.258 1.742 0.258 2.812zm-2.825 3.188v-3.61c0-0.679-0.039-1.277-0.117-1.793-0.078-0.523-0.195-0.964-0.351-1.324-0.149-0.367-0.336-0.664-0.563-0.89-0.226-0.235-0.484-0.403-0.773-0.504-0.289-0.11-0.614-0.164-0.973-0.164-0.438 0-0.828 0.086-1.172 0.257-0.344 0.164-0.633 0.43-0.867 0.797s-0.414 0.852-0.539 1.453c-0.117 0.594-0.176 1.317-0.176 2.168v3.61c0 0.687 0.039 1.293 0.117 1.816 0.078 0.524 0.196 0.973 0.352 1.348 0.156 0.367 0.344 0.672 0.562 0.914 0.227 0.234 0.485 0.406 0.774 0.516 0.297 0.109 0.621 0.164 0.972 0.164 0.446 0 0.84-0.086 1.184-0.258s0.633-0.446 0.867-0.821c0.235-0.382 0.41-0.878 0.528-1.488 0.117-0.609 0.175-1.34 0.175-2.191z" fill="#000" fill-opacity=".38"/>
|
||||
<path d="m135.47 881.48v17.121h-2.824v-13.77l-4.184 1.418v-2.332l6.668-2.437zm17.301 7.16v2.789c0 1.336-0.133 2.476-0.399 3.422-0.258 0.937-0.633 1.699-1.125 2.285s-1.082 1.015-1.769 1.289c-0.68 0.273-1.442 0.41-2.286 0.41-0.671 0-1.296-0.086-1.875-0.258-0.57-0.172-1.086-0.441-1.546-0.808-0.461-0.368-0.856-0.84-1.184-1.418-0.32-0.586-0.57-1.286-0.75-2.098-0.172-0.813-0.258-1.754-0.258-2.824v-2.789c0-1.344 0.133-2.477 0.399-3.399 0.265-0.929 0.644-1.683 1.136-2.261 0.492-0.586 1.078-1.012 1.758-1.278 0.688-0.265 1.453-0.398 2.297-0.398 0.68 0 1.305 0.086 1.875 0.258 0.578 0.164 1.094 0.425 1.547 0.785 0.461 0.359 0.851 0.828 1.172 1.406 0.328 0.57 0.578 1.262 0.75 2.074 0.172 0.805 0.258 1.742 0.258 2.813zm-2.825 3.187v-3.609c0-0.68-0.039-1.278-0.117-1.793-0.078-0.524-0.195-0.965-0.351-1.324-0.149-0.368-0.336-0.664-0.563-0.891-0.226-0.234-0.484-0.402-0.773-0.504-0.289-0.109-0.614-0.164-0.973-0.164-0.438 0-0.828 0.086-1.172 0.258-0.344 0.164-0.633 0.43-0.867 0.797s-0.414 0.851-0.539 1.453c-0.117 0.594-0.176 1.316-0.176 2.168v3.609c0 0.688 0.039 1.293 0.117 1.817 0.078 0.523 0.196 0.972 0.352 1.347 0.156 0.367 0.344 0.672 0.562 0.914 0.227 0.235 0.485 0.407 0.774 0.516 0.297 0.109 0.621 0.164 0.972 0.164 0.446 0 0.84-0.086 1.184-0.258s0.633-0.445 0.867-0.82c0.235-0.383 0.41-0.879 0.528-1.488 0.117-0.61 0.175-1.34 0.175-2.192z" fill="#000" fill-opacity=".38"/>
|
||||
<path d="m152.77 986.04v2.789c0 1.336-0.133 2.477-0.399 3.422-0.258 0.938-0.633 1.699-1.125 2.285s-1.082 1.016-1.769 1.289c-0.68 0.274-1.442 0.41-2.286 0.41-0.671 0-1.296-0.086-1.875-0.257-0.57-0.172-1.086-0.442-1.546-0.809-0.461-0.367-0.856-0.84-1.184-1.418-0.32-0.586-0.57-1.285-0.75-2.098-0.172-0.812-0.258-1.754-0.258-2.824v-2.789c0-1.344 0.133-2.477 0.399-3.398 0.265-0.93 0.644-1.684 1.136-2.262 0.492-0.586 1.078-1.012 1.758-1.277 0.688-0.266 1.453-0.399 2.297-0.399 0.68 0 1.305 0.086 1.875 0.258 0.578 0.164 1.094 0.426 1.547 0.785 0.461 0.359 0.851 0.828 1.172 1.406 0.328 0.571 0.578 1.262 0.75 2.075 0.172 0.804 0.258 1.742 0.258 2.812zm-2.825 3.188v-3.61c0-0.679-0.039-1.277-0.117-1.793-0.078-0.523-0.195-0.965-0.351-1.324-0.149-0.367-0.336-0.664-0.563-0.891-0.226-0.234-0.484-0.402-0.773-0.504-0.289-0.109-0.614-0.164-0.973-0.164-0.438 0-0.828 0.086-1.172 0.258-0.344 0.164-0.633 0.43-0.867 0.797s-0.414 0.852-0.539 1.453c-0.117 0.594-0.176 1.317-0.176 2.168v3.61c0 0.687 0.039 1.293 0.117 1.816s0.196 0.973 0.352 1.348c0.156 0.367 0.344 0.671 0.562 0.914 0.227 0.234 0.485 0.406 0.774 0.515 0.297 0.11 0.621 0.164 0.972 0.164 0.446 0 0.84-0.086 1.184-0.257 0.344-0.172 0.633-0.446 0.867-0.821 0.235-0.383 0.41-0.879 0.528-1.488 0.117-0.609 0.175-1.34 0.175-2.191z" fill="#000" fill-opacity=".38"/>
|
||||
</g>
|
||||
<path d="m201.79 0s-201.79 0-201.79 167.5v820.9c0 6.628 5.3727 11.601 12 11.601h576c6.627 0 12-4.973 12-11.601v-820.9c0-167.5-198.21-167.5-198.21-167.5h-101.79zm201.21 203c-3.866 0-7 3.134-7 7v751c0 3.866 3.134 7 7 7h43.998c3.866 0 7-3.134 7-7v-751c0-3.866-3.134-7-7-7z" fill="#000" fill-opacity="0" style="stroke-width:.55902" tb:tag="clickArea"/>
|
||||
<g fill="#d12730" style="display:none" tb:tag="critical">
|
||||
</g><path d="m201.79 0s-201.79 0-201.79 167.5v820.9c0 6.628 5.3727 11.601 12 11.601h576c6.627 0 12-4.973 12-11.601v-820.9c0-167.5-198.21-167.5-198.21-167.5h-101.79zm201.21 203c-3.866 0-7 3.134-7 7v751c0 3.866 3.134 7 7 7h43.998c3.866 0 7-3.134 7-7v-751c0-3.866-3.134-7-7-7z" fill="#000" fill-opacity="0" style="stroke-width:.55902" tb:tag="clickArea"/><g fill="#d12730" style="display: none;" tb:tag="critical">
|
||||
<rect width="84" height="84" rx="4" fill="#fff" style=""/>
|
||||
<rect width="84" height="84" rx="4" style=""/>
|
||||
<rect x="2" y="2" width="80" height="80" rx="2" stroke="#000" stroke-opacity=".87" stroke-width="4" style=""/>
|
||||
<path d="m44.559 27.562-0.4688 20.059h-4.0234l-0.4883-20.059zm-5.1172 26.211c0-0.7161 0.2344-1.3151 0.7031-1.7968 0.4818-0.4948 1.1459-0.7422 1.9922-0.7422 0.8334 0 1.4909 0.2474 1.9727 0.7422 0.4817 0.4817 0.7226 1.0807 0.7226 1.7968 0 0.6901-0.2409 1.2826-0.7226 1.7774-0.4818 0.4818-1.1393 0.7226-1.9727 0.7226-0.8463 0-1.5104-0.2408-1.9922-0.7226-0.4687-0.4948-0.7031-1.0873-0.7031-1.7774z" fill="#000" fill-opacity=".87" style=""/>
|
||||
</g>
|
||||
<g transform="translate(0,-4.9442)" fill="#faa405" style="display:none" tb:tag="warning">
|
||||
</g><g transform="translate(0,-4.9442)" fill="#faa405" style="display: none;" tb:tag="warning">
|
||||
<path d="m38.422 7.1554c1.4741-2.9482 5.6813-2.9482 7.1554 0l35.528 71.056c1.3298 2.6596-0.6042 5.7889-3.5777 5.7889h-71.056c-2.9735 0-4.9075-3.1292-3.5777-5.7889z" fill="#fff" style=""/>
|
||||
<path d="m38.422 7.1554c1.4741-2.9482 5.6813-2.9482 7.1554 0l35.528 71.056c1.3298 2.6596-0.6042 5.7889-3.5777 5.7889h-71.056c-2.9735 0-4.9075-3.1292-3.5777-5.7889z" style=""/>
|
||||
<path d="m40.211 8.0498c0.7371-1.4741 2.8407-1.4741 3.5778-1e-5l35.528 71.056c0.6649 1.3298-0.3021 2.8944-1.7888 2.8944h-71.056c-1.4868 0-2.4538-1.5646-1.7889-2.8944z" stroke="#000" stroke-opacity=".87" stroke-width="4" style=""/>
|
||||
<path d="m44.559 37.562-0.4688 20.059h-4.0234l-0.4883-20.059zm-5.1172 26.211c0-0.7161 0.2344-1.3151 0.7031-1.7968 0.4818-0.4948 1.1459-0.7422 1.9922-0.7422 0.8334 0 1.4909 0.2474 1.9727 0.7422 0.4817 0.4817 0.7226 1.0807 0.7226 1.7968 0 0.6901-0.2409 1.2826-0.7226 1.7774-0.4818 0.4818-1.1393 0.7226-1.9727 0.7226-0.8463 0-1.5104-0.2408-1.9922-0.7226-0.4687-0.4948-0.7031-1.0873-0.7031-1.7774z" fill="#000" fill-opacity=".87" style=""/>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
@ -59,10 +59,6 @@ $$
|
||||
ALTER TABLE mobile_app_oauth2_client RENAME TO mobile_app_bundle_oauth2_client;
|
||||
ALTER TABLE mobile_app_bundle_oauth2_client DROP CONSTRAINT IF EXISTS fk_domain;
|
||||
ALTER TABLE mobile_app_bundle_oauth2_client RENAME COLUMN mobile_app_id TO mobile_app_bundle_id;
|
||||
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'fk_mobile_app_bundle_oauth2_client_bundle_id') THEN
|
||||
ALTER TABLE mobile_app_bundle_oauth2_client ADD CONSTRAINT fk_mobile_app_bundle_oauth2_client_bundle_id
|
||||
FOREIGN KEY (mobile_app_bundle_id) REFERENCES mobile_app_bundle(id) ON DELETE CASCADE;
|
||||
END IF;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
@ -98,6 +94,10 @@ $$
|
||||
UPDATE mobile_app_bundle_oauth2_client SET mobile_app_bundle_id = generatedBundleId WHERE mobile_app_bundle_id = mobileAppRecord.id;
|
||||
END LOOP;
|
||||
END IF;
|
||||
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'fk_mobile_app_bundle_oauth2_client_bundle_id') THEN
|
||||
ALTER TABLE mobile_app_bundle_oauth2_client ADD CONSTRAINT fk_mobile_app_bundle_oauth2_client_bundle_id
|
||||
FOREIGN KEY (mobile_app_bundle_id) REFERENCES mobile_app_bundle(id) ON DELETE CASCADE;
|
||||
END IF;
|
||||
ALTER TABLE mobile_app DROP COLUMN IF EXISTS oauth2_enabled;
|
||||
IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'mobile_app_pkg_name_platform_unq_key') THEN
|
||||
ALTER TABLE mobile_app ADD CONSTRAINT mobile_app_pkg_name_platform_unq_key UNIQUE (pkg_name, platform_type);
|
||||
@ -155,7 +155,7 @@ $$
|
||||
iosAppId := uuid_generate_v4();
|
||||
INSERT INTO mobile_app(id, created_time, tenant_id, pkg_name, platform_type, status, store_info)
|
||||
VALUES (iosAppId, (extract(epoch from now()) * 1000), qrCodeRecord.tenant_id,
|
||||
iosPkgName, 'IOS', 'DRAFT', qrCodeRecord.ios_config);
|
||||
iosPkgName, 'IOS', 'DRAFT', qrCodeRecord.ios_config::jsonb - 'enabled');
|
||||
IF generatedBundleId IS NULL THEN
|
||||
generatedBundleId := uuid_generate_v4();
|
||||
INSERT INTO mobile_app_bundle(id, created_time, tenant_id, title, ios_app_id)
|
||||
|
||||
@ -15,21 +15,16 @@
|
||||
*/
|
||||
package org.thingsboard.server.service.subscription;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmInfo;
|
||||
import org.thingsboard.server.common.data.query.AlarmCountQuery;
|
||||
import org.thingsboard.server.common.data.query.OriginatorAlarmFilter;
|
||||
import org.thingsboard.server.dao.alarm.AlarmService;
|
||||
import org.thingsboard.server.dao.attributes.AttributesService;
|
||||
import org.thingsboard.server.dao.entity.EntityService;
|
||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.service.ws.WebSocketService;
|
||||
import org.thingsboard.server.service.ws.WebSocketSessionRef;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmCountUpdate;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmStatusCmd;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmStatusUpdate;
|
||||
import org.thingsboard.server.service.ws.telemetry.sub.AlarmSubscriptionUpdate;
|
||||
|
||||
import java.util.List;
|
||||
@ -82,7 +77,10 @@ public class TbAlarmStatusSubCtx extends TbAbstractSubCtx {
|
||||
}
|
||||
|
||||
public void sendUpdate() {
|
||||
sendWsMsg(subscription.createUpdate());
|
||||
sendWsMsg(AlarmStatusUpdate.builder()
|
||||
.cmdId(cmdId)
|
||||
.active(subscription.hasAlarms())
|
||||
.build());
|
||||
}
|
||||
|
||||
public void fetchActiveAlarms() {
|
||||
|
||||
@ -22,7 +22,6 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmStatusUpdate;
|
||||
import org.thingsboard.server.service.ws.telemetry.sub.AlarmSubscriptionUpdate;
|
||||
|
||||
import java.util.HashSet;
|
||||
@ -53,15 +52,12 @@ public class TbAlarmStatusSubscription extends TbSubscription<AlarmSubscriptionU
|
||||
this.severityList = severityList;
|
||||
}
|
||||
|
||||
public AlarmStatusUpdate createUpdate() {
|
||||
return AlarmStatusUpdate.builder()
|
||||
.cmdId(getSubscriptionId())
|
||||
.active(!alarmIds.isEmpty())
|
||||
.build();
|
||||
}
|
||||
|
||||
public boolean matches(AlarmInfo alarm) {
|
||||
return !alarm.isCleared() && (this.typeList == null || this.typeList.contains(alarm.getType())) &&
|
||||
(this.severityList == null || this.severityList.contains(alarm.getSeverity()));
|
||||
}
|
||||
|
||||
public boolean hasAlarms() {
|
||||
return !alarmIds.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountUnsubscribeCmd;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityDataCmd;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityDataUnsubscribeCmd;
|
||||
import org.thingsboard.server.service.ws.telemetry.cmd.v2.AlarmStatusUnsubscribeCmd;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -67,6 +68,7 @@ public class WsCommandsWrapper {
|
||||
@Type(name = "ENTITY_DATA_UNSUBSCRIBE", value = EntityDataUnsubscribeCmd.class),
|
||||
@Type(name = "ENTITY_COUNT_UNSUBSCRIBE", value = EntityCountUnsubscribeCmd.class),
|
||||
@Type(name = "NOTIFICATIONS_UNSUBSCRIBE", value = NotificationsUnsubCmd.class),
|
||||
@Type(name = "ALARM_STATUS_UNSUBSCRIBE", value = AlarmStatusUnsubscribeCmd.class),
|
||||
})
|
||||
private List<WsCmd> cmds;
|
||||
|
||||
|
||||
@ -22,6 +22,9 @@ import {
|
||||
AlarmDataCmd,
|
||||
AlarmDataUnsubscribeCmd,
|
||||
AlarmDataUpdate,
|
||||
AlarmStatusCmd,
|
||||
AlarmStatusUnsubscribeCmd,
|
||||
AlarmStatusUpdate,
|
||||
EntityCountCmd,
|
||||
EntityCountUnsubscribeCmd,
|
||||
EntityCountUpdate,
|
||||
@ -30,6 +33,7 @@ import {
|
||||
EntityDataUpdate,
|
||||
isAlarmCountUpdateMsg,
|
||||
isAlarmDataUpdateMsg,
|
||||
isAlarmStatusUpdateMsg,
|
||||
isEntityCountUpdateMsg,
|
||||
isEntityDataUpdateMsg,
|
||||
isNotificationCountUpdateMsg,
|
||||
@ -121,6 +125,10 @@ export class TelemetryWebsocketService extends WebsocketService<TelemetrySubscri
|
||||
const alarmCountUnsubscribeCmd = new AlarmCountUnsubscribeCmd();
|
||||
alarmCountUnsubscribeCmd.cmdId = subscriptionCommand.cmdId;
|
||||
this.cmdWrapper.cmds.push(alarmCountUnsubscribeCmd);
|
||||
} else if (subscriptionCommand instanceof AlarmStatusCmd) {
|
||||
const alarmCountUnsubscribeCmd = new AlarmStatusUnsubscribeCmd();
|
||||
alarmCountUnsubscribeCmd.cmdId = subscriptionCommand.cmdId;
|
||||
this.cmdWrapper.cmds.push(alarmCountUnsubscribeCmd);
|
||||
} else if (subscriptionCommand instanceof UnreadCountSubCmd || subscriptionCommand instanceof UnreadSubCmd) {
|
||||
const notificationsUnsubCmds = new UnsubscribeCmd();
|
||||
notificationsUnsubCmds.cmdId = subscriptionCommand.cmdId;
|
||||
@ -157,6 +165,8 @@ export class TelemetryWebsocketService extends WebsocketService<TelemetrySubscri
|
||||
subscriber.onEntityCount(new EntityCountUpdate(message));
|
||||
} else if (isAlarmCountUpdateMsg(message)) {
|
||||
subscriber.onAlarmCount(new AlarmCountUpdate(message));
|
||||
} else if (isAlarmStatusUpdateMsg(message)) {
|
||||
subscriber.onAlarmStatus(new AlarmStatusUpdate(message))
|
||||
}
|
||||
}
|
||||
} else if ('subscriptionId' in message && message.subscriptionId) {
|
||||
|
||||
@ -105,14 +105,14 @@ export class AuditLogDetailsDialogComponent extends DialogComponent<AuditLogDeta
|
||||
let newWidth = 600;
|
||||
if (content && content.length > 0) {
|
||||
const lines = content.split('\n');
|
||||
newHeight = 16 * lines.length + 16;
|
||||
newHeight = 17 * lines.length + 16;
|
||||
let maxLineLength = 0;
|
||||
lines.forEach((row) => {
|
||||
const line = row.replace(/\t/g, ' ').replace(/\n/g, '');
|
||||
const lineLength = line.length;
|
||||
maxLineLength = Math.max(maxLineLength, lineLength);
|
||||
});
|
||||
newWidth = 8 * maxLineLength + 16;
|
||||
newWidth = 9 * maxLineLength + 16;
|
||||
}
|
||||
// newHeight = Math.min(400, newHeight);
|
||||
this.renderer.setStyle(editorElement, 'minHeight', newHeight.toString() + 'px');
|
||||
|
||||
@ -139,14 +139,14 @@ export class EventContentDialogComponent extends DialogComponent<EventContentDia
|
||||
let newWidth = 600;
|
||||
if (content && content.length > 0) {
|
||||
const lines = content.split('\n');
|
||||
newHeight = 16 * lines.length + 16;
|
||||
newHeight = 17 * lines.length + 16;
|
||||
let maxLineLength = 0;
|
||||
lines.forEach((row) => {
|
||||
const line = row.replace(/\t/g, ' ').replace(/\n/g, '');
|
||||
const lineLength = line.length;
|
||||
maxLineLength = Math.max(maxLineLength, lineLength);
|
||||
});
|
||||
newWidth = 8 * maxLineLength + 16;
|
||||
newWidth = 9 * maxLineLength + 16;
|
||||
}
|
||||
// newHeight = Math.min(400, newHeight);
|
||||
this.renderer.setStyle(editorElement, 'minHeight', newHeight.toString() + 'px');
|
||||
|
||||
@ -242,6 +242,8 @@ export abstract class ValueGetter<V> extends ValueAction {
|
||||
return new AttributeValueGetter<V>(ctx, settings, valueType, valueObserver, simulated);
|
||||
case GetValueAction.GET_TIME_SERIES:
|
||||
return new TimeSeriesValueGetter<V>(ctx, settings, valueType, valueObserver, simulated);
|
||||
case GetValueAction.GET_ALARM_STATUS:
|
||||
return new AlarmStatusValueGetter<V>(ctx, settings, valueType, valueObserver, simulated);
|
||||
case GetValueAction.GET_DASHBOARD_STATE:
|
||||
return new DashboardStateGetter<V>(ctx, settings, valueType, valueObserver, simulated);
|
||||
}
|
||||
@ -257,7 +259,7 @@ export abstract class ValueGetter<V> extends ValueAction {
|
||||
protected valueObserver: Partial<Observer<V>>,
|
||||
protected simulated: boolean) {
|
||||
super(ctx, settings);
|
||||
if (this.settings.action !== GetValueAction.DO_NOTHING) {
|
||||
if (this.settings.action !== GetValueAction.DO_NOTHING && this.settings.action !== GetValueAction.GET_ALARM_STATUS) {
|
||||
this.dataConverter = new DataToValueConverter<V>(settings.dataToValue, valueType);
|
||||
}
|
||||
}
|
||||
@ -537,6 +539,58 @@ export class TimeSeriesValueGetter<V> extends TelemetryValueGetter<V, TelemetryV
|
||||
}
|
||||
}
|
||||
|
||||
export class AlarmStatusValueGetter<V> extends ValueGetter<V> {
|
||||
|
||||
protected targetEntityId: EntityId;
|
||||
private telemetrySubscriber: SharedTelemetrySubscriber;
|
||||
|
||||
constructor(protected ctx: WidgetContext,
|
||||
protected settings: GetValueSettings<V>,
|
||||
protected valueType: ValueType,
|
||||
protected valueObserver: Partial<Observer<V>>,
|
||||
protected simulated: boolean) {
|
||||
super(ctx, settings, valueType, valueObserver, simulated);
|
||||
const entityInfo = this.ctx.defaultSubscription.getFirstEntityInfo();
|
||||
this.targetEntityId = entityInfo?.entityId;
|
||||
}
|
||||
|
||||
protected doGetValue(): Observable<boolean> {
|
||||
if (this.simulated) {
|
||||
return of(false).pipe(delay(100));
|
||||
} else {
|
||||
if (!this.targetEntityId && !this.ctx.defaultSubscription.rpcEnabled) {
|
||||
return throwError(() => new Error(this.ctx.translate.instant('widgets.value-action.error.target-entity-is-not-set')));
|
||||
}
|
||||
if (this.targetEntityId) {
|
||||
return this.subscribeForTelemetryValue();
|
||||
} else {
|
||||
return of(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private subscribeForTelemetryValue(): Observable<boolean> {
|
||||
this.telemetrySubscriber =
|
||||
SharedTelemetrySubscriber.createAlarmStatusSubscription(this.ctx.telemetryWsService, this.targetEntityId,
|
||||
this.ctx.ngZone, this.settings.getAlarmStatus.severityList, this.settings.getAlarmStatus.typeList);
|
||||
this.telemetrySubscriber.subscribe();
|
||||
return this.telemetrySubscriber.alarmStatus$.pipe(
|
||||
map((data) => {
|
||||
return data.active;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
destroy() {
|
||||
if (this.telemetrySubscriber) {
|
||||
this.telemetrySubscriber.unsubscribe();
|
||||
this.telemetrySubscriber = null;
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
export class DashboardStateGetter<V> extends ValueGetter<V> {
|
||||
constructor(protected ctx: WidgetContext,
|
||||
protected settings: GetValueSettings<V>,
|
||||
|
||||
@ -38,6 +38,10 @@ export const actionButtonDefaultSettings: ActionButtonWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
@ -54,6 +58,10 @@ export const actionButtonDefaultSettings: ActionButtonWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
|
||||
@ -62,6 +62,10 @@ export const commandButtonDefaultSettings: CommandButtonWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
|
||||
@ -61,6 +61,10 @@ export const toggleButtonDefaultSettings: ToggleButtonWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
@ -77,6 +81,10 @@ export const toggleButtonDefaultSettings: ToggleButtonWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
|
||||
@ -145,6 +145,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi
|
||||
private rssi = -100;
|
||||
private noSignal = false;
|
||||
private noData = false;
|
||||
private noSignalRssiValue = -100;
|
||||
|
||||
constructor(public widgetComponent: WidgetComponent,
|
||||
private imagePipe: ImagePipe,
|
||||
@ -166,6 +167,8 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi
|
||||
this.dateStyle.color = this.settings.dateColor;
|
||||
}
|
||||
|
||||
this.noSignalRssiValue = this.settings.noSignalRssiValue ?? -100;
|
||||
|
||||
this.activeBarsColor = ColorProcessor.fromSettings(this.settings.activeBarsColor);
|
||||
const inactiveBarsColor = tinycolor(this.settings.inactiveBarsColor);
|
||||
this.inactiveBarsColorHex = inactiveBarsColor.toHexString();
|
||||
@ -262,7 +265,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi
|
||||
}
|
||||
}
|
||||
|
||||
this.noSignal = this.rssi <= this.settings.noSignalRssiValue;
|
||||
this.noSignal = this.rssi <= this.noSignalRssiValue;
|
||||
|
||||
this.activeBarsColor.update(this.rssi);
|
||||
|
||||
@ -342,7 +345,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi
|
||||
const activeBarsOpacity = activeBarsColor.getAlpha();
|
||||
for (let index = 0; index < this.bars.length; index++) {
|
||||
const bar = this.bars[index];
|
||||
const active = signalBarActive(this.rssi, index);
|
||||
const active = signalBarActive(this.rssi, index, this.noSignalRssiValue);
|
||||
const newFill = active ? activeBarsColorHex : this.inactiveBarsColorHex;
|
||||
const newOpacity = active ? activeBarsOpacity : this.inactiveBarsOpacity;
|
||||
if (newFill !== bar.fill() || newOpacity !== bar.opacity()) {
|
||||
|
||||
@ -133,10 +133,10 @@ export const signalStrengthDefaultSettings: SignalStrengthWidgetSettings = {
|
||||
padding: '12px'
|
||||
};
|
||||
|
||||
export const signalBarActive = (rssi: number, index: number): boolean => {
|
||||
export const signalBarActive = (rssi: number, index: number, minSignal: number): boolean => {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return rssi > -100;
|
||||
return rssi > minSignal;
|
||||
case 1:
|
||||
return rssi >= -85;
|
||||
case 2:
|
||||
|
||||
@ -85,6 +85,10 @@ export const statusWidgetDefaultSettings: StatusWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
@ -101,6 +105,10 @@ export const statusWidgetDefaultSettings: StatusWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
|
||||
@ -104,6 +104,10 @@ export const powerButtonDefaultSettings: PowerButtonWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
@ -120,6 +124,10 @@ export const powerButtonDefaultSettings: PowerButtonWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
|
||||
@ -100,6 +100,10 @@ export const singleSwitchDefaultSettings: SingleSwitchWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
@ -116,6 +120,10 @@ export const singleSwitchDefaultSettings: SingleSwitchWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
|
||||
@ -101,6 +101,10 @@ export const sliderWidgetDefaultSettings: SliderWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
@ -117,6 +121,10 @@ export const sliderWidgetDefaultSettings: SliderWidgetSettings = {
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
|
||||
@ -415,6 +415,10 @@ export const defaultGetValueSettings = (valueType: ValueType): GetValueSettings<
|
||||
getTimeSeries: {
|
||||
key: 'state'
|
||||
},
|
||||
getAlarmStatus: {
|
||||
severityList: null,
|
||||
typeList: null
|
||||
},
|
||||
dataToValue: {
|
||||
type: DataToValueType.NONE,
|
||||
compareToValue: true,
|
||||
|
||||
@ -103,8 +103,31 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
<ng-template [ngSwitchCase]="getValueAction.GET_ALARM_STATUS">
|
||||
<ng-container formGroupName="getAlarmStatus">
|
||||
<div class="tb-form-row space-between column-xs">
|
||||
<div class="fixed-title-width" translate>alarm.alarm-severity</div>
|
||||
<mat-chip-listbox multiple formControlName="severityList">
|
||||
<mat-chip-option *ngFor="let alarmSeverity of alarmSeverities" [value]="alarmSeverity">
|
||||
{{ alarmSeverityTranslationMap.get(alarmSeverity) | translate }}
|
||||
</mat-chip-option>
|
||||
</mat-chip-listbox>
|
||||
</div>
|
||||
<div class="tb-form-row column-xs">
|
||||
<div class="fixed-title-width" translate>alarm.alarm-types</div>
|
||||
<tb-entity-subtype-list subscriptSizing="dynamic"
|
||||
formControlName="typeList"
|
||||
appearance="outline"
|
||||
class="flex-1"
|
||||
[additionalClasses]="['tb-chips', 'flex']"
|
||||
[entityType]="entityType.ALARM">
|
||||
</tb-entity-subtype-list>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<div *ngIf="getValueSettingsFormGroup.get('action').value !== getValueAction.DO_NOTHING"
|
||||
<div *ngIf="getValueSettingsFormGroup.get('action').value !== getValueAction.DO_NOTHING &&
|
||||
getValueSettingsFormGroup.get('action').value !== getValueAction.GET_ALARM_STATUS"
|
||||
class="tb-form-panel stroked" formGroupName="dataToValue">
|
||||
<div class="tb-form-row no-padding no-border column-xs">
|
||||
<div class="fixed-title-width" translate>widgets.value-action.action-result-converter</div>
|
||||
|
||||
@ -33,6 +33,8 @@ import { TargetDevice, widgetType } from '@shared/models/widget.models';
|
||||
import { AttributeScope, DataKeyType, telemetryTypeTranslationsShort } from '@shared/models/telemetry/telemetry.models';
|
||||
import { IAliasController } from '@core/api/widget-api.models';
|
||||
import { WidgetService } from '@core/http/widget.service';
|
||||
import { AlarmSeverity, alarmSeverityTranslations } from '@shared/models/alarm.models';
|
||||
import { EntityType } from '@shared/models/entity-type.models';
|
||||
|
||||
@Component({
|
||||
selector: 'tb-get-value-action-settings-panel',
|
||||
@ -96,6 +98,9 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
|
||||
|
||||
getValueSettingsFormGroup: UntypedFormGroup;
|
||||
|
||||
alarmSeverities = Object.keys(AlarmSeverity) as AlarmSeverity[];
|
||||
alarmSeverityTranslationMap = alarmSeverityTranslations;
|
||||
|
||||
constructor(private fb: UntypedFormBuilder,
|
||||
private widgetService: WidgetService,
|
||||
protected store: Store<AppState>) {
|
||||
@ -122,6 +127,10 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
|
||||
getTimeSeries: this.fb.group({
|
||||
key: [this.getValueSettings?.getTimeSeries?.key, [Validators.required]]
|
||||
}),
|
||||
getAlarmStatus: this.fb.group({
|
||||
severityList: [this.getValueSettings?.getAlarmStatus?.severityList],
|
||||
typeList: [this.getValueSettings?.getAlarmStatus?.typeList]
|
||||
}),
|
||||
dataToValue: this.fb.group({
|
||||
type: [this.getValueSettings?.dataToValue?.type, [Validators.required]],
|
||||
dataToValueFunction: [this.getValueSettings?.dataToValue?.dataToValueFunction, [Validators.required]],
|
||||
@ -159,6 +168,7 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
|
||||
this.getValueSettingsFormGroup.get('executeRpc').disable({emitEvent: false});
|
||||
this.getValueSettingsFormGroup.get('getAttribute').disable({emitEvent: false});
|
||||
this.getValueSettingsFormGroup.get('getTimeSeries').disable({emitEvent: false});
|
||||
this.getValueSettingsFormGroup.get('getAlarmStatus').disable({emitEvent: false});
|
||||
switch (action) {
|
||||
case GetValueAction.DO_NOTHING:
|
||||
this.getValueSettingsFormGroup.get('defaultValue').enable({emitEvent: false});
|
||||
@ -178,8 +188,11 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
|
||||
case GetValueAction.GET_TIME_SERIES:
|
||||
this.getValueSettingsFormGroup.get('getTimeSeries').enable({emitEvent: false});
|
||||
break;
|
||||
case GetValueAction.GET_ALARM_STATUS:
|
||||
this.getValueSettingsFormGroup.get('getAlarmStatus').enable({emitEvent: false});
|
||||
break;
|
||||
}
|
||||
if (action === GetValueAction.DO_NOTHING) {
|
||||
if (action === GetValueAction.DO_NOTHING || action === GetValueAction.GET_ALARM_STATUS) {
|
||||
this.getValueSettingsFormGroup.get('dataToValue').disable({emitEvent: false});
|
||||
} else {
|
||||
this.getValueSettingsFormGroup.get('dataToValue').enable({emitEvent: false});
|
||||
@ -190,4 +203,6 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected readonly entityType = EntityType;
|
||||
}
|
||||
|
||||
@ -176,6 +176,9 @@ export class GetValueActionSettingsComponent implements OnInit, ControlValueAcce
|
||||
case GetValueAction.GET_TIME_SERIES:
|
||||
this.displayValue = this.translate.instant('widgets.value-action.get-time-series-text', {key: this.modelValue.getTimeSeries.key});
|
||||
break;
|
||||
case GetValueAction.GET_ALARM_STATUS:
|
||||
this.displayValue = this.translate.instant('widgets.value-action.get-alarm-status-text');
|
||||
break;
|
||||
case GetValueAction.GET_DASHBOARD_STATE:
|
||||
if (this.valueType === ValueType.BOOLEAN) {
|
||||
const state = this.modelValue.dataToValue?.compareToValue;
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
import { Component, Injector } from '@angular/core';
|
||||
import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models';
|
||||
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { formatValue } from '@core/utils';
|
||||
@ -88,7 +88,7 @@ export class SignalStrengthWidgetSettingsComponent extends WidgetSettingsCompone
|
||||
|
||||
background: [settings.background, []],
|
||||
padding: [settings.padding, []],
|
||||
noSignalRssiValue: [settings.noSignalRssiValue, []]
|
||||
noSignalRssiValue: [settings.noSignalRssiValue, [Validators.max(-86)]]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -16,12 +16,14 @@
|
||||
|
||||
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
|
||||
import { widgetType } from '@shared/models/widget.models';
|
||||
import { AlarmSeverity } from '@shared/models/alarm.models';
|
||||
|
||||
export enum GetValueAction {
|
||||
DO_NOTHING = 'DO_NOTHING',
|
||||
EXECUTE_RPC = 'EXECUTE_RPC',
|
||||
GET_ATTRIBUTE = 'GET_ATTRIBUTE',
|
||||
GET_TIME_SERIES = 'GET_TIME_SERIES',
|
||||
GET_ALARM_STATUS = 'GET_ALARM_STATUS',
|
||||
GET_DASHBOARD_STATE = 'GET_DASHBOARD_STATE'
|
||||
}
|
||||
|
||||
@ -41,6 +43,7 @@ export const getValueActionTranslations = new Map<GetValueAction, string>(
|
||||
[GetValueAction.EXECUTE_RPC, 'widgets.value-action.execute-rpc'],
|
||||
[GetValueAction.GET_ATTRIBUTE, 'widgets.value-action.get-attribute'],
|
||||
[GetValueAction.GET_TIME_SERIES, 'widgets.value-action.get-time-series'],
|
||||
[GetValueAction.GET_ALARM_STATUS, 'widgets.value-action.get-alarm-status'],
|
||||
[GetValueAction.GET_DASHBOARD_STATE, 'widgets.value-action.get-dashboard-state']
|
||||
]
|
||||
);
|
||||
@ -52,6 +55,11 @@ export interface RpcSettings {
|
||||
persistentPollingInterval: number;
|
||||
}
|
||||
|
||||
export interface AlarmStatusSettings {
|
||||
severityList: Array<AlarmSeverity>;
|
||||
typeList: Array<string>;
|
||||
}
|
||||
|
||||
export interface TelemetryValueSettings {
|
||||
key: string;
|
||||
}
|
||||
@ -85,6 +93,7 @@ export interface GetValueSettings<V> extends ValueActionSettings {
|
||||
executeRpc?: RpcSettings;
|
||||
getAttribute: GetAttributeValueSettings;
|
||||
getTimeSeries: TelemetryValueSettings;
|
||||
getAlarmStatus: AlarmStatusSettings;
|
||||
dataToValue: DataToValueSettings;
|
||||
}
|
||||
|
||||
|
||||
@ -33,9 +33,9 @@ import {
|
||||
TsValue
|
||||
} from '@shared/models/query/query.models';
|
||||
import { PageData } from '@shared/models/page/page-data';
|
||||
import { alarmFields } from '@shared/models/alarm.models';
|
||||
import { alarmFields, AlarmSeverity } from '@shared/models/alarm.models';
|
||||
import { entityFields } from '@shared/models/entity.models';
|
||||
import { isDefinedAndNotNull, isUndefined } from '@core/utils';
|
||||
import { deepClone, isDefinedAndNotNull, isUndefined } from '@core/utils';
|
||||
import { CmdWrapper, WsService, WsSubscriber } from '@shared/models/websocket/websocket.models';
|
||||
import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service';
|
||||
import { Notification, NotificationType } from '@shared/models/notification.models';
|
||||
@ -141,6 +141,7 @@ export enum WsCmdType {
|
||||
ENTITY_COUNT = 'ENTITY_COUNT',
|
||||
ALARM_DATA = 'ALARM_DATA',
|
||||
ALARM_COUNT = 'ALARM_COUNT',
|
||||
ALARM_STATUS = 'ALARM_STATUS',
|
||||
|
||||
NOTIFICATIONS = 'NOTIFICATIONS',
|
||||
NOTIFICATIONS_COUNT = 'NOTIFICATIONS_COUNT',
|
||||
@ -149,6 +150,7 @@ export enum WsCmdType {
|
||||
|
||||
ALARM_DATA_UNSUBSCRIBE = 'ALARM_DATA_UNSUBSCRIBE',
|
||||
ALARM_COUNT_UNSUBSCRIBE = 'ALARM_COUNT_UNSUBSCRIBE',
|
||||
ALARM_STATUS_UNSUBSCRIBE = 'ALARM_STATUS_UNSUBSCRIBE',
|
||||
ENTITY_DATA_UNSUBSCRIBE = 'ENTITY_DATA_UNSUBSCRIBE',
|
||||
ENTITY_COUNT_UNSUBSCRIBE = 'ENTITY_COUNT_UNSUBSCRIBE',
|
||||
NOTIFICATIONS_UNSUBSCRIBE = 'NOTIFICATIONS_UNSUBSCRIBE'
|
||||
@ -298,6 +300,14 @@ export class AlarmCountCmd implements WebsocketCmd {
|
||||
type = WsCmdType.ALARM_COUNT;
|
||||
}
|
||||
|
||||
export class AlarmStatusCmd implements WebsocketCmd {
|
||||
cmdId: number;
|
||||
originatorId: EntityId;
|
||||
severityList?: Array<AlarmSeverity>;
|
||||
typeList?: Array<string>;
|
||||
type = WsCmdType.ALARM_STATUS;
|
||||
}
|
||||
|
||||
export class UnreadCountSubCmd implements WebsocketCmd {
|
||||
cmdId: number;
|
||||
type = WsCmdType.NOTIFICATIONS_COUNT;
|
||||
@ -352,6 +362,11 @@ export class AlarmCountUnsubscribeCmd implements WebsocketCmd {
|
||||
type = WsCmdType.ALARM_COUNT_UNSUBSCRIBE;
|
||||
}
|
||||
|
||||
export class AlarmStatusUnsubscribeCmd implements WebsocketCmd {
|
||||
cmdId: number;
|
||||
type = WsCmdType.ALARM_STATUS_UNSUBSCRIBE;
|
||||
}
|
||||
|
||||
export class UnsubscribeCmd implements WebsocketCmd {
|
||||
cmdId: number;
|
||||
type = WsCmdType.NOTIFICATIONS_UNSUBSCRIBE;
|
||||
@ -432,6 +447,7 @@ export enum CmdUpdateType {
|
||||
ENTITY_DATA = 'ENTITY_DATA',
|
||||
ALARM_DATA = 'ALARM_DATA',
|
||||
ALARM_COUNT_DATA = 'ALARM_COUNT_DATA',
|
||||
ALARM_STATUS = 'ALARM_STATUS',
|
||||
COUNT_DATA = 'COUNT_DATA',
|
||||
NOTIFICATIONS_COUNT = 'NOTIFICATIONS_COUNT',
|
||||
NOTIFICATIONS = 'NOTIFICATIONS'
|
||||
@ -469,6 +485,11 @@ export interface AlarmCountUpdateMsg extends CmdUpdateMsg {
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface AlarmStatusUpdateMsg extends CmdUpdateMsg {
|
||||
cmdUpdateType: CmdUpdateType.ALARM_STATUS;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export interface NotificationCountUpdateMsg extends CmdUpdateMsg {
|
||||
cmdUpdateType: CmdUpdateType.NOTIFICATIONS_COUNT;
|
||||
totalUnreadCount: number;
|
||||
@ -506,6 +527,11 @@ export const isAlarmCountUpdateMsg = (message: WebsocketDataMsg): message is Ala
|
||||
return updateMsg.cmdId !== undefined && updateMsg.cmdUpdateType === CmdUpdateType.ALARM_COUNT_DATA;
|
||||
};
|
||||
|
||||
export const isAlarmStatusUpdateMsg = (message: WebsocketDataMsg): message is AlarmCountUpdateMsg => {
|
||||
const updateMsg = (message as CmdUpdateMsg);
|
||||
return updateMsg.cmdId !== undefined && updateMsg.cmdUpdateType === CmdUpdateType.ALARM_STATUS;
|
||||
};
|
||||
|
||||
export const isNotificationCountUpdateMsg = (message: WebsocketDataMsg): message is NotificationCountUpdateMsg => {
|
||||
const updateMsg = (message as CmdUpdateMsg);
|
||||
return updateMsg.cmdId !== undefined && updateMsg.cmdUpdateType === CmdUpdateType.NOTIFICATIONS_COUNT;
|
||||
@ -705,6 +731,15 @@ export class AlarmCountUpdate extends CmdUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
export class AlarmStatusUpdate extends CmdUpdate {
|
||||
active: boolean;
|
||||
|
||||
constructor(msg: AlarmStatusUpdateMsg) {
|
||||
super(msg);
|
||||
this.active = msg.active;
|
||||
}
|
||||
}
|
||||
|
||||
export class NotificationCountUpdate extends CmdUpdate {
|
||||
totalUnreadCount: number;
|
||||
sequenceNumber: number;
|
||||
@ -750,14 +785,29 @@ export class SharedTelemetrySubscriber {
|
||||
return key;
|
||||
}
|
||||
|
||||
private static createAlarmStatusSubscriberKey (entityId: EntityId, severityList: AlarmSeverity[] = null, typeList: string[] = null): string {
|
||||
let key = entityId.entityType + '_' + entityId.id;
|
||||
if (severityList) {
|
||||
key += '_' + severityList.sort().join('_');
|
||||
}
|
||||
if (typeList) {
|
||||
key += '_' + typeList.sort().join('_');
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private subscribed = false;
|
||||
|
||||
private attributeDataSubject = connectable(this.sharedSubscriptionInfo.subscriber.attributeData$(),
|
||||
{ connector: () => new ReplaySubject<Array<AttributeData>>(1)});
|
||||
|
||||
private alarmStatusSubject = connectable(this.sharedSubscriptionInfo.subscriber.alarmStatus$,
|
||||
{ connector: () => new ReplaySubject<AlarmStatusUpdate>()});
|
||||
|
||||
private subscriptions = new Array<Subscription>();
|
||||
|
||||
public attributeData$: Observable<Array<AttributeData>> = this.attributeDataSubject; //this.attributeDataSubject.asObservable();
|
||||
public alarmStatus$: Observable<AlarmStatusUpdate> = this.alarmStatusSubject;
|
||||
|
||||
public static createEntityAttributesSubscription(telemetryService: TelemetryWebsocketService,
|
||||
entityId: EntityId, attributeScope: TelemetryType,
|
||||
@ -781,6 +831,28 @@ export class SharedTelemetrySubscriber {
|
||||
return sharedSubscriber;
|
||||
}
|
||||
|
||||
public static createAlarmStatusSubscription(telemetryService: TelemetryWebsocketService,
|
||||
entityId: EntityId, zone: NgZone, severityList: AlarmSeverity[] = null,
|
||||
typeList: string[] = null): SharedTelemetrySubscriber {
|
||||
const key = SharedTelemetrySubscriber.createAlarmStatusSubscriberKey(entityId, severityList, typeList);
|
||||
let info = SharedTelemetrySubscriber.subscribersCache[key];
|
||||
if (!info) {
|
||||
const subscriber = TelemetrySubscriber.createAlarmStatusSubscription(
|
||||
telemetryService, entityId, zone, severityList, typeList
|
||||
);
|
||||
info = {
|
||||
key,
|
||||
subscriber,
|
||||
subscribed: false,
|
||||
sharedSubscribers: new Set<SharedTelemetrySubscriber>()
|
||||
};
|
||||
SharedTelemetrySubscriber.subscribersCache[key] = info;
|
||||
}
|
||||
const sharedSubscriber = new SharedTelemetrySubscriber(info);
|
||||
info.sharedSubscribers.add(sharedSubscriber);
|
||||
return sharedSubscriber;
|
||||
}
|
||||
|
||||
private constructor(private sharedSubscriptionInfo: SharedSubscriptionInfo) {
|
||||
}
|
||||
|
||||
@ -788,6 +860,7 @@ export class SharedTelemetrySubscriber {
|
||||
if (!this.subscribed) {
|
||||
this.subscribed = true;
|
||||
this.subscriptions.push(this.attributeDataSubject.connect());
|
||||
this.subscriptions.push(this.alarmStatusSubject.connect());
|
||||
if (!this.sharedSubscriptionInfo.subscribed) {
|
||||
this.sharedSubscriptionInfo.subscriber.subscribe();
|
||||
this.sharedSubscriptionInfo.subscribed = true;
|
||||
@ -823,6 +896,7 @@ export class TelemetrySubscriber extends WsSubscriber {
|
||||
private alarmDataSubject = new ReplaySubject<AlarmDataUpdate>(1);
|
||||
private entityCountSubject = new ReplaySubject<EntityCountUpdate>(1);
|
||||
private alarmCountSubject = new ReplaySubject<AlarmCountUpdate>(1);
|
||||
private alarmStatusSubject = new ReplaySubject<AlarmStatusUpdate>(1);
|
||||
private tsOffset = undefined;
|
||||
|
||||
public data$ = this.dataSubject.asObservable();
|
||||
@ -830,6 +904,7 @@ export class TelemetrySubscriber extends WsSubscriber {
|
||||
public alarmData$ = this.alarmDataSubject.asObservable();
|
||||
public entityCount$ = this.entityCountSubject.asObservable();
|
||||
public alarmCount$ = this.alarmCountSubject.asObservable();
|
||||
public alarmStatus$ = this.alarmStatusSubject.asObservable();
|
||||
|
||||
public static createEntityAttributesSubscription(telemetryService: TelemetryWebsocketService,
|
||||
entityId: EntityId, attributeScope: TelemetryType,
|
||||
@ -851,6 +926,17 @@ export class TelemetrySubscriber extends WsSubscriber {
|
||||
return subscriber;
|
||||
}
|
||||
|
||||
public static createAlarmStatusSubscription(telemetryService: TelemetryWebsocketService, entityId: EntityId,
|
||||
zone: NgZone, severityList: AlarmSeverity[] = null, typeList: string[] = null): TelemetrySubscriber {
|
||||
const subscriptionCommand = new AlarmStatusCmd();
|
||||
subscriptionCommand.originatorId = deepClone(entityId);
|
||||
subscriptionCommand.severityList = severityList;
|
||||
subscriptionCommand.typeList = typeList;
|
||||
const subscriber = new TelemetrySubscriber(telemetryService, zone);
|
||||
subscriber.subscriptionCommands.push(subscriptionCommand);
|
||||
return subscriber;
|
||||
}
|
||||
|
||||
public static createEntityFilterLatestSubscription(telemetryService: TelemetryWebsocketService,
|
||||
entityFilter: EntityFilter, zone: NgZone,
|
||||
latestKeys: EntityKey[] = null): TelemetrySubscriber {
|
||||
@ -882,6 +968,7 @@ export class TelemetrySubscriber extends WsSubscriber {
|
||||
this.alarmDataSubject.complete();
|
||||
this.entityCountSubject.complete();
|
||||
this.alarmCountSubject.complete();
|
||||
this.alarmStatusSubject.complete();
|
||||
super.complete();
|
||||
}
|
||||
|
||||
@ -971,6 +1058,18 @@ export class TelemetrySubscriber extends WsSubscriber {
|
||||
}
|
||||
}
|
||||
|
||||
public onAlarmStatus(message: AlarmStatusUpdate) {
|
||||
if (this.zone) {
|
||||
this.zone.run(
|
||||
() => {
|
||||
this.alarmStatusSubject.next(message);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.alarmStatusSubject.next(message);
|
||||
}
|
||||
}
|
||||
|
||||
public attributeData$(): Observable<Array<AttributeData>> {
|
||||
const attributeData = new Array<AttributeData>();
|
||||
return this.data$.pipe(
|
||||
|
||||
@ -21,4 +21,4 @@ For example, we have a device that has the following IP address: 192.168.0.120:5
|
||||
|
||||
4. Allow any devices:
|
||||
|
||||
**Address filter:** *:*
|
||||
**Address filter:** `*:*`
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
# Report Strategy for Data Transmission
|
||||
|
||||
This section allows you to configure the strategy for sending data. You can select one of the following behaviors:
|
||||
|
||||
1. **On Report Period** - Data is collected and sent at regular intervals, defined in milliseconds.
|
||||
|
||||
2. **On Value Change** - Data is transmitted immediately whenever a change is detected.
|
||||
|
||||
3. **On Value Change or Report Period** - Data is sent either when a change occurs or after a specified time period has elapsed since the last transmission.
|
||||
|
||||
4. **On Received** - Data is sent instantly upon being received.
|
||||
@ -596,6 +596,7 @@
|
||||
"ack-time": "Acknowledged time",
|
||||
"clear-time": "Cleared time",
|
||||
"duration": "Duration",
|
||||
"alarm-severity": "Alarm severity",
|
||||
"alarm-severity-list": "Alarm severity list",
|
||||
"any-severity": "Any severity",
|
||||
"severity-critical": "Critical",
|
||||
@ -634,6 +635,7 @@
|
||||
"fetch-size": "Fetch size",
|
||||
"fetch-size-required": "Fetch size is required.",
|
||||
"fetch-size-error-min": "Minimum value is 10.",
|
||||
"alarm-types": "Alarm types",
|
||||
"alarm-type-list": "Alarm type list",
|
||||
"any-type": "Any type",
|
||||
"assigned-to-current-user": "Assigned to current user",
|
||||
@ -7352,11 +7354,12 @@
|
||||
"get-attribute": "Get attribute",
|
||||
"set-attribute": "Set attribute",
|
||||
"get-time-series": "Get time series",
|
||||
"get-alarm-status": "Get alarm status",
|
||||
"get-dashboard-state": "Get dashboard state",
|
||||
"add-time-series": "Add time series",
|
||||
"execute-rpc-text": "Execute RPC method '{{methodName}}'",
|
||||
"get-attribute-text": "Use attribute '{{key}}'",
|
||||
"get-time-series-text": "Use time series '{{key}}'",
|
||||
"get-alarm-status-text": "Use alarm status",
|
||||
"get-dashboard-state-text": "Use dashboard state",
|
||||
"when-dashboard-state-is-text": "When dashboard state is '{{state}}'",
|
||||
"when-dashboard-state-function-is-text": "When f(dashboard state) is '{{state}}'",
|
||||
@ -7660,31 +7663,31 @@
|
||||
"language": {
|
||||
"language": "Language",
|
||||
"locales": {
|
||||
"ar_AE": "اَلْعَرَبِيَّةُ",
|
||||
"ca_ES": "Catalan",
|
||||
"cs_CZ": "Česky",
|
||||
"da_DK": "Dansk",
|
||||
"de_DE": "Deutsch",
|
||||
"el_GR": "Ελληνικά",
|
||||
"en_US": "English",
|
||||
"es_ES": "Español",
|
||||
"fa_IR": "فارسي",
|
||||
"fr_FR": "Français",
|
||||
"it_IT": "Italiano",
|
||||
"ja_JP": "日本語",
|
||||
"ka_GE": "ქართული",
|
||||
"ko_KR": "한국어",
|
||||
"lt_LT": "Lietuvių",
|
||||
"lv_LV": "Latviešu",
|
||||
"nl_BE": "Koninkrijk België",
|
||||
"pl_PL": "Polski",
|
||||
"pt_BR": "Português do Brasil",
|
||||
"ro_RO": "Română",
|
||||
"sl_SI": "Slovenščina",
|
||||
"tr_TR": "Türkçe",
|
||||
"uk_UA": "Українська",
|
||||
"zh_CN": "简体中文",
|
||||
"zh_TW": "繁體中文"
|
||||
"ar_AE": "العربية (الإمارات العربية المتحدة)",
|
||||
"ca_ES": "català (Espanya)",
|
||||
"cs_CZ": "čeština (Česko)",
|
||||
"da_DK": "dansk (Danmark)",
|
||||
"de_DE": "Deutsch (Deutschland)",
|
||||
"el_GR": "Ελληνικά (Ελλάδα)",
|
||||
"en_US": "English (United States)",
|
||||
"es_ES": "español (España)",
|
||||
"fa_IR": "فارسی (ایران)",
|
||||
"fr_FR": "français (France)",
|
||||
"it_IT": "italiano (Italia)",
|
||||
"ja_JP": "日本語 (日本)",
|
||||
"ka_GE": "ქართული (საქართველო)",
|
||||
"ko_KR": "한국어 (대한민국)",
|
||||
"lt_LT": "lietuvių (Lietuva)",
|
||||
"lv_LV": "latviešu (Latvija)",
|
||||
"nl_BE": "Nederlands (België)",
|
||||
"pl_PL": "polski (Polska)",
|
||||
"pt_BR": "português (Brasil)",
|
||||
"ro_RO": "română (România)",
|
||||
"sl_SI": "slovenščina (Slovenija)",
|
||||
"tr_TR": "Türkçe (Türkiye)",
|
||||
"uk_UA": "українська (Україна)",
|
||||
"zh_CN": "中文 (中国)",
|
||||
"zh_TW": "中文 (台灣)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||