dptlib/src/DPT19.ts
2022-03-09 22:38:02 +01:00

227 lines
8.4 KiB
TypeScript

'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',
},
};
}