iobroker.hydrawise 2.0.0 → 2.0.1

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
@@ -20,32 +20,37 @@
20
20
  ![Stable](http://iobroker.live/badges/hydrawise-stable.svg)
21
21
  ![Installed](http://iobroker.live/badges/hydrawise-installed.svg)
22
22
 
23
- Integrate your Hydrawise controller into iobroker.
24
- You can see all controller information, schedules and sensors. It is also possible to suspend planned watering by x seconds.
23
+ Integrate your Hydrawise controller into ioBroker.
25
24
 
26
- The adapter can use either API, or both:
25
+ Both APIs provide zones and schedules. Use **v2 (GraphQL)** by default (same login as the Hydrawise app). **v1 (REST)** is a fallback via API key if GraphQL is unavailable. Enable one or both.
27
26
 
28
- - **v1** (optional, API key, `schedule.*` / `customer.*`) status, sensors configuration, run/stop/suspend.
29
- - **v2** (optional, Hydrawise login, `zones.*` / `water.*` / `sensors.*` / `weather.*` / `controller.*`) — measured water usage, live sensor values, weather, leak indicator, and zone commands via GraphQL.
27
+ - **v2** (recommended): email/password like the app — `zones.*`, `sensors.*`, `weather.*`, `water.*`, `controller.*` (plus weather, measured sensors, leak indicator, GraphQL zone commands).
28
+ - **v1** (fallback): API key `schedule.*` / `customer.*` (same zones and schedules, no weather or measured sensors).
30
29
 
31
30
  ## Documentation
32
31
 
32
+ ### v2 API (recommended)
33
+
34
+ v2 is the unofficial GraphQL API used by the Hydrawise app (`app.hydrawise.com/api/v2/graph`). Enable **v2 API (GraphQL)** in instance settings and enter the same email/password as on hydrawise.com.
35
+
36
+ ### v1 API (fallback)
37
+
38
+ Only needed if GraphQL is unavailable:
39
+
33
40
  - log into https://app.hydrawise.com/config/account-details
34
41
  - generate API Key by clicking "Generate API Key" under "Account Settings"
35
- - paste key into adapter settings
42
+ - paste the key into the v1 tab
36
43
  - API documentation: https://support.hydrawise.com/hc/en-us/articles/360008965753-Hydrawise-API-Information
37
44
 
38
- ### v2 API (optional)
39
-
40
- v2 is the unofficial GraphQL API used by the Hydrawise app (`app.hydrawise.com/api/v2/graph`). Enable it in instance settings and enter the same email/password as the app. v1 can be disabled independently if you only want GraphQL.
41
-
42
45
  | Object tree | Source | Controls irrigation? |
43
46
  | --- | --- | --- |
44
47
  | `schedule.*` | v1 REST | yes (`setzone.php`) |
45
48
  | `zones.*` | v2 GraphQL | yes (GraphQL mutations), only if v2 is enabled |
46
49
  | `water.*`, `sensors.*`, `weather.*`, `controller.*` | v2 GraphQL | read-only |
47
- | `info.connection` | v1 | — |
48
- | `info.connectionV2` | v2 | — |
50
+ | `info.connection` | instance (all enabled APIs) | — |
51
+ | `info.connectionV2` | v2 GraphQL only | — |
52
+
53
+ The Admin traffic light (`info.connection`) is green only if **every enabled API** is online. v1 enabled but failing and v2 OK → yellow/red. v2-only and connected → green. `info.connectionV2` stays true whenever GraphQL works.
49
54
 
50
55
  v1 `schedule.sensors.*` only contains sensor *configuration*. Measured flow, rainfall and leak suspicion come from v2 `sensors.*` / `water.leakSuspected`.
51
56
 
@@ -62,6 +67,10 @@ Default v2 poll interval is **300 seconds** (minimum 120). GraphQL is rate-limit
62
67
  Placeholder for the next version (at the beginning of the line):
63
68
  ### **WORK IN PROGRESS**
64
69
  -->
70
+ ### 2.0.1 (2026-09-03)
71
+
72
+ * (SentiQ) **FIXED**: Instance `info.connection` follows every enabled API (v2-only no longer stays red)
73
+
65
74
  ### 2.0.0 (2026-09-02)
66
75
 
67
76
  * (SentiQ) **NEW**: Optional Hydrawise v2 GraphQL API (water usage, live sensors, weather, leak indicator, zone commands)
@@ -85,11 +94,6 @@ Default v2 poll interval is **300 seconds** (minimum 120). GraphQL is rate-limit
85
94
  - (SentiQ) updated js-controller dependency
86
95
  - (SentiQ) updated @iobroker/adapter-dev dependency
87
96
 
88
- ### 1.0.4 (2025-12-05)
89
-
90
- - (SentiQ) fixed dependencies
91
- - (SentiQ) fixed schema URLs
92
-
93
97
  [Older changelogs can be found there](CHANGELOG_OLD.md)
94
98
 
95
99
  ## License
@@ -27,6 +27,7 @@ __export(helpers_exports, {
27
27
  SCHEDULE_SKIP_KEYS: () => SCHEDULE_SKIP_KEYS,
28
28
  buildHydrawiseUrl: () => buildHydrawiseUrl,
29
29
  getRetryAfterSec: () => getRetryAfterSec,
30
+ instanceConnected: () => instanceConnected,
30
31
  isRateLimitError: () => isRateLimitError,
31
32
  isRateLimited: () => isRateLimited,
32
33
  isScalarKey: () => isScalarKey,
@@ -109,6 +110,12 @@ function nextBackoffMs(failCount, retryAfterSec, random = Math.random) {
109
110
  const jitter = 1 + (random() * 0.2 - 0.1);
110
111
  return Math.round(capped * jitter);
111
112
  }
113
+ function instanceConnected(v1Enabled, v2Enabled, v1Online, v2Online) {
114
+ if (!v1Enabled && !v2Enabled) {
115
+ return false;
116
+ }
117
+ return (!v1Enabled || v1Online) && (!v2Enabled || v2Online);
118
+ }
112
119
  // Annotate the CommonJS export names for ESM import in node:
113
120
  0 && (module.exports = {
114
121
  BACKOFF_CAP_MS,
@@ -120,6 +127,7 @@ function nextBackoffMs(failCount, retryAfterSec, random = Math.random) {
120
127
  SCHEDULE_SKIP_KEYS,
121
128
  buildHydrawiseUrl,
122
129
  getRetryAfterSec,
130
+ instanceConnected,
123
131
  isRateLimitError,
124
132
  isRateLimited,
125
133
  isScalarKey,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/helpers.ts"],
4
- "sourcesContent": ["export const HYDRAWISE_BASE_URL = 'https://api.hydrawise.com';\n\nexport const SCHEDULE_SKIP_KEYS = ['relays', 'sensors', 'expanders'] as const;\nexport const CUSTOMER_SKIP_KEYS = ['controllers'] as const;\n\nexport const CUSTOMER_INTERVAL_MS = 5 * 60 * 1000;\nexport const CUSTOMER_STAGGER_MS = 30_000;\nexport const BACKOFF_CAP_MS = 30 * 60 * 1000;\nexport const RATE_LIMIT_MESSAGE = /exceeded maximum number of requests/i;\n\n/**\n * Replace characters forbidden in ioBroker object IDs.\n *\n * @param name raw name from API\n * @param forbiddenChars adapter FORBIDDEN_CHARS regex\n */\nexport function name2id(name: string, forbiddenChars: RegExp): string {\n return (name || '').replace(forbiddenChars, '_');\n}\n\n/**\n * True when the key is a scalar field (not a nested array/object list).\n *\n * @param key API response key\n * @param skipKeys keys to skip (arrays/objects)\n */\nexport function isScalarKey(key: string, skipKeys: readonly string[]): boolean {\n return !skipKeys.includes(key);\n}\n\n/**\n * Build a full Hydrawise API URL with query parameters.\n *\n * @param service endpoint file name (e.g. statusschedule.php)\n * @param params query parameters\n */\nexport function buildHydrawiseUrl(service: string, params: Record<string, string | number | boolean>): string {\n const url = new URL(`/api/v1/${service}`, HYDRAWISE_BASE_URL);\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n return url.toString();\n}\n\n/**\n * Stable signature of schedule/customer structure for object-sync decisions.\n *\n * @param relayIds relay numbers from status API\n * @param sensorInputs sensor input numbers\n * @param controllerNames controller names from customer API\n */\nexport function structureSignature(\n relayIds: Array<string | number>,\n sensorInputs: Array<string | number>,\n controllerNames: string[] = [],\n): string {\n return JSON.stringify({\n relays: [...relayIds].map(String).sort(),\n sensors: [...sensorInputs].map(String).sort(),\n controllers: [...controllerNames].map(String).sort(),\n });\n}\n\n/**\n * Parse a Retry-After header (delta-seconds or HTTP date) to seconds.\n *\n * @param header Retry-After header value\n */\nexport function parseRetryAfter(header: string | null | undefined): number | undefined {\n if (!header) {\n return undefined;\n }\n const seconds = Number(header);\n if (Number.isFinite(seconds) && seconds >= 0) {\n return seconds;\n }\n const date = Date.parse(header);\n if (!Number.isNaN(date)) {\n return Math.max(0, (date - Date.now()) / 1000);\n }\n return undefined;\n}\n\n/**\n * True when HTTP status or body indicates a Hydrawise rate limit.\n *\n * @param status HTTP status code\n * @param body response body (string or parsed JSON)\n */\nexport function isRateLimited(status?: number, body?: unknown): boolean {\n if (status === 429) {\n return true;\n }\n if (typeof body === 'string') {\n return RATE_LIMIT_MESSAGE.test(body);\n }\n if (body && typeof body === 'object') {\n return RATE_LIMIT_MESSAGE.test(JSON.stringify(body));\n }\n return false;\n}\n\n/**\n * True when a thrown error is a Hydrawise rate-limit response.\n *\n * @param error caught error\n */\nexport function isRateLimitError(error: unknown): boolean {\n const err = error as {\n code?: number | string;\n data?: unknown;\n response?: { status?: number; data?: unknown };\n message?: string;\n };\n const status = typeof err?.code === 'number' ? err.code : err?.response?.status;\n const data = err?.response?.data ?? err?.data ?? err?.message;\n return isRateLimited(status, data);\n}\n\n/**\n * Retry-After seconds attached to a thrown HTTP error, if any.\n *\n * @param error caught error\n */\nexport function getRetryAfterSec(error: unknown): number | undefined {\n const retryAfter = (error as { retryAfter?: number })?.retryAfter;\n return typeof retryAfter === 'number' && Number.isFinite(retryAfter) ? retryAfter : undefined;\n}\n\n/**\n * Exponential backoff after a rate limit: max(300s, Retry-After) * 2^(failCount-1), \u00B110% jitter, cap 30 min.\n *\n * @param failCount consecutive rate-limit failures (1-based)\n * @param retryAfterSec optional Retry-After from the response\n * @param random RNG in [0, 1) \u2014 inject for tests\n */\nexport function nextBackoffMs(failCount: number, retryAfterSec?: number, random: () => number = Math.random): number {\n const n = Math.max(1, failCount);\n const base = Math.max(CUSTOMER_INTERVAL_MS, (retryAfterSec ?? 0) * 1000);\n const capped = Math.min(base * 2 ** (n - 1), BACKOFF_CAP_MS);\n const jitter = 1 + (random() * 0.2 - 0.1);\n return Math.round(capped * jitter);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export const HYDRAWISE_BASE_URL = 'https://api.hydrawise.com';\n\nexport const SCHEDULE_SKIP_KEYS = ['relays', 'sensors', 'expanders'] as const;\nexport const CUSTOMER_SKIP_KEYS = ['controllers'] as const;\n\nexport const CUSTOMER_INTERVAL_MS = 5 * 60 * 1000;\nexport const CUSTOMER_STAGGER_MS = 30_000;\nexport const BACKOFF_CAP_MS = 30 * 60 * 1000;\nexport const RATE_LIMIT_MESSAGE = /exceeded maximum number of requests/i;\n\n/**\n * Replace characters forbidden in ioBroker object IDs.\n *\n * @param name raw name from API\n * @param forbiddenChars adapter FORBIDDEN_CHARS regex\n */\nexport function name2id(name: string, forbiddenChars: RegExp): string {\n return (name || '').replace(forbiddenChars, '_');\n}\n\n/**\n * True when the key is a scalar field (not a nested array/object list).\n *\n * @param key API response key\n * @param skipKeys keys to skip (arrays/objects)\n */\nexport function isScalarKey(key: string, skipKeys: readonly string[]): boolean {\n return !skipKeys.includes(key);\n}\n\n/**\n * Build a full Hydrawise API URL with query parameters.\n *\n * @param service endpoint file name (e.g. statusschedule.php)\n * @param params query parameters\n */\nexport function buildHydrawiseUrl(service: string, params: Record<string, string | number | boolean>): string {\n const url = new URL(`/api/v1/${service}`, HYDRAWISE_BASE_URL);\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n return url.toString();\n}\n\n/**\n * Stable signature of schedule/customer structure for object-sync decisions.\n *\n * @param relayIds relay numbers from status API\n * @param sensorInputs sensor input numbers\n * @param controllerNames controller names from customer API\n */\nexport function structureSignature(\n relayIds: Array<string | number>,\n sensorInputs: Array<string | number>,\n controllerNames: string[] = [],\n): string {\n return JSON.stringify({\n relays: [...relayIds].map(String).sort(),\n sensors: [...sensorInputs].map(String).sort(),\n controllers: [...controllerNames].map(String).sort(),\n });\n}\n\n/**\n * Parse a Retry-After header (delta-seconds or HTTP date) to seconds.\n *\n * @param header Retry-After header value\n */\nexport function parseRetryAfter(header: string | null | undefined): number | undefined {\n if (!header) {\n return undefined;\n }\n const seconds = Number(header);\n if (Number.isFinite(seconds) && seconds >= 0) {\n return seconds;\n }\n const date = Date.parse(header);\n if (!Number.isNaN(date)) {\n return Math.max(0, (date - Date.now()) / 1000);\n }\n return undefined;\n}\n\n/**\n * True when HTTP status or body indicates a Hydrawise rate limit.\n *\n * @param status HTTP status code\n * @param body response body (string or parsed JSON)\n */\nexport function isRateLimited(status?: number, body?: unknown): boolean {\n if (status === 429) {\n return true;\n }\n if (typeof body === 'string') {\n return RATE_LIMIT_MESSAGE.test(body);\n }\n if (body && typeof body === 'object') {\n return RATE_LIMIT_MESSAGE.test(JSON.stringify(body));\n }\n return false;\n}\n\n/**\n * True when a thrown error is a Hydrawise rate-limit response.\n *\n * @param error caught error\n */\nexport function isRateLimitError(error: unknown): boolean {\n const err = error as {\n code?: number | string;\n data?: unknown;\n response?: { status?: number; data?: unknown };\n message?: string;\n };\n const status = typeof err?.code === 'number' ? err.code : err?.response?.status;\n const data = err?.response?.data ?? err?.data ?? err?.message;\n return isRateLimited(status, data);\n}\n\n/**\n * Retry-After seconds attached to a thrown HTTP error, if any.\n *\n * @param error caught error\n */\nexport function getRetryAfterSec(error: unknown): number | undefined {\n const retryAfter = (error as { retryAfter?: number })?.retryAfter;\n return typeof retryAfter === 'number' && Number.isFinite(retryAfter) ? retryAfter : undefined;\n}\n\n/**\n * Exponential backoff after a rate limit: max(300s, Retry-After) * 2^(failCount-1), \u00B110% jitter, cap 30 min.\n *\n * @param failCount consecutive rate-limit failures (1-based)\n * @param retryAfterSec optional Retry-After from the response\n * @param random RNG in [0, 1) \u2014 inject for tests\n */\nexport function nextBackoffMs(failCount: number, retryAfterSec?: number, random: () => number = Math.random): number {\n const n = Math.max(1, failCount);\n const base = Math.max(CUSTOMER_INTERVAL_MS, (retryAfterSec ?? 0) * 1000);\n const capped = Math.min(base * 2 ** (n - 1), BACKOFF_CAP_MS);\n const jitter = 1 + (random() * 0.2 - 0.1);\n return Math.round(capped * jitter);\n}\n\n/**\n * True when every enabled API is online. Admin uses this for `info.connection`.\n *\n * @param v1Enabled whether v1 REST is enabled\n * @param v2Enabled whether v2 GraphQL is enabled\n * @param v1Online whether v1 last poll succeeded\n * @param v2Online whether v2 last poll succeeded\n */\nexport function instanceConnected(\n v1Enabled: boolean,\n v2Enabled: boolean,\n v1Online: boolean,\n v2Online: boolean,\n): boolean {\n if (!v1Enabled && !v2Enabled) {\n return false;\n }\n return (!v1Enabled || v1Online) && (!v2Enabled || v2Online);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/build/main.js CHANGED
@@ -51,6 +51,8 @@ class Hydrawise extends utils.Adapter {
51
51
  v2LastRetryAfter;
52
52
  v2StructureSig = "";
53
53
  v2ObjectsReady = false;
54
+ v1Online = false;
55
+ v2Online = false;
54
56
  constructor(options = {}) {
55
57
  super({
56
58
  ...options,
@@ -63,6 +65,19 @@ class Hydrawise extends utils.Adapter {
63
65
  isV1Enabled() {
64
66
  return this.config.enableV1 !== false;
65
67
  }
68
+ setV1Online(online) {
69
+ this.v1Online = online;
70
+ this.syncInstanceConnection();
71
+ }
72
+ setV2Online(online) {
73
+ this.v2Online = online;
74
+ void this.setStateChangedAsync("info.connectionV2", online, true);
75
+ this.syncInstanceConnection();
76
+ }
77
+ syncInstanceConnection() {
78
+ const connected = (0, import_helpers.instanceConnected)(this.isV1Enabled(), !!this.config.enableV2, this.v1Online, this.v2Online);
79
+ void this.setStateChangedAsync("info.connection", connected, true);
80
+ }
66
81
  async onReady() {
67
82
  const v1 = this.isV1Enabled();
68
83
  const v2 = !!this.config.enableV2;
@@ -70,7 +85,9 @@ class Hydrawise extends utils.Adapter {
70
85
  this.log.error("Neither v1 nor v2 API is enabled");
71
86
  return;
72
87
  }
73
- void this.setStateChangedAsync("info.connection", false, true);
88
+ this.v1Online = false;
89
+ this.v2Online = false;
90
+ this.syncInstanceConnection();
74
91
  if (v1) {
75
92
  if (!this.config.apiKey) {
76
93
  this.log.error("No API-Key defined!");
@@ -88,7 +105,7 @@ class Hydrawise extends utils.Adapter {
88
105
  this.log.error("v2 API enabled but username or password is missing");
89
106
  } else {
90
107
  await this.subscribeV2Commands();
91
- void this.setStateChangedAsync("info.connectionV2", false, true);
108
+ this.setV2Online(false);
92
109
  this.scheduleV2Poll(0);
93
110
  }
94
111
  }
@@ -105,7 +122,7 @@ class Hydrawise extends utils.Adapter {
105
122
  return;
106
123
  }
107
124
  const content = response.data;
108
- void this.setStateChangedAsync("info.connection", true, true);
125
+ this.setV1Online(true);
109
126
  const relayIds = (content.relays || []).map((r) => r.relay);
110
127
  const sensorInputs = (content.sensors || []).map((s) => s.input);
111
128
  const nextStructureKey = (0, import_helpers.structureSignature)(relayIds, sensorInputs);
@@ -118,7 +135,7 @@ class Hydrawise extends utils.Adapter {
118
135
  this.updateScheduleStates(content);
119
136
  } catch (error) {
120
137
  this.log.debug(`(schedule) received error - API is now offline: ${(error == null ? void 0 : error.message) || error}`);
121
- void this.setStateChangedAsync("info.connection", false, true);
138
+ this.setV1Online(false);
122
139
  } finally {
123
140
  this.schedulePollRunning = false;
124
141
  }
@@ -887,7 +904,7 @@ class Hydrawise extends utils.Adapter {
887
904
  );
888
905
  if (!controller) {
889
906
  this.log.warn("v2 status: no controller in response");
890
- void this.setStateChangedAsync("info.connectionV2", false, true);
907
+ this.setV2Online(false);
891
908
  return "error";
892
909
  }
893
910
  this.v2ControllerId = Number(controller.id);
@@ -913,12 +930,12 @@ class Hydrawise extends utils.Adapter {
913
930
  for (const sensor of controller.sensors || []) {
914
931
  await this.applyMappedNodes((0, import_mapper.mapSensorStates)(sensor), needObjects);
915
932
  }
916
- void this.setStateChangedAsync("info.connectionV2", true, true);
933
+ this.setV2Online(true);
917
934
  return "ok";
918
935
  } catch (error) {
919
936
  this.v2LastRetryAfter = (0, import_helpers.getRetryAfterSec)(error);
920
937
  this.log.debug(`v2 status: ${(error == null ? void 0 : error.message) || error}`);
921
- void this.setStateChangedAsync("info.connectionV2", false, true);
938
+ this.setV2Online(false);
922
939
  return (0, import_helpers.isRateLimitError)(error) ? "rate-limit" : "error";
923
940
  }
924
941
  }
package/build/main.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/main.ts"],
4
- "sourcesContent": ["/*\n * Created with @iobroker/create-adapter v2.3.0\n */\n\nimport * as utils from '@iobroker/adapter-core';\nimport {\n CUSTOMER_INTERVAL_MS,\n CUSTOMER_SKIP_KEYS,\n CUSTOMER_STAGGER_MS,\n HYDRAWISE_BASE_URL,\n SCHEDULE_SKIP_KEYS,\n buildHydrawiseUrl,\n getRetryAfterSec,\n isRateLimitError,\n isScalarKey,\n name2id as sanitizeId,\n nextBackoffMs,\n parseRetryAfter,\n structureSignature,\n} from './lib/helpers';\nimport {\n HydrawiseV2Error,\n type V2Token,\n fetchAccessToken,\n graphqlRequest,\n refreshAccessToken,\n tokenNeedsRefresh,\n} from './lib/v2/auth';\nimport {\n type MappedNode,\n computeWaterSummary,\n mapAllZoneCommandObjects,\n mapControllerStates,\n mapSensorStates,\n mapWaterStates,\n mapWeatherStates,\n mapZoneCommandObjects,\n mapZoneStates,\n pickController,\n v2StructureKey,\n zoneIdMap,\n} from './lib/v2/mapper';\nimport {\n STATUS_QUERY,\n type WaterPeriod,\n nextLongPeriod,\n startAllZonesMutation,\n mutationErrorSummary,\n startZoneMutation,\n stopAllZonesMutation,\n stopZoneMutation,\n suspendAllZonesMutation,\n suspendZoneMutation,\n waterRequest,\n weatherRequest,\n} from './lib/v2/queries';\n\ninterface ApiResponse {\n status: number;\n data: any;\n}\n\nclass Hydrawise extends utils.Adapter {\n private pollScheduleTimer?: ioBroker.Interval;\n private pollCustomerTimer?: ioBroker.Timeout;\n private pollV2Timer?: ioBroker.Timeout;\n private resetSwitchTimer?: ioBroker.Timeout;\n private relays: Record<string, number> = {};\n private lastErrorCode: string | number = 0;\n private schedulePollRunning = false;\n private customerPollRunning = false;\n private scheduleStructureKey = '';\n private customerStructureKey = '';\n private scheduleObjectsReady = false;\n private customerObjectsReady = false;\n private customerBackoffFails = 0;\n private lastCustomerCallAt = 0;\n private v1ControllerId?: number;\n private v2Token: V2Token | null = null;\n private v2PollRunning = false;\n private v2BackoffFails = 0;\n private v2LongPeriodIndex = 0;\n private v2ControllerId?: number;\n private v2ZoneIds: Record<string, number> = {};\n private v2LastRetryAfter?: number;\n private v2StructureSig = '';\n private v2ObjectsReady = false;\n\n public constructor(options: Partial<utils.AdapterOptions> = {}) {\n super({\n ...options,\n name: 'hydrawise',\n });\n\n this.on('ready', this.onReady.bind(this));\n this.on('stateChange', this.onStateChange.bind(this));\n this.on('unload', this.onUnload.bind(this));\n }\n\n private isV1Enabled(): boolean {\n return this.config.enableV1 !== false;\n }\n\n private async onReady(): Promise<void> {\n const v1 = this.isV1Enabled();\n const v2 = !!this.config.enableV2;\n\n if (!v1 && !v2) {\n this.log.error('Neither v1 nor v2 API is enabled');\n return;\n }\n\n void this.setStateChangedAsync('info.connection', false, true);\n\n if (v1) {\n if (!this.config.apiKey) {\n this.log.error('No API-Key defined!');\n } else {\n await this.GetStatusSchedule();\n this.pollScheduleTimer = this.setInterval(() => {\n void this.GetStatusSchedule();\n }, this.config.apiInterval * 1000);\n\n this.scheduleCustomerPoll(CUSTOMER_STAGGER_MS);\n await this.subscribeV1Commands();\n }\n }\n\n if (v2) {\n if (!this.config.v2Username || !this.config.v2Password) {\n this.log.error('v2 API enabled but username or password is missing');\n } else {\n await this.subscribeV2Commands();\n void this.setStateChangedAsync('info.connectionV2', false, true);\n this.scheduleV2Poll(0);\n }\n }\n }\n\n private async GetStatusSchedule(): Promise<void> {\n if (this.schedulePollRunning) {\n this.log.debug('Skipping overlapping status schedule poll');\n return;\n }\n\n this.schedulePollRunning = true;\n try {\n const response = await this.buildRequest('statusschedule.php', { api_key: this.config.apiKey });\n if (response.status !== 200) {\n return;\n }\n\n const content = response.data;\n void this.setStateChangedAsync('info.connection', true, true);\n\n const relayIds = (content.relays || []).map((r: any) => r.relay);\n const sensorInputs = (content.sensors || []).map((s: any) => s.input);\n const nextStructureKey = structureSignature(relayIds, sensorInputs);\n const needObjects = !this.scheduleObjectsReady || this.scheduleStructureKey !== nextStructureKey;\n\n if (needObjects) {\n await this.ensureScheduleObjects(content);\n this.scheduleStructureKey = nextStructureKey;\n this.scheduleObjectsReady = true;\n }\n\n this.updateScheduleStates(content);\n } catch (error: any) {\n this.log.debug(`(schedule) received error - API is now offline: ${error?.message || error}`);\n void this.setStateChangedAsync('info.connection', false, true);\n } finally {\n this.schedulePollRunning = false;\n }\n }\n\n private async ensureScheduleObjects(content: any): Promise<void> {\n await this.setObjectNotExistsAsync('schedule.stopall', {\n type: 'state',\n common: {\n name: {\n en: 'stop all zones',\n de: 'alle Zonen stoppen',\n ru: '\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u043E\u043D\u044B',\n pt: 'parar todas as zonas',\n nl: 'stop alle zones',\n fr: 'arr\u00EAter toutes les zones',\n it: 'fermare tutte le zone',\n es: 'detener todas las zonas',\n pl: 'zatrzymuj\u0105 wszystkie strefy',\n uk: '\u0437\u0443\u043F\u0438\u043D\u0438\u0442\u0438 \u0432\u0441\u0456 \u0437\u043E\u043D\u0438',\n 'zh-cn': '\u505C\u6B62\u6240\u6709\u5730\u533A',\n },\n type: 'boolean',\n role: 'button.stop',\n read: false,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync('schedule.runall', {\n type: 'state',\n common: {\n name: {\n en: 'run all zones for x seconds',\n de: 'alle Zonen f\u00FCr x Sekunden ausf\u00FChren',\n ru: '\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u043E\u043D\u044B \u0437\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434\u044B',\n pt: 'executar todas as zonas por x segundos',\n nl: 'ren alle zones voor x seconden',\n fr: 'ex\u00E9cuter toutes les zones pendant x secondes',\n it: 'eseguire tutte le zone per x secondi',\n es: 'ejecutar todas las zonas durante x segundos',\n pl: 'wszystkie strefy startuj\u0105 dla x sekundy',\n uk: '\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0438 \u0432\u0441\u0456 \u0437\u043E\u043D\u0438 \u0434\u043B\u044F x \u0441\u0435\u043A\u0443\u043D\u0434',\n 'zh-cn': '\u8DD1\u9053\u533A',\n },\n type: 'number',\n role: 'level',\n unit: 'seconds',\n read: true,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync('schedule.suspendall', {\n type: 'state',\n common: {\n name: {\n en: 'suspend all zones for x seconds',\n de: 'alle Zonen f\u00FCr x Sekunden aussetzen',\n ru: '\u043F\u0440\u0438\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u043E\u043D\u044B \u0437\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434\u044B',\n pt: 'suspender todas as zonas por x segundos',\n nl: 'vertaling:',\n fr: 'suspendre toutes les zones pendant x secondes',\n it: 'sospendere tutte le zone per x secondi',\n es: 'suspender todas las zonas durante x segundos',\n pl: 'wszystkie strefy zawieszenia dla x sekundy',\n uk: '\u043F\u0440\u0438\u0437\u0443\u043F\u0438\u043D\u0438\u0442\u0438 \u0432\u0441\u0456 \u0437\u043E\u043D\u0438 \u043D\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434',\n 'zh-cn': '\u505C\u6B62\u6240\u6709\u00D7\u4E8C\u533A',\n },\n type: 'number',\n role: 'level',\n read: true,\n write: true,\n },\n native: {},\n });\n\n for (const rawKey of Object.keys(content)) {\n const key = this.name2id(rawKey);\n if (!isScalarKey(key, SCHEDULE_SKIP_KEYS)) {\n continue;\n }\n\n await this.setObjectNotExistsAsync(`schedule.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: key === 'message' ? 'string' : 'number',\n role: key === 'message' ? 'text' : 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n\n if (key === 'time') {\n await this.setObjectNotExistsAsync('schedule.timestr', {\n type: 'state',\n common: {\n name: 'last api call',\n type: 'string',\n role: 'text',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n }\n\n for (const relay of content.relays || []) {\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}`, {\n type: 'channel',\n common: {\n name: String(relay.relay),\n },\n native: {},\n });\n\n for (const rawKey of Object.keys(relay)) {\n const key = this.name2id(rawKey);\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: key === 'name' || key === 'timestr' ? 'string' : 'number',\n role: key === 'name' || key === 'timestr' ? 'text' : 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.stopZone`, {\n type: 'state',\n common: {\n name: {\n en: 'stop zone',\n de: 'Zone stoppen',\n ru: '\u0437\u043E\u043D\u0430 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438',\n pt: 'zona de paragem',\n nl: 'stop zone',\n fr: \"zone d ' arr\u00EAt\",\n it: 'zona di sosta',\n es: 'zona de parada',\n pl: 'strefa stopu',\n uk: '\u0437\u043E\u043D\u0430 \u0437\u0443\u043F\u0438\u043D\u043A\u0438',\n 'zh-cn': '\u505C\u6B62\u5730\u533A',\n },\n type: 'boolean',\n role: 'button.stop',\n read: false,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.runZone`, {\n type: 'state',\n common: {\n name: {\n en: 'run zone for x seconds',\n de: 'Zone f\u00FCr x Sekunden starten',\n ru: '\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0437\u043E\u043D\u0443 \u0437\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434\u044B',\n pt: 'zona de execu\u00E7\u00E3o por x segundos',\n nl: 'ren zone voor x seconden',\n fr: 'zone de course pour x secondes',\n it: 'zona di corsa per x secondi',\n es: 'zona de ejecuci\u00F3n por x segundos',\n pl: 'strefa x sekundy',\n uk: '\u0437\u043E\u043D\u0430 \u0437\u0430\u043F\u0443\u0441\u043A\u0443 \u0434\u043B\u044F x \u0441\u0435\u043A\u0443\u043D\u0434',\n 'zh-cn': '\u00D7\u4E8C\u533A',\n },\n type: 'number',\n role: 'level',\n read: true,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.suspendZone`, {\n type: 'state',\n common: {\n name: {\n en: 'suspend zone for x seconds',\n de: 'Zone f\u00FCr x Sekunden aussetzen',\n ru: '\u043F\u0440\u0438\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0437\u043E\u043D\u0443 \u043D\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434\u044B',\n pt: 'zona de suspens\u00E3o por x segundos',\n nl: 'quality over quantity (qoq) releases vertaling:',\n fr: 'zone de suspension pour x secondes',\n it: 'zona di sospensione per x secondi',\n es: 'zona de suspensi\u00F3n por x segundos',\n pl: 'strefa zawies\u0142a na x sekundy',\n uk: '\u0437\u043E\u043D\u0430 \u043F\u0456\u0434\u0432\u0456\u0441\u043A\u0438 \u0434\u043B\u044F x \u0441\u0435\u043A\u0443\u043D\u0434',\n 'zh-cn': '\u505C\u6B62x\u4E8C\u533A',\n },\n type: 'number',\n role: 'level',\n read: true,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.runDefault`, {\n type: 'state',\n common: {\n name: {\n en: 'run zone for default time',\n de: 'Zone mit Standardlaufzeit starten',\n ru: '\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0437\u043E\u043D\u0443 \u0434\u043B\u044F \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E',\n pt: 'fuso de execu\u00E7\u00E3o para o tempo padr\u00E3o',\n nl: 'run zone for default time',\n fr: 'run zone for default time',\n it: 'run zone per il tempo predefinito',\n es: 'zona de ejecuci\u00F3n por tiempo predeterminado',\n pl: 'strefa czasu domy\u015Blnego',\n uk: '\u0437\u043E\u043D\u0430 \u0437\u0430\u043F\u0443\u0441\u043A\u0443 \u0437\u0430 \u0437\u0430\u043C\u043E\u0432\u0447\u0443\u0432\u0430\u043D\u043D\u044F\u043C',\n 'zh-cn': 'a. \u6682\u505C\u65F6\u95F4\u533A',\n },\n type: 'boolean',\n role: 'button.start',\n read: true,\n write: true,\n },\n native: {},\n });\n }\n\n for (const sensor of content.sensors || []) {\n await this.setObjectNotExistsAsync(`schedule.sensors.${sensor.input}`, {\n type: 'channel',\n common: {\n name: 'sensors',\n },\n native: {},\n });\n\n for (const rawKey of Object.keys(sensor)) {\n if (rawKey === 'relays') {\n continue;\n }\n const key = this.name2id(rawKey);\n await this.setObjectNotExistsAsync(`schedule.sensors.${sensor.input}.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: 'number',\n role: 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n }\n }\n\n private updateScheduleStates(content: any): void {\n for (const rawKey of Object.keys(content)) {\n const key = this.name2id(rawKey);\n if (!isScalarKey(key, SCHEDULE_SKIP_KEYS)) {\n continue;\n }\n\n void this.setStateChangedAsync(`schedule.${key}`, content[rawKey], true);\n\n if (key === 'time') {\n const t = new Date(content[rawKey] * 1000);\n void this.setStateChangedAsync('schedule.timestr', t.toString(), true);\n }\n }\n\n for (const relay of content.relays || []) {\n this.relays[relay.relay] = relay.relay_id;\n\n for (const rawKey of Object.keys(relay)) {\n const key = this.name2id(rawKey);\n let value = relay[rawKey];\n\n if (key === 'timestr') {\n const t = new Date();\n t.setSeconds(t.getSeconds() + relay.time);\n value = t.toString();\n }\n\n void this.setStateChangedAsync(`schedule.${relay.relay}.${key}`, value, true);\n }\n }\n\n for (const sensor of content.sensors || []) {\n for (const rawKey of Object.keys(sensor)) {\n if (rawKey === 'relays') {\n continue;\n }\n const key = this.name2id(rawKey);\n void this.setStateChangedAsync(`schedule.sensors.${sensor.input}.${key}`, sensor[rawKey], true);\n }\n }\n }\n\n private scheduleCustomerPoll(delayMs: number): void {\n if (this.pollCustomerTimer) {\n this.clearTimeout(this.pollCustomerTimer);\n }\n this.pollCustomerTimer = this.setTimeout(\n () => {\n this.pollCustomerTimer = undefined;\n void this.runCustomerPoll();\n },\n Math.max(0, delayMs),\n );\n }\n\n private async runCustomerPoll(): Promise<void> {\n const delay = await this.GetCustomerDetails();\n this.scheduleCustomerPoll(delay);\n }\n\n private async GetCustomerDetails(): Promise<number> {\n if (this.customerPollRunning) {\n this.log.debug('Skipping overlapping customer details poll');\n return CUSTOMER_INTERVAL_MS;\n }\n\n const elapsed = this.lastCustomerCallAt ? Date.now() - this.lastCustomerCallAt : CUSTOMER_INTERVAL_MS;\n if (this.lastCustomerCallAt && elapsed < CUSTOMER_INTERVAL_MS) {\n this.log.debug('Skipping customer details poll (inside 5 minute window)');\n return CUSTOMER_INTERVAL_MS - elapsed;\n }\n\n this.customerPollRunning = true;\n this.lastCustomerCallAt = Date.now();\n try {\n const response = await this.buildRequest('customerdetails.php', { api_key: this.config.apiKey });\n if (response.status !== 200) {\n return CUSTOMER_INTERVAL_MS;\n }\n\n const content = response.data;\n this.customerBackoffFails = 0;\n if (content?.controller_id != null) {\n this.v1ControllerId = Number(content.controller_id);\n }\n\n const controllerNames = (content.controllers || []).map((c: any) => this.name2id(c.name));\n const nextStructureKey = structureSignature([], [], controllerNames);\n const needObjects = !this.customerObjectsReady || this.customerStructureKey !== nextStructureKey;\n\n if (needObjects) {\n await this.ensureCustomerObjects(content);\n this.customerStructureKey = nextStructureKey;\n this.customerObjectsReady = true;\n }\n\n this.updateCustomerStates(content);\n return CUSTOMER_INTERVAL_MS;\n } catch (error: any) {\n if (isRateLimitError(error)) {\n this.customerBackoffFails += 1;\n const delay = nextBackoffMs(this.customerBackoffFails, getRetryAfterSec(error));\n this.log.warn(\n `customerdetails rate limited, next poll in ${Math.round(delay / 1000)}s (attempt ${this.customerBackoffFails})`,\n );\n return delay;\n }\n\n this.log.debug(`(customer) received error: ${error?.message || error}`);\n return CUSTOMER_INTERVAL_MS;\n } finally {\n this.customerPollRunning = false;\n }\n }\n\n private async ensureCustomerObjects(content: any): Promise<void> {\n for (const rawKey of Object.keys(content)) {\n if (!isScalarKey(rawKey, CUSTOMER_SKIP_KEYS)) {\n continue;\n }\n const key = this.name2id(rawKey);\n\n await this.setObjectNotExistsAsync(`customer.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: key === 'message' || key === 'current_controller' ? 'string' : 'number',\n role: key === 'message' || key === 'current_controller' ? 'text' : 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n\n for (const controller of content.controllers || []) {\n const controllerId = this.name2id(controller.name);\n await this.setObjectNotExistsAsync(`customer.controllers.${controllerId}`, {\n type: 'channel',\n common: {\n name: controller.name,\n },\n native: {},\n });\n\n for (const rawKey of Object.keys(controller)) {\n const key = this.name2id(rawKey);\n await this.setObjectNotExistsAsync(`customer.controllers.${controllerId}.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: key !== 'controller_id' ? 'string' : 'number',\n role: key !== 'controller_id' ? 'text' : 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n }\n }\n\n private updateCustomerStates(content: any): void {\n for (const rawKey of Object.keys(content)) {\n if (!isScalarKey(rawKey, CUSTOMER_SKIP_KEYS)) {\n continue;\n }\n const key = this.name2id(rawKey);\n void this.setStateChangedAsync(`customer.${key}`, content[rawKey], true);\n }\n\n for (const controller of content.controllers || []) {\n const controllerId = this.name2id(controller.name);\n\n for (const rawKey of Object.keys(controller)) {\n const key = this.name2id(rawKey);\n let value = controller[rawKey];\n\n if (key === 'last_contact') {\n const t = new Date(controller[rawKey] * 1000);\n value = t.toString();\n }\n\n void this.setStateChangedAsync(`customer.controllers.${controllerId}.${key}`, value, true);\n }\n }\n }\n\n /**\n * Perform a GET request against the Hydrawise API.\n *\n * @param service endpoint file name\n * @param params query parameters\n */\n async buildRequest(service: string, params: Record<string, string | number | boolean>): Promise<ApiResponse> {\n if (!params.api_key) {\n throw new Error('API key is not configured');\n }\n\n const url = buildHydrawiseUrl(service, params);\n const abort = new AbortController();\n const timeout = setTimeout(() => abort.abort(), 30_000);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n signal: abort.signal,\n headers: { Accept: 'application/json' },\n });\n\n this.lastErrorCode = 0;\n\n let data: any = null;\n const text = await response.text();\n if (text) {\n try {\n data = JSON.parse(text);\n } catch {\n data = text;\n }\n }\n\n if (!response.ok) {\n this.log.warn(\n `received ${response.status} response from /api/v1/${service} with content: ${JSON.stringify(data)}`,\n );\n throw Object.assign(new Error(`HTTP ${response.status}`), {\n code: response.status,\n retryAfter: parseRetryAfter(response.headers.get('Retry-After')),\n response: { status: response.status, data },\n });\n }\n\n return { status: response.status, data };\n } catch (error: any) {\n if (error?.response) {\n // already logged above for HTTP errors\n } else if (error?.name === 'AbortError') {\n const code = 'ECONNABORTED';\n if (code === this.lastErrorCode) {\n this.log.debug(`timeout from ${HYDRAWISE_BASE_URL}/api/v1/${service}`);\n } else {\n this.log.info(`error ${code} from /api/v1/${service}: request timed out`);\n this.lastErrorCode = code;\n }\n throw Object.assign(new Error('request timed out'), { code });\n } else if (error?.message) {\n const code = error.code || error.cause?.code || 'ENOTFOUND';\n if (code === this.lastErrorCode) {\n this.log.debug(error.message);\n } else {\n this.log.info(`error ${code} from /api/v1/${service}: ${error.message}`);\n this.lastErrorCode = code;\n }\n } else {\n this.log.error(String(error));\n }\n\n throw error instanceof Error ? error : new Error(String(error));\n } finally {\n clearTimeout(timeout);\n }\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n *\n * @param callback callback function\n */\n private onUnload(callback: () => void): void {\n try {\n if (this.pollScheduleTimer) {\n this.clearInterval(this.pollScheduleTimer);\n this.pollScheduleTimer = undefined;\n }\n if (this.pollCustomerTimer) {\n this.clearTimeout(this.pollCustomerTimer);\n this.pollCustomerTimer = undefined;\n }\n if (this.pollV2Timer) {\n this.clearTimeout(this.pollV2Timer);\n this.pollV2Timer = undefined;\n }\n if (this.resetSwitchTimer) {\n this.clearTimeout(this.resetSwitchTimer);\n this.resetSwitchTimer = undefined;\n }\n\n callback();\n } catch {\n callback();\n }\n }\n\n /**\n * Is called if a subscribed state changes\n *\n * @param id id of the state\n * @param state state object\n */\n private onStateChange(id: string, state: ioBroker.State | null | undefined): void {\n if (!state) {\n return;\n }\n if (state.ack && state.from === `system.adapter.${this.namespace}`) {\n return;\n }\n void this.handleStateChange(id, state);\n }\n\n private async handleStateChange(id: string, state: ioBroker.State): Promise<void> {\n try {\n if (id.includes('.zones.')) {\n await this.handleV2Command(id, state);\n return;\n }\n if (!this.isV1Enabled() || !id.includes('.schedule.')) {\n return;\n }\n\n let commandSent = false;\n\n if (id.includes('stopall')) {\n await this.buildRequest('setzone.php', { api_key: this.config.apiKey, action: 'stopall' });\n commandSent = true;\n } else if (id.includes('stopZone')) {\n const relay = id.match(/.*schedule\\.(.*)\\.stopZone/);\n if (relay && relay.length > 1) {\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'stop',\n relay_id: this.relays[relay[1]],\n });\n commandSent = true;\n }\n }\n\n if (id.includes('runall') && (state.val || state.val === 0)) {\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'runall',\n period_id: 999,\n custom: state.val,\n });\n commandSent = true;\n } else if (id.includes('runZone') && (state.val || state.val === 0)) {\n const relay = id.match(/.*schedule\\.(.*)\\.runZone/);\n if (relay && relay.length > 1) {\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'run',\n period_id: 999,\n custom: state.val,\n relay_id: this.relays[relay[1]],\n });\n commandSent = true;\n }\n }\n\n if (id.includes('runDefault') && state.val !== null) {\n await this.initRunDefault(id, state.val as boolean);\n commandSent = true;\n }\n\n if (id.includes('suspendall') && (state.val || state.val === 0)) {\n const num = state.val as number;\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'suspendall',\n period_id: 999,\n custom: Math.trunc((state.ts + num) / 1000),\n });\n commandSent = true;\n } else if (id.includes('suspendZone') && (state.val || state.val === 0)) {\n const num = state.val as number;\n const relay = id.match(/.*schedule\\.(.*)\\.suspendZone/);\n if (relay && relay.length > 1) {\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'suspend',\n period_id: 999,\n custom: Math.trunc((state.ts + num) / 1000),\n relay_id: this.relays[relay[1]],\n });\n commandSent = true;\n }\n }\n\n if (commandSent && !id.includes('runDefault')) {\n await this.GetStatusSchedule();\n }\n } catch (error: any) {\n this.log.error(`Command failed for ${id}: ${error?.message || error}`);\n }\n }\n\n async initRunDefault(id: string, run: boolean): Promise<void> {\n const relay = id.match(/(.*schedule.*\\.)runDefault/);\n\n if (this.resetSwitchTimer) {\n this.clearTimeout(this.resetSwitchTimer);\n this.resetSwitchTimer = undefined;\n }\n\n if (relay) {\n if (run) {\n const defaultRunTime = await this.getStateAsync(`${relay[1]}run`);\n if (defaultRunTime && defaultRunTime.val) {\n void this.setState(`${relay[1]}runZone`, defaultRunTime.val, false);\n this.resetSwitchTimer = this.setTimeout(\n () => {\n void this.setState(id, false, true);\n this.resetSwitchTimer = undefined;\n },\n (defaultRunTime.val as number) * 1000,\n );\n }\n } else {\n void this.setState(`${relay[1]}stopZone`, true, false);\n }\n }\n }\n\n private async subscribeV1Commands(): Promise<void> {\n await this.subscribeStatesAsync('schedule.stopall');\n await this.subscribeStatesAsync('schedule.runall');\n await this.subscribeStatesAsync('schedule.suspendall');\n await this.subscribeStatesAsync('schedule.*.stopZone');\n await this.subscribeStatesAsync('schedule.*.runZone');\n await this.subscribeStatesAsync('schedule.*.suspendZone');\n await this.subscribeStatesAsync('schedule.*.runDefault');\n }\n\n private async subscribeV2Commands(): Promise<void> {\n await this.subscribeStatesAsync('zones.stopall');\n await this.subscribeStatesAsync('zones.runall');\n await this.subscribeStatesAsync('zones.suspendall');\n await this.subscribeStatesAsync('zones.*.stopZone');\n await this.subscribeStatesAsync('zones.*.runZone');\n await this.subscribeStatesAsync('zones.*.suspendZone');\n await this.subscribeStatesAsync('zones.*.runDefault');\n }\n\n private v2IntervalMs(): number {\n return Math.max(120, Number(this.config.apiIntervalV2) || 300) * 1000;\n }\n\n private scheduleV2Poll(delayMs: number): void {\n if (this.pollV2Timer) {\n this.clearTimeout(this.pollV2Timer);\n }\n this.pollV2Timer = this.setTimeout(\n () => {\n this.pollV2Timer = undefined;\n void this.runV2Poll();\n },\n Math.max(0, delayMs),\n );\n }\n\n private async runV2Poll(statusOnly = false): Promise<void> {\n if (this.v2PollRunning) {\n this.log.debug('Skipping overlapping v2 poll');\n return;\n }\n\n this.v2PollRunning = true;\n let delay = this.v2IntervalMs();\n try {\n const statusResult = await this.pollV2Status();\n if (statusResult === 'rate-limit') {\n this.v2BackoffFails += 1;\n delay = nextBackoffMs(this.v2BackoffFails, this.v2LastRetryAfter);\n this.log.warn(`v2 rate limited, next poll in ${Math.round(delay / 1000)}s`);\n return;\n }\n\n if (statusOnly || !this.v2ControllerId) {\n return;\n }\n\n const weatherResult = await this.pollV2Weather();\n if (weatherResult === 'rate-limit') {\n this.v2BackoffFails += 1;\n delay = nextBackoffMs(this.v2BackoffFails, this.v2LastRetryAfter);\n this.log.warn(`v2 rate limited, next poll in ${Math.round(delay / 1000)}s`);\n return;\n }\n\n const todayResult = await this.pollV2Water('today');\n if (todayResult === 'rate-limit') {\n this.v2BackoffFails += 1;\n delay = nextBackoffMs(this.v2BackoffFails, this.v2LastRetryAfter);\n this.log.warn(`v2 rate limited, next poll in ${Math.round(delay / 1000)}s`);\n return;\n }\n\n const { period, nextIndex } = nextLongPeriod(this.v2LongPeriodIndex);\n const longResult = await this.pollV2Water(period);\n if (longResult === 'rate-limit') {\n this.v2BackoffFails += 1;\n delay = nextBackoffMs(this.v2BackoffFails, this.v2LastRetryAfter);\n this.log.warn(`v2 rate limited, next poll in ${Math.round(delay / 1000)}s`);\n return;\n }\n this.v2LongPeriodIndex = nextIndex;\n this.v2BackoffFails = 0;\n } finally {\n this.v2PollRunning = false;\n if (!statusOnly) {\n this.scheduleV2Poll(delay);\n }\n }\n }\n\n private async ensureV2Token(): Promise<V2Token> {\n if (tokenNeedsRefresh(this.v2Token)) {\n if (this.v2Token?.refreshToken) {\n try {\n this.v2Token = await refreshAccessToken(this.v2Token.refreshToken);\n } catch {\n this.v2Token = await fetchAccessToken(this.config.v2Username, this.config.v2Password);\n }\n } else {\n this.v2Token = await fetchAccessToken(this.config.v2Username, this.config.v2Password);\n }\n }\n if (!this.v2Token) {\n throw new HydrawiseV2Error('No v2 token', 'unauthorized');\n }\n return this.v2Token;\n }\n\n private async v2Graphql(request: { query: string; variables?: Record<string, unknown> }): Promise<any> {\n const token = await this.ensureV2Token();\n try {\n return await graphqlRequest(token, request);\n } catch (error) {\n if (error instanceof HydrawiseV2Error && error.code === 401) {\n this.v2Token = await fetchAccessToken(this.config.v2Username, this.config.v2Password);\n return await graphqlRequest(this.v2Token, request);\n }\n throw error;\n }\n }\n\n private async v2Mutate(request: { query: string; variables?: Record<string, unknown> }): Promise<any> {\n const data = await this.v2Graphql(request);\n const failed = mutationErrorSummary(data);\n if (failed) {\n throw new HydrawiseV2Error(failed, 'mutation', data);\n }\n return data;\n }\n\n private async applyMappedNodes(nodes: MappedNode[], createObjects: boolean): Promise<void> {\n for (const node of nodes) {\n if (createObjects) {\n await this.setObjectNotExistsAsync(node.id, {\n type: node.type,\n common: node.common as any,\n native: {},\n });\n }\n if (node.type === 'state' && node.value !== undefined) {\n void this.setStateChangedAsync(node.id, node.value, true);\n }\n }\n }\n\n private async pollV2Status(): Promise<'ok' | 'rate-limit' | 'error'> {\n try {\n const data = await this.v2Graphql({ query: STATUS_QUERY });\n const controller = pickController(\n data?.me?.controllers,\n data?.me?.currentController?.id,\n this.v1ControllerId,\n );\n if (!controller) {\n this.log.warn('v2 status: no controller in response');\n void this.setStateChangedAsync('info.connectionV2', false, true);\n return 'error';\n }\n\n this.v2ControllerId = Number(controller.id);\n this.v2ZoneIds = zoneIdMap(controller);\n\n const nextKey = v2StructureKey(controller);\n const needObjects = !this.v2ObjectsReady || this.v2StructureSig !== nextKey;\n if (needObjects) {\n await this.applyMappedNodes(mapAllZoneCommandObjects(), true);\n for (const zone of controller.zones || []) {\n const n = zone?.number?.value;\n if (n !== undefined && n !== null) {\n await this.applyMappedNodes(mapZoneCommandObjects(n), true);\n }\n }\n this.v2StructureSig = nextKey;\n this.v2ObjectsReady = true;\n await this.subscribeV2Commands();\n }\n\n await this.applyMappedNodes(mapControllerStates(controller), needObjects);\n for (const zone of controller.zones || []) {\n await this.applyMappedNodes(mapZoneStates(zone), needObjects);\n }\n for (const sensor of controller.sensors || []) {\n await this.applyMappedNodes(mapSensorStates(sensor), needObjects);\n }\n\n void this.setStateChangedAsync('info.connectionV2', true, true);\n return 'ok';\n } catch (error: any) {\n this.v2LastRetryAfter = getRetryAfterSec(error);\n this.log.debug(`v2 status: ${error?.message || error}`);\n void this.setStateChangedAsync('info.connectionV2', false, true);\n return isRateLimitError(error) ? 'rate-limit' : 'error';\n }\n }\n\n private async pollV2Weather(): Promise<'ok' | 'rate-limit' | 'error'> {\n if (!this.v2ControllerId) {\n return 'error';\n }\n try {\n const data = await this.v2Graphql(weatherRequest(this.v2ControllerId));\n await this.applyMappedNodes(mapWeatherStates(data?.controller?.location?.forecast), true);\n return 'ok';\n } catch (error: any) {\n this.v2LastRetryAfter = getRetryAfterSec(error);\n this.log.debug(`v2 weather: ${error?.message || error}`);\n return isRateLimitError(error) ? 'rate-limit' : 'error';\n }\n }\n\n private async pollV2Water(period: WaterPeriod): Promise<'ok' | 'rate-limit' | 'error'> {\n if (!this.v2ControllerId) {\n return 'error';\n }\n try {\n const request = waterRequest(this.v2ControllerId, period);\n const data = await this.v2Graphql(request);\n const summary = computeWaterSummary(data?.controller);\n await this.applyMappedNodes(mapWaterStates(period, summary), true);\n return 'ok';\n } catch (error: any) {\n this.v2LastRetryAfter = getRetryAfterSec(error);\n this.log.debug(`v2 water (${period}): ${error?.message || error}`);\n return isRateLimitError(error) ? 'rate-limit' : 'error';\n }\n }\n\n private async handleV2Command(id: string, state: ioBroker.State): Promise<void> {\n if (!this.config.enableV2) {\n return;\n }\n if (!this.v2ControllerId) {\n this.log.warn('v2 command ignored: controller id is unknown');\n return;\n }\n\n try {\n let sent = false;\n const zoneMatch = id.match(/\\.zones\\.(\\d+)\\.(stopZone|runZone|suspendZone|runDefault)$/);\n\n if (id.endsWith('.zones.stopall')) {\n await this.v2Mutate(stopAllZonesMutation(this.v2ControllerId));\n sent = true;\n } else if (id.endsWith('.zones.runall') && (state.val || state.val === 0)) {\n await this.v2Mutate(startAllZonesMutation(this.v2ControllerId, Number(state.val)));\n sent = true;\n } else if (id.endsWith('.zones.suspendall') && (state.val || state.val === 0)) {\n const until = new Date(state.ts + Number(state.val) * 1000);\n await this.v2Mutate(suspendAllZonesMutation(this.v2ControllerId, until));\n sent = true;\n } else if (zoneMatch) {\n const zoneId = this.v2ZoneIds[zoneMatch[1]];\n if (!zoneId) {\n this.log.warn(`v2 command ignored: unknown zone ${zoneMatch[1]}`);\n return;\n }\n const action = zoneMatch[2];\n if (action === 'stopZone') {\n await this.v2Mutate(stopZoneMutation(zoneId));\n sent = true;\n } else if (action === 'runZone' && (state.val || state.val === 0)) {\n this.log.info(`v2 start zone ${zoneMatch[1]} for ${Number(state.val)}s`);\n await this.v2Mutate(startZoneMutation(zoneId, Number(state.val)));\n sent = true;\n } else if (action === 'runDefault' && state.val) {\n this.log.info(`v2 start zone ${zoneMatch[1]} with default duration`);\n await this.v2Mutate(startZoneMutation(zoneId));\n void this.setState(id, false, true);\n sent = true;\n } else if (action === 'suspendZone' && (state.val || state.val === 0)) {\n const until = new Date(state.ts + Number(state.val) * 1000);\n await this.v2Mutate(suspendZoneMutation(zoneId, until));\n sent = true;\n }\n }\n\n if (sent) {\n if (zoneMatch?.[2] !== 'runDefault') {\n void this.setState(id, state.val, true);\n }\n await this.pollV2Status();\n }\n } catch (error: any) {\n if (isRateLimitError(error)) {\n this.v2BackoffFails += 1;\n const delay = nextBackoffMs(this.v2BackoffFails, getRetryAfterSec(error));\n this.log.warn(`v2 command rate limited, delaying poll by ${Math.round(delay / 1000)}s`);\n this.scheduleV2Poll(delay);\n return;\n }\n this.log.error(`v2 command failed for ${id}: ${error?.message || error}`);\n }\n }\n\n name2id(pName: string): string {\n return sanitizeId(pName, this.FORBIDDEN_CHARS);\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial<utils.AdapterOptions> | undefined) => new Hydrawise(options);\n} else {\n // otherwise start the instance directly\n (() => new Hydrawise())();\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n * Created with @iobroker/create-adapter v2.3.0\n */\n\nimport * as utils from '@iobroker/adapter-core';\nimport {\n CUSTOMER_INTERVAL_MS,\n CUSTOMER_SKIP_KEYS,\n CUSTOMER_STAGGER_MS,\n HYDRAWISE_BASE_URL,\n SCHEDULE_SKIP_KEYS,\n buildHydrawiseUrl,\n getRetryAfterSec,\n instanceConnected,\n isRateLimitError,\n isScalarKey,\n name2id as sanitizeId,\n nextBackoffMs,\n parseRetryAfter,\n structureSignature,\n} from './lib/helpers';\nimport {\n HydrawiseV2Error,\n type V2Token,\n fetchAccessToken,\n graphqlRequest,\n refreshAccessToken,\n tokenNeedsRefresh,\n} from './lib/v2/auth';\nimport {\n type MappedNode,\n computeWaterSummary,\n mapAllZoneCommandObjects,\n mapControllerStates,\n mapSensorStates,\n mapWaterStates,\n mapWeatherStates,\n mapZoneCommandObjects,\n mapZoneStates,\n pickController,\n v2StructureKey,\n zoneIdMap,\n} from './lib/v2/mapper';\nimport {\n STATUS_QUERY,\n type WaterPeriod,\n nextLongPeriod,\n startAllZonesMutation,\n mutationErrorSummary,\n startZoneMutation,\n stopAllZonesMutation,\n stopZoneMutation,\n suspendAllZonesMutation,\n suspendZoneMutation,\n waterRequest,\n weatherRequest,\n} from './lib/v2/queries';\n\ninterface ApiResponse {\n status: number;\n data: any;\n}\n\nclass Hydrawise extends utils.Adapter {\n private pollScheduleTimer?: ioBroker.Interval;\n private pollCustomerTimer?: ioBroker.Timeout;\n private pollV2Timer?: ioBroker.Timeout;\n private resetSwitchTimer?: ioBroker.Timeout;\n private relays: Record<string, number> = {};\n private lastErrorCode: string | number = 0;\n private schedulePollRunning = false;\n private customerPollRunning = false;\n private scheduleStructureKey = '';\n private customerStructureKey = '';\n private scheduleObjectsReady = false;\n private customerObjectsReady = false;\n private customerBackoffFails = 0;\n private lastCustomerCallAt = 0;\n private v1ControllerId?: number;\n private v2Token: V2Token | null = null;\n private v2PollRunning = false;\n private v2BackoffFails = 0;\n private v2LongPeriodIndex = 0;\n private v2ControllerId?: number;\n private v2ZoneIds: Record<string, number> = {};\n private v2LastRetryAfter?: number;\n private v2StructureSig = '';\n private v2ObjectsReady = false;\n private v1Online = false;\n private v2Online = false;\n\n public constructor(options: Partial<utils.AdapterOptions> = {}) {\n super({\n ...options,\n name: 'hydrawise',\n });\n\n this.on('ready', this.onReady.bind(this));\n this.on('stateChange', this.onStateChange.bind(this));\n this.on('unload', this.onUnload.bind(this));\n }\n\n private isV1Enabled(): boolean {\n return this.config.enableV1 !== false;\n }\n\n private setV1Online(online: boolean): void {\n this.v1Online = online;\n this.syncInstanceConnection();\n }\n\n private setV2Online(online: boolean): void {\n this.v2Online = online;\n void this.setStateChangedAsync('info.connectionV2', online, true);\n this.syncInstanceConnection();\n }\n\n private syncInstanceConnection(): void {\n const connected = instanceConnected(this.isV1Enabled(), !!this.config.enableV2, this.v1Online, this.v2Online);\n void this.setStateChangedAsync('info.connection', connected, true);\n }\n\n private async onReady(): Promise<void> {\n const v1 = this.isV1Enabled();\n const v2 = !!this.config.enableV2;\n\n if (!v1 && !v2) {\n this.log.error('Neither v1 nor v2 API is enabled');\n return;\n }\n\n this.v1Online = false;\n this.v2Online = false;\n this.syncInstanceConnection();\n\n if (v1) {\n if (!this.config.apiKey) {\n this.log.error('No API-Key defined!');\n } else {\n await this.GetStatusSchedule();\n this.pollScheduleTimer = this.setInterval(() => {\n void this.GetStatusSchedule();\n }, this.config.apiInterval * 1000);\n\n this.scheduleCustomerPoll(CUSTOMER_STAGGER_MS);\n await this.subscribeV1Commands();\n }\n }\n\n if (v2) {\n if (!this.config.v2Username || !this.config.v2Password) {\n this.log.error('v2 API enabled but username or password is missing');\n } else {\n await this.subscribeV2Commands();\n this.setV2Online(false);\n this.scheduleV2Poll(0);\n }\n }\n }\n\n private async GetStatusSchedule(): Promise<void> {\n if (this.schedulePollRunning) {\n this.log.debug('Skipping overlapping status schedule poll');\n return;\n }\n\n this.schedulePollRunning = true;\n try {\n const response = await this.buildRequest('statusschedule.php', { api_key: this.config.apiKey });\n if (response.status !== 200) {\n return;\n }\n\n const content = response.data;\n this.setV1Online(true);\n\n const relayIds = (content.relays || []).map((r: any) => r.relay);\n const sensorInputs = (content.sensors || []).map((s: any) => s.input);\n const nextStructureKey = structureSignature(relayIds, sensorInputs);\n const needObjects = !this.scheduleObjectsReady || this.scheduleStructureKey !== nextStructureKey;\n\n if (needObjects) {\n await this.ensureScheduleObjects(content);\n this.scheduleStructureKey = nextStructureKey;\n this.scheduleObjectsReady = true;\n }\n\n this.updateScheduleStates(content);\n } catch (error: any) {\n this.log.debug(`(schedule) received error - API is now offline: ${error?.message || error}`);\n this.setV1Online(false);\n } finally {\n this.schedulePollRunning = false;\n }\n }\n\n private async ensureScheduleObjects(content: any): Promise<void> {\n await this.setObjectNotExistsAsync('schedule.stopall', {\n type: 'state',\n common: {\n name: {\n en: 'stop all zones',\n de: 'alle Zonen stoppen',\n ru: '\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u043E\u043D\u044B',\n pt: 'parar todas as zonas',\n nl: 'stop alle zones',\n fr: 'arr\u00EAter toutes les zones',\n it: 'fermare tutte le zone',\n es: 'detener todas las zonas',\n pl: 'zatrzymuj\u0105 wszystkie strefy',\n uk: '\u0437\u0443\u043F\u0438\u043D\u0438\u0442\u0438 \u0432\u0441\u0456 \u0437\u043E\u043D\u0438',\n 'zh-cn': '\u505C\u6B62\u6240\u6709\u5730\u533A',\n },\n type: 'boolean',\n role: 'button.stop',\n read: false,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync('schedule.runall', {\n type: 'state',\n common: {\n name: {\n en: 'run all zones for x seconds',\n de: 'alle Zonen f\u00FCr x Sekunden ausf\u00FChren',\n ru: '\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u043E\u043D\u044B \u0437\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434\u044B',\n pt: 'executar todas as zonas por x segundos',\n nl: 'ren alle zones voor x seconden',\n fr: 'ex\u00E9cuter toutes les zones pendant x secondes',\n it: 'eseguire tutte le zone per x secondi',\n es: 'ejecutar todas las zonas durante x segundos',\n pl: 'wszystkie strefy startuj\u0105 dla x sekundy',\n uk: '\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0438 \u0432\u0441\u0456 \u0437\u043E\u043D\u0438 \u0434\u043B\u044F x \u0441\u0435\u043A\u0443\u043D\u0434',\n 'zh-cn': '\u8DD1\u9053\u533A',\n },\n type: 'number',\n role: 'level',\n unit: 'seconds',\n read: true,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync('schedule.suspendall', {\n type: 'state',\n common: {\n name: {\n en: 'suspend all zones for x seconds',\n de: 'alle Zonen f\u00FCr x Sekunden aussetzen',\n ru: '\u043F\u0440\u0438\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u043E\u043D\u044B \u0437\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434\u044B',\n pt: 'suspender todas as zonas por x segundos',\n nl: 'vertaling:',\n fr: 'suspendre toutes les zones pendant x secondes',\n it: 'sospendere tutte le zone per x secondi',\n es: 'suspender todas las zonas durante x segundos',\n pl: 'wszystkie strefy zawieszenia dla x sekundy',\n uk: '\u043F\u0440\u0438\u0437\u0443\u043F\u0438\u043D\u0438\u0442\u0438 \u0432\u0441\u0456 \u0437\u043E\u043D\u0438 \u043D\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434',\n 'zh-cn': '\u505C\u6B62\u6240\u6709\u00D7\u4E8C\u533A',\n },\n type: 'number',\n role: 'level',\n read: true,\n write: true,\n },\n native: {},\n });\n\n for (const rawKey of Object.keys(content)) {\n const key = this.name2id(rawKey);\n if (!isScalarKey(key, SCHEDULE_SKIP_KEYS)) {\n continue;\n }\n\n await this.setObjectNotExistsAsync(`schedule.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: key === 'message' ? 'string' : 'number',\n role: key === 'message' ? 'text' : 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n\n if (key === 'time') {\n await this.setObjectNotExistsAsync('schedule.timestr', {\n type: 'state',\n common: {\n name: 'last api call',\n type: 'string',\n role: 'text',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n }\n\n for (const relay of content.relays || []) {\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}`, {\n type: 'channel',\n common: {\n name: String(relay.relay),\n },\n native: {},\n });\n\n for (const rawKey of Object.keys(relay)) {\n const key = this.name2id(rawKey);\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: key === 'name' || key === 'timestr' ? 'string' : 'number',\n role: key === 'name' || key === 'timestr' ? 'text' : 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.stopZone`, {\n type: 'state',\n common: {\n name: {\n en: 'stop zone',\n de: 'Zone stoppen',\n ru: '\u0437\u043E\u043D\u0430 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438',\n pt: 'zona de paragem',\n nl: 'stop zone',\n fr: \"zone d ' arr\u00EAt\",\n it: 'zona di sosta',\n es: 'zona de parada',\n pl: 'strefa stopu',\n uk: '\u0437\u043E\u043D\u0430 \u0437\u0443\u043F\u0438\u043D\u043A\u0438',\n 'zh-cn': '\u505C\u6B62\u5730\u533A',\n },\n type: 'boolean',\n role: 'button.stop',\n read: false,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.runZone`, {\n type: 'state',\n common: {\n name: {\n en: 'run zone for x seconds',\n de: 'Zone f\u00FCr x Sekunden starten',\n ru: '\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0437\u043E\u043D\u0443 \u0437\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434\u044B',\n pt: 'zona de execu\u00E7\u00E3o por x segundos',\n nl: 'ren zone voor x seconden',\n fr: 'zone de course pour x secondes',\n it: 'zona di corsa per x secondi',\n es: 'zona de ejecuci\u00F3n por x segundos',\n pl: 'strefa x sekundy',\n uk: '\u0437\u043E\u043D\u0430 \u0437\u0430\u043F\u0443\u0441\u043A\u0443 \u0434\u043B\u044F x \u0441\u0435\u043A\u0443\u043D\u0434',\n 'zh-cn': '\u00D7\u4E8C\u533A',\n },\n type: 'number',\n role: 'level',\n read: true,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.suspendZone`, {\n type: 'state',\n common: {\n name: {\n en: 'suspend zone for x seconds',\n de: 'Zone f\u00FCr x Sekunden aussetzen',\n ru: '\u043F\u0440\u0438\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0437\u043E\u043D\u0443 \u043D\u0430 x \u0441\u0435\u043A\u0443\u043D\u0434\u044B',\n pt: 'zona de suspens\u00E3o por x segundos',\n nl: 'quality over quantity (qoq) releases vertaling:',\n fr: 'zone de suspension pour x secondes',\n it: 'zona di sospensione per x secondi',\n es: 'zona de suspensi\u00F3n por x segundos',\n pl: 'strefa zawies\u0142a na x sekundy',\n uk: '\u0437\u043E\u043D\u0430 \u043F\u0456\u0434\u0432\u0456\u0441\u043A\u0438 \u0434\u043B\u044F x \u0441\u0435\u043A\u0443\u043D\u0434',\n 'zh-cn': '\u505C\u6B62x\u4E8C\u533A',\n },\n type: 'number',\n role: 'level',\n read: true,\n write: true,\n },\n native: {},\n });\n\n await this.setObjectNotExistsAsync(`schedule.${relay.relay}.runDefault`, {\n type: 'state',\n common: {\n name: {\n en: 'run zone for default time',\n de: 'Zone mit Standardlaufzeit starten',\n ru: '\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0437\u043E\u043D\u0443 \u0434\u043B\u044F \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E',\n pt: 'fuso de execu\u00E7\u00E3o para o tempo padr\u00E3o',\n nl: 'run zone for default time',\n fr: 'run zone for default time',\n it: 'run zone per il tempo predefinito',\n es: 'zona de ejecuci\u00F3n por tiempo predeterminado',\n pl: 'strefa czasu domy\u015Blnego',\n uk: '\u0437\u043E\u043D\u0430 \u0437\u0430\u043F\u0443\u0441\u043A\u0443 \u0437\u0430 \u0437\u0430\u043C\u043E\u0432\u0447\u0443\u0432\u0430\u043D\u043D\u044F\u043C',\n 'zh-cn': 'a. \u6682\u505C\u65F6\u95F4\u533A',\n },\n type: 'boolean',\n role: 'button.start',\n read: true,\n write: true,\n },\n native: {},\n });\n }\n\n for (const sensor of content.sensors || []) {\n await this.setObjectNotExistsAsync(`schedule.sensors.${sensor.input}`, {\n type: 'channel',\n common: {\n name: 'sensors',\n },\n native: {},\n });\n\n for (const rawKey of Object.keys(sensor)) {\n if (rawKey === 'relays') {\n continue;\n }\n const key = this.name2id(rawKey);\n await this.setObjectNotExistsAsync(`schedule.sensors.${sensor.input}.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: 'number',\n role: 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n }\n }\n\n private updateScheduleStates(content: any): void {\n for (const rawKey of Object.keys(content)) {\n const key = this.name2id(rawKey);\n if (!isScalarKey(key, SCHEDULE_SKIP_KEYS)) {\n continue;\n }\n\n void this.setStateChangedAsync(`schedule.${key}`, content[rawKey], true);\n\n if (key === 'time') {\n const t = new Date(content[rawKey] * 1000);\n void this.setStateChangedAsync('schedule.timestr', t.toString(), true);\n }\n }\n\n for (const relay of content.relays || []) {\n this.relays[relay.relay] = relay.relay_id;\n\n for (const rawKey of Object.keys(relay)) {\n const key = this.name2id(rawKey);\n let value = relay[rawKey];\n\n if (key === 'timestr') {\n const t = new Date();\n t.setSeconds(t.getSeconds() + relay.time);\n value = t.toString();\n }\n\n void this.setStateChangedAsync(`schedule.${relay.relay}.${key}`, value, true);\n }\n }\n\n for (const sensor of content.sensors || []) {\n for (const rawKey of Object.keys(sensor)) {\n if (rawKey === 'relays') {\n continue;\n }\n const key = this.name2id(rawKey);\n void this.setStateChangedAsync(`schedule.sensors.${sensor.input}.${key}`, sensor[rawKey], true);\n }\n }\n }\n\n private scheduleCustomerPoll(delayMs: number): void {\n if (this.pollCustomerTimer) {\n this.clearTimeout(this.pollCustomerTimer);\n }\n this.pollCustomerTimer = this.setTimeout(\n () => {\n this.pollCustomerTimer = undefined;\n void this.runCustomerPoll();\n },\n Math.max(0, delayMs),\n );\n }\n\n private async runCustomerPoll(): Promise<void> {\n const delay = await this.GetCustomerDetails();\n this.scheduleCustomerPoll(delay);\n }\n\n private async GetCustomerDetails(): Promise<number> {\n if (this.customerPollRunning) {\n this.log.debug('Skipping overlapping customer details poll');\n return CUSTOMER_INTERVAL_MS;\n }\n\n const elapsed = this.lastCustomerCallAt ? Date.now() - this.lastCustomerCallAt : CUSTOMER_INTERVAL_MS;\n if (this.lastCustomerCallAt && elapsed < CUSTOMER_INTERVAL_MS) {\n this.log.debug('Skipping customer details poll (inside 5 minute window)');\n return CUSTOMER_INTERVAL_MS - elapsed;\n }\n\n this.customerPollRunning = true;\n this.lastCustomerCallAt = Date.now();\n try {\n const response = await this.buildRequest('customerdetails.php', { api_key: this.config.apiKey });\n if (response.status !== 200) {\n return CUSTOMER_INTERVAL_MS;\n }\n\n const content = response.data;\n this.customerBackoffFails = 0;\n if (content?.controller_id != null) {\n this.v1ControllerId = Number(content.controller_id);\n }\n\n const controllerNames = (content.controllers || []).map((c: any) => this.name2id(c.name));\n const nextStructureKey = structureSignature([], [], controllerNames);\n const needObjects = !this.customerObjectsReady || this.customerStructureKey !== nextStructureKey;\n\n if (needObjects) {\n await this.ensureCustomerObjects(content);\n this.customerStructureKey = nextStructureKey;\n this.customerObjectsReady = true;\n }\n\n this.updateCustomerStates(content);\n return CUSTOMER_INTERVAL_MS;\n } catch (error: any) {\n if (isRateLimitError(error)) {\n this.customerBackoffFails += 1;\n const delay = nextBackoffMs(this.customerBackoffFails, getRetryAfterSec(error));\n this.log.warn(\n `customerdetails rate limited, next poll in ${Math.round(delay / 1000)}s (attempt ${this.customerBackoffFails})`,\n );\n return delay;\n }\n\n this.log.debug(`(customer) received error: ${error?.message || error}`);\n return CUSTOMER_INTERVAL_MS;\n } finally {\n this.customerPollRunning = false;\n }\n }\n\n private async ensureCustomerObjects(content: any): Promise<void> {\n for (const rawKey of Object.keys(content)) {\n if (!isScalarKey(rawKey, CUSTOMER_SKIP_KEYS)) {\n continue;\n }\n const key = this.name2id(rawKey);\n\n await this.setObjectNotExistsAsync(`customer.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: key === 'message' || key === 'current_controller' ? 'string' : 'number',\n role: key === 'message' || key === 'current_controller' ? 'text' : 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n\n for (const controller of content.controllers || []) {\n const controllerId = this.name2id(controller.name);\n await this.setObjectNotExistsAsync(`customer.controllers.${controllerId}`, {\n type: 'channel',\n common: {\n name: controller.name,\n },\n native: {},\n });\n\n for (const rawKey of Object.keys(controller)) {\n const key = this.name2id(rawKey);\n await this.setObjectNotExistsAsync(`customer.controllers.${controllerId}.${key}`, {\n type: 'state',\n common: {\n name: key,\n type: key !== 'controller_id' ? 'string' : 'number',\n role: key !== 'controller_id' ? 'text' : 'value',\n read: true,\n write: false,\n },\n native: {},\n });\n }\n }\n }\n\n private updateCustomerStates(content: any): void {\n for (const rawKey of Object.keys(content)) {\n if (!isScalarKey(rawKey, CUSTOMER_SKIP_KEYS)) {\n continue;\n }\n const key = this.name2id(rawKey);\n void this.setStateChangedAsync(`customer.${key}`, content[rawKey], true);\n }\n\n for (const controller of content.controllers || []) {\n const controllerId = this.name2id(controller.name);\n\n for (const rawKey of Object.keys(controller)) {\n const key = this.name2id(rawKey);\n let value = controller[rawKey];\n\n if (key === 'last_contact') {\n const t = new Date(controller[rawKey] * 1000);\n value = t.toString();\n }\n\n void this.setStateChangedAsync(`customer.controllers.${controllerId}.${key}`, value, true);\n }\n }\n }\n\n /**\n * Perform a GET request against the Hydrawise API.\n *\n * @param service endpoint file name\n * @param params query parameters\n */\n async buildRequest(service: string, params: Record<string, string | number | boolean>): Promise<ApiResponse> {\n if (!params.api_key) {\n throw new Error('API key is not configured');\n }\n\n const url = buildHydrawiseUrl(service, params);\n const abort = new AbortController();\n const timeout = setTimeout(() => abort.abort(), 30_000);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n signal: abort.signal,\n headers: { Accept: 'application/json' },\n });\n\n this.lastErrorCode = 0;\n\n let data: any = null;\n const text = await response.text();\n if (text) {\n try {\n data = JSON.parse(text);\n } catch {\n data = text;\n }\n }\n\n if (!response.ok) {\n this.log.warn(\n `received ${response.status} response from /api/v1/${service} with content: ${JSON.stringify(data)}`,\n );\n throw Object.assign(new Error(`HTTP ${response.status}`), {\n code: response.status,\n retryAfter: parseRetryAfter(response.headers.get('Retry-After')),\n response: { status: response.status, data },\n });\n }\n\n return { status: response.status, data };\n } catch (error: any) {\n if (error?.response) {\n // already logged above for HTTP errors\n } else if (error?.name === 'AbortError') {\n const code = 'ECONNABORTED';\n if (code === this.lastErrorCode) {\n this.log.debug(`timeout from ${HYDRAWISE_BASE_URL}/api/v1/${service}`);\n } else {\n this.log.info(`error ${code} from /api/v1/${service}: request timed out`);\n this.lastErrorCode = code;\n }\n throw Object.assign(new Error('request timed out'), { code });\n } else if (error?.message) {\n const code = error.code || error.cause?.code || 'ENOTFOUND';\n if (code === this.lastErrorCode) {\n this.log.debug(error.message);\n } else {\n this.log.info(`error ${code} from /api/v1/${service}: ${error.message}`);\n this.lastErrorCode = code;\n }\n } else {\n this.log.error(String(error));\n }\n\n throw error instanceof Error ? error : new Error(String(error));\n } finally {\n clearTimeout(timeout);\n }\n }\n\n /**\n * Is called when adapter shuts down - callback has to be called under any circumstances!\n *\n * @param callback callback function\n */\n private onUnload(callback: () => void): void {\n try {\n if (this.pollScheduleTimer) {\n this.clearInterval(this.pollScheduleTimer);\n this.pollScheduleTimer = undefined;\n }\n if (this.pollCustomerTimer) {\n this.clearTimeout(this.pollCustomerTimer);\n this.pollCustomerTimer = undefined;\n }\n if (this.pollV2Timer) {\n this.clearTimeout(this.pollV2Timer);\n this.pollV2Timer = undefined;\n }\n if (this.resetSwitchTimer) {\n this.clearTimeout(this.resetSwitchTimer);\n this.resetSwitchTimer = undefined;\n }\n\n callback();\n } catch {\n callback();\n }\n }\n\n /**\n * Is called if a subscribed state changes\n *\n * @param id id of the state\n * @param state state object\n */\n private onStateChange(id: string, state: ioBroker.State | null | undefined): void {\n if (!state) {\n return;\n }\n if (state.ack && state.from === `system.adapter.${this.namespace}`) {\n return;\n }\n void this.handleStateChange(id, state);\n }\n\n private async handleStateChange(id: string, state: ioBroker.State): Promise<void> {\n try {\n if (id.includes('.zones.')) {\n await this.handleV2Command(id, state);\n return;\n }\n if (!this.isV1Enabled() || !id.includes('.schedule.')) {\n return;\n }\n\n let commandSent = false;\n\n if (id.includes('stopall')) {\n await this.buildRequest('setzone.php', { api_key: this.config.apiKey, action: 'stopall' });\n commandSent = true;\n } else if (id.includes('stopZone')) {\n const relay = id.match(/.*schedule\\.(.*)\\.stopZone/);\n if (relay && relay.length > 1) {\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'stop',\n relay_id: this.relays[relay[1]],\n });\n commandSent = true;\n }\n }\n\n if (id.includes('runall') && (state.val || state.val === 0)) {\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'runall',\n period_id: 999,\n custom: state.val,\n });\n commandSent = true;\n } else if (id.includes('runZone') && (state.val || state.val === 0)) {\n const relay = id.match(/.*schedule\\.(.*)\\.runZone/);\n if (relay && relay.length > 1) {\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'run',\n period_id: 999,\n custom: state.val,\n relay_id: this.relays[relay[1]],\n });\n commandSent = true;\n }\n }\n\n if (id.includes('runDefault') && state.val !== null) {\n await this.initRunDefault(id, state.val as boolean);\n commandSent = true;\n }\n\n if (id.includes('suspendall') && (state.val || state.val === 0)) {\n const num = state.val as number;\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'suspendall',\n period_id: 999,\n custom: Math.trunc((state.ts + num) / 1000),\n });\n commandSent = true;\n } else if (id.includes('suspendZone') && (state.val || state.val === 0)) {\n const num = state.val as number;\n const relay = id.match(/.*schedule\\.(.*)\\.suspendZone/);\n if (relay && relay.length > 1) {\n await this.buildRequest('setzone.php', {\n api_key: this.config.apiKey,\n action: 'suspend',\n period_id: 999,\n custom: Math.trunc((state.ts + num) / 1000),\n relay_id: this.relays[relay[1]],\n });\n commandSent = true;\n }\n }\n\n if (commandSent && !id.includes('runDefault')) {\n await this.GetStatusSchedule();\n }\n } catch (error: any) {\n this.log.error(`Command failed for ${id}: ${error?.message || error}`);\n }\n }\n\n async initRunDefault(id: string, run: boolean): Promise<void> {\n const relay = id.match(/(.*schedule.*\\.)runDefault/);\n\n if (this.resetSwitchTimer) {\n this.clearTimeout(this.resetSwitchTimer);\n this.resetSwitchTimer = undefined;\n }\n\n if (relay) {\n if (run) {\n const defaultRunTime = await this.getStateAsync(`${relay[1]}run`);\n if (defaultRunTime && defaultRunTime.val) {\n void this.setState(`${relay[1]}runZone`, defaultRunTime.val, false);\n this.resetSwitchTimer = this.setTimeout(\n () => {\n void this.setState(id, false, true);\n this.resetSwitchTimer = undefined;\n },\n (defaultRunTime.val as number) * 1000,\n );\n }\n } else {\n void this.setState(`${relay[1]}stopZone`, true, false);\n }\n }\n }\n\n private async subscribeV1Commands(): Promise<void> {\n await this.subscribeStatesAsync('schedule.stopall');\n await this.subscribeStatesAsync('schedule.runall');\n await this.subscribeStatesAsync('schedule.suspendall');\n await this.subscribeStatesAsync('schedule.*.stopZone');\n await this.subscribeStatesAsync('schedule.*.runZone');\n await this.subscribeStatesAsync('schedule.*.suspendZone');\n await this.subscribeStatesAsync('schedule.*.runDefault');\n }\n\n private async subscribeV2Commands(): Promise<void> {\n await this.subscribeStatesAsync('zones.stopall');\n await this.subscribeStatesAsync('zones.runall');\n await this.subscribeStatesAsync('zones.suspendall');\n await this.subscribeStatesAsync('zones.*.stopZone');\n await this.subscribeStatesAsync('zones.*.runZone');\n await this.subscribeStatesAsync('zones.*.suspendZone');\n await this.subscribeStatesAsync('zones.*.runDefault');\n }\n\n private v2IntervalMs(): number {\n return Math.max(120, Number(this.config.apiIntervalV2) || 300) * 1000;\n }\n\n private scheduleV2Poll(delayMs: number): void {\n if (this.pollV2Timer) {\n this.clearTimeout(this.pollV2Timer);\n }\n this.pollV2Timer = this.setTimeout(\n () => {\n this.pollV2Timer = undefined;\n void this.runV2Poll();\n },\n Math.max(0, delayMs),\n );\n }\n\n private async runV2Poll(statusOnly = false): Promise<void> {\n if (this.v2PollRunning) {\n this.log.debug('Skipping overlapping v2 poll');\n return;\n }\n\n this.v2PollRunning = true;\n let delay = this.v2IntervalMs();\n try {\n const statusResult = await this.pollV2Status();\n if (statusResult === 'rate-limit') {\n this.v2BackoffFails += 1;\n delay = nextBackoffMs(this.v2BackoffFails, this.v2LastRetryAfter);\n this.log.warn(`v2 rate limited, next poll in ${Math.round(delay / 1000)}s`);\n return;\n }\n\n if (statusOnly || !this.v2ControllerId) {\n return;\n }\n\n const weatherResult = await this.pollV2Weather();\n if (weatherResult === 'rate-limit') {\n this.v2BackoffFails += 1;\n delay = nextBackoffMs(this.v2BackoffFails, this.v2LastRetryAfter);\n this.log.warn(`v2 rate limited, next poll in ${Math.round(delay / 1000)}s`);\n return;\n }\n\n const todayResult = await this.pollV2Water('today');\n if (todayResult === 'rate-limit') {\n this.v2BackoffFails += 1;\n delay = nextBackoffMs(this.v2BackoffFails, this.v2LastRetryAfter);\n this.log.warn(`v2 rate limited, next poll in ${Math.round(delay / 1000)}s`);\n return;\n }\n\n const { period, nextIndex } = nextLongPeriod(this.v2LongPeriodIndex);\n const longResult = await this.pollV2Water(period);\n if (longResult === 'rate-limit') {\n this.v2BackoffFails += 1;\n delay = nextBackoffMs(this.v2BackoffFails, this.v2LastRetryAfter);\n this.log.warn(`v2 rate limited, next poll in ${Math.round(delay / 1000)}s`);\n return;\n }\n this.v2LongPeriodIndex = nextIndex;\n this.v2BackoffFails = 0;\n } finally {\n this.v2PollRunning = false;\n if (!statusOnly) {\n this.scheduleV2Poll(delay);\n }\n }\n }\n\n private async ensureV2Token(): Promise<V2Token> {\n if (tokenNeedsRefresh(this.v2Token)) {\n if (this.v2Token?.refreshToken) {\n try {\n this.v2Token = await refreshAccessToken(this.v2Token.refreshToken);\n } catch {\n this.v2Token = await fetchAccessToken(this.config.v2Username, this.config.v2Password);\n }\n } else {\n this.v2Token = await fetchAccessToken(this.config.v2Username, this.config.v2Password);\n }\n }\n if (!this.v2Token) {\n throw new HydrawiseV2Error('No v2 token', 'unauthorized');\n }\n return this.v2Token;\n }\n\n private async v2Graphql(request: { query: string; variables?: Record<string, unknown> }): Promise<any> {\n const token = await this.ensureV2Token();\n try {\n return await graphqlRequest(token, request);\n } catch (error) {\n if (error instanceof HydrawiseV2Error && error.code === 401) {\n this.v2Token = await fetchAccessToken(this.config.v2Username, this.config.v2Password);\n return await graphqlRequest(this.v2Token, request);\n }\n throw error;\n }\n }\n\n private async v2Mutate(request: { query: string; variables?: Record<string, unknown> }): Promise<any> {\n const data = await this.v2Graphql(request);\n const failed = mutationErrorSummary(data);\n if (failed) {\n throw new HydrawiseV2Error(failed, 'mutation', data);\n }\n return data;\n }\n\n private async applyMappedNodes(nodes: MappedNode[], createObjects: boolean): Promise<void> {\n for (const node of nodes) {\n if (createObjects) {\n await this.setObjectNotExistsAsync(node.id, {\n type: node.type,\n common: node.common as any,\n native: {},\n });\n }\n if (node.type === 'state' && node.value !== undefined) {\n void this.setStateChangedAsync(node.id, node.value, true);\n }\n }\n }\n\n private async pollV2Status(): Promise<'ok' | 'rate-limit' | 'error'> {\n try {\n const data = await this.v2Graphql({ query: STATUS_QUERY });\n const controller = pickController(\n data?.me?.controllers,\n data?.me?.currentController?.id,\n this.v1ControllerId,\n );\n if (!controller) {\n this.log.warn('v2 status: no controller in response');\n this.setV2Online(false);\n return 'error';\n }\n\n this.v2ControllerId = Number(controller.id);\n this.v2ZoneIds = zoneIdMap(controller);\n\n const nextKey = v2StructureKey(controller);\n const needObjects = !this.v2ObjectsReady || this.v2StructureSig !== nextKey;\n if (needObjects) {\n await this.applyMappedNodes(mapAllZoneCommandObjects(), true);\n for (const zone of controller.zones || []) {\n const n = zone?.number?.value;\n if (n !== undefined && n !== null) {\n await this.applyMappedNodes(mapZoneCommandObjects(n), true);\n }\n }\n this.v2StructureSig = nextKey;\n this.v2ObjectsReady = true;\n await this.subscribeV2Commands();\n }\n\n await this.applyMappedNodes(mapControllerStates(controller), needObjects);\n for (const zone of controller.zones || []) {\n await this.applyMappedNodes(mapZoneStates(zone), needObjects);\n }\n for (const sensor of controller.sensors || []) {\n await this.applyMappedNodes(mapSensorStates(sensor), needObjects);\n }\n\n this.setV2Online(true);\n return 'ok';\n } catch (error: any) {\n this.v2LastRetryAfter = getRetryAfterSec(error);\n this.log.debug(`v2 status: ${error?.message || error}`);\n this.setV2Online(false);\n return isRateLimitError(error) ? 'rate-limit' : 'error';\n }\n }\n\n private async pollV2Weather(): Promise<'ok' | 'rate-limit' | 'error'> {\n if (!this.v2ControllerId) {\n return 'error';\n }\n try {\n const data = await this.v2Graphql(weatherRequest(this.v2ControllerId));\n await this.applyMappedNodes(mapWeatherStates(data?.controller?.location?.forecast), true);\n return 'ok';\n } catch (error: any) {\n this.v2LastRetryAfter = getRetryAfterSec(error);\n this.log.debug(`v2 weather: ${error?.message || error}`);\n return isRateLimitError(error) ? 'rate-limit' : 'error';\n }\n }\n\n private async pollV2Water(period: WaterPeriod): Promise<'ok' | 'rate-limit' | 'error'> {\n if (!this.v2ControllerId) {\n return 'error';\n }\n try {\n const request = waterRequest(this.v2ControllerId, period);\n const data = await this.v2Graphql(request);\n const summary = computeWaterSummary(data?.controller);\n await this.applyMappedNodes(mapWaterStates(period, summary), true);\n return 'ok';\n } catch (error: any) {\n this.v2LastRetryAfter = getRetryAfterSec(error);\n this.log.debug(`v2 water (${period}): ${error?.message || error}`);\n return isRateLimitError(error) ? 'rate-limit' : 'error';\n }\n }\n\n private async handleV2Command(id: string, state: ioBroker.State): Promise<void> {\n if (!this.config.enableV2) {\n return;\n }\n if (!this.v2ControllerId) {\n this.log.warn('v2 command ignored: controller id is unknown');\n return;\n }\n\n try {\n let sent = false;\n const zoneMatch = id.match(/\\.zones\\.(\\d+)\\.(stopZone|runZone|suspendZone|runDefault)$/);\n\n if (id.endsWith('.zones.stopall')) {\n await this.v2Mutate(stopAllZonesMutation(this.v2ControllerId));\n sent = true;\n } else if (id.endsWith('.zones.runall') && (state.val || state.val === 0)) {\n await this.v2Mutate(startAllZonesMutation(this.v2ControllerId, Number(state.val)));\n sent = true;\n } else if (id.endsWith('.zones.suspendall') && (state.val || state.val === 0)) {\n const until = new Date(state.ts + Number(state.val) * 1000);\n await this.v2Mutate(suspendAllZonesMutation(this.v2ControllerId, until));\n sent = true;\n } else if (zoneMatch) {\n const zoneId = this.v2ZoneIds[zoneMatch[1]];\n if (!zoneId) {\n this.log.warn(`v2 command ignored: unknown zone ${zoneMatch[1]}`);\n return;\n }\n const action = zoneMatch[2];\n if (action === 'stopZone') {\n await this.v2Mutate(stopZoneMutation(zoneId));\n sent = true;\n } else if (action === 'runZone' && (state.val || state.val === 0)) {\n this.log.info(`v2 start zone ${zoneMatch[1]} for ${Number(state.val)}s`);\n await this.v2Mutate(startZoneMutation(zoneId, Number(state.val)));\n sent = true;\n } else if (action === 'runDefault' && state.val) {\n this.log.info(`v2 start zone ${zoneMatch[1]} with default duration`);\n await this.v2Mutate(startZoneMutation(zoneId));\n void this.setState(id, false, true);\n sent = true;\n } else if (action === 'suspendZone' && (state.val || state.val === 0)) {\n const until = new Date(state.ts + Number(state.val) * 1000);\n await this.v2Mutate(suspendZoneMutation(zoneId, until));\n sent = true;\n }\n }\n\n if (sent) {\n if (zoneMatch?.[2] !== 'runDefault') {\n void this.setState(id, state.val, true);\n }\n await this.pollV2Status();\n }\n } catch (error: any) {\n if (isRateLimitError(error)) {\n this.v2BackoffFails += 1;\n const delay = nextBackoffMs(this.v2BackoffFails, getRetryAfterSec(error));\n this.log.warn(`v2 command rate limited, delaying poll by ${Math.round(delay / 1000)}s`);\n this.scheduleV2Poll(delay);\n return;\n }\n this.log.error(`v2 command failed for ${id}: ${error?.message || error}`);\n }\n }\n\n name2id(pName: string): string {\n return sanitizeId(pName, this.FORBIDDEN_CHARS);\n }\n}\n\nif (require.main !== module) {\n // Export the constructor in compact mode\n module.exports = (options: Partial<utils.AdapterOptions> | undefined) => new Hydrawise(options);\n} else {\n // otherwise start the instance directly\n (() => new Hydrawise())();\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["sanitizeId"]
7
7
  }
package/io-package.json CHANGED
@@ -1,8 +1,21 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "hydrawise",
4
- "version": "2.0.0",
4
+ "version": "2.0.1",
5
5
  "news": {
6
+ "2.0.1": {
7
+ "en": "**FIXED**: Instance `info.connection` follows every enabled API (v2-only no longer stays red)",
8
+ "de": "**REPARIERT**: Instanz `info.connection` folgt jeder API (nur v2 bleibt nicht mehr rot)",
9
+ "ru": "**ИСПРАВЛЕНО**: экземпляр `info.connection` следует за всеми включенными API (только версия 2 больше не отображается красным цветом)",
10
+ "pt": "**CORRIGIDO**: A instância `info.connection` segue cada API (a v2 não fica mais vermelha)",
11
+ "nl": "**FIXED**: De instantie `info.connection` volgt elke ingeschakelde API (alleen v2 blijft niet langer rood)",
12
+ "fr": "**CORRIGÉ** : L'instance « info.connection » suit toutes les API activées (la v2 seule ne reste plus rouge)",
13
+ "it": "**FISSO**: L'istanza `info.connection` segue ogni API abilitata (solo v2 non è più rossa)",
14
+ "es": "**FIJO**: La instancia `info.connection` sigue todas las API habilitadas (solo la v2 ya no está en rojo)",
15
+ "pl": "**NAPRAWIONO**: Instancja `info.connection` podąża za każdym włączonym interfejsem API (tylko v2 nie pozostaje już czerwony)",
16
+ "uk": "** ВИПРАВЛЕНО**: Екземпляр `info.connection` слідує за кожним увімкненим API (лише v2 більше не залишається червоним)",
17
+ "zh-cn": "**已修复**:实例 “info.connection” 遵循每个已启用的 API(仅限 v2 不再保持红色)"
18
+ },
6
19
  "2.0.0": {
7
20
  "en": "**NEW**: Optional Hydrawise v2 GraphQL API (water usage, live sensors, weather, leak indicator, zone commands)\n**ENHANCED**: customerdetails.php polls on its own 5-minute timer with backoff after rate limits",
8
21
  "de": "**NEU**: Optionale Hydrawise v2 GraphQL API (Wasserverbrauch, Livesensoren, Wetter, Zonenbefehle)\n**VERBESSERT**: customerdetails.php fragt im eigenen 5-Minuten-Timer ab, nach Ratenlimit",
@@ -80,19 +93,6 @@
80
93
  "pl": "zaktualizowane zależności",
81
94
  "uk": "оновлені залежності",
82
95
  "zh-cn": "更新的依赖关系"
83
- },
84
- "1.0.2": {
85
- "en": "fixed issues detected by repository checker",
86
- "de": "von repository checker erkannte probleme",
87
- "ru": "фиксированные проблемы, выявленные регистратором",
88
- "pt": "problemas corrigidos detectados pelo verificador de repositório",
89
- "nl": "vaste problemen gedetecteerd door repository checker",
90
- "fr": "problèmes corrigés détectés par le vérificateur du dépôt",
91
- "it": "problemi fissi rilevati da repository checker",
92
- "es": "problemas fijos detectados por el repositorio",
93
- "pl": "stałe problemy wykryte przez kontroler repozytorium",
94
- "uk": "виправлені питання, виявлені репозиторійним чекером",
95
- "zh-cn": "仓库检查器检测到的固定问题"
96
96
  }
97
97
  },
98
98
  "titleLang": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.hydrawise",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Adapter to control the Hydrawise irrigation control system",
5
5
  "author": {
6
6
  "name": "SentiQ",