zigbee-herdsman-zigate
Version:
An open source ZigBee gateway solution with node.js.
349 lines • 11.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const buffalo_1 = require("../buffalo");
const definition_1 = require("./definition");
const aliases = {
'boolean': 'uint8',
'bitmap8': 'uint8',
'enum8': 'uint8',
'data8': 'uint8',
'data16': 'uint16',
'bitmap16': 'uint16',
'uint16': 'uint16',
'enum16': 'uint16',
'clusterId': 'uint16',
'attrId': 'uint16',
'data24': 'uint24',
'bitmap24': 'uint24',
'data32': 'uint32',
'bitmap32': 'uint32',
'uint32': 'uint32',
'tod': 'uint32',
'date': 'uint32',
'utc': 'uint32',
'bacOid': 'uint32',
'singlePrec': 'floatle',
'doublePrec': 'doublele',
'bitmap40': 'uint40',
'data40': 'uint40',
'bitmap48': 'uint48',
'data48': 'uint48',
'bitmap56': 'uint56',
'data56': 'uint56',
'bitmap64': 'uint64',
'data64': 'uint64',
'ieeeAddr': 'uint64',
'longOctetStr': 'longCharStr',
'secKey': 'buffer16',
'noData': 'EMPTY',
'unknown': 'EMPTY',
'bag': 'array',
'set': 'array',
};
class BuffaloZcl extends buffalo_1.Buffalo {
readUseDataType(options) {
return this.read(options.dataType, options);
}
writeUseDataType(value, options) {
return this.write(options.dataType, value, options);
}
readArray() {
const values = [];
const elementType = definition_1.DataType[this.readUInt8()];
const numberOfElements = this.readUInt16();
for (let i = 0; i < numberOfElements; i++) {
const value = this.read(elementType, {});
values.push(value);
}
return values;
}
writeArray(value) {
const elTypeNumeric = typeof value.elementType === 'number' ? value.elementType : definition_1.DataType[value.elementType];
this.writeUInt8(elTypeNumeric);
this.writeUInt16(value.elements.length);
value.elements.forEach(element => {
this.write(definition_1.DataType[elTypeNumeric], element, {});
});
}
readStruct() {
const values = [];
const numberOfElements = this.readUInt16();
for (let i = 0; i < numberOfElements; i++) {
const elementType = this.readUInt8();
const value = this.read(definition_1.DataType[elementType], {});
values.push({ elmType: elementType, elmVal: value });
}
return values;
}
readOctetStr() {
const length = this.readUInt8();
const value = this.buffer.slice(this.position, this.position + length);
this.position += length;
return value;
}
readCharStr(options) {
const length = this.readUInt8();
if (options.attrId === 65281) {
const value = {};
// Xiaomi struct parsing
for (let i = 0; i < length; i++) {
const index = this.readUInt8();
const dataType = definition_1.DataType[this.readUInt8()];
value[index] = this.read(dataType, {});
if (this.position === this.buffer.length) {
break;
}
}
return value;
}
else {
const value = this.buffer.toString('utf8', this.position, this.position + length);
this.position += length;
return value;
}
}
writeCharStr(value) {
if (typeof value === 'string') {
this.writeUInt8(value.length);
this.position += this.buffer.write(value, this.position, 'utf8');
}
else {
this.writeBuffer(value, value.length);
}
}
readLongCharStr() {
const length = this.readUInt16();
const value = this.buffer.toString('utf8', this.position, this.position + length);
this.position += length;
return value;
}
writeLongCharStr(value) {
this.writeUInt16(value.length);
this.position += this.buffer.write(value, this.position, 'utf8');
}
writeOctetStr(value) {
this.writeUInt8(value.length);
this.writeBuffer(value, value.length);
}
readExtensionFielSets() {
const value = [];
while (this.position < this.buffer.length) {
const clstId = this.readUInt16();
const len = this.readUInt8();
const extField = [];
for (let k = 0; k < len; k++) {
extField.push(this.readUInt8());
}
value.push({ extField, clstId, len });
}
return value;
}
writeExtensionFieldSets(values) {
for (const value of values) {
this.writeUInt16(value.clstId);
this.writeUInt8(value.len);
for (const entry of value.extField) {
this.writeUInt8(entry);
}
}
}
writeListZoneInfo(values) {
for (const value of values) {
this.writeUInt8(value.zoneID);
this.writeUInt16(value.zoneStatus);
}
}
readListZoneInfo(options) {
const value = [];
for (let i = 0; i < options.length; i++) {
value.push({
zoneID: this.readUInt8(),
zoneStatus: this.readUInt16(),
});
}
return value;
}
readListThermoTransitions(options) {
const heat = options.payload['mode'] & 1;
const cool = options.payload['mode'] & 2;
const result = [];
for (let i = 0; i < options.payload.numoftrans; i++) {
const entry = { transitionTime: this.readUInt16() };
if (heat) {
entry.heatSetpoint = this.readUInt16();
}
if (cool) {
entry.coolSetpoint = this.readUInt16();
}
result.push(entry);
}
return result;
}
writeListThermoTransitions(value) {
for (const entry of value) {
this.writeUInt16(entry.transitionTime);
if (entry.hasOwnProperty('heatSetpoint')) {
this.writeUInt16(entry.heatSetpoint);
}
if (entry.hasOwnProperty('coolSetpoint')) {
this.writeUInt16(entry.coolSetpoint);
}
}
}
readGdpFrame(options) {
// Commisioning
if (options.payload.commandID === 224) {
return {
deviceID: this.readUInt8(),
options: this.readUInt8(),
extendedOptions: this.readUInt8(),
securityKey: this.readBuffer(16),
keyMic: this.readUInt32(),
outgoingCounter: this.readUInt32(),
};
}
else if (this.position != this.buffer.length) {
return { raw: this.buffer.slice(this.position) };
}
else {
return {};
}
}
readUInt40() {
const lsb = this.readUInt32();
const msb = this.readUInt8();
return [msb, lsb];
}
writeUInt40(value) {
this.writeUInt32(value[1]);
this.writeUInt8(value[0]);
}
readUInt48() {
const lsb = this.readUInt32();
const msb = this.readUInt16();
return [msb, lsb];
}
writeUInt48(value) {
this.writeUInt32(value[1]);
this.writeUInt16(value[0]);
}
readUInt56() {
const lsb = this.readUInt32();
const xsb = this.readUInt16();
const msb = this.readUInt8();
return [msb, xsb, lsb];
}
writeUInt56(value) {
const temp = Buffer.alloc(8);
temp.writeUInt32LE(value[1], 0);
temp.writeUInt32LE(value[0], 4);
this.writeBuffer(temp.slice(0, 7), 7);
}
readUInt64() {
return this.readIeeeAddr();
}
writeUInt64(value) {
const msb = parseInt(value.slice(2, 10), 16);
const lsb = parseInt(value.slice(10), 16);
this.writeUInt32(lsb);
this.writeUInt32(msb);
}
write(type, value, options) {
// TODO: write for the following is missing: struct
type = aliases[type] || type;
if (type === 'uint40') {
return this.writeUInt40(value);
}
else if (type === 'EXTENSION_FIELD_SETS') {
return this.writeExtensionFieldSets(value);
}
else if (type === 'LIST_ZONEINFO') {
return this.writeListZoneInfo(value);
}
else if (type === 'LIST_THERMO_TRANSITIONS') {
return this.writeListThermoTransitions(value);
}
else if (type === 'uint48') {
return this.writeUInt48(value);
}
else if (type === 'uint56') {
return this.writeUInt56(value);
}
else if (type === 'uint64') {
return this.writeUInt64(value);
}
else if (type === 'charStr') {
return this.writeCharStr(value);
}
else if (type === 'longCharStr') {
return this.writeLongCharStr(value);
}
else if (type === 'octetStr') {
return this.writeOctetStr(value);
}
else if (type === 'array') {
return this.writeArray(value);
}
else if (type === 'USE_DATA_TYPE') {
return this.writeUseDataType(value, options);
}
else {
// In case the type is undefined, write it as a buffer to easily allow for custom types
// e.g. for https://github.com/Koenkk/zigbee-herdsman/issues/127
type = type === undefined ? 'BUFFER' : type;
// TODO: remove uppercase once dataTypes are snake case
return super.write(type.toUpperCase(), value, options);
}
}
read(type, options) {
type = aliases[type] || type;
if (type === 'USE_DATA_TYPE') {
return this.readUseDataType(options);
}
else if (type === 'EXTENSION_FIELD_SETS') {
return this.readExtensionFielSets();
}
else if (type === 'LIST_ZONEINFO') {
return this.readListZoneInfo(options);
}
else if (type === 'LIST_THERMO_TRANSITIONS') {
return this.readListThermoTransitions(options);
}
else if (type === 'GDP_FRAME') {
return this.readGdpFrame(options);
}
else if (type === 'uint40') {
return this.readUInt40();
}
else if (type === 'uint48') {
return this.readUInt48();
}
else if (type === 'uint56') {
return this.readUInt56();
}
else if (type === 'uint64') {
return this.readUInt64();
}
else if (type === 'octetStr') {
return this.readOctetStr();
}
else if (type === 'charStr') {
return this.readCharStr(options);
}
else if (type === 'longCharStr') {
return this.readLongCharStr();
}
else if (type === 'array') {
return this.readArray();
}
else if (type === 'struct') {
return this.readStruct();
}
else {
// TODO: remove uppercase once dataTypes are snake case
return super.read(type.toUpperCase(), options);
}
}
}
exports.default = BuffaloZcl;
//# sourceMappingURL=buffaloZcl.js.map