iobroker.govee-smart 2.0.1 → 2.0.3

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.
package/README.md CHANGED
@@ -61,7 +61,7 @@ Full user documentation lives in the **[Wiki](https://github.com/krobipd/ioBroke
61
61
  ## Requirements
62
62
 
63
63
  - Node.js >= 20
64
- - ioBroker js-controller >= 7.0.0
64
+ - ioBroker js-controller >= 6.0.11
65
65
  - ioBroker Admin >= 7.6.20
66
66
  - A Govee account and at least one Govee WiFi device. LAN control needs a light with LAN mode enabled in the Govee Home app — see Govee's [LAN-supported device list](https://app-h5.govee.com/user-manual/wlan-guide).
67
67
 
@@ -106,45 +106,33 @@ This adapter's MQTT authentication and BLE-over-LAN (ptReal) protocol implementa
106
106
  ---
107
107
 
108
108
  ## Changelog
109
+ ### 2.0.3 (2026-04-26)
110
+ - Min js-controller correction: was incorrectly bumped to `>=7.0.23` in 2.0.2 (and admin downgraded from `>=7.6.20` to `>=7.6.17`). The repochecker-recommended values are `>=6.0.11` / `>=7.6.20` — restored.
111
+
112
+ ### 2.0.2 (2026-04-26)
113
+ - OpenAPI MQTT now keeps a stable client ID across reconnects (was `Date.now`-based, which Govee's broker treats as new connections).
114
+ - Stop shipping the `manual-review` release-script plugin and the redundant `@iobroker/types` runtime dep — adapter-only consequences.
115
+ - Bump min js-controller to `>=7.0.23` (matches latest-repo recommendation).
116
+ - Audit-driven boilerplate sync with the other krobi adapters (`.vscode` json5 schemas, dependabot assignees + github-actions ecosystem, `tsconfig.test` looser test rules).
117
+ - Repo hygiene: ignore `package/` (npm-pack artefact).
109
118
 
110
119
  ### 2.0.1 (2026-04-26)
111
- - Hotfixes from a real-world v2.0.0 install on a setup with H5179 thermometers, heaters and lights.
112
- - Sensor state IDs (`battery`, `temperature`, `humidity`, `co2`, `online`) now route to `sensor/` instead of `control/`. Event IDs (`lackWater`, `iceFull`, `bodyAppeared`, `dirtDetected`) route to `events/`. The state objects are created lazily on the first write — fixes the `info: control.battery has no existing object` warning that appeared the first time the App-API poll delivered sensor data.
113
- - Snapshots and scenes are no longer attached to non-light devices. Thermometers, heaters and kettles previously got `snapshot_local` / `snapshot_save` / `snapshot_delete` regardless now those state defs are gated behind `device.type === "devices.types.light"`.
114
- - The boot-time `N experimental device(s) detected: H5051, H5100, …` log dump is gone. The adapter only nudges you when a real device of an experimental SKU actually shows up on LAN or Cloud — once per adapter lifetime, per SKU.
115
- - Routine `OpenAPI MQTT connected for sensor events` info line dropped. The adapter-ready summary covers it; the recovery log on reconnect (`OpenAPI MQTT connection restored`) is kept.
120
+ - Sensor states route to `sensor/`, event states to `events/` (was `control/` for both); state objects are created lazily on first write to avoid `no existing object` warnings.
121
+ - Snapshots and scenes only attach to lights now; thermometers, heaters and kettles no longer get `snapshot_local` / `snapshot_save` / `snapshot_delete`.
122
+ - No more boot-time `N experimental device(s) detected` log dump only triggers when an experimental SKU actually shows up, once per lifetime per SKU.
123
+ - Routine `OpenAPI MQTT connected for sensor events` info line removed; reconnect-recovery log kept.
116
124
 
117
125
  ### 2.0.0 (2026-04-26)
118
- - Major release — Govee appliances and sensors are now handled by this adapter alongside lights. Govee thermometers (e.g. H5179), heaters, kettles, ice makers and more are imported through the App API (sensor states) and the OpenAPI-MQTT push channel (appliance events).
119
- - The standalone `iobroker.govee-appliances` adapter is deprecated and rolls into here. The old adapter still runs but receives no further updates — install govee-smart 2.0.0+ and uninstall govee-appliances at your convenience.
120
- - New checkbox **"Enable experimental device support"** in the adapter config makes it easier to try unconfirmed models. The Wiki page [Devices](https://github.com/krobipd/ioBroker.govee-smart/wiki/Devices) lists every supported SKU and its status (verified ✅ / user-confirmed 🟢 / experimental ⚪).
121
- - Devices catalog (`devices.json` in the repo root) tracks 36 SKUs at release time; the catalog is the single source of truth for the Wiki page and for runtime quirk-overrides like the per-SKU color-temperature ranges that Govee's API misreports.
122
- - New state `info.openapiMqttConnected` for the second MQTT channel that delivers appliance events. The existing `info.mqttConnected` keeps tracking AWS IoT MQTT for light status push.
126
+ - Major release — Govee appliances and sensors (thermometers like H5179, heaters, kettles, ice makers) are now handled here alongside lights, via the App API and OpenAPI-MQTT push channel.
127
+ - The standalone `iobroker.govee-appliances` adapter is deprecated and rolls into here. Install govee-smart 2.0.0+ and uninstall govee-appliances when convenient.
128
+ - New **"Enable experimental device support"** checkbox in the adapter config. The Wiki [Devices](https://github.com/krobipd/ioBroker.govee-smart/wiki/Devices) page lists every SKU and its status.
129
+ - `devices.json` in the repo root tracks 36 SKUs and is the single source of truth for the Wiki and for runtime quirk overrides.
130
+ - New state `info.openapiMqttConnected` for the OpenAPI-MQTT channel; `info.mqttConnected` keeps tracking AWS IoT MQTT for lights.
123
131
 
124
132
  ### 1.11.0 (2026-04-25)
125
- - Scene / DIY-scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS scripts: the index as a string (`"1"`), the index as a number (`1`), or the entry name (`"Aurora"`, case-insensitive, surrounding whitespace ignored). The state type changed from `string` to `mixed` so the js-controller no longer warns `expects type string but received number` when a script writes a numeric index.
126
- - Duplicate names from the cloud (Govee allows two scenes called "Movie") are now auto-disambiguated in the dropdown with `" (2)"`, `" (3)"` suffixes — the first occurrence keeps the original name, every label maps to exactly one index, and the reverse-lookup is deterministic.
127
- - After activation the adapter acks back the canonical key so the dropdown stays in sync regardless of how the user wrote the value `setState(oid, "Aurora")` ends up showing "Aurora" in the dropdown just like `setState(oid, "1")` does.
128
-
129
- ### 1.10.1 (2026-04-20)
130
- - Fix — the `info.refresh_cloud_data` button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several of those endpoints return 403 for many accounts, so running them again on every refresh only produced a multi-minute rate-limiter backlog — visible in the log as minute-spaced POSTs to `/device/scenes` and `/device/diy-scenes` in the minutes after each click. The button now only re-fetches the scene/snapshot endpoint, which is where new Govee-app snapshots actually show up. Call count per click drops from ~7 to 2 per light device.
131
-
132
- ### 1.10.0 (2026-04-20)
133
- - Scenes with a `scenceParam` (the multi-packet A3 BLE payload that drives per-segment animation) are now skipped on devices without segments and activated via the Govee Cloud instead. Curtain Lights (H70B3) and bulbs silently drop those A3 packets, which left complex scenes unplayed; the simple presets without `scenceParam` kept working. With this fix every scene reaches the device, at the cost of one Cloud call per scene change on non-segmented hardware.
134
- - Powering a device off now resets every mode dropdown (scene, DIY scene, Cloud/local snapshot, music) to "---", whether the off was triggered from ioBroker or from the Govee Home app. A device that is off cannot be "playing Aurora-A" — the UI now reflects that.
135
-
136
- ### 1.9.1 (2026-04-20)
137
- - Hotfix — Govee's `/device/scenes` endpoint occasionally returns e.g. 149 scenes + 0 snapshots on the same device where a snapshot clearly exists. The old combined guard (`if any of the three lists is non-empty, overwrite all three`) wiped the snapshot list in that case, and the cloud-snapshot dropdown then errored out with `invalid snapshot index 1` on click. Each of scenes, DIY scenes and snapshots is now guarded independently — a lucky list no longer clobbers an unlucky one. Applies to every device with cloud-side snapshots, not just the device where it first surfaced.
138
-
139
- ### 1.9.0 (2026-04-20)
140
- - **BREAKING** — the cloud-snapshot dropdown has been renamed from `snapshots.snapshot` to `snapshots.snapshot_cloud`. The new id is unambiguous next to `snapshots.snapshot_local`, `snapshots.snapshot_save` and `snapshots.snapshot_delete`. If your scripts or VIS widgets reference the old id, update them to the new one. The old state is simply removed on first start — nothing is migrated because the value (a dropdown index) is set again on the next selection anyway.
141
- - Fix — scenes and snapshots are now re-fetched from the Govee Cloud on every adapter start. Previously, once `scenesChecked` was set on the cache, the adapter skipped the Cloud round-trip even when you had created a new snapshot in the Govee Home app, so new snapshots only appeared after wiping the cache. This was a genuine bug. Scene data is essentially static, but snapshots are user content — refreshing is cheap (one call per light device per startup) and much less surprising.
142
- - New — `info.refresh_cloud_data` button at adapter level. Write `true` to trigger the same fresh fetch without restarting the adapter. Useful when you just created a snapshot in the Govee Home app and want to pick it in ioBroker right now.
143
- - All four snapshot states (`snapshot_cloud`, `snapshot_local`, `snapshot_save`, `snapshot_delete`) now carry a `common.desc` text that makes it clear in the object browser which is the Govee-app kind and which is the ioBroker kind.
144
-
145
- Older entries have been moved to [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
146
-
147
- ---
133
+ - Scene / DIY-scene / snapshot / music-mode dropdowns now accept index-as-number, index-as-string and the entry name (case-insensitive). The state type is `mixed` no more `expects type string but received number` warning when scripts write a numeric index.
134
+ - Duplicate scene names from the cloud are auto-disambiguated with `" (2)"`, `" (3)"` suffixes; reverse-lookup is deterministic.
135
+ - The adapter acks back the canonical key after activation, so the dropdown stays in sync regardless of how the value was written.
148
136
 
149
137
  ## Support
150
138
 
@@ -31,6 +31,7 @@ __export(govee_openapi_mqtt_client_exports, {
31
31
  GoveeOpenapiMqttClient: () => GoveeOpenapiMqttClient
32
32
  });
33
33
  module.exports = __toCommonJS(govee_openapi_mqtt_client_exports);
34
+ var crypto = __toESM(require("node:crypto"));
34
35
  var mqtt = __toESM(require("mqtt"));
35
36
  var import_types = require("./types.js");
36
37
  const MAX_CONNECT_FAILURES = 5;
@@ -39,6 +40,14 @@ class GoveeOpenapiMqttClient {
39
40
  apiKey;
40
41
  log;
41
42
  timers;
43
+ /**
44
+ * Stable client ID for the lifetime of the adapter instance. Generated once
45
+ * in the constructor so reconnects keep the same identity — Govee's broker
46
+ * can then take over the previous socket cleanly instead of rejecting the
47
+ * new connection as a duplicate. Reusing Date.now() per connect() created a
48
+ * fresh ID on every reconnect.
49
+ */
50
+ sessionUuid = crypto.randomUUID();
42
51
  client = null;
43
52
  topic;
44
53
  reconnectTimer = void 0;
@@ -74,7 +83,7 @@ class GoveeOpenapiMqttClient {
74
83
  this.client = mqtt.connect(BROKER_URL, {
75
84
  username: this.apiKey,
76
85
  password: this.apiKey,
77
- clientId: `iob_govee_smart_${Date.now().toString(36)}`,
86
+ clientId: `iob_govee_smart_${this.sessionUuid}`,
78
87
  protocolVersion: 4,
79
88
  keepalive: 60,
80
89
  reconnectPeriod: 0,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/govee-openapi-mqtt-client.ts"],
4
- "sourcesContent": ["import * as mqtt from \"mqtt\";\nimport {\n classifyError,\n type ErrorCategory,\n type OpenApiMqttEvent,\n type CloudStateCapability,\n type TimerAdapter,\n} from \"./types.js\";\n\n/** Max consecutive connection failures before giving up */\nconst MAX_CONNECT_FAILURES = 5;\n\nconst BROKER_URL = \"mqtts://mqtt.openapi.govee.com:8883\";\n\n/** Callback for incoming sensor events */\nexport type OpenApiEventCallback = (event: OpenApiMqttEvent) => void;\n\n/** Callback for raw MQTT messages (for diagnostics) */\nexport type OpenApiRawCallback = (rawJson: string) => void;\n\n/** Callback for connection state changes */\nexport type OpenApiConnectionCallback = (connected: boolean) => void;\n\n/**\n * Govee OpenAPI MQTT client for real-time sensor events.\n * Connects to mqtt.openapi.govee.com:8883 using the API key for auth.\n * Receives event capabilities (lackWater, iceFull, bodyAppeared etc.)\n * without consuming Cloud API budget.\n */\nexport class GoveeOpenapiMqttClient {\n private readonly apiKey: string;\n private readonly log: ioBroker.Logger;\n private readonly timers: TimerAdapter;\n private client: mqtt.MqttClient | null = null;\n private topic: string;\n private reconnectTimer: ioBroker.Timeout | undefined = undefined;\n private reconnectAttempts = 0;\n private connectFailCount = 0;\n private lastErrorCategory: ErrorCategory | null = null;\n private onEvent: OpenApiEventCallback | null = null;\n private onRaw: OpenApiRawCallback | null = null;\n private onConnection: OpenApiConnectionCallback | null = null;\n\n /**\n * @param apiKey Govee Cloud API key (used as username AND password)\n * @param log ioBroker logger\n * @param timers Timer adapter\n */\n constructor(apiKey: string, log: ioBroker.Logger, timers: TimerAdapter) {\n this.apiKey = apiKey;\n this.log = log;\n this.timers = timers;\n this.topic = `GA/${apiKey}`;\n }\n\n /**\n * Connect to the OpenAPI MQTT broker.\n *\n * @param onEvent Called on incoming sensor events\n * @param onConnection Called on connection state changes\n * @param onRaw Called with raw JSON for diagnostics\n */\n connect(\n onEvent: OpenApiEventCallback,\n onConnection: OpenApiConnectionCallback,\n onRaw?: OpenApiRawCallback,\n ): void {\n this.onEvent = onEvent;\n this.onConnection = onConnection;\n this.onRaw = onRaw ?? null;\n\n try {\n this.client = mqtt.connect(BROKER_URL, {\n username: this.apiKey,\n password: this.apiKey,\n clientId: `iob_govee_smart_${Date.now().toString(36)}`,\n protocolVersion: 4,\n keepalive: 60,\n reconnectPeriod: 0,\n rejectUnauthorized: true,\n });\n\n this.client.on(\"connect\", () => {\n this.reconnectAttempts = 0;\n this.connectFailCount = 0;\n if (this.lastErrorCategory) {\n // Only log on transition out of an error state \u2014 the routine\n // first-connect message is redundant with the adapter-level\n // \"Govee adapter ready \u2014 N devices, M groups (channels: \u2026)\"\n // line and was just noise.\n this.log.info(\"OpenAPI MQTT connection restored\");\n this.lastErrorCategory = null;\n }\n\n this.client?.subscribe(this.topic, { qos: 0 }, (err) => {\n if (err) {\n this.log.warn(`OpenAPI MQTT subscribe failed: ${err.message}`);\n } else {\n this.log.debug(\"OpenAPI MQTT subscribed to event topic\");\n this.onConnection?.(true);\n }\n });\n });\n\n this.client.on(\"message\", (_topic, payload) => {\n this.handleMessage(payload);\n });\n\n this.client.on(\"error\", (err) => {\n const category = classifyError(err);\n if (category === \"AUTH\") {\n this.connectFailCount++;\n if (this.connectFailCount >= MAX_CONNECT_FAILURES) {\n this.log.warn(\n \"OpenAPI MQTT auth failed repeatedly \u2014 check API key\",\n );\n this.onConnection?.(false);\n this.disconnect();\n return;\n }\n }\n this.log.debug(`OpenAPI MQTT error: ${err.message}`);\n });\n\n this.client.on(\"close\", () => {\n this.onConnection?.(false);\n if (!this.lastErrorCategory) {\n this.lastErrorCategory = \"NETWORK\";\n this.log.debug(\"OpenAPI MQTT disconnected \u2014 will reconnect\");\n }\n this.scheduleReconnect();\n });\n } catch (err) {\n const category = classifyError(err);\n const msg = `OpenAPI MQTT connection failed: ${err instanceof Error ? err.message : String(err)}`;\n\n if (category !== this.lastErrorCategory) {\n this.lastErrorCategory = category;\n this.log.warn(msg);\n } else {\n this.log.debug(msg);\n }\n\n this.scheduleReconnect();\n }\n }\n\n /** Whether the client is currently connected */\n get connected(): boolean {\n return this.client?.connected ?? false;\n }\n\n /** Disconnect and cleanup */\n disconnect(): void {\n if (this.reconnectTimer) {\n this.timers.clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n if (this.client) {\n this.client.removeAllListeners();\n this.client.on(\"error\", () => {\n /* ignore late errors */\n });\n this.client.end(true);\n this.client = null;\n }\n }\n\n /**\n * Parse incoming MQTT event message.\n * Expected format: { sku, device, capabilities: [{ type, instance, state: { value } }] }\n *\n * @param payload Raw MQTT message buffer\n */\n private handleMessage(payload: Buffer): void {\n try {\n const rawStr = payload.toString();\n\n // Always forward raw JSON for diagnostics\n this.onRaw?.(rawStr);\n\n const raw = JSON.parse(rawStr) as Record<string, unknown>;\n\n const sku = (raw.sku as string) ?? \"\";\n const device = (raw.device as string) ?? \"\";\n\n if (!sku && !device) {\n this.log.debug(\n `OpenAPI MQTT: message without device info: ${payload.toString().slice(0, 200)}`,\n );\n return;\n }\n\n // Extract capabilities array\n const caps = raw.capabilities as CloudStateCapability[] | undefined;\n if (!caps || !Array.isArray(caps) || caps.length === 0) {\n this.log.debug(\n `OpenAPI MQTT: message without capabilities from ${sku}: ${payload.toString().slice(0, 300)}`,\n );\n return;\n }\n\n const event: OpenApiMqttEvent = { sku, device, capabilities: caps };\n this.onEvent?.(event);\n } catch {\n this.log.debug(\n `OpenAPI MQTT: failed to parse message: ${payload.toString().slice(0, 200)}`,\n );\n }\n }\n\n /** Schedule reconnect with exponential backoff */\n private scheduleReconnect(): void {\n if (this.reconnectTimer) {\n return;\n }\n if (this.connectFailCount >= MAX_CONNECT_FAILURES) {\n return;\n }\n\n this.reconnectAttempts++;\n const delay = Math.min(\n 5_000 * Math.pow(2, this.reconnectAttempts - 1),\n 300_000,\n );\n this.log.debug(\n `OpenAPI MQTT: reconnecting in ${delay / 1000}s (attempt ${this.reconnectAttempts})`,\n );\n\n this.reconnectTimer = this.timers.setTimeout(() => {\n this.reconnectTimer = undefined;\n if (this.onEvent && this.onConnection) {\n this.connect(this.onEvent, this.onConnection, this.onRaw ?? undefined);\n }\n }, delay);\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAAsB;AACtB,mBAMO;AAGP,MAAM,uBAAuB;AAE7B,MAAM,aAAa;AAiBZ,MAAM,uBAAuB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACT,SAAiC;AAAA,EACjC;AAAA,EACA,iBAA+C;AAAA,EAC/C,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,oBAA0C;AAAA,EAC1C,UAAuC;AAAA,EACvC,QAAmC;AAAA,EACnC,eAAiD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzD,YAAY,QAAgB,KAAsB,QAAsB;AACtE,SAAK,SAAS;AACd,SAAK,MAAM;AACX,SAAK,SAAS;AACd,SAAK,QAAQ,MAAM,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,QACE,SACA,cACA,OACM;AACN,SAAK,UAAU;AACf,SAAK,eAAe;AACpB,SAAK,QAAQ,wBAAS;AAEtB,QAAI;AACF,WAAK,SAAS,KAAK,QAAQ,YAAY;AAAA,QACrC,UAAU,KAAK;AAAA,QACf,UAAU,KAAK;AAAA,QACf,UAAU,mBAAmB,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAAA,QACpD,iBAAiB;AAAA,QACjB,WAAW;AAAA,QACX,iBAAiB;AAAA,QACjB,oBAAoB;AAAA,MACtB,CAAC;AAED,WAAK,OAAO,GAAG,WAAW,MAAM;AAlFtC;AAmFQ,aAAK,oBAAoB;AACzB,aAAK,mBAAmB;AACxB,YAAI,KAAK,mBAAmB;AAK1B,eAAK,IAAI,KAAK,kCAAkC;AAChD,eAAK,oBAAoB;AAAA,QAC3B;AAEA,mBAAK,WAAL,mBAAa,UAAU,KAAK,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,QAAQ;AA9FhE,cAAAA;AA+FU,cAAI,KAAK;AACP,iBAAK,IAAI,KAAK,kCAAkC,IAAI,OAAO,EAAE;AAAA,UAC/D,OAAO;AACL,iBAAK,IAAI,MAAM,wCAAwC;AACvD,aAAAA,MAAA,KAAK,iBAAL,gBAAAA,IAAA,WAAoB;AAAA,UACtB;AAAA,QACF;AAAA,MACF,CAAC;AAED,WAAK,OAAO,GAAG,WAAW,CAAC,QAAQ,YAAY;AAC7C,aAAK,cAAc,OAAO;AAAA,MAC5B,CAAC;AAED,WAAK,OAAO,GAAG,SAAS,CAAC,QAAQ;AA5GvC;AA6GQ,cAAM,eAAW,4BAAc,GAAG;AAClC,YAAI,aAAa,QAAQ;AACvB,eAAK;AACL,cAAI,KAAK,oBAAoB,sBAAsB;AACjD,iBAAK,IAAI;AAAA,cACP;AAAA,YACF;AACA,uBAAK,iBAAL,8BAAoB;AACpB,iBAAK,WAAW;AAChB;AAAA,UACF;AAAA,QACF;AACA,aAAK,IAAI,MAAM,uBAAuB,IAAI,OAAO,EAAE;AAAA,MACrD,CAAC;AAED,WAAK,OAAO,GAAG,SAAS,MAAM;AA5HpC;AA6HQ,mBAAK,iBAAL,8BAAoB;AACpB,YAAI,CAAC,KAAK,mBAAmB;AAC3B,eAAK,oBAAoB;AACzB,eAAK,IAAI,MAAM,iDAA4C;AAAA,QAC7D;AACA,aAAK,kBAAkB;AAAA,MACzB,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,eAAW,4BAAc,GAAG;AAClC,YAAM,MAAM,mCAAmC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAE/F,UAAI,aAAa,KAAK,mBAAmB;AACvC,aAAK,oBAAoB;AACzB,aAAK,IAAI,KAAK,GAAG;AAAA,MACnB,OAAO;AACL,aAAK,IAAI,MAAM,GAAG;AAAA,MACpB;AAEA,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA;AAAA,EAGA,IAAI,YAAqB;AApJ3B;AAqJI,YAAO,gBAAK,WAAL,mBAAa,cAAb,YAA0B;AAAA,EACnC;AAAA;AAAA,EAGA,aAAmB;AACjB,QAAI,KAAK,gBAAgB;AACvB,WAAK,OAAO,aAAa,KAAK,cAAc;AAC5C,WAAK,iBAAiB;AAAA,IACxB;AACA,QAAI,KAAK,QAAQ;AACf,WAAK,OAAO,mBAAmB;AAC/B,WAAK,OAAO,GAAG,SAAS,MAAM;AAAA,MAE9B,CAAC;AACD,WAAK,OAAO,IAAI,IAAI;AACpB,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,cAAc,SAAuB;AA9K/C;AA+KI,QAAI;AACF,YAAM,SAAS,QAAQ,SAAS;AAGhC,iBAAK,UAAL,8BAAa;AAEb,YAAM,MAAM,KAAK,MAAM,MAAM;AAE7B,YAAM,OAAO,SAAI,QAAJ,YAAsB;AACnC,YAAM,UAAU,SAAI,WAAJ,YAAyB;AAEzC,UAAI,CAAC,OAAO,CAAC,QAAQ;AACnB,aAAK,IAAI;AAAA,UACP,8CAA8C,QAAQ,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC;AAAA,QAChF;AACA;AAAA,MACF;AAGA,YAAM,OAAO,IAAI;AACjB,UAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,GAAG;AACtD,aAAK,IAAI;AAAA,UACP,mDAAmD,GAAG,KAAK,QAAQ,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC;AAAA,QAC7F;AACA;AAAA,MACF;AAEA,YAAM,QAA0B,EAAE,KAAK,QAAQ,cAAc,KAAK;AAClE,iBAAK,YAAL,8BAAe;AAAA,IACjB,QAAQ;AACN,WAAK,IAAI;AAAA,QACP,0CAA0C,QAAQ,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC;AAAA,MAC5E;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,oBAA0B;AAChC,QAAI,KAAK,gBAAgB;AACvB;AAAA,IACF;AACA,QAAI,KAAK,oBAAoB,sBAAsB;AACjD;AAAA,IACF;AAEA,SAAK;AACL,UAAM,QAAQ,KAAK;AAAA,MACjB,MAAQ,KAAK,IAAI,GAAG,KAAK,oBAAoB,CAAC;AAAA,MAC9C;AAAA,IACF;AACA,SAAK,IAAI;AAAA,MACP,iCAAiC,QAAQ,GAAI,cAAc,KAAK,iBAAiB;AAAA,IACnF;AAEA,SAAK,iBAAiB,KAAK,OAAO,WAAW,MAAM;AArOvD;AAsOM,WAAK,iBAAiB;AACtB,UAAI,KAAK,WAAW,KAAK,cAAc;AACrC,aAAK,QAAQ,KAAK,SAAS,KAAK,eAAc,UAAK,UAAL,YAAc,MAAS;AAAA,MACvE;AAAA,IACF,GAAG,KAAK;AAAA,EACV;AACF;",
4
+ "sourcesContent": ["import * as crypto from \"node:crypto\";\nimport * as mqtt from \"mqtt\";\nimport {\n classifyError,\n type ErrorCategory,\n type OpenApiMqttEvent,\n type CloudStateCapability,\n type TimerAdapter,\n} from \"./types.js\";\n\n/** Max consecutive connection failures before giving up */\nconst MAX_CONNECT_FAILURES = 5;\n\nconst BROKER_URL = \"mqtts://mqtt.openapi.govee.com:8883\";\n\n/** Callback for incoming sensor events */\nexport type OpenApiEventCallback = (event: OpenApiMqttEvent) => void;\n\n/** Callback for raw MQTT messages (for diagnostics) */\nexport type OpenApiRawCallback = (rawJson: string) => void;\n\n/** Callback for connection state changes */\nexport type OpenApiConnectionCallback = (connected: boolean) => void;\n\n/**\n * Govee OpenAPI MQTT client for real-time sensor events.\n * Connects to mqtt.openapi.govee.com:8883 using the API key for auth.\n * Receives event capabilities (lackWater, iceFull, bodyAppeared etc.)\n * without consuming Cloud API budget.\n */\nexport class GoveeOpenapiMqttClient {\n private readonly apiKey: string;\n private readonly log: ioBroker.Logger;\n private readonly timers: TimerAdapter;\n /**\n * Stable client ID for the lifetime of the adapter instance. Generated once\n * in the constructor so reconnects keep the same identity \u2014 Govee's broker\n * can then take over the previous socket cleanly instead of rejecting the\n * new connection as a duplicate. Reusing Date.now() per connect() created a\n * fresh ID on every reconnect.\n */\n private readonly sessionUuid: string = crypto.randomUUID();\n private client: mqtt.MqttClient | null = null;\n private topic: string;\n private reconnectTimer: ioBroker.Timeout | undefined = undefined;\n private reconnectAttempts = 0;\n private connectFailCount = 0;\n private lastErrorCategory: ErrorCategory | null = null;\n private onEvent: OpenApiEventCallback | null = null;\n private onRaw: OpenApiRawCallback | null = null;\n private onConnection: OpenApiConnectionCallback | null = null;\n\n /**\n * @param apiKey Govee Cloud API key (used as username AND password)\n * @param log ioBroker logger\n * @param timers Timer adapter\n */\n constructor(apiKey: string, log: ioBroker.Logger, timers: TimerAdapter) {\n this.apiKey = apiKey;\n this.log = log;\n this.timers = timers;\n this.topic = `GA/${apiKey}`;\n }\n\n /**\n * Connect to the OpenAPI MQTT broker.\n *\n * @param onEvent Called on incoming sensor events\n * @param onConnection Called on connection state changes\n * @param onRaw Called with raw JSON for diagnostics\n */\n connect(\n onEvent: OpenApiEventCallback,\n onConnection: OpenApiConnectionCallback,\n onRaw?: OpenApiRawCallback,\n ): void {\n this.onEvent = onEvent;\n this.onConnection = onConnection;\n this.onRaw = onRaw ?? null;\n\n try {\n this.client = mqtt.connect(BROKER_URL, {\n username: this.apiKey,\n password: this.apiKey,\n clientId: `iob_govee_smart_${this.sessionUuid}`,\n protocolVersion: 4,\n keepalive: 60,\n reconnectPeriod: 0,\n rejectUnauthorized: true,\n });\n\n this.client.on(\"connect\", () => {\n this.reconnectAttempts = 0;\n this.connectFailCount = 0;\n if (this.lastErrorCategory) {\n // Only log on transition out of an error state \u2014 the routine\n // first-connect message is redundant with the adapter-level\n // \"Govee adapter ready \u2014 N devices, M groups (channels: \u2026)\"\n // line and was just noise.\n this.log.info(\"OpenAPI MQTT connection restored\");\n this.lastErrorCategory = null;\n }\n\n this.client?.subscribe(this.topic, { qos: 0 }, (err) => {\n if (err) {\n this.log.warn(`OpenAPI MQTT subscribe failed: ${err.message}`);\n } else {\n this.log.debug(\"OpenAPI MQTT subscribed to event topic\");\n this.onConnection?.(true);\n }\n });\n });\n\n this.client.on(\"message\", (_topic, payload) => {\n this.handleMessage(payload);\n });\n\n this.client.on(\"error\", (err) => {\n const category = classifyError(err);\n if (category === \"AUTH\") {\n this.connectFailCount++;\n if (this.connectFailCount >= MAX_CONNECT_FAILURES) {\n this.log.warn(\n \"OpenAPI MQTT auth failed repeatedly \u2014 check API key\",\n );\n this.onConnection?.(false);\n this.disconnect();\n return;\n }\n }\n this.log.debug(`OpenAPI MQTT error: ${err.message}`);\n });\n\n this.client.on(\"close\", () => {\n this.onConnection?.(false);\n if (!this.lastErrorCategory) {\n this.lastErrorCategory = \"NETWORK\";\n this.log.debug(\"OpenAPI MQTT disconnected \u2014 will reconnect\");\n }\n this.scheduleReconnect();\n });\n } catch (err) {\n const category = classifyError(err);\n const msg = `OpenAPI MQTT connection failed: ${err instanceof Error ? err.message : String(err)}`;\n\n if (category !== this.lastErrorCategory) {\n this.lastErrorCategory = category;\n this.log.warn(msg);\n } else {\n this.log.debug(msg);\n }\n\n this.scheduleReconnect();\n }\n }\n\n /** Whether the client is currently connected */\n get connected(): boolean {\n return this.client?.connected ?? false;\n }\n\n /** Disconnect and cleanup */\n disconnect(): void {\n if (this.reconnectTimer) {\n this.timers.clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n if (this.client) {\n this.client.removeAllListeners();\n this.client.on(\"error\", () => {\n /* ignore late errors */\n });\n this.client.end(true);\n this.client = null;\n }\n }\n\n /**\n * Parse incoming MQTT event message.\n * Expected format: { sku, device, capabilities: [{ type, instance, state: { value } }] }\n *\n * @param payload Raw MQTT message buffer\n */\n private handleMessage(payload: Buffer): void {\n try {\n const rawStr = payload.toString();\n\n // Always forward raw JSON for diagnostics\n this.onRaw?.(rawStr);\n\n const raw = JSON.parse(rawStr) as Record<string, unknown>;\n\n const sku = (raw.sku as string) ?? \"\";\n const device = (raw.device as string) ?? \"\";\n\n if (!sku && !device) {\n this.log.debug(\n `OpenAPI MQTT: message without device info: ${payload.toString().slice(0, 200)}`,\n );\n return;\n }\n\n // Extract capabilities array\n const caps = raw.capabilities as CloudStateCapability[] | undefined;\n if (!caps || !Array.isArray(caps) || caps.length === 0) {\n this.log.debug(\n `OpenAPI MQTT: message without capabilities from ${sku}: ${payload.toString().slice(0, 300)}`,\n );\n return;\n }\n\n const event: OpenApiMqttEvent = { sku, device, capabilities: caps };\n this.onEvent?.(event);\n } catch {\n this.log.debug(\n `OpenAPI MQTT: failed to parse message: ${payload.toString().slice(0, 200)}`,\n );\n }\n }\n\n /** Schedule reconnect with exponential backoff */\n private scheduleReconnect(): void {\n if (this.reconnectTimer) {\n return;\n }\n if (this.connectFailCount >= MAX_CONNECT_FAILURES) {\n return;\n }\n\n this.reconnectAttempts++;\n const delay = Math.min(\n 5_000 * Math.pow(2, this.reconnectAttempts - 1),\n 300_000,\n );\n this.log.debug(\n `OpenAPI MQTT: reconnecting in ${delay / 1000}s (attempt ${this.reconnectAttempts})`,\n );\n\n this.reconnectTimer = this.timers.setTimeout(() => {\n this.reconnectTimer = undefined;\n if (this.onEvent && this.onConnection) {\n this.connect(this.onEvent, this.onConnection, this.onRaw ?? undefined);\n }\n }, delay);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["_a"]
7
7
  }
package/io-package.json CHANGED
@@ -1,326 +1,326 @@
1
1
  {
2
- "common": {
3
- "name": "govee-smart",
4
- "version": "2.0.1",
5
- "news": {
6
- "2.0.1": {
7
- "en": "Hotfixes from real-world v2.0.0 install. Sensor state IDs (battery, temperature, humidity, …) now route to sensor/ instead of control/, and the state objects are created lazily on first write — fixes the \"control.battery has no existing object\" warning. Snapshots and scenes are no longer attached to non-light devices like thermometers and heaters. The boot-time \"27 experimental device(s) detected\" log dump was replaced with a targeted, once-per-SKU nudge that only fires when a real device of an experimental SKU appears. The redundant \"OpenAPI MQTT connected for sensor events\" info line was dropped (the adapter-ready summary already covers it). The govee-appliances v0.1.0 deprecation tag now also has its GitHub release page.",
8
- "de": "Hotfixes aus dem realen v2.0.0-Install. Sensor-State-IDs (battery, temperature, humidity, …) landen jetzt unter sensor/ statt control/, und die State-Objekte werden bei der ersten Schreibung lazy angelegt — fixt die Warnung „control.battery has no existing object\". Snapshots und Szenen werden nicht mehr an Nicht-Lights wie Thermometer oder Heizgeräte gehängt. Das Start-Log mit „27 experimentelle Geräte erkannt\" ist weg — stattdessen kommt ein gezielter Hinweis nur dann, wenn ein reales Gerät einer experimentellen SKU auftaucht. Die redundante „OpenAPI MQTT connected for sensor events\"-Info-Zeile fällt weg (der Adapter-Ready-Summary deckt sie). Der govee-appliances v0.1.0-Deprecation-Tag hat jetzt auch eine GitHub-Release-Seite.",
9
- "ru": "Хотфиксы из реальной установки v2.0.0. Sensor-State-IDs (battery, temperature, humidity, …) теперь идут в sensor/ вместо control/, и State-объекты создаются лениво при первой записи — исправляет предупреждение «control.battery has no existing object». Snapshots и сцены больше не прикрепляются к не-Light устройствам. Spam-лог «27 experimental devices detected» заменён на целевое уведомление только при появлении реального устройства экспериментального SKU. Избыточная info-строка «OpenAPI MQTT connected for sensor events» убрана.",
10
- "pt": "Correções de uma instalação real v2.0.0. IDs de state de sensor (battery, temperature, humidity, …) agora vão para sensor/ em vez de control/, e os objetos de state são criados lazily na primeira gravação — corrige o aviso «control.battery has no existing object». Snapshots e cenas não são mais anexados a dispositivos não-Light. O dump de log «27 experimental devices detected» foi substituído por uma notificação direcionada apenas quando um dispositivo real de SKU experimental aparece. A linha info redundante «OpenAPI MQTT connected for sensor events» foi removida.",
11
- "nl": "Hotfixes uit een echte v2.0.0-installatie. Sensor-state-IDs (battery, temperature, humidity, …) gaan nu naar sensor/ in plaats van control/, en de state-objecten worden lazy aangemaakt bij de eerste schrijfactie — repareert de waarschuwing «control.battery has no existing object». Snapshots en scènes worden niet meer aan niet-Light apparaten gekoppeld. De boot-log dump «27 experimental devices detected» is vervangen door een gerichte melding alleen bij een echt apparaat van een experimentele SKU. De overbodige info-regel «OpenAPI MQTT connected for sensor events» is verwijderd.",
12
- "fr": "Correctifs d'une installation v2.0.0 réelle. Les ID d'état de capteur (battery, temperature, humidity, …) vont maintenant vers sensor/ au lieu de control/, et les objets d'état sont créés paresseusement à la première écriture — corrige l'avertissement « control.battery has no existing object ». Les snapshots et scènes ne sont plus attachés aux appareils non-Light. Le dump de log « 27 experimental devices detected » a été remplacé par une notification ciblée uniquement quand un appareil réel d'un SKU expérimental apparaît. La ligne info redondante « OpenAPI MQTT connected for sensor events » a été supprimée.",
13
- "it": "Correzioni da un'installazione v2.0.0 reale. Gli ID di state dei sensori (battery, temperature, humidity, …) ora vanno in sensor/ invece di control/, e gli oggetti di state vengono creati lazy alla prima scrittura — risolve l'avviso «control.battery has no existing object». Snapshot e scene non vengono più collegati a dispositivi non-Light. Il dump di log all'avvio «27 experimental devices detected» è stato sostituito con una notifica mirata solo quando appare un dispositivo reale di una SKU sperimentale. La riga info ridondante «OpenAPI MQTT connected for sensor events» è stata rimossa.",
14
- "es": "Correcciones de una instalación v2.0.0 real. Los IDs de state de sensor (battery, temperature, humidity, …) ahora van a sensor/ en lugar de control/, y los objetos de state se crean perezosamente en la primera escritura — corrige la advertencia «control.battery has no existing object». Snapshots y escenas ya no se adjuntan a dispositivos no-Light. El volcado de log al inicio «27 experimental devices detected» fue reemplazado por una notificación dirigida solo cuando aparece un dispositivo real de un SKU experimental. La línea info redundante «OpenAPI MQTT connected for sensor events» fue eliminada.",
15
- "pl": "Poprawki z prawdziwej instalacji v2.0.0. Sensor-state-ID (battery, temperature, humidity, …) trafiają teraz do sensor/ zamiast control/, a obiekty state tworzone leniwie przy pierwszym zapisie naprawia ostrzeżenie «control.battery has no existing object». Snapshoty i sceny nie są już dołączane do urządzeń nie-Light. Log startowy «27 experimental devices detected» został zastąpiony celowym powiadomieniem tylko gdy pojawia się prawdziwe urządzenie eksperymentalnego SKU. Zbędna linia info «OpenAPI MQTT connected for sensor events» została usunięta.",
16
- "uk": "Хотфікси з реальної інсталяції v2.0.0. Sensor-state-ID (battery, temperature, humidity, …) тепер ідуть до sensor/ замість control/, а state-об'єкти створюються лінувато при першому записі — виправляє попередження «control.battery has no existing object». Снапшоти й сцени більше не прикріплюються до не-Light пристроїв. Запис при старті «27 experimental devices detected» замінено на цільове сповіщення лише коли з'являється реальний пристрій експериментального SKU. Зайвий info-рядок «OpenAPI MQTT connected for sensor events» прибрано.",
17
- "zh-cn": "来自真实 v2.0.0 安装的热修复。传感器状态 ID (battery, temperature, humidity, …) 现在路由到 sensor/ 而不是 control/,并且状态对象在第一次写入时延迟创建——修复「control.battery has no existing object」警告。快照和场景不再附加到非灯设备。启动时的「27 experimental devices detected」日志转储已被替换为仅在出现真实实验性 SKU 设备时的定向通知。冗余的「OpenAPI MQTT connected for sensor events」信息行已删除。"
18
- },
19
- "2.0.0": {
20
- "en": "Major release — Govee appliances and sensors are now handled by this adapter alongside lights. The standalone iobroker.govee-appliances adapter is deprecated and rolls into here. A new checkbox 'Enable experimental device support' in the config makes it easier to try unconfirmed models — the Wiki page Devices lists every supported SKU and its status. New info.openapiMqttConnected state for the second MQTT channel that delivers appliance events.",
21
- "de": "Major Release Govee Appliances und Sensoren laufen jetzt zusammen mit den Lights über diesen Adapter. Der separate iobroker.govee-appliances Adapter ist deprecated und wandert hier rein. Neuer Schalter 'Experimentelle Geräte-Unterstützung aktivieren' in der Config zum einfacheren Ausprobieren ungeprüfter Modelle — Wiki-Seite Geräte listet jedes unterstützte SKU mit Status. Neuer State info.openapiMqttConnected für den zweiten MQTT-Kanal mit Appliance-Events.",
22
- "ru": "Мажорный релиз приборы и датчики Govee теперь обрабатываются этим адаптером вместе с лампами. Отдельный адаптер iobroker.govee-appliances устарел и переезжает сюда. Новый переключатель 'Включить экспериментальную поддержку устройств' в настройках упрощает тестирование неподтверждённых моделей — страница Wiki Devices перечисляет каждый поддерживаемый SKU и его статус.",
23
- "pt": "Lançamento principal eletrodomésticos e sensores Govee agora são gerenciados por este adaptador junto com as luzes. O adaptador iobroker.govee-appliances autônomo está obsoleto e foi integrado aqui. Nova caixa de seleção 'Ativar suporte experimental a dispositivos' na configuração facilita testar modelos não confirmados — a página Wiki Devices lista todos os SKUs suportados e seu status.",
24
- "nl": "Major release Govee apparaten en sensoren worden nu door deze adapter samen met de lichten beheerd. De aparte iobroker.govee-appliances adapter is verouderd en is hierin opgenomen. Nieuw selectievakje 'Experimentele apparaatondersteuning inschakelen' in de configuratie maakt het eenvoudiger om onbevestigde modellen te proberen — de Wiki-pagina Devices vermeldt elke ondersteunde SKU en de status.",
25
- "fr": "Version majeure les appareils et capteurs Govee sont désormais gérés par cet adaptateur aux côtés des lumières. L'adaptateur iobroker.govee-appliances autonome est obsolète et fusionné ici. Une nouvelle case 'Activer la prise en charge expérimentale des appareils' dans la configuration facilite l'essai des modèles non confirmés — la page Wiki Devices liste chaque SKU pris en charge et son statut.",
26
- "it": "Rilascio principale gli elettrodomestici e i sensori Govee sono ora gestiti da questo adattatore insieme alle luci. L'adattatore iobroker.govee-appliances autonomo è obsoleto e si fonde qui. Nuova casella 'Attiva il supporto sperimentale dei dispositivi' nella configurazione facilita la prova di modelli non confermati la pagina Wiki Devices elenca ogni SKU supportato e il suo stato.",
27
- "es": "Versión principal los electrodomésticos y sensores Govee ahora son manejados por este adaptador junto con las luces. El adaptador iobroker.govee-appliances independiente está obsoleto y se fusiona aquí. Nueva casilla 'Activar soporte experimental de dispositivos' en la configuración facilita probar modelos no confirmados — la página Wiki Devices lista cada SKU compatible y su estado.",
28
- "pl": "Główne wydanie urządzenia i czujniki Govee teraz obsługiwane przez ten adapter razem z lampami. Samodzielny adapter iobroker.govee-appliances jest przestarzały i jest scalany tutaj. Nowe pole wyboru 'Włącz eksperymentalne wsparcie urządzeń' w konfiguracji ułatwia testowanie niepotwierdzonych modeli — strona Wiki Devices wymienia każdy obsługiwany SKU i jego status.",
29
- "uk": "Великий випуск пристрої та датчики Govee тепер обробляються цим адаптером разом із лампами. Окремий адаптер iobroker.govee-appliances застарілий і об'єднаний сюди. Новий перемикач 'Увімкнути експериментальну підтримку пристроїв' у конфігурації полегшує тестування непідтверджених моделей — сторінка Wiki Devices містить кожен підтримуваний SKU та його статус.",
30
- "zh-cn": "主要版本 Govee 电器和传感器现在由此适配器与灯具一起处理。独立的 iobroker.govee-appliances 适配器已弃用并合并到此处。配置中新增的'启用实验性设备支持'复选框使得测试未确认的型号更加容易 Wiki Devices 页面列出每个受支持的 SKU 及其状态。"
31
- },
32
- "1.11.0": {
33
- "en": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
34
- "de": "Szenen- / DIY- / Snapshot- / Music-Mode-Dropdowns akzeptieren jetzt drei Schreibweisen aus Blockly und JavaScript: den Index als String (\"1\"), den Index als Zahl (1), oder den Klartext-Namen (\"Aurora\", Groß/Klein egal, Whitespace egal). Der State-Typ wurde von string auf mixed geändert, damit der js-controller bei numerischem Schreiben nicht mehr \"expects type string but received number\" warnt. Doppelte Cloud-Namen werden automatisch eindeutig gemacht über Suffixe \" (2)\", \" (3)\" der erste Eintrag behält den Originalnamen, jedes Label landet in genau einem Index. Nach der Aktivierung ackt der Adapter den kanonischen Key zurück, damit das Dropdown unabhängig vom Schreibweg synchron bleibt.",
35
- "ru": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
36
- "pt": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
37
- "nl": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
38
- "fr": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
39
- "it": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
40
- "es": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
41
- "pl": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
42
- "uk": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value.",
43
- "zh-cn": "Scene / DIY scene / snapshot / music-mode dropdowns now accept three input forms from Blockly and JS: the index as a string (\"1\"), the index as a number (1), or the entry name (\"Aurora\", case-insensitive, trimmed). The state type changed from string to mixed so the js-controller no longer warns \"expects type string but received number\" when a script writes a numeric index. Duplicate entry names from the cloud are auto-disambiguated with \" (2)\", \" (3)\" suffixes so each label maps to exactly one index — first occurrence keeps the original name. After activation the adapter acks back the canonical key, so the dropdown stays in sync regardless of how the user wrote the value."
44
- },
45
- "1.10.1": {
46
- "en": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
47
- "de": "Fixder Knopf info.refresh_cloud_data hat bei jedem Klick alle Scene-/Music-/DIY-/SKU-Features-Bibliotheken pro Gerät neu abgefragt. Bibliotheken ändern sich pro SKU nie, mehrere Endpunkte liefern bei vielen Accounts 403 zurück, ergo baut sich nur ein mehrminütiger Rate-Limiter-Backlog auf (im Log sichtbar als minütliche POSTs an /device/scenes und /device/diy-scenes nach jedem Klick). Der Knopf lädt jetzt nur noch den Scenes-/Snapshot-Endpunkt nach, wo neue Govee-App-Snapshots tatsächlich auftauchen. Aufruf-Anzahl pro Klick sinkt von ~7 auf 2 pro Licht-Gerät.",
48
- "ru": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
49
- "pt": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
50
- "nl": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
51
- "fr": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
52
- "it": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
53
- "es": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
54
- "pl": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
55
- "uk": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device.",
56
- "zh-cn": "Fixthe info.refresh_cloud_data button was re-fetching every device's scene / music / DIY / SKU-features libraries on each click. Libraries never change for a given SKU, and several endpoints 403 for many accounts, so this only produced a multi-minute rate-limiter backlog (minute-spaced POSTs to /device/scenes and /device/diy-scenes after a click). The button now only re-runs the scene/snapshot endpoint, which is what new Govee-app snapshots actually show up on. Call count per click drops from ~7 to 2 per light device."
57
- },
58
- "1.10.0": {
59
- "en": "Two fixes around mode tracking. First, scenes with a scenceParam (the multi-packet A3 BLE payload that drives per-segment animation) are now skipped for devices without segments (e.g. H70B3 Curtain Lights, bulbs) and activated via the Govee Cloud instead those devices silently drop the A3 packets, so the old ptReal path left the scene unplayed. Second, powering a device off now resets every mode dropdown (scene, DIY scene, Cloud/local snapshot, music) to \"---\", whether the off was triggered from ioBroker or from the Govee app — a device that is off cannot be \"playing Aurora-A\".",
60
- "de": "Zwei Fixes rund um Mode-Tracking. Erstens: Szenen mit scenceParam (das Multi-Packet-A3-BLE-Format für Segment-Animationen) werden auf Geräten ohne Segmente (z.B. H70B3 Curtain Lights, Birnen) nicht mehr per ptReal versucht sondern direkt über die Govee Cloud aktiviert diese Geräte verwerfen die A3-Pakete stumm, der alte ptReal-Pfad ließ die Szene damit ungespielt. Zweitens: Beim Ausschalten eines Geräts werden jetzt alle Mode-Dropdowns (Szene, DIY-Szene, Cloud-/lokaler Snapshot, Musik) auf \"---\" zurückgesetzt — egal ob die Power-off-Aktion von ioBroker oder aus der Govee App kam. Ein ausgeschaltetes Gerät kann nicht mehr \"Aurora-A spielen\".",
61
- "ru": "Два исправления связанных с режимами. Сцены со scenceParam теперь используют Cloud-активацию на устройствах без сегментов (H70B3 и др.)ptReal-пакеты эти устройства молча игнорировали. Выключение устройства теперь сбрасывает все mode-dropdowns (сцена, snapshot, music) на \"---\", независимо от источника выключения.",
62
- "pt": "Duas correções em mode-tracking. Cenas com scenceParam agora usam ativação Cloud em dispositivos sem segmentos (H70B3 etc.)os pacotes ptReal eram silenciosamente descartados. Desligar o dispositivo agora reseta todos os mode-dropdowns para \"---\", independente da origem.",
63
- "nl": "Twee fixes voor mode-tracking. Scenes met scenceParam gebruiken nu cloud-activatie op apparaten zonder segmenten (H70B3 etc.) die verwerpen de ptReal-pakketten stilletjes. Apparaat uitschakelen reset nu alle mode-dropdowns naar \"---\", ongeacht de bron.",
64
- "fr": "Deux correctifs autour du tracking des modes. Les scènes avec scenceParam utilisent maintenant l’activation Cloud sur les appareils sans segments (H70B3 etc.)ces appareils rejetaient silencieusement les paquets ptReal. Éteindre un appareil remet maintenant tous les mode-dropdowns à « --- », quelle que soit la source.",
65
- "it": "Due fix sul mode-tracking. Scene con scenceParam ora usano attivazione Cloud sui dispositivi senza segmenti (H70B3 etc.)quei dispositivi scartavano silenziosamente i pacchetti ptReal. Spegnere un dispositivo ora resetta tutti i mode-dropdown a \"---\", indipendentemente dall’origine.",
66
- "es": "Dos correcciones en el mode-tracking. Las escenas con scenceParam ahora usan activación Cloud en dispositivos sin segmentos (H70B3 etc.)esos dispositivos descartaban silenciosamente los paquetes ptReal. Apagar un dispositivo ahora resetea todos los mode-dropdowns a \"---\", independientemente del origen.",
67
- "pl": "Dwie poprawki w mode-tracking. Sceny z scenceParam używają teraz aktywacji Cloud na urządzeniach bez segmentów (H70B3 itd.)te urządzenia po cichu odrzucały pakiety ptReal. Wyłączenie urządzenia resetuje teraz wszystkie mode-dropdowns do \"---\", niezależnie od źródła.",
68
- "uk": "Два виправлення в mode-tracking. Сцени з scenceParam тепер активуються через Cloud на пристроях без сегментів (H70B3 тощо) — ці пристрої мовчки відкидали ptReal-пакети. Вимкнення пристрою тепер скидає всі mode-dropdowns на \"---\", незалежно від джерела.",
69
- "zh-cn": "两个 mode-tracking 修复。带 scenceParam 的场景现在在无段设备(H70B3 等)上通过 Cloud 激活 这些设备会默默丢弃 ptReal 包。关闭设备现在会将所有 mode-dropdown 重置为 \"---\",无论来源。"
70
- },
71
- "1.9.1": {
72
- "en": "Hotfix cloud-side scene/snapshot updates are now merged per list instead of all-or-nothing. Govee’s /device/scenes occasionally returns e.g. 149 scenes + 0 snapshots on the same device where a snapshot clearly exists; the old combined guard wiped the snapshots list in that case, breaking the cloud-snapshot dropdown with “invalid snapshot index” errors. Each of scenes, DIY scenes and snapshots is now guarded independently so a lucky list never clobbers an unlucky one.",
73
- "de": "Hotfix — Cloud-Aktualisierungen für Szenen/Snapshots werden jetzt pro Liste gemerged statt alles-oder-nichts. Govees /device/scenes liefert gelegentlich z.B. 149 Szenen + 0 Snapshots obwohl ein Snapshot existiert; der alte kombinierte Guard hat die Snapshot-Liste in dem Fall geleert und damit das Cloud-Snapshot-Dropdown mit „invalid snapshot index“-Fehlern gebrochen. Szenen, DIY-Szenen und Snapshots werden jetzt unabhängig gegen leeres Cloud-Ergebnis geschützt.",
74
- "ru": "Хотфикс обновление сцен/снапшотов из облака теперь мержится по отдельным спискам, а не всё сразу. Govee иногда возвращает сцены + 0 снапшотов там где снапшот реально существует; старая логика стирала список снапшотов, ломая dropdown с ошибкой \"invalid snapshot index\". Списки теперь защищены независимо.",
75
- "pt": "Hotfix atualizações cloud de cenas/snapshots agora são mescladas por lista. Govee às vezes retorna cenas + 0 snapshots quando o snapshot existe; o guard antigo apagava a lista de snapshots, causando erros \"invalid snapshot index\" no dropdown. Agora cada lista é protegida separadamente.",
76
- "nl": "Hotfix — cloud-updates van scenes/snapshots worden nu per lijst samengevoegd. Govee retourneert soms scenes + 0 snapshots terwijl de snapshot bestaat; de oude guard wiste de snapshot-lijst in dat geval, waardoor het dropdown brak met \"invalid snapshot index\". Elke lijst wordt nu afzonderlijk beschermd.",
77
- "fr": "Hotfix les mises à jour cloud des scènes/snapshots sont maintenant fusionnées par liste. Govee renvoie parfois des scènes + 0 snapshot alors que le snapshot existe ; l’ancien guard effaçait la liste des snapshots, cassant le dropdown avec l’erreur « invalid snapshot index ». Chaque liste est maintenant protégée séparément.",
78
- "it": "Hotfix gli aggiornamenti cloud di scene/snapshot ora vengono uniti per lista. Govee talvolta restituisce scene + 0 snapshot quando lo snapshot esiste; il vecchio guard cancellava la lista degli snapshot, rompendo il dropdown con errori \"invalid snapshot index\". Ora ogni lista è protetta separatamente.",
79
- "es": "Hotfix las actualizaciones cloud de escenas/snapshots ahora se fusionan por lista. Govee a veces devuelve escenas + 0 snapshots cuando el snapshot existe; el guard antiguo borraba la lista de snapshots, rompiendo el dropdown con errores \"invalid snapshot index\". Cada lista ahora está protegida por separado.",
80
- "pl": "Hotfix aktualizacje cloud scen/snapshotów teraz mergeowane osobno dla każdej listy. Govee czasem zwraca sceny + 0 snapshotów gdy snapshot istnieje; stary guard czyścił listę snapshotów, psując dropdown z błędem \"invalid snapshot index\". Każda lista jest teraz chroniona osobno.",
81
- "uk": "Хотфікс оновлення сцен/снепшотів з клауду тепер мержаться посписочно. Govee іноді повертає сцени + 0 снепшотів коли снепшот існує; старий guard стирав список снепшотів, ламаючи dropdown з помилкою \"invalid snapshot index\". Кожен список тепер захищено окремо.",
82
- "zh-cn": "热修复 云端场景/快照更新现在按列表分别合并。Govee 有时返回场景 + 0 快照(快照实际存在),旧的 guard 会清空快照列表,导致 dropdown 出现 \"invalid snapshot index\" 错误。每个列表现在独立保护。"
83
- },
84
- "1.9.0": {
85
- "en": "BREAKING: the cloud-snapshot dropdown has been renamed from snapshots.snapshot to snapshots.snapshot_cloud — update your scripts if they reference the old id. Plus: scene and snapshot data are now re-fetched from the Govee Cloud on every adapter start (a new snapshot you created in the Govee Home app now appears after restart) and a new info.refresh_cloud_data button lets you trigger the same refresh without a restart. Every snapshot state now carries a clear description telling you whether it is the Cloud or the Local kind.",
86
- "de": "BREAKING: der Cloud-Snapshot-Datenpunkt heißt jetzt snapshots.snapshot_cloud statt snapshots.snapshot — Skripte mit der alten ID anpassen. Außerdem: Szenen- und Snapshot-Daten werden bei jedem Adapter-Start frisch aus der Govee Cloud geholt (ein neuer Snapshot aus der Govee Home App ist nach einem Restart sichtbar), plus neuer Button info.refresh_cloud_data für den manuellen Refresh ohne Restart. Alle vier Snapshot-States haben jetzt eine Beschreibung die Cloud vs. Lokal klar benennt.",
87
- "ru": "BREAKING: состояние snapshots.snapshot переименовано в snapshots.snapshot_cloud. Сценарии и снапшоты обновляются из Govee Cloud при каждом запуске. Новая кнопка info.refresh_cloud_data для ручного обновления. У всех состояний снапшотов теперь понятное описание.",
88
- "pt": "BREAKING: snapshots.snapshot renomeado para snapshots.snapshot_cloud. Cenas e snapshots agora são atualizados da Govee Cloud a cada inicialização. Novo botão info.refresh_cloud_data para refresh manual. Descrições claras em todos os estados de snapshot.",
89
- "nl": "BREAKING: snapshots.snapshot hernoemd naar snapshots.snapshot_cloud. Scenes en snapshots worden bij elke adapterstart vers opgehaald uit de Govee Cloud. Nieuwe knop info.refresh_cloud_data voor handmatige refresh. Duidelijke beschrijvingen bij alle snapshot-states.",
90
- "fr": "BREAKING : snapshots.snapshot renommé en snapshots.snapshot_cloud. Les scènes et snapshots sont maintenant rechargés depuis le Cloud Govee à chaque démarrage. Nouveau bouton info.refresh_cloud_data pour un refresh manuel. Descriptions claires sur tous les states snapshot.",
91
- "it": "BREAKING: snapshots.snapshot rinominato in snapshots.snapshot_cloud. Scene e snapshot ora vengono ricaricati dal Cloud Govee ad ogni avvio. Nuovo pulsante info.refresh_cloud_data per refresh manuale. Descrizioni chiare su tutti gli state degli snapshot.",
92
- "es": "BREAKING: snapshots.snapshot renombrado a snapshots.snapshot_cloud. Escenas y snapshots se recargan desde Govee Cloud en cada inicio. Nuevo botón info.refresh_cloud_data para refresh manual. Descripciones claras en todos los states de snapshot.",
93
- "pl": "BREAKING: snapshots.snapshot przemianowany na snapshots.snapshot_cloud. Sceny i snapshoty odświeżane z Govee Cloud przy każdym starcie. Nowy przycisk info.refresh_cloud_data do ręcznego odświeżenia. Jasne opisy przy wszystkich stanach snapshot.",
94
- "uk": "BREAKING: snapshots.snapshot перейменовано на snapshots.snapshot_cloud. Сцени та снепшоти оновлюються з Govee Cloud при кожному запуску. Нова кнопка info.refresh_cloud_data для ручного оновлення. Чіткі описи в усіх snapshot-states.",
95
- "zh-cn": "BREAKING: snapshots.snapshot 重命名为 snapshots.snapshot_cloud。场景和快照在每次适配器启动时从 Govee Cloud 刷新。新的 info.refresh_cloud_data 按钮用于手动刷新。所有快照状态都有清晰的描述。"
96
- }
97
- },
98
- "titleLang": {
99
- "en": "Govee Smart",
100
- "de": "Govee Smart",
101
- "ru": "Govee Smart",
102
- "pt": "Govee Smart",
103
- "nl": "Govee Smart",
104
- "fr": "Govee Smart",
105
- "it": "Govee Smart",
106
- "es": "Govee Smart",
107
- "pl": "Govee Smart",
108
- "uk": "Govee Smart",
109
- "zh-cn": "Govee Smart"
110
- },
111
- "desc": {
112
- "en": "Control Govee WiFi devices via LAN, MQTT and Cloud API.",
113
- "de": "Govee WiFi-Geräte über LAN, MQTT und Cloud-API steuern.",
114
- "ru": "Управление WiFi-устройствами Govee через LAN, MQTT и Cloud API.",
115
- "pt": "Controle dispositivos Govee WiFi via LAN, MQTT e Cloud API.",
116
- "nl": "Bedien Govee WiFi-apparaten via LAN, MQTT en Cloud API.",
117
- "fr": "Contrôlez les appareils WiFi Govee via LAN, MQTT et Cloud API.",
118
- "it": "Controlla i dispositivi WiFi Govee tramite LAN, MQTT e Cloud API.",
119
- "es": "Controla los dispositivos WiFi de Govee mediante LAN, MQTT y Cloud API.",
120
- "pl": "Steruj urządzeniami WiFi Govee przez LAN, MQTT i Cloud API.",
121
- "uk": "Керування пристроями Govee WiFi через LAN, MQTT та Cloud API.",
122
- "zh-cn": "通过 LAN、MQTT 和 Cloud API 控制 Govee WiFi 设备。"
123
- },
124
- "authors": [
125
- "krobi <krobi@power-dreams.com>"
126
- ],
127
- "licenseInformation": {
128
- "license": "MIT",
129
- "type": "free"
130
- },
131
- "platform": "Javascript/Node.js",
132
- "icon": "govee-smart.svg",
133
- "extIcon": "https://raw.githubusercontent.com/krobipd/ioBroker.govee-smart/main/admin/govee-smart.svg",
134
- "readme": "https://github.com/krobipd/ioBroker.govee-smart/blob/main/README.md",
135
- "enabled": true,
136
- "tier": 3,
137
- "loglevel": "info",
138
- "mode": "daemon",
139
- "messagebox": true,
140
- "keywords": [
141
- "govee",
142
- "lights",
143
- "led",
144
- "lan",
145
- "mqtt",
146
- "ble"
147
- ],
148
- "type": "lighting",
149
- "compact": true,
150
- "connectionType": "local",
151
- "dataSource": "push",
152
- "adminUI": {
153
- "config": "json"
154
- },
155
- "supportedMessages": {
156
- "stopInstance": true
157
- },
158
- "dependencies": [
159
- {
160
- "js-controller": ">=7.0.0"
161
- }
162
- ],
163
- "globalDependencies": [
164
- {
165
- "admin": ">=7.6.20"
166
- }
167
- ]
2
+ "common": {
3
+ "name": "govee-smart",
4
+ "version": "2.0.3",
5
+ "news": {
6
+ "2.0.3": {
7
+ "en": "Min js-controller correction: was incorrectly bumped to `>=7.0.23` in 2.0.2 (and admin downgraded from `>=7.6.20` to `>=7.6.17`). The repochecker-recommended values are `>=6.0.11` / `>=7.6.20` restored.",
8
+ "de": "Min js-Controller-Korrektur: wurde falsch auf `>=7.0.23` in 2.0.2 (und admin downgraded von `>=7.6.20` auf `>=7.6.17 `) gesprungen. Die repochecker-recommended Werte sind `>=6.0.11 ` / `>=7.6.20 ` - restauriert.",
9
+ "ru": "Коррекция Min js-контроллера: в 2.0.2 она была неправильно увеличена до «>=7.0.23» (и админ был понижен с «>=7.6.20» до «>=7.6.17»). Рекомендуемые значения репочекера - \">=6.0.11\" / \">=7.6.20\" - восстановлены.",
10
+ "pt": "Min js-controller correção: foi incorretamente bateu para `>=7.0.23` em 2.0.2 (e admin desclassificado de `>=7.6,20` para `>=7.6.17`). Os valores recomendados pelo repochecker são `>=6.0.11` / `>=7.6.20` restaurados.",
11
+ "nl": "Min js-controller correctie: werd foutief gestoten naar De door de repochecker aanbevolen waardes zijn hersteld.",
12
+ "fr": "Correction de l'administrateur de Min js: a été incorrectement cognée à `>=7.0.23` en 2.0.2 (et l'administrateur a été rétrogradé de `>=7.6.20` à `>=7.6.17`). Les valeurs recommandées par repochecker sont `>=6.0.11` / `>=7.6.20` - restaurées.",
13
+ "it": "Min js-controller correzione: è stato erroneamente urtato a `>=7.0.23` in 2.0.2 (e admin downgraded da `>=7.6.20` a `>=7.6.17`). I valori repochecker-recommended sono `>=6.0.11` / `>=7.6.20` ripristinati.",
14
+ "es": "Min js-controller correction: was incorrectly toped to ` ` {=7.0.23` in 2.0.2 (and admin downgraded from ` {=7.6.20` to ` {=7.6.17`). Los valores recomendados por el depositchecker son \" confianza=6.0.11 \" / ` confianza=7.6.20 \" , restaurados.",
15
+ "pl": "Korekta Min js- controller: została nieprawidłowo przeskoczona do '> = 7.0.23' w 2.0.2 (a admin zmniejszył się z '> = 7.6.20' do '> = 7.6.17'). Zalecane wartości repochecker- to '> = 6.0.11' / '> = 7.6.20' - przywrócone.",
16
+ "uk": "Нормативно звернулися до `>=7.0.23` в 2.0.2 (і адміністратором, опущений від `>=7.6.20` до `>=7.6.17`). Репочекерно-відновлені значення `>=6.0.11` / `>=7.6.20` відновлено.",
17
+ "zh-cn": "Min js-controler更正:错误地在2.0.2中跌至QQ7.0.23 ' (行政级别从QQ7.6.20`降至QQ7.6.17) 重新检查器推荐的数值为6.0.11` /`7.6.20 ' ——恢复."
18
+ },
19
+ "2.0.2": {
20
+ "en": "OpenAPI MQTT now uses a stable client ID across reconnects (Govee's broker treated each reconnect as a new connection). Min js-controller bumped to >=7.0.23. Consistency cleanup vs. the other krobi adapters.",
21
+ "de": "OpenAPI MQTT verwendet jetzt eine stabile Client-ID über Reconnects hinweg (Goveeas Broker behandelte jeden Reconnect bisher als neue Verbindung). js-controller-Mindestversion auf >=7.0.23 angehoben. Konsistenz-Cleanup gegenüber den anderen krobi-Adaptern.",
22
+ "ru": "OpenAPI MQTT теперь использует стабильный client ID при переподключениях (брокер Govee воспринимал каждое переподключение как новое). Минимальная версия js-controller повышена до >=7.0.23. Очистка несогласованностей по сравнению с другими krobi-адаптерами.",
23
+ "pt": "OpenAPI MQTT agora usa um client ID estável entre reconexões (o broker da Govee tratava cada reconexão como uma nova conexão). Versão mínima do js-controller atualizada para >=7.0.23. Limpeza de consistência em relação aos outros adaptadores krobi.",
24
+ "nl": "OpenAPI MQTT gebruikt nu een stabiele client-ID bij reconnects (Govee's broker behandelde elke reconnect als nieuwe verbinding). Minimale js-controller-versie verhoogd naar >=7.0.23. Consistency-opruiming tegenover de andere krobi-adapters.",
25
+ "fr": "OpenAPI MQTT utilise désormais un client ID stable lors des reconnexions (le broker Govee traitait chaque reconnexion comme une nouvelle connexion). Version minimale de js-controller portée à >=7.0.23. Nettoyage de cohérence par rapport aux autres adaptateurs krobi.",
26
+ "it": "OpenAPI MQTT usa ora un client ID stabile tra le riconnessioni (il broker Govee trattava ogni riconnessione come una nuova connessione). Versione minima di js-controller alzata a >=7.0.23. Pulizia di coerenza rispetto agli altri adattatori krobi.",
27
+ "es": "OpenAPI MQTT ahora usa un client ID estable entre reconexiones (el broker de Govee trataba cada reconexión como una conexión nueva). Versión mínima de js-controller elevada a >=7.0.23. Limpieza de consistencia respecto a los demás adaptadores krobi.",
28
+ "pl": "OpenAPI MQTT używa teraz stabilnego identyfikatora klienta przy ponownych połączeniach (broker Govee traktował każde ponowne połączenie jako nowe). Minimalna wersja js-controller podniesiona do >=7.0.23. Porządkowanie spójności względem pozostałych adapterów krobi.",
29
+ "uk": "OpenAPI MQTT тепер використовує стабільний client ID під час перепідключень (брокер Govee розглядав кожне перепідключення як нове). Мінімальну версію js-controller підвищено до >=7.0.23. Очищення узгодженості порівняно з іншими krobi-адаптерами.",
30
+ "zh-cn": "OpenAPI MQTT 现在在重新连接时使用稳定的 client ID(Govee broker 之前将每次重连视为新连接)。js-controller 最低版本提升到 >=7.0.23。与其他 krobi 适配器的一致性清理。"
31
+ },
32
+ "2.0.1": {
33
+ "en": "Hotfixes from a real-world v2.0.0 install. Sensor states route to sensor/, event states to events/ (was control/ for both); state objects are created lazily on first write. Snapshots and scenes only attach to lights now; thermometers/heaters/kettles no longer get snapshot states. Boot-time experimental-device log dump removed.",
34
+ "de": "Hotfixes aus dem realen v2.0.0-Install. Sensor-States landen jetzt unter sensor/, Event-States unter events/ (vorher control/ für beide); State-Objekte werden lazy beim ersten Schreiben angelegt. Snapshots und Szenen hängen jetzt nur noch an Leuchten; Thermometer/Heizgeräte/Wasserkocher bekommen keine Snapshot-States mehr. Der experimental-device-Log-Dump beim Start entfällt.",
35
+ "ru": "Хотфіксы після реальної інсталяції v2.0.0. State-IDs сенсорів тепер розташовуються в sensor/, події в events/ (раніше control/); state-об'єкти створюються лениво при першому записі. Snapshots і сцени тепер прикріплюються лише до ламп; термометри/обігрівачі/чайники більше не отримують snapshot-states. Стартовий experimental-device-лог прибрано.",
36
+ "pt": "Correções de uma instalação real do v2.0.0. Os states de sensor agora ficam em sensor/, os de eventos em events/ (antes control/ para ambos); os objetos são criados de forma preguiçosa na primeira escrita. Snapshots e cenas se anexam a luzes agora; termômetros/aquecedores/chaleiras não recebem mais snapshot-states. O log de experimental devices na inicialização foi removido.",
37
+ "nl": "Hotfixes na een echte v2.0.0-installatie. Sensor-states lopen nu naar sensor/, event-states naar events/ (was eerder control/ voor beide); state-objecten worden lui aangemaakt bij de eerste schrijving. Snapshots en scènes hangen nu alleen nog aan lampen; thermometers/verwarmingen/waterkokers krijgen geen snapshot-states meer. De boot-tijd experimental-device-logdump is weg.",
38
+ "fr": "Correctifs d'une installation réelle v2.0.0. Les states de capteurs vont maintenant dans sensor/, les états d'événements dans events/ (avant control/ pour les deux); les objets d'état sont créés à la volée au premier write. Snapshots et scènes ne s'attachent qu'aux lampes désormais; thermomètres/chauffages/bouilloires n'ont plus de snapshot-states. Le dump d'experimental devices au démarrage a été supprimé.",
39
+ "it": "Hotfix da un'installazione v2.0.0 reale. Gli state dei sensori ora vanno in sensor/, gli eventi in events/ (prima control/ per entrambi); gli oggetti vengono creati lazy alla prima scrittura. Snapshot e scene si collegano solo alle luci ora; termometri/riscaldatori/bollitori non hanno più snapshot-states. Il log di experimental device all'avvio è stato rimosso.",
40
+ "es": "Hotfixes de una instalación real de v2.0.0. Los states de sensor ahora van a sensor/, los de eventos a events/ (antes control/ para ambos); los objetos se crean lazy en la primera escritura. Snapshots y escenas solo se asocian a luces ahora; termómetros/calefactores/hervidores ya no reciben snapshot-states. El volcado de experimental devices al arranque se ha eliminado.",
41
+ "pl": "Hotfiksy z prawdziwej instalacji v2.0.0. State-ID sensorów trafiają teraz do sensor/, eventy do events/ (wcześniej control/ dla obu); obiekty stanu tworzone leniwie przy pierwszym zapisie. Snapshoty i sceny dołączane tylko do oświetlenia; termometry/grzejniki/czajniki nie mają już snapshot-states. Startowy log experimental devices usunięty.",
42
+ "uk": "Хотфікси з реальної інсталяції v2.0.0. State сенсорів тепер у sensor/, події у events/ (раніше control/ для обох); state-об'єкти створюються лениво при першому записі. Snapshots і сцени тепер прив'язуються лише до ламп; термометри/обігрівачі/чайники більше не отримують snapshot-states. Стартовий experimental-device-дамп прибрано.",
43
+ "zh-cn": "来自真实 v2.0.0 安装的热修复。传感器状态 ID 现在路由到 sensor/,事件状态到 events/(之前都在 control/);状态对象在首次写入时延迟创建。Snapshots 和场景现在只附加到 lights;温度计/加热器/水壶不再获得 snapshot-states。启动时的 experimental device 日志已移除。"
44
+ },
45
+ "2.0.0": {
46
+ "en": "Major release Govee appliances and sensors (e.g. H5179 thermometers, heaters, kettles, ice makers) are now handled here alongside lights. The standalone iobroker.govee-appliances adapter is deprecated. New 'Enable experimental device support' checkbox; the Wiki Devices page lists every supported SKU. New info.openapiMqttConnected state for the OpenAPI-MQTT push channel.",
47
+ "de": "Major-ReleaseGovee-Appliances und -Sensoren (z.B. H5179-Thermometer, Heizgeräte, Wasserkocher, Eiswürfelbereiter) werden jetzt zusammen mit Leuchten hier verwaltet. Der eigenständige iobroker.govee-appliances-Adapter ist deprecated. Neue Checkbox 'Enable experimental device support'; die Wiki-Seite Devices listet alle unterstützten SKUs. Neuer State info.openapiMqttConnected für den OpenAPI-MQTT-Push-Kanal.",
48
+ "ru": "Major-релізпристрої Govee Appliances і сенсори (термометри H5179, обігрівачі, чайники, льодогенератори) тепер обробляються тут разом із лампами. Окремий адаптер iobroker.govee-appliances застарів. Новий чекбокс 'Enable experimental device support'; сторінка Devices у Wiki перелічує всі підтримувані SKU. Новий стейт info.openapiMqttConnected для OpenAPI-MQTT push-каналу.",
49
+ "pt": "Major release appliances e sensores Govee (por exemplo termômetros H5179, aquecedores, chaleiras, máquinas de gelo) são agora tratados aqui junto com as luzes. O adaptador iobroker.govee-appliances autônomo está depreciado. Nova caixa 'Enable experimental device support'; a página Devices do Wiki lista todos os SKUs suportados. Novo state info.openapiMqttConnected para o canal OpenAPI-MQTT push.",
50
+ "nl": "Major release Govee-appliances en -sensoren (bijv. H5179-thermometers, kachels, waterkokers, ijsmakers) worden nu samen met lampen hier afgehandeld. De losse iobroker.govee-appliances-adapter is deprecated. Nieuwe checkbox 'Enable experimental device support'; de Wiki Devices-pagina toont alle ondersteunde SKUs. Nieuwe state info.openapiMqttConnected voor het OpenAPI-MQTT push-kanaal.",
51
+ "fr": "Major release les appareils et capteurs Govee (thermomètres H5179, chauffages, bouilloires, machines à glace) sont maintenant gérés ici avec les lampes. L'adaptateur autonome iobroker.govee-appliances est déprécié. Nouvelle case 'Enable experimental device support'; la page Devices du Wiki liste tous les SKUs pris en charge. Nouveau state info.openapiMqttConnected pour le canal OpenAPI-MQTT push.",
52
+ "it": "Major release gli apparecchi e i sensori Govee (termometri H5179, riscaldatori, bollitori, macchine del ghiaccio) sono ora gestiti qui insieme alle luci. L'adattatore iobroker.govee-appliances autonomo è deprecato. Nuova checkbox 'Enable experimental device support'; la pagina Devices della Wiki elenca tutti gli SKU supportati. Nuovo state info.openapiMqttConnected per il canale OpenAPI-MQTT push.",
53
+ "es": "Major release los electrodomésticos y sensores Govee (termómetros H5179, calentadores, hervidores, máquinas de hielo) ahora se gestionan aquí junto a las luces. El adaptador independiente iobroker.govee-appliances está obsoleto. Nueva casilla 'Enable experimental device support'; la página Devices del Wiki lista todos los SKUs soportados. Nuevo state info.openapiMqttConnected para el canal OpenAPI-MQTT push.",
54
+ "pl": "Major release urządzenia i czujniki Govee (np. termometry H5179, grzejniki, czajniki, kostkarki) teraz obsługiwane tutaj wraz z oświetleniem. Samodzielny adapter iobroker.govee-appliances jest deprecated. Nowy checkbox 'Enable experimental device support'; strona Devices w Wiki zawiera listę wszystkich obsługiwanych SKU. Nowy state info.openapiMqttConnected dla kanału OpenAPI-MQTT push.",
55
+ "uk": "Major-релізтехніка Govee (термометри H5179, обігрівачі, чайники, льодогенератори) і сенсори тепер обробляються тут разом із лампами. Окремий iobroker.govee-appliances адаптер застарів. Новий чекбокс 'Enable experimental device support'; сторінка Devices у Wiki містить усі підтримувані SKU. Новий state info.openapiMqttConnected для OpenAPI-MQTT push-каналу.",
56
+ "zh-cn": "主版本发布Govee 电器和传感器(H5179 温度计、加热器、水壶、制冰机等)现在与灯具一起在此处理。独立的 iobroker.govee-appliances 适配器已弃用。新增 'Enable experimental device support' 复选框;Wiki Devices 页面列出所有支持的 SKU。新增 info.openapiMqttConnected state 用于 OpenAPI-MQTT push 通道。"
57
+ },
58
+ "1.11.0": {
59
+ "en": "Scene/DIY/snapshot/music-mode dropdowns now accept index-as-number, index-as-string and the entry name (case-insensitive). State type is mixedno more 'expects type string but received number' warning. Duplicate scene names from the cloud are auto-disambiguated with ' (2)', ' (3)' suffixes.",
60
+ "de": "Scene/DIY/Snapshot/Musik-Modus-Dropdowns akzeptieren jetzt Index als Zahl, Index als String und den Klartext-Namen (case-insensitive). State-Typ ist 'mixed'kein 'expects type string but received number'-Warning mehr. Doppelte Szenennamen aus der Cloud werden automatisch mit ' (2)', ' (3)' suffixiert.",
61
+ "ru": "Випадайки для сцен/DIY/snapshot/музики тепер приймають індекс як число, як string і назву елемента (case-insensitive). Тип state mixedпопередження 'expects type string but received number' зникло. Дублікати назв сцен з cloud отримують суфікси ' (2)', ' (3)'.",
62
+ "pt": "Os dropdowns de scene/DIY/snapshot/music-mode agora aceitam índice como número, como string e o nome da entrada (case-insensitive). O tipo do state é mixed o aviso 'expects type string but received number' desapareceu. Nomes duplicados de cena vindos da nuvem são automaticamente desambiguados com sufixos ' (2)', ' (3)'.",
63
+ "nl": "Scene/DIY/snapshot/music-mode dropdowns accepteren nu de index als number, als string en de entry-name (case-insensitive). State-type is mixed de waarschuwing 'expects type string but received number' is weg. Dubbele scènenamen uit de cloud krijgen automatisch ' (2)', ' (3)' achtervoegsels.",
64
+ "fr": "Les dropdowns scene/DIY/snapshot/music-mode acceptent désormais l'index en number, en string ou le nom (insensible à la casse). Le type de state est mixed l'avertissement 'expects type string but received number' a disparu. Les noms de scène dupliqués depuis le cloud sont automatiquement suffixés ' (2)', ' (3)'.",
65
+ "it": "I dropdown scene/DIY/snapshot/music-mode ora accettano l'indice come number, come string e il nome (case-insensitive). Il tipo di state è mixed l'avviso 'expects type string but received number' è scomparso. I nomi di scena duplicati dal cloud vengono auto-disambiguati con suffissi ' (2)', ' (3)'.",
66
+ "es": "Los desplegables scene/DIY/snapshot/music-mode aceptan ahora el índice como number, como string o el nombre (case-insensitive). El tipo de state es mixeddesaparece la advertencia 'expects type string but received number'. Los nombres de escena duplicados de la nube se desambiguan automáticamente con sufijos ' (2)', ' (3)'.",
67
+ "pl": "Listy rozwijane scene/DIY/snapshot/music-mode akceptują teraz indeks jako number, jako string oraz nazwę (case-insensitive). Typ state to mixed ostrzeżenie 'expects type string but received number' znika. Zduplikowane nazwy scen z chmury automatycznie różnicowane sufiksami ' (2)', ' (3)'.",
68
+ "uk": "Випадайки для scene/DIY/snapshot/music-mode тепер приймають індекс як number, як string і назву елемента (case-insensitive). Тип state mixed попередження 'expects type string but received number' зникло. Дубльовані назви сцен з cloud автоматично отримують суфікси ' (2)', ' (3)'.",
69
+ "zh-cn": "场景/DIY/snapshot/音乐模式下拉菜单现在接受索引为数字、索引为字符串或条目名称(不区分大小写)。state 类型为 mixed —— 'expects type string but received number' 警告消失。云端重复场景名称自动添加 ' (2)'、' (3)' 后缀。"
70
+ },
71
+ "1.10.1": {
72
+ "en": "Refresh button no longer re-fetches static SKU libraries (scene/music/DIY/features) call count drops from ~7 to 2 per device per click. Those endpoints returned 403 for many accounts and just produced minute-long rate-limiter backlogs.",
73
+ "de": "Refresh-Button holt nicht mehr die statischen SKU-Libraries (Scene/Music/DIY/Features) Call-Anzahl pro Gerät pro Klick fällt von ~7 auf 2. Diese Endpunkte lieferten 403 für viele Accounts und produzierten nur minutenlange Rate-Limiter-Backlogs.",
74
+ "ru": "Кнопка Refresh більше не перезавантажує статичні SKU-бібліотеки (scene/music/DIY/features) кількість викликів знижується з ~7 до 2 на пристрій за клік. Ці endpoint'и повертали 403 для багатьох акаунтів і лише накопичували відставання rate-limiter на хвилини.",
75
+ "pt": "O botão Refresh não busca mais as bibliotecas estáticas por SKU (scene/music/DIY/features) o número de chamadas cai de ~7 para 2 por dispositivo por clique. Esses endpoints retornavam 403 para muitas contas e produziam backlog de minutos no rate-limiter.",
76
+ "nl": "Refresh-knop haalt de statische SKU-bibliotheken (scene/music/DIY/features) niet meer opnieuw op aantal calls daalt van ~7 naar 2 per device per klik. Die endpoints leverden 403 voor veel accounts en zorgden alleen voor minutenlange rate-limiter backlog.",
77
+ "fr": "Le bouton Refresh ne récupère plus les bibliothèques statiques par SKU (scene/music/DIY/features) le nombre d'appels passe de ~7 à 2 par appareil par clic. Ces endpoints retournaient 403 pour beaucoup de comptes et ne produisaient qu'un backlog de plusieurs minutes côté rate-limiter.",
78
+ "it": "Il pulsante Refresh non ricarica più le librerie statiche per SKU (scene/music/DIY/features) il numero di chiamate scende da ~7 a 2 per dispositivo per click. Quegli endpoint restituivano 403 per molti account e producevano solo arretrati di minuti nel rate-limiter.",
79
+ "es": "El botón Refresh ya no vuelve a buscar las librerías estáticas por SKU (scene/music/DIY/features) el número de llamadas baja de ~7 a 2 por dispositivo por clic. Esos endpoints devolvían 403 para muchas cuentas y solo producían backlogs de minutos en el rate-limiter.",
80
+ "pl": "Przycisk Refresh nie pobiera już statycznych bibliotek SKU (scene/music/DIY/features) liczba wywołań spada z ~7 do 2 na urządzenie na kliknięcie. Te endpointy zwracały 403 dla wielu kont i powodowały tylko minutowy backlog rate-limitera.",
81
+ "uk": "Кнопка Refresh більше не перезавантажує статичні SKU-бібліотеки (scene/music/DIY/features) кількість викликів знижується з ~7 до 2 на пристрій за клік. Ці endpoint'и повертали 403 для багатьох акаунтів і лише накопичували rate-limiter-backlog на хвилини.",
82
+ "zh-cn": "刷新按钮不再重新获取静态 SKU 库(scene/music/DIY/features)—— 每次点击每设备的调用数从约 7 个降至 2 个。这些端点对许多账户返回 403,只会产生数分钟的 rate-limiter 积压。"
83
+ },
84
+ "1.10.0": {
85
+ "en": "Multi-packet A3 BLE scenes (scenceParam) are now activated via Cloud on devices without segments; bulbs and Curtain Lights silently dropped those packets before, so complex scenes never played. Powering a device off resets every mode dropdown to '---' both ioBroker and Govee-app initiated off events.",
86
+ "de": "Multi-Packet-A3-BLE-Szenen (scenceParam) werden jetzt auf Geräten ohne Segmente über die Cloud aktiviert; Bulbs und Curtain Lights haben diese Pakete bisher still verworfen, sodass komplexe Szenen nie liefen. Beim Ausschalten eines Geräts werden alle Modus-Dropdowns auf '---' zurückgesetzt sowohl bei ioBroker- als auch bei Govee-App-Off-Events.",
87
+ "ru": "Multi-packet A3 BLE-сцени (scenceParam) тепер активуються через Cloud на пристроях без сегментів; лампи і Curtain Lights раніше тихо ігнорували ці пакети, через що складні сцени не запускалися. При вимкненні пристрою всі моди-випадайки скидаються на '---' — як для ioBroker, так і для Govee-app off-event.",
88
+ "pt": "Cenas multi-packet A3 BLE (scenceParam) agora são ativadas via Cloud em dispositivos sem segmentos; lâmpadas e Curtain Lights descartavam silenciosamente esses pacotes, então cenas complexas nunca eram reproduzidas. Desligar um dispositivo reseta todos os dropdowns de modo para '---' — tanto eventos ioBroker quanto Govee-app.",
89
+ "nl": "Multi-packet A3 BLE-scènes (scenceParam) worden nu via Cloud geactiveerd op apparaten zonder segmenten; bulbs en Curtain Lights gooiden die pakketten stilzwijgend weg, dus complexe scènes speelden nooit. Een apparaat uitzetten reset alle mode-dropdowns naar '---' — zowel ioBroker- als Govee-app off-events.",
90
+ "fr": "Les scènes A3 BLE multi-paquets (scenceParam) sont maintenant activées via le Cloud sur les appareils sans segments; les ampoules et Curtain Lights ignoraient silencieusement ces paquets, donc les scènes complexes ne jouaient jamais. Éteindre un appareil réinitialise tous les dropdowns de mode à '---' — événements ioBroker et Govee-app.",
91
+ "it": "Le scene A3 BLE multi-pacchetto (scenceParam) ora vengono attivate via Cloud sui dispositivi senza segmenti; lampadine e Curtain Lights scartavano silenziosamente quei pacchetti, quindi le scene complesse non venivano mai riprodotte. Spegnere un dispositivo resetta tutti i dropdown di modalità a '---' — eventi ioBroker e Govee-app.",
92
+ "es": "Las escenas A3 BLE multi-paquete (scenceParam) ahora se activan vía Cloud en dispositivos sin segmentos; las bombillas y Curtain Lights descartaban silenciosamente esos paquetes, por lo que las escenas complejas nunca se reproducían. Apagar un dispositivo resetea todos los dropdowns de modo a '---' — tanto eventos de ioBroker como de la Govee-app.",
93
+ "pl": "Sceny A3 BLE z wielu pakietów (scenceParam) są teraz aktywowane przez Cloud na urządzeniach bez segmentów; żarówki i Curtain Lights po cichu odrzucały te pakiety, więc złożone sceny nigdy się nie odtwarzały. Wyłączenie urządzenia resetuje wszystkie listy modów do '---' zdarzenia z ioBrokera i z aplikacji Govee.",
94
+ "uk": "Multi-packet A3 BLE сцени (scenceParam) тепер активуються через Cloud на пристроях без сегментів; bulbs і Curtain Lights раніше мовчки відкидали ці пакети, тож складні сцени не запускалися. Вимкнення пристрою скидає всі моди-випадайки на '---' — як для ioBroker, так і для Govee-app off-події.",
95
+ "zh-cn": "多包 A3 BLE 场景(scenceParam)现在在没有 segments 的设备上通过 Cloud 激活;灯泡和 Curtain Lights 之前会静默丢弃这些包,导致复杂场景从未播放。关闭设备时所有模式下拉菜单重置为 '---' —— ioBroker 和 Govee-app 触发的关机事件都生效。"
96
+ }
168
97
  },
169
- "encryptedNative": [
170
- "apiKey",
171
- "goveePassword"
98
+ "titleLang": {
99
+ "en": "Govee Smart",
100
+ "de": "Govee Smart",
101
+ "ru": "Govee Smart",
102
+ "pt": "Govee Smart",
103
+ "nl": "Govee Smart",
104
+ "fr": "Govee Smart",
105
+ "it": "Govee Smart",
106
+ "es": "Govee Smart",
107
+ "pl": "Govee Smart",
108
+ "uk": "Govee Smart",
109
+ "zh-cn": "Govee Smart"
110
+ },
111
+ "desc": {
112
+ "en": "Control Govee WiFi devices via LAN, MQTT and Cloud API.",
113
+ "de": "Govee WiFi-Geräte über LAN, MQTT und Cloud-API steuern.",
114
+ "ru": "Управление WiFi-устройствами Govee через LAN, MQTT и Cloud API.",
115
+ "pt": "Controle dispositivos Govee WiFi via LAN, MQTT e Cloud API.",
116
+ "nl": "Bedien Govee WiFi-apparaten via LAN, MQTT en Cloud API.",
117
+ "fr": "Contrôlez les appareils WiFi Govee via LAN, MQTT et Cloud API.",
118
+ "it": "Controlla i dispositivi WiFi Govee tramite LAN, MQTT e Cloud API.",
119
+ "es": "Controla los dispositivos WiFi de Govee mediante LAN, MQTT y Cloud API.",
120
+ "pl": "Steruj urządzeniami WiFi Govee przez LAN, MQTT i Cloud API.",
121
+ "uk": "Керування пристроями Govee WiFi через LAN, MQTT та Cloud API.",
122
+ "zh-cn": "通过 LAN、MQTT 和 Cloud API 控制 Govee WiFi 设备。"
123
+ },
124
+ "authors": [
125
+ "krobi <krobi@power-dreams.com>"
172
126
  ],
173
- "protectedNative": [
174
- "apiKey",
175
- "goveePassword"
127
+ "licenseInformation": {
128
+ "license": "MIT",
129
+ "type": "free"
130
+ },
131
+ "platform": "Javascript/Node.js",
132
+ "icon": "govee-smart.svg",
133
+ "extIcon": "https://raw.githubusercontent.com/krobipd/ioBroker.govee-smart/main/admin/govee-smart.svg",
134
+ "readme": "https://github.com/krobipd/ioBroker.govee-smart/blob/main/README.md",
135
+ "enabled": true,
136
+ "tier": 3,
137
+ "loglevel": "info",
138
+ "mode": "daemon",
139
+ "messagebox": true,
140
+ "keywords": [
141
+ "govee",
142
+ "lights",
143
+ "led",
144
+ "lan",
145
+ "mqtt",
146
+ "ble"
176
147
  ],
177
- "instanceObjects": [
178
- {
179
- "_id": "info",
180
- "type": "channel",
181
- "common": {
182
- "name": {
183
- "en": "Information",
184
- "de": "Information",
185
- "ru": "Информация",
186
- "pt": "Informação",
187
- "nl": "Informatie",
188
- "fr": "Information",
189
- "it": "Informazioni",
190
- "es": "Información",
191
- "pl": "Informacja",
192
- "uk": "Інформація",
193
- "zh-cn": "信息"
194
- }
195
- },
196
- "native": {}
197
- },
198
- {
199
- "_id": "info.connection",
200
- "type": "state",
201
- "common": {
202
- "name": "Adapter connected",
203
- "type": "boolean",
204
- "role": "indicator.connected",
205
- "read": true,
206
- "write": false,
207
- "def": false
208
- },
209
- "native": {}
210
- },
211
- {
212
- "_id": "info.mqttConnected",
213
- "type": "state",
214
- "common": {
215
- "name": "MQTT connected",
216
- "type": "boolean",
217
- "role": "indicator.connected",
218
- "read": true,
219
- "write": false,
220
- "def": false
221
- },
222
- "native": {}
223
- },
224
- {
225
- "_id": "info.cloudConnected",
226
- "type": "state",
227
- "common": {
228
- "name": "Cloud API connected",
229
- "type": "boolean",
230
- "role": "indicator.connected",
231
- "read": true,
232
- "write": false,
233
- "def": false
234
- },
235
- "native": {}
236
- },
237
- {
238
- "_id": "info.openapiMqttConnected",
239
- "type": "state",
240
- "common": {
241
- "name": "Govee OpenAPI MQTT connected",
242
- "desc": "Push channel for sensor and appliance events. Independent of the AWS-IoT MQTT used for status push of regular Govee lights.",
243
- "type": "boolean",
244
- "role": "indicator.connected",
245
- "read": true,
246
- "write": false,
247
- "def": false
248
- },
249
- "native": {}
250
- },
251
- {
252
- "_id": "info.wizardStatus",
253
- "type": "state",
254
- "common": {
255
- "name": "Segment-Wizard status",
256
- "type": "string",
257
- "role": "text",
258
- "read": true,
259
- "write": false,
260
- "def": ""
261
- },
262
- "native": {}
263
- },
264
- {
265
- "_id": "info.refresh_cloud_data",
266
- "type": "state",
267
- "common": {
268
- "name": "Refresh Cloud Data",
269
- "desc": "Write true to re-fetch scenes, snapshots and device list from the Govee Cloud for all devices. Use this after creating a new snapshot in the Govee Home app to see it in the dropdown without restarting the adapter.",
270
- "type": "boolean",
271
- "role": "button",
272
- "read": true,
273
- "write": true,
274
- "def": false
275
- },
276
- "native": {}
277
- },
278
- {
279
- "_id": "devices",
280
- "type": "folder",
281
- "common": {
282
- "name": {
283
- "en": "Devices",
284
- "de": "Geräte",
285
- "ru": "Устройства",
286
- "pt": "Dispositivos",
287
- "nl": "Apparaten",
288
- "fr": "Appareils",
289
- "it": "Dispositivi",
290
- "es": "Dispositivos",
291
- "pl": "Urządzenia",
292
- "uk": "Пристрої",
293
- "zh-cn": "设备"
294
- }
295
- },
296
- "native": {}
297
- },
298
- {
299
- "_id": "groups",
300
- "type": "folder",
301
- "common": {
302
- "name": {
303
- "en": "Groups",
304
- "de": "Gruppen",
305
- "ru": "Группы",
306
- "pt": "Grupos",
307
- "nl": "Groepen",
308
- "fr": "Groupes",
309
- "it": "Gruppi",
310
- "es": "Grupos",
311
- "pl": "Grupy",
312
- "uk": "Групи",
313
- "zh-cn": "组"
314
- }
315
- },
316
- "native": {}
317
- }
148
+ "type": "lighting",
149
+ "compact": true,
150
+ "connectionType": "local",
151
+ "dataSource": "push",
152
+ "adminUI": {
153
+ "config": "json"
154
+ },
155
+ "supportedMessages": {
156
+ "stopInstance": true
157
+ },
158
+ "dependencies": [
159
+ {
160
+ "js-controller": ">=6.0.11"
161
+ }
318
162
  ],
319
- "native": {
320
- "apiKey": "",
321
- "goveeEmail": "",
322
- "goveePassword": "",
323
- "networkInterface": "0.0.0.0",
324
- "experimentalQuirks": false
163
+ "globalDependencies": [
164
+ {
165
+ "admin": ">=7.6.20"
166
+ }
167
+ ]
168
+ },
169
+ "encryptedNative": [
170
+ "apiKey",
171
+ "goveePassword"
172
+ ],
173
+ "protectedNative": [
174
+ "apiKey",
175
+ "goveePassword"
176
+ ],
177
+ "instanceObjects": [
178
+ {
179
+ "_id": "info",
180
+ "type": "channel",
181
+ "common": {
182
+ "name": {
183
+ "en": "Information",
184
+ "de": "Information",
185
+ "ru": "Информация",
186
+ "pt": "Informação",
187
+ "nl": "Informatie",
188
+ "fr": "Information",
189
+ "it": "Informazioni",
190
+ "es": "Información",
191
+ "pl": "Informacja",
192
+ "uk": "Інформація",
193
+ "zh-cn": "信息"
194
+ }
195
+ },
196
+ "native": {}
197
+ },
198
+ {
199
+ "_id": "info.connection",
200
+ "type": "state",
201
+ "common": {
202
+ "name": "Adapter connected",
203
+ "type": "boolean",
204
+ "role": "indicator.connected",
205
+ "read": true,
206
+ "write": false,
207
+ "def": false
208
+ },
209
+ "native": {}
210
+ },
211
+ {
212
+ "_id": "info.mqttConnected",
213
+ "type": "state",
214
+ "common": {
215
+ "name": "MQTT connected",
216
+ "type": "boolean",
217
+ "role": "indicator.connected",
218
+ "read": true,
219
+ "write": false,
220
+ "def": false
221
+ },
222
+ "native": {}
223
+ },
224
+ {
225
+ "_id": "info.cloudConnected",
226
+ "type": "state",
227
+ "common": {
228
+ "name": "Cloud API connected",
229
+ "type": "boolean",
230
+ "role": "indicator.connected",
231
+ "read": true,
232
+ "write": false,
233
+ "def": false
234
+ },
235
+ "native": {}
236
+ },
237
+ {
238
+ "_id": "info.openapiMqttConnected",
239
+ "type": "state",
240
+ "common": {
241
+ "name": "Govee OpenAPI MQTT connected",
242
+ "desc": "Push channel for sensor and appliance events. Independent of the AWS-IoT MQTT used for status push of regular Govee lights.",
243
+ "type": "boolean",
244
+ "role": "indicator.connected",
245
+ "read": true,
246
+ "write": false,
247
+ "def": false
248
+ },
249
+ "native": {}
250
+ },
251
+ {
252
+ "_id": "info.wizardStatus",
253
+ "type": "state",
254
+ "common": {
255
+ "name": "Segment-Wizard status",
256
+ "type": "string",
257
+ "role": "text",
258
+ "read": true,
259
+ "write": false,
260
+ "def": ""
261
+ },
262
+ "native": {}
263
+ },
264
+ {
265
+ "_id": "info.refresh_cloud_data",
266
+ "type": "state",
267
+ "common": {
268
+ "name": "Refresh Cloud Data",
269
+ "desc": "Write true to re-fetch scenes, snapshots and device list from the Govee Cloud for all devices. Use this after creating a new snapshot in the Govee Home app to see it in the dropdown without restarting the adapter.",
270
+ "type": "boolean",
271
+ "role": "button",
272
+ "read": true,
273
+ "write": true,
274
+ "def": false
275
+ },
276
+ "native": {}
277
+ },
278
+ {
279
+ "_id": "devices",
280
+ "type": "folder",
281
+ "common": {
282
+ "name": {
283
+ "en": "Devices",
284
+ "de": "Geräte",
285
+ "ru": "Устройства",
286
+ "pt": "Dispositivos",
287
+ "nl": "Apparaten",
288
+ "fr": "Appareils",
289
+ "it": "Dispositivi",
290
+ "es": "Dispositivos",
291
+ "pl": "Urządzenia",
292
+ "uk": "Пристрої",
293
+ "zh-cn": "设备"
294
+ }
295
+ },
296
+ "native": {}
297
+ },
298
+ {
299
+ "_id": "groups",
300
+ "type": "folder",
301
+ "common": {
302
+ "name": {
303
+ "en": "Groups",
304
+ "de": "Gruppen",
305
+ "ru": "Группы",
306
+ "pt": "Grupos",
307
+ "nl": "Groepen",
308
+ "fr": "Groupes",
309
+ "it": "Gruppi",
310
+ "es": "Grupos",
311
+ "pl": "Grupy",
312
+ "uk": "Групи",
313
+ "zh-cn": "组"
314
+ }
315
+ },
316
+ "native": {}
325
317
  }
318
+ ],
319
+ "native": {
320
+ "apiKey": "",
321
+ "goveeEmail": "",
322
+ "goveePassword": "",
323
+ "networkInterface": "0.0.0.0",
324
+ "experimentalQuirks": false
325
+ }
326
326
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.govee-smart",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Control Govee WiFi devices via LAN, MQTT and Cloud.",
5
5
  "author": {
6
6
  "name": "krobi",
@@ -31,7 +31,6 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@iobroker/adapter-core": "^3.3.2",
34
- "@iobroker/types": "^7.1.1",
35
34
  "mqtt": "^5.15.1",
36
35
  "node-forge": "^1.4.0"
37
36
  },
@@ -39,12 +38,11 @@
39
38
  "@alcalzone/release-script": "^5.1.1",
40
39
  "@alcalzone/release-script-plugin-iobroker": "^5.1.2",
41
40
  "@alcalzone/release-script-plugin-license": "^5.1.1",
42
- "@alcalzone/release-script-plugin-manual-review": "^5.1.1",
43
41
  "@iobroker/adapter-dev": "^1.5.0",
44
42
  "@iobroker/eslint-config": "^2.2.0",
45
43
  "@iobroker/testing": "^5.2.2",
46
44
  "@tsconfig/node20": "^20.1.9",
47
- "@types/iobroker": "npm:@iobroker/types@^7.1.0",
45
+ "@types/iobroker": "npm:@iobroker/types@^7.1.1",
48
46
  "@types/node": "^25.5.2",
49
47
  "@types/node-forge": "^1.3.14",
50
48
  "rimraf": "^6.1.3",