@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,696 @@
1
+ /**
2
+ * Device Factory Functions
3
+ * Create UniversalDevice instances with appropriate features
4
+ */
5
+
6
+ import { UniversalDevice, type IDeviceCreateOptions } from '../device/device.classes.device.js';
7
+ import { ScanFeature, type IScanFeatureOptions } from '../features/feature.scan.js';
8
+ import { PrintFeature, type IPrintFeatureOptions } from '../features/feature.print.js';
9
+ import { PlaybackFeature, type IPlaybackFeatureOptions } from '../features/feature.playback.js';
10
+ import { VolumeFeature, type IVolumeFeatureOptions } from '../features/feature.volume.js';
11
+ import { PowerFeature, type IPowerFeatureOptions } from '../features/feature.power.js';
12
+ import { SnmpFeature, type ISnmpFeatureOptions } from '../features/feature.snmp.js';
13
+ import type {
14
+ TScannerProtocol,
15
+ TScanFormat,
16
+ TColorMode,
17
+ TScanSource,
18
+ IRetryOptions,
19
+ } from '../interfaces/index.js';
20
+ import type { TPrintProtocol } from '../interfaces/feature.interfaces.js';
21
+
22
+ // ============================================================================
23
+ // Scanner Factory
24
+ // ============================================================================
25
+
26
+ export interface IScannerDiscoveryInfo {
27
+ id: string;
28
+ name: string;
29
+ address: string;
30
+ port: number;
31
+ protocol: TScannerProtocol | 'ipp';
32
+ txtRecords: Record<string, string>;
33
+ }
34
+
35
+ /**
36
+ * Create a scanner device (UniversalDevice with ScanFeature)
37
+ */
38
+ export function createScanner(
39
+ info: IScannerDiscoveryInfo,
40
+ retryOptions?: IRetryOptions
41
+ ): UniversalDevice {
42
+ const protocol = info.protocol === 'ipp' ? 'escl' : info.protocol;
43
+ const isSecure = info.txtRecords['TLS'] === '1' || (protocol === 'escl' && info.port === 443);
44
+
45
+ // Parse capabilities from TXT records
46
+ const formats = parseScanFormats(info.txtRecords);
47
+ const resolutions = parseScanResolutions(info.txtRecords);
48
+ const colorModes = parseScanColorModes(info.txtRecords);
49
+ const sources = parseScanSources(info.txtRecords);
50
+
51
+ const device = new UniversalDevice(info.address, info.port, {
52
+ name: info.name,
53
+ manufacturer: info.txtRecords['usb_MFG'] || info.txtRecords['mfg'],
54
+ model: info.txtRecords['usb_MDL'] || info.txtRecords['mdl'] || info.txtRecords['ty'],
55
+ retryOptions,
56
+ });
57
+
58
+ // Override the generated ID with discovery ID
59
+ (device as { id: string }).id = info.id;
60
+
61
+ // Add scan feature
62
+ const scanFeature = new ScanFeature(device.getDeviceReference(), info.port, {
63
+ protocol: protocol as 'escl' | 'sane',
64
+ secure: isSecure,
65
+ supportedFormats: formats,
66
+ supportedResolutions: resolutions,
67
+ supportedColorModes: colorModes,
68
+ supportedSources: sources,
69
+ hasAdf: sources.includes('adf') || sources.includes('adf-duplex'),
70
+ hasDuplex: sources.includes('adf-duplex'),
71
+ });
72
+
73
+ device.addFeature(scanFeature);
74
+ return device;
75
+ }
76
+
77
+ // ============================================================================
78
+ // Printer Factory
79
+ // ============================================================================
80
+
81
+ export interface IPrinterDiscoveryInfo {
82
+ id: string;
83
+ name: string;
84
+ address: string;
85
+ port: number;
86
+ txtRecords: Record<string, string>;
87
+ }
88
+
89
+ /**
90
+ * Create a printer device (UniversalDevice with PrintFeature)
91
+ */
92
+ export function createPrinter(
93
+ info: IPrinterDiscoveryInfo,
94
+ retryOptions?: IRetryOptions
95
+ ): UniversalDevice {
96
+ const ippPath = info.txtRecords['rp'] || info.txtRecords['rfo'] || '/ipp/print';
97
+ const uri = `ipp://${info.address}:${info.port}${ippPath.startsWith('/') ? '' : '/'}${ippPath}`;
98
+
99
+ const device = new UniversalDevice(info.address, info.port, {
100
+ name: info.name,
101
+ manufacturer: info.txtRecords['usb_MFG'] || info.txtRecords['mfg'],
102
+ model: info.txtRecords['usb_MDL'] || info.txtRecords['mdl'] || info.txtRecords['ty'],
103
+ retryOptions,
104
+ });
105
+
106
+ // Override the generated ID with discovery ID
107
+ (device as { id: string }).id = info.id;
108
+
109
+ // Add print feature
110
+ const printFeature = new PrintFeature(device.getDeviceReference(), info.port, {
111
+ protocol: 'ipp',
112
+ uri,
113
+ supportsColor: info.txtRecords['Color'] === 'T' || info.txtRecords['color'] === 'true',
114
+ supportsDuplex: info.txtRecords['Duplex'] === 'T' || info.txtRecords['duplex'] === 'true',
115
+ });
116
+
117
+ device.addFeature(printFeature);
118
+ return device;
119
+ }
120
+
121
+ // ============================================================================
122
+ // SNMP Device Factory
123
+ // ============================================================================
124
+
125
+ export interface ISnmpDiscoveryInfo {
126
+ id: string;
127
+ name: string;
128
+ address: string;
129
+ port: number;
130
+ community?: string;
131
+ }
132
+
133
+ /**
134
+ * Create an SNMP device (UniversalDevice with SnmpFeature)
135
+ */
136
+ export function createSnmpDevice(
137
+ info: ISnmpDiscoveryInfo,
138
+ retryOptions?: IRetryOptions
139
+ ): UniversalDevice {
140
+ const device = new UniversalDevice(info.address, info.port, {
141
+ name: info.name,
142
+ retryOptions,
143
+ });
144
+
145
+ // Override the generated ID with discovery ID
146
+ (device as { id: string }).id = info.id;
147
+
148
+ // Add SNMP feature
149
+ const snmpFeature = new SnmpFeature(device.getDeviceReference(), info.port, {
150
+ community: info.community ?? 'public',
151
+ });
152
+
153
+ device.addFeature(snmpFeature);
154
+ return device;
155
+ }
156
+
157
+ // ============================================================================
158
+ // UPS Device Factory
159
+ // ============================================================================
160
+
161
+ export interface IUpsDiscoveryInfo {
162
+ id: string;
163
+ name: string;
164
+ address: string;
165
+ port: number;
166
+ protocol: 'nut' | 'snmp';
167
+ upsName?: string;
168
+ community?: string;
169
+ }
170
+
171
+ /**
172
+ * Create a UPS device (UniversalDevice with PowerFeature)
173
+ */
174
+ export function createUpsDevice(
175
+ info: IUpsDiscoveryInfo,
176
+ retryOptions?: IRetryOptions
177
+ ): UniversalDevice {
178
+ const device = new UniversalDevice(info.address, info.port, {
179
+ name: info.name,
180
+ retryOptions,
181
+ });
182
+
183
+ // Override the generated ID with discovery ID
184
+ (device as { id: string }).id = info.id;
185
+
186
+ // Add power feature
187
+ const powerFeature = new PowerFeature(device.getDeviceReference(), info.port, {
188
+ protocol: info.protocol,
189
+ upsName: info.upsName,
190
+ community: info.community,
191
+ });
192
+
193
+ device.addFeature(powerFeature);
194
+ return device;
195
+ }
196
+
197
+ // ============================================================================
198
+ // Speaker Factory
199
+ // ============================================================================
200
+
201
+ export interface ISpeakerDiscoveryInfo {
202
+ id: string;
203
+ name: string;
204
+ address: string;
205
+ port: number;
206
+ protocol: 'sonos' | 'airplay' | 'chromecast' | 'dlna';
207
+ roomName?: string;
208
+ modelName?: string;
209
+ features?: number; // AirPlay feature flags
210
+ deviceId?: string;
211
+ friendlyName?: string;
212
+ }
213
+
214
+ /**
215
+ * Create a speaker device (UniversalDevice with PlaybackFeature and VolumeFeature)
216
+ */
217
+ export function createSpeaker(
218
+ info: ISpeakerDiscoveryInfo,
219
+ retryOptions?: IRetryOptions
220
+ ): UniversalDevice {
221
+ const device = new UniversalDevice(info.address, info.port, {
222
+ name: info.name,
223
+ model: info.modelName,
224
+ retryOptions,
225
+ });
226
+
227
+ // Override the generated ID with discovery ID
228
+ (device as { id: string }).id = info.id;
229
+
230
+ // Add playback feature
231
+ const playbackFeature = new PlaybackFeature(device.getDeviceReference(), info.port, {
232
+ protocol: info.protocol,
233
+ supportsQueue: info.protocol === 'sonos',
234
+ supportsSeek: info.protocol !== 'airplay',
235
+ });
236
+
237
+ device.addFeature(playbackFeature);
238
+
239
+ // Add volume feature
240
+ const volumeFeature = new VolumeFeature(device.getDeviceReference(), info.port, {
241
+ volumeProtocol: info.protocol,
242
+ minVolume: 0,
243
+ maxVolume: 100,
244
+ supportsMute: true,
245
+ });
246
+
247
+ device.addFeature(volumeFeature);
248
+
249
+ return device;
250
+ }
251
+
252
+ // ============================================================================
253
+ // DLNA Factory
254
+ // ============================================================================
255
+
256
+ export interface IDlnaRendererDiscoveryInfo {
257
+ id: string;
258
+ name: string;
259
+ address: string;
260
+ port: number;
261
+ controlUrl: string;
262
+ friendlyName: string;
263
+ modelName?: string;
264
+ manufacturer?: string;
265
+ }
266
+
267
+ /**
268
+ * Create a DLNA renderer device (UniversalDevice with PlaybackFeature)
269
+ */
270
+ export function createDlnaRenderer(
271
+ info: IDlnaRendererDiscoveryInfo,
272
+ retryOptions?: IRetryOptions
273
+ ): UniversalDevice {
274
+ const device = new UniversalDevice(info.address, info.port, {
275
+ name: info.friendlyName || info.name,
276
+ manufacturer: info.manufacturer,
277
+ model: info.modelName,
278
+ retryOptions,
279
+ });
280
+
281
+ // Override the generated ID with discovery ID
282
+ (device as { id: string }).id = info.id;
283
+
284
+ // Add playback feature for DLNA
285
+ const playbackFeature = new PlaybackFeature(device.getDeviceReference(), info.port, {
286
+ protocol: 'dlna',
287
+ supportsQueue: false,
288
+ supportsSeek: true,
289
+ });
290
+
291
+ device.addFeature(playbackFeature);
292
+
293
+ // Add volume feature
294
+ const volumeFeature = new VolumeFeature(device.getDeviceReference(), info.port, {
295
+ volumeProtocol: 'dlna',
296
+ minVolume: 0,
297
+ maxVolume: 100,
298
+ supportsMute: true,
299
+ });
300
+
301
+ device.addFeature(volumeFeature);
302
+
303
+ return device;
304
+ }
305
+
306
+ // ============================================================================
307
+ // Parsing Helpers
308
+ // ============================================================================
309
+
310
+ function parseScanFormats(txtRecords: Record<string, string>): TScanFormat[] {
311
+ const formats: TScanFormat[] = [];
312
+ const pdl = txtRecords['pdl'] || txtRecords['DocumentFormat'] || '';
313
+
314
+ if (pdl.includes('jpeg') || pdl.includes('jpg')) formats.push('jpeg');
315
+ if (pdl.includes('png')) formats.push('png');
316
+ if (pdl.includes('pdf')) formats.push('pdf');
317
+ if (pdl.includes('tiff')) formats.push('tiff');
318
+
319
+ return formats.length > 0 ? formats : ['jpeg', 'png'];
320
+ }
321
+
322
+ function parseScanResolutions(txtRecords: Record<string, string>): number[] {
323
+ const rs = txtRecords['rs'] || '';
324
+ const parts = rs.split(',').map((s) => parseInt(s.trim())).filter((n) => !isNaN(n) && n > 0);
325
+ return parts.length > 0 ? parts : [75, 150, 300, 600];
326
+ }
327
+
328
+ function parseScanColorModes(txtRecords: Record<string, string>): TColorMode[] {
329
+ const cs = txtRecords['cs'] || txtRecords['ColorSpace'] || '';
330
+ const modes: TColorMode[] = [];
331
+
332
+ if (cs.includes('color') || cs.includes('RGB')) modes.push('color');
333
+ if (cs.includes('gray') || cs.includes('grayscale')) modes.push('grayscale');
334
+ if (cs.includes('binary') || cs.includes('bw')) modes.push('blackwhite');
335
+
336
+ return modes.length > 0 ? modes : ['color', 'grayscale'];
337
+ }
338
+
339
+ function parseScanSources(txtRecords: Record<string, string>): TScanSource[] {
340
+ const is = txtRecords['is'] || txtRecords['InputSource'] || '';
341
+ const sources: TScanSource[] = [];
342
+
343
+ if (is.includes('platen') || is.includes('flatbed') || is === '') {
344
+ sources.push('flatbed');
345
+ }
346
+ if (is.includes('adf') || is.includes('feeder')) {
347
+ sources.push('adf');
348
+ }
349
+ if (is.includes('duplex')) {
350
+ sources.push('adf-duplex');
351
+ }
352
+
353
+ return sources.length > 0 ? sources : ['flatbed'];
354
+ }
355
+
356
+ // ============================================================================
357
+ // Smart Home Factories
358
+ // ============================================================================
359
+
360
+ import { SwitchFeature, type ISwitchFeatureOptions } from '../features/feature.switch.js';
361
+ import { SensorFeature, type ISensorFeatureOptions } from '../features/feature.sensor.js';
362
+ import { LightFeature, type ILightFeatureOptions } from '../features/feature.light.js';
363
+ import { CoverFeature, type ICoverFeatureOptions } from '../features/feature.cover.js';
364
+ import { LockFeature, type ILockFeatureOptions } from '../features/feature.lock.js';
365
+ import { FanFeature, type IFanFeatureOptions } from '../features/feature.fan.js';
366
+ import { ClimateFeature, type IClimateFeatureOptions } from '../features/feature.climate.js';
367
+ import { CameraFeature, type ICameraFeatureOptions } from '../features/feature.camera.js';
368
+
369
+ import type {
370
+ TSwitchProtocol,
371
+ TSensorProtocol,
372
+ TLightProtocol,
373
+ TCoverProtocol,
374
+ TLockProtocol,
375
+ TFanProtocol,
376
+ TClimateProtocol,
377
+ TCameraProtocol,
378
+ ISwitchProtocolClient,
379
+ ISensorProtocolClient,
380
+ ILightProtocolClient,
381
+ ICoverProtocolClient,
382
+ ILockProtocolClient,
383
+ IFanProtocolClient,
384
+ IClimateProtocolClient,
385
+ ICameraProtocolClient,
386
+ ILightCapabilities,
387
+ ICoverCapabilities,
388
+ IFanCapabilities,
389
+ IClimateCapabilities,
390
+ ICameraCapabilities,
391
+ TSensorDeviceClass,
392
+ TSensorStateClass,
393
+ TCoverDeviceClass,
394
+ } from '../interfaces/smarthome.interfaces.js';
395
+
396
+ // Smart Switch Factory
397
+ export interface ISmartSwitchDiscoveryInfo {
398
+ id: string;
399
+ name: string;
400
+ address: string;
401
+ port: number;
402
+ entityId: string;
403
+ protocol: TSwitchProtocol;
404
+ protocolClient: ISwitchProtocolClient;
405
+ deviceClass?: 'outlet' | 'switch';
406
+ }
407
+
408
+ export function createSmartSwitch(
409
+ info: ISmartSwitchDiscoveryInfo,
410
+ retryOptions?: IRetryOptions
411
+ ): UniversalDevice {
412
+ const device = new UniversalDevice(info.address, info.port, {
413
+ name: info.name,
414
+ retryOptions,
415
+ });
416
+
417
+ (device as { id: string }).id = info.id;
418
+
419
+ const switchFeature = new SwitchFeature(device.getDeviceReference(), info.port, {
420
+ protocol: info.protocol,
421
+ entityId: info.entityId,
422
+ protocolClient: info.protocolClient,
423
+ deviceClass: info.deviceClass,
424
+ });
425
+
426
+ device.addFeature(switchFeature);
427
+ return device;
428
+ }
429
+
430
+ // Smart Sensor Factory
431
+ export interface ISmartSensorDiscoveryInfo {
432
+ id: string;
433
+ name: string;
434
+ address: string;
435
+ port: number;
436
+ entityId: string;
437
+ protocol: TSensorProtocol;
438
+ protocolClient: ISensorProtocolClient;
439
+ deviceClass?: TSensorDeviceClass;
440
+ stateClass?: TSensorStateClass;
441
+ unit?: string;
442
+ }
443
+
444
+ export function createSmartSensor(
445
+ info: ISmartSensorDiscoveryInfo,
446
+ retryOptions?: IRetryOptions
447
+ ): UniversalDevice {
448
+ const device = new UniversalDevice(info.address, info.port, {
449
+ name: info.name,
450
+ retryOptions,
451
+ });
452
+
453
+ (device as { id: string }).id = info.id;
454
+
455
+ const sensorFeature = new SensorFeature(device.getDeviceReference(), info.port, {
456
+ protocol: info.protocol,
457
+ entityId: info.entityId,
458
+ protocolClient: info.protocolClient,
459
+ deviceClass: info.deviceClass,
460
+ stateClass: info.stateClass,
461
+ unit: info.unit,
462
+ });
463
+
464
+ device.addFeature(sensorFeature);
465
+ return device;
466
+ }
467
+
468
+ // Smart Light Factory
469
+ export interface ISmartLightDiscoveryInfo {
470
+ id: string;
471
+ name: string;
472
+ address: string;
473
+ port: number;
474
+ entityId: string;
475
+ protocol: TLightProtocol;
476
+ protocolClient: ILightProtocolClient;
477
+ capabilities?: Partial<ILightCapabilities>;
478
+ }
479
+
480
+ export function createSmartLight(
481
+ info: ISmartLightDiscoveryInfo,
482
+ retryOptions?: IRetryOptions
483
+ ): UniversalDevice {
484
+ const device = new UniversalDevice(info.address, info.port, {
485
+ name: info.name,
486
+ retryOptions,
487
+ });
488
+
489
+ (device as { id: string }).id = info.id;
490
+
491
+ const lightFeature = new LightFeature(device.getDeviceReference(), info.port, {
492
+ protocol: info.protocol,
493
+ entityId: info.entityId,
494
+ protocolClient: info.protocolClient,
495
+ capabilities: info.capabilities,
496
+ });
497
+
498
+ device.addFeature(lightFeature);
499
+ return device;
500
+ }
501
+
502
+ // Smart Cover Factory
503
+ export interface ISmartCoverDiscoveryInfo {
504
+ id: string;
505
+ name: string;
506
+ address: string;
507
+ port: number;
508
+ entityId: string;
509
+ protocol: TCoverProtocol;
510
+ protocolClient: ICoverProtocolClient;
511
+ deviceClass?: TCoverDeviceClass;
512
+ capabilities?: Partial<ICoverCapabilities>;
513
+ }
514
+
515
+ export function createSmartCover(
516
+ info: ISmartCoverDiscoveryInfo,
517
+ retryOptions?: IRetryOptions
518
+ ): UniversalDevice {
519
+ const device = new UniversalDevice(info.address, info.port, {
520
+ name: info.name,
521
+ retryOptions,
522
+ });
523
+
524
+ (device as { id: string }).id = info.id;
525
+
526
+ const coverFeature = new CoverFeature(device.getDeviceReference(), info.port, {
527
+ protocol: info.protocol,
528
+ entityId: info.entityId,
529
+ protocolClient: info.protocolClient,
530
+ deviceClass: info.deviceClass,
531
+ capabilities: info.capabilities,
532
+ });
533
+
534
+ device.addFeature(coverFeature);
535
+ return device;
536
+ }
537
+
538
+ // Smart Lock Factory
539
+ export interface ISmartLockDiscoveryInfo {
540
+ id: string;
541
+ name: string;
542
+ address: string;
543
+ port: number;
544
+ entityId: string;
545
+ protocol: TLockProtocol;
546
+ protocolClient: ILockProtocolClient;
547
+ supportsOpen?: boolean;
548
+ }
549
+
550
+ export function createSmartLock(
551
+ info: ISmartLockDiscoveryInfo,
552
+ retryOptions?: IRetryOptions
553
+ ): UniversalDevice {
554
+ const device = new UniversalDevice(info.address, info.port, {
555
+ name: info.name,
556
+ retryOptions,
557
+ });
558
+
559
+ (device as { id: string }).id = info.id;
560
+
561
+ const lockFeature = new LockFeature(device.getDeviceReference(), info.port, {
562
+ protocol: info.protocol,
563
+ entityId: info.entityId,
564
+ protocolClient: info.protocolClient,
565
+ supportsOpen: info.supportsOpen,
566
+ });
567
+
568
+ device.addFeature(lockFeature);
569
+ return device;
570
+ }
571
+
572
+ // Smart Fan Factory
573
+ export interface ISmartFanDiscoveryInfo {
574
+ id: string;
575
+ name: string;
576
+ address: string;
577
+ port: number;
578
+ entityId: string;
579
+ protocol: TFanProtocol;
580
+ protocolClient: IFanProtocolClient;
581
+ capabilities?: Partial<IFanCapabilities>;
582
+ }
583
+
584
+ export function createSmartFan(
585
+ info: ISmartFanDiscoveryInfo,
586
+ retryOptions?: IRetryOptions
587
+ ): UniversalDevice {
588
+ const device = new UniversalDevice(info.address, info.port, {
589
+ name: info.name,
590
+ retryOptions,
591
+ });
592
+
593
+ (device as { id: string }).id = info.id;
594
+
595
+ const fanFeature = new FanFeature(device.getDeviceReference(), info.port, {
596
+ protocol: info.protocol,
597
+ entityId: info.entityId,
598
+ protocolClient: info.protocolClient,
599
+ capabilities: info.capabilities,
600
+ });
601
+
602
+ device.addFeature(fanFeature);
603
+ return device;
604
+ }
605
+
606
+ // Smart Climate Factory
607
+ export interface ISmartClimateDiscoveryInfo {
608
+ id: string;
609
+ name: string;
610
+ address: string;
611
+ port: number;
612
+ entityId: string;
613
+ protocol: TClimateProtocol;
614
+ protocolClient: IClimateProtocolClient;
615
+ capabilities?: Partial<IClimateCapabilities>;
616
+ }
617
+
618
+ export function createSmartClimate(
619
+ info: ISmartClimateDiscoveryInfo,
620
+ retryOptions?: IRetryOptions
621
+ ): UniversalDevice {
622
+ const device = new UniversalDevice(info.address, info.port, {
623
+ name: info.name,
624
+ retryOptions,
625
+ });
626
+
627
+ (device as { id: string }).id = info.id;
628
+
629
+ const climateFeature = new ClimateFeature(device.getDeviceReference(), info.port, {
630
+ protocol: info.protocol,
631
+ entityId: info.entityId,
632
+ protocolClient: info.protocolClient,
633
+ capabilities: info.capabilities,
634
+ });
635
+
636
+ device.addFeature(climateFeature);
637
+ return device;
638
+ }
639
+
640
+ // Smart Camera Factory
641
+ export interface ISmartCameraDiscoveryInfo {
642
+ id: string;
643
+ name: string;
644
+ address: string;
645
+ port: number;
646
+ entityId: string;
647
+ protocol: TCameraProtocol;
648
+ protocolClient: ICameraProtocolClient;
649
+ capabilities?: Partial<ICameraCapabilities>;
650
+ }
651
+
652
+ export function createSmartCamera(
653
+ info: ISmartCameraDiscoveryInfo,
654
+ retryOptions?: IRetryOptions
655
+ ): UniversalDevice {
656
+ const device = new UniversalDevice(info.address, info.port, {
657
+ name: info.name,
658
+ retryOptions,
659
+ });
660
+
661
+ (device as { id: string }).id = info.id;
662
+
663
+ const cameraFeature = new CameraFeature(device.getDeviceReference(), info.port, {
664
+ protocol: info.protocol,
665
+ entityId: info.entityId,
666
+ protocolClient: info.protocolClient,
667
+ capabilities: info.capabilities,
668
+ });
669
+
670
+ device.addFeature(cameraFeature);
671
+ return device;
672
+ }
673
+
674
+ // ============================================================================
675
+ // Exports
676
+ // ============================================================================
677
+
678
+ export {
679
+ // Re-export device and feature types for convenience
680
+ UniversalDevice,
681
+ ScanFeature,
682
+ PrintFeature,
683
+ PlaybackFeature,
684
+ VolumeFeature,
685
+ PowerFeature,
686
+ SnmpFeature,
687
+ // Smart home features
688
+ SwitchFeature,
689
+ SensorFeature,
690
+ LightFeature,
691
+ CoverFeature,
692
+ LockFeature,
693
+ FanFeature,
694
+ ClimateFeature,
695
+ CameraFeature,
696
+ };