iobroker.nut2 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,150 @@
1
+ {
2
+ "tab_connection": "连接",
3
+ "tab_advanced": "高级",
4
+ "label_host": "NUT 服务器主机",
5
+ "help_host": "NUT 服务器的主机名或 IP 地址(例如 192.168.1.100)",
6
+ "label_port": "端口",
7
+ "label_networkInterface": "网络接口",
8
+ "tooltip_networkInterface": "选择用于传出连接的特定网络接口(可选)",
9
+ "label_pollInterval": "轮询间隔(秒)",
10
+ "help_pollInterval": "查询 NUT 服务器的频率(2–300 秒)",
11
+ "label_username": "用户名",
12
+ "help_username": "NUT 用户名(可选——发送命令和修改可写变量时需要)",
13
+ "label_password": "密码",
14
+ "btn_checkConnection": "测试连接",
15
+ "label_commandTimeout": "命令超时(秒)",
16
+ "help_commandTimeout": "单个 NUT 命令的超时时间(1–30 秒)",
17
+ "label_enableCommands": "启用即时命令",
18
+ "help_enableCommands": "允许向 UPS 发送即时命令 (INSTCMD)——需要身份验证",
19
+ "label_enableSetVar": "启用可写变量",
20
+ "help_enableSetVar": "允许更改 UPS 可写变量 (SET VAR)——需要身份验证",
21
+ "supportHeader": "支持",
22
+ "aboutInfo": "ioBroker.nut2 通过 Network UPS Tools (NUT) 协议监控 UPS 设备。连接到 NUT 服务器的所有 UPS 设备会被自动发现。",
23
+ "donateKofi": "在 Ko-fi 上支持",
24
+ "donatePaypal": "通过 PayPal 捐赠",
25
+ "channelInfo": "适配器信息",
26
+ "connectionStatus": "连接状态",
27
+ "channelBattery": "电池",
28
+ "channelDevice": "设备",
29
+ "channelDriver": "驱动程序",
30
+ "channelInput": "输入功率",
31
+ "channelOutput": "输出功率",
32
+ "channelUps": "UPS",
33
+ "channelOutlet": "插座",
34
+ "channelAmbient": "环境传感器",
35
+ "channelStatus": "状态标志",
36
+ "channelCommands": "命令",
37
+ "statusRaw": "原始状态",
38
+ "statusSeverity": "严重程度",
39
+ "statusDisplay": "状态显示",
40
+ "upsReachable": "可访问",
41
+ "channelUpsInfo": "信息",
42
+ "flagOnline": "市电供电",
43
+ "flagOnBattery": "使用电池",
44
+ "flagLowBattery": "电量低",
45
+ "flagHighBattery": "电量满",
46
+ "flagReplaceBattery": "更换电池",
47
+ "flagCharging": "充电中",
48
+ "flagDischarging": "放电中",
49
+ "flagBypass": "旁路激活",
50
+ "flagCalibrating": "校准中",
51
+ "flagOff": "关闭",
52
+ "flagOverloaded": "过载",
53
+ "flagTrimming": "削减电压",
54
+ "flagBoosting": "升压",
55
+ "flagForcedShutdown": "强制关机",
56
+ "flagAlarm": "警报",
57
+ "cmdBeeperDisable": "禁用蜂鸣器",
58
+ "cmdBeeperEnable": "启用蜂鸣器",
59
+ "cmdBeeperMute": "静音蜂鸣器",
60
+ "cmdLoadOff": "关闭负载",
61
+ "cmdLoadOn": "打开负载",
62
+ "cmdLoadOffDelay": "延时关闭负载",
63
+ "cmdLoadOnDelay": "延时打开负载",
64
+ "cmdShutdownReturn": "关机并恢复",
65
+ "cmdShutdownStayoff": "关机并保持关闭",
66
+ "cmdShutdownStop": "停止关机",
67
+ "cmdShutdownReboot": "重启UPS",
68
+ "cmdTestBatteryStart": "开始电池测试",
69
+ "cmdTestBatteryStop": "停止电池测试",
70
+ "cmdCalibrateStart": "开始校准",
71
+ "cmdCalibrateStop": "停止校准",
72
+ "battery.charge": "电量",
73
+ "battery.charge.low": "低电量阈值",
74
+ "battery.runtime": "剩余运行时间",
75
+ "battery.type": "电池类型",
76
+ "battery.voltage": "电池电压",
77
+ "battery.temperature": "电池温度",
78
+ "battery.capacity": "电池容量",
79
+ "battery.charger.status": "充电器状态",
80
+ "device.mfr": "制造商",
81
+ "device.model": "型号",
82
+ "device.serial": "序列号",
83
+ "device.type": "设备类型",
84
+ "driver.name": "驱动名称",
85
+ "driver.version": "驱动版本",
86
+ "driver.version.data": "驱动数据版本",
87
+ "driver.version.internal": "驱动内部版本",
88
+ "driver.parameter.pollfreq": "轮询频率",
89
+ "driver.parameter.pollinterval": "轮询间隔",
90
+ "driver.parameter.port": "端口",
91
+ "driver.parameter.synchronous": "同步模式",
92
+ "driver.flag.ignorelb": "忽略低电量",
93
+ "driver.version.usb": "USB库版本",
94
+ "input.voltage": "输入电压",
95
+ "input.frequency": "输入频率",
96
+ "input.transfer.high": "高转换电压",
97
+ "input.transfer.low": "低转换电压",
98
+ "input.voltage.extended": "扩展电压范围",
99
+ "output.voltage": "输出电压",
100
+ "output.frequency": "输出频率",
101
+ "output.voltage.nominal": "额定输出电压",
102
+ "output.frequency.nominal": "额定输出频率",
103
+ "output.current": "输出电流",
104
+ "ups.status": "UPS状态",
105
+ "ups.load": "负载",
106
+ "ups.power": "视在功率",
107
+ "ups.realpower": "有功功率",
108
+ "ups.power.nominal": "额定功率",
109
+ "ups.temperature": "UPS温度",
110
+ "ups.delay.shutdown": "关机延迟",
111
+ "ups.delay.start": "启动延迟",
112
+ "ups.timer.shutdown": "关机计时器",
113
+ "ups.timer.start": "启动计时器",
114
+ "ups.firmware": "固件版本",
115
+ "ups.beeper.status": "蜂鸣器状态",
116
+ "ups.mfr": "UPS制造商",
117
+ "ups.model": "UPS型号",
118
+ "ups.serial": "UPS序列号",
119
+ "ups.vendorid": "供应商ID",
120
+ "ups.productid": "产品ID",
121
+ "outlet.desc": "插座描述",
122
+ "outlet.id": "插座ID",
123
+ "outlet.switchable": "可切换",
124
+ "outlet.status": "插座状态",
125
+ "ambient.temperature": "环境温度",
126
+ "ambient.humidity": "环境湿度",
127
+ "flagWaiting": "等待中",
128
+ "flagEcoMode": "ECO 模式",
129
+ "label_useTls": "使用 TLS (STARTTLS)",
130
+ "help_useTls": "通过 STARTTLS 加密连接 — 发送用户名和密码时推荐启用",
131
+ "label_tlsRejectUnauthorized": "要求有效证书",
132
+ "help_tlsRejectUnauthorized": "拒绝自签名或无效证书。典型的自签名 NUT 服务器请保持关闭;启用以防范中间人攻击",
133
+ "cmdShutdownDefault": "默认关机",
134
+ "cmdShutdownRebootGraceful": "平稳重启",
135
+ "cmdTestPanelStart": "开始面板测试",
136
+ "cmdTestPanelStop": "停止面板测试",
137
+ "cmdTestFailureStart": "开始断电测试",
138
+ "cmdTestFailureStop": "停止断电测试",
139
+ "cmdTestBatteryStartQuick": "开始快速电池测试",
140
+ "cmdTestBatteryStartLow": "电池测试至低电量",
141
+ "cmdTestBatteryStartDeep": "开始深度电池测试",
142
+ "cmdTestSystemStart": "开始系统测试",
143
+ "cmdBypassStart": "切换到旁路模式",
144
+ "cmdBypassStop": "退出旁路模式",
145
+ "cmdResetInputMinmax": "重置输入最小/最大值",
146
+ "cmdResetWatchdog": "重置看门狗定时器",
147
+ "cmdBeeperToggle": "切换蜂鸣器",
148
+ "flagTesting": "测试中",
149
+ "flagOverheat": "过热"
150
+ }
@@ -0,0 +1,204 @@
1
+ {
2
+ "type": "tabs",
3
+ "i18n": true,
4
+ "items": {
5
+ "tab_connection": {
6
+ "type": "panel",
7
+ "label": "tab_connection",
8
+ "items": {
9
+ "host": {
10
+ "type": "text",
11
+ "label": "label_host",
12
+ "help": "help_host",
13
+ "placeholder": "192.168.1.100",
14
+ "xs": 12,
15
+ "sm": 12,
16
+ "md": 6,
17
+ "lg": 6,
18
+ "xl": 6
19
+ },
20
+ "port": {
21
+ "type": "number",
22
+ "label": "label_port",
23
+ "min": 1,
24
+ "max": 65535,
25
+ "default": 3493,
26
+ "xs": 12,
27
+ "sm": 12,
28
+ "md": 3,
29
+ "lg": 3,
30
+ "xl": 3
31
+ },
32
+ "pollInterval": {
33
+ "type": "number",
34
+ "label": "label_pollInterval",
35
+ "help": "help_pollInterval",
36
+ "min": 2,
37
+ "max": 300,
38
+ "default": 15,
39
+ "xs": 12,
40
+ "sm": 12,
41
+ "md": 3,
42
+ "lg": 3,
43
+ "xl": 3
44
+ },
45
+ "networkInterface": {
46
+ "newLine": true,
47
+ "type": "ip",
48
+ "label": "label_networkInterface",
49
+ "tooltip": "tooltip_networkInterface",
50
+ "onlyIp4": true,
51
+ "noInternal": true,
52
+ "listenOnAllPorts": true,
53
+ "xs": 12,
54
+ "sm": 12,
55
+ "md": 6,
56
+ "lg": 6,
57
+ "xl": 6
58
+ },
59
+ "username": {
60
+ "newLine": true,
61
+ "type": "text",
62
+ "label": "label_username",
63
+ "help": "help_username",
64
+ "xs": 12,
65
+ "sm": 12,
66
+ "md": 6,
67
+ "lg": 6,
68
+ "xl": 6
69
+ },
70
+ "password": {
71
+ "type": "password",
72
+ "label": "label_password",
73
+ "xs": 12,
74
+ "sm": 12,
75
+ "md": 6,
76
+ "lg": 6,
77
+ "xl": 6
78
+ },
79
+ "useTls": {
80
+ "newLine": true,
81
+ "type": "checkbox",
82
+ "label": "label_useTls",
83
+ "help": "help_useTls",
84
+ "default": false,
85
+ "xs": 12,
86
+ "sm": 12,
87
+ "md": 6,
88
+ "lg": 6,
89
+ "xl": 6
90
+ },
91
+ "tlsRejectUnauthorized": {
92
+ "type": "checkbox",
93
+ "label": "label_tlsRejectUnauthorized",
94
+ "help": "help_tlsRejectUnauthorized",
95
+ "default": false,
96
+ "hidden": "!data.useTls",
97
+ "xs": 12,
98
+ "sm": 12,
99
+ "md": 6,
100
+ "lg": 6,
101
+ "xl": 6
102
+ },
103
+ "checkConnection": {
104
+ "newLine": true,
105
+ "type": "sendTo",
106
+ "command": "checkConnection",
107
+ "jsonData": "{\"host\": \"${data.host}\", \"port\": ${data.port}, \"username\": \"${data.username}\", \"password\": \"${data.password}\", \"networkInterface\": \"${data.networkInterface}\", \"commandTimeout\": ${data.commandTimeout}, \"useTls\": ${data.useTls}, \"tlsRejectUnauthorized\": ${data.tlsRejectUnauthorized}}",
108
+ "label": "btn_checkConnection",
109
+ "xs": 12,
110
+ "sm": 12,
111
+ "md": 4,
112
+ "lg": 4,
113
+ "xl": 4
114
+ },
115
+ "_supportHeader": {
116
+ "newLine": true,
117
+ "type": "header",
118
+ "text": "supportHeader",
119
+ "size": 5
120
+ },
121
+ "_aboutInfo": {
122
+ "type": "staticText",
123
+ "text": "aboutInfo",
124
+ "xs": 12,
125
+ "sm": 12,
126
+ "md": 12,
127
+ "lg": 12,
128
+ "xl": 12,
129
+ "style": {
130
+ "fontSize": 14,
131
+ "marginBottom": 16
132
+ }
133
+ },
134
+ "_kofiLink": {
135
+ "type": "staticLink",
136
+ "href": "https://ko-fi.com/krobipd",
137
+ "label": "donateKofi",
138
+ "button": true,
139
+ "variant": "outlined",
140
+ "color": "primary",
141
+ "xs": 12,
142
+ "sm": 6,
143
+ "md": 4,
144
+ "lg": 4,
145
+ "xl": 4
146
+ },
147
+ "_paypalLink": {
148
+ "type": "staticLink",
149
+ "href": "https://paypal.me/krobipd",
150
+ "label": "donatePaypal",
151
+ "button": true,
152
+ "variant": "outlined",
153
+ "color": "primary",
154
+ "xs": 12,
155
+ "sm": 6,
156
+ "md": 4,
157
+ "lg": 4,
158
+ "xl": 4
159
+ }
160
+ }
161
+ },
162
+ "tab_advanced": {
163
+ "type": "panel",
164
+ "label": "tab_advanced",
165
+ "items": {
166
+ "commandTimeout": {
167
+ "type": "number",
168
+ "label": "label_commandTimeout",
169
+ "help": "help_commandTimeout",
170
+ "min": 1,
171
+ "max": 30,
172
+ "default": 5,
173
+ "xs": 12,
174
+ "sm": 12,
175
+ "md": 4,
176
+ "lg": 4,
177
+ "xl": 4
178
+ },
179
+ "enableCommands": {
180
+ "type": "checkbox",
181
+ "label": "label_enableCommands",
182
+ "help": "help_enableCommands",
183
+ "default": false,
184
+ "xs": 12,
185
+ "sm": 12,
186
+ "md": 6,
187
+ "lg": 6,
188
+ "xl": 6
189
+ },
190
+ "enableSetVar": {
191
+ "type": "checkbox",
192
+ "label": "label_enableSetVar",
193
+ "help": "help_enableSetVar",
194
+ "default": false,
195
+ "xs": 12,
196
+ "sm": 12,
197
+ "md": 6,
198
+ "lg": 6,
199
+ "xl": 6
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
package/admin/nut2.png ADDED
Binary file
package/admin/nut2.svg ADDED
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="256" height="256">
2
+ <defs>
3
+ <linearGradient id="battGrad" x1="0" y1="0" x2="0" y2="1">
4
+ <stop offset="0%" stop-color="#5cb85c"/>
5
+ <stop offset="100%" stop-color="#3d8b3d"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <!-- Battery terminal -->
9
+ <rect x="96" y="24" width="64" height="24" rx="4" fill="url(#battGrad)"/>
10
+ <!-- Battery body -->
11
+ <rect x="56" y="48" width="144" height="184" rx="16" fill="url(#battGrad)"/>
12
+ <!-- Inner cutout lines (charge level indicators) -->
13
+ <rect x="76" y="72" width="104" height="4" rx="2" fill="rgba(255,255,255,0.4)"/>
14
+ <rect x="76" y="108" width="104" height="4" rx="2" fill="rgba(255,255,255,0.4)"/>
15
+ <rect x="76" y="144" width="104" height="4" rx="2" fill="rgba(255,255,255,0.4)"/>
16
+ <rect x="76" y="180" width="104" height="4" rx="2" fill="rgba(255,255,255,0.4)"/>
17
+ <!-- Lightning bolt -->
18
+ <polygon points="148,80 116,148 140,148 108,216 152,136 128,136 160,80" fill="#F5A623"/>
19
+ </svg>
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var coerce_exports = {};
20
+ __export(coerce_exports, {
21
+ coerceCommandTimeoutMs: () => coerceCommandTimeoutMs,
22
+ coerceHost: () => coerceHost,
23
+ coercePollIntervalSec: () => coercePollIntervalSec,
24
+ coercePort: () => coercePort,
25
+ computeReconnectDelay: () => computeReconnectDelay,
26
+ errText: () => errText,
27
+ localAddressOf: () => localAddressOf,
28
+ parseDecimal: () => parseDecimal
29
+ });
30
+ module.exports = __toCommonJS(coerce_exports);
31
+ var import_types = require("./types");
32
+ const DECIMAL_NUMBER_RE = /^-?\d+(\.\d+)?$/;
33
+ function parseDecimal(raw) {
34
+ if (typeof raw === "number") {
35
+ return Number.isFinite(raw) ? raw : NaN;
36
+ }
37
+ if (typeof raw === "string" && DECIMAL_NUMBER_RE.test(raw.trim())) {
38
+ return Number(raw.trim());
39
+ }
40
+ return NaN;
41
+ }
42
+ function errText(err) {
43
+ if (err instanceof Error) {
44
+ return err.message;
45
+ }
46
+ if (err === null) {
47
+ return "null";
48
+ }
49
+ if (err === void 0) {
50
+ return "undefined";
51
+ }
52
+ if (typeof err === "string") {
53
+ return err;
54
+ }
55
+ if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint") {
56
+ return String(err);
57
+ }
58
+ try {
59
+ return JSON.stringify(err);
60
+ } catch {
61
+ return Object.prototype.toString.call(err);
62
+ }
63
+ }
64
+ function coerceHost(raw) {
65
+ if (typeof raw !== "string") {
66
+ return null;
67
+ }
68
+ const trimmed = raw.trim();
69
+ return trimmed.length > 0 ? trimmed : null;
70
+ }
71
+ function localAddressOf(raw) {
72
+ if (typeof raw !== "string") {
73
+ return void 0;
74
+ }
75
+ const trimmed = raw.trim();
76
+ return trimmed.length > 0 && trimmed !== "0.0.0.0" ? trimmed : void 0;
77
+ }
78
+ function coercePort(raw) {
79
+ const n = parseDecimal(raw);
80
+ if (!Number.isFinite(n)) {
81
+ return import_types.NUT_DEFAULT_PORT;
82
+ }
83
+ return Math.max(1, Math.min(65535, Math.floor(n)));
84
+ }
85
+ function coercePollIntervalSec(raw) {
86
+ const n = parseDecimal(raw);
87
+ if (!Number.isFinite(n)) {
88
+ return 15;
89
+ }
90
+ return Math.max(2, Math.min(300, Math.floor(n)));
91
+ }
92
+ function coerceCommandTimeoutMs(raw) {
93
+ const n = parseDecimal(raw);
94
+ if (!Number.isFinite(n)) {
95
+ return import_types.NUT_DEFAULT_COMMAND_TIMEOUT;
96
+ }
97
+ return Math.max(1, Math.min(30, Math.floor(n))) * 1e3;
98
+ }
99
+ function computeReconnectDelay(attempt, baseMs, maxMs) {
100
+ const a = Math.max(1, Math.floor(attempt));
101
+ return Math.min(baseMs * 2 ** (a - 1), maxMs);
102
+ }
103
+ // Annotate the CommonJS export names for ESM import in node:
104
+ 0 && (module.exports = {
105
+ coerceCommandTimeoutMs,
106
+ coerceHost,
107
+ coercePollIntervalSec,
108
+ coercePort,
109
+ computeReconnectDelay,
110
+ errText,
111
+ localAddressOf,
112
+ parseDecimal
113
+ });
114
+ //# sourceMappingURL=coerce.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/coerce.ts"],
4
+ "sourcesContent": ["import { NUT_DEFAULT_COMMAND_TIMEOUT, NUT_DEFAULT_PORT } from \"./types\";\n\n// Strict decimal-only number parsing (fleet line, hassemu E8 origin): a plain\n// float parse would half-accept garbage suffixes (\"34abc\" \u2192 34) and allow\n// hex/exponential notation. Only `-?\\d+(\\.\\d+)?` counts as a number.\nconst DECIMAL_NUMBER_RE = /^-?\\d+(\\.\\d+)?$/;\n\n/**\n * Strict decimal parse: returns the number only for a plain finite decimal\n * (`-?\\d+(\\.\\d+)?`), otherwise NaN. Rejects garbage suffixes (\"12abc\"),\n * non-finite tokens (\"Infinity\") and hex/exponential notation. Shared by the\n * config validators and the device-value type detector.\n *\n * @param raw Raw value (string from NUT/admin config, or already a number)\n */\nexport function parseDecimal(raw: unknown): number {\n if (typeof raw === \"number\") {\n return Number.isFinite(raw) ? raw : NaN;\n }\n if (typeof raw === \"string\" && DECIMAL_NUMBER_RE.test(raw.trim())) {\n return Number(raw.trim());\n }\n return NaN;\n}\n\n/**\n * Extract a log-friendly message from a thrown / rejected value.\n *\n * @param err Caught value of unknown shape\n */\nexport function errText(err: unknown): string {\n if (err instanceof Error) {\n return err.message;\n }\n if (err === null) {\n return \"null\";\n }\n if (err === undefined) {\n return \"undefined\";\n }\n if (typeof err === \"string\") {\n return err;\n }\n if (typeof err === \"number\" || typeof err === \"boolean\" || typeof err === \"bigint\") {\n return String(err);\n }\n try {\n return JSON.stringify(err);\n } catch {\n return Object.prototype.toString.call(err);\n }\n}\n\n/**\n * Validate and return the NUT server host. Returns null if the host\n * is missing or not a non-empty string after trimming.\n *\n * @param raw Raw host value from admin config\n */\nexport function coerceHost(raw: unknown): string | null {\n if (typeof raw !== \"string\") {\n return null;\n }\n const trimmed = raw.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\n/**\n * Resolve the outgoing source-bind address from the admin `networkInterface`.\n * Empty or the \"all interfaces\" sentinel `0.0.0.0` mean \"let the OS choose the\n * source\" \u2192 undefined (no explicit bind).\n *\n * @param raw Raw networkInterface value from admin config\n */\nexport function localAddressOf(raw: unknown): string | undefined {\n if (typeof raw !== \"string\") {\n return undefined;\n }\n const trimmed = raw.trim();\n return trimmed.length > 0 && trimmed !== \"0.0.0.0\" ? trimmed : undefined;\n}\n\n/**\n * Coerce NUT port to a valid integer in [1, 65535], default NUT_DEFAULT_PORT.\n *\n * @param raw Raw port value from admin config\n */\nexport function coercePort(raw: unknown): number {\n const n = parseDecimal(raw);\n if (!Number.isFinite(n)) {\n return NUT_DEFAULT_PORT;\n }\n return Math.max(1, Math.min(65535, Math.floor(n)));\n}\n\n/**\n * Coerce poll interval to seconds, clamped to [2, 300], default 15.\n * Matches admin/jsonConfig min/max.\n *\n * The lower bound is where NUT itself stops producing new data: ups.conf's\n * `pollinterval` \u2014 how often the driver refreshes the UPS status \u2014 defaults to\n * 2 seconds, and `pollfreq` (the full variable set, usbhid-ups/snmp-ups/nutdrv_qx)\n * to 30. Polling faster than the driver only re-reads unchanged values.\n *\n * @param raw Raw pollInterval from admin config (seconds)\n */\nexport function coercePollIntervalSec(raw: unknown): number {\n const n = parseDecimal(raw);\n if (!Number.isFinite(n)) {\n return 15;\n }\n return Math.max(2, Math.min(300, Math.floor(n)));\n}\n\n/**\n * Coerce command timeout from seconds to milliseconds,\n * clamped to [1s, 30s] \u2192 [1000, 30000], default 5000ms.\n *\n * @param raw Raw commandTimeout from admin config (seconds)\n */\nexport function coerceCommandTimeoutMs(raw: unknown): number {\n const n = parseDecimal(raw);\n if (!Number.isFinite(n)) {\n return NUT_DEFAULT_COMMAND_TIMEOUT;\n }\n return Math.max(1, Math.min(30, Math.floor(n))) * 1000;\n}\n\n/**\n * Exponential reconnect backoff: attempt 1 \u2192 baseMs, doubling each attempt, capped at maxMs.\n *\n * @param attempt 1-based attempt counter (values < 1 are treated as 1)\n * @param baseMs Delay for the first attempt\n * @param maxMs Upper bound for the delay\n */\nexport function computeReconnectDelay(attempt: number, baseMs: number, maxMs: number): number {\n const a = Math.max(1, Math.floor(attempt));\n return Math.min(baseMs * 2 ** (a - 1), maxMs);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA8D;AAK9D,MAAM,oBAAoB;AAUnB,SAAS,aAAa,KAAsB;AACjD,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO,OAAO,SAAS,GAAG,IAAI,MAAM;AAAA,EACtC;AACA,MAAI,OAAO,QAAQ,YAAY,kBAAkB,KAAK,IAAI,KAAK,CAAC,GAAG;AACjE,WAAO,OAAO,IAAI,KAAK,CAAC;AAAA,EAC1B;AACA,SAAO;AACT;AAOO,SAAS,QAAQ,KAAsB;AAC5C,MAAI,eAAe,OAAO;AACxB,WAAO,IAAI;AAAA,EACb;AACA,MAAI,QAAQ,MAAM;AAChB,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,QAAW;AACrB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO;AAAA,EACT;AACA,MAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,aAAa,OAAO,QAAQ,UAAU;AAClF,WAAO,OAAO,GAAG;AAAA,EACnB;AACA,MAAI;AACF,WAAO,KAAK,UAAU,GAAG;AAAA,EAC3B,QAAQ;AACN,WAAO,OAAO,UAAU,SAAS,KAAK,GAAG;AAAA,EAC3C;AACF;AAQO,SAAS,WAAW,KAA6B;AACtD,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,IAAI,KAAK;AACzB,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;AASO,SAAS,eAAe,KAAkC;AAC/D,MAAI,OAAO,QAAQ,UAAU;AAC3B,WAAO;AAAA,EACT;AACA,QAAM,UAAU,IAAI,KAAK;AACzB,SAAO,QAAQ,SAAS,KAAK,YAAY,YAAY,UAAU;AACjE;AAOO,SAAS,WAAW,KAAsB;AAC/C,QAAM,IAAI,aAAa,GAAG;AAC1B,MAAI,CAAC,OAAO,SAAS,CAAC,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC;AACnD;AAaO,SAAS,sBAAsB,KAAsB;AAC1D,QAAM,IAAI,aAAa,GAAG;AAC1B,MAAI,CAAC,OAAO,SAAS,CAAC,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC;AACjD;AAQO,SAAS,uBAAuB,KAAsB;AAC3D,QAAM,IAAI,aAAa,GAAG;AAC1B,MAAI,CAAC,OAAO,SAAS,CAAC,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI;AACpD;AASO,SAAS,sBAAsB,SAAiB,QAAgB,OAAuB;AAC5F,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,CAAC;AACzC,SAAO,KAAK,IAAI,SAAS,MAAM,IAAI,IAAI,KAAK;AAC9C;",
6
+ "names": []
7
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var i18n_exports = {};
20
+ __export(i18n_exports, {
21
+ tName: () => tName
22
+ });
23
+ module.exports = __toCommonJS(i18n_exports);
24
+ var import_adapter_core = require("@iobroker/adapter-core");
25
+ function tName(key) {
26
+ return import_adapter_core.I18n.getTranslatedObject(key);
27
+ }
28
+ // Annotate the CommonJS export names for ESM import in node:
29
+ 0 && (module.exports = {
30
+ tName
31
+ });
32
+ //# sourceMappingURL=i18n.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/i18n.ts"],
4
+ "sourcesContent": ["import { I18n } from \"@iobroker/adapter-core\";\nimport type translations from \"../../admin/i18n/en.json\";\n\nexport type I18nKey = keyof typeof translations;\n\n/**\n * Resolve an admin/i18n key to a translation object for `common.name` / state labels.\n *\n * @param key Admin i18n key\n */\nexport function tName(key: I18nKey): ioBroker.StringOrTranslated {\n return I18n.getTranslatedObject(key);\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAqB;AAUd,SAAS,MAAM,KAA2C;AAC/D,SAAO,yBAAK,oBAAoB,GAAG;AACrC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var message_router_exports = {};
20
+ __export(message_router_exports, {
21
+ dispatchMessage: () => dispatchMessage,
22
+ makeTestClientFactory: () => makeTestClientFactory
23
+ });
24
+ module.exports = __toCommonJS(message_router_exports);
25
+ var import_coerce = require("./coerce");
26
+ function makeTestClientFactory(NutClientClass, logger) {
27
+ return (host, port, options) => new NutClientClass(host, port, { ...options, logger });
28
+ }
29
+ async function dispatchMessage(obj, deps) {
30
+ var _a, _b;
31
+ deps.log.debug(`onMessage: command='${obj == null ? void 0 : obj.command}' from='${obj == null ? void 0 : obj.from}' has-callback=${!!(obj == null ? void 0 : obj.callback)}`);
32
+ if (!obj.callback) {
33
+ return;
34
+ }
35
+ try {
36
+ switch (obj.command) {
37
+ case "checkConnection": {
38
+ const raw = obj.message;
39
+ const config = typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
40
+ const host = (0, import_coerce.coerceHost)(config.host);
41
+ if (!host) {
42
+ deps.log.debug("checkConnection: missing host in message");
43
+ deps.sendTo(obj.from, obj.command, { error: "Host is required" }, obj.callback);
44
+ return;
45
+ }
46
+ const port = (0, import_coerce.coercePort)(config.port);
47
+ const username = typeof config.username === "string" ? config.username : "";
48
+ const password = typeof config.password === "string" ? config.password : "";
49
+ const localAddress = (0, import_coerce.localAddressOf)(config.networkInterface);
50
+ const options = {
51
+ localAddress,
52
+ commandTimeout: (0, import_coerce.coerceCommandTimeoutMs)(config.commandTimeout),
53
+ useTls: !!config.useTls,
54
+ tlsRejectUnauthorized: !!config.tlsRejectUnauthorized
55
+ };
56
+ const testClient = deps.createTestClient(host, port, options);
57
+ (_a = deps.onTestClientCreated) == null ? void 0 : _a.call(deps, testClient);
58
+ try {
59
+ await testClient.connect();
60
+ const upsList = await testClient.listUps();
61
+ const names = upsList.map((u) => u.name).join(", ");
62
+ deps.log.debug(`checkConnection: found ${upsList.length} UPS(es): ${names}`);
63
+ if (username && password) {
64
+ await testClient.authenticate(username, password);
65
+ deps.sendTo(
66
+ obj.from,
67
+ obj.command,
68
+ { result: `Connected and authenticated \u2014 ${upsList.length} UPS(es): ${names}` },
69
+ obj.callback
70
+ );
71
+ } else {
72
+ deps.sendTo(
73
+ obj.from,
74
+ obj.command,
75
+ { result: `Connected \u2014 ${upsList.length} UPS(es): ${names}` },
76
+ obj.callback
77
+ );
78
+ }
79
+ } finally {
80
+ testClient.destroy();
81
+ (_b = deps.onTestClientDone) == null ? void 0 : _b.call(deps, testClient);
82
+ }
83
+ break;
84
+ }
85
+ default:
86
+ deps.log.debug(`onMessage: unknown command '${obj.command}'`);
87
+ deps.sendTo(obj.from, obj.command, { error: "Unknown command" }, obj.callback);
88
+ }
89
+ } catch (err) {
90
+ deps.log.debug(`onMessage: '${obj.command}' failed: ${(0, import_coerce.errText)(err)}`);
91
+ deps.sendTo(obj.from, obj.command, { error: (0, import_coerce.errText)(err) }, obj.callback);
92
+ }
93
+ }
94
+ // Annotate the CommonJS export names for ESM import in node:
95
+ 0 && (module.exports = {
96
+ dispatchMessage,
97
+ makeTestClientFactory
98
+ });
99
+ //# sourceMappingURL=message-router.js.map