Initial commit.
This commit is contained in:
232
src/DPT1.ts
Normal file
232
src/DPT1.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT1 implements DPT {
|
||||
id = '1';
|
||||
name = '1-bit value';
|
||||
bufferLength = 1;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the on/off value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
const val = buffer.readUInt8(0);
|
||||
if (val !== 0 && val !== 1) {
|
||||
throw new InvalidValueError(`Invalid binary value ${val} for DPT1. Expected 1 or 0`);
|
||||
}
|
||||
return val;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (value !== 0 && value !== 1) {
|
||||
throw new InvalidValueError(`Invalid value ${value} for a DPT1. Should be 0 or 1.`);
|
||||
}
|
||||
const buf = Buffer.alloc(this.bufferLength);
|
||||
buf.writeUInt8(value, 0);
|
||||
return buf;
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 1.001 on/off
|
||||
'001': {
|
||||
use: 'G',
|
||||
name: 'DPT_Switch',
|
||||
desc: 'switch',
|
||||
enc: { 0: 'Off', 1: 'On' },
|
||||
},
|
||||
|
||||
// 1.002 boolean
|
||||
'002': {
|
||||
use: 'G',
|
||||
name: 'DPT_Bool',
|
||||
desc: 'bool',
|
||||
enc: { 0: 'false', 1: 'true' },
|
||||
},
|
||||
|
||||
// 1.003 enable
|
||||
'003': {
|
||||
use: 'G',
|
||||
name: 'DPT_Enable',
|
||||
desc: 'enable',
|
||||
enc: { 0: 'disable', 1: 'enable' },
|
||||
},
|
||||
|
||||
// 1.004 ramp
|
||||
'004': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Ramp',
|
||||
desc: 'ramp',
|
||||
enc: { 0: 'No ramp', 1: 'Ramp' },
|
||||
},
|
||||
|
||||
// 1.005 alarm
|
||||
'005': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Alarm',
|
||||
desc: 'alarm',
|
||||
enc: { 0: 'No alarm', 1: 'Alarm' },
|
||||
},
|
||||
|
||||
// 1.006 binary value
|
||||
'006': {
|
||||
use: 'FB',
|
||||
name: 'DPT_BinaryValue',
|
||||
desc: 'binary value',
|
||||
enc: { 0: 'Low', 1: 'High' },
|
||||
},
|
||||
|
||||
// 1.007 step
|
||||
'007': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Step',
|
||||
desc: 'step',
|
||||
enc: { 0: 'Decrease', 1: 'Increase' },
|
||||
},
|
||||
|
||||
// 1.008 up/down
|
||||
'008': {
|
||||
use: 'G',
|
||||
name: 'DPT_UpDown',
|
||||
desc: 'up/down',
|
||||
enc: { 0: 'Up', 1: 'Down' },
|
||||
},
|
||||
|
||||
// 1.009 open/close
|
||||
'009': {
|
||||
use: 'G',
|
||||
name: 'DPT_OpenClose',
|
||||
desc: 'open/close',
|
||||
enc: { 0: 'Open', 1: 'Close' },
|
||||
},
|
||||
|
||||
// 1.010 start/stop
|
||||
'010': {
|
||||
use: 'G',
|
||||
name: 'DPT_Start',
|
||||
desc: 'start/stop',
|
||||
enc: { 0: 'Stop', 1: 'Start' },
|
||||
},
|
||||
|
||||
// 1.011 state
|
||||
'011': {
|
||||
use: 'FB',
|
||||
name: 'DPT_State',
|
||||
desc: 'state',
|
||||
enc: { 0: 'Inactive', 1: 'Active' },
|
||||
},
|
||||
|
||||
// 1.012 invert
|
||||
'012': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Invert',
|
||||
desc: 'invert',
|
||||
enc: { 0: 'Not inverted', 1: 'inverted' },
|
||||
},
|
||||
|
||||
// 1.013 dim send style
|
||||
'013': {
|
||||
use: 'FB',
|
||||
name: 'DPT_DimSendStyle',
|
||||
desc: 'dim send style',
|
||||
enc: { 0: 'Start/stop', 1: 'Cyclically' },
|
||||
},
|
||||
|
||||
// 1.014 input source
|
||||
'014': {
|
||||
use: 'FB',
|
||||
name: 'DPT_InputSource',
|
||||
desc: 'input source',
|
||||
enc: { 0: 'Fixed', 1: 'Calculated' },
|
||||
},
|
||||
|
||||
// 1.015 reset
|
||||
'015': {
|
||||
use: 'G',
|
||||
name: 'DPT_Reset',
|
||||
desc: 'reset',
|
||||
enc: { 0: 'no action(dummy)', 1: 'reset command(trigger)' },
|
||||
},
|
||||
|
||||
// 1.016 acknowledge
|
||||
'016': {
|
||||
use: 'G',
|
||||
name: 'DPT_Ack',
|
||||
desc: 'ack',
|
||||
enc: { 0: 'no action(dummy)', 1: 'acknowledge command(trigger)' },
|
||||
},
|
||||
|
||||
// 1.017 trigger
|
||||
'017': {
|
||||
use: 'G',
|
||||
name: 'DPT_Trigger',
|
||||
desc: 'trigger',
|
||||
enc: { 0: 'trigger', 1: 'trigger' },
|
||||
},
|
||||
|
||||
// 1.018 occupied
|
||||
'018': {
|
||||
use: 'G',
|
||||
name: 'DPT_Occupancy',
|
||||
desc: 'occupancy',
|
||||
enc: { 0: 'not occupied', 1: 'occupied' },
|
||||
},
|
||||
|
||||
// 1.019 open window or door
|
||||
'019': {
|
||||
use: 'G',
|
||||
name: 'DPT_WindowDoor',
|
||||
desc: 'open window/door',
|
||||
enc: { 0: 'closed', 1: 'open' },
|
||||
},
|
||||
|
||||
// 1.021 and/or
|
||||
'021': {
|
||||
use: 'FB',
|
||||
name: 'DPT_LogicalFunction',
|
||||
desc: 'and/or',
|
||||
enc: { 0: 'logical function OR', 1: 'logical function AND' },
|
||||
},
|
||||
|
||||
// 1.022 scene A/B
|
||||
'022': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Scene_AB',
|
||||
desc: 'scene A/B',
|
||||
enc: { 0: 'scene A', 1: 'scene B' },
|
||||
},
|
||||
|
||||
// 1.023 shutter/blinds mode
|
||||
'023': {
|
||||
use: 'FB',
|
||||
name: 'DPT_ShutterBlinds_Mode',
|
||||
desc: 'shutter/blinds mode',
|
||||
enc: {
|
||||
0: 'only move Up/Down mode (shutter)',
|
||||
1: 'move Up/Down + StepStop mode (blind)',
|
||||
},
|
||||
},
|
||||
|
||||
// 1.100 cooling/heating ---FIXME---
|
||||
100: {
|
||||
use: '???',
|
||||
name: 'DPT_Heat/Cool',
|
||||
desc: 'heat/cool',
|
||||
enc: { 0: '???', 1: '???' },
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
92
src/DPT10.ts
Normal file
92
src/DPT10.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
const timeRegexp = /(\d{1,2}):(\d{1,2}):(\d{1,2})/;
|
||||
|
||||
export class DPT10 implements DPT {
|
||||
id = '10';
|
||||
name = 'day of week + time of day';
|
||||
bufferLength = 3;
|
||||
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): Date {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
const [dnh, minutes, seconds] = buffer;
|
||||
const dow = (dnh & 0b11100000) >> 5;
|
||||
const hours = dnh & 0b00011111;
|
||||
|
||||
if (hours < 0 || hours > 23)
|
||||
throw new InvalidValueError(`Hours out of range: Expected [0-23], got ${hours}`)
|
||||
if (minutes < 0 || minutes > 59)
|
||||
throw new InvalidValueError(`Minutes out of range: Expected [0-59], got ${minutes}`)
|
||||
if (seconds < 0 || seconds > 59)
|
||||
throw new InvalidValueError(`Seconds out of range: Expected [0-59], got ${seconds}`)
|
||||
|
||||
const d = new Date();
|
||||
if (d.getDay() !== dow)
|
||||
// adjust day of month to get the day of week right
|
||||
d.setDate(d.getDate() + dow - d.getDay());
|
||||
// TODO: Shouldn't this be UTCHours?
|
||||
d.setHours(hours, minutes, seconds);
|
||||
// reset the milliseconds
|
||||
d.setMilliseconds(0)
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: Date | number | string): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError(`Must supply a Date, number or String for DPT10 time.`);
|
||||
|
||||
let dow, hour, minute, second;
|
||||
// day of week. NOTE: JS Sunday = 0
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
// try to parse
|
||||
let match = timeRegexp.exec(value);
|
||||
if (match) {
|
||||
dow = ((new Date().getDay() - 7) % 7) + 7;
|
||||
hour = parseInt(match[1]);
|
||||
minute = parseInt(match[2]);
|
||||
second = parseInt(match[3]);
|
||||
} else {
|
||||
throw new InvalidValueError(`DPT10: invalid time format (${value})`);
|
||||
}
|
||||
break;
|
||||
case 'number':
|
||||
value = new Date(value);
|
||||
default:
|
||||
dow = ((value.getDay() - 7) % 7) + 7;
|
||||
hour = value.getHours();
|
||||
minute = value.getMinutes();
|
||||
second = value.getSeconds();
|
||||
}
|
||||
|
||||
return Buffer.from([(dow << 5) + hour, minute, second]);
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// 10.001 time of day
|
||||
'001': {
|
||||
name: 'DPT_TimeOfDay',
|
||||
desc: 'time of day',
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
77
src/DPT11.ts
Normal file
77
src/DPT11.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT11 implements DPT {
|
||||
id = '11';
|
||||
name = '3-byte date value';
|
||||
bufferLength = 3;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): Date {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
const day = buffer[0] & 31; //0b00011111);
|
||||
const month = buffer[1] & 15; //0b00001111);
|
||||
let year = buffer[2] & 127; //0b01111111);
|
||||
year = year + (year > 89 ? 1900 : 2000);
|
||||
if (
|
||||
day < 1 ||
|
||||
day > 31 ||
|
||||
month < 1 ||
|
||||
month > 12 ||
|
||||
year < 1990 ||
|
||||
year > 2089
|
||||
) {
|
||||
throw new InvalidValueError(`${buffer} => ${day}/${month}/${year} is not valid date according to DPT11, setting to 1990/01/01`);
|
||||
}
|
||||
return new Date(year, month - 1, day);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: Date | string): Buffer {
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
case 'number':
|
||||
value = new Date(value);
|
||||
break;
|
||||
case 'object':
|
||||
// this expects the month property to be zero-based (January = 0, etc.)
|
||||
if (value instanceof Date) break;
|
||||
const { year, month, day } = value;
|
||||
value = new Date(parseInt(year), parseInt(month), parseInt(day));
|
||||
}
|
||||
|
||||
if (isNaN(value.getDate()))
|
||||
throw new InvalidValueError('Must supply a numeric timestamp, Date or String object for DPT11 Date')
|
||||
|
||||
const year = value.getFullYear();
|
||||
return Buffer.from([
|
||||
value.getDate(),
|
||||
value.getMonth() + 1,
|
||||
year - (year >= 2000 ? 2000 : 1900),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// 11.001 date
|
||||
'001': {
|
||||
name: 'DPT_Date',
|
||||
desc: 'Date',
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
48
src/DPT12.ts
Normal file
48
src/DPT12.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
import { buffer } from 'stream/consumers';
|
||||
|
||||
export class DPT12 implements DPT {
|
||||
id = '12';
|
||||
name = '4-byte unsigned value';
|
||||
bufferLength = 4
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
return buffer.readUInt32BE(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (!value)
|
||||
throw new InvalidValueError('Cannot write null value');
|
||||
|
||||
let result = Buffer.alloc(this.bufferLength)
|
||||
result.writeUInt32BE(value)
|
||||
return result;
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 12.001 counter pulses
|
||||
"001": {
|
||||
"name": "DPT_Value_4_Ucount",
|
||||
"desc": "counter pulses"
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
102
src/DPT13.ts
Normal file
102
src/DPT13.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT13 implements DPT {
|
||||
id = '13';
|
||||
name = '4-byte signed value';
|
||||
bufferLength = 4;
|
||||
range = [-Math.pow(2, 31), Math.pow(2, 31) - 1]
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
// In 4 bytes, there's no way to exceed the range
|
||||
return buffer.readInt32BE(0)
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
|
||||
if (value === undefined || value === null || Number.isFinite(value))
|
||||
throw new InvalidValueError(`Value is not viable`)
|
||||
if (Number.isInteger(value))
|
||||
throw new InvalidValueError(`Value ${value} is not an integer`)
|
||||
|
||||
if (value < this.range[0] || value > this.range[1])
|
||||
throw new InvalidValueError(`Value ${value} is out of range`)
|
||||
|
||||
let result = Buffer.alloc(this.bufferLength)
|
||||
result.writeInt32BE(value)
|
||||
return result;
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 13.001 counter pulses (signed)
|
||||
"001": {
|
||||
"name": "DPT_Value_4_Count", "desc": "counter pulses (signed)",
|
||||
"unit": "pulses"
|
||||
},
|
||||
|
||||
"002": {
|
||||
"name": "DPT_Value_Activation_Energy", "desc": "activation energy (J/mol)",
|
||||
"unit": "J/mol"
|
||||
},
|
||||
|
||||
// 13.010 active energy (Wh)
|
||||
"010": {
|
||||
"name": "DPT_ActiveEnergy", "desc": "active energy (Wh)",
|
||||
"unit": "Wh"
|
||||
},
|
||||
|
||||
// 13.011 apparent energy (VAh)
|
||||
"011": {
|
||||
"name": "DPT_ApparantEnergy", "desc": "apparent energy (VAh)",
|
||||
"unit": "VAh"
|
||||
},
|
||||
|
||||
// 13.012 reactive energy (VARh)
|
||||
"012": {
|
||||
"name": "DPT_ReactiveEnergy", "desc": "reactive energy (VARh)",
|
||||
"unit": "VARh"
|
||||
},
|
||||
|
||||
// 13.013 active energy (KWh)
|
||||
"013": {
|
||||
"name": "DPT_ActiveEnergy_kWh", "desc": "active energy (kWh)",
|
||||
"unit": "kWh"
|
||||
},
|
||||
|
||||
// 13.014 apparent energy (kVAh)
|
||||
"014": {
|
||||
"name": "DPT_ApparantEnergy_kVAh", "desc": "apparent energy (kVAh)",
|
||||
"unit": "VAh"
|
||||
},
|
||||
|
||||
// 13.015 reactive energy (kVARh)
|
||||
"015": {
|
||||
"name": "DPT_ReactiveEnergy_kVARh", "desc": "reactive energy (kVARh)",
|
||||
"unit": "kVARh"
|
||||
},
|
||||
|
||||
// 13.100 time lag(s)
|
||||
"100": {
|
||||
"name": "DPT_LongDeltaTimeSec", "desc": "time lag(s)",
|
||||
"unit": "s"
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
169
src/DPT14.ts
Normal file
169
src/DPT14.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT14 implements DPT {
|
||||
id = '14';
|
||||
name = '32-bit floating point value';
|
||||
bufferLength = 4;
|
||||
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
return buffer.readFloatBE(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (!value || typeof value != 'number')
|
||||
throw new InvalidValueError(`Invalid value [${value}]`)
|
||||
const apdu_data = Buffer.alloc(this.bufferLength);
|
||||
apdu_data.writeFloatBE(value, 0);
|
||||
return apdu_data;
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// TODO
|
||||
'007': {
|
||||
name: 'DPT_Value_AngleDeg°',
|
||||
desc: 'angle, degree',
|
||||
unit: '°',
|
||||
},
|
||||
|
||||
'019': {
|
||||
name: 'DPT_Value_Electric_Current',
|
||||
desc: 'electric current',
|
||||
unit: 'A',
|
||||
},
|
||||
|
||||
'027': {
|
||||
name: 'DPT_Value_Electric_Potential',
|
||||
desc: 'electric potential',
|
||||
unit: 'V',
|
||||
},
|
||||
|
||||
'028': {
|
||||
name: 'DPT_Value_Electric_PotentialDifference',
|
||||
desc: 'electric potential difference',
|
||||
unit: 'V',
|
||||
},
|
||||
|
||||
'031': {
|
||||
name: 'DPT_Value_Energ',
|
||||
desc: 'energy',
|
||||
unit: 'J',
|
||||
},
|
||||
|
||||
'032': {
|
||||
name: 'DPT_Value_Force',
|
||||
desc: 'force',
|
||||
unit: 'N',
|
||||
},
|
||||
|
||||
'033': {
|
||||
name: 'DPT_Value_Frequency',
|
||||
desc: 'frequency',
|
||||
unit: 'Hz',
|
||||
},
|
||||
|
||||
'036': {
|
||||
name: 'DPT_Value_Heat_FlowRate',
|
||||
desc: 'heat flow rate',
|
||||
unit: 'W',
|
||||
},
|
||||
|
||||
'037': {
|
||||
name: 'DPT_Value_Heat_Quantity',
|
||||
desc: 'heat, quantity of',
|
||||
unit: 'J',
|
||||
},
|
||||
|
||||
'038': {
|
||||
name: 'DPT_Value_Impedance',
|
||||
desc: 'impedance',
|
||||
unit: 'Ω',
|
||||
},
|
||||
|
||||
'039': {
|
||||
name: 'DPT_Value_Length',
|
||||
desc: 'length',
|
||||
unit: 'm',
|
||||
},
|
||||
|
||||
'051': {
|
||||
name: 'DPT_Value_Mass',
|
||||
desc: 'mass',
|
||||
unit: 'kg',
|
||||
},
|
||||
|
||||
'056': {
|
||||
name: 'DPT_Value_Power',
|
||||
desc: 'power',
|
||||
unit: 'W',
|
||||
},
|
||||
|
||||
'065': {
|
||||
name: 'DPT_Value_Speed',
|
||||
desc: 'speed',
|
||||
unit: 'm/s',
|
||||
},
|
||||
|
||||
'066': {
|
||||
name: 'DPT_Value_Stress',
|
||||
desc: 'stress',
|
||||
unit: 'Pa',
|
||||
},
|
||||
|
||||
'067': {
|
||||
name: 'DPT_Value_Surface_Tension',
|
||||
desc: 'surface tension',
|
||||
unit: '1/Nm',
|
||||
},
|
||||
|
||||
'068': {
|
||||
name: 'DPT_Value_Common_Temperature',
|
||||
desc: 'temperature, common',
|
||||
unit: '°C',
|
||||
},
|
||||
|
||||
'069': {
|
||||
name: 'DPT_Value_Absolute_Temperature',
|
||||
desc: 'temperature (absolute)',
|
||||
unit: 'K',
|
||||
},
|
||||
|
||||
'070': {
|
||||
name: 'DPT_Value_TemperatureDifference',
|
||||
desc: 'temperature difference',
|
||||
unit: 'K',
|
||||
},
|
||||
|
||||
'078': {
|
||||
name: 'DPT_Value_Weight',
|
||||
desc: 'weight',
|
||||
unit: 'N',
|
||||
},
|
||||
|
||||
'079': {
|
||||
name: 'DPT_Value_Work',
|
||||
desc: 'work',
|
||||
unit: 'J',
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
100
src/DPT15.ts
Normal file
100
src/DPT15.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
/**
|
||||
* U 4 bit
|
||||
* V 4 bit
|
||||
* W 4 bit
|
||||
* X 4 bit
|
||||
* Y 4 bit
|
||||
* Z 4 bit
|
||||
* E 1 bit
|
||||
* P 1 bit
|
||||
* D 1 bit
|
||||
* C 1 bit
|
||||
* N 4 bit
|
||||
*
|
||||
* U,V,W,X,Y,Z = [0 … 9]; E,P,D,C = {0,1}; N = [0 … 15]
|
||||
*
|
||||
* Source: https://www.promotic.eu/en/pmdoc/Subsystems/Comm/PmDrivers/KNXDTypes.htm
|
||||
*/
|
||||
export interface DPT15Result {
|
||||
U: number
|
||||
V: number
|
||||
W: number
|
||||
X: number
|
||||
Y: number
|
||||
Z: number
|
||||
E: number
|
||||
P: number
|
||||
D: number
|
||||
C: number
|
||||
N: number
|
||||
}
|
||||
export class DPT15 implements DPT {
|
||||
id = '';
|
||||
name = '4-byte access control data';
|
||||
bufferLength = 4;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): DPT15Result {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
const result: DPT15Result = {
|
||||
U: (buffer[0] & 0xf0) >> 4,
|
||||
V: (buffer[0] & 0x0f),
|
||||
W: (buffer[1] & 0xf0) >> 4,
|
||||
X: (buffer[1] & 0x0f),
|
||||
Y: (buffer[2] & 0xf0) >> 4,
|
||||
Z: (buffer[2] & 0x0f),
|
||||
E: (buffer[3] >> 7) & 0x01,
|
||||
P: (buffer[3] >> 6) & 0x01,
|
||||
D: (buffer[3] >> 5) & 0x01,
|
||||
C: (buffer[3] >> 4) & 0x01,
|
||||
N: (buffer[3] & 0x0f),
|
||||
}
|
||||
|
||||
if (Math.max(result.U, result.V, result.W, result.X, result.Y, result.Z) > 9)
|
||||
throw new InvalidValueError(`Value must be < 9 (U: ${result.U}, V: ${result.V}, W: ${result.W}, X: ${result.X}, y: ${result.Y}, Z: ${result.Z})`)
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: DPT15Result): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError(`Invalid value [${value}]`)
|
||||
|
||||
if (Math.max(value.U, value.V, value.W, value.X, value.Y, value.Z) > 9)
|
||||
throw new InvalidValueError(`Value must be < 9 (U: ${value.U}, V: ${value.V}, W: ${value.W}, X: ${value.X}, y: ${value.Y}, Z: ${value.Z})`)
|
||||
|
||||
const apdu_data = Buffer.alloc(this.bufferLength);
|
||||
apdu_data.writeUInt8((value.U << 4) + value.V, 0);
|
||||
apdu_data.writeUInt8((value.W << 4) + value.X, 1);
|
||||
apdu_data.writeUInt8((value.Y << 4) + value.Z, 2);
|
||||
apdu_data.writeUInt8((value.E << 7) + (value.P << 6) + (value.D << 5) + (value.C << 4) + value.N, 3);
|
||||
return apdu_data;
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
"000": {
|
||||
name: "DPT_Access_Data",
|
||||
desc: "default field"
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
59
src/DPT16.ts
Normal file
59
src/DPT16.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT16 implements DPT {
|
||||
id = '16';
|
||||
name = '14-character string';
|
||||
bufferLength = 14;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): string {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
|
||||
return buffer.toString('ascii');
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: string): Buffer {
|
||||
if (typeof value !== 'string')
|
||||
throw new InvalidValueError('Must supply a string value')
|
||||
|
||||
const buf = Buffer.alloc(14);
|
||||
buf.write(value, 'ascii');
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// 16.000 ASCII string
|
||||
'000': {
|
||||
use: 'G',
|
||||
name: 'DPT_String_ASCII',
|
||||
desc: 'ASCII string',
|
||||
force_encoding: 'US-ASCII',
|
||||
},
|
||||
|
||||
// 16.001 ISO-8859-1 string
|
||||
'001': {
|
||||
use: 'G',
|
||||
name: 'DPT_String_8859_1',
|
||||
desc: 'ISO-8859-1 string',
|
||||
force_encoding: 'ISO-8859-1',
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
52
src/DPT17.ts
Normal file
52
src/DPT17.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT17 implements DPT {
|
||||
id = '17';
|
||||
name = 'scene number';
|
||||
bufferLength = 1;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
// Scene number between 0 and 63
|
||||
return buffer.readUInt8(0) & 0b00111111;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError(`Invalid value [${value}]`)
|
||||
|
||||
if (value > 63)
|
||||
throw new InvalidValueError(`Expected scene number [0, 63]. Got [${value}]`)
|
||||
|
||||
let buf = Buffer.alloc(this.bufferLength)
|
||||
buf.writeUInt8(value, 0)
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// 17.001 Scene number
|
||||
"001": {
|
||||
use: "G",
|
||||
name: "DPT_SceneNumber", desc: "Scene Number",
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
62
src/DPT18.ts
Normal file
62
src/DPT18.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export interface DPT18Result {
|
||||
activateLearn: number
|
||||
// pad: number // reserved
|
||||
sceneNumber: number
|
||||
}
|
||||
export class DPT18 implements DPT {
|
||||
id = '18';
|
||||
name = '8-bit Scene Activate/Learn + number';
|
||||
bufferLength = 1;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): DPT18Result {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
|
||||
return {
|
||||
activateLearn: (buffer[0] & 0b10000000) >> 7,
|
||||
sceneNumber: buffer[0] & 0b00111111
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: DPT18Result): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError(`Invalid value [${value}]`)
|
||||
|
||||
if (value.sceneNumber > 63)
|
||||
throw new InvalidValueError(`Expected scene number [0..63]. Got [${value.sceneNumber}]`)
|
||||
|
||||
if (value.activateLearn > 1)
|
||||
throw new InvalidValueError(`Expected scene number [0, 1]. Got [${value.activateLearn}]`)
|
||||
|
||||
let buf = Buffer.alloc(this.bufferLength)
|
||||
buf.writeUInt8((value.activateLearn << 7) + value.sceneNumber)
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// 9.001 temperature (oC)
|
||||
"001": {
|
||||
name: "DPT_SceneControl", desc: "scene control"
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
226
src/DPT19.ts
Normal file
226
src/DPT19.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
/**
|
||||
* <strong>19.001</strong> Date & Time
|
||||
*
|
||||
* <pre>
|
||||
* +-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+
|
||||
* Field Names | (Year) | 0 0 0 0 (Month) |
|
||||
* Encoding | U U U U U U U U | r r r r U U U U |
|
||||
* +-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+
|
||||
* | 0 0 0 (Day Of Month) | (DayOfWeek) (Hour) |
|
||||
* | r r r U U U U U | U U U U U U U U |
|
||||
* +-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+
|
||||
* | 0 0 (Minutes) | 0 0 (Seconds) |
|
||||
* | r r U U U U U U | r r U U U U U U |
|
||||
* +-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+
|
||||
* | F WD NWD NY ND NDoW NT SST| CLQ SRC 0 0 0 0 0 0 |
|
||||
* | B B B B B B B B | B B r r r r r r |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* Format: 8 octets (U<sub>8</sub> [r<sub>4</sub>U<sub>4</sub>] [r<sub>3</sub>U<sub>5</sub>] [r<sub>3</sub>U<sub>5</sub>] [r<sub>2</sub>U<sub>6</sub>] [r<sub>2</sub>U<sub>6</sub>] B<sub>16</sub>)
|
||||
* Encoding:
|
||||
* Year = [0 .. 255]
|
||||
* 0 = year 1900
|
||||
* 255 = year 2155
|
||||
* Month = [1 .. 12]
|
||||
* DayOfMonth = [1 .. 31]
|
||||
* DayOfWeek = [0 .. 7]
|
||||
* 1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 = Thursday, 5 = Friday, 6 = Saturday, 7 = Sunday, 0 = any day
|
||||
* Hour = [0 .. 24]
|
||||
* Minutes = [0 .. 59]
|
||||
* Seconds = [0 .. 59]
|
||||
* (F) Fault = {0, 1}
|
||||
* 0 = Normal (no fault)
|
||||
* 1 = Fault
|
||||
* (WD) WorkingDay = {0, 1}
|
||||
* 0 = No Working Day
|
||||
* 1 = Working Day
|
||||
* (NWD) NoWorkingDay = {0, 1}
|
||||
* 0 = WorkingDay field valid
|
||||
* 1 = WorkingDay field not valid
|
||||
* (NY) NoYear = {0, 1}
|
||||
* 0 = Year field valid
|
||||
* 1 = Year field not valid
|
||||
* (ND) NoDate = {0, 1}
|
||||
* 0 = Month and DayOfMonth fields valid
|
||||
* 1 = Month and DayOfMonth fields not valid
|
||||
* (NDoW) NoDayOfWeek = {0, 1}
|
||||
* 0 = DayOfWeek field valid
|
||||
* 1 = DayOfWeek field not valid
|
||||
* (NT) NoTime = {0, 1}
|
||||
* 0 = Hour, Minutes and Seconds valid
|
||||
* 1 = Hour, Minutes and Seconds not valid
|
||||
* (SST) Standard Summer Time = {0, 1}
|
||||
* 0 = UTC+x (standard time)
|
||||
* 1 = UTC+x +1h (summer daylight saving time)
|
||||
* (CLQ) QualityOfClock = {0, 1}
|
||||
* 0 = Clock without external synchronization signal
|
||||
* 1 = Clock with external synchronization signal (DCF 77, VideoText, ...)
|
||||
* (SRC) SynchronisationSourceReliability = {0, 1}
|
||||
* 0 = Unreliable Synchronisation (mains, local quartz)
|
||||
* 1 = Reliable Synchronisation (radio, internet)
|
||||
* </pre>
|
||||
* <p>
|
||||
* The encoding of the hour is within the range [0 .. 24] instead of [0 .. 23]. When the hour is set to "24", the
|
||||
* values of octet 3 (Minutes) and 2 (Seconds) have to be set to zero.
|
||||
* <p>
|
||||
* "Fault" is set if one ore more supported fields of the Date & Time information are corrupted. "Fault" is set e.g.
|
||||
* power-down if battery backup was not sufficient, after 1st start up of device (clock un-configured) or radio-clock
|
||||
* (DCF 77) had no reception for a very long time. "Fault" is usually cleared automatically by the device if the
|
||||
* local clock is set or clock data is refreshed
|
||||
* <p>
|
||||
* The receiver (e.g. a room unit, MMI) will interpret Date&Time with "Fault" as corrupted and will either ignore
|
||||
* the message or show --:--:-- or blinking 00:00:00 (as known from Video recorders after power-up).
|
||||
*/
|
||||
export class DPT19Result {
|
||||
dateTime: Date = new Date()
|
||||
dayOfWeek: number = undefined
|
||||
f: boolean = false
|
||||
wd: boolean = false
|
||||
nwd: boolean = false
|
||||
ny: boolean = false
|
||||
nd: boolean = false
|
||||
ndow: boolean = false
|
||||
nt: boolean = false
|
||||
sst: boolean = false
|
||||
internalClock: boolean = true // Assume external clock
|
||||
reliability: boolean = false;
|
||||
}
|
||||
export class DPT19 implements DPT {
|
||||
id = '19';
|
||||
name = '8-byte Date+Time';
|
||||
bufferLength = 8;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): DPT19Result {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
const byte8 = buffer.readUInt8(0)
|
||||
const byte7 = buffer.readUInt8(1)
|
||||
const byte6 = buffer.readUInt8(2)
|
||||
const byte5 = buffer.readUInt8(3)
|
||||
const byte4 = buffer.readUInt8(4)
|
||||
const byte3 = buffer.readUInt8(5)
|
||||
const byte2 = buffer.readUInt8(6)
|
||||
const byte1 = buffer.readUInt8(7)
|
||||
|
||||
let year = byte8
|
||||
let month = byte7 & 0xF
|
||||
const dayOfMonth = byte6 & 0x1F
|
||||
let dayOfWeek = byte5 >> 5
|
||||
const hourOfDay = byte5 & 0x1F
|
||||
const minutes = byte4 & 0x3F
|
||||
const seconds = byte3 & 0x3F
|
||||
const f = !!(byte2 & 0x80)
|
||||
const wd = !!(byte2 & 0x40)
|
||||
const nwd = !!(byte2 & 0x20)
|
||||
const ny = !!(byte2 & 0x10)
|
||||
const nd = !!(byte2 & 0x8)
|
||||
const ndow = !!(byte2 & 0x4)
|
||||
const nt = !!(byte2 & 0x2)
|
||||
const suti = !!(byte2 & 0x1)
|
||||
const clq = !!(byte1 & 0x80)
|
||||
const reliability = !!(byte1 & 0x40)
|
||||
|
||||
year += 1900
|
||||
|
||||
// Convert month from knx to JavaScript (12 => 11, 11 => 10, ...)
|
||||
month -= 1
|
||||
|
||||
// Convert day of week from knx to JavaScript (7 => 0, 0 => undefined)
|
||||
if (dayOfWeek === 7) {
|
||||
dayOfWeek = 0
|
||||
} else if (dayOfWeek === 0) {
|
||||
dayOfWeek = undefined
|
||||
}
|
||||
|
||||
// Check minutes and seconds if hours equals 24
|
||||
if (hourOfDay === 24 && (minutes !== 0 || seconds !== 0)) {
|
||||
throw new RangeError('Invalid time (hour of day is 24, but minutes or seconds are not 0)')
|
||||
}
|
||||
|
||||
return {
|
||||
dateTime: new Date(year, month, dayOfMonth, hourOfDay, minutes, seconds),
|
||||
dayOfWeek: dayOfWeek,
|
||||
f: f,
|
||||
wd: wd,
|
||||
nwd: nwd,
|
||||
ny: ny,
|
||||
nd: nd,
|
||||
ndow: ndow,
|
||||
nt: nt,
|
||||
sst: suti,
|
||||
internalClock: clq,
|
||||
reliability: reliability
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: DPT19Result | Date): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError(`Invalid value [${value}]`)
|
||||
|
||||
let temp: DPT19Result;
|
||||
|
||||
if (value.constructor.name === 'Date') {
|
||||
temp = new DPT19Result()
|
||||
temp.dateTime = value as Date
|
||||
temp.dayOfWeek = (value as Date).getDay()
|
||||
} else {
|
||||
temp = value as DPT19Result
|
||||
}
|
||||
|
||||
let dayOfWeek = temp.dayOfWeek
|
||||
const f = !!temp.f ? 1 : 0
|
||||
const wd = !!temp.wd ? 1 : 0
|
||||
const nwd = !!temp.nwd ? 1 : 0
|
||||
const ny = !!temp.ny ? 1 : 0
|
||||
const nd = !!temp.nd ? 1 : 0
|
||||
const ndow = !!temp.ndow ? 1 : 0
|
||||
const nt = !!temp.nt ? 1 : 0
|
||||
const sst = !!temp.sst ? 1 : 0
|
||||
const clq = !!temp.internalClock ? 1 : 0
|
||||
const reliability = !!temp.reliability ? 1 : 0
|
||||
|
||||
// Convert day of week from JavaScript to knx (0 => 7, undefined => 0)
|
||||
if (typeof dayOfWeek === 'undefined') {
|
||||
dayOfWeek = 0
|
||||
} else if (dayOfWeek === 0) {
|
||||
dayOfWeek = 7
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(8, 0)
|
||||
buffer.writeUInt8(temp.dateTime.getFullYear() - 1900, 0)
|
||||
buffer.writeUInt8(temp.dateTime.getMonth() + 1, 1)
|
||||
buffer.writeUInt8(temp.dateTime.getDate(), 2)
|
||||
buffer.writeUInt8((dayOfWeek << 5) | temp.dateTime.getHours(), 3)
|
||||
buffer.writeUInt8(temp.dateTime.getMinutes(), 4)
|
||||
buffer.writeUInt8(temp.dateTime.getSeconds(), 5)
|
||||
buffer.writeUInt8((f << 7) | (wd << 6) | (nwd << 5) | (ny << 4) | (nd << 3) | (ndow << 2) | (nt << 1) | sst, 6)
|
||||
buffer.writeUInt8(clq << 7 | reliability << 6, 7)
|
||||
|
||||
return buffer
|
||||
}
|
||||
subtypes: {
|
||||
// 19.001
|
||||
'001': {
|
||||
name: 'DPT_DateTime',
|
||||
desc: 'datetime',
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
140
src/DPT2.ts
Normal file
140
src/DPT2.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export interface DPT2Result {
|
||||
priority: boolean;
|
||||
data: boolean;
|
||||
}
|
||||
|
||||
export class DPT2 implements DPT {
|
||||
id = '2';
|
||||
name = '1-bit value with priority';
|
||||
bufferLength = 1;
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): DPT2Result {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
const value = buffer.readUInt8(0)
|
||||
return {
|
||||
priority: ((value & 0b00000010) >> 1) === 1,
|
||||
data: (value & 0b00000001) === 1,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: DPT2Result): Buffer {
|
||||
if (!value) throw new InvalidValueError('DPT2: cannot write null value');
|
||||
|
||||
return Buffer.from([((value.priority ? 1 : 0) << 1) + ((value.data ? 1 : 0) & 0b00000001)]);
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 2.001 switch control
|
||||
'001': {
|
||||
use: 'G',
|
||||
name: 'DPT_Switch_Control',
|
||||
desc: 'switch with priority',
|
||||
enc: { 0: 'Off', 1: 'On' },
|
||||
},
|
||||
// 2.002 boolean control
|
||||
'002': {
|
||||
use: 'G',
|
||||
name: 'DPT_Bool_Control',
|
||||
desc: 'boolean with priority',
|
||||
enc: { 0: 'false', 1: 'true' },
|
||||
},
|
||||
// 2.003 enable control
|
||||
'003': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Emable_Control',
|
||||
desc: 'enable with priority',
|
||||
enc: { 0: 'Disabled', 1: 'Enabled' },
|
||||
},
|
||||
|
||||
// 2.004 ramp control
|
||||
'004': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Ramp_Control',
|
||||
desc: 'ramp with priority',
|
||||
enc: { 0: 'No ramp', 1: 'Ramp' },
|
||||
},
|
||||
|
||||
// 2.005 alarm control
|
||||
'005': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Alarm_Control',
|
||||
desc: 'alarm with priority',
|
||||
enc: { 0: 'No alarm', 1: 'Alarm' },
|
||||
},
|
||||
|
||||
// 2.006 binary value control
|
||||
'006': {
|
||||
use: 'FB',
|
||||
name: 'DPT_BinaryValue_Control',
|
||||
desc: 'binary value with priority',
|
||||
enc: { 0: 'Off', 1: 'On' },
|
||||
},
|
||||
|
||||
// 2.007 step control
|
||||
'007': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Step_Control',
|
||||
desc: 'step with priority',
|
||||
enc: { 0: 'Off', 1: 'On' },
|
||||
},
|
||||
|
||||
// 2.008 Direction1 control
|
||||
'008': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Direction1_Control',
|
||||
desc: 'direction 1 with priority',
|
||||
enc: { 0: 'Off', 1: 'On' },
|
||||
},
|
||||
|
||||
// 2.009 Direction2 control
|
||||
'009': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Direction2_Control',
|
||||
desc: 'direction 2 with priority',
|
||||
enc: { 0: 'Off', 1: 'On' },
|
||||
},
|
||||
|
||||
// 2.010 start control
|
||||
'010': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Start_Control',
|
||||
desc: 'start with priority',
|
||||
enc: { 0: 'No control', 1: 'No control', 2: 'Off', 3: 'On' },
|
||||
},
|
||||
|
||||
// 2.011 state control
|
||||
'011': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Switch_Control',
|
||||
desc: 'switch',
|
||||
enc: { 0: 'No control', 1: 'No control', 2: 'Off', 3: 'On' },
|
||||
},
|
||||
|
||||
// 2.012 invert control
|
||||
'012': {
|
||||
use: 'FB',
|
||||
name: 'DPT_Switch_Control',
|
||||
desc: 'switch',
|
||||
enc: { 0: 'No control', 1: 'No control', 2: 'Off', 3: 'On' },
|
||||
},
|
||||
};
|
||||
}
|
||||
94
src/DPT20.ts
Normal file
94
src/DPT20.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
/**
|
||||
* Original at https://github.com/pitschr/knx-core/blob/main/src/main/java/li/pitschmann/knx/core/datapoint/DPT20.java
|
||||
*
|
||||
* Data Point Type 20 for '8-Bit Enumeration' (1 Octet)
|
||||
*
|
||||
* <pre>
|
||||
* +-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+
|
||||
* Field Names | (Field 1) |
|
||||
* Encoding | N N N N N N N N |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* Format: 8 bit (N<sub>8</sub>)
|
||||
* </pre>
|
||||
*/
|
||||
export class DPT20 implements DPT {
|
||||
id = '20';
|
||||
name = '8-Bit Enumeration';
|
||||
bufferLength = 1;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
return buffer.readUInt8(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError(`Invalid value [${value}]`)
|
||||
|
||||
return Buffer.from([value & 0xff])
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// 20.001 SCLO Mode
|
||||
1: {
|
||||
name: 'SCLO_Mode',
|
||||
desc: '',
|
||||
unit: '',
|
||||
scalar_range: {
|
||||
0: 'Autonomous',
|
||||
1: 'Slave',
|
||||
2: 'Master'
|
||||
},
|
||||
range: undefined,
|
||||
},
|
||||
|
||||
// 20.001 Building Mode
|
||||
2: {
|
||||
name: 'Building_Mode',
|
||||
desc: '',
|
||||
unit: '',
|
||||
scalar_range: {
|
||||
0: 'Building in use',
|
||||
1: 'Building not used',
|
||||
2: 'Building protection'
|
||||
},
|
||||
range: undefined,
|
||||
},
|
||||
|
||||
// 20.102 HVAC mode
|
||||
102: {
|
||||
name: 'HVAC_Mode',
|
||||
desc: '',
|
||||
unit: '',
|
||||
scalar_range: {
|
||||
0: 'Auto',
|
||||
1: 'Comfort',
|
||||
2: 'Standby',
|
||||
3: 'Economy',
|
||||
4: 'Building protection'
|
||||
},
|
||||
range: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
101
src/DPT21.ts
Normal file
101
src/DPT21.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
/**
|
||||
* Original at https://github.com/pitschr/knx-core/blob/main/src/main/java/li/pitschmann/knx/core/datapoint/DPT21.java
|
||||
* * Data Point Type 21 for 8-Bits flagged messages
|
||||
*
|
||||
* <pre>
|
||||
* +-7-+-6-+-5-+-4-+-3-+-2-+-1-+-0-+
|
||||
* Field Names | b b b b b b b b |
|
||||
* Encoding | B B B B B B B B |
|
||||
* +---+---+---+---+---+---+---+---+
|
||||
* Format: 8 bits (B<sub>8</sub>)
|
||||
* </pre>
|
||||
*/
|
||||
export class DPT21 implements DPT {
|
||||
id = '';
|
||||
name = '';
|
||||
bufferLength = 0;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): boolean[] {
|
||||
if (buffer.length !== 2)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected 2.`);
|
||||
|
||||
const result = [
|
||||
!!(buffer[0] & 0x80),
|
||||
!!(buffer[0] & 0x40),
|
||||
!!(buffer[0] & 0x20),
|
||||
!!(buffer[0] & 0x10),
|
||||
!!(buffer[0] & 0x08),
|
||||
!!(buffer[0] & 0x04),
|
||||
!!(buffer[0] & 0x02),
|
||||
!!(buffer[0] & 0x01),
|
||||
]
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: boolean[]): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError(`Invalid value [${value}]`)
|
||||
|
||||
if (value.length != 8)
|
||||
throw new InvalidValueError(`Value length should be 8. Got ${value.length}.`)
|
||||
|
||||
const b7 = value[0] ? 1 : 0
|
||||
const b6 = value[0] ? 1 : 0
|
||||
const b5 = value[0] ? 1 : 0
|
||||
const b4 = value[0] ? 1 : 0
|
||||
const b3 = value[0] ? 1 : 0
|
||||
const b2 = value[0] ? 1 : 0
|
||||
const b1 = value[0] ? 1 : 0
|
||||
const b0 = value[0] ? 1 : 0
|
||||
|
||||
const buf = Buffer.from([
|
||||
b7 << 7 |
|
||||
b6 << 6 |
|
||||
b5 << 5 |
|
||||
b4 << 4 |
|
||||
b3 << 3 |
|
||||
b2 << 2 |
|
||||
b1 << 1 |
|
||||
b0
|
||||
])
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// 21.001 status - 5 bits
|
||||
"001": {
|
||||
"name": "DPT_StatusGen",
|
||||
"desc": "General Status",
|
||||
"unit": "",
|
||||
"scalar_range": undefined,
|
||||
"range": undefined
|
||||
},
|
||||
// 21.002 control - 3 bits
|
||||
"002": {
|
||||
"name": "DPT_Device_Control",
|
||||
"desc": "Device Control",
|
||||
"unit": "",
|
||||
"scalar_range": undefined,
|
||||
"range": undefined
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
66
src/DPT232.ts
Normal file
66
src/DPT232.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
export interface DPT232Result {
|
||||
red: number,
|
||||
green: number,
|
||||
blue: number
|
||||
}
|
||||
export class DPT232 implements DPT {
|
||||
id = '232';
|
||||
name = 'RGB array';
|
||||
bufferLength = 3
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the on/off value
|
||||
*/
|
||||
decoder(buffer: Buffer): DPT232Result {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
const result: DPT232Result = {
|
||||
red: buffer.readUInt8(0),
|
||||
green: buffer.readUInt8(1),
|
||||
blue: buffer.readUInt8(2),
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: DPT232Result): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError('Cannot write null value');
|
||||
|
||||
if (value.red < 0 || value.red > 255)
|
||||
throw new InvalidValueError(`Red component out of range ${value.red}`);
|
||||
if (value.blue < 0 || value.blue > 255)
|
||||
throw new InvalidValueError(`Blue component out of range ${value.blue}`);
|
||||
if (value.green < 0 || value.green > 255)
|
||||
throw new InvalidValueError(`Green component out of range ${value.green}`);
|
||||
|
||||
let buffer = Buffer.alloc(this.bufferLength)
|
||||
buffer.writeUInt8(value.red, 0)
|
||||
buffer.writeUInt8(value.green, 1)
|
||||
buffer.writeUInt8(value.blue, 2)
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
'600': {
|
||||
name: 'RGB',
|
||||
desc: 'RGB color triplet',
|
||||
unit: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
39
src/DPT237.ts
Normal file
39
src/DPT237.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT237 implements DPT {
|
||||
id = '';
|
||||
name = '';
|
||||
bufferLength = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT8. Expected ${this.bufferLength}.`);
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
};
|
||||
|
||||
}
|
||||
74
src/DPT238.ts
Normal file
74
src/DPT238.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT238 implements DPT {
|
||||
id = '238';
|
||||
name = '8-bit unsigned value';
|
||||
bufferLength = 1
|
||||
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
return buffer.readUInt8(0)
|
||||
}
|
||||
|
||||
encoder(value: number): Buffer {
|
||||
if (!value)
|
||||
throw new InvalidValueError('DPT5: cannot write null value');
|
||||
|
||||
let buf = Buffer.alloc(this.bufferLength);
|
||||
buf.writeUInt8(value, 0)
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 20.102 HVAC mode
|
||||
102: {
|
||||
name: 'HVAC_Mode',
|
||||
desc: '',
|
||||
unit: '',
|
||||
//scalar_range: [,],
|
||||
//range: [,],
|
||||
},
|
||||
|
||||
// 5.003 angle (degrees 0=0, ff=360)
|
||||
'003': {
|
||||
name: 'DPT_Angle',
|
||||
desc: 'angle degrees',
|
||||
unit: '°',
|
||||
scalar_range: [0, 360],
|
||||
},
|
||||
|
||||
// 5.004 percentage (0..255%)
|
||||
'004': {
|
||||
name: 'DPT_Percent_U8',
|
||||
desc: 'percent',
|
||||
unit: '%',
|
||||
},
|
||||
|
||||
// 5.005 ratio (0..255)
|
||||
'005': {
|
||||
name: 'DPT_DecimalFactor',
|
||||
desc: 'ratio',
|
||||
unit: 'ratio',
|
||||
},
|
||||
|
||||
// 5.006 tariff (0..255)
|
||||
'006': {
|
||||
name: 'DPT_Tariff',
|
||||
desc: 'tariff',
|
||||
unit: 'tariff',
|
||||
},
|
||||
|
||||
// 5.010 counter pulses (0..255)
|
||||
'010': {
|
||||
name: 'DPT_Value_1_Ucount',
|
||||
desc: 'counter pulses',
|
||||
unit: 'pulses',
|
||||
},
|
||||
}
|
||||
}
|
||||
64
src/DPT3.ts
Normal file
64
src/DPT3.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export interface DPT3Result {
|
||||
decr_incr: number;
|
||||
data: number;
|
||||
}
|
||||
|
||||
export class DPT3 implements DPT {
|
||||
id = '3';
|
||||
name = '4-bit relative dimming control';
|
||||
bufferLength = 1;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): DPT3Result {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
const value = buffer.readUInt8(0)
|
||||
return {
|
||||
decr_incr: (value & 0b00001000) >> 3,
|
||||
data: value & 0b00000111,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: DPT3Result): Buffer {
|
||||
if (!value)
|
||||
throw new InvalidValueError('DPT3: cannot write null value');
|
||||
|
||||
if (value.decr_incr > 1)
|
||||
throw new InvalidValueError(`DPT3: Invalid increment/decrement value: ${value.decr_incr}. Expected 1 or 0.`);
|
||||
|
||||
return Buffer.from([(value.decr_incr << 3) + (value.data & 0b00000111)]);
|
||||
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 3.007 dimming control
|
||||
'007': {
|
||||
name: 'DPT_Control_Dimming',
|
||||
desc: 'dimming control',
|
||||
},
|
||||
|
||||
// 3.008 blind control
|
||||
'008': {
|
||||
name: 'DPT_Control_Blinds',
|
||||
desc: 'blinds control',
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
57
src/DPT4.ts
Normal file
57
src/DPT4.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT4 implements DPT {
|
||||
id = '4';
|
||||
name = '8-bit character';
|
||||
bufferLength = 1;
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): string {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
return String.fromCharCode(buffer[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: string): Buffer {
|
||||
if (!value)
|
||||
throw new InvalidValueError('DPT4: cannot write null value');
|
||||
|
||||
const apdu_data = value.charCodeAt(0);
|
||||
if (apdu_data > 255)
|
||||
throw new InvalidValueError('DPT4: must supply an ASCII character');
|
||||
|
||||
return Buffer.from([apdu_data]);
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 4.001 character (ASCII)
|
||||
'001': {
|
||||
name: 'DPT_Char_ASCII',
|
||||
desc: 'ASCII character (0-127)',
|
||||
range: [0, 127],
|
||||
use: 'G',
|
||||
},
|
||||
// 4.002 character (ISO-8859-1)
|
||||
'002': {
|
||||
name: 'DPT_Char_8859_1',
|
||||
desc: 'ISO-8859-1 character (0..255)',
|
||||
use: 'G',
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
73
src/DPT5.ts
Normal file
73
src/DPT5.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT5 implements DPT {
|
||||
id = '5';
|
||||
name = '8-bit unsigned value';
|
||||
bufferLength = 1;
|
||||
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
return buffer.readUInt8(0)
|
||||
}
|
||||
|
||||
encoder(value: number): Buffer {
|
||||
if (!value)
|
||||
throw new InvalidValueError('DPT5: cannot write null value');
|
||||
|
||||
let buf = Buffer.alloc(1);
|
||||
buf.writeUInt8(value, 0)
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 5.001 percentage (0=0..ff=100%)
|
||||
"001": {
|
||||
"name": "DPT_Scaling",
|
||||
"desc": "percent",
|
||||
"unit": "%",
|
||||
"scalar_range": [0, 100]
|
||||
},
|
||||
|
||||
// 5.003 angle (degrees 0=0, ff=360)
|
||||
"003": {
|
||||
"name": "DPT_Angle",
|
||||
"desc": "angle degrees",
|
||||
"unit": "°",
|
||||
"scalar_range": [0, 360]
|
||||
},
|
||||
|
||||
// 5.004 percentage (0..255%)
|
||||
"004": {
|
||||
"name": "DPT_Percent_U8",
|
||||
"desc": "percent",
|
||||
"unit": "%",
|
||||
},
|
||||
|
||||
// 5.005 ratio (0..255)
|
||||
"005": {
|
||||
"name": "DPT_DecimalFactor",
|
||||
"desc": "ratio",
|
||||
"unit": "ratio",
|
||||
},
|
||||
|
||||
// 5.006 tariff (0..255)
|
||||
"006": {
|
||||
"name": "DPT_Tariff",
|
||||
"desc": "tariff",
|
||||
"unit": "tariff",
|
||||
},
|
||||
|
||||
// 5.010 counter pulses (0..255)
|
||||
"010": {
|
||||
"name": "DPT_Value_1_Ucount",
|
||||
"desc": "counter pulses",
|
||||
"unit": "pulses",
|
||||
},
|
||||
}
|
||||
}
|
||||
58
src/DPT6.ts
Normal file
58
src/DPT6.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT6 implements DPT {
|
||||
id = '6';
|
||||
name = "8-bit signed value";
|
||||
bufferLength = 1;
|
||||
range = [-128, 127];
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
const value = buffer.readInt8(0)
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (!value)
|
||||
throw new InvalidValueError('DPT6: cannot write null value');
|
||||
|
||||
if (value < this.range[0] || value > this.range[1])
|
||||
throw new InvalidValueError(`DPT6: Value ${value} out of range [${this.range[0]}, ${this.range[1]}].`);
|
||||
|
||||
let buf = Buffer.alloc(this.bufferLength);
|
||||
buf.writeInt8(value, 0)
|
||||
return buf;
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 6.001 percentage (-128%..127%)
|
||||
"001": {
|
||||
"name": "DPT_Switch", "desc": "percent",
|
||||
"unit": "%",
|
||||
},
|
||||
|
||||
// 6.002 counter pulses (-128..127)
|
||||
"010": {
|
||||
"name": "DPT_Bool", "desc": "counter pulses",
|
||||
"unit": "pulses"
|
||||
},
|
||||
};
|
||||
}
|
||||
134
src/DPT7.ts
Normal file
134
src/DPT7.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT7 implements DPT {
|
||||
id = '7';
|
||||
name = '16-bit unsigned value';
|
||||
bufferLength = 2
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
const value = buffer.readUInt16BE(0)
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (!value)
|
||||
throw new InvalidValueError('DPT7: cannot write null value');
|
||||
|
||||
if (value < 0)
|
||||
throw new InvalidValueError(`DPT7: Cannot write negative value ${value}`);
|
||||
|
||||
let buf = Buffer.alloc(this.bufferLength);
|
||||
buf.writeUInt16BE(value, 0)
|
||||
return buf;
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 7.001 pulses
|
||||
"001": {
|
||||
"use": "G",
|
||||
"name": "DPT_Value_2_Ucount",
|
||||
"desc": "pulses",
|
||||
"unit": "pulses"
|
||||
},
|
||||
|
||||
// 7.002 time(ms)
|
||||
"002": {
|
||||
"use": "G",
|
||||
"name": "DPT_TimePeriodMsec",
|
||||
"desc": "time (ms)",
|
||||
"unit": "milliseconds"
|
||||
},
|
||||
|
||||
// 7.003 time (10ms)
|
||||
"003": {
|
||||
"use": "G",
|
||||
"name": "DPT_TimePeriod10Msec",
|
||||
"desc": "time (10ms)",
|
||||
"unit": "centiseconds"
|
||||
},
|
||||
|
||||
// 7.004 time (100ms)
|
||||
"004": {
|
||||
"use": "G",
|
||||
"name": "DPT_TimePeriod100Msec",
|
||||
"desc": "time (100ms)",
|
||||
"unit": "deciseconds"
|
||||
},
|
||||
|
||||
// 7.005 time (sec)
|
||||
"005": {
|
||||
"use": "G",
|
||||
"name": "DPT_TimePeriodSec",
|
||||
"desc": "time (s)",
|
||||
"unit": "seconds"
|
||||
},
|
||||
|
||||
// 7.006 time (min)
|
||||
"006": {
|
||||
"use": "G",
|
||||
"name": "DPT_TimePeriodMin",
|
||||
"desc": "time (min)",
|
||||
"unit": "minutes"
|
||||
},
|
||||
|
||||
// 7.007 time (hour)
|
||||
"007": {
|
||||
"use": "G",
|
||||
"name": "DPT_TimePeriodHrs",
|
||||
"desc": "time (hrs)",
|
||||
"unit": "hours"
|
||||
},
|
||||
|
||||
// 7.010 DPT_PropDataType
|
||||
// not to be used in runtime communications!
|
||||
"010": {
|
||||
"use": "FB",
|
||||
"name": "DPT_PropDataType",
|
||||
"desc": "Identifier Interface Object Property data type "
|
||||
},
|
||||
|
||||
// 7.011
|
||||
"011": {
|
||||
"use": "FB SAB",
|
||||
"name": "DPT_Length_mm",
|
||||
"desc": "Length in mm",
|
||||
"unit": "mm"
|
||||
},
|
||||
|
||||
// 7.012
|
||||
"012": {
|
||||
"use": "FB",
|
||||
"name": "DPT_UEICurrentmA",
|
||||
"desc": "bus power supply current (mA)",
|
||||
"unit": "mA"
|
||||
},
|
||||
|
||||
// 7.013
|
||||
"013": {
|
||||
"use": "FB",
|
||||
"name": "DPT_Brightness",
|
||||
"desc": "interior brightness",
|
||||
"unit": "lux"
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
111
src/DPT8.ts
Normal file
111
src/DPT8.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
export class DPT8 implements DPT {
|
||||
id = '8';
|
||||
name = '16-bit signed value';
|
||||
bufferLength = 2;
|
||||
"range" = [-32768, 32767];
|
||||
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the DPT value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
const value = buffer.readInt16BE(0)
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (!value)
|
||||
throw new InvalidValueError('DPT8: cannot write null value');
|
||||
|
||||
if (value < this.range[0] || value > this.range[1])
|
||||
throw new InvalidValueError(`DPT6: Value ${value} out of range [${this.range[0]}, ${this.range[1]}].`);
|
||||
|
||||
let buf = Buffer.alloc(this.bufferLength);
|
||||
buf.writeInt16BE(value, 0)
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
subtypes: {
|
||||
// 8.001 pulses difference
|
||||
"001": {
|
||||
"name": "DPT_Value_2_Count",
|
||||
"desc": "pulses",
|
||||
"unit": "pulses"
|
||||
},
|
||||
|
||||
// 8.002 time lag (ms)
|
||||
"002": {
|
||||
"name": "DPT_DeltaTimeMsec",
|
||||
"desc": "time lag(ms)",
|
||||
"unit": "milliseconds"
|
||||
},
|
||||
|
||||
// 8.003 time lag (10ms)
|
||||
"003": {
|
||||
"name": "DPT_DeltaTime10Msec",
|
||||
"desc": "time lag(10ms)",
|
||||
"unit": "centiseconds"
|
||||
},
|
||||
|
||||
// 8.004 time lag (100ms)
|
||||
"004": {
|
||||
"name": "DPT_DeltaTime100Msec",
|
||||
"desc": "time lag(100ms)",
|
||||
"unit": "deciseconds"
|
||||
},
|
||||
|
||||
// 8.005 time lag (sec)
|
||||
"005": {
|
||||
"name": "DPT_DeltaTimeSec",
|
||||
"desc": "time lag(s)",
|
||||
"unit": "seconds"
|
||||
},
|
||||
|
||||
// 8.006 time lag (min)
|
||||
"006": {
|
||||
"name": "DPT_DeltaTimeMin",
|
||||
"desc": "time lag(min)",
|
||||
"unit": "minutes"
|
||||
},
|
||||
|
||||
// 8.007 time lag (hour)
|
||||
"007": {
|
||||
"name": "DPT_DeltaTimeHrs",
|
||||
"desc": "time lag(hrs)",
|
||||
"unit": "hours"
|
||||
},
|
||||
|
||||
// 8.010 percentage difference (%)
|
||||
"010": {
|
||||
"name": "DPT_Percent_V16",
|
||||
"desc": "percentage difference",
|
||||
"unit": "%"
|
||||
},
|
||||
|
||||
// 8.011 rotation angle (deg)
|
||||
"011": {
|
||||
"name": "DPT_RotationAngle",
|
||||
"desc": "angle(degrees)",
|
||||
"unit": "°"
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
232
src/DPT9.ts
Normal file
232
src/DPT9.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
'use strict';
|
||||
import { BufferLengthError } from './errors/BufferLengthError';
|
||||
import { InvalidValueError } from './errors/InvalidValueError';
|
||||
import { DPT } from './definitions';
|
||||
|
||||
function ldexp(mantissa: number, exponent: number): number {
|
||||
return exponent > 1023 // avoid multiplying by infinity
|
||||
? mantissa * Math.pow(2, 1023) * Math.pow(2, exponent - 1023)
|
||||
: exponent < -1074 // avoid multiplying by zero
|
||||
? mantissa * Math.pow(2, -1074) * Math.pow(2, exponent + 1074)
|
||||
: mantissa * Math.pow(2, exponent);
|
||||
}
|
||||
function frexp(value: number): number[] {
|
||||
if (value === 0) return [0, 0];
|
||||
const data = new DataView(new ArrayBuffer(8));
|
||||
data.setFloat64(0, value);
|
||||
let bits = (data.getUint32(0) >>> 20) & 0x7ff;
|
||||
if (bits === 0) {
|
||||
data.setFloat64(0, value * Math.pow(2, 64));
|
||||
bits = ((data.getUint32(0) >>> 20) & 0x7ff) - 64;
|
||||
}
|
||||
const exponent = bits - 1022;
|
||||
const mantissa = ldexp(value, -exponent);
|
||||
return [mantissa, exponent];
|
||||
};
|
||||
|
||||
export class DPT9 implements DPT {
|
||||
id = '9';
|
||||
name = '16-bit floating point value';
|
||||
bufferLength = 2;
|
||||
/**
|
||||
* Decode a buffer
|
||||
*
|
||||
* @param buffer the buffer
|
||||
* @returns the on/off value
|
||||
*/
|
||||
decoder(buffer: Buffer): number {
|
||||
if (buffer.length !== this.bufferLength)
|
||||
throw new BufferLengthError(`Invalid buffer length ${buffer.length}/${buffer} for DPT1. Expected ${this.bufferLength}.`);
|
||||
|
||||
const sign = buffer[0] >> 7;
|
||||
const exponent = (buffer[0] & 0b01111000) >> 3;
|
||||
let mantissa = 256 * (buffer[0] & 0b00000111) + buffer[1];
|
||||
if (sign) mantissa = ~(mantissa ^ 2047);
|
||||
|
||||
return parseFloat(ldexp(0.01 * mantissa, exponent).toPrecision(15));
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a buffer
|
||||
*
|
||||
* @param value the value to be converted to buffer
|
||||
* @returns the buffer
|
||||
*/
|
||||
encoder(value: number): Buffer {
|
||||
if (value === undefined || value === null)
|
||||
throw new InvalidValueError('DPT9: cannot write null value');
|
||||
|
||||
if (!isFinite(value))
|
||||
throw new InvalidValueError('DPT9: cannot write non-numeric or undefined value');
|
||||
|
||||
const arr = frexp(value);
|
||||
const [mantissa, exponent] = arr;
|
||||
// find the minimum exponent that will upsize the normalized mantissa (0,5 to 1 range)
|
||||
// in order to fit in 11 bits ([-2048, 2047])
|
||||
let max_mantissa = 0;
|
||||
let e: number
|
||||
for (e = exponent; e >= -15; e--) {
|
||||
max_mantissa = ldexp(100 * mantissa, e);
|
||||
if (max_mantissa > -2048 && max_mantissa < 2047) break;
|
||||
}
|
||||
const sign = mantissa < 0 ? 1 : 0;
|
||||
const mant = mantissa < 0 ? ~(max_mantissa ^ 2047) : max_mantissa;
|
||||
const exp = exponent - e;
|
||||
// yucks
|
||||
return Buffer.from([(sign << 7) + (exp << 3) + (mant >> 8), mant % 256]);
|
||||
}
|
||||
|
||||
subtypes: {
|
||||
// 9.001 temperature (oC)
|
||||
'001': {
|
||||
name: 'DPT_Value_Temp',
|
||||
desc: 'temperature',
|
||||
unit: '°C',
|
||||
range: [-273, 670760],
|
||||
},
|
||||
|
||||
// 9.002 temperature difference (oC)
|
||||
'002': {
|
||||
name: 'DPT_Value_Tempd',
|
||||
desc: 'temperature difference',
|
||||
unit: '°C',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.003 kelvin/hour (K/h)
|
||||
'003': {
|
||||
name: 'DPT_Value_Tempa',
|
||||
desc: 'kelvin/hour',
|
||||
unit: '°K/h',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.004 lux (Lux)
|
||||
'004': {
|
||||
name: 'DPT_Value_Lux',
|
||||
desc: 'lux',
|
||||
unit: 'lux',
|
||||
range: [0, 670760],
|
||||
},
|
||||
|
||||
// 9.005 speed (m/s)
|
||||
'005': {
|
||||
name: 'DPT_Value_Wsp',
|
||||
desc: 'wind speed',
|
||||
unit: 'm/s',
|
||||
range: [0, 670760],
|
||||
},
|
||||
|
||||
// 9.006 pressure (Pa)
|
||||
'006': {
|
||||
name: 'DPT_Value_Pres',
|
||||
desc: 'pressure',
|
||||
unit: 'Pa',
|
||||
range: [0, 670760],
|
||||
},
|
||||
|
||||
// 9.007 humidity (%)
|
||||
'007': {
|
||||
name: 'DPT_Value_Humidity',
|
||||
desc: 'humidity',
|
||||
unit: '%',
|
||||
range: [0, 670760],
|
||||
},
|
||||
|
||||
// 9.008 parts/million (ppm)
|
||||
'008': {
|
||||
name: 'DPT_Value_AirQuality',
|
||||
desc: 'air quality',
|
||||
unit: 'ppm',
|
||||
range: [0, 670760],
|
||||
},
|
||||
|
||||
// 9.010 time (s)
|
||||
'010': {
|
||||
name: 'DPT_Value_Time1',
|
||||
desc: 'time(sec)',
|
||||
unit: 's',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.011 time (ms)
|
||||
'011': {
|
||||
name: 'DPT_Value_Time2',
|
||||
desc: 'time(msec)',
|
||||
unit: 'ms',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.020 voltage (mV)
|
||||
'020': {
|
||||
name: 'DPT_Value_Volt',
|
||||
desc: 'voltage',
|
||||
unit: 'mV',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.021 current (mA)
|
||||
'021': {
|
||||
name: 'DPT_Value_Curr',
|
||||
desc: 'current',
|
||||
unit: 'mA',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.022 power density (W/m2)
|
||||
'022': {
|
||||
name: 'DPT_PowerDensity',
|
||||
desc: 'power density',
|
||||
unit: 'W/m²',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.023 kelvin/percent (K/%)
|
||||
'023': {
|
||||
name: 'DPT_KelvinPerPercent',
|
||||
desc: 'Kelvin / %',
|
||||
unit: 'K/%',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.024 power (kW)
|
||||
'024': {
|
||||
name: 'DPT_Power',
|
||||
desc: 'power (kW)',
|
||||
unit: 'kW',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.025 volume flow (l/h)
|
||||
'025': {
|
||||
name: 'DPT_Value_Volume_Flow',
|
||||
desc: 'volume flow',
|
||||
unit: 'l/h',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.026 rain amount (l/m2)
|
||||
'026': {
|
||||
name: 'DPT_Rain_Amount',
|
||||
desc: 'rain amount',
|
||||
unit: 'l/m²',
|
||||
range: [-670760, 670760],
|
||||
},
|
||||
|
||||
// 9.027 temperature (Fahrenheit)
|
||||
'027': {
|
||||
name: 'DPT_Value_Temp_F',
|
||||
desc: 'temperature (F)',
|
||||
unit: '°F',
|
||||
range: [-459.6, 670760],
|
||||
},
|
||||
|
||||
// 9.028 wind speed (km/h)
|
||||
'028': {
|
||||
name: 'DPT_Value_Wsp_kmh',
|
||||
desc: 'wind speed (km/h)',
|
||||
unit: 'km/h',
|
||||
range: [0, 670760],
|
||||
},
|
||||
};
|
||||
}
|
||||
113
src/DataPointType.ts
Normal file
113
src/DataPointType.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
'use strict';
|
||||
|
||||
import { Encoder, Decoder, DPT } from './definitions';
|
||||
|
||||
import { DPT1 } from './DPT1';
|
||||
import { DPT2 } from './DPT2';
|
||||
import { DPT3 } from './DPT3';
|
||||
import { DPT4 } from './DPT4';
|
||||
import { DPT5 } from './DPT5';
|
||||
import { DPT6 } from './DPT6';
|
||||
import { DPT7 } from './DPT7';
|
||||
import { DPT8 } from './DPT8';
|
||||
import { DPT9 } from './DPT9';
|
||||
import { DPT10 } from './DPT10';
|
||||
import { DPT11 } from './DPT11';
|
||||
import { DPT12 } from './DPT12';
|
||||
import { DPT13 } from './DPT13';
|
||||
import { DPT14 } from './DPT14';
|
||||
import { DPT15 } from './DPT15';
|
||||
import { DPT16 } from './DPT16';
|
||||
import { DPT17 } from './DPT17';
|
||||
import { DPT18 } from './DPT18';
|
||||
import { DPT19 } from './DPT19';
|
||||
import { DPT20 } from './DPT20';
|
||||
import { DPT21 } from './DPT21';
|
||||
//import { DPT22 } from './DPT22';
|
||||
import { DPT232 } from './DPT232';
|
||||
import { DPT237 } from './DPT237';
|
||||
import { DPT238 } from './DPT238';
|
||||
|
||||
export class DataPointType {
|
||||
|
||||
get type(): string {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
get subtype(): string {
|
||||
return this._subtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* @property {DPTYPE} DPT1
|
||||
* @property {DPTYPE} DPT2
|
||||
* @property {DPTYPE} DPT3
|
||||
* @property {DPTYPE} DPT4
|
||||
* @property {DPTYPE} DPT5
|
||||
* @property {DPTYPE} DPT6
|
||||
* @property {DPTYPE} DPT7
|
||||
* @property {DPTYPE} DPT8
|
||||
* @property {DPTYPE} DPT9
|
||||
* @property {DPTYPE} DPT10
|
||||
* @property {DPTYPE} DPT11
|
||||
* @property {DPTYPE} DPT12
|
||||
* @property {DPTYPE} DPT13
|
||||
* @property {DPTYPE} DPT14
|
||||
* @property {DPTYPE} DPT15
|
||||
* @property {DPTYPE} DPT16
|
||||
* @property {DPTYPE} DPT17
|
||||
* @property {DPTYPE} DPT18
|
||||
* @property {DPTYPE} DPT19
|
||||
* @property {DPTYPE} DPT20
|
||||
*/
|
||||
static get TYPES(): { [index: string]: DPT | null } {
|
||||
return {
|
||||
DPT1: new DPT1(),
|
||||
DPT2: new DPT2(),
|
||||
DPT3: new DPT3(),
|
||||
DPT4: new DPT4(),
|
||||
DPT5: new DPT5(),
|
||||
DPT6: new DPT6(),
|
||||
DPT7: new DPT7(),
|
||||
DPT8: new DPT8(),
|
||||
DPT9: new DPT9(),
|
||||
DPT10: new DPT10(),
|
||||
DPT11: new DPT11(),
|
||||
DPT12: new DPT12(),
|
||||
DPT13: new DPT13(),
|
||||
DPT14: new DPT14(),
|
||||
DPT15: new DPT15(),
|
||||
DPT16: new DPT16(),
|
||||
DPT17: new DPT17(),
|
||||
DPT18: new DPT18(),
|
||||
DPT19: new DPT19(),
|
||||
DPT20: new DPT20(),
|
||||
DPT21: new DPT21(),
|
||||
//DPT22: new DPT22(),
|
||||
|
||||
DPT232: new DPT232(),
|
||||
DPT237: new DPT237(),
|
||||
DPT238: new DPT238()
|
||||
};
|
||||
}
|
||||
|
||||
constructor(private _type: string, private _subtype: string, private _encoder: Encoder, private _decoder: Decoder) {
|
||||
}
|
||||
|
||||
static validType(text: string): boolean {
|
||||
const m = text.toUpperCase().match(/(?:DPT)?(\d+)(\.(\d+))?/);
|
||||
return m != null;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.type}.${this.subtype}`;
|
||||
}
|
||||
|
||||
decode(buffer: Buffer): string | number {
|
||||
return this._decoder(buffer);
|
||||
}
|
||||
|
||||
encode(value: string | number): Buffer {
|
||||
return this._encoder(value);
|
||||
}
|
||||
}
|
||||
35
src/definitions.ts
Normal file
35
src/definitions.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Definitions for the KNX library
|
||||
*/
|
||||
|
||||
export type Encoder = (value: any) => Buffer;
|
||||
export type Decoder = (buffer: Buffer) => any;
|
||||
|
||||
/**
|
||||
* @property {string} use
|
||||
* @property {string} name
|
||||
* @property {string} desc
|
||||
* @property {any} enc
|
||||
*/
|
||||
export interface DPTSubType {
|
||||
use?: string;
|
||||
name: string;
|
||||
desc: string;
|
||||
enc?: any;
|
||||
|
||||
unit?: string;
|
||||
range?: number[];
|
||||
}
|
||||
|
||||
/**
|
||||
* DPT generic interface
|
||||
*/
|
||||
export interface DPT {
|
||||
id: string;
|
||||
name: string;
|
||||
bufferLength: number;
|
||||
subtypes: { [index: string]: DPTSubType };
|
||||
|
||||
decoder: Decoder;
|
||||
encoder: Encoder;
|
||||
}
|
||||
2
src/errors/BufferLengthError.ts
Normal file
2
src/errors/BufferLengthError.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export class BufferLengthError extends Error {
|
||||
}
|
||||
2
src/errors/InvalidValueError.ts
Normal file
2
src/errors/InvalidValueError.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export class InvalidValueError extends Error {
|
||||
}
|
||||
Reference in New Issue
Block a user