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,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/state-manager.ts"],
4
+ "sourcesContent": ["import type * as utils from \"@iobroker/adapter-core\";\nimport { tName, type I18nKey } from \"./i18n\";\nimport { ALL_FLAG_KEYS, FLAG_META, getDisplayString, parseStatus } from \"./status-parser\";\nimport { detectStates, detectType } from \"./type-detector\";\nimport type { NutCommand, NutVariable } from \"./types\";\n\ntype LocalizedName = ioBroker.StringOrTranslated;\n\nconst CHANNEL_I18N: Record<string, I18nKey> = {\n battery: \"channelBattery\",\n device: \"channelDevice\",\n driver: \"channelDriver\",\n input: \"channelInput\",\n output: \"channelOutput\",\n ups: \"channelUps\",\n outlet: \"channelOutlet\",\n ambient: \"channelAmbient\",\n status: \"channelStatus\",\n commands: \"channelCommands\",\n info: \"channelUpsInfo\",\n};\n\nconst COMMAND_I18N: Record<string, I18nKey> = {\n \"beeper.disable\": \"cmdBeeperDisable\",\n \"beeper.enable\": \"cmdBeeperEnable\",\n \"beeper.mute\": \"cmdBeeperMute\",\n \"beeper.toggle\": \"cmdBeeperToggle\",\n \"load.off\": \"cmdLoadOff\",\n \"load.on\": \"cmdLoadOn\",\n \"load.off.delay\": \"cmdLoadOffDelay\",\n \"load.on.delay\": \"cmdLoadOnDelay\",\n \"shutdown.default\": \"cmdShutdownDefault\",\n \"shutdown.return\": \"cmdShutdownReturn\",\n \"shutdown.stayoff\": \"cmdShutdownStayoff\",\n \"shutdown.stop\": \"cmdShutdownStop\",\n \"shutdown.reboot\": \"cmdShutdownReboot\",\n \"shutdown.reboot.graceful\": \"cmdShutdownRebootGraceful\",\n \"test.battery.start\": \"cmdTestBatteryStart\",\n \"test.battery.start.quick\": \"cmdTestBatteryStartQuick\",\n \"test.battery.start.low\": \"cmdTestBatteryStartLow\",\n \"test.battery.start.deep\": \"cmdTestBatteryStartDeep\",\n \"test.battery.stop\": \"cmdTestBatteryStop\",\n \"test.panel.start\": \"cmdTestPanelStart\",\n \"test.panel.stop\": \"cmdTestPanelStop\",\n \"test.failure.start\": \"cmdTestFailureStart\",\n \"test.failure.stop\": \"cmdTestFailureStop\",\n \"test.system.start\": \"cmdTestSystemStart\",\n \"calibrate.start\": \"cmdCalibrateStart\",\n \"calibrate.stop\": \"cmdCalibrateStop\",\n \"bypass.start\": \"cmdBypassStart\",\n \"bypass.stop\": \"cmdBypassStop\",\n \"reset.input.minmax\": \"cmdResetInputMinmax\",\n \"reset.watchdog\": \"cmdResetWatchdog\",\n};\n\nconst TRANSLATED_VARIABLES = new Set<I18nKey>([\n \"battery.charge\",\n \"battery.charge.low\",\n \"battery.runtime\",\n \"battery.type\",\n \"battery.voltage\",\n \"battery.temperature\",\n \"battery.capacity\",\n \"battery.charger.status\",\n \"device.mfr\",\n \"device.model\",\n \"device.serial\",\n \"device.type\",\n \"driver.name\",\n \"driver.version\",\n \"driver.version.data\",\n \"driver.version.internal\",\n \"driver.parameter.pollfreq\",\n \"driver.parameter.pollinterval\",\n \"driver.parameter.port\",\n \"driver.parameter.synchronous\",\n \"driver.flag.ignorelb\",\n \"driver.version.usb\",\n \"input.voltage\",\n \"input.frequency\",\n \"input.transfer.high\",\n \"input.transfer.low\",\n \"input.voltage.extended\",\n \"output.voltage\",\n \"output.frequency\",\n \"output.voltage.nominal\",\n \"output.frequency.nominal\",\n \"output.current\",\n \"ups.status\",\n \"ups.load\",\n \"ups.power\",\n \"ups.realpower\",\n \"ups.power.nominal\",\n \"ups.temperature\",\n \"ups.delay.shutdown\",\n \"ups.delay.start\",\n \"ups.timer.shutdown\",\n \"ups.timer.start\",\n \"ups.firmware\",\n \"ups.beeper.status\",\n \"ups.mfr\",\n \"ups.model\",\n \"ups.serial\",\n \"ups.vendorid\",\n \"ups.productid\",\n \"outlet.desc\",\n \"outlet.id\",\n \"outlet.switchable\",\n \"outlet.status\",\n \"ambient.temperature\",\n \"ambient.humidity\",\n] as I18nKey[]);\n\nfunction varTranslation(nutVarName: string): LocalizedName | undefined {\n if (TRANSLATED_VARIABLES.has(nutVarName as I18nKey)) {\n return tName(nutVarName as I18nKey);\n }\n // Collapse a per-instance or phase segment (ambient.2., input.L1., input.L1-L2., input.N.) to\n // the base name so three-phase and multi-sensor variables reuse the translated base label.\n const generic = nutVarName.replace(/\\.(\\d+|L\\d(-(L\\d|N))?|N)\\./, \".\");\n if (generic !== nutVarName && TRANSLATED_VARIABLES.has(generic as I18nKey)) {\n return tName(generic as I18nKey);\n }\n return undefined;\n}\n\n/**\n * Convert NUT variable name to ioBroker state ID (dots after channel \u2192 dashes).\n *\n * @param upsName UPS identifier\n * @param nutVarName NUT variable name\n */\nexport function nutVarToStateId(upsName: string, nutVarName: string): string {\n const firstDot = nutVarName.indexOf(\".\");\n if (firstDot < 0) {\n return `${upsName}.${nutVarName}`;\n }\n const channel = nutVarName.slice(0, firstDot);\n const leaf = nutVarName.slice(firstDot + 1).replace(/\\./g, \"-\");\n return `${upsName}.${channel}.${leaf}`;\n}\n\n/**\n * Format NUT variable name as human-readable label.\n *\n * @param nutVarName NUT variable name\n */\nexport function nutVarToReadableName(nutVarName: string): string {\n const firstDot = nutVarName.indexOf(\".\");\n const leaf = firstDot >= 0 ? nutVarName.slice(firstDot + 1) : nutVarName;\n return leaf.replace(/\\./g, \" \").replace(/^./, c => c.toUpperCase());\n}\n\n/** Manages creation, update and cleanup of ioBroker objects and states for NUT UPS devices. */\nexport class StateManager {\n private readonly adapter: utils.AdapterInstance;\n private readonly createdIds = new Set<string>();\n /** NUT variables already warned about as garbage in a numeric field (warn once). */\n private readonly warnedGarbageVars = new Set<string>();\n /** Last device name derived from mfr+model per UPS \u2014 lets a transient/wrong fallback self-correct. */\n private readonly fallbackNames = new Map<string, string>();\n /**\n * stateId \u2192 original NUT variable/command name. The dot\u2192dash id mapping is lossy for names\n * containing a literal dash (three-phase input.L1-L2.*), so onStateChange reads the real name\n * back from here instead of reversing the id.\n */\n private readonly nutNames = new Map<string, string>();\n\n /**\n * @param adapter The ioBroker adapter instance\n */\n constructor(adapter: utils.AdapterInstance) {\n this.adapter = adapter;\n }\n\n /**\n * Create device + standard channels for a discovered UPS.\n *\n * @param upsName NUT UPS identifier (e.g. \"ups0\")\n * @param description UPS description from LIST UPS\n */\n async ensureUpsDevice(upsName: string, description: string): Promise<void> {\n this.adapter.log.debug(`ensureUpsDevice: ${upsName} desc='${description}'`);\n await this.adapter.extendObject(\n upsName,\n {\n type: \"device\",\n common: {\n name: description,\n statusStates: {\n onlineId: `${this.adapter.namespace}.${upsName}.info.reachable`,\n },\n },\n native: {},\n },\n { preserve: { common: [\"name\"] } },\n );\n this.createdIds.add(upsName);\n\n await this.ensureChannel(upsName, \"info\");\n\n await this.ensureState(`${upsName}.info.reachable`, {\n type: \"boolean\",\n role: \"indicator.reachable\",\n read: true,\n write: false,\n name: tName(\"upsReachable\"),\n def: false,\n });\n\n await this.cleanupDeprecatedInfoStates(upsName);\n }\n\n /**\n * Update device common.name from LIST VAR data when LIST UPS description is unusable.\n *\n * The fallback must NOT use `preserve: common.name` \u2014 the device object always has a\n * name (set by ensureUpsDevice from the unusable description), so a preserved write\n * would never apply (js-controller 7.x `removePreservedProperties` drops the new name\n * whenever the old object has one; this silently killed the feature in v0.2.5-v0.4.1).\n * User-modified names stay safe through the guard instead: the fallback only fires\n * while the CURRENT name is still the auto-set placeholder or a value WE derived\n * earlier \u2014 so a transient/wrong mfr+model that arrived first self-corrects, while a\n * user-chosen name is left untouched. No broker round-trip while the derived name is stable.\n *\n * @param upsName UPS identifier\n * @param description UPS description from LIST UPS\n * @param variables Variables from LIST VAR\n */\n async updateDeviceName(\n upsName: string,\n description: string,\n variables: Array<{ name: string; value: string }>,\n ): Promise<void> {\n if (description && description !== \"Description unavailable\") {\n return;\n }\n const mfr = variables.find(v => v.name === \"device.mfr\")?.value?.trim();\n const model = variables.find(v => v.name === \"device.model\")?.value?.trim();\n if (!mfr && !model) {\n return;\n }\n const name = [mfr, model].filter(Boolean).join(\" \");\n // Already applied this exact fallback name \u2192 no broker round-trip on steady-state polls.\n if (this.fallbackNames.get(upsName) === name) {\n return;\n }\n\n const obj = await this.adapter.getObjectAsync(upsName);\n const currentName = obj?.common?.name;\n // Replace the auto-set placeholder OR a name WE derived earlier (self-correct a\n // transient/wrong mfr+model that arrived first). A user-chosen name stays (preserve, mcm1957).\n const replaceable =\n currentName === description ||\n currentName === \"Description unavailable\" ||\n currentName === \"\" ||\n currentName === this.fallbackNames.get(upsName);\n if (!replaceable) {\n return;\n }\n\n this.adapter.log.debug(`updateDeviceName ${upsName}: using fallback '${name}' (mfr+model)`);\n await this.adapter.extendObject(upsName, { common: { name } });\n this.fallbackNames.set(upsName, name);\n }\n\n /**\n * Ensure a channel exists for a NUT domain (e.g. \"battery\", \"ups\").\n *\n * @param upsName UPS identifier\n * @param channelName Channel name (NUT domain)\n */\n async ensureChannel(upsName: string, channelName: string): Promise<void> {\n const id = `${upsName}.${channelName}`;\n const i18nKey = CHANNEL_I18N[channelName];\n const name: LocalizedName = i18nKey ? tName(i18nKey) : channelName;\n\n await this.ensureObject(id, {\n type: \"channel\",\n common: { name },\n native: {},\n });\n }\n\n /**\n * Update variables from LIST VAR, creating states as needed.\n * Variables are processed sorted by dot-depth (shallow first) to ensure\n * parent states exist before children.\n *\n * @param upsName UPS identifier\n * @param variables Variables from LIST VAR\n * @param rwNames Set of writable variable names from LIST RW\n */\n async updateVariables(upsName: string, variables: NutVariable[], rwNames: Set<string>): Promise<void> {\n this.adapter.log.debug(`updateVariables ${upsName}: ${variables.length} vars, ${rwNames.size} writable`);\n const sorted = [...variables].sort((a, b) => {\n const depthA = a.name.split(\".\").length;\n const depthB = b.name.split(\".\").length;\n return depthA - depthB;\n });\n\n for (const v of sorted) {\n // Dotless variables (e.g. a bare \"ALARM\" that some drivers expose) have no\n // channel segment \u2014 a same-named channel would collide with the state id and\n // leave a typeless object. Create those directly under the device instead.\n const firstDot = v.name.indexOf(\".\");\n if (firstDot >= 0) {\n await this.ensureChannel(upsName, v.name.slice(0, firstDot));\n }\n\n const isWritable = rwNames.has(v.name);\n const detected = detectType(v.name, v.value, isWritable);\n\n // Garbage value in a numeric field (e.g. \"Infinity\", \"12abc\") \u2192 discard\n // instead of storing junk, and warn once per variable (no log spam).\n if (detected.expectedNumeric) {\n if (!this.warnedGarbageVars.has(v.name)) {\n this.warnedGarbageVars.add(v.name);\n this.adapter.log.warn(\n `Discarding non-numeric value ${JSON.stringify(v.value)} for numeric variable '${v.name}' on ${upsName}`,\n );\n }\n continue;\n }\n\n const stateId = nutVarToStateId(upsName, v.name);\n this.nutNames.set(stateId, v.name);\n const states = detectStates(v.name);\n await this.ensureState(stateId, {\n type: detected.type,\n role: detected.role,\n unit: detected.unit,\n read: detected.read,\n write: detected.write,\n name: varTranslation(v.name) ?? nutVarToReadableName(v.name),\n states,\n });\n\n await this.adapter.setStateChangedAsync(stateId, { val: detected.parsedValue, ack: true });\n }\n }\n\n /**\n * Parse ups.status and update status channel with individual boolean flags + severity.\n *\n * @param upsName UPS identifier\n * @param rawStatus Raw ups.status value\n * @param chargerStatus Optional battery.charger.status (modern source for charging/discharging)\n */\n async updateStatusFlags(upsName: string, rawStatus: string, chargerStatus?: string): Promise<void> {\n await this.ensureChannel(upsName, \"status\");\n\n const result = parseStatus(rawStatus, chargerStatus);\n const activeFlags = ALL_FLAG_KEYS.filter(k => result.flags[k]).join(\", \") || \"none\";\n this.adapter.log.debug(\n `updateStatusFlags ${upsName}: raw='${rawStatus}' severity=${result.severity} active=[${activeFlags}]`,\n );\n\n await this.ensureAndSet(\n `${upsName}.status.raw`,\n { type: \"string\", role: \"text\", read: true, write: false, name: tName(\"statusRaw\") },\n result.raw,\n );\n\n await this.ensureAndSet(\n `${upsName}.status.severity`,\n {\n type: \"number\",\n role: \"value\",\n read: true,\n write: false,\n name: tName(\"statusSeverity\"),\n states: { 0: \"OK\", 1: \"Info\", 2: \"Warning\", 3: \"Critical\", 4: \"Emergency\" },\n },\n result.severity,\n );\n\n await this.ensureAndSet(\n `${upsName}.status.display`,\n { type: \"string\", role: \"text\", read: true, write: false, name: tName(\"statusDisplay\") },\n getDisplayString(rawStatus),\n );\n\n for (const flagKey of ALL_FLAG_KEYS) {\n const meta = FLAG_META[flagKey];\n await this.ensureAndSet(\n `${upsName}.status.${flagKey}`,\n {\n type: \"boolean\",\n role: meta?.role ?? \"indicator\",\n read: true,\n write: false,\n name: meta ? tName(meta.i18nKey) : flagKey,\n },\n result.flags[flagKey],\n );\n }\n }\n\n /**\n * Create button states for instant commands.\n *\n * @param upsName UPS identifier\n * @param commands Commands from LIST CMD\n */\n async createCommandButtons(upsName: string, commands: NutCommand[]): Promise<void> {\n await this.ensureChannel(upsName, \"commands\");\n\n for (const cmd of commands) {\n const stateId = `${upsName}.commands.${cmd.name.replace(/\\./g, \"-\")}`;\n this.nutNames.set(stateId, cmd.name);\n const cmdI18nKey = COMMAND_I18N[cmd.name];\n await this.ensureState(stateId, {\n type: \"boolean\",\n role: \"button\",\n read: false,\n write: true,\n name: cmdI18nKey ? tName(cmdI18nKey) : cmd.name.replace(/\\./g, \" \").replace(/^./, c => c.toUpperCase()),\n def: false,\n });\n }\n }\n\n /**\n * The original NUT variable/command name for a created state id. onStateChange uses it instead\n * of reversing the dot\u2192dash id mapping, which is lossy for names carrying a literal dash\n * (e.g. three-phase input.L1-L2.voltage). Undefined for states not backed by a NUT var/command.\n *\n * @param stateId Local state id (e.g. \"ups0.input.L1-L2-voltage\")\n */\n nutNameForState(stateId: string): string | undefined {\n return this.nutNames.get(stateId);\n }\n\n /**\n * Remove device objects for UPS devices no longer reported by the NUT server.\n *\n * @param currentUpsNames Set of currently discovered UPS names\n */\n async cleanupRemovedUps(currentUpsNames: Set<string>): Promise<void> {\n const adapterObjects = await this.adapter.getAdapterObjectsAsync();\n const deviceIds = new Set<string>();\n\n for (const [id, obj] of Object.entries(adapterObjects)) {\n if (obj.type === \"device\") {\n const localId = id.replace(`${this.adapter.namespace}.`, \"\");\n if (!currentUpsNames.has(localId)) {\n deviceIds.add(localId);\n }\n }\n }\n\n for (const deviceId of deviceIds) {\n this.adapter.log.info(`Removing stale UPS device: ${deviceId}`);\n await this.adapter.delObjectAsync(deviceId, { recursive: true });\n this.dropCacheUnder(deviceId);\n }\n }\n\n /**\n * Remove orphaned objects from previous adapter versions and v0.1.0 dot-style objects.\n *\n * @param knownUpsNames Set of currently discovered UPS names\n */\n async cleanupLegacyObjects(knownUpsNames: Set<string>): Promise<void> {\n const adapterObjects = await this.adapter.getAdapterObjectsAsync();\n const orphanRoots = new Set<string>();\n const dotStyleIds: string[] = [];\n\n for (const fullId of Object.keys(adapterObjects)) {\n const localId = fullId.replace(`${this.adapter.namespace}.`, \"\");\n const parts = localId.split(\".\");\n const topLevel = parts[0];\n\n if (topLevel === \"info\") {\n continue;\n }\n\n if (!knownUpsNames.has(topLevel)) {\n orphanRoots.add(topLevel);\n continue;\n }\n\n if (parts.length > 3) {\n dotStyleIds.push(localId);\n }\n }\n\n for (const root of orphanRoots) {\n this.adapter.log.info(`Removing orphaned root object from previous adapter version: ${root}`);\n await this.adapter.delObjectAsync(root, { recursive: true });\n this.dropCacheUnder(root);\n }\n\n const sorted = dotStyleIds.sort((a, b) => b.split(\".\").length - a.split(\".\").length);\n for (const id of sorted) {\n this.adapter.log.debug(`Removing v0.1.0 dot-style object: ${id}`);\n await this.adapter.delObjectAsync(id);\n this.createdIds.delete(id);\n }\n }\n\n private async cleanupDeprecatedInfoStates(upsName: string): Promise<void> {\n // Once per runtime per UPS \u2014 these states are gone after the first connect, so re-running\n // the delObject calls on every reconnect is wasted work. Cache-keyed like the name fallback;\n // cleared together with the device in cleanupRemovedUps, so a re-added UPS cleans up again.\n const cacheKey = `${upsName}.__deprecatedCleanup`;\n if (this.createdIds.has(cacheKey)) {\n return;\n }\n this.createdIds.add(cacheKey);\n const deprecated = [\n `${upsName}.info.name`,\n `${upsName}.info.description`,\n // Renamed to info.reachable in 0.4.0 (the old `online` leaf collided with the\n // status.online / OL flag). Without this delete the old state lingers frozen at its\n // last value \u2014 ioBroker does not auto-remove states an adapter stops writing.\n `${upsName}.info.online`,\n // Dropped non-standard status flags \u2014 not real NUT status_set tokens (COMM/NOCOMM),\n // or renamed (highEfficiency \u2192 ecoMode). NB: `testing` is NOT here \u2014 TEST is a real\n // token (apc_modbus, powercom, \u2026) and is a current flag again.\n `${upsName}.status.commEstablished`,\n `${upsName}.status.commLost`,\n `${upsName}.status.highEfficiency`,\n ];\n for (const id of deprecated) {\n try {\n await this.adapter.delObjectAsync(id);\n this.adapter.log.debug(`Removed deprecated state: ${id}`);\n } catch {\n // Object doesn't exist \u2014 nothing to clean up\n }\n }\n }\n\n /**\n * Remove all cached IDs under a prefix.\n *\n * @param prefix ID prefix to clear\n */\n private dropCacheUnder(prefix: string): void {\n for (const id of [...this.createdIds]) {\n if (id === prefix || id.startsWith(`${prefix}.`)) {\n this.createdIds.delete(id);\n }\n }\n for (const id of [...this.nutNames.keys()]) {\n if (id === prefix || id.startsWith(`${prefix}.`)) {\n this.nutNames.delete(id);\n }\n }\n }\n\n private async ensureObject(\n id: string,\n obj: {\n type: \"device\" | \"channel\" | \"folder\";\n common: Partial<ioBroker.ObjectCommon>;\n native: Record<string, unknown>;\n },\n ): Promise<void> {\n if (this.createdIds.has(id)) {\n return;\n }\n await this.adapter.setObjectNotExistsAsync(id, {\n type: obj.type,\n common: obj.common as ioBroker.ObjectCommon,\n native: obj.native,\n });\n this.createdIds.add(id);\n }\n\n private async ensureState(\n id: string,\n common: {\n type: ioBroker.CommonType;\n role: string;\n read: boolean;\n write: boolean;\n name: LocalizedName;\n unit?: string;\n def?: boolean;\n states?: Record<string, string>;\n },\n ): Promise<void> {\n if (this.createdIds.has(id)) {\n return;\n }\n await this.adapter.extendObject(\n id,\n {\n type: \"state\",\n common,\n native: {},\n },\n { preserve: { common: [\"name\"] } },\n );\n this.createdIds.add(id);\n }\n\n /**\n * Ensure a state exists (once) and write its current value \u2014 the create-then-set pair used for\n * every status/flag datapoint.\n *\n * @param id State id\n * @param common Object definition forwarded to ensureState\n * @param val Value to write (acknowledged)\n */\n private async ensureAndSet(\n id: string,\n common: Parameters<StateManager[\"ensureState\"]>[1],\n val: ioBroker.StateValue,\n ): Promise<void> {\n await this.ensureState(id, common);\n await this.adapter.setStateChangedAsync(id, { val, ack: true });\n }\n\n /**\n * Enrich an existing state with ENUM/RANGE metadata from the NUT server.\n * Uses extendObject to deep-merge \u2014 overwrites only the provided keys.\n *\n * @param id State object ID\n * @param patch Metadata to apply (states for ENUM, min/max for RANGE)\n * @param patch.states ENUM value map\n * @param patch.min RANGE minimum\n * @param patch.max RANGE maximum\n */\n async enrichStateMetadata(\n id: string,\n patch: { states?: Record<string, string>; min?: number; max?: number },\n ): Promise<void> {\n this.adapter.log.debug(`enrichStateMetadata ${id}: ${JSON.stringify(patch)}`);\n const common: Record<string, unknown> = {};\n if (patch.states) {\n common.states = patch.states;\n }\n if (patch.min !== undefined) {\n common.min = patch.min;\n }\n if (patch.max !== undefined) {\n common.max = patch.max;\n }\n if (Object.keys(common).length > 0) {\n await this.adapter.extendObject(id, { common }, { preserve: { common: [\"name\"] } });\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,131 @@
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 status_parser_exports = {};
20
+ __export(status_parser_exports, {
21
+ ALL_FLAG_KEYS: () => ALL_FLAG_KEYS,
22
+ FLAG_META: () => FLAG_META,
23
+ STATUS_FLAGS: () => STATUS_FLAGS,
24
+ getDisplayString: () => getDisplayString,
25
+ parseStatus: () => parseStatus
26
+ });
27
+ module.exports = __toCommonJS(status_parser_exports);
28
+ const STATUS_CATALOG = [
29
+ { token: "OL", flag: "online", label: "On line power", i18nKey: "flagOnline", role: "indicator" },
30
+ { token: "OB", flag: "onBattery", label: "On Battery", i18nKey: "flagOnBattery", role: "indicator.alarm" },
31
+ { token: "LB", flag: "lowBattery", label: "Low Battery", i18nKey: "flagLowBattery", role: "indicator.lowbat" },
32
+ { token: "HB", flag: "highBattery", label: "High Battery", i18nKey: "flagHighBattery", role: "indicator" },
33
+ {
34
+ token: "RB",
35
+ flag: "replaceBattery",
36
+ label: "Replace Battery",
37
+ i18nKey: "flagReplaceBattery",
38
+ role: "indicator.maintenance"
39
+ },
40
+ { token: "CHRG", flag: "charging", label: "Charging", i18nKey: "flagCharging", role: "indicator" },
41
+ { token: "DISCHRG", flag: "discharging", label: "Discharging", i18nKey: "flagDischarging", role: "indicator" },
42
+ { token: "BYPASS", flag: "bypass", label: "Bypass", i18nKey: "flagBypass", role: "indicator" },
43
+ { token: "CAL", flag: "calibrating", label: "Calibrating", i18nKey: "flagCalibrating", role: "indicator" },
44
+ { token: "OFF", flag: "off", label: "Off", i18nKey: "flagOff", role: "indicator" },
45
+ { token: "OVER", flag: "overloaded", label: "Overloaded", i18nKey: "flagOverloaded", role: "indicator.alarm" },
46
+ { token: "TRIM", flag: "trimming", label: "Trimming", i18nKey: "flagTrimming", role: "indicator" },
47
+ { token: "BOOST", flag: "boosting", label: "Boosting", i18nKey: "flagBoosting", role: "indicator" },
48
+ {
49
+ token: "FSD",
50
+ flag: "forcedShutdown",
51
+ label: "Forced Shutdown",
52
+ i18nKey: "flagForcedShutdown",
53
+ role: "indicator.alarm"
54
+ },
55
+ { token: "ALARM", flag: "alarm", label: "Alarm", i18nKey: "flagAlarm", role: "indicator.alarm" },
56
+ { token: "WAIT", flag: "waiting", label: "Waiting", i18nKey: "flagWaiting", role: "indicator" },
57
+ { token: "ECO", flag: "ecoMode", label: "ECO Mode", i18nKey: "flagEcoMode", role: "indicator" },
58
+ { token: "TEST", flag: "testing", label: "Testing", i18nKey: "flagTesting", role: "indicator" },
59
+ { token: "OVERHEAT", flag: "overheat", label: "Overheated", i18nKey: "flagOverheat", role: "indicator.alarm" }
60
+ ];
61
+ const STATUS_ALIASES = {
62
+ HE: "ECO"
63
+ };
64
+ const STATUS_FLAGS = {};
65
+ const DISPLAY_LABELS = {};
66
+ const FLAG_META = {};
67
+ for (const d of STATUS_CATALOG) {
68
+ STATUS_FLAGS[d.token] = d.flag;
69
+ DISPLAY_LABELS[d.token] = d.label;
70
+ FLAG_META[d.flag] = { i18nKey: d.i18nKey, role: d.role };
71
+ }
72
+ for (const [alias, token] of Object.entries(STATUS_ALIASES)) {
73
+ STATUS_FLAGS[alias] = STATUS_FLAGS[token];
74
+ DISPLAY_LABELS[alias] = DISPLAY_LABELS[token];
75
+ }
76
+ const ALL_FLAG_KEYS = STATUS_CATALOG.map((d) => d.flag);
77
+ function parseStatus(rawStatus, chargerStatus) {
78
+ const tokens = rawStatus.trim().split(/\s+/).filter((t) => t.length > 0);
79
+ const flags = {};
80
+ for (const key of ALL_FLAG_KEYS) {
81
+ flags[key] = false;
82
+ }
83
+ const activeTokens = /* @__PURE__ */ new Set();
84
+ for (const token of tokens) {
85
+ const flag = STATUS_FLAGS[token];
86
+ if (flag) {
87
+ flags[flag] = true;
88
+ activeTokens.add(token);
89
+ }
90
+ }
91
+ if (chargerStatus) {
92
+ const cs = chargerStatus.trim().toLowerCase();
93
+ if (cs === "charging") {
94
+ flags.charging = true;
95
+ } else if (cs === "discharging") {
96
+ flags.discharging = true;
97
+ }
98
+ }
99
+ const severity = computeSeverity(activeTokens);
100
+ return { raw: rawStatus, flags, severity };
101
+ }
102
+ function getDisplayString(rawStatus) {
103
+ return rawStatus.trim().split(/\s+/).filter((t) => t.length > 0).map((t) => {
104
+ var _a;
105
+ return (_a = DISPLAY_LABELS[t]) != null ? _a : t;
106
+ }).join(", ");
107
+ }
108
+ function computeSeverity(tokens) {
109
+ if (tokens.has("FSD")) {
110
+ return 4;
111
+ }
112
+ if (tokens.has("OB") && tokens.has("LB")) {
113
+ return 3;
114
+ }
115
+ if (tokens.has("OB") || tokens.has("RB") || tokens.has("BYPASS")) {
116
+ return 2;
117
+ }
118
+ if (tokens.has("TRIM") || tokens.has("BOOST") || tokens.has("CAL")) {
119
+ return 1;
120
+ }
121
+ return 0;
122
+ }
123
+ // Annotate the CommonJS export names for ESM import in node:
124
+ 0 && (module.exports = {
125
+ ALL_FLAG_KEYS,
126
+ FLAG_META,
127
+ STATUS_FLAGS,
128
+ getDisplayString,
129
+ parseStatus
130
+ });
131
+ //# sourceMappingURL=status-parser.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/status-parser.ts"],
4
+ "sourcesContent": ["import type { I18nKey } from \"./i18n\";\n\n/** Parsed status flags with individual booleans and computed severity. */\nexport interface StatusResult {\n /** Raw status string (e.g. \"OL CHRG\") */\n raw: string;\n /** Individual boolean flags */\n flags: Record<string, boolean>;\n /** Computed severity: 0=OK, 1=Info, 2=Warning, 3=Critical, 4=Emergency */\n severity: number;\n}\n\n/** One status-flag definition. Single source of truth for token, flag id, label, i18n key and role. */\ninterface StatusFlagDef {\n /** NUT ups.status token */\n token: string;\n /** ioBroker boolean state id (leaf under status.) */\n flag: string;\n /** Human-readable display label */\n label: string;\n /** admin/i18n key for the state name */\n i18nKey: I18nKey;\n /** ioBroker state role */\n role: string;\n}\n\n// Authoritative ups.status flag catalog, verified against the bundled NUT 2.8.5 source\n// (`grep status_set(` across drivers/) and docs/new-drivers.txt. Documented standard set:\n// the 14 core tokens (OL..FSD) + ALARM (set internally by alarm_set, not status_set) +\n// WAIT (upsd's initial value while a driver connects). Non-documented but real extras\n// emitted by multiple shipped drivers are also mapped: TEST (5 drivers incl. apc_modbus,\n// powercom), OVERHEAT (belkinunv, microsol), and ECO (emerging eco-mode, real on Eaton\n// Ellipse ECO; legacy name \"HE\" aliased via STATUS_ALIASES). Driver-private one-off tokens\n// (ACFAIL/COMMFAULT/DEPLETED/BY/TIP/SD \u2014 mostly \"self-invented\" in a single driver) are\n// intentionally NOT mapped: per new-drivers.txt clients MAY ignore unidentified tokens, and\n// any such token still appears verbatim in status.raw / status.display.\nconst STATUS_CATALOG: StatusFlagDef[] = [\n { token: \"OL\", flag: \"online\", label: \"On line power\", i18nKey: \"flagOnline\", role: \"indicator\" },\n { token: \"OB\", flag: \"onBattery\", label: \"On Battery\", i18nKey: \"flagOnBattery\", role: \"indicator.alarm\" },\n { token: \"LB\", flag: \"lowBattery\", label: \"Low Battery\", i18nKey: \"flagLowBattery\", role: \"indicator.lowbat\" },\n { token: \"HB\", flag: \"highBattery\", label: \"High Battery\", i18nKey: \"flagHighBattery\", role: \"indicator\" },\n {\n token: \"RB\",\n flag: \"replaceBattery\",\n label: \"Replace Battery\",\n i18nKey: \"flagReplaceBattery\",\n role: \"indicator.maintenance\",\n },\n { token: \"CHRG\", flag: \"charging\", label: \"Charging\", i18nKey: \"flagCharging\", role: \"indicator\" },\n { token: \"DISCHRG\", flag: \"discharging\", label: \"Discharging\", i18nKey: \"flagDischarging\", role: \"indicator\" },\n { token: \"BYPASS\", flag: \"bypass\", label: \"Bypass\", i18nKey: \"flagBypass\", role: \"indicator\" },\n { token: \"CAL\", flag: \"calibrating\", label: \"Calibrating\", i18nKey: \"flagCalibrating\", role: \"indicator\" },\n { token: \"OFF\", flag: \"off\", label: \"Off\", i18nKey: \"flagOff\", role: \"indicator\" },\n { token: \"OVER\", flag: \"overloaded\", label: \"Overloaded\", i18nKey: \"flagOverloaded\", role: \"indicator.alarm\" },\n { token: \"TRIM\", flag: \"trimming\", label: \"Trimming\", i18nKey: \"flagTrimming\", role: \"indicator\" },\n { token: \"BOOST\", flag: \"boosting\", label: \"Boosting\", i18nKey: \"flagBoosting\", role: \"indicator\" },\n {\n token: \"FSD\",\n flag: \"forcedShutdown\",\n label: \"Forced Shutdown\",\n i18nKey: \"flagForcedShutdown\",\n role: \"indicator.alarm\",\n },\n { token: \"ALARM\", flag: \"alarm\", label: \"Alarm\", i18nKey: \"flagAlarm\", role: \"indicator.alarm\" },\n { token: \"WAIT\", flag: \"waiting\", label: \"Waiting\", i18nKey: \"flagWaiting\", role: \"indicator\" },\n { token: \"ECO\", flag: \"ecoMode\", label: \"ECO Mode\", i18nKey: \"flagEcoMode\", role: \"indicator\" },\n { token: \"TEST\", flag: \"testing\", label: \"Testing\", i18nKey: \"flagTesting\", role: \"indicator\" },\n { token: \"OVERHEAT\", flag: \"overheat\", label: \"Overheated\", i18nKey: \"flagOverheat\", role: \"indicator.alarm\" },\n];\n\n/** Legacy / alternative tokens mapped to a catalog token (e.g. legacy \"HE\" \u2192 \"ECO\"). */\nconst STATUS_ALIASES: Record<string, string> = {\n HE: \"ECO\",\n};\n\n/** token \u2192 flag id (incl. aliases). */\nexport const STATUS_FLAGS: Record<string, string> = {};\n/** token \u2192 display label (incl. aliases). */\nconst DISPLAY_LABELS: Record<string, string> = {};\n/** flag id \u2192 { i18nKey, role } (for state-manager). */\nexport const FLAG_META: Record<string, { i18nKey: I18nKey; role: string }> = {};\nfor (const d of STATUS_CATALOG) {\n STATUS_FLAGS[d.token] = d.flag;\n DISPLAY_LABELS[d.token] = d.label;\n FLAG_META[d.flag] = { i18nKey: d.i18nKey, role: d.role };\n}\nfor (const [alias, token] of Object.entries(STATUS_ALIASES)) {\n STATUS_FLAGS[alias] = STATUS_FLAGS[token];\n DISPLAY_LABELS[alias] = DISPLAY_LABELS[token];\n}\n\n/** All known flag keys for creating default-false states (catalog order). */\nexport const ALL_FLAG_KEYS = STATUS_CATALOG.map(d => d.flag);\n\n/**\n * Parse ups.status space-separated flags into individual booleans and severity.\n *\n * @param rawStatus Raw ups.status value (e.g. \"OL CHRG\")\n * @param chargerStatus Optional battery.charger.status value (modern NUT source for charging/discharging)\n */\nexport function parseStatus(rawStatus: string, chargerStatus?: string): StatusResult {\n const tokens = rawStatus\n .trim()\n .split(/\\s+/)\n .filter(t => t.length > 0);\n\n const flags: Record<string, boolean> = {};\n for (const key of ALL_FLAG_KEYS) {\n flags[key] = false;\n }\n\n const activeTokens = new Set<string>();\n for (const token of tokens) {\n const flag = STATUS_FLAGS[token];\n if (flag) {\n flags[flag] = true;\n activeTokens.add(token);\n }\n }\n\n // Modern NUT exposes charging state via battery.charger.status instead of CHRG/DISCHRG\n // flags (e.g. Eaton Ellipse ECO). Derive charging/discharging from it when present.\n if (chargerStatus) {\n const cs = chargerStatus.trim().toLowerCase();\n if (cs === \"charging\") {\n flags.charging = true;\n } else if (cs === \"discharging\") {\n flags.discharging = true;\n }\n // \"floating\" (maintained) / \"resting\" (idle) \u2192 neither charging nor discharging\n }\n\n const severity = computeSeverity(activeTokens);\n\n return { raw: rawStatus, flags, severity };\n}\n\n/**\n * Convert raw ups.status to human-readable display string.\n *\n * @param rawStatus Raw ups.status value (e.g. \"OL CHRG\")\n */\nexport function getDisplayString(rawStatus: string): string {\n return rawStatus\n .trim()\n .split(/\\s+/)\n .filter(t => t.length > 0)\n .map(t => DISPLAY_LABELS[t] ?? t)\n .join(\", \");\n}\n\n// Severity reflects the POWER-SOURCE state only (OL \u2192 trimming \u2192 on battery \u2192 critical \u2192\n// forced shutdown). Fault flags such as OVER/ALARM/OFF are intentionally NOT folded in \u2014\n// they are exposed as their own booleans; conflating them here would dilute a single-meaning\n// value. Design decision (krobi 2026-05-31), not an oversight.\nfunction computeSeverity(tokens: Set<string>): number {\n if (tokens.has(\"FSD\")) {\n return 4;\n }\n if (tokens.has(\"OB\") && tokens.has(\"LB\")) {\n return 3;\n }\n if (tokens.has(\"OB\") || tokens.has(\"RB\") || tokens.has(\"BYPASS\")) {\n return 2;\n }\n if (tokens.has(\"TRIM\") || tokens.has(\"BOOST\") || tokens.has(\"CAL\")) {\n return 1;\n }\n return 0;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,255 @@
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 type_detector_exports = {};
20
+ __export(type_detector_exports, {
21
+ detectStates: () => detectStates,
22
+ detectType: () => detectType
23
+ });
24
+ module.exports = __toCommonJS(type_detector_exports);
25
+ var import_coerce = require("./coerce");
26
+ const KNOWN_STRING_SUFFIXES = /* @__PURE__ */ new Set([
27
+ "model",
28
+ "mfr",
29
+ "serial",
30
+ "firmware",
31
+ "status",
32
+ "alarm",
33
+ "date",
34
+ "type",
35
+ "id",
36
+ "name",
37
+ "desc",
38
+ "location",
39
+ "contact",
40
+ "vendorid",
41
+ "productid",
42
+ // Opaque identifiers per the NUT catalog — keep as strings (leading zeros etc. must survive).
43
+ "part",
44
+ "address",
45
+ "color",
46
+ "groupid"
47
+ ]);
48
+ const KNOWN_STRING_PREFIXES = [
49
+ "driver.flag.",
50
+ "driver.parameter.port",
51
+ "driver.parameter.synchronous",
52
+ "driver.version."
53
+ ];
54
+ function detectType(varName, rawValue, isWritable) {
55
+ if (isKnownString(varName)) {
56
+ return {
57
+ type: "string",
58
+ role: detectRole(varName, "string", isWritable),
59
+ unit: void 0,
60
+ read: true,
61
+ write: isWritable,
62
+ parsedValue: rawValue
63
+ };
64
+ }
65
+ const bool = parseYesNo(rawValue);
66
+ if (bool !== void 0) {
67
+ return {
68
+ type: "boolean",
69
+ role: isWritable ? "switch" : "indicator",
70
+ unit: void 0,
71
+ read: true,
72
+ write: isWritable,
73
+ parsedValue: bool
74
+ };
75
+ }
76
+ const num = (0, import_coerce.parseDecimal)(rawValue);
77
+ if (Number.isFinite(num)) {
78
+ return {
79
+ type: "number",
80
+ role: detectRole(varName, "number", isWritable),
81
+ unit: detectUnit(varName),
82
+ read: true,
83
+ write: isWritable,
84
+ parsedValue: num
85
+ };
86
+ }
87
+ return {
88
+ type: "string",
89
+ role: detectRole(varName, "string", isWritable),
90
+ unit: void 0,
91
+ read: true,
92
+ write: isWritable,
93
+ parsedValue: rawValue,
94
+ expectedNumeric: detectUnit(varName) !== void 0
95
+ };
96
+ }
97
+ function parseYesNo(rawValue) {
98
+ const v = rawValue.trim().toLowerCase();
99
+ if (v === "yes") {
100
+ return true;
101
+ }
102
+ if (v === "no") {
103
+ return false;
104
+ }
105
+ return void 0;
106
+ }
107
+ function isKnownString(varName) {
108
+ const lastDot = varName.lastIndexOf(".");
109
+ if (lastDot >= 0) {
110
+ const suffix = varName.slice(lastDot + 1);
111
+ if (KNOWN_STRING_SUFFIXES.has(suffix)) {
112
+ return true;
113
+ }
114
+ }
115
+ for (const prefix of KNOWN_STRING_PREFIXES) {
116
+ if (varName.startsWith(prefix) || varName === prefix) {
117
+ return true;
118
+ }
119
+ }
120
+ if (varName.includes(".version")) {
121
+ return true;
122
+ }
123
+ return false;
124
+ }
125
+ function detectUnit(varName) {
126
+ if (/\.frequency\..+\.range$/.test(varName)) {
127
+ return "%";
128
+ }
129
+ if (varName === "battery.energysave.delay") {
130
+ return "min";
131
+ }
132
+ if (varName.includes("voltage")) {
133
+ return "V";
134
+ }
135
+ if (/^input\.transfer\.(.*\.)?(low|high|min|max)$/.test(varName) || varName === "input.transfer.hysteresis") {
136
+ return "V";
137
+ }
138
+ if (varName.includes("frequency")) {
139
+ return "Hz";
140
+ }
141
+ if (varName.includes("current")) {
142
+ return "A";
143
+ }
144
+ if (varName.includes("charge")) {
145
+ return "%";
146
+ }
147
+ if (varName.includes("humidity")) {
148
+ return "%";
149
+ }
150
+ if (varName.endsWith(".load") || varName.endsWith(".load.high") || varName.endsWith(".efficiency") || varName.endsWith(".percent")) {
151
+ return "%";
152
+ }
153
+ if (varName.includes("temperature")) {
154
+ return "\xB0C";
155
+ }
156
+ if (varName.includes("runtime") || varName.includes(".delay.") || varName.endsWith(".delay") || varName.includes(".timer.") || varName.endsWith(".uptime") || varName.endsWith(".test.interval") || varName.endsWith(".latency")) {
157
+ return "s";
158
+ }
159
+ if (varName.endsWith(".realpower") || varName.endsWith(".realpower.nominal")) {
160
+ return "W";
161
+ }
162
+ if (varName.endsWith(".power") || varName.endsWith(".power.nominal")) {
163
+ return "VA";
164
+ }
165
+ if (varName.includes("capacity")) {
166
+ return "Ah";
167
+ }
168
+ if (varName === "input.phase.shift") {
169
+ return "\xB0";
170
+ }
171
+ return void 0;
172
+ }
173
+ function detectRole(varName, type, isWritable) {
174
+ if (varName === "ups.status") {
175
+ return "text";
176
+ }
177
+ if (type === "string") {
178
+ return "text";
179
+ }
180
+ if (varName === "battery.charge") {
181
+ return "value.battery";
182
+ }
183
+ if (varName.includes("voltage")) {
184
+ return isWritable ? "level" : "value.voltage";
185
+ }
186
+ if (varName.includes("temperature")) {
187
+ return "value.temperature";
188
+ }
189
+ if (varName.includes("current")) {
190
+ return "value.current";
191
+ }
192
+ if (varName.includes("power") && !varName.includes("powerfactor")) {
193
+ return isWritable ? "level" : "value.power";
194
+ }
195
+ if (varName.includes("runtime") || varName.includes(".delay.") || varName.includes(".timer.")) {
196
+ return isWritable ? "level" : "value.interval";
197
+ }
198
+ return isWritable ? "level" : "value";
199
+ }
200
+ const KNOWN_ENUM_STATES = {
201
+ "battery.charger.status": {
202
+ charging: "charging",
203
+ discharging: "discharging",
204
+ floating: "floating",
205
+ resting: "resting"
206
+ },
207
+ "ups.beeper.status": {
208
+ enabled: "enabled",
209
+ disabled: "disabled",
210
+ muted: "muted"
211
+ }
212
+ };
213
+ const OUTLET_ON_OFF = { on: "on", off: "off" };
214
+ const THRESHOLD_STATUS = {
215
+ good: "good",
216
+ "warning-low": "warning-low",
217
+ "warning-high": "warning-high",
218
+ "critical-low": "critical-low",
219
+ "critical-high": "critical-high"
220
+ };
221
+ const FREQUENCY_STATUS = { ...THRESHOLD_STATUS, "out-of-range": "out-of-range" };
222
+ const ENABLED_DISABLED = { enabled: "enabled", disabled: "disabled" };
223
+ const CONTACTS_STATUS = {
224
+ open: "open",
225
+ closed: "closed",
226
+ active: "active",
227
+ inactive: "inactive"
228
+ };
229
+ function detectStates(varName) {
230
+ if (KNOWN_ENUM_STATES[varName]) {
231
+ return KNOWN_ENUM_STATES[varName];
232
+ }
233
+ if (/^outlet(\.\d+)?\.(switch|status)$/.test(varName) || /^outlet\.group(\.\d+)?\.status$/.test(varName)) {
234
+ return OUTLET_ON_OFF;
235
+ }
236
+ if (/\.frequency\.status$/.test(varName)) {
237
+ return FREQUENCY_STATUS;
238
+ }
239
+ if (/\.(voltage|current|temperature|humidity)\.status$/.test(varName)) {
240
+ return THRESHOLD_STATUS;
241
+ }
242
+ if (varName === "ups.watchdog.status" || varName === "ups.shutdown" || varName === "input.bypass.switchable" || /^input\.transfer\.bypass\.(forced|overload|outlimits)$/.test(varName) || /^ambient(\.\d+)?\.(temperature|humidity)\.alarm$/.test(varName)) {
243
+ return ENABLED_DISABLED;
244
+ }
245
+ if (/^ambient(\.\d+)?\.contacts\.\d+\.status$/.test(varName)) {
246
+ return CONTACTS_STATUS;
247
+ }
248
+ return void 0;
249
+ }
250
+ // Annotate the CommonJS export names for ESM import in node:
251
+ 0 && (module.exports = {
252
+ detectStates,
253
+ detectType
254
+ });
255
+ //# sourceMappingURL=type-detector.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/type-detector.ts"],
4
+ "sourcesContent": ["import { parseDecimal } from \"./coerce\";\n\n/** Known-string suffixes \u2014 always string regardless of numeric parsing. */\nconst KNOWN_STRING_SUFFIXES = new Set([\n \"model\",\n \"mfr\",\n \"serial\",\n \"firmware\",\n \"status\",\n \"alarm\",\n \"date\",\n \"type\",\n \"id\",\n \"name\",\n \"desc\",\n \"location\",\n \"contact\",\n \"vendorid\",\n \"productid\",\n // Opaque identifiers per the NUT catalog \u2014 keep as strings (leading zeros etc. must survive).\n \"part\",\n \"address\",\n \"color\",\n \"groupid\",\n]);\n\n/** Known-string exact prefixes \u2014 always string. */\nconst KNOWN_STRING_PREFIXES = [\n \"driver.flag.\",\n \"driver.parameter.port\",\n \"driver.parameter.synchronous\",\n \"driver.version.\",\n];\n\n/** Result of type detection for a NUT variable. */\nexport interface TypeDetectResult {\n /** ioBroker state type */\n type: \"number\" | \"string\" | \"boolean\";\n /** ioBroker state role */\n role: string;\n /** Unit string if applicable */\n unit?: string;\n /** Always true */\n read: true;\n /** Whether the variable is writable via SET VAR */\n write: boolean;\n /** Parsed value (number, string or boolean) */\n parsedValue: number | string | boolean;\n /**\n * True when the variable name denotes a numeric quantity (carries a unit) but\n * the raw value is not a strict number (garbage / non-finite). The caller\n * should discard the value and warn once rather than store junk.\n */\n expectedNumeric?: boolean;\n}\n\n/**\n * Detect ioBroker state type, role, and unit from a NUT variable name and raw value.\n *\n * @param varName NUT variable name (e.g. battery.charge)\n * @param rawValue Raw string value from LIST VAR\n * @param isWritable Whether the variable appears in LIST RW\n */\nexport function detectType(varName: string, rawValue: string, isWritable: boolean): TypeDetectResult {\n if (isKnownString(varName)) {\n return {\n type: \"string\",\n role: detectRole(varName, \"string\", isWritable),\n unit: undefined,\n read: true,\n write: isWritable,\n parsedValue: rawValue,\n };\n }\n\n // A yes/no reading is a real boolean state, not a text dump \u2014 even when the variable name\n // carries a numeric-unit substring (e.g. input.frequency.extended = \"no\", ambient.n.present =\n // \"yes\"). Value-driven so it covers every driver's yes/no variables, not a hand-kept list.\n // After the known-string check so an opaque text field that happens to read \"no\" stays a string.\n const bool = parseYesNo(rawValue);\n if (bool !== undefined) {\n return {\n type: \"boolean\",\n role: isWritable ? \"switch\" : \"indicator\",\n unit: undefined,\n read: true,\n write: isWritable,\n parsedValue: bool,\n };\n }\n\n // Strict decimal only (same fleet line as the config coerce): garbage suffixes\n // (\"12abc\" \u2192 12) and non-finite tokens (\"Infinity\" \u2192 null on setState) must NOT\n // become numbers \u2014 a number field never holds letters. Such values stay raw strings.\n const num = parseDecimal(rawValue);\n if (Number.isFinite(num)) {\n return {\n type: \"number\",\n role: detectRole(varName, \"number\", isWritable),\n unit: detectUnit(varName),\n read: true,\n write: isWritable,\n parsedValue: num,\n };\n }\n\n // Not a known string and not a strict number \u2192 opaque string. If the variable\n // name denotes a numeric quantity (carries a unit), the value is garbage for a\n // number field \u2192 flag it so the caller discards it and warns once.\n return {\n type: \"string\",\n role: detectRole(varName, \"string\", isWritable),\n unit: undefined,\n read: true,\n write: isWritable,\n parsedValue: rawValue,\n expectedNumeric: detectUnit(varName) !== undefined,\n };\n}\n\n/**\n * NUT yes/no fields become real boolean states (the point of the typed rewrite), not text.\n *\n * @param rawValue Raw string value from LIST VAR\n */\nfunction parseYesNo(rawValue: string): boolean | undefined {\n const v = rawValue.trim().toLowerCase();\n if (v === \"yes\") {\n return true;\n }\n if (v === \"no\") {\n return false;\n }\n return undefined;\n}\n\nfunction isKnownString(varName: string): boolean {\n const lastDot = varName.lastIndexOf(\".\");\n if (lastDot >= 0) {\n const suffix = varName.slice(lastDot + 1);\n if (KNOWN_STRING_SUFFIXES.has(suffix)) {\n return true;\n }\n }\n\n for (const prefix of KNOWN_STRING_PREFIXES) {\n if (varName.startsWith(prefix) || varName === prefix) {\n return true;\n }\n }\n\n if (varName.includes(\".version\")) {\n return true;\n }\n\n return false;\n}\n\n// Only called for numeric variables (string vars never carry a unit).\nfunction detectUnit(varName: string): string | undefined {\n // Percent-of-nominal ranges carry \"frequency\" in the name but are a percentage.\n if (/\\.frequency\\..+\\.range$/.test(varName)) {\n return \"%\";\n }\n // Minutes (checked before the generic seconds rules that also match \".delay\").\n if (varName === \"battery.energysave.delay\") {\n return \"min\";\n }\n if (varName.includes(\"voltage\")) {\n return \"V\";\n }\n // Transfer/bypass voltage set-points carry no \"voltage\" token in the name.\n if (/^input\\.transfer\\.(.*\\.)?(low|high|min|max)$/.test(varName) || varName === \"input.transfer.hysteresis\") {\n return \"V\";\n }\n if (varName.includes(\"frequency\")) {\n return \"Hz\";\n }\n if (varName.includes(\"current\")) {\n return \"A\";\n }\n if (varName.includes(\"charge\")) {\n return \"%\";\n }\n if (varName.includes(\"humidity\")) {\n return \"%\";\n }\n if (\n varName.endsWith(\".load\") ||\n varName.endsWith(\".load.high\") ||\n varName.endsWith(\".efficiency\") ||\n varName.endsWith(\".percent\")\n ) {\n return \"%\";\n }\n if (varName.includes(\"temperature\")) {\n return \"\u00B0C\";\n }\n if (\n varName.includes(\"runtime\") ||\n varName.includes(\".delay.\") ||\n varName.endsWith(\".delay\") ||\n varName.includes(\".timer.\") ||\n varName.endsWith(\".uptime\") ||\n varName.endsWith(\".test.interval\") ||\n varName.endsWith(\".latency\")\n ) {\n return \"s\";\n }\n if (varName.endsWith(\".realpower\") || varName.endsWith(\".realpower.nominal\")) {\n return \"W\";\n }\n if (varName.endsWith(\".power\") || varName.endsWith(\".power.nominal\")) {\n return \"VA\";\n }\n if (varName.includes(\"capacity\")) {\n return \"Ah\";\n }\n if (varName === \"input.phase.shift\") {\n return \"\u00B0\";\n }\n return undefined;\n}\n\nfunction detectRole(varName: string, type: \"number\" | \"string\", isWritable: boolean): string {\n // ups.status is the one string that always gets a text role.\n if (varName === \"ups.status\") {\n return \"text\";\n }\n // String states never get a value.* role \u2014 they are text (or a writable text field).\n if (type === \"string\") {\n return \"text\";\n }\n\n // Numeric roles.\n if (varName === \"battery.charge\") {\n return \"value.battery\";\n }\n if (varName.includes(\"voltage\")) {\n return isWritable ? \"level\" : \"value.voltage\";\n }\n if (varName.includes(\"temperature\")) {\n return \"value.temperature\";\n }\n if (varName.includes(\"current\")) {\n return \"value.current\";\n }\n // \"powerfactor\" contains \"power\" but is a 0..1 factor, not a power value.\n if (varName.includes(\"power\") && !varName.includes(\"powerfactor\")) {\n return isWritable ? \"level\" : \"value.power\";\n }\n if (varName.includes(\"runtime\") || varName.includes(\".delay.\") || varName.includes(\".timer.\")) {\n return isWritable ? \"level\" : \"value.interval\";\n }\n\n return isWritable ? \"level\" : \"value\";\n}\n\nconst KNOWN_ENUM_STATES: Record<string, Record<string, string>> = {\n \"battery.charger.status\": {\n charging: \"charging\",\n discharging: \"discharging\",\n floating: \"floating\",\n resting: \"resting\",\n },\n \"ups.beeper.status\": {\n enabled: \"enabled\",\n disabled: \"disabled\",\n muted: \"muted\",\n },\n};\n\nconst OUTLET_ON_OFF: Record<string, string> = { on: \"on\", off: \"off\" };\n\n// good / warning-low / warning-high / critical-low / critical-high \u2014 threshold status enum for\n// *.voltage.status, *.current.status, ambient.*.{temperature,humidity}.status (incl. three-phase\n// variants like input.L1.voltage.status).\nconst THRESHOLD_STATUS: Record<string, string> = {\n good: \"good\",\n \"warning-low\": \"warning-low\",\n \"warning-high\": \"warning-high\",\n \"critical-low\": \"critical-low\",\n \"critical-high\": \"critical-high\",\n};\n\n// Frequency status additionally reports \"out-of-range\".\nconst FREQUENCY_STATUS: Record<string, string> = { ...THRESHOLD_STATUS, \"out-of-range\": \"out-of-range\" };\n\n// Two-state toggles reported as a word (ups.watchdog.status, ups.shutdown,\n// input.transfer.bypass.{forced,overload,outlimits}, input.bypass.switchable,\n// ambient.*.{temperature,humidity}.alarm) \u2014 an enum, not bare text.\nconst ENABLED_DISABLED: Record<string, string> = { enabled: \"enabled\", disabled: \"disabled\" };\n\n// Dry-contact sensor status: raw open/closed, or active/inactive relative to its configuration.\nconst CONTACTS_STATUS: Record<string, string> = {\n open: \"open\",\n closed: \"closed\",\n active: \"active\",\n inactive: \"inactive\",\n};\n\n/**\n * Detect common.states for known enum variables.\n *\n * @param varName NUT variable name\n */\nexport function detectStates(varName: string): Record<string, string> | undefined {\n if (KNOWN_ENUM_STATES[varName]) {\n return KNOWN_ENUM_STATES[varName];\n }\n // on/off switches \u2014 individual outlets and outlet groups.\n if (/^outlet(\\.\\d+)?\\.(switch|status)$/.test(varName) || /^outlet\\.group(\\.\\d+)?\\.status$/.test(varName)) {\n return OUTLET_ON_OFF;\n }\n // Threshold status enums (frequency additionally reports out-of-range).\n if (/\\.frequency\\.status$/.test(varName)) {\n return FREQUENCY_STATUS;\n }\n if (/\\.(voltage|current|temperature|humidity)\\.status$/.test(varName)) {\n return THRESHOLD_STATUS;\n }\n // Two-state enabled/disabled toggles that would otherwise fall through to bare text.\n if (\n varName === \"ups.watchdog.status\" ||\n varName === \"ups.shutdown\" ||\n varName === \"input.bypass.switchable\" ||\n /^input\\.transfer\\.bypass\\.(forced|overload|outlimits)$/.test(varName) ||\n /^ambient(\\.\\d+)?\\.(temperature|humidity)\\.alarm$/.test(varName)\n ) {\n return ENABLED_DISABLED;\n }\n // Dry-contact sensor status.\n if (/^ambient(\\.\\d+)?\\.contacts\\.\\d+\\.status$/.test(varName)) {\n return CONTACTS_STATUS;\n }\n return undefined;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,59 @@
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 types_exports = {};
20
+ __export(types_exports, {
21
+ NUT_DEFAULT_COMMAND_TIMEOUT: () => NUT_DEFAULT_COMMAND_TIMEOUT,
22
+ NUT_DEFAULT_PORT: () => NUT_DEFAULT_PORT,
23
+ NUT_ERRORS: () => NUT_ERRORS
24
+ });
25
+ module.exports = __toCommonJS(types_exports);
26
+ const NUT_DEFAULT_PORT = 3493;
27
+ const NUT_DEFAULT_COMMAND_TIMEOUT = 5e3;
28
+ const NUT_ERRORS = [
29
+ "ACCESS-DENIED",
30
+ "UNKNOWN-UPS",
31
+ "VAR-NOT-SUPPORTED",
32
+ "CMD-NOT-SUPPORTED",
33
+ "INVALID-ARGUMENT",
34
+ "INSTCMD-FAILED",
35
+ "SET-FAILED",
36
+ "READONLY",
37
+ "TOO-LONG",
38
+ "FEATURE-NOT-SUPPORTED",
39
+ "FEATURE-NOT-CONFIGURED",
40
+ "ALREADY-SSL-MODE",
41
+ "DRIVER-NOT-CONNECTED",
42
+ "DATA-STALE",
43
+ "ALREADY-LOGGED-IN",
44
+ "INVALID-PASSWORD",
45
+ "ALREADY-SET-PASSWORD",
46
+ "INVALID-USERNAME",
47
+ "ALREADY-SET-USERNAME",
48
+ "USERNAME-REQUIRED",
49
+ "PASSWORD-REQUIRED",
50
+ "UNKNOWN-COMMAND",
51
+ "INVALID-VALUE"
52
+ ];
53
+ // Annotate the CommonJS export names for ESM import in node:
54
+ 0 && (module.exports = {
55
+ NUT_DEFAULT_COMMAND_TIMEOUT,
56
+ NUT_DEFAULT_PORT,
57
+ NUT_ERRORS
58
+ });
59
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/types.ts"],
4
+ "sourcesContent": ["/** Adapter configuration as stored in ioBroker native config. */\nexport interface AdapterConfig {\n /** NUT server hostname or IP */\n host: string;\n /** NUT server port */\n port: number;\n /** Local network interface for outgoing connections */\n networkInterface: string;\n /** Poll interval in seconds */\n pollInterval: number;\n /** NUT username (optional, for SET/INSTCMD) */\n username: string;\n /** NUT password (optional) */\n password: string;\n /** Use STARTTLS to encrypt the connection */\n useTls: boolean;\n /** Reject invalid/self-signed TLS certificates (default false) */\n tlsRejectUnauthorized: boolean;\n /** Per-command timeout in seconds */\n commandTimeout: number;\n /** Enable instant commands (INSTCMD) */\n enableCommands: boolean;\n /** Enable writable variables (SET VAR) */\n enableSetVar: boolean;\n}\n\n/** UPS device discovered via LIST UPS. */\nexport interface UpsInfo {\n /** UPS identifier */\n name: string;\n /** UPS description */\n description: string;\n}\n\n/** NUT variable from LIST VAR / LIST RW. */\nexport interface NutVariable {\n /** Variable name (e.g. battery.charge) */\n name: string;\n /** Raw string value */\n value: string;\n}\n\n/** NUT instant command from LIST CMD. */\nexport interface NutCommand {\n /** Command name (e.g. beeper.enable) */\n name: string;\n}\n\n/** NUT range constraint from LIST RANGE. */\nexport interface NutRange {\n /** Minimum value */\n min: string;\n /** Maximum value */\n max: string;\n}\n\n/** Logger interface for the NUT client. */\nexport interface NutLogger {\n /** Debug-level log */\n debug(message: string): void;\n /** Warning-level log */\n warn(message: string): void;\n /** Info-level log */\n info(message: string): void;\n}\n\n/** Options for NutClient constructor. */\nexport interface NutClientOptions {\n /** Local address to bind to (network interface selection) */\n localAddress?: string;\n /** Per-command timeout in milliseconds */\n commandTimeout?: number;\n /** Optional logger */\n logger?: NutLogger;\n /** Use STARTTLS to encrypt the connection (credentials otherwise travel in clear text). */\n useTls?: boolean;\n /** Reject self-signed/invalid TLS certs (default false \u2014 NUT servers are typically self-signed). */\n tlsRejectUnauthorized?: boolean;\n /** Injected managed timer (adapter.setTimeout) \u2014 auto-cleared on unload. Defaults to the global timer. */\n setTimer?: (callback: () => void, ms: number) => unknown;\n /** Injected managed clear (adapter.clearTimeout). Defaults to the global clear. */\n clearTimer?: (handle: unknown) => void;\n}\n\n/** Default NUT TCP port. */\nexport const NUT_DEFAULT_PORT = 3493;\n/** Default per-command timeout in milliseconds. */\nexport const NUT_DEFAULT_COMMAND_TIMEOUT = 5000;\n\n// Documented reference catalog of the 23 NUT protocol error codes (net-protocol.txt).\n// NutError.code is typed `string` (not NutErrorCode) because a server may send codes\n// outside this set; this list documents the meanings, it does not constrain the type.\nexport const NUT_ERRORS = [\n \"ACCESS-DENIED\",\n \"UNKNOWN-UPS\",\n \"VAR-NOT-SUPPORTED\",\n \"CMD-NOT-SUPPORTED\",\n \"INVALID-ARGUMENT\",\n \"INSTCMD-FAILED\",\n \"SET-FAILED\",\n \"READONLY\",\n \"TOO-LONG\",\n \"FEATURE-NOT-SUPPORTED\",\n \"FEATURE-NOT-CONFIGURED\",\n \"ALREADY-SSL-MODE\",\n \"DRIVER-NOT-CONNECTED\",\n \"DATA-STALE\",\n \"ALREADY-LOGGED-IN\",\n \"INVALID-PASSWORD\",\n \"ALREADY-SET-PASSWORD\",\n \"INVALID-USERNAME\",\n \"ALREADY-SET-USERNAME\",\n \"USERNAME-REQUIRED\",\n \"PASSWORD-REQUIRED\",\n \"UNKNOWN-COMMAND\",\n \"INVALID-VALUE\",\n] as const;\n\n/** Union type of all known NUT error codes. */\nexport type NutErrorCode = (typeof NUT_ERRORS)[number];\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqFO,MAAM,mBAAmB;AAEzB,MAAM,8BAA8B;AAKpC,MAAM,aAAa;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;",
6
+ "names": []
7
+ }