diff --git a/application/src/main/data/json/system/scada_symbols/leak-sensor.svg b/application/src/main/data/json/system/scada_symbols/leak-sensor.svg
new file mode 100644
index 0000000000..506385d7fb
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/leak-sensor.svg
@@ -0,0 +1,158 @@
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/left-analog-water-level-meter.svg b/application/src/main/data/json/system/scada_symbols/left-analog-water-level-meter.svg
new file mode 100644
index 0000000000..ae02548602
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/left-analog-water-level-meter.svg
@@ -0,0 +1,679 @@
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/right-analog-water-level-meter.svg b/application/src/main/data/json/system/scada_symbols/right-analog-water-level-meter.svg
new file mode 100644
index 0000000000..8658a6dc3e
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/right-analog-water-level-meter.svg
@@ -0,0 +1,679 @@
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/scada_symbols/stand-filter.svg b/application/src/main/data/json/system/scada_symbols/stand-filter.svg
index 87d578605d..ebd1e28edd 100644
--- a/application/src/main/data/json/system/scada_symbols/stand-filter.svg
+++ b/application/src/main/data/json/system/scada_symbols/stand-filter.svg
@@ -7,7 +7,7 @@
],
"widgetSizeX": 3,
"widgetSizeY": 5,
- "stateRenderFunction": "",
+ "stateRenderFunction": "var running = ctx.values.running;\nif (running) {\n ctx.api.enable(svg.children());\n} else {\n ctx.api.disable(svg.children());\n}",
"tags": [
{
"tag": "background",
@@ -25,7 +25,7 @@
},
{
"tag": "filterMode",
- "stateRenderFunction": "var defaultBorderColor = ctx.properties.defaultBorderColor;\nvar activeBorderColor = ctx.properties.activeBorderColor;\nvar defaultLabelColor = ctx.properties.defaultLabelColor;\nvar activeLabelColor = ctx.properties.activeLabelColor;\nvar boxBackground = ctx.properties.modeBoxBackground;\n\nvar running = ctx.values.running;\nvar filtrationMode = ctx.values.filtrationMode;\n\nvar filtrationMap = {};\nvar bottomShift = 104;\nvar rightShift = 226;\nvar middleShift = 121;\n\nvar filterModeSet = element.remember('filterModeSet');\n\nif (!filterModeSet) {\n element.remember('filterModeSet', true);\n var clone = element.children()[0];\n setFilterModeColors(clone);\n element.clear();\n \n var i = 0;\n if (ctx.properties.filtrationMode) {\n i++;\n filtrationMap[i] = 'filter';\n }\n if (ctx.properties.wasteMode) {\n i++;\n filtrationMap[i] = 'waste';\n }\n if (ctx.properties.backwashMode) {\n i++;\n filtrationMap[i] = 'backwash';\n }\n if (ctx.properties.recirculateMode) {\n i++;\n filtrationMap[i] = 'recirculate';\n }\n if (ctx.properties.rinseMode) {\n i++;\n filtrationMap[i] = 'rinse';\n }\n if (ctx.properties.closedMode) {\n i++;\n filtrationMap[i] = 'closed';\n }\n \n var filterMode = Object.values(filtrationMap);\n var lastToMiddle = filterMode.length % 2;\n \n filterMode.forEach((mode, index, arr) => {\n var template = clone.clone();\n var x = (index % 2) * rightShift;\n var y = Math.floor((index % filterMode.length) / 2) * bottomShift;\n if (index === filterMode.length-1 && lastToMiddle) {\n x = middleShift;\n }\n template.attr({'class': mode}).css('cursor', 'pointer').translate(x, y);\n ctx.api.text(template.findOne('text'), capitalizeFirstLetter(mode));\n template.click((event) => click(event, getFilterModeKey(mode)));\n element.add(template);\n })\n if (isFinite(filtrationMode)) {\n setFilterModeColorsByMap(filtrationMode, running);\n }\n}\n\nif (running) {\n ctx.api.enable(element.children());\n} else {\n ctx.api.disable(element.children());\n}\n\nfunction click(event, index) {\n var filtrationMode = ctx.values.filtrationMode;\n if (ctx.values.running && isFinite(filtrationMode)) {\n ctx.api.disable(element.children());\n var newValue = +index;\n if (newValue === filtrationMode) {\n newValue = 0;\n } else {\n setFilterModeColorsByMap(filtrationMode);\n }\n ctx.api.setValue('filtrationMode', newValue);\n ctx.api.callAction(event, 'filtrationModeUpdateState', newValue, {\n next: () => {\n setFilterModeColorsByMap(newValue ? newValue: filtrationMode, newValue);\n ctx.api.enable(element.children());\n },\n error: () => {\n setFilterModeColorsByMap(newValue);\n ctx.api.setValue('filtrationMode', filtrationMode);\n }\n });\n }\n}\n\nfunction getFilterModeKey(value) {\n return Object.keys(filtrationMap).find(key => filtrationMap[key] === value);\n}\n\nfunction setFilterModeColorsByMap(mode, active = false) {\n var filterBox = element.findOne('g.'+filtrationMap[mode])\n if (filterBox) {\n return setFilterModeColors(filterBox, active);\n }\n}\n\nfunction setFilterModeColors(filterBox, active = false) {\n if (filterBox) {\n var borderColor = active ? activeBorderColor : defaultBorderColor;\n var labelColor = active ? activeLabelColor : defaultLabelColor;\n filterBox.children()[0].fill(boxBackground);\n filterBox.children()[1].stroke(borderColor);\n filterBox.children()[2].fill(borderColor);\n ctx.api.font(filterBox.findOne('text'), null, labelColor);\n }\n}\n\nfunction capitalizeFirstLetter(string) {\n return string.charAt(0).toUpperCase() + string.slice(1);\n}",
+ "stateRenderFunction": "var defaultBorderColor = ctx.properties.defaultBorderColor;\nvar activeBorderColor = ctx.properties.activeBorderColor;\nvar defaultLabelColor = ctx.properties.defaultLabelColor;\nvar activeLabelColor = ctx.properties.activeLabelColor;\nvar boxBackground = ctx.properties.modeBoxBackground;\n\nvar running = ctx.values.running;\nvar filtrationMode = ctx.values.filtrationMode;\n\nvar filtrationMap = {};\nvar bottomShift = 104;\nvar rightShift = 226;\nvar middleShift = 121;\n\nvar filterModeSet = element.remember('filterModeSet');\n\nvar i = 0;\nif (ctx.properties.filtrationMode) {\n i++;\n filtrationMap[i] = 'filter';\n}\nif (ctx.properties.wasteMode) {\n i++;\n filtrationMap[i] = 'waste';\n}\nif (ctx.properties.backwashMode) {\n i++;\n filtrationMap[i] = 'backwash';\n}\nif (ctx.properties.recirculateMode) {\n i++;\n filtrationMap[i] = 'recirculate';\n}\nif (ctx.properties.rinseMode) {\n i++;\n filtrationMap[i] = 'rinse';\n}\nif (ctx.properties.closedMode) {\n i++;\n filtrationMap[i] = 'closed';\n}\n\nif (!filterModeSet) {\n element.remember('filterModeSet', true);\n var clone = element.children()[0];\n setFilterModeColors(clone);\n element.clear();\n \n var filterMode = Object.values(filtrationMap);\n var lastToMiddle = filterMode.length % 2;\n \n filterMode.forEach((mode, index, arr) => {\n var template = clone.clone();\n var x = (index % 2) * rightShift;\n var y = Math.floor((index % filterMode.length) / 2) * bottomShift;\n if (index === filterMode.length-1 && lastToMiddle) {\n x = middleShift;\n }\n template.attr({'class': mode}).css('cursor', 'pointer').translate(x, y);\n ctx.api.text(template.findOne('text'), capitalizeFirstLetter(mode));\n template.click((event) => click(event, getFilterModeKey(mode)));\n element.add(template);\n })\n}\n\nif (isFinite(filtrationMode)) {\n if (element.findOne('.active')) {\n setFilterModeColors(element.findOne('.active'));\n }\n setFilterModeColorsByMap(filtrationMode, running);\n}\n\nfunction click(event, index) {\n var filtrationMode = ctx.values.filtrationMode;\n if (ctx.values.running && isFinite(filtrationMode)) {\n ctx.api.disable(element.children());\n var newValue = +index;\n if (newValue === filtrationMode) {\n newValue = 0;\n } else {\n setFilterModeColorsByMap(filtrationMode);\n }\n ctx.api.setValue('filtrationMode', newValue);\n ctx.api.callAction(event, 'filtrationModeUpdateState', newValue, {\n next: () => {\n setFilterModeColorsByMap(newValue ? newValue: filtrationMode, newValue);\n ctx.api.enable(element.children());\n },\n error: () => {\n setFilterModeColorsByMap(newValue);\n ctx.api.setValue('filtrationMode', filtrationMode);\n ctx.api.enable(element.children());\n }\n });\n }\n}\n\nfunction getFilterModeKey(value) {\n return Object.keys(filtrationMap).find(key => filtrationMap[key] === value);\n}\n\nfunction setFilterModeColorsByMap(mode, active = false) {\n var filterBox = element.findOne('g.'+filtrationMap[mode])\n if (filterBox) {\n return setFilterModeColors(filterBox, active);\n }\n}\n\nfunction setFilterModeColors(filterBox, active = false) {\n if (filterBox) {\n if (active) {\n filterBox.addClass('active');\n } else {\n filterBox.removeClass('active');\n }\n var borderColor = active ? activeBorderColor : defaultBorderColor;\n var labelColor = active ? activeLabelColor : defaultLabelColor;\n filterBox.children()[0].fill(boxBackground);\n filterBox.children()[1].stroke(borderColor);\n filterBox.children()[2].fill(borderColor);\n ctx.api.font(filterBox.findOne('text'), null, labelColor);\n }\n}\n\nfunction capitalizeFirstLetter(string) {\n return string.charAt(0).toUpperCase() + string.slice(1);\n}",
"actions": null
}
],
@@ -159,7 +159,7 @@
"id": "filtrationMode",
"name": "{i18n:scada.symbol.filter-mode}",
"type": "switch",
- "default": false,
+ "default": true,
"required": null,
"subLabel": null,
"divider": null,
@@ -175,7 +175,7 @@
"id": "wasteMode",
"name": "{i18n:scada.symbol.waste-mode}",
"type": "switch",
- "default": false,
+ "default": true,
"required": null,
"subLabel": null,
"divider": null,
@@ -191,7 +191,7 @@
"id": "backwashMode",
"name": "{i18n:scada.symbol.backwash-mode}",
"type": "switch",
- "default": false,
+ "default": true,
"required": null,
"subLabel": null,
"divider": null,
@@ -207,7 +207,7 @@
"id": "recirculateMode",
"name": "{i18n:scada.symbol.recirculate-mode}",
"type": "switch",
- "default": false,
+ "default": true,
"required": null,
"subLabel": null,
"divider": null,
@@ -223,7 +223,7 @@
"id": "rinseMode",
"name": "{i18n:scada.symbol.rinse-mode}",
"type": "switch",
- "default": false,
+ "default": true,
"required": null,
"subLabel": null,
"divider": null,
@@ -239,7 +239,7 @@
"id": "closedMode",
"name": "{i18n:scada.symbol.closed-mode}",
"type": "switch",
- "default": false,
+ "default": true,
"required": null,
"subLabel": null,
"divider": null,
diff --git a/application/src/main/data/json/system/scada_symbols/waterstop.svg b/application/src/main/data/json/system/scada_symbols/waterstop.svg
new file mode 100644
index 0000000000..e3fb963d71
--- /dev/null
+++ b/application/src/main/data/json/system/scada_symbols/waterstop.svg
@@ -0,0 +1,276 @@
+
\ No newline at end of file
diff --git a/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json b/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json
index 6f0edcd02f..22575e0697 100644
--- a/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json
+++ b/application/src/main/data/json/system/widget_bundles/scada_water_system_symbols.json
@@ -34,6 +34,9 @@
"left_flow_meter",
"horizontal_inline_flow_meter",
"vertical_inline_flow_meter",
+ "left_analog_water_level_meter",
+ "right_analog_water_level_meter",
+ "leak_sensor",
"centrifugal_pump",
"small_right_motor_pump",
"small_left_motor_pump",
@@ -50,6 +53,7 @@
"vertical_wheel_valve",
"horizontal_ball_valve",
"vertical_ball_valve",
+ "water_stop",
"vertical_tank",
"stand_vertical_tank",
"cylindrical_tank",
diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
index d188111cc3..7f7b1f699f 100644
--- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
+++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
@@ -273,13 +273,13 @@ public class TbUtils {
Long.class, boolean.class, boolean.class)));
parserConfig.addImport("longToHex", new MethodStub(TbUtils.class.getMethod("longToHex",
Long.class, boolean.class, boolean.class, int.class)));
- parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
+ parserConfig.addImport("intLongToRadixString", new MethodStub(TbUtils.class.getMethod("intLongToRadixString",
Long.class)));
- parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
+ parserConfig.addImport("intLongToRadixString", new MethodStub(TbUtils.class.getMethod("intLongToRadixString",
Long.class, int.class)));
- parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
+ parserConfig.addImport("intLongToRadixString", new MethodStub(TbUtils.class.getMethod("intLongToRadixString",
Long.class, int.class, boolean.class)));
- parserConfig.addImport("intLongToString", new MethodStub(TbUtils.class.getMethod("intLongToString",
+ parserConfig.addImport("intLongToRadixString", new MethodStub(TbUtils.class.getMethod("intLongToRadixString",
Long.class, int.class, boolean.class, boolean.class)));
parserConfig.addImport("floatToHex", new MethodStub(TbUtils.class.getMethod("floatToHex",
Float.class)));
@@ -315,8 +315,6 @@ public class TbUtils {
String.class)));
parserConfig.addImport("decodeURI", new MethodStub(TbUtils.class.getMethod("decodeURI",
String.class)));
- parserConfig.addImport("raiseError", new MethodStub(TbUtils.class.getMethod("raiseError",
- String.class, Object.class)));
parserConfig.addImport("raiseError", new MethodStub(TbUtils.class.getMethod("raiseError",
String.class)));
parserConfig.addImport("isBinary", new MethodStub(TbUtils.class.getMethod("isBinary",
@@ -327,7 +325,7 @@ public class TbUtils {
String.class)));
parserConfig.addImport("isHexadecimal", new MethodStub(TbUtils.class.getMethod("isHexadecimal",
String.class)));
- parserConfig.addImport("byteArrayToExecutionArrayList", new MethodStub(TbUtils.class.getMethod("bytesToExecutionArrayList",
+ parserConfig.addImport("bytesToExecutionArrayList", new MethodStub(TbUtils.class.getMethod("bytesToExecutionArrayList",
ExecutionContext.class, byte[].class)));
parserConfig.addImport("padStart", new MethodStub(TbUtils.class.getMethod("padStart",
String.class, int.class, char.class)));
@@ -725,19 +723,19 @@ public class TbUtils {
return prepareNumberHexString(l, bigEndian, pref, len, HEX_LEN_LONG_MAX);
}
- public static String intLongToString(Long number) {
- return intLongToString(number, DEC_RADIX);
+ public static String intLongToRadixString(Long number) {
+ return intLongToRadixString(number, DEC_RADIX);
}
- public static String intLongToString(Long number, int radix) {
- return intLongToString(number, radix, true);
+ public static String intLongToRadixString(Long number, int radix) {
+ return intLongToRadixString(number, radix, true);
}
- public static String intLongToString(Long number, int radix, boolean bigEndian) {
- return intLongToString(number, radix, bigEndian, false);
+ public static String intLongToRadixString(Long number, int radix, boolean bigEndian) {
+ return intLongToRadixString(number, radix, bigEndian, false);
}
- public static String intLongToString(Long number, int radix, boolean bigEndian, boolean pref) {
+ public static String intLongToRadixString(Long number, int radix, boolean bigEndian, boolean pref) {
if (radix >= 25 && radix <= MAX_RADIX) {
return Long.toString(number, radix);
}
@@ -1150,12 +1148,7 @@ public class TbUtils {
}
public static void raiseError(String message) {
- raiseError(message, null);
- }
-
- public static void raiseError(String message, Object value) {
- String msg = value == null ? message : message + " for value " + value;
- throw new RuntimeException(msg);
+ throw new RuntimeException(message);
}
private static void parseRecursive(Object json, Map map, List excludeList, String path, boolean pathInKey) {
@@ -1344,8 +1337,8 @@ public class TbUtils {
* Writes the bit value to the appropriate location in the bins array, starting at the end of the array,
* to ensure proper alignment (highest bit to low end).
*/
- public static byte[] parseLongToBinaryArray(long longValue, int binsLength) {
- int len = Math.min(binsLength, BYTES_LEN_LONG_MAX * BIN_LEN_MAX);
+ public static byte[] parseLongToBinaryArray(long longValue, int binLength) {
+ int len = Math.min(binLength, BYTES_LEN_LONG_MAX * BIN_LEN_MAX);
byte[] bins = new byte[len];
for (int i = 0; i < len; i++) {
bins[len - 1 - i] = (byte) ((longValue >> i) & 1);
diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java
index 0c22f62f1f..b7276edd8d 100644
--- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java
+++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java
@@ -19,6 +19,7 @@ import com.google.common.collect.Lists;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Ints;
import lombok.extern.slf4j.Slf4j;
+import org.checkerframework.checker.units.qual.A;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@@ -330,8 +331,8 @@ public class TbUtilsTest {
@Test
public void parseBytesIntToFloat() {
byte[] intValByte = {0x00, 0x00, 0x00, 0x0A};
- Float valueExpected = 10.0f;
- Float valueActual = TbUtils.parseBytesIntToFloat(intValByte, 3, 1, true);
+ float valueExpected = 10.0f;
+ float valueActual = TbUtils.parseBytesIntToFloat(intValByte, 3, 1, true);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseBytesIntToFloat(intValByte, 3, 1, false);
Assertions.assertEquals(valueExpected, valueActual);
@@ -345,20 +346,23 @@ public class TbUtilsTest {
valueExpected = 10.0f;
valueActual = TbUtils.parseBytesIntToFloat(intValByte, 0, 4, true);
Assertions.assertEquals(valueExpected, valueActual);
- valueExpected = 1.6777216E8f;
- valueActual = TbUtils.parseBytesIntToFloat(intValByte, 0, 4, false);
+ valueExpected = 167772.16f;
+ double factor = 1e3;
+ valueActual = (float) (TbUtils.parseBytesIntToFloat(intValByte, 0, 4, false) / factor);
+
Assertions.assertEquals(valueExpected, valueActual);
String dataAT101 = "0x01756403671B01048836BF7701F000090722050000";
List byteAT101 = TbUtils.hexToBytes(ctx, dataAT101);
float latitudeExpected = 24.62495f;
int offset = 9;
- valueActual = TbUtils.parseBytesIntToFloat(byteAT101, offset, 4, false);
- Assertions.assertEquals(latitudeExpected, valueActual / 1000000);
+ factor = 1e6;
+ valueActual = (float) (TbUtils.parseBytesIntToFloat(byteAT101, offset, 4, false) / factor);
+ Assertions.assertEquals(latitudeExpected, valueActual);
float longitudeExpected = 118.030576f;
- valueActual = TbUtils.parseBytesIntToFloat(byteAT101, offset + 4, 4, false);
- Assertions.assertEquals(longitudeExpected, valueActual / 1000000);
+ valueActual = (float) (TbUtils.parseBytesIntToFloat(byteAT101, offset + 4, 4, false) / factor);
+ Assertions.assertEquals(longitudeExpected, valueActual);
valueExpected = 9.185175E8f;
valueActual = TbUtils.parseBytesIntToFloat(byteAT101, offset);
@@ -520,6 +524,18 @@ public class TbUtilsTest {
valueExpected = 7.2057594037927936E17d;
valueActual = TbUtils.parseBytesLongToDouble(longValByte, 0, 8, false);
Assertions.assertEquals(valueExpected, valueActual);
+
+ String dataPalacKiyv = "0x32D009423F23B300B0106E08D96B6C00";
+ List byteAT101 = TbUtils.hexToBytes(ctx, dataPalacKiyv);
+ double latitudeExpected = 50.422775429058610d;
+ int offset = 0;
+ double factor = 1e15;
+ valueActual = TbUtils.parseBytesLongToDouble(byteAT101, offset, 8, false);
+ Assertions.assertEquals(latitudeExpected, valueActual / factor);
+
+ double longitudeExpected = 30.517877378257072d;
+ valueActual = TbUtils.parseBytesLongToDouble(byteAT101, offset + 8, 8, false);
+ Assertions.assertEquals(longitudeExpected, valueActual / factor);
}
@Test
@@ -720,27 +736,27 @@ public class TbUtilsTest {
@Test
public void numberToString_Test() {
- Assertions.assertEquals("00111010", TbUtils.intLongToString(58L, MIN_RADIX));
- Assertions.assertEquals("0000000010011110", TbUtils.intLongToString(158L, MIN_RADIX));
- Assertions.assertEquals("00000000000000100000001000000001", TbUtils.intLongToString(131585L, MIN_RADIX));
- Assertions.assertEquals("0111111111111111111111111111111111111111111111111111111111111111", TbUtils.intLongToString(Long.MAX_VALUE, MIN_RADIX));
- Assertions.assertEquals("1000000000000000000000000000000000000000000000000000000000000001", TbUtils.intLongToString(-Long.MAX_VALUE, MIN_RADIX));
- Assertions.assertEquals("1111111111111111111111111111111111111111111111111111111110011010", TbUtils.intLongToString(-102L, MIN_RADIX));
- Assertions.assertEquals("1111111111111111111111111111111111111111111111111100110010011010", TbUtils.intLongToString(-13158L, MIN_RADIX));
- Assertions.assertEquals("777777777777777777777", TbUtils.intLongToString(Long.MAX_VALUE, 8));
- Assertions.assertEquals("1000000000000000000000", TbUtils.intLongToString(Long.MIN_VALUE, 8));
- Assertions.assertEquals("9223372036854775807", TbUtils.intLongToString(Long.MAX_VALUE));
- Assertions.assertEquals("-9223372036854775808", TbUtils.intLongToString(Long.MIN_VALUE));
- Assertions.assertEquals("3366", TbUtils.intLongToString(13158L, 16));
- Assertions.assertEquals("FFCC9A", TbUtils.intLongToString(-13158L, 16));
- Assertions.assertEquals("0xFFCC9A", TbUtils.intLongToString(-13158L, 16, true, true));
-
- Assertions.assertEquals("0x0400", TbUtils.intLongToString(1024L, 16, true, true));
- Assertions.assertNotEquals("400", TbUtils.intLongToString(1024L, 16));
- Assertions.assertEquals("0xFFFC00", TbUtils.intLongToString(-1024L, 16, true, true));
- Assertions.assertNotEquals("0xFC00", TbUtils.intLongToString(-1024L, 16, true, true));
-
- Assertions.assertEquals("hazelnut", TbUtils.intLongToString(1356099454469L, MAX_RADIX));
+ Assertions.assertEquals("00111010", TbUtils.intLongToRadixString(58L, MIN_RADIX));
+ Assertions.assertEquals("0000000010011110", TbUtils.intLongToRadixString(158L, MIN_RADIX));
+ Assertions.assertEquals("00000000000000100000001000000001", TbUtils.intLongToRadixString(131585L, MIN_RADIX));
+ Assertions.assertEquals("0111111111111111111111111111111111111111111111111111111111111111", TbUtils.intLongToRadixString(Long.MAX_VALUE, MIN_RADIX));
+ Assertions.assertEquals("1000000000000000000000000000000000000000000000000000000000000001", TbUtils.intLongToRadixString(-Long.MAX_VALUE, MIN_RADIX));
+ Assertions.assertEquals("1111111111111111111111111111111111111111111111111111111110011010", TbUtils.intLongToRadixString(-102L, MIN_RADIX));
+ Assertions.assertEquals("1111111111111111111111111111111111111111111111111100110010011010", TbUtils.intLongToRadixString(-13158L, MIN_RADIX));
+ Assertions.assertEquals("777777777777777777777", TbUtils.intLongToRadixString(Long.MAX_VALUE, 8));
+ Assertions.assertEquals("1000000000000000000000", TbUtils.intLongToRadixString(Long.MIN_VALUE, 8));
+ Assertions.assertEquals("9223372036854775807", TbUtils.intLongToRadixString(Long.MAX_VALUE));
+ Assertions.assertEquals("-9223372036854775808", TbUtils.intLongToRadixString(Long.MIN_VALUE));
+ Assertions.assertEquals("3366", TbUtils.intLongToRadixString(13158L, 16));
+ Assertions.assertEquals("FFCC9A", TbUtils.intLongToRadixString(-13158L, 16));
+ Assertions.assertEquals("0xFFCC9A", TbUtils.intLongToRadixString(-13158L, 16, true, true));
+
+ Assertions.assertEquals("0x0400", TbUtils.intLongToRadixString(1024L, 16, true, true));
+ Assertions.assertNotEquals("400", TbUtils.intLongToRadixString(1024L, 16));
+ Assertions.assertEquals("0xFFFC00", TbUtils.intLongToRadixString(-1024L, 16, true, true));
+ Assertions.assertNotEquals("0xFC00", TbUtils.intLongToRadixString(-1024L, 16, true, true));
+
+ Assertions.assertEquals("hazelnut", TbUtils.intLongToRadixString(1356099454469L, MAX_RADIX));
}
@Test
@@ -870,14 +886,16 @@ public class TbUtilsTest {
@Test
public void raiseError_Test() {
- String message = "frequency_weighting_type must be 0, 1 or 2.";
Object value = 4;
+ String message = "frequency_weighting_type must be 0, 1 or 2. A value of " + value.toString() + " is invalid.";
+
try {
- TbUtils.raiseError(message, value);
+ TbUtils.raiseError(message);
Assertions.fail("Should throw NumberFormatException");
} catch (RuntimeException e) {
- Assertions.assertTrue(e.getMessage().contains("frequency_weighting_type must be 0, 1 or 2. for value 4"));
+ Assertions.assertTrue(e.getMessage().contains("frequency_weighting_type must be 0, 1 or 2. A value of 4 is invalid."));
}
+ message = "frequency_weighting_type must be 0, 1 or 2.";
try {
TbUtils.raiseError(message);
Assertions.fail("Should throw NumberFormatException");
@@ -1067,6 +1085,18 @@ public class TbUtilsTest {
String actual = TbUtils.hexToBase64(hex);
Assertions.assertEquals(expected, actual);
}
+ @Test
+ public void bytesToHex_Test() {
+ byte[] bb = {(byte) 0xBB, (byte) 0xAA};
+ String expected = "BBAA";
+ String actual = TbUtils.bytesToHex(bb);
+ Assertions.assertEquals(expected, actual);
+ ExecutionArrayList expectedList = new ExecutionArrayList<>(ctx);
+ expectedList.addAll(List.of(-69, 83));
+ expected = "BB53";
+ actual = TbUtils.bytesToHex(expectedList);
+ Assertions.assertEquals(expected, actual);
+ }
private static List toList(byte[] data) {
List result = new ArrayList<>(data.length);
diff --git a/pom.xml b/pom.xml
index 09cf0393b7..aa2a50bc8b 100755
--- a/pom.xml
+++ b/pom.xml
@@ -83,7 +83,7 @@
3.9.2
3.25.3
1.63.0
- 1.2.2
+ 1.2.3
1.18.32
1.2.5
1.2.5
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 aaa51ea3dd..0d32107f8d 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -3835,6 +3835,8 @@
"open-hint": "Action invoked when user clicks to open component.",
"close": "Close",
"close-hint": "Action invoked when user clicks to close component.",
+ "close-state-animation": "Closed state animation",
+ "close-state-animation-hint": "Whether to enable blinking animation when component is in closed state.",
"opened-color": "Opened color",
"closed-color": "Closed color",
"opened-rotation-angle": "Opened rotation angle",
@@ -3880,7 +3882,14 @@
"stand-filter-color": "Stand filter color",
"mode-box-background": "Mode box background",
"border-color": "Border color",
- "label-color": "Label color"
+ "label-color": "Label color",
+ "water-leak-hint": "Indicates whether a leak.",
+ "default-color": "Default color",
+ "leak-color": "Leak color",
+ "full-value": "Full value",
+ "full-value-hint": "Double value indicating full value.",
+ "label": "Label",
+ "icon": "Icon"
}
},
"item": {