knx.ts 1.0.0

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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +211 -0
  3. package/dist/@types/interfaces/DPTs.d.ts +144 -0
  4. package/dist/@types/interfaces/DPTs.js +3 -0
  5. package/dist/@types/interfaces/EMI.d.ts +396 -0
  6. package/dist/@types/interfaces/EMI.js +2 -0
  7. package/dist/@types/interfaces/ServiceMessage.d.ts +11 -0
  8. package/dist/@types/interfaces/ServiceMessage.js +2 -0
  9. package/dist/@types/interfaces/SystemStatus.d.ts +18 -0
  10. package/dist/@types/interfaces/SystemStatus.js +2 -0
  11. package/dist/@types/interfaces/connection.d.ts +139 -0
  12. package/dist/@types/interfaces/connection.js +2 -0
  13. package/dist/@types/interfaces/localEndPoint.d.ts +5 -0
  14. package/dist/@types/interfaces/localEndPoint.js +2 -0
  15. package/dist/@types/types/AllDpts.d.ts +3 -0
  16. package/dist/@types/types/AllDpts.js +3 -0
  17. package/dist/@types/types/DecodedDPTType.d.ts +21 -0
  18. package/dist/@types/types/DecodedDPTType.js +2 -0
  19. package/dist/connection/KNXService.d.ts +58 -0
  20. package/dist/connection/KNXService.js +242 -0
  21. package/dist/connection/KNXTunneling.d.ts +44 -0
  22. package/dist/connection/KNXTunneling.js +509 -0
  23. package/dist/connection/KNXnetIPServer.d.ts +64 -0
  24. package/dist/connection/KNXnetIPServer.js +900 -0
  25. package/dist/connection/Router.d.ts +49 -0
  26. package/dist/connection/Router.js +269 -0
  27. package/dist/connection/TPUART.d.ts +32 -0
  28. package/dist/connection/TPUART.js +497 -0
  29. package/dist/connection/TunnelConnection.d.ts +57 -0
  30. package/dist/connection/TunnelConnection.js +167 -0
  31. package/dist/core/CEMI.d.ts +1130 -0
  32. package/dist/core/CEMI.js +1281 -0
  33. package/dist/core/ControlField.d.ts +57 -0
  34. package/dist/core/ControlField.js +120 -0
  35. package/dist/core/ControlFieldExtended.d.ts +56 -0
  36. package/dist/core/ControlFieldExtended.js +114 -0
  37. package/dist/core/EMI.d.ts +2515 -0
  38. package/dist/core/EMI.js +3898 -0
  39. package/dist/core/KNXAddInfoTypes.d.ts +225 -0
  40. package/dist/core/KNXAddInfoTypes.js +602 -0
  41. package/dist/core/KNXnetIPHeader.d.ts +10 -0
  42. package/dist/core/KNXnetIPHeader.js +38 -0
  43. package/dist/core/KNXnetIPStructures.d.ts +179 -0
  44. package/dist/core/KNXnetIPStructures.js +622 -0
  45. package/dist/core/MessageCodeField.d.ts +886 -0
  46. package/dist/core/MessageCodeField.js +399 -0
  47. package/dist/core/SystemStatus.d.ts +144 -0
  48. package/dist/core/SystemStatus.js +325 -0
  49. package/dist/core/data/KNXData.d.ts +7 -0
  50. package/dist/core/data/KNXData.js +30 -0
  51. package/dist/core/data/KNXDataDecode.d.ts +396 -0
  52. package/dist/core/data/KNXDataDecode.js +1186 -0
  53. package/dist/core/data/KNXDataEncode.d.ts +332 -0
  54. package/dist/core/data/KNXDataEncode.js +1504 -0
  55. package/dist/core/enum/APCIEnum.d.ts +587 -0
  56. package/dist/core/enum/APCIEnum.js +591 -0
  57. package/dist/core/enum/EnumControlField.d.ts +24 -0
  58. package/dist/core/enum/EnumControlField.js +36 -0
  59. package/dist/core/enum/EnumControlFieldExtended.d.ts +36 -0
  60. package/dist/core/enum/EnumControlFieldExtended.js +41 -0
  61. package/dist/core/enum/EnumShortACKFrame.d.ts +6 -0
  62. package/dist/core/enum/EnumShortACKFrame.js +10 -0
  63. package/dist/core/enum/ErrorCodeSet.d.ts +57 -0
  64. package/dist/core/enum/ErrorCodeSet.js +2 -0
  65. package/dist/core/enum/KNXnetIPEnum.d.ts +95 -0
  66. package/dist/core/enum/KNXnetIPEnum.js +90 -0
  67. package/dist/core/enum/SAP.d.ts +19 -0
  68. package/dist/core/enum/SAP.js +23 -0
  69. package/dist/core/layers/data/APDU.d.ts +38 -0
  70. package/dist/core/layers/data/APDU.js +115 -0
  71. package/dist/core/layers/data/NPDU.d.ts +73 -0
  72. package/dist/core/layers/data/NPDU.js +103 -0
  73. package/dist/core/layers/data/TPDU.d.ts +53 -0
  74. package/dist/core/layers/data/TPDU.js +73 -0
  75. package/dist/core/layers/interfaces/APCI.d.ts +61 -0
  76. package/dist/core/layers/interfaces/APCI.js +92 -0
  77. package/dist/core/layers/interfaces/TPCI.d.ts +110 -0
  78. package/dist/core/layers/interfaces/TPCI.js +196 -0
  79. package/dist/core/resources/DeviceDescriptorType.d.ts +46 -0
  80. package/dist/core/resources/DeviceDescriptorType.js +69 -0
  81. package/dist/errors/DPTNotFound.d.ts +6 -0
  82. package/dist/errors/DPTNotFound.js +15 -0
  83. package/dist/errors/InvalidKnxAddresExeption.d.ts +3 -0
  84. package/dist/errors/InvalidKnxAddresExeption.js +9 -0
  85. package/dist/index.d.ts +7 -0
  86. package/dist/index.js +18 -0
  87. package/dist/utils/CEMIAdapter.d.ts +16 -0
  88. package/dist/utils/CEMIAdapter.js +94 -0
  89. package/dist/utils/KNXHelper.d.ts +78 -0
  90. package/dist/utils/KNXHelper.js +338 -0
  91. package/dist/utils/Logger.d.ts +17 -0
  92. package/dist/utils/Logger.js +96 -0
  93. package/dist/utils/MessageCodeTranslator.d.ts +19 -0
  94. package/dist/utils/MessageCodeTranslator.js +77 -0
  95. package/dist/utils/checksumFrame.d.ts +18 -0
  96. package/dist/utils/checksumFrame.js +41 -0
  97. package/dist/utils/localIp.d.ts +7 -0
  98. package/dist/utils/localIp.js +45 -0
  99. package/package.json +49 -0
@@ -0,0 +1,1186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KnxDataDecode = void 0;
4
+ const DPTNotFound_1 = require("../../errors/DPTNotFound");
5
+ const KNXData_1 = require("./KNXData");
6
+ /**
7
+ * Represents KNX DPTs (Data Point Types), decodes them according to their specification
8
+ */
9
+ class KnxDataDecode extends KNXData_1.KNXData {
10
+ constructor() {
11
+ super();
12
+ throw new Error("This class is static and cannot be instantiated.");
13
+ }
14
+ static decodeThis(dpt, buffer) {
15
+ let dptNum = this.getDptNumber(dpt);
16
+ if (dptNum === null)
17
+ throw new DPTNotFound_1.DPTNotFound();
18
+ dptNum = this.fallbackDPT(dptNum);
19
+ switch (dptNum) {
20
+ case 1:
21
+ return this.asDpt1(buffer);
22
+ break;
23
+ case 2:
24
+ return this.asDpt2(buffer);
25
+ break;
26
+ case 3007:
27
+ return this.asDpt3007(buffer);
28
+ break;
29
+ case 3008:
30
+ return this.asDpt3008(buffer);
31
+ break;
32
+ case 4001:
33
+ return this.asDpt4001(buffer);
34
+ break;
35
+ case 4002:
36
+ return this.asDpt4002(buffer);
37
+ break;
38
+ case 5:
39
+ return this.asDpt5(buffer);
40
+ break;
41
+ case 5001:
42
+ return this.asDpt5001(buffer);
43
+ break;
44
+ case 5002:
45
+ return this.asDpt5002(buffer);
46
+ case 6:
47
+ return this.asDpt6(buffer);
48
+ break;
49
+ case 6001:
50
+ return this.asDpt6001(buffer);
51
+ break;
52
+ case 6010:
53
+ return this.asDpt6010(buffer);
54
+ break;
55
+ case 6020:
56
+ return this.asDpt6020(buffer);
57
+ break;
58
+ case 7:
59
+ return this.asDpt7(buffer);
60
+ break;
61
+ case 7001:
62
+ return this.asDpt7001(buffer);
63
+ break;
64
+ case 7002:
65
+ return this.asDpt7002(buffer);
66
+ break;
67
+ case 7003:
68
+ return this.asDpt7003(buffer);
69
+ break;
70
+ case 7004:
71
+ return this.asDpt7004(buffer);
72
+ break;
73
+ case 7005:
74
+ return this.asDpt7005(buffer);
75
+ break;
76
+ case 7006:
77
+ return this.asDpt7006(buffer);
78
+ break;
79
+ case 7007:
80
+ return this.asDpt7007(buffer);
81
+ break;
82
+ case 7011:
83
+ return this.asDpt7011(buffer);
84
+ break;
85
+ case 7012:
86
+ return this.asDpt7012(buffer);
87
+ break;
88
+ case 7013:
89
+ return this.asDpt7013(buffer);
90
+ break;
91
+ case 8:
92
+ return this.asDpt8(buffer);
93
+ break;
94
+ case 9:
95
+ return this.asDpt9(buffer);
96
+ break;
97
+ case 10001:
98
+ return this.asDpt10001(buffer);
99
+ break;
100
+ case 11001:
101
+ return this.asDpt11001(buffer);
102
+ break;
103
+ case 12001:
104
+ return this.asDpt12001(buffer);
105
+ break;
106
+ case 12002:
107
+ return this.asDpt12002(buffer);
108
+ break;
109
+ case 13:
110
+ return this.asDpt13(buffer);
111
+ break;
112
+ case 13001:
113
+ return this.asDpt13001(buffer);
114
+ break;
115
+ case 13002:
116
+ return this.asDpt13002(buffer);
117
+ break;
118
+ case 13010:
119
+ return this.asDpt13010(buffer);
120
+ break;
121
+ case 13011:
122
+ return this.asDpt13011(buffer);
123
+ break;
124
+ case 13012:
125
+ return this.asDpt13012(buffer);
126
+ break;
127
+ case 13013:
128
+ return this.asDpt13013(buffer);
129
+ break;
130
+ case 13014:
131
+ return this.asDpt13014(buffer);
132
+ break;
133
+ case 13015:
134
+ return this.asDpt13015(buffer);
135
+ break;
136
+ case 13016:
137
+ return this.asDpt13016(buffer);
138
+ break;
139
+ case 13100:
140
+ return this.asDpt13100(buffer);
141
+ case 14:
142
+ return this.asDpt14(buffer);
143
+ break;
144
+ case 15000:
145
+ return this.asDpt15000(buffer);
146
+ break;
147
+ case 16:
148
+ return this.asDpt16(buffer);
149
+ break;
150
+ case 16002:
151
+ return this.asDpt16002(buffer);
152
+ break;
153
+ case 20:
154
+ return this.asDpt20(buffer);
155
+ break;
156
+ case 20001:
157
+ return this.asDpt20001(buffer);
158
+ break;
159
+ case 20002:
160
+ return this.asDpt20002(buffer);
161
+ break;
162
+ case 20003:
163
+ return this.asDpt20003(buffer);
164
+ break;
165
+ case 20004:
166
+ return this.asDpt20004(buffer);
167
+ break;
168
+ case 20005:
169
+ return this.asDpt20005(buffer);
170
+ break;
171
+ case 20006:
172
+ return this.asDpt20006(buffer);
173
+ break;
174
+ case 20007:
175
+ return this.asDpt20007(buffer);
176
+ break;
177
+ case 20008:
178
+ return this.asDpt20008(buffer);
179
+ break;
180
+ case 20011:
181
+ return this.asDpt20011(buffer);
182
+ break;
183
+ case 20012:
184
+ return this.asDpt20012(buffer);
185
+ break;
186
+ case 20013:
187
+ return this.asDpt20013(buffer);
188
+ break;
189
+ case 20014:
190
+ return this.asDpt20014(buffer);
191
+ break;
192
+ case 20017:
193
+ return this.asDpt20017(buffer);
194
+ break;
195
+ case 20020:
196
+ return this.asDpt20020(buffer);
197
+ break;
198
+ case 20021:
199
+ return this.asDpt20021(buffer);
200
+ break;
201
+ case 20022:
202
+ return this.asDpt20022(buffer);
203
+ break;
204
+ case 27001:
205
+ return this.asDpt27001(buffer);
206
+ break;
207
+ case 28001:
208
+ return this.asDpt28001(buffer);
209
+ break;
210
+ case 29:
211
+ return this.asDpt29(buffer);
212
+ break;
213
+ case 29010:
214
+ return this.asDpt29010(buffer);
215
+ break;
216
+ case 29011:
217
+ return this.asDpt29011(buffer);
218
+ break;
219
+ case 29012:
220
+ return this.asDpt29012(buffer);
221
+ break;
222
+ case 232600:
223
+ return this.asDpt232600(buffer);
224
+ break;
225
+ case 238600:
226
+ return this.asDpt238600(buffer);
227
+ break;
228
+ case 245600:
229
+ return this.asDpt245600(buffer);
230
+ break;
231
+ case 250600:
232
+ return this.asDpt250600(buffer);
233
+ break;
234
+ case 251600:
235
+ return this.asDpt251600(buffer);
236
+ break;
237
+ default:
238
+ throw new DPTNotFound_1.DPTNotFound();
239
+ }
240
+ }
241
+ static get dptEnum() {
242
+ return [1, 2, 3007, 3008, 4001, 4002, 5, 5001, 5002, 6, 6001, 6010, 6020, 7, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7011, 7012, 7013, 8, 9, 10001, 11001, 12001, 12002, 13, 13001, 13002, 13010, 13011, 13012, 13013, 13014, 13015, 13016, 13100, 14, 15000, 16, 16002, 20, 20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20011, 20012, 20013, 20014, 20017, 20020, 20021, 20022, 27001, 28001, 29, 29010, 29011, 29012, 232600, 238600, 245600, 250600, 251600];
243
+ }
244
+ static toPercentage(value) {
245
+ return (value / 255) * 100 + '%';
246
+ }
247
+ static toAngle(value) {
248
+ return (value / 255) * 360 + 'ª';
249
+ }
250
+ /**
251
+ * Interpret the underlying data as boolean value
252
+ * @returns
253
+ */
254
+ static asDpt1(buffer) {
255
+ // 0x3F = 0011 1111
256
+ const data = 0x3f & buffer[0];
257
+ return data != 0;
258
+ }
259
+ /**
260
+ * Interpretar la información del DPT2 (B2) y devolver un objeto con los campos:
261
+ * - control (c): 0 o 1
262
+ * - value (v): 0 o 1
263
+ * - description: descripción basada en la combinación de bits
264
+ *
265
+ * Los datos se encuentran en el primer octeto (buffer[0]), y solo se toman en cuenta los dos bits menos significativos.
266
+ */
267
+ static asDpt2(buffer) {
268
+ // Extraer los dos bits menos significativos del primer octeto.
269
+ const raw = buffer[0] & 0x03;
270
+ const c = (raw >> 1) & 0x01; // Bit de control
271
+ const v = raw & 0x01; // Bit de valor
272
+ let description = '';
273
+ // Según la combinación de bits, asignamos una descripción:
274
+ // - c = 0: sin control.
275
+ // - v = 0: DPT_Enable_Control (2.003)
276
+ // - v = 1: DPT_Ramp_Control (2.004)
277
+ // - c = 1: con control.
278
+ // - v = 0: DPT_Alarm_Control (2.005)
279
+ // - v = 1: DPT_BinaryValue_Control (2.006)
280
+ if (c === 0) {
281
+ if (v === 0) {
282
+ description = 'No control (DPT_Enable_Control)';
283
+ }
284
+ else {
285
+ description = 'No control (DPT_Ramp_Control)';
286
+ }
287
+ }
288
+ else {
289
+ // c === 1
290
+ if (v === 0) {
291
+ description = 'Control. Function value 0 (DPT_Alarm_Control)';
292
+ }
293
+ else {
294
+ description = 'Control. Function value 1 (DPT_BinaryValue_Control)';
295
+ }
296
+ }
297
+ return {
298
+ control: c,
299
+ value: v,
300
+ description: description,
301
+ };
302
+ }
303
+ /**
304
+ * Interpretar la información del DPT3007 (B1U3) y devolver un objeto con:
305
+ * - control: 0 (Decrease) o 1 (Increase)
306
+ * - stepCode: valor de 3 bits (0…7)
307
+ * - action: descripción de la acción (Decrease o Increase)
308
+ * - description: "Break" si stepCode es 0 o el detalle de step con el número de intervalos
309
+ *
310
+ * Se asume que el dato se encuentra en el primer octeto útil, es decir, en buffer[0].
311
+ * Como la información es de 4 bits, se toma el nibble inferior del byte.
312
+ */
313
+ static asDpt3007(buffer) {
314
+ // Extraemos el nibble inferior del byte en buffer[0].
315
+ // El formato es: c StepCode, donde:
316
+ // - c es el bit más significativo del nibble (bit 3) y
317
+ // - StepCode son los 3 bits menos significativos (bits 0-2).
318
+ const rawNibble = buffer[0] & 0x0f;
319
+ const control = (rawNibble >> 3) & 0x01; // Extrae el bit c.
320
+ const stepCode = rawNibble & 0x07; // Extrae los 3 bits de StepCode.
321
+ // Determinar la acción según el bit de control.
322
+ const action = control === 0 ? 'Decrease' : 'Increase';
323
+ // Descripción basada en el valor de StepCode:
324
+ // - Si StepCode es 0, se interpreta como "Break".
325
+ // - Si StepCode es 1..7, se calcula el número de intervalos como 2^(stepCode - 1)
326
+ let description = '';
327
+ if (stepCode === 0) {
328
+ description = 'Break';
329
+ }
330
+ else {
331
+ const intervals = Math.pow(2, stepCode - 1);
332
+ description = `StepCode ${stepCode} (Intervals: ${intervals})`;
333
+ }
334
+ return {
335
+ control, // 0: Decrease, 1: Increase.
336
+ stepCode, // Valor del StepCode (0...7).
337
+ action, // Descripción breve: "Decrease" o "Increase".
338
+ description, // Descripción completa: "Break" o detalle del step.
339
+ };
340
+ }
341
+ /**
342
+ * Interpretar la información del DPT3008 (DPT_Control_Blinds).
343
+ * Se asume que los datos se encuentran en el primer octeto de la carga útil.
344
+ *
345
+ * Formato: 4 bit: B1U3
346
+ * Campos:
347
+ * - c: 1 bit (0 = Up, 1 = Down)
348
+ * - stepCode: 3 bits
349
+ *
350
+ * Retorna un objeto con:
351
+ * - control: 0 o 1
352
+ * - stepCode: valor numérico de 0 a 7
353
+ * - description: texto descriptivo (p.ej. "Up" o "Down")
354
+ * - intervals: Si stepCode es distinto de 0, se calcula como 2^(stepCode - 1), o bien se indica "Break" si es 0.
355
+ */
356
+ static asDpt3008(buffer) {
357
+ const byte = buffer.readUInt8(0);
358
+ // Extraer el nibble inferior (4 bits)
359
+ const nibble = byte & 0x0f;
360
+ // Extraer el bit de control (c) y el StepCode (3 bits)
361
+ const control = (nibble >> 3) & 0x01; // Bit más significativo del nibble
362
+ const stepCode = nibble & 0x07; // Los 3 bits menos significativos
363
+ // Determinar la descripción y el número de intervalos
364
+ const description = control === 0 ? 'Move Up' : 'Move Down';
365
+ const intervals = stepCode === 0 ? 'Break indication' : Math.pow(2, stepCode - 1);
366
+ return {
367
+ control: control,
368
+ stepCode: stepCode,
369
+ description: description,
370
+ intervals: intervals,
371
+ };
372
+ }
373
+ /**
374
+ * Interpreta la información del DPT4001 (DPT_Char_ASCII).
375
+ * Se asume que el dato se encuentra en el primer octeto de la carga útil.
376
+ *
377
+ * - Valida que el MSB sea 0 (valor en el rango 0...127).
378
+ * - Retorna el carácter ASCII correspondiente.
379
+ */
380
+ static asDpt4001(buffer) {
381
+ const value = buffer.readUInt8(0);
382
+ // Validación: el MSB debe ser 0 para un carácter ASCII
383
+ if (value & 0x80) {
384
+ throw new Error(`Valor inválido para DPT4001: ${value}. El MSB debe ser 0.`);
385
+ }
386
+ return String.fromCharCode(value);
387
+ }
388
+ /**
389
+ * Interpreta la información del DPT4002 (DPT_Char_8859_1).
390
+ * Se asume que el dato se encuentra en el primer octeto de la carga útil.
391
+ *
392
+ * - No se impone restricción en el MSB (valor en el rango 0...255).
393
+ * - Retorna el carácter correspondiente en ISO-8859-1.
394
+ */
395
+ static asDpt4002(buffer) {
396
+ const value = buffer.readUInt8(0);
397
+ return String.fromCharCode(value);
398
+ }
399
+ /**
400
+ * Interpret the underlying data as 1 Byte unsigned value
401
+ * @returns
402
+ */
403
+ static asDpt5(buffer) {
404
+ return buffer.readUInt8(0);
405
+ }
406
+ static asDpt5001(buffer) {
407
+ return this.toPercentage(this.asDpt5(buffer));
408
+ }
409
+ static asDpt5002(buffer) {
410
+ return this.toAngle(this.asDpt5(buffer));
411
+ }
412
+ static asDpt6(buffer) {
413
+ return buffer.readInt8(0);
414
+ }
415
+ static asDpt6001(buffer) {
416
+ return this.asDpt6(buffer) + '%';
417
+ }
418
+ static asDpt6010(buffer) {
419
+ return this.asDpt6(buffer) + ' counter pulses';
420
+ }
421
+ static asDpt6020(buffer) {
422
+ // Extraer los primeros 5 bits (estado) de la primera posición
423
+ const status = buffer.readUInt8(0) >> 3; // Desplazamos 3 bits a la derecha para obtener los primeros 5 bits
424
+ // Extraer los últimos 3 bits (modo) de la primera posición
425
+ const mode = buffer.readUInt8(0) & 0b111; // Usamos una máscara para obtener los últimos 3 bits
426
+ // Asignar el modo (1: Modo 0, 2: Modo 1, 3: Modo 2)
427
+ let modeText = '';
428
+ switch (mode) {
429
+ case 0b001:
430
+ modeText = 'Modo 0 activo';
431
+ break;
432
+ case 0b010:
433
+ modeText = 'Modo 1 activo';
434
+ break;
435
+ case 0b100:
436
+ modeText = 'Modo 2 activo';
437
+ break;
438
+ default:
439
+ modeText = 'Modo desconocido';
440
+ }
441
+ // Devolver los resultados como un objeto con estado y modo
442
+ return {
443
+ status: status === 1 ? 'Activo' : 'Inactivo', // Si el bit de estado es 1, es activo
444
+ mode: modeText,
445
+ };
446
+ }
447
+ static asDpt7(buffer) {
448
+ if (buffer.length === 1) {
449
+ return buffer.readUInt8(0);
450
+ }
451
+ else {
452
+ return buffer.readUInt16BE(0);
453
+ }
454
+ }
455
+ static asDpt7001(buffer) {
456
+ const data = this.asDpt7(buffer);
457
+ return data + 'pulses';
458
+ }
459
+ static asDpt7002(buffer) {
460
+ return this.asDpt7(buffer) + 'ms';
461
+ }
462
+ static asDpt7003(buffer) {
463
+ return this.asDpt7(buffer) / 100 + 's';
464
+ }
465
+ static asDpt7004(buffer) {
466
+ return this.asDpt7(buffer) / 10 + 's';
467
+ }
468
+ static asDpt7005(buffer) {
469
+ return this.asDpt7(buffer) + 's';
470
+ }
471
+ static asDpt7006(buffer) {
472
+ return this.asDpt7(buffer) + 'min';
473
+ }
474
+ static asDpt7007(buffer) {
475
+ return this.asDpt7(buffer) + 'h';
476
+ }
477
+ static asDpt7011(buffer) {
478
+ return this.asDpt7(buffer) + 'mm';
479
+ }
480
+ static asDpt7012(buffer) {
481
+ const data = this.asDpt7(buffer);
482
+ if (data === 0) {
483
+ return {
484
+ value: data,
485
+ status: 'No bus power supply functionality available',
486
+ };
487
+ }
488
+ else {
489
+ return {
490
+ value: data + 'mA',
491
+ status: '',
492
+ };
493
+ }
494
+ }
495
+ static asDpt7013(buffer) {
496
+ return this.asDpt7(buffer) + 'lux';
497
+ }
498
+ static asDpt8(buffer) {
499
+ return buffer.readInt16BE(0);
500
+ }
501
+ /**
502
+ * Decodifica un DPT9 (2-octetos) según la especificación KNX:
503
+ * FloatValue = 0.01 * M * 2^(E)
504
+ * S (1 bit) = Signo de la mantisa
505
+ * E (4 bits) = [0…15]
506
+ * M (11 bits) = Mantisa
507
+ * Si el valor codificado es 0x7FFF, se considera inválido.
508
+ *
509
+ * @returns El valor en punto flotante.
510
+ */
511
+ static asDpt9(buffer) {
512
+ const raw = buffer.readUInt16BE(0);
513
+ // Si el valor es 0x7FFF, se considera dato inválido.
514
+ if (raw === 0x7fff) {
515
+ throw new Error('DPT9: Invalid data (0x7FFF encountered)');
516
+ }
517
+ const s = raw >> 15;
518
+ const exponent = (raw >> 11) & 0x0f;
519
+ let mantissa = raw & 0x07ff;
520
+ if (s) {
521
+ mantissa = mantissa - 2048;
522
+ }
523
+ // Calcular el valor real:
524
+ const value = 0.01 * mantissa * Math.pow(2, exponent);
525
+ return value;
526
+ }
527
+ /**
528
+ * Interpreta la información del DPT 10001 (Time of Day).
529
+ * Se asume que la carga útil contiene 3 octetos codificados según:
530
+ *
531
+ * Octeto 1: NNNUUUUU -> 3 bits para el Día y 5 bits para la Hora.
532
+ * Octeto 2: rrUUUUUU -> 6 bits para los Minutos (dos bits reservados).
533
+ * Octeto 3: rrUUUUUU -> 6 bits para los Segundos (dos bits reservados).
534
+ *
535
+ * Retorna un objeto con:
536
+ * - day: número del día (0 = no day, 1 = lunes, …, 7 = domingo)
537
+ * - dayName: nombre del día (o "No day")
538
+ * - hour: hora (0...23)
539
+ * - minutes: minutos (0...59)
540
+ * - seconds: segundos (0...59)
541
+ */
542
+ static asDpt10001(buffer) {
543
+ if (buffer.length < 3) {
544
+ throw new Error('No hay suficientes datos para DPT10001');
545
+ }
546
+ // Octeto 1: Día y Hora
547
+ const byte0 = buffer.readUInt8(0);
548
+ const day = (byte0 >> 5) & 0x07; // Extrae los 3 bits superiores
549
+ const hour = byte0 & 0x1f; // Extrae los 5 bits inferiores
550
+ // Octeto 2: Minutos (6 bits)
551
+ const byte1 = buffer.readUInt8(1);
552
+ const minutes = byte1 & 0x3f; // Máscara 0011 1111
553
+ // Octeto 3: Segundos (6 bits)
554
+ const byte2 = buffer.readUInt8(2);
555
+ const seconds = byte2 & 0x3f; // Máscara 0011 1111
556
+ // Opcional: conversión del número del día a nombre
557
+ const days = {
558
+ 0: 'No day',
559
+ 1: 'Monday',
560
+ 2: 'Tuesday',
561
+ 3: 'Wednesday',
562
+ 4: 'Thursday',
563
+ 5: 'Friday',
564
+ 6: 'Saturday',
565
+ 7: 'Sunday',
566
+ };
567
+ return {
568
+ day: day,
569
+ dayName: days[day] || 'Unknown',
570
+ hour: hour,
571
+ minutes: minutes,
572
+ seconds: seconds,
573
+ };
574
+ }
575
+ /**
576
+ * Interpreta la información del DPT 11001 (Date).
577
+ * Se asume que la carga útil contiene 3 octetos codificados según:
578
+ *
579
+ * Octeto 1: r3U5 => Day: 5 bits (bits [4:0])
580
+ * Octeto 2: r4U4 => Month: 4 bits (bits [3:0])
581
+ * Octeto 3: r1U7 => Year: 7 bits (bits [6:0])
582
+ *
583
+ * La interpretación del año es:
584
+ * - Si el valor es >= 90: año = 1900 + valor (siglo XX)
585
+ * - Si el valor es < 90: año = 2000 + valor (siglo XXI)
586
+ *
587
+ * Retorna un objeto con los campos day, month, year y una cadena formateada.
588
+ */
589
+ static asDpt11001(buffer) {
590
+ if (buffer.length < 3) {
591
+ throw new Error('No hay suficientes datos para DPT11001');
592
+ }
593
+ // Octeto 1: Extraer el día (los 5 bits menos significativos)
594
+ const byte0 = buffer.readUInt8(0);
595
+ const day = byte0 & 0x1f; // 0x1F equivale a 0001 1111
596
+ // Octeto 2: Extraer el mes (los 4 bits menos significativos)
597
+ const byte1 = buffer.readUInt8(1);
598
+ const month = byte1 & 0x0f; // 0x0F equivale a 0000 1111
599
+ // Octeto 3: Extraer el año (los 7 bits menos significativos)
600
+ const byte2 = buffer.readUInt8(2);
601
+ const rawYear = byte2 & 0x7f; // 0x7F equivale a 0111 1111
602
+ // Interpretar el siglo:
603
+ // Si rawYear >= 90 => 1900 + rawYear (siglo XX: 1990-1999)
604
+ // Si rawYear < 90 => 2000 + rawYear (siglo XXI: 2000-2089)
605
+ const century = rawYear >= 90 ? 1900 : 2000;
606
+ const year = century + rawYear;
607
+ return {
608
+ day,
609
+ month,
610
+ year,
611
+ // Formateamos la fecha en formato DD/MM/YYYY
612
+ dateString: `${day.toString().padStart(2, '0')}/${month.toString().padStart(2, '0')}/${year}`,
613
+ };
614
+ }
615
+ /**
616
+ * Interpreta la información del DPT 12.001 (4-Octet Unsigned Value para counter pulses).
617
+ * Se asume que la carga útil contiene 4 octetos.
618
+ *
619
+ * @returns Un objeto con el valor sin signo y la unidad ("pulses").
620
+ */
621
+ static asDpt12001(buffer) {
622
+ if (buffer.length < 4) {
623
+ throw new Error('No hay suficientes datos para DPT 12.001');
624
+ }
625
+ const value = buffer.readUInt32BE(0);
626
+ return {
627
+ value,
628
+ unit: 'pulses',
629
+ };
630
+ }
631
+ /**
632
+ * Interpreta la información de los DPT LongTimePeriod (12.100, 12.101, 12.102) para operating hours.
633
+ * Se asume que la carga útil contiene 4 octetos.
634
+ *
635
+ * @param variant Puede ser:
636
+ * - "sec" para DPT_LongTimePeriod_Sec (12.100, segundos),
637
+ * - "min" para DPT_LongTimePeriod_Min (12.101, minutos),
638
+ * - "hrs" para DPT_LongTimePeriod_Hrs (12.102, horas).
639
+ * Por defecto se usa "sec".
640
+ *
641
+ * @returns Un objeto con el valor sin signo y la unidad seleccionada.
642
+ */
643
+ static asDpt12002(buffer, variant = 'sec') {
644
+ if (buffer.length < 4) {
645
+ throw new Error('No hay suficientes datos para el DPT LongTimePeriod');
646
+ }
647
+ const value = buffer.readUInt32BE(0);
648
+ let unit;
649
+ switch (variant) {
650
+ case 'sec':
651
+ unit = 's';
652
+ break;
653
+ case 'min':
654
+ unit = 'min';
655
+ break;
656
+ case 'hrs':
657
+ unit = 'h';
658
+ break;
659
+ }
660
+ return {
661
+ value,
662
+ unit,
663
+ };
664
+ }
665
+ /**
666
+ * Interpret the underlying data as 4 byte signed integer
667
+ * @returns
668
+ */
669
+ static asDpt13(buffer) {
670
+ return buffer.readInt32BE(0);
671
+ }
672
+ /**
673
+ * DPT 13.001: DPT_Value_4_Count
674
+ * Interpreta un contador de pulsos (valor de 4 octetos con signo).
675
+ */
676
+ static asDpt13001(buffer) {
677
+ if (buffer.length < 4) {
678
+ throw new Error('No hay suficientes datos para DPT 13.001');
679
+ }
680
+ const value = buffer.readInt32BE(0);
681
+ return {
682
+ value,
683
+ unit: 'pulses',
684
+ };
685
+ }
686
+ /**
687
+ * DPT 13.002: DPT_FlowRate_m3/h
688
+ * Interpreta el flujo en m³/h (valor de 4 octetos con signo) con alta resolución.
689
+ */
690
+ static asDpt13002(buffer) {
691
+ if (buffer.length < 4) {
692
+ throw new Error('No hay suficientes datos para DPT 13.002');
693
+ }
694
+ const rawValue = buffer.readInt32BE(0);
695
+ const value = rawValue * 0.0001;
696
+ return {
697
+ value,
698
+ unit: 'm³/h',
699
+ };
700
+ }
701
+ /**
702
+ * DPT 13.010: DPT_ActiveEnergy
703
+ * Interpreta la energía activa en Wh.
704
+ */
705
+ static asDpt13010(buffer) {
706
+ if (buffer.length < 4) {
707
+ throw new Error('No hay suficientes datos para DPT 13.010');
708
+ }
709
+ const value = buffer.readInt32BE(0);
710
+ return {
711
+ value,
712
+ unit: 'Wh',
713
+ };
714
+ }
715
+ /**
716
+ * DPT 13.011: DPT_ApparantEnergy
717
+ * Interpreta la energía aparente en VAh.
718
+ */
719
+ static asDpt13011(buffer) {
720
+ if (buffer.length < 4) {
721
+ throw new Error('No hay suficientes datos para DPT 13.011');
722
+ }
723
+ const value = buffer.readInt32BE(0);
724
+ return {
725
+ value,
726
+ unit: 'VAh',
727
+ };
728
+ }
729
+ /**
730
+ * DPT 13.012: DPT_ReactiveEnergy
731
+ * Interpreta la energía reactiva en VARh.
732
+ */
733
+ static asDpt13012(buffer) {
734
+ if (buffer.length < 4) {
735
+ throw new Error('No hay suficientes datos para DPT 13.012');
736
+ }
737
+ const value = buffer.readInt32BE(0);
738
+ return {
739
+ value,
740
+ unit: 'VARh',
741
+ };
742
+ }
743
+ /**
744
+ * DPT 13.013: DPT_ActiveEnergy_kWh
745
+ * Interpreta la energía activa en kWh.
746
+ */
747
+ static asDpt13013(buffer) {
748
+ if (buffer.length < 4) {
749
+ throw new Error('No hay suficientes datos para DPT 13.013');
750
+ }
751
+ const value = buffer.readInt32BE(0);
752
+ return {
753
+ value,
754
+ unit: 'kWh',
755
+ };
756
+ }
757
+ /**
758
+ * DPT 13.014: DPT_ApparantEnergy_kVAh
759
+ * Interpreta la energía aparente en kVAh.
760
+ */
761
+ static asDpt13014(buffer) {
762
+ if (buffer.length < 4) {
763
+ throw new Error('No hay suficientes datos para DPT 13.014');
764
+ }
765
+ const value = buffer.readInt32BE(0);
766
+ return {
767
+ value,
768
+ unit: 'kVAh',
769
+ };
770
+ }
771
+ /**
772
+ * DPT 13.015: DPT_ReactiveEnergy_kVARh
773
+ * Interpreta la energía reactiva en kVARh.
774
+ */
775
+ static asDpt13015(buffer) {
776
+ if (buffer.length < 4) {
777
+ throw new Error('No hay suficientes datos para DPT 13.015');
778
+ }
779
+ const value = buffer.readInt32BE(0);
780
+ return {
781
+ value,
782
+ unit: 'kVARh',
783
+ };
784
+ }
785
+ /**
786
+ * DPT 13.016: DPT_ActiveEnergy_MWh
787
+ * Interpreta la energía activa en MWh.
788
+ */
789
+ static asDpt13016(buffer) {
790
+ if (buffer.length < 4) {
791
+ throw new Error('No hay suficientes datos para DPT 13.016');
792
+ }
793
+ const value = buffer.readInt32BE(0);
794
+ return {
795
+ value,
796
+ unit: 'MWh',
797
+ };
798
+ }
799
+ /**
800
+ * DPT 13.100: DPT_LongDeltaTimeSec
801
+ * Interpreta un periodo de tiempo en segundos.
802
+ */
803
+ static asDpt13100(buffer) {
804
+ if (buffer.length < 4) {
805
+ throw new Error('No hay suficientes datos para DPT 13.100');
806
+ }
807
+ const value = buffer.readInt32BE(0);
808
+ return {
809
+ value,
810
+ unit: 's',
811
+ };
812
+ }
813
+ /**
814
+ * Interpret the underlying data as 4 byte floating point number
815
+ */
816
+ static asDpt14(buffer) {
817
+ return buffer.readFloatBE(0);
818
+ }
819
+ /**
820
+ * DPT 15.000: DPT_Access_Data
821
+ * Decodifica un valor de 4 bytes con información de acceso.
822
+ */
823
+ static asDpt15000(buffer) {
824
+ if (buffer.length < 4) {
825
+ throw new Error('No hay suficientes datos para DPT 15.000 (Access Data).');
826
+ }
827
+ const d6 = buffer.readUInt8(0); // Octeto 4
828
+ const d5 = (buffer.readUInt8(1) & 0b11110000) >> 4;
829
+ const d4 = buffer.readUInt8(1) & 0b00001111;
830
+ const d3 = (buffer.readUInt8(2) & 0b11110000) >> 4;
831
+ const d2 = buffer.readUInt8(2) & 0b00001111;
832
+ const d1 = (buffer.readUInt8(3) & 0b11110000) >> 4;
833
+ const e = (buffer.readUInt8(3) & 0b00001000) !== 0;
834
+ const p = (buffer.readUInt8(3) & 0b00000100) !== 0;
835
+ const d = (buffer.readUInt8(3) & 0b00000010) !== 0;
836
+ const c = (buffer.readUInt8(3) & 0b00000001) !== 0;
837
+ const index = buffer.readUInt8(3) & 0b00001111;
838
+ return {
839
+ accessCode: `${d6}${d5}${d4}${d3}${d2}${d1}`,
840
+ error: e,
841
+ permission: p,
842
+ readDirection: d,
843
+ encryption: c,
844
+ index: index,
845
+ };
846
+ }
847
+ /**
848
+ * DPT 16.000 / 16.001: DPT_String
849
+ * Decodifica una cadena de 14 bytes en ASCII o ISO-8859-1.
850
+ */
851
+ static asDpt16(buffer) {
852
+ if (buffer.length < 14) {
853
+ throw new Error('Datos insuficientes para DPT 16 (String).');
854
+ }
855
+ let str = '';
856
+ for (let i = 0; i < 14; i++) {
857
+ const charCode = buffer.readUInt8(i);
858
+ if (charCode === 0x00)
859
+ break; // Ignorar caracteres NULL
860
+ str += String.fromCharCode(charCode);
861
+ }
862
+ return str;
863
+ }
864
+ /**
865
+ * Decodifica un buffer de 14 bytes en formato hexadecimal (DPT 16.002).
866
+ * (No oficial en la especificacion del DataPointType de Knx en la version 02.02.01)
867
+ */
868
+ static asDpt16002(buffer) {
869
+ if (buffer.length < 14) {
870
+ throw new Error('Datos insuficientes para DPT 16.002 (Se esperan 14 bytes).');
871
+ }
872
+ let hexString = '';
873
+ let decimalValue = BigInt(0);
874
+ for (let i = 0; i < 14; i++) {
875
+ if (buffer.readUInt8(i) === 0x00)
876
+ break; // Ignorar caracteres NULL
877
+ hexString += buffer.readUInt8(i).toString(16).padStart(2, '0').toUpperCase();
878
+ }
879
+ if (hexString) {
880
+ decimalValue = BigInt('0x' + hexString); // Convertir de Hex a Decimal
881
+ }
882
+ return { hex: hexString, decimal: decimalValue.toString() };
883
+ }
884
+ static asDpt20(buffer) {
885
+ return buffer.readUInt8(0);
886
+ }
887
+ static asDpt20001(buffer) {
888
+ const value = buffer.readUInt8(0);
889
+ return ['autonomous', 'slave', 'master'][value] || 'reserved';
890
+ }
891
+ static asDpt20002(buffer) {
892
+ const value = buffer.readUInt8(0);
893
+ return ['Building in use', 'Building not used', 'Building protection'][value] || 'reserved';
894
+ }
895
+ static asDpt20003(buffer) {
896
+ const value = buffer.readUInt8(0);
897
+ return ['occupied', 'standby', 'not occupied'][value] || 'reserved';
898
+ }
899
+ static asDpt20004(buffer) {
900
+ const value = buffer.readUInt8(0);
901
+ return ['High', 'Medium', 'Low', 'void'][value] || 'reserved';
902
+ }
903
+ static asDpt20005(buffer) {
904
+ const value = buffer.readUInt8(0);
905
+ return ['normal', 'presence simulation', 'night round'][value] || 'manufacturer specific';
906
+ }
907
+ static asDpt20006(buffer) {
908
+ const value = buffer.readUInt8(0);
909
+ const mapping = {
910
+ 0: 'no fault',
911
+ 1: 'system and functions of common interest',
912
+ 10: 'HVAC general FBs',
913
+ 11: 'HVAC Hot Water Heating',
914
+ 12: 'HVAC Direct Electrical Heating',
915
+ 13: 'HVAC Terminal Units',
916
+ 14: 'HVAC VAC',
917
+ 20: 'Lighting',
918
+ 30: 'Security',
919
+ 40: 'Load Management',
920
+ 50: 'Shutters and blinds',
921
+ };
922
+ return mapping[value] || 'reserved';
923
+ }
924
+ static asDpt20007(buffer) {
925
+ const value = buffer.readUInt8(0);
926
+ return ['reserved', 'simple alarm', 'basic alarm', 'extended alarm'][value] || 'reserved';
927
+ }
928
+ static asDpt20008(buffer) {
929
+ const value = buffer.readUInt8(0);
930
+ return ['disabled', 'enabled', 'auto'][value] || 'reserved';
931
+ }
932
+ static asDpt20011(buffer) {
933
+ const value = buffer.readUInt8(0);
934
+ const mapping = [
935
+ 'no fault',
936
+ 'general device fault',
937
+ 'communication fault',
938
+ 'configuration fault',
939
+ 'hardware fault',
940
+ 'software fault',
941
+ 'insufficient non-volatile memory',
942
+ 'insufficient volatile memory',
943
+ 'memory allocation size 0 received',
944
+ 'CRC-error',
945
+ 'watchdog reset detected',
946
+ 'invalid opcode detected',
947
+ 'general protection fault',
948
+ 'maximal table length exceeded',
949
+ 'undefined load command received',
950
+ 'Group Address Table not sorted',
951
+ 'invalid connection number (TSAP)',
952
+ 'invalid Group Object number (ASAP)',
953
+ 'Group Object Type exceeds limit',
954
+ ];
955
+ return mapping[value] || 'reserved';
956
+ }
957
+ static asDpt20012(buffer) {
958
+ const value = buffer.readUInt8(0);
959
+ return ['no fault', 'sensor fault', 'process/controller fault', 'actuator fault', 'other fault'][value] || 'reserved';
960
+ }
961
+ static asDpt20013(buffer) {
962
+ const value = buffer.readUInt8(0);
963
+ const mapping = [
964
+ 'not active',
965
+ '1 s',
966
+ '2 s',
967
+ '3 s',
968
+ '5 s',
969
+ '10 s',
970
+ '15 s',
971
+ '20 s',
972
+ '30 s',
973
+ '45 s',
974
+ '1 min',
975
+ '1.25 min',
976
+ '1.5 min',
977
+ '2 min',
978
+ '2.5 min',
979
+ '3 min',
980
+ '5 min',
981
+ '15 min',
982
+ '20 min',
983
+ '30 min',
984
+ '1 h',
985
+ '2 h',
986
+ '3 h',
987
+ '5 h',
988
+ '12 h',
989
+ '24 h',
990
+ ];
991
+ return mapping[value] || 'reserved';
992
+ }
993
+ static asDpt20014(buffer) {
994
+ const value = buffer.readUInt8(0);
995
+ return ([
996
+ 'calm (no wind)',
997
+ 'light air',
998
+ 'light breeze',
999
+ 'gentle breeze',
1000
+ 'moderate breeze',
1001
+ 'fresh breeze',
1002
+ 'strong breeze',
1003
+ 'near gale / moderate gale',
1004
+ 'fresh gale',
1005
+ 'strong gale',
1006
+ 'whole gale / storm',
1007
+ 'violent storm',
1008
+ 'hurricane',
1009
+ ][value] || 'reserved');
1010
+ }
1011
+ static asDpt20017(buffer) {
1012
+ const value = buffer.readUInt8(0);
1013
+ return (['inactive', 'digital input not inverted', 'digital input inverted', 'analog input 0%-100%', 'temperature sensor input'][value] || 'reserved');
1014
+ }
1015
+ static asDpt20020(buffer) {
1016
+ const value = buffer.readUInt8(0);
1017
+ return ['reserved', 'SensorConnection', 'ControllerConnection'][value] || 'reserved';
1018
+ }
1019
+ static asDpt20021(buffer) {
1020
+ const value = buffer.readUInt8(0);
1021
+ return ([
1022
+ 'Cloudless',
1023
+ 'Sunny',
1024
+ 'Sunshiny',
1025
+ 'Lightly cloudy',
1026
+ 'Scattered clouds',
1027
+ 'Cloudy',
1028
+ 'Heavily cloudy',
1029
+ 'Almost overcast',
1030
+ 'Overcast',
1031
+ 'Sky obstructed from view',
1032
+ ][value] || 'reserved');
1033
+ }
1034
+ static asDpt20022(buffer) {
1035
+ const value = buffer.readUInt8(0);
1036
+ return ['do not send', 'send always', 'send if value changed during powerdown'][value] || 'reserved';
1037
+ }
1038
+ static asDpt27001(buffer) {
1039
+ // Leer los 4 octetos (32 bits)
1040
+ const binaryValue = buffer.readUInt32BE(0);
1041
+ // Decodificar los 16 bits de salidas (outputs)
1042
+ const outputs = [];
1043
+ for (let i = 0; i < 16; i++) {
1044
+ outputs.push(((binaryValue >> i) & 1) === 1); // Comprobar si el bit i es 1 (encendido)
1045
+ }
1046
+ // Decodificar los 16 bits de máscaras (masks)
1047
+ const masks = [];
1048
+ for (let i = 16; i < 32; i++) {
1049
+ masks.push(((binaryValue >> i) & 1) === 1); // Comprobar si el bit i es 1 (válido)
1050
+ }
1051
+ return { outputs, masks };
1052
+ }
1053
+ static asDpt28001(buffer) {
1054
+ const utf8Bytes = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
1055
+ // Convertir los bytes a una cadena de texto usando UTF-8
1056
+ const decodedString = new TextDecoder('utf-8').decode(utf8Bytes);
1057
+ // Retornar la cadena decodificada
1058
+ return decodedString;
1059
+ }
1060
+ static asDpt29(buffer) {
1061
+ const signedValue = buffer.readBigInt64BE(0);
1062
+ return Number(signedValue); // Convertir a número
1063
+ }
1064
+ static asDpt29010(buffer) {
1065
+ const signedValue = buffer.readBigInt64BE(0);
1066
+ return Number(signedValue); // Convertir a número
1067
+ }
1068
+ static asDpt29011(buffer) {
1069
+ const signedValue = buffer.readBigInt64BE(0);
1070
+ return Number(signedValue); // Convertir a número
1071
+ }
1072
+ static asDpt29012(buffer) {
1073
+ const signedValue = buffer.readBigInt64BE(0);
1074
+ return Number(signedValue); // Convertir a número
1075
+ }
1076
+ static asDpt232600(buffer) {
1077
+ const rgb = {
1078
+ R: buffer.readUInt8(0),
1079
+ G: buffer.readUInt8(1),
1080
+ B: buffer.readUInt8(2),
1081
+ };
1082
+ const result = {
1083
+ dataBuffer: buffer,
1084
+ rgb: rgb,
1085
+ };
1086
+ return result;
1087
+ }
1088
+ static asDpt238600(buffer) {
1089
+ const byte = buffer.readUInt8(0);
1090
+ // Decodificar los campos
1091
+ const addr = byte & 0x3f; // Los primeros 6 bits (b0 a b5) para la dirección del dispositivo
1092
+ const lf = (byte >> 6) & 0x01; // El bit b6 para fallo de lámpara
1093
+ const bf = (byte >> 7) & 0x01; // El bit b7 para fallo de balasto
1094
+ return {
1095
+ addr,
1096
+ lf: lf === 1,
1097
+ bf: bf === 1,
1098
+ };
1099
+ }
1100
+ static asDpt245600(buffer) {
1101
+ // Decodificar los valores de cada campo
1102
+ const LPDTR = buffer.readUInt8(0); // 8 bits LPDTR (último resultado PDT)
1103
+ // Los 8 bits siguientes contienen los campos SF, SD, SP, y LDTR
1104
+ const byte1 = buffer.readUInt8(1);
1105
+ const SF = (byte1 >> 0) & 0x03; // Los 2 primeros bits para SF
1106
+ const SD = (byte1 >> 2) & 0x03; // Los siguientes 2 bits para SD
1107
+ const SP = (byte1 >> 4) & 0x03; // Los siguientes 2 bits para SP
1108
+ const LDTR = (byte1 >> 6) & 0x3f; // Los 6 bits restantes para LDTR
1109
+ // Los 12 bits siguientes contienen los campos LTRF, LTRD y LTRP
1110
+ const byte2 = buffer.readUInt8(2);
1111
+ const LTRF = (byte2 >> 12) & 0x0f; // Primeros 4 bits para LTRF
1112
+ const LTRD = (byte2 >> 8) & 0x0f; // Siguientes 4 bits para LTRD
1113
+ const LTRP = (byte2 >> 4) & 0x0f; // Últimos 4 bits para LTRP
1114
+ return {
1115
+ LTRF: LTRF, // Resultado de la última prueba de función
1116
+ LTRD: LTRD, // Resultado de la última prueba de duración
1117
+ LTRP: LTRP, // Resultado de la última prueba parcial de duración
1118
+ SF: SF, // Método de inicio de la última prueba de función
1119
+ SD: SD, // Método de inicio de la última prueba de duración
1120
+ SP: SP, // Método de inicio de la última prueba parcial de duración
1121
+ LDTR: LDTR, // Tiempo de descarga de batería
1122
+ LPDTR: LPDTR, // Nivel de carga restante después de la última prueba PDT
1123
+ };
1124
+ }
1125
+ static asDpt250600(buffer) {
1126
+ // Decodificar el tercer octeto (last byte) para obtener los campos
1127
+ const byte3 = buffer.readUInt8(2);
1128
+ // r4B1U3r4B1U3B8
1129
+ const r4_1 = (byte3 >> 7) & 0x01; // r (bit 7)
1130
+ const r4_2 = (byte3 >> 6) & 0x01; // r (bit 6)
1131
+ const r4_3 = (byte3 >> 5) & 0x01; // r (bit 5)
1132
+ const r4_4 = (byte3 >> 4) & 0x01; // r (bit 4)
1133
+ const C = (byte3 >> 3) & 0x01; // C: Colour Temperature (bit 3)
1134
+ const StepCodeColourTemp = (byte3 >> 0) & 0x07; // Step Code Colour Temperature (bits 2-0)
1135
+ // Decodificar el segundo octeto
1136
+ const byte2 = buffer.readUInt8(1);
1137
+ const r4_5 = (byte2 >> 7) & 0x01; // r (bit 7)
1138
+ const r4_6 = (byte2 >> 6) & 0x01; // r (bit 6)
1139
+ const r4_7 = (byte2 >> 5) & 0x01; // r (bit 5)
1140
+ const r4_8 = (byte2 >> 4) & 0x01; // r (bit 4)
1141
+ const B = (byte2 >> 3) & 0x01; // Brightness (bit 3)
1142
+ const StepCodeBrightness = (byte2 >> 0) & 0x07; // Step Code Brightness (bits 2-0)
1143
+ // Decodificar el primer octeto
1144
+ const byte1 = buffer.readUInt8(0);
1145
+ // Los 6 bits más altos deben ser 0 (reservado)
1146
+ const reserved = (byte1 >> 2) & 0x3f; // Bits 7-2
1147
+ const validityColourTemp = (byte1 >> 1) & 0x01; // Validez de los campos CCT (bit 1)
1148
+ const validityBrightness = byte1 & 0x01; // Validez de los campos CB (bit 0)
1149
+ return {
1150
+ r4_1,
1151
+ r4_2,
1152
+ r4_3,
1153
+ r4_4, // r valores (bits 7 a 4)
1154
+ C, // Colour Temp Increase or Decrease (bit 3)
1155
+ StepCodeColourTemp, // Step Code for Colour Temp (bits 2-0)
1156
+ r4_5,
1157
+ r4_6,
1158
+ r4_7,
1159
+ r4_8, // r valores (bits 7 a 4) del segundo byte
1160
+ B, // Brightness Increase or Decrease (bit 3)
1161
+ StepCodeBrightness, // Step Code for Brightness (bits 2-0)
1162
+ reserved, // Bits reservados (bits 7-2)
1163
+ validityColourTemp, // Validación CCT (bit 1)
1164
+ validityBrightness, // Validación CB (bit 0)
1165
+ };
1166
+ }
1167
+ /**
1168
+ * DPT 251.600: DPT_Colour_RGBW
1169
+ * Decodifica un valor RGBW de 6 bytes con indicadores de validez.
1170
+ */
1171
+ static asDpt251600(buffer) {
1172
+ const red = buffer.readUInt8(0);
1173
+ const green = buffer.readUInt8(1);
1174
+ const blue = buffer.readUInt8(2);
1175
+ const white = buffer.readUInt8(3);
1176
+ // Octeto 5 es reservado y no se usa
1177
+ const validityBits = buffer.readUInt8(5); // Último octeto
1178
+ return {
1179
+ R: { value: red, valid: (validityBits & 0b00001000) !== 0 },
1180
+ G: { value: green, valid: (validityBits & 0b00000100) !== 0 },
1181
+ B: { value: blue, valid: (validityBits & 0b00000010) !== 0 },
1182
+ W: { value: white, valid: (validityBits & 0b00000001) !== 0 },
1183
+ };
1184
+ }
1185
+ }
1186
+ exports.KnxDataDecode = KnxDataDecode;