knxultimate
Version:
KNX IP protocol implementation for Node. This is the ENGINE of Node-Red KNX-Ultimate node.
317 lines • 10.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const KnxLog_1 = require("../KnxLog");
const logger = (0, KnxLog_1.module)('DPT60001');
function toRadix(value, radix) {
if (!Number.isSafeInteger(value)) {
logger.error('value must be a safe integer');
}
const digits = Math.ceil(64 / Math.log2(radix));
const twosComplement = value < 0 ? BigInt(radix) ** BigInt(digits) + BigInt(value) : value;
return twosComplement.toString(radix).padStart(digits, '0');
}
function griesserSectorCode(Byte0, Byte1) {
const SectorCode = Byte0 + (Byte1 & 3) * 256;
return SectorCode;
}
function griesserCommandCode(Byte1) {
const command = (Byte1 / 4) >> 0;
return command;
}
function griesserParameter(command, Byte2, Byte3, Byte4, Byte5) {
let commandOperation;
switch (command) {
case 1:
switch (Byte2 & 31) {
case 0:
return 'no driving movement';
case 1:
return 'upper end position';
case 2:
return 'lower end position';
case 3:
if (Byte3 >= 1 && Byte3 <= 4) {
return `fixed position P${Byte3} approach`;
}
return `Unknown value for Pn ${Byte3}`;
default:
return `Unknown drive command${Byte2}`;
}
case 4:
if (Byte2 === 0) {
return 'no lock';
}
switch (Byte2 & 3) {
case 1:
return 'driving command';
case 2:
return 'button lock';
case 3:
return 'driving command- and button lock';
}
if (Byte3 === 0) {
return 'delete lock';
}
return 'set lock';
case 5:
if (Byte2 <= 6) {
commandOperation = 'groupoperation';
}
else if (Byte2 >= 128 && Byte2 <= 134) {
commandOperation = 'localoperation';
}
else {
commandOperation = `unknown command Byte3 for ${Byte2}`;
}
if ((Byte2 & 127) === 0) {
return [commandOperation, 'long up'];
}
if ((Byte2 & 127) === 1) {
return [commandOperation, 'long down'];
}
if ((Byte2 & 127) === 2) {
return [commandOperation, 'short up'];
}
if ((Byte2 & 127) === 3) {
return [commandOperation, 'short down'];
}
if ((Byte2 & 127) === 4) {
return [commandOperation, 'stop'];
}
if ((Byte2 & 127) === 5) {
return [commandOperation, 'long-short up'];
}
if ((Byte2 & 127) === 6) {
return [commandOperation, 'long-short down'];
}
return [commandOperation, `unknown command Byte3 for ${Byte2}`];
case 22:
return [
`min. angle: ${Byte2}`,
`max. angle: ${Byte3}`,
`min. height: ${Byte4}`,
`max. height: ${Byte5}`,
];
default:
return `unknown value for command: ${command}`;
}
}
function griesserSectors(SectorCode) {
let SectorMin;
let SectorMax;
let dA;
let a;
let SectorCodeMin;
let SectorCodeMax;
dA = 1;
a = SectorCode;
if (a > 0) {
while ((a & 1) === 0) {
a = (a / 2) >> 0;
dA *= 2;
}
dA -= 1;
SectorMin = SectorCode - dA;
SectorMax = SectorCode + dA;
}
else {
SectorMin = 0;
SectorMax = 0;
}
if (SectorMin === 0) {
SectorCodeMin = 0;
}
else {
SectorCodeMin = (((SectorMin - 1) / 2) >> 0) + 1;
}
if (SectorMax === 0) {
SectorCodeMax = 0;
}
else {
SectorCodeMax = (((SectorMax - 1) / 2) >> 0) + 1;
}
if (SectorCodeMax === SectorCodeMin) {
return [SectorCodeMin];
}
const Sectors = [];
for (let i = SectorCodeMin; i <= SectorCodeMax; i++) {
Sectors.push(i);
}
return Sectors;
}
function griesserSectorToSectorCode(sectors) {
if (sectors.length === 1) {
return sectors[0] + sectors[0] - 1;
}
return Math.min(...sectors) + Math.max(...sectors) - 1;
}
function griesserCommandToCommandCode(command) {
switch (command) {
case 'operation code':
return 5;
default:
logger.error(`not implemented yet: ${command}`);
return null;
}
}
function griesserCommandToCommandCodeP1(command) {
switch (command) {
case 'long up':
return 128;
case 'long down':
return 129;
case 'short up':
return 130;
case 'short down':
return 131;
case 'stop':
return 132;
case 'long-short up':
return 133;
case 'long-short down':
return 134;
default:
logger.error(`unknown command: ${command}`);
return null;
}
}
function griesserCommand(command) {
switch (command) {
case 1:
return 'drive command';
case 2:
return 'value correction';
case 3:
return 'automatic state';
case 4:
return 'set/delete lock';
case 5:
return 'operation code';
case 6:
return 'set scene';
case 7:
return 'special command';
case 8:
return 'date';
case 9:
return 'sync time';
case 10:
return 'sensor reading notification';
case 11:
return 'bus monitoring';
case 16:
return 'driving range limits for safety drive commands';
case 17:
return 'driving range limits for safety drive commands';
case 19:
return 'driving range limits for safety drive commands';
case 20:
return 'driving range limits for safety drive commands';
case 22:
return 'driving range limits for automatic drive commands';
case 23:
return 'driving range limits for automatic drive commands';
case 24:
return 'driving range limits for automatic drive commands';
default:
return `unknown value for function: ${command}`;
}
}
function griesserPrio(prio, command) {
const prioCommand = ((command & 224) / 32) >> 0;
if (((prio & 252) / 4) >> 0 === 0) {
switch (prioCommand) {
case 0:
return 'border command';
case 1:
return 'automatic command';
case 3:
return 'priority command';
case 4:
return 'warning command';
case 5:
return 'security command';
case 6:
return 'danger command';
default:
return `unknown priority${prioCommand}`;
}
}
else {
return '-';
}
}
const config = {
id: 'DPT60001',
formatAPDU(value) {
if (!value) {
logger.error('cannot write null value');
return null;
}
if (typeof value === 'object' &&
Object.prototype.hasOwnProperty.call(value, 'command') &&
Object.prototype.hasOwnProperty.call(value, 'data') &&
Object.prototype.hasOwnProperty.call(value, 'sectors') &&
value.data[0] === 'localoperation') {
const sectorCode = griesserSectorToSectorCode(value.sectors);
const commandCode = griesserCommandToCommandCode(value.command);
const p1 = griesserCommandToCommandCodeP1(value.data[1]);
const bufferTotal = Buffer.alloc(6);
bufferTotal[0] = parseInt(toRadix(sectorCode, 2).slice(-8), 2);
bufferTotal[1] = parseInt(toRadix(commandCode, 2).slice(-6) +
toRadix(sectorCode, 2).slice(-10, -8), 2);
bufferTotal[2] = parseInt(toRadix(p1, 2).slice(-8), 2);
return bufferTotal;
}
logger.error('Must supply an value {command:"operation code", data:["localoperation", "long up"], sectors:[159]}');
return null;
},
fromBuffer(buf) {
if (buf.length !== 6) {
logger.warn('DPTGriesser.fromBuffer: buf should be 6 bytes long (got %d bytes)', buf.length);
return null;
}
const hexToDecimal = (hex) => parseInt(hex, 16);
const bufTotale = buf.toString('hex');
const Byte0 = hexToDecimal(bufTotale.slice(0, 2));
const Byte1 = hexToDecimal(bufTotale.slice(2, 4));
const Byte2 = hexToDecimal(bufTotale.slice(4, 6));
const Byte3 = hexToDecimal(bufTotale.slice(6, 8));
const Byte4 = hexToDecimal(bufTotale.slice(8, 10));
const Byte5 = hexToDecimal(bufTotale.slice(10, 12));
const sectorCode = griesserSectorCode(Byte0, Byte1);
const commandCode = griesserCommandCode(Byte1);
return {
Byte0,
Byte1,
Byte2,
Byte3,
Byte4,
Byte5,
sectorCode,
commandCode,
sectors: griesserSectors(sectorCode),
prio: griesserPrio(Byte1, Byte2),
command: griesserCommand(commandCode),
data: griesserParameter(commandCode, Byte2, Byte3, Byte4, Byte5),
};
},
basetype: {
bitlength: 4 * 8 + 2 * 6 + 1 * 10,
valuetype: 'composite',
desc: 'Commands for solar shading actors',
help: `// Sample of 60001.
// Now are only the local operation implemented.
// For example, for 60001, set the sector 42 localy up.
msg.payload = { command: "operation code", data: ["localoperation", "long up"], sectors: [42] };
return msg;`,
},
subtypes: {
'001': {
desc: 'DPT_Griesser_Object',
name: 'Griesser Object',
},
},
};
exports.default = config;
//# sourceMappingURL=dpt60001.js.map