@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,364 @@
1
+ import * as plugins from '../plugins.js';
2
+ /**
3
+ * NUT Protocol variable definitions
4
+ */
5
+ export const NUT_VARIABLES = {
6
+ // Device info
7
+ deviceMfr: 'device.mfr',
8
+ deviceModel: 'device.model',
9
+ deviceSerial: 'device.serial',
10
+ deviceType: 'device.type',
11
+ // UPS status
12
+ upsStatus: 'ups.status',
13
+ upsAlarm: 'ups.alarm',
14
+ upsTime: 'ups.time',
15
+ upsLoad: 'ups.load',
16
+ upsTemperature: 'ups.temperature',
17
+ // Battery
18
+ batteryCharge: 'battery.charge',
19
+ batteryRuntime: 'battery.runtime',
20
+ batteryVoltage: 'battery.voltage',
21
+ batteryVoltageNominal: 'battery.voltage.nominal',
22
+ batteryType: 'battery.type',
23
+ batteryDate: 'battery.date',
24
+ batteryTemperature: 'battery.temperature',
25
+ // Input
26
+ inputVoltage: 'input.voltage',
27
+ inputVoltageNominal: 'input.voltage.nominal',
28
+ inputFrequency: 'input.frequency',
29
+ inputFrequencyNominal: 'input.frequency.nominal',
30
+ inputTransferHigh: 'input.transfer.high',
31
+ inputTransferLow: 'input.transfer.low',
32
+ // Output
33
+ outputVoltage: 'output.voltage',
34
+ outputVoltageNominal: 'output.voltage.nominal',
35
+ outputFrequency: 'output.frequency',
36
+ outputCurrent: 'output.current',
37
+ };
38
+ /**
39
+ * NUT instant commands
40
+ */
41
+ export const NUT_COMMANDS = {
42
+ testBatteryStart: 'test.battery.start',
43
+ testBatteryStartQuick: 'test.battery.start.quick',
44
+ testBatteryStartDeep: 'test.battery.start.deep',
45
+ testBatteryStop: 'test.battery.stop',
46
+ calibrateStart: 'calibrate.start',
47
+ calibrateStop: 'calibrate.stop',
48
+ shutdown: 'shutdown.return',
49
+ shutdownStayOff: 'shutdown.stayoff',
50
+ shutdownStop: 'shutdown.stop',
51
+ shutdownReboot: 'shutdown.reboot',
52
+ beeperEnable: 'beeper.enable',
53
+ beeperDisable: 'beeper.disable',
54
+ beeperMute: 'beeper.mute',
55
+ beeperToggle: 'beeper.toggle',
56
+ loadOff: 'load.off',
57
+ loadOn: 'load.on',
58
+ };
59
+ /**
60
+ * NUT Protocol handler for Network UPS Tools
61
+ * TCP-based text protocol on port 3493
62
+ */
63
+ export class NutProtocol {
64
+ socket = null;
65
+ address;
66
+ port;
67
+ connected = false;
68
+ responseBuffer = '';
69
+ responseResolver = null;
70
+ responseRejecter = null;
71
+ constructor(address, port = 3493) {
72
+ this.address = address;
73
+ this.port = port;
74
+ }
75
+ /**
76
+ * Connect to NUT server
77
+ */
78
+ async connect() {
79
+ if (this.connected) {
80
+ return;
81
+ }
82
+ return new Promise((resolve, reject) => {
83
+ this.socket = new plugins.net.Socket();
84
+ const timeout = setTimeout(() => {
85
+ if (this.socket) {
86
+ this.socket.destroy();
87
+ this.socket = null;
88
+ }
89
+ reject(new Error(`Connection timeout to ${this.address}:${this.port}`));
90
+ }, 5000);
91
+ this.socket.on('connect', () => {
92
+ clearTimeout(timeout);
93
+ this.connected = true;
94
+ resolve();
95
+ });
96
+ this.socket.on('error', (err) => {
97
+ clearTimeout(timeout);
98
+ this.connected = false;
99
+ if (this.responseRejecter) {
100
+ this.responseRejecter(err);
101
+ this.responseRejecter = null;
102
+ this.responseResolver = null;
103
+ }
104
+ reject(err);
105
+ });
106
+ this.socket.on('data', (data) => {
107
+ this.handleData(data);
108
+ });
109
+ this.socket.on('close', () => {
110
+ this.connected = false;
111
+ if (this.responseRejecter) {
112
+ this.responseRejecter(new Error('Connection closed'));
113
+ this.responseRejecter = null;
114
+ this.responseResolver = null;
115
+ }
116
+ });
117
+ this.socket.connect(this.port, this.address);
118
+ });
119
+ }
120
+ /**
121
+ * Disconnect from NUT server
122
+ */
123
+ async disconnect() {
124
+ if (!this.connected || !this.socket) {
125
+ return;
126
+ }
127
+ try {
128
+ await this.sendCommand('LOGOUT');
129
+ }
130
+ catch {
131
+ // Ignore logout errors
132
+ }
133
+ this.socket.destroy();
134
+ this.socket = null;
135
+ this.connected = false;
136
+ }
137
+ /**
138
+ * Check if connected
139
+ */
140
+ get isConnected() {
141
+ return this.connected;
142
+ }
143
+ /**
144
+ * Handle incoming data
145
+ */
146
+ handleData(data) {
147
+ this.responseBuffer += data.toString();
148
+ // Check for complete response (ends with newline)
149
+ const lines = this.responseBuffer.split('\n');
150
+ // Check if we have a complete response
151
+ if (this.responseBuffer.endsWith('\n')) {
152
+ const responseLines = lines.filter((l) => l.trim().length > 0);
153
+ this.responseBuffer = '';
154
+ if (this.responseResolver) {
155
+ this.responseResolver(responseLines);
156
+ this.responseResolver = null;
157
+ this.responseRejecter = null;
158
+ }
159
+ }
160
+ }
161
+ /**
162
+ * Send command and get response
163
+ */
164
+ async sendCommand(command) {
165
+ if (!this.socket || !this.connected) {
166
+ throw new Error('Not connected to NUT server');
167
+ }
168
+ return new Promise((resolve, reject) => {
169
+ this.responseResolver = resolve;
170
+ this.responseRejecter = reject;
171
+ const timeout = setTimeout(() => {
172
+ this.responseResolver = null;
173
+ this.responseRejecter = null;
174
+ reject(new Error(`Command timeout: ${command}`));
175
+ }, 10000);
176
+ this.responseResolver = (lines) => {
177
+ clearTimeout(timeout);
178
+ resolve(lines);
179
+ };
180
+ this.responseRejecter = (err) => {
181
+ clearTimeout(timeout);
182
+ reject(err);
183
+ };
184
+ this.socket.write(`${command}\n`);
185
+ });
186
+ }
187
+ /**
188
+ * List available UPS devices
189
+ */
190
+ async listUps() {
191
+ await this.ensureConnected();
192
+ const response = await this.sendCommand('LIST UPS');
193
+ const upsList = [];
194
+ for (const line of response) {
195
+ // Format: UPS <name> "<description>"
196
+ const match = line.match(/^UPS\s+(\S+)\s+"([^"]*)"/);
197
+ if (match) {
198
+ upsList.push({
199
+ name: match[1],
200
+ description: match[2],
201
+ });
202
+ }
203
+ }
204
+ return upsList;
205
+ }
206
+ /**
207
+ * Get all variables for a UPS
208
+ */
209
+ async listVariables(upsName) {
210
+ await this.ensureConnected();
211
+ const response = await this.sendCommand(`LIST VAR ${upsName}`);
212
+ const variables = [];
213
+ for (const line of response) {
214
+ // Format: VAR <ups> <name> "<value>"
215
+ const match = line.match(/^VAR\s+\S+\s+(\S+)\s+"([^"]*)"/);
216
+ if (match) {
217
+ variables.push({
218
+ name: match[1],
219
+ value: match[2],
220
+ });
221
+ }
222
+ }
223
+ return variables;
224
+ }
225
+ /**
226
+ * Get a specific variable value
227
+ */
228
+ async getVariable(upsName, varName) {
229
+ await this.ensureConnected();
230
+ const response = await this.sendCommand(`GET VAR ${upsName} ${varName}`);
231
+ for (const line of response) {
232
+ // Format: VAR <ups> <name> "<value>"
233
+ const match = line.match(/^VAR\s+\S+\s+\S+\s+"([^"]*)"/);
234
+ if (match) {
235
+ return match[1];
236
+ }
237
+ // Handle error responses
238
+ if (line.startsWith('ERR')) {
239
+ return null;
240
+ }
241
+ }
242
+ return null;
243
+ }
244
+ /**
245
+ * Get multiple variables at once
246
+ */
247
+ async getVariables(upsName, varNames) {
248
+ const results = new Map();
249
+ for (const varName of varNames) {
250
+ const value = await this.getVariable(upsName, varName);
251
+ if (value !== null) {
252
+ results.set(varName, value);
253
+ }
254
+ }
255
+ return results;
256
+ }
257
+ /**
258
+ * Execute an instant command
259
+ */
260
+ async runCommand(upsName, command) {
261
+ await this.ensureConnected();
262
+ const response = await this.sendCommand(`INSTCMD ${upsName} ${command}`);
263
+ for (const line of response) {
264
+ if (line === 'OK') {
265
+ return true;
266
+ }
267
+ if (line.startsWith('ERR')) {
268
+ return false;
269
+ }
270
+ }
271
+ return false;
272
+ }
273
+ /**
274
+ * List available commands for a UPS
275
+ */
276
+ async listCommands(upsName) {
277
+ await this.ensureConnected();
278
+ const response = await this.sendCommand(`LIST CMD ${upsName}`);
279
+ const commands = [];
280
+ for (const line of response) {
281
+ // Format: CMD <ups> <command>
282
+ const match = line.match(/^CMD\s+\S+\s+(\S+)/);
283
+ if (match) {
284
+ commands.push(match[1]);
285
+ }
286
+ }
287
+ return commands;
288
+ }
289
+ /**
290
+ * Parse UPS status string into flags
291
+ */
292
+ parseStatus(statusString) {
293
+ return statusString.split(/\s+/).filter((s) => s.length > 0);
294
+ }
295
+ /**
296
+ * Get comprehensive UPS status
297
+ */
298
+ async getUpsStatus(upsName) {
299
+ const vars = await this.getVariables(upsName, [
300
+ NUT_VARIABLES.upsStatus,
301
+ NUT_VARIABLES.batteryCharge,
302
+ NUT_VARIABLES.batteryRuntime,
303
+ NUT_VARIABLES.inputVoltage,
304
+ NUT_VARIABLES.outputVoltage,
305
+ NUT_VARIABLES.upsLoad,
306
+ ]);
307
+ return {
308
+ status: this.parseStatus(vars.get(NUT_VARIABLES.upsStatus) || ''),
309
+ batteryCharge: parseFloat(vars.get(NUT_VARIABLES.batteryCharge) || '0'),
310
+ batteryRuntime: parseFloat(vars.get(NUT_VARIABLES.batteryRuntime) || '0'),
311
+ inputVoltage: parseFloat(vars.get(NUT_VARIABLES.inputVoltage) || '0'),
312
+ outputVoltage: parseFloat(vars.get(NUT_VARIABLES.outputVoltage) || '0'),
313
+ load: parseFloat(vars.get(NUT_VARIABLES.upsLoad) || '0'),
314
+ };
315
+ }
316
+ /**
317
+ * Get device information
318
+ */
319
+ async getDeviceInfo(upsName) {
320
+ const vars = await this.getVariables(upsName, [
321
+ NUT_VARIABLES.deviceMfr,
322
+ NUT_VARIABLES.deviceModel,
323
+ NUT_VARIABLES.deviceSerial,
324
+ NUT_VARIABLES.deviceType,
325
+ ]);
326
+ return {
327
+ manufacturer: vars.get(NUT_VARIABLES.deviceMfr) || '',
328
+ model: vars.get(NUT_VARIABLES.deviceModel) || '',
329
+ serial: vars.get(NUT_VARIABLES.deviceSerial) || '',
330
+ type: vars.get(NUT_VARIABLES.deviceType) || '',
331
+ };
332
+ }
333
+ /**
334
+ * Ensure connected before command
335
+ */
336
+ async ensureConnected() {
337
+ if (!this.connected) {
338
+ await this.connect();
339
+ }
340
+ }
341
+ /**
342
+ * Check if a NUT server is reachable
343
+ */
344
+ static async probe(address, port = 3493, timeout = 3000) {
345
+ return new Promise((resolve) => {
346
+ const socket = new plugins.net.Socket();
347
+ const timer = setTimeout(() => {
348
+ socket.destroy();
349
+ resolve(false);
350
+ }, timeout);
351
+ socket.on('connect', () => {
352
+ clearTimeout(timer);
353
+ socket.destroy();
354
+ resolve(true);
355
+ });
356
+ socket.on('error', () => {
357
+ clearTimeout(timer);
358
+ resolve(false);
359
+ });
360
+ socket.connect(port, address);
361
+ });
362
+ }
363
+ }
364
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdG9jb2wubnV0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvcHJvdG9jb2xzL3Byb3RvY29sLm51dC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUV6Qzs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRztJQUMzQixjQUFjO0lBQ2QsU0FBUyxFQUFFLFlBQVk7SUFDdkIsV0FBVyxFQUFFLGNBQWM7SUFDM0IsWUFBWSxFQUFFLGVBQWU7SUFDN0IsVUFBVSxFQUFFLGFBQWE7SUFFekIsYUFBYTtJQUNiLFNBQVMsRUFBRSxZQUFZO0lBQ3ZCLFFBQVEsRUFBRSxXQUFXO0lBQ3JCLE9BQU8sRUFBRSxVQUFVO0lBQ25CLE9BQU8sRUFBRSxVQUFVO0lBQ25CLGNBQWMsRUFBRSxpQkFBaUI7SUFFakMsVUFBVTtJQUNWLGFBQWEsRUFBRSxnQkFBZ0I7SUFDL0IsY0FBYyxFQUFFLGlCQUFpQjtJQUNqQyxjQUFjLEVBQUUsaUJBQWlCO0lBQ2pDLHFCQUFxQixFQUFFLHlCQUF5QjtJQUNoRCxXQUFXLEVBQUUsY0FBYztJQUMzQixXQUFXLEVBQUUsY0FBYztJQUMzQixrQkFBa0IsRUFBRSxxQkFBcUI7SUFFekMsUUFBUTtJQUNSLFlBQVksRUFBRSxlQUFlO0lBQzdCLG1CQUFtQixFQUFFLHVCQUF1QjtJQUM1QyxjQUFjLEVBQUUsaUJBQWlCO0lBQ2pDLHFCQUFxQixFQUFFLHlCQUF5QjtJQUNoRCxpQkFBaUIsRUFBRSxxQkFBcUI7SUFDeEMsZ0JBQWdCLEVBQUUsb0JBQW9CO0lBRXRDLFNBQVM7SUFDVCxhQUFhLEVBQUUsZ0JBQWdCO0lBQy9CLG9CQUFvQixFQUFFLHdCQUF3QjtJQUM5QyxlQUFlLEVBQUUsa0JBQWtCO0lBQ25DLGFBQWEsRUFBRSxnQkFBZ0I7Q0FDaEMsQ0FBQztBQUVGOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHO0lBQzFC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
@@ -0,0 +1,104 @@
1
+ import type { ISaneDevice, ISaneParameters, IScanOptions, IScanResult } from '../interfaces/index.js';
2
+ /**
3
+ * SANE network protocol client
4
+ */
5
+ export declare class SaneProtocol {
6
+ private socket;
7
+ private address;
8
+ private port;
9
+ private handle;
10
+ private options;
11
+ private readBuffer;
12
+ constructor(address: string, port?: number);
13
+ /**
14
+ * Connect to SANE daemon
15
+ */
16
+ connect(): Promise<void>;
17
+ /**
18
+ * Disconnect from SANE daemon
19
+ */
20
+ disconnect(): Promise<void>;
21
+ /**
22
+ * Initialize connection (SANE_NET_INIT)
23
+ */
24
+ private init;
25
+ /**
26
+ * Get available devices (SANE_NET_GET_DEVICES)
27
+ */
28
+ getDevices(): Promise<ISaneDevice[]>;
29
+ /**
30
+ * Open a device (SANE_NET_OPEN)
31
+ */
32
+ open(deviceName: string): Promise<void>;
33
+ /**
34
+ * Close the current device (SANE_NET_CLOSE)
35
+ */
36
+ close(): Promise<void>;
37
+ /**
38
+ * Exit connection (SANE_NET_EXIT)
39
+ */
40
+ private exit;
41
+ /**
42
+ * Get option descriptors (SANE_NET_GET_OPTION_DESCRIPTORS)
43
+ */
44
+ private getOptionDescriptors;
45
+ /**
46
+ * Set an option value
47
+ */
48
+ setOption(name: string, value: unknown): Promise<void>;
49
+ /**
50
+ * Get scan parameters (SANE_NET_GET_PARAMETERS)
51
+ */
52
+ getParameters(): Promise<ISaneParameters>;
53
+ /**
54
+ * Start scanning (SANE_NET_START)
55
+ */
56
+ start(): Promise<{
57
+ port: number;
58
+ byteOrder: 'little' | 'big';
59
+ }>;
60
+ /**
61
+ * Cancel scanning (SANE_NET_CANCEL)
62
+ */
63
+ cancel(): Promise<void>;
64
+ /**
65
+ * Perform a complete scan
66
+ */
67
+ scan(options: IScanOptions): Promise<IScanResult>;
68
+ /**
69
+ * Configure scan options based on IScanOptions
70
+ */
71
+ private configureOptions;
72
+ /**
73
+ * Read image data from data port
74
+ */
75
+ private readImageData;
76
+ /**
77
+ * Map color mode to SANE mode string
78
+ */
79
+ private mapColorMode;
80
+ /**
81
+ * Map SANE format code to string
82
+ */
83
+ private mapFormat;
84
+ /**
85
+ * Map value type code to string
86
+ */
87
+ private mapValueType;
88
+ /**
89
+ * Map unit code to string
90
+ */
91
+ private mapUnit;
92
+ /**
93
+ * Map constraint type code to string
94
+ */
95
+ private mapConstraintType;
96
+ private buildRequest;
97
+ private writeWord;
98
+ private writeString;
99
+ private sendRequest;
100
+ private readResponse;
101
+ private waitForData;
102
+ private readWord;
103
+ private readString;
104
+ }