@ecobridge.xyz/devicemanager 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/.gitea/workflows/default_nottags.yaml +66 -0
  2. package/.gitea/workflows/default_tags.yaml +124 -0
  3. package/.vscode/launch.json +11 -0
  4. package/.vscode/settings.json +26 -0
  5. package/changelog.md +91 -0
  6. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  7. package/dist_ts/00_commitinfo_data.js +9 -0
  8. package/dist_ts/device/device.classes.device.d.ts +205 -0
  9. package/dist_ts/device/device.classes.device.js +344 -0
  10. package/dist_ts/devicemanager.classes.devicemanager.d.ts +210 -0
  11. package/dist_ts/devicemanager.classes.devicemanager.js +835 -0
  12. package/dist_ts/discovery/discovery.classes.homeassistant.d.ts +101 -0
  13. package/dist_ts/discovery/discovery.classes.homeassistant.js +313 -0
  14. package/dist_ts/discovery/discovery.classes.mdns.d.ts +90 -0
  15. package/dist_ts/discovery/discovery.classes.mdns.js +291 -0
  16. package/dist_ts/discovery/discovery.classes.networkscanner.d.ts +64 -0
  17. package/dist_ts/discovery/discovery.classes.networkscanner.js +535 -0
  18. package/dist_ts/discovery/discovery.classes.ssdp.d.ts +112 -0
  19. package/dist_ts/discovery/discovery.classes.ssdp.js +255 -0
  20. package/dist_ts/factories/index.d.ts +190 -0
  21. package/dist_ts/factories/index.js +350 -0
  22. package/dist_ts/features/feature.abstract.d.ts +118 -0
  23. package/dist_ts/features/feature.abstract.js +172 -0
  24. package/dist_ts/features/feature.camera.d.ts +95 -0
  25. package/dist_ts/features/feature.camera.js +162 -0
  26. package/dist_ts/features/feature.climate.d.ts +174 -0
  27. package/dist_ts/features/feature.climate.js +328 -0
  28. package/dist_ts/features/feature.cover.d.ts +121 -0
  29. package/dist_ts/features/feature.cover.js +217 -0
  30. package/dist_ts/features/feature.fan.d.ts +127 -0
  31. package/dist_ts/features/feature.fan.js +235 -0
  32. package/dist_ts/features/feature.light.d.ts +156 -0
  33. package/dist_ts/features/feature.light.js +296 -0
  34. package/dist_ts/features/feature.lock.d.ts +103 -0
  35. package/dist_ts/features/feature.lock.js +170 -0
  36. package/dist_ts/features/feature.playback.d.ts +98 -0
  37. package/dist_ts/features/feature.playback.js +191 -0
  38. package/dist_ts/features/feature.power.d.ts +79 -0
  39. package/dist_ts/features/feature.power.js +173 -0
  40. package/dist_ts/features/feature.print.d.ts +78 -0
  41. package/dist_ts/features/feature.print.js +226 -0
  42. package/dist_ts/features/feature.scan.d.ts +79 -0
  43. package/dist_ts/features/feature.scan.js +315 -0
  44. package/dist_ts/features/feature.sensor.d.ts +95 -0
  45. package/dist_ts/features/feature.sensor.js +147 -0
  46. package/dist_ts/features/feature.snmp.d.ts +88 -0
  47. package/dist_ts/features/feature.snmp.js +175 -0
  48. package/dist_ts/features/feature.switch.d.ts +75 -0
  49. package/dist_ts/features/feature.switch.js +126 -0
  50. package/dist_ts/features/feature.volume.d.ts +104 -0
  51. package/dist_ts/features/feature.volume.js +186 -0
  52. package/dist_ts/features/index.d.ts +19 -0
  53. package/dist_ts/features/index.js +23 -0
  54. package/dist_ts/helpers/helpers.iprange.d.ts +35 -0
  55. package/dist_ts/helpers/helpers.iprange.js +151 -0
  56. package/dist_ts/helpers/helpers.retry.d.ts +25 -0
  57. package/dist_ts/helpers/helpers.retry.js +69 -0
  58. package/dist_ts/index.d.ts +15 -0
  59. package/dist_ts/index.js +40 -0
  60. package/dist_ts/interfaces/feature.interfaces.d.ts +255 -0
  61. package/dist_ts/interfaces/feature.interfaces.js +6 -0
  62. package/dist_ts/interfaces/homeassistant.interfaces.d.ts +550 -0
  63. package/dist_ts/interfaces/homeassistant.interfaces.js +111 -0
  64. package/dist_ts/interfaces/index.d.ts +330 -0
  65. package/dist_ts/interfaces/index.js +16 -0
  66. package/dist_ts/interfaces/smarthome.interfaces.d.ts +282 -0
  67. package/dist_ts/interfaces/smarthome.interfaces.js +7 -0
  68. package/dist_ts/paths.d.ts +1 -0
  69. package/dist_ts/paths.js +3 -0
  70. package/dist_ts/plugins.d.ts +23 -0
  71. package/dist_ts/plugins.js +30 -0
  72. package/dist_ts/protocols/index.d.ts +12 -0
  73. package/dist_ts/protocols/index.js +21 -0
  74. package/dist_ts/protocols/protocol.escl.d.ts +58 -0
  75. package/dist_ts/protocols/protocol.escl.js +364 -0
  76. package/dist_ts/protocols/protocol.homeassistant.d.ts +248 -0
  77. package/dist_ts/protocols/protocol.homeassistant.js +611 -0
  78. package/dist_ts/protocols/protocol.ipp.d.ts +45 -0
  79. package/dist_ts/protocols/protocol.ipp.js +284 -0
  80. package/dist_ts/protocols/protocol.nut.d.ts +160 -0
  81. package/dist_ts/protocols/protocol.nut.js +364 -0
  82. package/dist_ts/protocols/protocol.sane.d.ts +104 -0
  83. package/dist_ts/protocols/protocol.sane.js +597 -0
  84. package/dist_ts/protocols/protocol.snmp.d.ts +133 -0
  85. package/dist_ts/protocols/protocol.snmp.js +333 -0
  86. package/dist_ts/protocols/protocol.upnp.d.ts +207 -0
  87. package/dist_ts/protocols/protocol.upnp.js +442 -0
  88. package/dist_ts/protocols/protocol.upssnmp.d.ts +160 -0
  89. package/dist_ts/protocols/protocol.upssnmp.js +263 -0
  90. package/npmextra.json +24 -0
  91. package/package.json +39 -0
  92. package/readme.hints.md +115 -0
  93. package/readme.md +624 -0
  94. package/test/test.ts +261 -0
  95. package/ts/00_commitinfo_data.ts +8 -0
  96. package/ts/device/device.classes.device.ts +454 -0
  97. package/ts/devicemanager.classes.devicemanager.ts +1219 -0
  98. package/ts/discovery/discovery.classes.homeassistant.ts +376 -0
  99. package/ts/discovery/discovery.classes.mdns.ts +347 -0
  100. package/ts/discovery/discovery.classes.networkscanner.ts +648 -0
  101. package/ts/discovery/discovery.classes.ssdp.ts +357 -0
  102. package/ts/factories/index.ts +696 -0
  103. package/ts/features/feature.abstract.ts +251 -0
  104. package/ts/features/feature.camera.ts +214 -0
  105. package/ts/features/feature.climate.ts +407 -0
  106. package/ts/features/feature.cover.ts +278 -0
  107. package/ts/features/feature.fan.ts +296 -0
  108. package/ts/features/feature.light.ts +369 -0
  109. package/ts/features/feature.lock.ts +223 -0
  110. package/ts/features/feature.playback.ts +246 -0
  111. package/ts/features/feature.power.ts +231 -0
  112. package/ts/features/feature.print.ts +297 -0
  113. package/ts/features/feature.scan.ts +370 -0
  114. package/ts/features/feature.sensor.ts +202 -0
  115. package/ts/features/feature.snmp.ts +235 -0
  116. package/ts/features/feature.switch.ts +170 -0
  117. package/ts/features/feature.volume.ts +256 -0
  118. package/ts/features/index.ts +25 -0
  119. package/ts/helpers/helpers.iprange.ts +172 -0
  120. package/ts/helpers/helpers.retry.ts +100 -0
  121. package/ts/index.ts +165 -0
  122. package/ts/interfaces/feature.interfaces.ts +359 -0
  123. package/ts/interfaces/homeassistant.interfaces.ts +666 -0
  124. package/ts/interfaces/index.ts +421 -0
  125. package/ts/interfaces/smarthome.interfaces.ts +421 -0
  126. package/ts/paths.ts +5 -0
  127. package/ts/plugins.ts +41 -0
  128. package/ts/protocols/index.ts +59 -0
  129. package/ts/protocols/protocol.escl.ts +439 -0
  130. package/ts/protocols/protocol.homeassistant.ts +737 -0
  131. package/ts/protocols/protocol.ipp.ts +329 -0
  132. package/ts/protocols/protocol.nut.ts +471 -0
  133. package/ts/protocols/protocol.sane.ts +694 -0
  134. package/ts/protocols/protocol.snmp.ts +439 -0
  135. package/ts/protocols/protocol.upnp.ts +627 -0
  136. package/ts/protocols/protocol.upssnmp.ts +377 -0
  137. package/tsconfig.json +12 -0
@@ -0,0 +1,611 @@
1
+ import * as plugins from '../plugins.js';
2
+ /**
3
+ * Home Assistant WebSocket Protocol Handler
4
+ * Connects to HA via WebSocket, handles authentication, state subscriptions, and service calls
5
+ */
6
+ export class HomeAssistantProtocol extends plugins.events.EventEmitter {
7
+ ws = null;
8
+ config;
9
+ messageId = 1;
10
+ pendingRequests = new Map();
11
+ isAuthenticated = false;
12
+ haConfig = null;
13
+ reconnectAttempt = 0;
14
+ reconnectTimer = null;
15
+ stateSubscriptionId = null;
16
+ entityStates = new Map();
17
+ intentionalDisconnect = false;
18
+ constructor(config) {
19
+ super();
20
+ this.config = {
21
+ port: 8123,
22
+ secure: false,
23
+ autoReconnect: true,
24
+ reconnectDelay: 5000,
25
+ ...config,
26
+ };
27
+ }
28
+ /**
29
+ * Get the WebSocket URL for this HA instance
30
+ */
31
+ get wsUrl() {
32
+ const protocol = this.config.secure ? 'wss' : 'ws';
33
+ return `${protocol}://${this.config.host}:${this.config.port}/api/websocket`;
34
+ }
35
+ /**
36
+ * Get connection state
37
+ */
38
+ get isConnected() {
39
+ return this.ws !== null && this.ws.readyState === plugins.WebSocket.OPEN && this.isAuthenticated;
40
+ }
41
+ /**
42
+ * Get HA config if authenticated
43
+ */
44
+ get homeAssistantConfig() {
45
+ return this.haConfig;
46
+ }
47
+ /**
48
+ * Get all cached entity states
49
+ */
50
+ get entities() {
51
+ return this.entityStates;
52
+ }
53
+ /**
54
+ * Connect to Home Assistant
55
+ */
56
+ async connect() {
57
+ if (this.ws && this.ws.readyState === plugins.WebSocket.OPEN) {
58
+ return;
59
+ }
60
+ this.intentionalDisconnect = false;
61
+ return new Promise((resolve, reject) => {
62
+ try {
63
+ this.ws = new plugins.WebSocket(this.wsUrl);
64
+ const connectionTimeout = setTimeout(() => {
65
+ if (this.ws) {
66
+ this.ws.close();
67
+ this.ws = null;
68
+ }
69
+ reject(new Error(`Connection timeout to ${this.wsUrl}`));
70
+ }, 10000);
71
+ this.ws.on('open', () => {
72
+ // Connection established, waiting for auth_required
73
+ });
74
+ this.ws.on('message', async (data) => {
75
+ const message = JSON.parse(data.toString());
76
+ if (message.type === 'auth_required') {
77
+ // Send authentication
78
+ await this.sendAuth();
79
+ }
80
+ else if (message.type === 'auth_ok') {
81
+ clearTimeout(connectionTimeout);
82
+ this.isAuthenticated = true;
83
+ this.reconnectAttempt = 0;
84
+ // Get HA config
85
+ try {
86
+ this.haConfig = await this.getConfig();
87
+ this.emit('authenticated', this.haConfig);
88
+ }
89
+ catch (err) {
90
+ // Non-fatal, continue anyway
91
+ }
92
+ this.emit('connected');
93
+ resolve();
94
+ }
95
+ else if (message.type === 'auth_invalid') {
96
+ clearTimeout(connectionTimeout);
97
+ const authInvalid = message;
98
+ this.emit('auth:failed', authInvalid.message);
99
+ reject(new Error(`Authentication failed: ${authInvalid.message}`));
100
+ }
101
+ else {
102
+ // Handle other messages
103
+ this.handleMessage(message);
104
+ }
105
+ });
106
+ this.ws.on('error', (error) => {
107
+ this.emit('error', error);
108
+ });
109
+ this.ws.on('close', () => {
110
+ this.isAuthenticated = false;
111
+ this.stateSubscriptionId = null;
112
+ // Reject all pending requests
113
+ for (const [id, request] of this.pendingRequests) {
114
+ clearTimeout(request.timeout);
115
+ request.reject(new Error('Connection closed'));
116
+ this.pendingRequests.delete(id);
117
+ }
118
+ this.emit('disconnected');
119
+ // Auto-reconnect if not intentional
120
+ if (this.config.autoReconnect && !this.intentionalDisconnect) {
121
+ this.scheduleReconnect();
122
+ }
123
+ });
124
+ }
125
+ catch (err) {
126
+ reject(err);
127
+ }
128
+ });
129
+ }
130
+ /**
131
+ * Disconnect from Home Assistant
132
+ */
133
+ async disconnect() {
134
+ this.intentionalDisconnect = true;
135
+ if (this.reconnectTimer) {
136
+ clearTimeout(this.reconnectTimer);
137
+ this.reconnectTimer = null;
138
+ }
139
+ if (this.ws) {
140
+ // Clear all pending requests
141
+ for (const [id, request] of this.pendingRequests) {
142
+ clearTimeout(request.timeout);
143
+ request.reject(new Error('Disconnecting'));
144
+ this.pendingRequests.delete(id);
145
+ }
146
+ this.ws.close();
147
+ this.ws = null;
148
+ }
149
+ this.isAuthenticated = false;
150
+ this.stateSubscriptionId = null;
151
+ this.entityStates.clear();
152
+ }
153
+ /**
154
+ * Send authentication message
155
+ */
156
+ async sendAuth() {
157
+ if (!this.ws)
158
+ return;
159
+ const authMessage = {
160
+ type: 'auth',
161
+ access_token: this.config.token,
162
+ };
163
+ this.ws.send(JSON.stringify(authMessage));
164
+ }
165
+ /**
166
+ * Handle incoming messages
167
+ */
168
+ handleMessage(message) {
169
+ if (message.type === 'result') {
170
+ const result = message;
171
+ const pending = this.pendingRequests.get(result.id);
172
+ if (pending) {
173
+ clearTimeout(pending.timeout);
174
+ this.pendingRequests.delete(result.id);
175
+ if (result.success) {
176
+ pending.resolve(result.result);
177
+ }
178
+ else {
179
+ pending.reject(new Error(result.error?.message || 'Unknown error'));
180
+ }
181
+ }
182
+ }
183
+ else if (message.type === 'event') {
184
+ const event = message;
185
+ if (event.event.event_type === 'state_changed') {
186
+ const stateChanged = event.event.data;
187
+ // Update cached state
188
+ if (stateChanged.new_state) {
189
+ this.entityStates.set(stateChanged.entity_id, stateChanged.new_state);
190
+ }
191
+ else {
192
+ this.entityStates.delete(stateChanged.entity_id);
193
+ }
194
+ this.emit('state:changed', stateChanged);
195
+ }
196
+ }
197
+ }
198
+ /**
199
+ * Send a request and wait for response
200
+ */
201
+ async sendRequest(type, data = {}) {
202
+ if (!this.ws || !this.isAuthenticated) {
203
+ throw new Error('Not connected to Home Assistant');
204
+ }
205
+ const id = this.messageId++;
206
+ const message = { id, type, ...data };
207
+ return new Promise((resolve, reject) => {
208
+ const timeout = setTimeout(() => {
209
+ this.pendingRequests.delete(id);
210
+ reject(new Error(`Request timeout: ${type}`));
211
+ }, 30000);
212
+ this.pendingRequests.set(id, {
213
+ resolve: resolve,
214
+ reject,
215
+ timeout,
216
+ });
217
+ this.ws.send(JSON.stringify(message));
218
+ });
219
+ }
220
+ /**
221
+ * Schedule reconnection attempt
222
+ */
223
+ scheduleReconnect() {
224
+ if (this.reconnectTimer)
225
+ return;
226
+ this.reconnectAttempt++;
227
+ const delay = Math.min(this.config.reconnectDelay * Math.pow(1.5, this.reconnectAttempt - 1), 60000 // Max 60 seconds
228
+ );
229
+ this.emit('reconnecting', this.reconnectAttempt);
230
+ this.reconnectTimer = setTimeout(async () => {
231
+ this.reconnectTimer = null;
232
+ try {
233
+ await this.connect();
234
+ // Re-subscribe to state changes
235
+ if (this.isConnected) {
236
+ await this.subscribeToStateChanges();
237
+ }
238
+ }
239
+ catch {
240
+ // connect() will schedule another reconnect on failure
241
+ }
242
+ }, delay);
243
+ }
244
+ // ==========================================================================
245
+ // Public API - State
246
+ // ==========================================================================
247
+ /**
248
+ * Get HA config
249
+ */
250
+ async getConfig() {
251
+ return this.sendRequest('get_config');
252
+ }
253
+ /**
254
+ * Subscribe to state change events
255
+ */
256
+ async subscribeToStateChanges() {
257
+ const result = await this.sendRequest('subscribe_events', {
258
+ event_type: 'state_changed',
259
+ });
260
+ // Get all current states after subscribing
261
+ const states = await this.getStates();
262
+ for (const entity of states) {
263
+ this.entityStates.set(entity.entity_id, entity);
264
+ }
265
+ this.emit('states:loaded', states);
266
+ this.stateSubscriptionId = this.messageId - 1;
267
+ return this.stateSubscriptionId;
268
+ }
269
+ /**
270
+ * Get all entity states
271
+ */
272
+ async getStates() {
273
+ return this.sendRequest('get_states');
274
+ }
275
+ /**
276
+ * Get a specific entity state
277
+ */
278
+ async getState(entityId) {
279
+ // First check cache
280
+ const cached = this.entityStates.get(entityId);
281
+ if (cached)
282
+ return cached;
283
+ // Otherwise fetch all states and find it
284
+ const states = await this.getStates();
285
+ return states.find((s) => s.entity_id === entityId) || null;
286
+ }
287
+ /**
288
+ * Get entities by domain
289
+ */
290
+ async getEntitiesByDomain(domain) {
291
+ const states = await this.getStates();
292
+ return states.filter((s) => s.entity_id.startsWith(`${domain}.`));
293
+ }
294
+ // ==========================================================================
295
+ // Public API - Service Calls
296
+ // ==========================================================================
297
+ /**
298
+ * Call a Home Assistant service
299
+ */
300
+ async callService(domain, service, target, serviceData) {
301
+ await this.sendRequest('call_service', {
302
+ domain,
303
+ service,
304
+ target,
305
+ service_data: serviceData,
306
+ });
307
+ }
308
+ /**
309
+ * Turn on an entity
310
+ */
311
+ async turnOn(entityId, data) {
312
+ const domain = entityId.split('.')[0];
313
+ await this.callService(domain, 'turn_on', { entity_id: entityId }, data);
314
+ }
315
+ /**
316
+ * Turn off an entity
317
+ */
318
+ async turnOff(entityId) {
319
+ const domain = entityId.split('.')[0];
320
+ await this.callService(domain, 'turn_off', { entity_id: entityId });
321
+ }
322
+ /**
323
+ * Toggle an entity
324
+ */
325
+ async toggle(entityId) {
326
+ const domain = entityId.split('.')[0];
327
+ await this.callService(domain, 'toggle', { entity_id: entityId });
328
+ }
329
+ // ==========================================================================
330
+ // Light Services
331
+ // ==========================================================================
332
+ /**
333
+ * Control a light
334
+ */
335
+ async lightTurnOn(entityId, options) {
336
+ await this.callService('light', 'turn_on', { entity_id: entityId }, options);
337
+ }
338
+ async lightTurnOff(entityId, options) {
339
+ await this.callService('light', 'turn_off', { entity_id: entityId }, options);
340
+ }
341
+ async lightToggle(entityId, options) {
342
+ await this.callService('light', 'toggle', { entity_id: entityId }, options);
343
+ }
344
+ // ==========================================================================
345
+ // Climate Services
346
+ // ==========================================================================
347
+ /**
348
+ * Set HVAC mode
349
+ */
350
+ async climateSetHvacMode(entityId, hvacMode) {
351
+ await this.callService('climate', 'set_hvac_mode', { entity_id: entityId }, { hvac_mode: hvacMode });
352
+ }
353
+ /**
354
+ * Set target temperature
355
+ */
356
+ async climateSetTemperature(entityId, options) {
357
+ await this.callService('climate', 'set_temperature', { entity_id: entityId }, options);
358
+ }
359
+ /**
360
+ * Set fan mode
361
+ */
362
+ async climateSetFanMode(entityId, fanMode) {
363
+ await this.callService('climate', 'set_fan_mode', { entity_id: entityId }, { fan_mode: fanMode });
364
+ }
365
+ /**
366
+ * Set preset mode
367
+ */
368
+ async climateSetPresetMode(entityId, presetMode) {
369
+ await this.callService('climate', 'set_preset_mode', { entity_id: entityId }, { preset_mode: presetMode });
370
+ }
371
+ /**
372
+ * Set swing mode
373
+ */
374
+ async climateSetSwingMode(entityId, swingMode) {
375
+ await this.callService('climate', 'set_swing_mode', { entity_id: entityId }, { swing_mode: swingMode });
376
+ }
377
+ /**
378
+ * Set aux heat
379
+ */
380
+ async climateSetAuxHeat(entityId, auxHeat) {
381
+ await this.callService('climate', 'set_aux_heat', { entity_id: entityId }, { aux_heat: auxHeat });
382
+ }
383
+ // ==========================================================================
384
+ // Cover Services
385
+ // ==========================================================================
386
+ /**
387
+ * Open cover
388
+ */
389
+ async coverOpen(entityId) {
390
+ await this.callService('cover', 'open_cover', { entity_id: entityId });
391
+ }
392
+ /**
393
+ * Close cover
394
+ */
395
+ async coverClose(entityId) {
396
+ await this.callService('cover', 'close_cover', { entity_id: entityId });
397
+ }
398
+ /**
399
+ * Stop cover
400
+ */
401
+ async coverStop(entityId) {
402
+ await this.callService('cover', 'stop_cover', { entity_id: entityId });
403
+ }
404
+ /**
405
+ * Set cover position
406
+ */
407
+ async coverSetPosition(entityId, position) {
408
+ await this.callService('cover', 'set_cover_position', { entity_id: entityId }, { position });
409
+ }
410
+ /**
411
+ * Set cover tilt position
412
+ */
413
+ async coverSetTiltPosition(entityId, tiltPosition) {
414
+ await this.callService('cover', 'set_cover_tilt_position', { entity_id: entityId }, { tilt_position: tiltPosition });
415
+ }
416
+ // ==========================================================================
417
+ // Fan Services
418
+ // ==========================================================================
419
+ /**
420
+ * Turn on fan
421
+ */
422
+ async fanTurnOn(entityId, options) {
423
+ await this.callService('fan', 'turn_on', { entity_id: entityId }, options);
424
+ }
425
+ /**
426
+ * Turn off fan
427
+ */
428
+ async fanTurnOff(entityId) {
429
+ await this.callService('fan', 'turn_off', { entity_id: entityId });
430
+ }
431
+ /**
432
+ * Set fan percentage
433
+ */
434
+ async fanSetPercentage(entityId, percentage) {
435
+ await this.callService('fan', 'set_percentage', { entity_id: entityId }, { percentage });
436
+ }
437
+ /**
438
+ * Set fan preset mode
439
+ */
440
+ async fanSetPresetMode(entityId, presetMode) {
441
+ await this.callService('fan', 'set_preset_mode', { entity_id: entityId }, { preset_mode: presetMode });
442
+ }
443
+ /**
444
+ * Oscillate fan
445
+ */
446
+ async fanOscillate(entityId, oscillating) {
447
+ await this.callService('fan', 'oscillate', { entity_id: entityId }, { oscillating });
448
+ }
449
+ /**
450
+ * Set fan direction
451
+ */
452
+ async fanSetDirection(entityId, direction) {
453
+ await this.callService('fan', 'set_direction', { entity_id: entityId }, { direction });
454
+ }
455
+ // ==========================================================================
456
+ // Lock Services
457
+ // ==========================================================================
458
+ /**
459
+ * Lock
460
+ */
461
+ async lockLock(entityId) {
462
+ await this.callService('lock', 'lock', { entity_id: entityId });
463
+ }
464
+ /**
465
+ * Unlock
466
+ */
467
+ async lockUnlock(entityId) {
468
+ await this.callService('lock', 'unlock', { entity_id: entityId });
469
+ }
470
+ /**
471
+ * Open (if supported)
472
+ */
473
+ async lockOpen(entityId) {
474
+ await this.callService('lock', 'open', { entity_id: entityId });
475
+ }
476
+ // ==========================================================================
477
+ // Switch Services
478
+ // ==========================================================================
479
+ /**
480
+ * Turn on switch
481
+ */
482
+ async switchTurnOn(entityId) {
483
+ await this.callService('switch', 'turn_on', { entity_id: entityId });
484
+ }
485
+ /**
486
+ * Turn off switch
487
+ */
488
+ async switchTurnOff(entityId) {
489
+ await this.callService('switch', 'turn_off', { entity_id: entityId });
490
+ }
491
+ /**
492
+ * Toggle switch
493
+ */
494
+ async switchToggle(entityId) {
495
+ await this.callService('switch', 'toggle', { entity_id: entityId });
496
+ }
497
+ // ==========================================================================
498
+ // Media Player Services
499
+ // ==========================================================================
500
+ /**
501
+ * Play media
502
+ */
503
+ async mediaPlayerPlay(entityId) {
504
+ await this.callService('media_player', 'media_play', { entity_id: entityId });
505
+ }
506
+ /**
507
+ * Pause media
508
+ */
509
+ async mediaPlayerPause(entityId) {
510
+ await this.callService('media_player', 'media_pause', { entity_id: entityId });
511
+ }
512
+ /**
513
+ * Stop media
514
+ */
515
+ async mediaPlayerStop(entityId) {
516
+ await this.callService('media_player', 'media_stop', { entity_id: entityId });
517
+ }
518
+ /**
519
+ * Next track
520
+ */
521
+ async mediaPlayerNext(entityId) {
522
+ await this.callService('media_player', 'media_next_track', { entity_id: entityId });
523
+ }
524
+ /**
525
+ * Previous track
526
+ */
527
+ async mediaPlayerPrevious(entityId) {
528
+ await this.callService('media_player', 'media_previous_track', { entity_id: entityId });
529
+ }
530
+ /**
531
+ * Set volume
532
+ */
533
+ async mediaPlayerSetVolume(entityId, volumeLevel) {
534
+ await this.callService('media_player', 'volume_set', { entity_id: entityId }, { volume_level: volumeLevel });
535
+ }
536
+ /**
537
+ * Mute/unmute
538
+ */
539
+ async mediaPlayerMute(entityId, isMuted) {
540
+ await this.callService('media_player', 'volume_mute', { entity_id: entityId }, { is_volume_muted: isMuted });
541
+ }
542
+ /**
543
+ * Seek to position
544
+ */
545
+ async mediaPlayerSeek(entityId, position) {
546
+ await this.callService('media_player', 'media_seek', { entity_id: entityId }, { seek_position: position });
547
+ }
548
+ /**
549
+ * Select source
550
+ */
551
+ async mediaPlayerSelectSource(entityId, source) {
552
+ await this.callService('media_player', 'select_source', { entity_id: entityId }, { source });
553
+ }
554
+ // ==========================================================================
555
+ // Camera Services
556
+ // ==========================================================================
557
+ /**
558
+ * Get camera snapshot URL
559
+ */
560
+ getCameraSnapshotUrl(entityId) {
561
+ const protocol = this.config.secure ? 'https' : 'http';
562
+ const entity = this.entityStates.get(entityId);
563
+ const accessToken = entity?.attributes?.access_token || '';
564
+ return `${protocol}://${this.config.host}:${this.config.port}/api/camera_proxy/${entityId}?token=${accessToken}`;
565
+ }
566
+ /**
567
+ * Get camera stream URL
568
+ */
569
+ getCameraStreamUrl(entityId) {
570
+ const protocol = this.config.secure ? 'https' : 'http';
571
+ return `${protocol}://${this.config.host}:${this.config.port}/api/camera_proxy_stream/${entityId}`;
572
+ }
573
+ // ==========================================================================
574
+ // Static Helpers
575
+ // ==========================================================================
576
+ /**
577
+ * Probe if a Home Assistant instance is reachable
578
+ */
579
+ static async probe(host, port = 8123, secure = false, timeout = 5000) {
580
+ return new Promise((resolve) => {
581
+ const protocol = secure ? 'wss' : 'ws';
582
+ const url = `${protocol}://${host}:${port}/api/websocket`;
583
+ try {
584
+ const ws = new plugins.WebSocket(url);
585
+ const timer = setTimeout(() => {
586
+ ws.close();
587
+ resolve(false);
588
+ }, timeout);
589
+ ws.on('open', () => {
590
+ // Wait for auth_required message
591
+ });
592
+ ws.on('message', (data) => {
593
+ const message = JSON.parse(data.toString());
594
+ if (message.type === 'auth_required') {
595
+ clearTimeout(timer);
596
+ ws.close();
597
+ resolve(true);
598
+ }
599
+ });
600
+ ws.on('error', () => {
601
+ clearTimeout(timer);
602
+ resolve(false);
603
+ });
604
+ }
605
+ catch {
606
+ resolve(false);
607
+ }
608
+ });
609
+ }
610
+ }
611
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdG9jb2wuaG9tZWFzc2lzdGFudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3Byb3RvY29scy9wcm90b2NvbC5ob21lYXNzaXN0YW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBb0J6Qzs7O0dBR0c7QUFDSCxNQUFNLE9BQU8scUJBQXNCLFNBQVEsT0FBTyxDQUFDLE1BQU0sQ0FBQyxZQUFZO0lBQzVELEVBQUUsR0FBa0QsSUFBSSxDQUFDO0lBQ3pELE1BQU0sQ0FBK0I7SUFDckMsU0FBUyxHQUFXLENBQUMsQ0FBQztJQUN0QixlQUFlLEdBSWxCLElBQUksR0FBRyxFQUFFLENBQUM7SUFDUCxlQUFlLEdBQVksS0FBSyxDQUFDO0lBQ2pDLFFBQVEsR0FBZ0MsSUFBSSxDQUFDO0lBQzdDLGdCQUFnQixHQUFXLENBQUMsQ0FBQztJQUM3QixjQUFjLEdBQXlDLElBQUksQ0FBQztJQUM1RCxtQkFBbUIsR0FBa0IsSUFBSSxDQUFDO0lBQzFDLFlBQVksR0FBc0MsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUM1RCxxQkFBcUIsR0FBWSxLQUFLLENBQUM7SUFFL0MsWUFBWSxNQUFvQztRQUM5QyxLQUFLLEVBQUUsQ0FBQztRQUNSLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixJQUFJLEVBQUUsSUFBSTtZQUNWLE1BQU0sRUFBRSxLQUFLO1lBQ2IsYUFBYSxFQUFFLElBQUk7WUFDbkIsY0FBYyxFQUFFLElBQUk7WUFDcEIsR0FBRyxNQUFNO1NBQ1YsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILElBQVksS0FBSztRQUNmLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNuRCxPQUFPLEdBQUcsUUFBUSxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsSUFB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