@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.
- package/.gitea/workflows/default_nottags.yaml +66 -0
- package/.gitea/workflows/default_tags.yaml +124 -0
- package/.vscode/launch.json +11 -0
- package/.vscode/settings.json +26 -0
- package/changelog.md +91 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/device/device.classes.device.d.ts +205 -0
- package/dist_ts/device/device.classes.device.js +344 -0
- package/dist_ts/devicemanager.classes.devicemanager.d.ts +210 -0
- package/dist_ts/devicemanager.classes.devicemanager.js +835 -0
- package/dist_ts/discovery/discovery.classes.homeassistant.d.ts +101 -0
- package/dist_ts/discovery/discovery.classes.homeassistant.js +313 -0
- package/dist_ts/discovery/discovery.classes.mdns.d.ts +90 -0
- package/dist_ts/discovery/discovery.classes.mdns.js +291 -0
- package/dist_ts/discovery/discovery.classes.networkscanner.d.ts +64 -0
- package/dist_ts/discovery/discovery.classes.networkscanner.js +535 -0
- package/dist_ts/discovery/discovery.classes.ssdp.d.ts +112 -0
- package/dist_ts/discovery/discovery.classes.ssdp.js +255 -0
- package/dist_ts/factories/index.d.ts +190 -0
- package/dist_ts/factories/index.js +350 -0
- package/dist_ts/features/feature.abstract.d.ts +118 -0
- package/dist_ts/features/feature.abstract.js +172 -0
- package/dist_ts/features/feature.camera.d.ts +95 -0
- package/dist_ts/features/feature.camera.js +162 -0
- package/dist_ts/features/feature.climate.d.ts +174 -0
- package/dist_ts/features/feature.climate.js +328 -0
- package/dist_ts/features/feature.cover.d.ts +121 -0
- package/dist_ts/features/feature.cover.js +217 -0
- package/dist_ts/features/feature.fan.d.ts +127 -0
- package/dist_ts/features/feature.fan.js +235 -0
- package/dist_ts/features/feature.light.d.ts +156 -0
- package/dist_ts/features/feature.light.js +296 -0
- package/dist_ts/features/feature.lock.d.ts +103 -0
- package/dist_ts/features/feature.lock.js +170 -0
- package/dist_ts/features/feature.playback.d.ts +98 -0
- package/dist_ts/features/feature.playback.js +191 -0
- package/dist_ts/features/feature.power.d.ts +79 -0
- package/dist_ts/features/feature.power.js +173 -0
- package/dist_ts/features/feature.print.d.ts +78 -0
- package/dist_ts/features/feature.print.js +226 -0
- package/dist_ts/features/feature.scan.d.ts +79 -0
- package/dist_ts/features/feature.scan.js +315 -0
- package/dist_ts/features/feature.sensor.d.ts +95 -0
- package/dist_ts/features/feature.sensor.js +147 -0
- package/dist_ts/features/feature.snmp.d.ts +88 -0
- package/dist_ts/features/feature.snmp.js +175 -0
- package/dist_ts/features/feature.switch.d.ts +75 -0
- package/dist_ts/features/feature.switch.js +126 -0
- package/dist_ts/features/feature.volume.d.ts +104 -0
- package/dist_ts/features/feature.volume.js +186 -0
- package/dist_ts/features/index.d.ts +19 -0
- package/dist_ts/features/index.js +23 -0
- package/dist_ts/helpers/helpers.iprange.d.ts +35 -0
- package/dist_ts/helpers/helpers.iprange.js +151 -0
- package/dist_ts/helpers/helpers.retry.d.ts +25 -0
- package/dist_ts/helpers/helpers.retry.js +69 -0
- package/dist_ts/index.d.ts +15 -0
- package/dist_ts/index.js +40 -0
- package/dist_ts/interfaces/feature.interfaces.d.ts +255 -0
- package/dist_ts/interfaces/feature.interfaces.js +6 -0
- package/dist_ts/interfaces/homeassistant.interfaces.d.ts +550 -0
- package/dist_ts/interfaces/homeassistant.interfaces.js +111 -0
- package/dist_ts/interfaces/index.d.ts +330 -0
- package/dist_ts/interfaces/index.js +16 -0
- package/dist_ts/interfaces/smarthome.interfaces.d.ts +282 -0
- package/dist_ts/interfaces/smarthome.interfaces.js +7 -0
- package/dist_ts/paths.d.ts +1 -0
- package/dist_ts/paths.js +3 -0
- package/dist_ts/plugins.d.ts +23 -0
- package/dist_ts/plugins.js +30 -0
- package/dist_ts/protocols/index.d.ts +12 -0
- package/dist_ts/protocols/index.js +21 -0
- package/dist_ts/protocols/protocol.escl.d.ts +58 -0
- package/dist_ts/protocols/protocol.escl.js +364 -0
- package/dist_ts/protocols/protocol.homeassistant.d.ts +248 -0
- package/dist_ts/protocols/protocol.homeassistant.js +611 -0
- package/dist_ts/protocols/protocol.ipp.d.ts +45 -0
- package/dist_ts/protocols/protocol.ipp.js +284 -0
- package/dist_ts/protocols/protocol.nut.d.ts +160 -0
- package/dist_ts/protocols/protocol.nut.js +364 -0
- package/dist_ts/protocols/protocol.sane.d.ts +104 -0
- package/dist_ts/protocols/protocol.sane.js +597 -0
- package/dist_ts/protocols/protocol.snmp.d.ts +133 -0
- package/dist_ts/protocols/protocol.snmp.js +333 -0
- package/dist_ts/protocols/protocol.upnp.d.ts +207 -0
- package/dist_ts/protocols/protocol.upnp.js +442 -0
- package/dist_ts/protocols/protocol.upssnmp.d.ts +160 -0
- package/dist_ts/protocols/protocol.upssnmp.js +263 -0
- package/npmextra.json +24 -0
- package/package.json +39 -0
- package/readme.hints.md +115 -0
- package/readme.md +624 -0
- package/test/test.ts +261 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/device/device.classes.device.ts +454 -0
- package/ts/devicemanager.classes.devicemanager.ts +1219 -0
- package/ts/discovery/discovery.classes.homeassistant.ts +376 -0
- package/ts/discovery/discovery.classes.mdns.ts +347 -0
- package/ts/discovery/discovery.classes.networkscanner.ts +648 -0
- package/ts/discovery/discovery.classes.ssdp.ts +357 -0
- package/ts/factories/index.ts +696 -0
- package/ts/features/feature.abstract.ts +251 -0
- package/ts/features/feature.camera.ts +214 -0
- package/ts/features/feature.climate.ts +407 -0
- package/ts/features/feature.cover.ts +278 -0
- package/ts/features/feature.fan.ts +296 -0
- package/ts/features/feature.light.ts +369 -0
- package/ts/features/feature.lock.ts +223 -0
- package/ts/features/feature.playback.ts +246 -0
- package/ts/features/feature.power.ts +231 -0
- package/ts/features/feature.print.ts +297 -0
- package/ts/features/feature.scan.ts +370 -0
- package/ts/features/feature.sensor.ts +202 -0
- package/ts/features/feature.snmp.ts +235 -0
- package/ts/features/feature.switch.ts +170 -0
- package/ts/features/feature.volume.ts +256 -0
- package/ts/features/index.ts +25 -0
- package/ts/helpers/helpers.iprange.ts +172 -0
- package/ts/helpers/helpers.retry.ts +100 -0
- package/ts/index.ts +165 -0
- package/ts/interfaces/feature.interfaces.ts +359 -0
- package/ts/interfaces/homeassistant.interfaces.ts +666 -0
- package/ts/interfaces/index.ts +421 -0
- package/ts/interfaces/smarthome.interfaces.ts +421 -0
- package/ts/paths.ts +5 -0
- package/ts/plugins.ts +41 -0
- package/ts/protocols/index.ts +59 -0
- package/ts/protocols/protocol.escl.ts +439 -0
- package/ts/protocols/protocol.homeassistant.ts +737 -0
- package/ts/protocols/protocol.ipp.ts +329 -0
- package/ts/protocols/protocol.nut.ts +471 -0
- package/ts/protocols/protocol.sane.ts +694 -0
- package/ts/protocols/protocol.snmp.ts +439 -0
- package/ts/protocols/protocol.upnp.ts +627 -0
- package/ts/protocols/protocol.upssnmp.ts +377 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Device Factory Functions
|
|
3
|
+
* Create UniversalDevice instances with appropriate features
|
|
4
|
+
*/
|
|
5
|
+
import { UniversalDevice } from '../device/device.classes.device.js';
|
|
6
|
+
import { ScanFeature } from '../features/feature.scan.js';
|
|
7
|
+
import { PrintFeature } from '../features/feature.print.js';
|
|
8
|
+
import { PlaybackFeature } from '../features/feature.playback.js';
|
|
9
|
+
import { VolumeFeature } from '../features/feature.volume.js';
|
|
10
|
+
import { PowerFeature } from '../features/feature.power.js';
|
|
11
|
+
import { SnmpFeature } from '../features/feature.snmp.js';
|
|
12
|
+
/**
|
|
13
|
+
* Create a scanner device (UniversalDevice with ScanFeature)
|
|
14
|
+
*/
|
|
15
|
+
export function createScanner(info, retryOptions) {
|
|
16
|
+
const protocol = info.protocol === 'ipp' ? 'escl' : info.protocol;
|
|
17
|
+
const isSecure = info.txtRecords['TLS'] === '1' || (protocol === 'escl' && info.port === 443);
|
|
18
|
+
// Parse capabilities from TXT records
|
|
19
|
+
const formats = parseScanFormats(info.txtRecords);
|
|
20
|
+
const resolutions = parseScanResolutions(info.txtRecords);
|
|
21
|
+
const colorModes = parseScanColorModes(info.txtRecords);
|
|
22
|
+
const sources = parseScanSources(info.txtRecords);
|
|
23
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
24
|
+
name: info.name,
|
|
25
|
+
manufacturer: info.txtRecords['usb_MFG'] || info.txtRecords['mfg'],
|
|
26
|
+
model: info.txtRecords['usb_MDL'] || info.txtRecords['mdl'] || info.txtRecords['ty'],
|
|
27
|
+
retryOptions,
|
|
28
|
+
});
|
|
29
|
+
// Override the generated ID with discovery ID
|
|
30
|
+
device.id = info.id;
|
|
31
|
+
// Add scan feature
|
|
32
|
+
const scanFeature = new ScanFeature(device.getDeviceReference(), info.port, {
|
|
33
|
+
protocol: protocol,
|
|
34
|
+
secure: isSecure,
|
|
35
|
+
supportedFormats: formats,
|
|
36
|
+
supportedResolutions: resolutions,
|
|
37
|
+
supportedColorModes: colorModes,
|
|
38
|
+
supportedSources: sources,
|
|
39
|
+
hasAdf: sources.includes('adf') || sources.includes('adf-duplex'),
|
|
40
|
+
hasDuplex: sources.includes('adf-duplex'),
|
|
41
|
+
});
|
|
42
|
+
device.addFeature(scanFeature);
|
|
43
|
+
return device;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a printer device (UniversalDevice with PrintFeature)
|
|
47
|
+
*/
|
|
48
|
+
export function createPrinter(info, retryOptions) {
|
|
49
|
+
const ippPath = info.txtRecords['rp'] || info.txtRecords['rfo'] || '/ipp/print';
|
|
50
|
+
const uri = `ipp://${info.address}:${info.port}${ippPath.startsWith('/') ? '' : '/'}${ippPath}`;
|
|
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
|
+
// Override the generated ID with discovery ID
|
|
58
|
+
device.id = info.id;
|
|
59
|
+
// Add print feature
|
|
60
|
+
const printFeature = new PrintFeature(device.getDeviceReference(), info.port, {
|
|
61
|
+
protocol: 'ipp',
|
|
62
|
+
uri,
|
|
63
|
+
supportsColor: info.txtRecords['Color'] === 'T' || info.txtRecords['color'] === 'true',
|
|
64
|
+
supportsDuplex: info.txtRecords['Duplex'] === 'T' || info.txtRecords['duplex'] === 'true',
|
|
65
|
+
});
|
|
66
|
+
device.addFeature(printFeature);
|
|
67
|
+
return device;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create an SNMP device (UniversalDevice with SnmpFeature)
|
|
71
|
+
*/
|
|
72
|
+
export function createSnmpDevice(info, retryOptions) {
|
|
73
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
74
|
+
name: info.name,
|
|
75
|
+
retryOptions,
|
|
76
|
+
});
|
|
77
|
+
// Override the generated ID with discovery ID
|
|
78
|
+
device.id = info.id;
|
|
79
|
+
// Add SNMP feature
|
|
80
|
+
const snmpFeature = new SnmpFeature(device.getDeviceReference(), info.port, {
|
|
81
|
+
community: info.community ?? 'public',
|
|
82
|
+
});
|
|
83
|
+
device.addFeature(snmpFeature);
|
|
84
|
+
return device;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Create a UPS device (UniversalDevice with PowerFeature)
|
|
88
|
+
*/
|
|
89
|
+
export function createUpsDevice(info, retryOptions) {
|
|
90
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
91
|
+
name: info.name,
|
|
92
|
+
retryOptions,
|
|
93
|
+
});
|
|
94
|
+
// Override the generated ID with discovery ID
|
|
95
|
+
device.id = info.id;
|
|
96
|
+
// Add power feature
|
|
97
|
+
const powerFeature = new PowerFeature(device.getDeviceReference(), info.port, {
|
|
98
|
+
protocol: info.protocol,
|
|
99
|
+
upsName: info.upsName,
|
|
100
|
+
community: info.community,
|
|
101
|
+
});
|
|
102
|
+
device.addFeature(powerFeature);
|
|
103
|
+
return device;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create a speaker device (UniversalDevice with PlaybackFeature and VolumeFeature)
|
|
107
|
+
*/
|
|
108
|
+
export function createSpeaker(info, retryOptions) {
|
|
109
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
110
|
+
name: info.name,
|
|
111
|
+
model: info.modelName,
|
|
112
|
+
retryOptions,
|
|
113
|
+
});
|
|
114
|
+
// Override the generated ID with discovery ID
|
|
115
|
+
device.id = info.id;
|
|
116
|
+
// Add playback feature
|
|
117
|
+
const playbackFeature = new PlaybackFeature(device.getDeviceReference(), info.port, {
|
|
118
|
+
protocol: info.protocol,
|
|
119
|
+
supportsQueue: info.protocol === 'sonos',
|
|
120
|
+
supportsSeek: info.protocol !== 'airplay',
|
|
121
|
+
});
|
|
122
|
+
device.addFeature(playbackFeature);
|
|
123
|
+
// Add volume feature
|
|
124
|
+
const volumeFeature = new VolumeFeature(device.getDeviceReference(), info.port, {
|
|
125
|
+
volumeProtocol: info.protocol,
|
|
126
|
+
minVolume: 0,
|
|
127
|
+
maxVolume: 100,
|
|
128
|
+
supportsMute: true,
|
|
129
|
+
});
|
|
130
|
+
device.addFeature(volumeFeature);
|
|
131
|
+
return device;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Create a DLNA renderer device (UniversalDevice with PlaybackFeature)
|
|
135
|
+
*/
|
|
136
|
+
export function createDlnaRenderer(info, retryOptions) {
|
|
137
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
138
|
+
name: info.friendlyName || info.name,
|
|
139
|
+
manufacturer: info.manufacturer,
|
|
140
|
+
model: info.modelName,
|
|
141
|
+
retryOptions,
|
|
142
|
+
});
|
|
143
|
+
// Override the generated ID with discovery ID
|
|
144
|
+
device.id = info.id;
|
|
145
|
+
// Add playback feature for DLNA
|
|
146
|
+
const playbackFeature = new PlaybackFeature(device.getDeviceReference(), info.port, {
|
|
147
|
+
protocol: 'dlna',
|
|
148
|
+
supportsQueue: false,
|
|
149
|
+
supportsSeek: true,
|
|
150
|
+
});
|
|
151
|
+
device.addFeature(playbackFeature);
|
|
152
|
+
// Add volume feature
|
|
153
|
+
const volumeFeature = new VolumeFeature(device.getDeviceReference(), info.port, {
|
|
154
|
+
volumeProtocol: 'dlna',
|
|
155
|
+
minVolume: 0,
|
|
156
|
+
maxVolume: 100,
|
|
157
|
+
supportsMute: true,
|
|
158
|
+
});
|
|
159
|
+
device.addFeature(volumeFeature);
|
|
160
|
+
return device;
|
|
161
|
+
}
|
|
162
|
+
// ============================================================================
|
|
163
|
+
// Parsing Helpers
|
|
164
|
+
// ============================================================================
|
|
165
|
+
function parseScanFormats(txtRecords) {
|
|
166
|
+
const formats = [];
|
|
167
|
+
const pdl = txtRecords['pdl'] || txtRecords['DocumentFormat'] || '';
|
|
168
|
+
if (pdl.includes('jpeg') || pdl.includes('jpg'))
|
|
169
|
+
formats.push('jpeg');
|
|
170
|
+
if (pdl.includes('png'))
|
|
171
|
+
formats.push('png');
|
|
172
|
+
if (pdl.includes('pdf'))
|
|
173
|
+
formats.push('pdf');
|
|
174
|
+
if (pdl.includes('tiff'))
|
|
175
|
+
formats.push('tiff');
|
|
176
|
+
return formats.length > 0 ? formats : ['jpeg', 'png'];
|
|
177
|
+
}
|
|
178
|
+
function parseScanResolutions(txtRecords) {
|
|
179
|
+
const rs = txtRecords['rs'] || '';
|
|
180
|
+
const parts = rs.split(',').map((s) => parseInt(s.trim())).filter((n) => !isNaN(n) && n > 0);
|
|
181
|
+
return parts.length > 0 ? parts : [75, 150, 300, 600];
|
|
182
|
+
}
|
|
183
|
+
function parseScanColorModes(txtRecords) {
|
|
184
|
+
const cs = txtRecords['cs'] || txtRecords['ColorSpace'] || '';
|
|
185
|
+
const modes = [];
|
|
186
|
+
if (cs.includes('color') || cs.includes('RGB'))
|
|
187
|
+
modes.push('color');
|
|
188
|
+
if (cs.includes('gray') || cs.includes('grayscale'))
|
|
189
|
+
modes.push('grayscale');
|
|
190
|
+
if (cs.includes('binary') || cs.includes('bw'))
|
|
191
|
+
modes.push('blackwhite');
|
|
192
|
+
return modes.length > 0 ? modes : ['color', 'grayscale'];
|
|
193
|
+
}
|
|
194
|
+
function parseScanSources(txtRecords) {
|
|
195
|
+
const is = txtRecords['is'] || txtRecords['InputSource'] || '';
|
|
196
|
+
const sources = [];
|
|
197
|
+
if (is.includes('platen') || is.includes('flatbed') || is === '') {
|
|
198
|
+
sources.push('flatbed');
|
|
199
|
+
}
|
|
200
|
+
if (is.includes('adf') || is.includes('feeder')) {
|
|
201
|
+
sources.push('adf');
|
|
202
|
+
}
|
|
203
|
+
if (is.includes('duplex')) {
|
|
204
|
+
sources.push('adf-duplex');
|
|
205
|
+
}
|
|
206
|
+
return sources.length > 0 ? sources : ['flatbed'];
|
|
207
|
+
}
|
|
208
|
+
// ============================================================================
|
|
209
|
+
// Smart Home Factories
|
|
210
|
+
// ============================================================================
|
|
211
|
+
import { SwitchFeature } from '../features/feature.switch.js';
|
|
212
|
+
import { SensorFeature } from '../features/feature.sensor.js';
|
|
213
|
+
import { LightFeature } from '../features/feature.light.js';
|
|
214
|
+
import { CoverFeature } from '../features/feature.cover.js';
|
|
215
|
+
import { LockFeature } from '../features/feature.lock.js';
|
|
216
|
+
import { FanFeature } from '../features/feature.fan.js';
|
|
217
|
+
import { ClimateFeature } from '../features/feature.climate.js';
|
|
218
|
+
import { CameraFeature } from '../features/feature.camera.js';
|
|
219
|
+
export function createSmartSwitch(info, retryOptions) {
|
|
220
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
221
|
+
name: info.name,
|
|
222
|
+
retryOptions,
|
|
223
|
+
});
|
|
224
|
+
device.id = info.id;
|
|
225
|
+
const switchFeature = new SwitchFeature(device.getDeviceReference(), info.port, {
|
|
226
|
+
protocol: info.protocol,
|
|
227
|
+
entityId: info.entityId,
|
|
228
|
+
protocolClient: info.protocolClient,
|
|
229
|
+
deviceClass: info.deviceClass,
|
|
230
|
+
});
|
|
231
|
+
device.addFeature(switchFeature);
|
|
232
|
+
return device;
|
|
233
|
+
}
|
|
234
|
+
export function createSmartSensor(info, retryOptions) {
|
|
235
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
236
|
+
name: info.name,
|
|
237
|
+
retryOptions,
|
|
238
|
+
});
|
|
239
|
+
device.id = info.id;
|
|
240
|
+
const sensorFeature = new SensorFeature(device.getDeviceReference(), info.port, {
|
|
241
|
+
protocol: info.protocol,
|
|
242
|
+
entityId: info.entityId,
|
|
243
|
+
protocolClient: info.protocolClient,
|
|
244
|
+
deviceClass: info.deviceClass,
|
|
245
|
+
stateClass: info.stateClass,
|
|
246
|
+
unit: info.unit,
|
|
247
|
+
});
|
|
248
|
+
device.addFeature(sensorFeature);
|
|
249
|
+
return device;
|
|
250
|
+
}
|
|
251
|
+
export function createSmartLight(info, retryOptions) {
|
|
252
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
253
|
+
name: info.name,
|
|
254
|
+
retryOptions,
|
|
255
|
+
});
|
|
256
|
+
device.id = info.id;
|
|
257
|
+
const lightFeature = new LightFeature(device.getDeviceReference(), info.port, {
|
|
258
|
+
protocol: info.protocol,
|
|
259
|
+
entityId: info.entityId,
|
|
260
|
+
protocolClient: info.protocolClient,
|
|
261
|
+
capabilities: info.capabilities,
|
|
262
|
+
});
|
|
263
|
+
device.addFeature(lightFeature);
|
|
264
|
+
return device;
|
|
265
|
+
}
|
|
266
|
+
export function createSmartCover(info, retryOptions) {
|
|
267
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
268
|
+
name: info.name,
|
|
269
|
+
retryOptions,
|
|
270
|
+
});
|
|
271
|
+
device.id = info.id;
|
|
272
|
+
const coverFeature = new CoverFeature(device.getDeviceReference(), info.port, {
|
|
273
|
+
protocol: info.protocol,
|
|
274
|
+
entityId: info.entityId,
|
|
275
|
+
protocolClient: info.protocolClient,
|
|
276
|
+
deviceClass: info.deviceClass,
|
|
277
|
+
capabilities: info.capabilities,
|
|
278
|
+
});
|
|
279
|
+
device.addFeature(coverFeature);
|
|
280
|
+
return device;
|
|
281
|
+
}
|
|
282
|
+
export function createSmartLock(info, retryOptions) {
|
|
283
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
284
|
+
name: info.name,
|
|
285
|
+
retryOptions,
|
|
286
|
+
});
|
|
287
|
+
device.id = info.id;
|
|
288
|
+
const lockFeature = new LockFeature(device.getDeviceReference(), info.port, {
|
|
289
|
+
protocol: info.protocol,
|
|
290
|
+
entityId: info.entityId,
|
|
291
|
+
protocolClient: info.protocolClient,
|
|
292
|
+
supportsOpen: info.supportsOpen,
|
|
293
|
+
});
|
|
294
|
+
device.addFeature(lockFeature);
|
|
295
|
+
return device;
|
|
296
|
+
}
|
|
297
|
+
export function createSmartFan(info, retryOptions) {
|
|
298
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
299
|
+
name: info.name,
|
|
300
|
+
retryOptions,
|
|
301
|
+
});
|
|
302
|
+
device.id = info.id;
|
|
303
|
+
const fanFeature = new FanFeature(device.getDeviceReference(), info.port, {
|
|
304
|
+
protocol: info.protocol,
|
|
305
|
+
entityId: info.entityId,
|
|
306
|
+
protocolClient: info.protocolClient,
|
|
307
|
+
capabilities: info.capabilities,
|
|
308
|
+
});
|
|
309
|
+
device.addFeature(fanFeature);
|
|
310
|
+
return device;
|
|
311
|
+
}
|
|
312
|
+
export function createSmartClimate(info, retryOptions) {
|
|
313
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
314
|
+
name: info.name,
|
|
315
|
+
retryOptions,
|
|
316
|
+
});
|
|
317
|
+
device.id = info.id;
|
|
318
|
+
const climateFeature = new ClimateFeature(device.getDeviceReference(), info.port, {
|
|
319
|
+
protocol: info.protocol,
|
|
320
|
+
entityId: info.entityId,
|
|
321
|
+
protocolClient: info.protocolClient,
|
|
322
|
+
capabilities: info.capabilities,
|
|
323
|
+
});
|
|
324
|
+
device.addFeature(climateFeature);
|
|
325
|
+
return device;
|
|
326
|
+
}
|
|
327
|
+
export function createSmartCamera(info, retryOptions) {
|
|
328
|
+
const device = new UniversalDevice(info.address, info.port, {
|
|
329
|
+
name: info.name,
|
|
330
|
+
retryOptions,
|
|
331
|
+
});
|
|
332
|
+
device.id = info.id;
|
|
333
|
+
const cameraFeature = new CameraFeature(device.getDeviceReference(), info.port, {
|
|
334
|
+
protocol: info.protocol,
|
|
335
|
+
entityId: info.entityId,
|
|
336
|
+
protocolClient: info.protocolClient,
|
|
337
|
+
capabilities: info.capabilities,
|
|
338
|
+
});
|
|
339
|
+
device.addFeature(cameraFeature);
|
|
340
|
+
return device;
|
|
341
|
+
}
|
|
342
|
+
// ============================================================================
|
|
343
|
+
// Exports
|
|
344
|
+
// ============================================================================
|
|
345
|
+
export {
|
|
346
|
+
// Re-export device and feature types for convenience
|
|
347
|
+
UniversalDevice, ScanFeature, PrintFeature, PlaybackFeature, VolumeFeature, PowerFeature, SnmpFeature,
|
|
348
|
+
// Smart home features
|
|
349
|
+
SwitchFeature, SensorFeature, LightFeature, CoverFeature, LockFeature, FanFeature, ClimateFeature, CameraFeature, };
|
|
350
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9mYWN0b3JpZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxFQUFFLGVBQWUsRUFBNkIsTUFBTSxvQ0FBb0MsQ0FBQztBQUNoRyxPQUFPLEVBQUUsV0FBVyxFQUE0QixNQUFNLDZCQUE2QixDQUFDO0FBQ3BGLE9BQU8sRUFBRSxZQUFZLEVBQTZCLE1BQU0sOEJBQThCLENBQUM7QUFDdkYsT0FBTyxFQUFFLGVBQWUsRUFBZ0MsTUFBTSxpQ0FBaUMsQ0FBQztBQUNoRyxPQUFPLEVBQUUsYUFBYSxFQUE4QixNQUFNLCtCQUErQixDQUFDO0FBQzFGLE9BQU8sRUFBRSxZQUFZLEVBQTZCLE1BQU0sOEJBQThCLENBQUM7QUFDdkYsT0FBTyxFQUFFLFdBQVcsRUFBNEIsTUFBTSw2QkFBNkIsQ0FBQztBQXVCcEY7O0dBRUc7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUMzQixJQUEyQixFQUMzQixZQUE0QjtJQUU1QixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ2xFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxLQUFLLE1BQU0sSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBRTlGLHNDQUFzQztJQUN0QyxNQUFNLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDbEQsTUFBTSxXQUFXLEdBQUcsb0JBQW9CLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzFELE1BQU0sVUFBVSxHQUFHLG1CQUFtQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FB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
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract Feature base class
|
|
3
|
+
* Features are composable capabilities that can be attached to devices
|
|
4
|
+
*/
|
|
5
|
+
import * as plugins from '../plugins.js';
|
|
6
|
+
import type { TFeatureType, TFeatureState, IFeature, IFeatureInfo, IFeatureOptions } from '../interfaces/feature.interfaces.js';
|
|
7
|
+
import type { IRetryOptions } from '../interfaces/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* Forward reference to Device to avoid circular dependency
|
|
10
|
+
* The actual Device class will set this reference
|
|
11
|
+
*/
|
|
12
|
+
export type TDeviceReference = {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
address: string;
|
|
16
|
+
port: number;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Abstract base class for all features
|
|
20
|
+
* Provides common functionality for connection management, state tracking, and retry logic
|
|
21
|
+
*/
|
|
22
|
+
export declare abstract class Feature extends plugins.events.EventEmitter implements IFeature {
|
|
23
|
+
/**
|
|
24
|
+
* The feature type identifier
|
|
25
|
+
*/
|
|
26
|
+
abstract readonly type: TFeatureType;
|
|
27
|
+
/**
|
|
28
|
+
* The protocol used by this feature
|
|
29
|
+
*/
|
|
30
|
+
abstract readonly protocol: string;
|
|
31
|
+
/**
|
|
32
|
+
* The port used by this feature
|
|
33
|
+
*/
|
|
34
|
+
protected _port: number;
|
|
35
|
+
/**
|
|
36
|
+
* Current feature state
|
|
37
|
+
*/
|
|
38
|
+
protected _state: TFeatureState;
|
|
39
|
+
/**
|
|
40
|
+
* Last error encountered
|
|
41
|
+
*/
|
|
42
|
+
protected _lastError?: Error;
|
|
43
|
+
/**
|
|
44
|
+
* Reference to the parent device
|
|
45
|
+
*/
|
|
46
|
+
protected _device: TDeviceReference;
|
|
47
|
+
/**
|
|
48
|
+
* Retry configuration
|
|
49
|
+
*/
|
|
50
|
+
protected _retryConfig: Required<IRetryOptions>;
|
|
51
|
+
/**
|
|
52
|
+
* Additional metadata from discovery
|
|
53
|
+
*/
|
|
54
|
+
protected _metadata: Record<string, unknown>;
|
|
55
|
+
constructor(device: TDeviceReference, port: number, options?: IFeatureOptions);
|
|
56
|
+
/**
|
|
57
|
+
* Get the feature port
|
|
58
|
+
*/
|
|
59
|
+
get port(): number;
|
|
60
|
+
/**
|
|
61
|
+
* Get the current feature state
|
|
62
|
+
*/
|
|
63
|
+
get state(): TFeatureState;
|
|
64
|
+
/**
|
|
65
|
+
* Check if the feature is connected
|
|
66
|
+
*/
|
|
67
|
+
get isConnected(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Get the last error
|
|
70
|
+
*/
|
|
71
|
+
get lastError(): Error | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Get the device address
|
|
74
|
+
*/
|
|
75
|
+
get address(): string;
|
|
76
|
+
/**
|
|
77
|
+
* Get the device ID
|
|
78
|
+
*/
|
|
79
|
+
get deviceId(): string;
|
|
80
|
+
/**
|
|
81
|
+
* Connect to the feature endpoint
|
|
82
|
+
*/
|
|
83
|
+
connect(): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Disconnect from the feature endpoint
|
|
86
|
+
*/
|
|
87
|
+
disconnect(): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Perform the actual connection logic
|
|
90
|
+
* Implemented by each feature subclass
|
|
91
|
+
*/
|
|
92
|
+
protected abstract doConnect(): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Perform the actual disconnection logic
|
|
95
|
+
* Implemented by each feature subclass
|
|
96
|
+
*/
|
|
97
|
+
protected abstract doDisconnect(): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Get feature-specific info for serialization
|
|
100
|
+
*/
|
|
101
|
+
abstract getFeatureInfo(): IFeatureInfo;
|
|
102
|
+
/**
|
|
103
|
+
* Set the feature state and emit change event
|
|
104
|
+
*/
|
|
105
|
+
protected setState(state: TFeatureState): void;
|
|
106
|
+
/**
|
|
107
|
+
* Execute an operation with retry logic
|
|
108
|
+
*/
|
|
109
|
+
protected withRetry<T>(operation: () => Promise<T>): Promise<T>;
|
|
110
|
+
/**
|
|
111
|
+
* Get base feature info
|
|
112
|
+
*/
|
|
113
|
+
protected getBaseFeatureInfo(): IFeatureInfo;
|
|
114
|
+
/**
|
|
115
|
+
* Clear error state
|
|
116
|
+
*/
|
|
117
|
+
clearError(): void;
|
|
118
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract Feature base class
|
|
3
|
+
* Features are composable capabilities that can be attached to devices
|
|
4
|
+
*/
|
|
5
|
+
import * as plugins from '../plugins.js';
|
|
6
|
+
import { withRetry } from '../helpers/helpers.retry.js';
|
|
7
|
+
/**
|
|
8
|
+
* Abstract base class for all features
|
|
9
|
+
* Provides common functionality for connection management, state tracking, and retry logic
|
|
10
|
+
*/
|
|
11
|
+
export class Feature extends plugins.events.EventEmitter {
|
|
12
|
+
/**
|
|
13
|
+
* The port used by this feature
|
|
14
|
+
*/
|
|
15
|
+
_port;
|
|
16
|
+
/**
|
|
17
|
+
* Current feature state
|
|
18
|
+
*/
|
|
19
|
+
_state = 'disconnected';
|
|
20
|
+
/**
|
|
21
|
+
* Last error encountered
|
|
22
|
+
*/
|
|
23
|
+
_lastError;
|
|
24
|
+
/**
|
|
25
|
+
* Reference to the parent device
|
|
26
|
+
*/
|
|
27
|
+
_device;
|
|
28
|
+
/**
|
|
29
|
+
* Retry configuration
|
|
30
|
+
*/
|
|
31
|
+
_retryConfig;
|
|
32
|
+
/**
|
|
33
|
+
* Additional metadata from discovery
|
|
34
|
+
*/
|
|
35
|
+
_metadata;
|
|
36
|
+
constructor(device, port, options) {
|
|
37
|
+
super();
|
|
38
|
+
this._device = device;
|
|
39
|
+
this._port = port;
|
|
40
|
+
this._metadata = options?.metadata ?? {};
|
|
41
|
+
// Setup retry config
|
|
42
|
+
const retryOpts = options?.retryOptions ?? {};
|
|
43
|
+
this._retryConfig = {
|
|
44
|
+
maxRetries: retryOpts.maxRetries ?? 3,
|
|
45
|
+
baseDelay: retryOpts.baseDelay ?? 1000,
|
|
46
|
+
maxDelay: retryOpts.maxDelay ?? 30000,
|
|
47
|
+
multiplier: retryOpts.multiplier ?? 2,
|
|
48
|
+
jitter: retryOpts.jitter ?? true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Public Properties
|
|
53
|
+
// ============================================================================
|
|
54
|
+
/**
|
|
55
|
+
* Get the feature port
|
|
56
|
+
*/
|
|
57
|
+
get port() {
|
|
58
|
+
return this._port;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get the current feature state
|
|
62
|
+
*/
|
|
63
|
+
get state() {
|
|
64
|
+
return this._state;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if the feature is connected
|
|
68
|
+
*/
|
|
69
|
+
get isConnected() {
|
|
70
|
+
return this._state === 'connected';
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get the last error
|
|
74
|
+
*/
|
|
75
|
+
get lastError() {
|
|
76
|
+
return this._lastError;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get the device address
|
|
80
|
+
*/
|
|
81
|
+
get address() {
|
|
82
|
+
return this._device.address;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the device ID
|
|
86
|
+
*/
|
|
87
|
+
get deviceId() {
|
|
88
|
+
return this._device.id;
|
|
89
|
+
}
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Connection Management
|
|
92
|
+
// ============================================================================
|
|
93
|
+
/**
|
|
94
|
+
* Connect to the feature endpoint
|
|
95
|
+
*/
|
|
96
|
+
async connect() {
|
|
97
|
+
if (this._state === 'connected') {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (this._state === 'connecting') {
|
|
101
|
+
throw new Error(`Feature ${this.type} is already connecting`);
|
|
102
|
+
}
|
|
103
|
+
this.setState('connecting');
|
|
104
|
+
this._lastError = undefined;
|
|
105
|
+
try {
|
|
106
|
+
await this.withRetry(() => this.doConnect());
|
|
107
|
+
this.setState('connected');
|
|
108
|
+
this.emit('connected');
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
this._lastError = error instanceof Error ? error : new Error(String(error));
|
|
112
|
+
this.setState('error');
|
|
113
|
+
this.emit('error', this._lastError);
|
|
114
|
+
throw this._lastError;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Disconnect from the feature endpoint
|
|
119
|
+
*/
|
|
120
|
+
async disconnect() {
|
|
121
|
+
if (this._state === 'disconnected') {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
await this.doDisconnect();
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
this.setState('disconnected');
|
|
129
|
+
this.emit('disconnected');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// ============================================================================
|
|
133
|
+
// Helper Methods
|
|
134
|
+
// ============================================================================
|
|
135
|
+
/**
|
|
136
|
+
* Set the feature state and emit change event
|
|
137
|
+
*/
|
|
138
|
+
setState(state) {
|
|
139
|
+
if (this._state !== state) {
|
|
140
|
+
const oldState = this._state;
|
|
141
|
+
this._state = state;
|
|
142
|
+
this.emit('state:changed', { oldState, newState: state });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Execute an operation with retry logic
|
|
147
|
+
*/
|
|
148
|
+
async withRetry(operation) {
|
|
149
|
+
return withRetry(operation, this._retryConfig);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get base feature info
|
|
153
|
+
*/
|
|
154
|
+
getBaseFeatureInfo() {
|
|
155
|
+
return {
|
|
156
|
+
type: this.type,
|
|
157
|
+
protocol: this.protocol,
|
|
158
|
+
port: this._port,
|
|
159
|
+
state: this._state,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Clear error state
|
|
164
|
+
*/
|
|
165
|
+
clearError() {
|
|
166
|
+
this._lastError = undefined;
|
|
167
|
+
if (this._state === 'error') {
|
|
168
|
+
this.setState('disconnected');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmVhdHVyZS5hYnN0cmFjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2ZlYXR1cmVzL2ZlYXR1cmUuYWJzdHJhY3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFTekMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBYXhEOzs7R0FHRztBQUNILE1BQU0sT0FBZ0IsT0FBUSxTQUFRLE9BQU8sQ0FBQyxNQUFNLENBQUMsWUFBWTtJQVcvRDs7T0FFRztJQUNPLEtBQUssQ0FBUztJQUV4Qjs7T0FFRztJQUNPLE1BQU0sR0FBa0IsY0FBYyxDQUFDO0lBRWpEOztPQUVHO0lBQ08sVUFBVSxDQUFTO0lBRTdCOztPQUVHO0lBQ08sT0FBTyxDQUFtQjtJQUVwQzs7T0FFRztJQUNPLFlBQVksQ0FBMEI7SUFFaEQ7O09BRUc7SUFDTyxTQUFTLENBQTBCO0lBRTdDLFlBQ0UsTUFBd0IsRUFDeEIsSUFBWSxFQUNaLE9BQXlCO1FBRXpCLEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7UUFDdEIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLEVBQUUsUUFBUSxJQUFJLEVBQUUsQ0FBQztRQUV6QyxxQkFBcUI7UUFDckIsTUFBTSxTQUFTLEdBQUcsT0FBTyxFQUFFLFlBQVksSUFBSSxFQUFFLENBQUM7UUFDOUMsSUFBSSxDQUFDLFlBQVksR0FBRztZQUNsQixVQUFVLEVBQUUsU0FBUyxDQUFDLFVBQVUsSUFBSSxDQUFDO1lBQ3JDLFNBQVMsRUFBRSxTQUFTLENBQUMsU0FBUyxJQUFJLElBQUk7WUFDdEMsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRLElBQUksS0FBSztZQUNyQyxVQUFVLEVBQUUsU0FBUyxDQUFDLFVBQVUsSUFBSSxD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
|