iobroker.govee-smart 2.35.0 → 2.35.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -103,6 +103,14 @@ This adapter's MQTT authentication and BLE-over-LAN (ptReal) protocol implementa
103
103
  ### **WORK IN PROGRESS**
104
104
  -->
105
105
 
106
+ ### 2.35.2 (2026-09-11)
107
+
108
+ - Fixed: A light that is unplugged no longer shows as switched on after a start — Govee's answer for a device it cannot reach carries the values of the last contact, and those are no longer written
109
+
110
+ ### 2.35.1 (2026-09-11)
111
+
112
+ - Fixed: The values Govee reports for a device at start no longer wait behind the loading of the scene libraries — on an installation with a dozen lights they arrived seven minutes after the start
113
+
106
114
  ### 2.35.0 (2026-09-11)
107
115
 
108
116
  - New: An air purifier's mode, level and filter life follow the device's own status report — a change made in the Govee app shows in ioBroker within a second, no cloud call (H7127, #47)
@@ -140,23 +148,6 @@ This adapter's MQTT authentication and BLE-over-LAN (ptReal) protocol implementa
140
148
  - New: An experimental model is tried by enabling "experimental device support"; a diagnostics report from the Expert tab confirms it for everyone
141
149
  - Changed: The wiki's device list folds each device type into one block with its counts, so 602 entries stay readable
142
150
 
143
- ### 2.32.1 (2026-09-07)
144
-
145
- - Fixed: Your devices and their recorded history no longer disappear from the object tree when the Govee cloud cannot be reached at startup
146
-
147
- ### 2.32.0 (2026-09-07)
148
-
149
- - Fixed: In an account without a single light, every device stopped being switchable after a restart — appliances, plugs and sensors had no state and no reachability until you pressed sync devices
150
- - Fixed: A device could stay green for up to 30 minutes after Govee had reported it offline; an arriving reading no longer overrides an explicit offline report
151
- - Fixed: With only an API key configured, devices fell offline 30 minutes after the start although they were still controllable — the proof now renews itself without account credentials
152
- - Fixed: Scene and snapshot commands that fell back to the cloud and failed there were still confirmed as carried out; a command that did not arrive now stays unconfirmed
153
- - Fixed: A manually chosen segment list could only ever lengthen the learned strip and never shorten it again — the wizard's own measurement was overwritten by it
154
- - Fixed: Under load the adapter stopped counting appliance commands against their daily limit, so a heater or humidifier could burn through its Govee quota and stop responding
155
- - Fixed: On a device model the adapter does not know yet, the tier datapoint told the user to press a button that 2.31.0 had already removed from the admin page
156
- - Fixed: Without account credentials, a group from the Govee app grew an empty entry in the object tree on every restart; it now appears only once its members are actually known
157
- - New: Datapoints carry an explanation in all 11 languages wherever the name alone does not say enough — 99 of them instead of 26
158
- - Changed: The adapter can no longer be installed directly from GitHub — install it from the ioBroker repository or from npm, as with every other adapter
159
-
160
151
  [Older changelogs can be found there](CHANGELOG_OLD.md)
161
152
 
162
153
  ## Support
@@ -19,12 +19,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var cloud_state_loader_exports = {};
20
20
  __export(cloud_state_loader_exports, {
21
21
  applyCloudCapabilities: () => applyCloudCapabilities,
22
+ cloudReportsOffline: () => cloudReportsOffline,
22
23
  loadCloudStates: () => loadCloudStates
23
24
  });
24
25
  module.exports = __toCommonJS(cloud_state_loader_exports);
25
26
  var import_capability_mapper = require("../capability-mapper");
27
+ var import_govee_constants = require("../govee-constants");
26
28
  var import_rate_limiter = require("../rate-limiter");
27
29
  var import_types = require("../types");
30
+ function cloudReportsOffline(caps) {
31
+ return caps.some(
32
+ (c) => {
33
+ var _a;
34
+ return c && typeof c.type === "string" && (c.type === import_govee_constants.GOVEE_CAP_TYPE.ONLINE || c.type === "online") && ((_a = c.state) == null ? void 0 : _a.value) === false;
35
+ }
36
+ );
37
+ }
28
38
  async function loadCloudStates(adapter, only) {
29
39
  if (!adapter.cloudClient || !adapter.deviceManager || !adapter.stateManager) {
30
40
  return;
@@ -39,6 +49,12 @@ async function loadCloudStates(adapter, only) {
39
49
  try {
40
50
  const caps = await adapter.cloudClient.getDeviceState(device.sku, device.deviceId);
41
51
  (_a = adapter.deviceManager) == null ? void 0 : _a.applyCloudStateOnline(device, caps);
52
+ if (cloudReportsOffline(caps)) {
53
+ adapter.log.debug(
54
+ `Cloud state for ${(0, import_types.deviceLabel)(device)}: Govee reports the device offline \u2014 its remembered values are not written`
55
+ );
56
+ return;
57
+ }
42
58
  const prefix = adapter.stateManager.devicePrefix(device);
43
59
  const writes = [];
44
60
  for (const mapped of caps.flatMap((cap) => (0, import_capability_mapper.mapCloudStateValues)(cap, device.capabilities))) {
@@ -61,7 +77,7 @@ async function loadCloudStates(adapter, only) {
61
77
  }
62
78
  };
63
79
  if (adapter.rateLimiter) {
64
- await adapter.rateLimiter.tryExecute(loadOne, 2, (0, import_rate_limiter.applianceBudget)(device));
80
+ await adapter.rateLimiter.tryExecute(loadOne, 1, (0, import_rate_limiter.applianceBudget)(device));
65
81
  } else {
66
82
  await loadOne();
67
83
  }
@@ -96,6 +112,7 @@ async function applyCloudCapabilities(adapter, device, caps) {
96
112
  // Annotate the CommonJS export names for ESM import in node:
97
113
  0 && (module.exports = {
98
114
  applyCloudCapabilities,
115
+ cloudReportsOffline,
99
116
  loadCloudStates
100
117
  });
101
118
  //# sourceMappingURL=cloud-state-loader.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/handlers/cloud-state-loader.ts"],
4
- "sourcesContent": ["import { LAN_STATE_IDS, mapCloudStateValues, planCloudCapabilityWrites } from \"../capability-mapper\";\nimport type { DeviceManager } from \"../device-manager\";\nimport type { GoveeCloudClient } from \"../govee-cloud-client\";\nimport { applianceBudget, type RateLimiter } from \"../rate-limiter\";\nimport type { StateManager } from \"../state-manager\";\nimport { deviceLabel, logRejected, type CloudStateCapability, type GoveeDevice } from \"../types\";\n\n/**\n * Adapter surface required by the cloud-state-loader helpers. Loose\n * `setState` for utils.Adapter structural matching.\n */\nexport interface CloudStateLoaderAdapter {\n readonly log: ioBroker.Logger;\n readonly cloudClient: GoveeCloudClient | null;\n readonly deviceManager: DeviceManager | null;\n readonly stateManager: StateManager | null;\n readonly rateLimiter: RateLimiter | null;\n setState(id: string, state: ioBroker.SettableState | ioBroker.StateValue): Promise<unknown>;\n}\n\n/**\n * Load current state for Cloud devices and populate state values.\n * Called after the initial Cloud device list load, on Cloud recovery,\n * and (scoped via `only`) by the per-device refresh_cloud button.\n *\n * LAN-first: never overwrite LAN states with Cloud values. For\n * LAN-capable devices, the LAN state IDs are filtered out \u2014 Cloud only\n * fills the gaps the LAN client doesn't cover.\n *\n * Every /device/state call runs through the RateLimiter (background\n * priority, same as scene loads): a fleet-sized burst would otherwise\n * blow the per-minute safety budget and bypass the daily accounting \u2014\n * including the 100/day appliance budget. On an exhausted budget the\n * calls queue and the values land when budget frees up.\n *\n * @param adapter Adapter surface\n * @param only When set, load only this device (per-device refresh)\n */\nexport async function loadCloudStates(adapter: CloudStateLoaderAdapter, only?: GoveeDevice): Promise<void> {\n if (!adapter.cloudClient || !adapter.deviceManager || !adapter.stateManager) {\n return;\n }\n\n const targets = adapter.deviceManager\n .getDevices()\n .filter(d => d.channels.cloud && d.capabilities.length > 0 && (!only || d === only));\n\n for (const device of targets) {\n const loadOne = async (): Promise<void> => {\n if (!adapter.cloudClient || !adapter.stateManager) {\n return;\n }\n try {\n const caps = await adapter.cloudClient.getDeviceState(device.sku, device.deviceId);\n // Govee's own reachability rides along in this response and used to be\n // discarded \u2014 the value translator has no `online` branch. For a device\n // with no local API this is the ONLY evidence there is, so without it\n // such a device could never be shown as reachable at all.\n adapter.deviceManager?.applyCloudStateOnline(device, caps);\n const prefix = adapter.stateManager.devicePrefix(device);\n\n const writes: Promise<unknown>[] = [];\n // One capability can carry two datapoints (work_mode \u2192 mode + level),\n // so the list is flattened first and the LAN-shadow rule below applies\n // per RESULT \u2014 same shape and same nesting level as before.\n for (const mapped of caps.flatMap(cap => mapCloudStateValues(cap, device.capabilities))) {\n if (device.lanIp && LAN_STATE_IDS.has(mapped.stateId)) {\n continue;\n }\n const statePath = adapter.stateManager.resolveStatePath(prefix, mapped.stateId);\n // Fire-and-forget \u2014 States are created before loadCloudStates runs;\n // a rejection here means the state was deleted out-of-band and\n // can be safely ignored.\n writes.push(\n adapter\n .setState(statePath, { val: mapped.value, ack: true })\n .catch(logRejected(adapter.log, `write ${statePath}`)),\n );\n }\n await Promise.all(writes);\n adapter.log.debug(`Cloud state loaded for ${deviceLabel(device)}`);\n } catch (e) {\n // v2.9.1 \u2014 record failure with HTTP status (and HttpError.responseBody\n // when available) so the diag JSON shows why state-load failed instead\n // of just \"could not load\". Previously this catch was silent \u2014 Class\n // C2 of the v2.9.1 diag-coverage audit.\n if (adapter.deviceManager) {\n const status =\n e && typeof e === \"object\" && \"statusCode\" in e ? (e as { statusCode?: number }).statusCode : undefined;\n adapter.deviceManager\n .getDiagnostics()\n .recordApiFailure(device.deviceId, \"/router/api/v1/device/state\", e, status);\n }\n adapter.log.debug(`Could not load Cloud state for ${deviceLabel(device)}`);\n }\n };\n if (adapter.rateLimiter) {\n // With the device's allowance \u2014 the doc comment above has always claimed\n // these calls are covered by the 100/day appliance budget, and until now\n // none of them were: no budget was passed, so an appliance's state reads\n // only ever counted against the account-wide limit.\n await adapter.rateLimiter.tryExecute(loadOne, 2, applianceBudget(device));\n } else {\n await loadOne();\n }\n }\n\n if (targets.length > 0) {\n adapter.log.debug(`Cloud state load dispatched for ${targets.length} device(s) (rate-limited)`);\n }\n}\n\n/**\n * Apply a list of synthesized Cloud-state capabilities to a single device \u2014\n * the App-API poll and OpenAPI-MQTT events both use this path so their\n * values flow through the same `mapCloudStateValue` pipeline that polled\n * Cloud states use.\n *\n * App-API and OpenAPI-MQTT deliver state IDs (battery, temperature,\n * humidity, lack_water, \u2026) that the Cloud-capability pipeline doesn't\n * declare for sensor/appliance SKUs \u2014 the state objects therefore don't\n * exist yet on first write. ensureSyntheticStateObject creates them\n * lazily with the right channel + role + unit.\n *\n */\nexport async function applyCloudCapabilities(\n adapter: CloudStateLoaderAdapter,\n device: GoveeDevice,\n caps: CloudStateCapability[],\n): Promise<void> {\n if (!adapter.stateManager) {\n return;\n }\n const prefix = adapter.stateManager.devicePrefix(device);\n const planned = planCloudCapabilityWrites(caps, Boolean(device.lanIp), LAN_STATE_IDS, device.capabilities);\n for (const mapped of planned) {\n await adapter.stateManager.ensureSyntheticStateObject(prefix, mapped.stateId);\n // v2.9.1 \u2014 mirror appliance/sensor values into device.state so the diag-\n // export `state` field is honest about non-Light runtime state. Without\n // this, `state` only ever held Light fields (power/brightness/color/\n // colorTemperature/scene) because handleLanStatus/handleMqttStatus were\n // the only writers \u2014 App-API + OpenAPI-MQTT routed straight to setState\n // without touching the in-memory device. Diag-export then showed an\n // empty `state: {online: ?}` for sensors / appliances even though the\n // real values lived in the state tree.\n if (mapped.value !== null && mapped.value !== undefined) {\n (device.state as Record<string, unknown>)[mapped.stateId] = mapped.value;\n }\n }\n const writes = planned.map(mapped => {\n const statePath = adapter.stateManager!.resolveStatePath(prefix, mapped.stateId);\n return adapter\n .setState(statePath, { val: mapped.value, ack: true })\n .catch(logRejected(adapter.log, `write ${statePath}`));\n });\n await Promise.all(writes);\n\n // Remove a phantom `humidity` datapoint on a temp-only thermometer:\n // Govee reports `hum:0` for devices without a humidity sensor (e.g. H5109),\n // which older versions turned into a permanent `humidity=0` state\n // (#31 inspee). A device that declares sensorTemperature but not\n // sensorHumidity has no humidity sensor \u2014 drop the orphan once. A real\n // hygrometer (sensorHumidity capability) is never touched.\n const hasTempCap = device.capabilities.some(c => c.instance === \"sensorTemperature\");\n const hasHumidityCap = device.capabilities.some(c => c.instance === \"sensorHumidity\");\n if (hasTempCap && !hasHumidityCap) {\n await adapter.stateManager.removeSyntheticStateOnce(prefix, \"humidity\");\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { LAN_STATE_IDS, mapCloudStateValues, planCloudCapabilityWrites } from \"../capability-mapper\";\nimport type { DeviceManager } from \"../device-manager\";\nimport type { GoveeCloudClient } from \"../govee-cloud-client\";\nimport { GOVEE_CAP_TYPE } from \"../govee-constants\";\nimport { applianceBudget, type RateLimiter } from \"../rate-limiter\";\nimport type { StateManager } from \"../state-manager\";\nimport { deviceLabel, logRejected, type CloudStateCapability, type GoveeDevice } from \"../types\";\n\n/**\n * Adapter surface required by the cloud-state-loader helpers. Loose\n * `setState` for utils.Adapter structural matching.\n */\nexport interface CloudStateLoaderAdapter {\n readonly log: ioBroker.Logger;\n readonly cloudClient: GoveeCloudClient | null;\n readonly deviceManager: DeviceManager | null;\n readonly stateManager: StateManager | null;\n readonly rateLimiter: RateLimiter | null;\n setState(id: string, state: ioBroker.SettableState | ioBroker.StateValue): Promise<unknown>;\n}\n\n/**\n * Whether Govee's state answer says the device is offline \u2014 the `online`\n * capability with an explicit `false`. Absent or non-boolean counts as \"no\n * statement\", not as offline.\n *\n * @param caps The capabilities of one `/device/state` answer\n */\nexport function cloudReportsOffline(caps: CloudStateCapability[]): boolean {\n return caps.some(\n c =>\n c &&\n typeof c.type === \"string\" &&\n (c.type === GOVEE_CAP_TYPE.ONLINE || c.type === \"online\") &&\n c.state?.value === false,\n );\n}\n\n/**\n * Load current state for Cloud devices and populate state values.\n * Called after the initial Cloud device list load, on Cloud recovery,\n * and (scoped via `only`) by the per-device refresh_cloud button.\n *\n * LAN-first: never overwrite LAN states with Cloud values. For\n * LAN-capable devices, the LAN state IDs are filtered out \u2014 Cloud only\n * fills the gaps the LAN client doesn't cover.\n *\n * Every /device/state call runs through the RateLimiter (background\n * priority, same as scene loads): a fleet-sized burst would otherwise\n * blow the per-minute safety budget and bypass the daily accounting \u2014\n * including the 100/day appliance budget. On an exhausted budget the\n * calls queue and the values land when budget frees up.\n *\n * @param adapter Adapter surface\n * @param only When set, load only this device (per-device refresh)\n */\nexport async function loadCloudStates(adapter: CloudStateLoaderAdapter, only?: GoveeDevice): Promise<void> {\n if (!adapter.cloudClient || !adapter.deviceManager || !adapter.stateManager) {\n return;\n }\n\n const targets = adapter.deviceManager\n .getDevices()\n .filter(d => d.channels.cloud && d.capabilities.length > 0 && (!only || d === only));\n\n for (const device of targets) {\n const loadOne = async (): Promise<void> => {\n if (!adapter.cloudClient || !adapter.stateManager) {\n return;\n }\n try {\n const caps = await adapter.cloudClient.getDeviceState(device.sku, device.deviceId);\n // Govee's own reachability rides along in this response and used to be\n // discarded \u2014 the value translator has no `online` branch. For a device\n // with no local API this is the ONLY evidence there is, so without it\n // such a device could never be shown as reachable at all.\n adapter.deviceManager?.applyCloudStateOnline(device, caps);\n // Govee's memory of a device it cannot reach is not the device's state:\n // for an unplugged light the same answer carried `online: false` AND\n // `powerSwitch: 1`, `brightness: 100` (krobi's H70C5, unplugged for a\n // week, measured on the first 2.35.0 start) \u2014 the values of the last\n // contact. Written, they showed an unplugged light as switched on. The\n // online evidence above is applied; the remembered values are not.\n if (cloudReportsOffline(caps)) {\n adapter.log.debug(\n `Cloud state for ${deviceLabel(device)}: Govee reports the device offline \u2014 its remembered values are not written`,\n );\n return;\n }\n const prefix = adapter.stateManager.devicePrefix(device);\n\n const writes: Promise<unknown>[] = [];\n // One capability can carry two datapoints (work_mode \u2192 mode + level),\n // so the list is flattened first and the LAN-shadow rule below applies\n // per RESULT \u2014 same shape and same nesting level as before.\n for (const mapped of caps.flatMap(cap => mapCloudStateValues(cap, device.capabilities))) {\n if (device.lanIp && LAN_STATE_IDS.has(mapped.stateId)) {\n continue;\n }\n const statePath = adapter.stateManager.resolveStatePath(prefix, mapped.stateId);\n // Fire-and-forget \u2014 States are created before loadCloudStates runs;\n // a rejection here means the state was deleted out-of-band and\n // can be safely ignored.\n writes.push(\n adapter\n .setState(statePath, { val: mapped.value, ack: true })\n .catch(logRejected(adapter.log, `write ${statePath}`)),\n );\n }\n await Promise.all(writes);\n adapter.log.debug(`Cloud state loaded for ${deviceLabel(device)}`);\n } catch (e) {\n // v2.9.1 \u2014 record failure with HTTP status (and HttpError.responseBody\n // when available) so the diag JSON shows why state-load failed instead\n // of just \"could not load\". Previously this catch was silent \u2014 Class\n // C2 of the v2.9.1 diag-coverage audit.\n if (adapter.deviceManager) {\n const status =\n e && typeof e === \"object\" && \"statusCode\" in e ? (e as { statusCode?: number }).statusCode : undefined;\n adapter.deviceManager\n .getDiagnostics()\n .recordApiFailure(device.deviceId, \"/router/api/v1/device/state\", e, status);\n }\n adapter.log.debug(`Could not load Cloud state for ${deviceLabel(device)}`);\n }\n };\n if (adapter.rateLimiter) {\n // With the device's allowance \u2014 the doc comment above has always claimed\n // these calls are covered by the 100/day appliance budget, and until now\n // none of them were: no budget was passed, so an appliance's state reads\n // only ever counted against the account-wide limit.\n // Status tier (1), not the scene-library tier (2): at start the library\n // loads of every light are already queued (five calls per light, eight\n // calls a minute), and a read queued BEHIND them at the same tier came\n // seven minutes after the start on a 12-device installation (measured\n // 2026-09-11, first start on 2.35.0) \u2014 the values a user looks at first\n // arrived last. A priority-1 call overtakes the queued tier-2 loads.\n await adapter.rateLimiter.tryExecute(loadOne, 1, applianceBudget(device));\n } else {\n await loadOne();\n }\n }\n\n if (targets.length > 0) {\n adapter.log.debug(`Cloud state load dispatched for ${targets.length} device(s) (rate-limited)`);\n }\n}\n\n/**\n * Apply a list of synthesized Cloud-state capabilities to a single device \u2014\n * the App-API poll and OpenAPI-MQTT events both use this path so their\n * values flow through the same `mapCloudStateValue` pipeline that polled\n * Cloud states use.\n *\n * App-API and OpenAPI-MQTT deliver state IDs (battery, temperature,\n * humidity, lack_water, \u2026) that the Cloud-capability pipeline doesn't\n * declare for sensor/appliance SKUs \u2014 the state objects therefore don't\n * exist yet on first write. ensureSyntheticStateObject creates them\n * lazily with the right channel + role + unit.\n *\n */\nexport async function applyCloudCapabilities(\n adapter: CloudStateLoaderAdapter,\n device: GoveeDevice,\n caps: CloudStateCapability[],\n): Promise<void> {\n if (!adapter.stateManager) {\n return;\n }\n const prefix = adapter.stateManager.devicePrefix(device);\n const planned = planCloudCapabilityWrites(caps, Boolean(device.lanIp), LAN_STATE_IDS, device.capabilities);\n for (const mapped of planned) {\n await adapter.stateManager.ensureSyntheticStateObject(prefix, mapped.stateId);\n // v2.9.1 \u2014 mirror appliance/sensor values into device.state so the diag-\n // export `state` field is honest about non-Light runtime state. Without\n // this, `state` only ever held Light fields (power/brightness/color/\n // colorTemperature/scene) because handleLanStatus/handleMqttStatus were\n // the only writers \u2014 App-API + OpenAPI-MQTT routed straight to setState\n // without touching the in-memory device. Diag-export then showed an\n // empty `state: {online: ?}` for sensors / appliances even though the\n // real values lived in the state tree.\n if (mapped.value !== null && mapped.value !== undefined) {\n (device.state as Record<string, unknown>)[mapped.stateId] = mapped.value;\n }\n }\n const writes = planned.map(mapped => {\n const statePath = adapter.stateManager!.resolveStatePath(prefix, mapped.stateId);\n return adapter\n .setState(statePath, { val: mapped.value, ack: true })\n .catch(logRejected(adapter.log, `write ${statePath}`));\n });\n await Promise.all(writes);\n\n // Remove a phantom `humidity` datapoint on a temp-only thermometer:\n // Govee reports `hum:0` for devices without a humidity sensor (e.g. H5109),\n // which older versions turned into a permanent `humidity=0` state\n // (#31 inspee). A device that declares sensorTemperature but not\n // sensorHumidity has no humidity sensor \u2014 drop the orphan once. A real\n // hygrometer (sensorHumidity capability) is never touched.\n const hasTempCap = device.capabilities.some(c => c.instance === \"sensorTemperature\");\n const hasHumidityCap = device.capabilities.some(c => c.instance === \"sensorHumidity\");\n if (hasTempCap && !hasHumidityCap) {\n await adapter.stateManager.removeSyntheticStateOnce(prefix, \"humidity\");\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "govee-smart",
4
- "version": "2.35.0",
4
+ "version": "2.35.2",
5
5
  "news": {
6
+ "2.35.2": {
7
+ "en": "A light that is unplugged no longer shows as switched on after a start — Govee's answer for a device it cannot reach carries the values of the last contact, and those are no longer written.",
8
+ "de": "Eine ausgesteckte Lampe zeigt sich nach einem Start nicht mehr als eingeschaltet — Govees Antwort für ein unerreichbares Gerät trägt die Werte des letzten Kontakts, die nicht mehr geschrieben werden.",
9
+ "ru": "Отключённая от сети лампа после старта больше не показывается включённой — ответ Govee для недоступного устройства несёт значения последнего контакта, и они больше не записываются.",
10
+ "pt": "Uma luz desligada da tomada já não aparece como ligada após um arranque — a resposta da Govee para um aparelho inacessível traz os valores do último contacto, e esses já não são escritos.",
11
+ "nl": "Een lamp zonder stroom toont zich na een start niet meer als ingeschakeld — Govees antwoord voor een onbereikbaar apparaat draagt de waarden van het laatste contact, die niet meer worden geschreven.",
12
+ "fr": "Une lampe débranchée ne s'affiche plus comme allumée après un démarrage — la réponse de Govee pour un appareil injoignable porte les valeurs du dernier contact, qui ne sont plus écrites.",
13
+ "it": "Una luce scollegata non appare più accesa dopo un avvio — la risposta di Govee per un dispositivo irraggiungibile porta i valori dell'ultimo contatto, che non vengono più scritti.",
14
+ "es": "Una luz desenchufada ya no aparece encendida tras un inicio — la respuesta de Govee para un dispositivo inalcanzable trae los valores del último contacto, y esos ya no se escriben.",
15
+ "pl": "Odłączona od prądu lampa nie pokazuje się już po starcie jako włączona — odpowiedź Govee dla nieosiągalnego urządzenia niesie wartości ostatniego kontaktu, a te nie są już zapisywane.",
16
+ "uk": "Вимкнена з розетки лампа після старту більше не показується увімкненою — відповідь Govee для недосяжного пристрою несе значення останнього контакту, і вони більше не записуються.",
17
+ "zh-cn": "拔掉电源的灯在启动后不再显示为已开启——Govee 对无法访问的设备返回的是上次联系时的数值,这些数值不再被写入。"
18
+ },
19
+ "2.35.1": {
20
+ "en": "The values Govee reports for a device at start no longer wait behind the loading of the scene libraries — with a dozen lights they used to arrive seven minutes after the start.",
21
+ "de": "Die Werte, die Govee beim Start für ein Gerät meldet, warten nicht mehr hinter dem Laden der Szenen-Bibliotheken — mit einem Dutzend Lampen kamen sie sieben Minuten nach dem Start.",
22
+ "ru": "Значения, которые Govee сообщает для устройства при старте, больше не ждут загрузки библиотек сцен — с дюжиной ламп они приходили через семь минут после старта.",
23
+ "pt": "Os valores que a Govee comunica para um aparelho no arranque já não esperam pelo carregamento das bibliotecas de cenas — com uma dúzia de luzes chegavam sete minutos depois.",
24
+ "nl": "De waarden die Govee bij de start voor een apparaat meldt, wachten niet meer op het laden van de scènebibliotheken — met een dozijn lampen kwamen ze zeven minuten na de start.",
25
+ "fr": "Les valeurs que Govee signale pour un appareil au démarrage n'attendent plus le chargement des bibliothèques de scènes — avec une douzaine de lampes elles arrivaient sept minutes après.",
26
+ "it": "I valori che Govee riporta per un dispositivo all'avvio non aspettano più il caricamento delle librerie di scene — con una dozzina di luci arrivavano sette minuti dopo l'avvio.",
27
+ "es": "Los valores que Govee informa para un dispositivo al inicio ya no esperan a la carga de las bibliotecas de escenas — con una docena de luces llegaban siete minutos después del inicio.",
28
+ "pl": "Wartości, które Govee zgłasza dla urządzenia przy starcie, nie czekają już na załadowanie bibliotek scen — przy tuzinie lamp przychodziły siedem minut po starcie.",
29
+ "uk": "Значення, які Govee повідомляє для пристрою при старті, більше не чекають завантаження бібліотек сцен — із дюжиною ламп вони надходили через сім хвилин після старту.",
30
+ "zh-cn": "Govee 在启动时为设备报告的数值不再排在场景库加载之后——在有十几盏灯的安装中,它们曾在启动七分钟后才到达。"
31
+ },
6
32
  "2.35.0": {
7
33
  "en": "Air purifier mode, level and filter life follow the device's own status report, the device-state query delivers values at start, and an API-key-only setup keeps its appliance commands all day.",
8
34
  "de": "Modus, Stufe und Filterlebensdauer eines Luftreinigers folgen der Statusmeldung des Geräts, die Zustandsabfrage liefert beim Start Werte, ein Nur-API-Key-Setup behält seine Befehle den ganzen Tag.",
@@ -67,32 +93,6 @@
67
93
  "pl": "Urządzenia na koncie bez ani jednego światła są po restarcie znowu sterowalne.\nUrządzenie nie jest już pokazywane jako osiągalne, gdy Govee zgłosi je jako offline, a wskazanie pozostaje poprawne także przy samym kluczu API.\nNieudane polecenie w chmurze nie liczy się już jako wykonane, a punkty danych objaśniają się w 11 językach.",
68
94
  "uk": "Пристрої в обліковому записі без жодного світильника знову керуються після перезапуску.\nПристрій більше не показується доступним, щойно Govee повідомить про його від'єднання, і показ лишається правильним навіть з одним ключем API.\nНевдала хмарна команда більше не вважається виконаною, а точки даних пояснюються 11 мовами.",
69
95
  "zh-cn": "账号中没有任何灯具时,设备在重启后重新可控。\n一旦 Govee 报告设备离线,就不再显示为可达;只配置了 API 密钥的安装,显示同样保持正确。\n失败的云端指令不再算作已执行,数据点也会用 11 种语言自我说明。"
70
- },
71
- "2.31.1": {
72
- "en": "Fixed: when the adapter met an unknown device model, its log asked for a button that 2.31.0 had removed — it now points at the Expert tab",
73
- "de": "Behoben: Bei einem unbekannten Gerätemodell verwies das Protokoll auf einen Knopf, den 2.31.0 entfernt hatte — es nennt jetzt den Reiter „Experte“",
74
- "ru": "Исправлено: при неизвестной модели устройства журнал ссылался на кнопку, удалённую в 2.31.0 — теперь он указывает на вкладку «Эксперт»",
75
- "pt": "Corrigido: perante um modelo desconhecido, o registo pedia um botão removido na 2.31.0 — agora indica o separador Especialista",
76
- "nl": "Opgelost: bij een onbekend apparaatmodel verwees het logboek naar een knop die 2.31.0 had verwijderd — het noemt nu het tabblad Expert",
77
- "fr": "Corrigé : face à un modèle inconnu, le journal renvoyait à un bouton supprimé en 2.31.0 — il indique désormais l'onglet Expert",
78
- "it": "Corretto: con un modello sconosciuto il log rimandava a un pulsante rimosso nella 2.31.0 — ora indica la scheda Esperto",
79
- "es": "Corregido: ante un modelo desconocido, el registro pedía un botón eliminado en 2.31.0: ahora indica la pestaña Experto",
80
- "pl": "Naprawiono: przy nieznanym modelu dziennik odsyłał do przycisku usuniętego w 2.31.0 — teraz wskazuje zakładkę Ekspert",
81
- "uk": "Виправлено: для невідомої моделі журнал посилався на кнопку, вилучену в 2.31.0 — тепер він вказує на вкладку «Експерт»",
82
- "zh-cn": "修复:遇到未知设备型号时,日志要求按下 2.31.0 已移除的按钮 — 现在改为指向“专家”选项卡"
83
- },
84
- "2.31.0": {
85
- "en": "Fixed: on instances upgraded from 2.27.0 or newer every admin card was dead; affected installations repair themselves on the next start\nFixed: a card that could not reach the adapter reported \"no devices yet\" instead of the real error\nChanged: segment detection and diagnostics share one Expert tab with a button each\nChanged: the per-device diag.export button is gone; the Expert tab hands you the file in one press\nChanged: diag.lastExport now records WHEN the last report was taken\nImproved: both cards say \"Loading devices …\" while they search\nFixed: the diagnostics report described the reachability rule as it was before 2.30.0",
86
- "de": "Behoben: Auf Instanzen ab 2.27.0 war jede Admin-Karte funktionslos; betroffene Installationen reparieren sich beim nächsten Start selbst\nBehoben: Eine Karte, die den Adapter nicht erreichte, meldete „noch keine Geräte“ statt des echten Fehlers\nGeändert: Segment-Erkennung und Diagnose teilen sich einen Reiter „Experte“ mit je einem Knopf\nGeändert: Der Knopf diag.export je Gerät entfällt; der Reiter Experte liefert die Datei in einem Druck\nGeändert: diag.lastExport hält jetzt fest, WANN der letzte Bericht erzeugt wurde\nVerbessert: Beide Karten schreiben „Geräte werden geladen …“ während der Suche\nBehoben: Der Diagnosebericht beschrieb die Erreichbarkeits-Regel im Stand vor 2.30.0",
87
- "ru": "Исправлено: на экземплярах с 2.27.0 и новее все карточки администратора не работали; затронутые установки чинятся при следующем запуске\nИсправлено: карточка, не достучавшаяся до адаптера, сообщала «устройств пока нет» вместо настоящей ошибки\nИзменено: определение сегментов и диагностика — одна вкладка «Эксперт», по кнопке на каждую\nИзменено: кнопка diag.export убрана; вкладка «Эксперт» отдаёт файл одним нажатием\nИзменено: diag.lastExport теперь хранит, КОГДА создан последний отчёт\nУлучшено: обе карточки пишут «Загрузка устройств …» во время поиска\nИсправлено: отчёт диагностики описывал правило доступности до версии 2.30.0",
88
- "pt": "Corrigido: em instâncias a partir da 2.27.0 todos os cartões de administração não funcionavam; as instalações afetadas reparam-se no arranque seguinte\nCorrigido: um cartão sem acesso ao adaptador indicava \"ainda sem dispositivos\" em vez do erro real\nAlterado: deteção de segmentos e diagnóstico partilham um separador Especialista, com um botão cada\nAlterado: o botão diag.export desapareceu; o separador Especialista entrega o ficheiro num só clique\nAlterado: diag.lastExport regista agora QUANDO foi feito o último relatório\nMelhorado: ambos os cartões indicam \"A carregar dispositivos …\" durante a procura\nCorrigido: o relatório de diagnóstico descrevia a regra de acessibilidade anterior à 2.30.0",
89
- "nl": "Opgelost: op instanties vanaf 2.27.0 werkte elke admin-kaart niet; getroffen installaties herstellen zichzelf bij de volgende start\nOpgelost: een kaart die de adapter niet bereikte meldde \"nog geen apparaten\" in plaats van de echte fout\nGewijzigd: segmentdetectie en diagnose delen één tabblad Expert, met elk een knop\nGewijzigd: de knop diag.export is weg; het tabblad Expert levert het bestand in één druk\nGewijzigd: diag.lastExport legt nu vast WANNEER het laatste rapport is gemaakt\nVerbeterd: beide kaarten tonen \"Apparaten laden …\" tijdens het zoeken\nOpgelost: het diagnoserapport beschreef de bereikbaarheidsregel van vóór 2.30.0",
90
- "fr": "Corrigé : sur les instances à partir de la 2.27.0, toutes les cartes d'administration étaient inertes ; les installations concernées se réparent au prochain démarrage\nCorrigé : une carte sans accès à l'adaptateur annonçait « aucun appareil » au lieu de l'erreur réelle\nModifié : détection des segments et diagnostic partagent un onglet Expert, avec un bouton chacun\nModifié : le bouton diag.export disparaît ; l'onglet Expert fournit le fichier en une pression\nModifié : diag.lastExport indique désormais QUAND le dernier rapport a été pris\nAmélioré : les deux cartes affichent « Chargement des appareils … » pendant la recherche\nCorrigé : le rapport de diagnostic décrivait la règle d'accessibilité d'avant la 2.30.0",
91
- "it": "Corretto: sulle istanze dalla 2.27.0 in poi tutte le schede di amministrazione erano inerti; le installazioni interessate si riparano al riavvio successivo\nCorretto: una scheda che non raggiungeva l'adattatore segnalava \"nessun dispositivo\" invece dell'errore reale\nModificato: rilevamento segmenti e diagnostica condividono una scheda Esperto, con un pulsante ciascuno\nModificato: il pulsante diag.export non c'è più; la scheda Esperto consegna il file in una pressione\nModificato: diag.lastExport registra ora QUANDO è stato preso l'ultimo rapporto\nMigliorato: entrambe le schede mostrano \"Caricamento dispositivi …\" durante la ricerca\nCorretto: il rapporto diagnostico descriveva la regola di raggiungibilità precedente alla 2.30.0",
92
- "es": "Corregido: en instancias desde la 2.27.0 todas las tarjetas de administración estaban inertes; las instalaciones afectadas se reparan en el siguiente arranque\nCorregido: una tarjeta sin acceso al adaptador indicaba \"aún no hay dispositivos\" en lugar del error real\nCambiado: detección de segmentos y diagnóstico comparten una pestaña Experto, con un botón cada uno\nCambiado: el botón diag.export desaparece; la pestaña Experto entrega el archivo en una pulsación\nCambiado: diag.lastExport registra ahora CUÁNDO se tomó el último informe\nMejorado: ambas tarjetas muestran \"Cargando dispositivos …\" mientras buscan\nCorregido: el informe de diagnóstico describía la regla de accesibilidad anterior a la 2.30.0",
93
- "pl": "Naprawiono: na instancjach od 2.27.0 wszystkie karty administracyjne nie działały; dotknięte instalacje naprawiają się przy następnym starcie\nNaprawiono: karta bez dostępu do adaptera zgłaszała „brak urządzeń” zamiast prawdziwego błędu\nZmieniono: wykrywanie segmentów i diagnostyka dzielą jedną zakładkę Ekspert, każde z własnym przyciskiem\nZmieniono: przycisk diag.export został usunięty; zakładka Ekspert wydaje plik jednym naciśnięciem\nZmieniono: diag.lastExport zapisuje teraz, KIEDY powstał ostatni raport\nUlepszono: obie karty pokazują „Wczytywanie urządzeń …” podczas wyszukiwania\nNaprawiono: raport diagnostyczny opisywał regułę dostępności sprzed 2.30.0",
94
- "uk": "Виправлено: на екземплярах від 2.27.0 усі картки адміністратора не працювали; уражені встановлення виправляються під час наступного запуску\nВиправлено: картка без доступу до адаптера повідомляла «пристроїв ще немає» замість справжньої помилки\nЗмінено: виявлення сегментів і діагностика мають спільну вкладку «Експерт» із кнопкою для кожного\nЗмінено: кнопку diag.export прибрано; вкладка «Експерт» видає файл одним натисканням\nЗмінено: diag.lastExport тепер зберігає, КОЛИ створено останній звіт\nПокращено: обидві картки показують «Завантаження пристроїв …» під час пошуку\nВиправлено: звіт діагностики описував правило досяжності станом до 2.30.0",
95
- "zh-cn": "修复:在 2.27.0 及更高版本升级的实例上,所有管理页卡片均失效;受影响的安装会在下次启动时自行修复\n修复:无法连接适配器的卡片显示“暂无设备”,而不是真正的错误\n变更:分段检测与诊断共用一个“专家”选项卡,各有一个按钮\n变更:diag.export 按钮已移除;“专家”选项卡一次按下即可交付文件\n变更:diag.lastExport 现在记录上次生成报告的时间\n改进:两个卡片在搜索期间显示“正在加载设备 …”\n修复:诊断报告描述的是 2.30.0 之前的可达性规则"
96
96
  }
97
97
  },
98
98
  "plugins": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.govee-smart",
3
- "version": "2.35.0",
3
+ "version": "2.35.2",
4
4
  "description": "Control Govee WiFi devices via LAN, MQTT and Cloud.",
5
5
  "author": {
6
6
  "name": "krobi",