UNPKG

zwave-js

Version:

Z-Wave driver written entirely in JavaScript/TypeScript

183 lines 6.03 kB
import { ZWaveError, ZWaveErrorCodes } from "@zwave-js/core"; import { Bytes } from "@zwave-js/shared"; export var AttachmentTypes; (function (AttachmentTypes) { AttachmentTypes[AttachmentTypes["NetworkKeys"] = 3] = "NetworkKeys"; AttachmentTypes[AttachmentTypes["FrameComment"] = 4] = "FrameComment"; AttachmentTypes[AttachmentTypes["Session"] = 5] = "Session"; })(AttachmentTypes || (AttachmentTypes = {})); export class ZLFAttachmentRaw { type; version; data; constructor(type, version, data) { this.type = type; this.version = version; this.data = data; } static parse(buffer) { if (buffer.length < 2) { throw new ZWaveError("Incomplete ZLF attachment", ZWaveErrorCodes.PacketFormat_Truncated); } const type = buffer[0]; const version = buffer[1]; // The remaining bytes are the data const data = Bytes.view(buffer.subarray(2)); return { raw: new ZLFAttachmentRaw(type, version, data), bytesRead: buffer.length, }; } withData(data) { return new ZLFAttachmentRaw(this.type, this.version, data); } } /** * Retrieves the correct constructor for the attachment based on its type. */ function getZLFAttachmentConstructor(raw) { switch (raw.type) { case AttachmentTypes.NetworkKeys: return ZLFNetworkKeysAttachment; case AttachmentTypes.FrameComment: return ZLFFrameCommentAttachment; case AttachmentTypes.Session: return ZLFSessionAttachment; default: return ZLFAttachment; } } /** * Represents a ZLF attachment for parsing data from a Zniffer trace */ export class ZLFAttachment { constructor(options) { this.type = options.type; this.version = options.version; this.data = options.data || new Bytes(); } static parse(buffer) { const { raw, bytesRead } = ZLFAttachmentRaw.parse(buffer); const Constructor = getZLFAttachmentConstructor(raw); return { attachment: Constructor.from(raw), bytesRead, }; } /** Creates an instance of the attachment that is serialized in the given buffer */ static from(raw) { return new this({ type: raw.type, version: raw.version, data: raw.data, }); } type; version; data; /** Serializes this attachment into a Buffer */ serialize() { return Bytes.concat([ Bytes.from([this.type, this.version]), this.data, ]); } } export class ZLFNetworkKeysAttachment extends ZLFAttachment { constructor(options) { super({ type: AttachmentTypes.NetworkKeys, version: 1, }); this.homeId = options.homeId; this.keys = options.keys.map((key) => Bytes.from(key)); this.tempKeys = options.tempKeys.map((key) => Bytes.from(key)); } static from(raw) { // This attachment consists of at least 2x4 home ID bytes, // 2x1 byte count and 2x1 byte flags, plus 16 bytes per key if (raw.data.length < 12) { throw new ZWaveError("Incomplete NetworkKeysAttachment", ZWaveErrorCodes.PacketFormat_Truncated); } let offset = 0; // Home ID seems to not be populated by the Zniffer software, // but we'll parse it anyways const homeId = raw.data.readUInt32BE(offset); offset += 4; const tempKeys = []; const keys = []; // Read first set of keys let count = raw.data[offset++]; let isTemporary = !!(raw.data[offset++] & 0x01); if (offset + count * 16 + 6 >= raw.data.length) { throw new ZWaveError("Incomplete NetworkKeysAttachment", ZWaveErrorCodes.PacketFormat_Truncated); } for (let i = 0; i < count; i++) { const key = raw.data.subarray(offset, offset + 16); offset += 16; if (isTemporary) { tempKeys.push(key); } else { keys.push(key); } } // Read second set of keys // Skip homeID bytes offset += 4; count = raw.data[offset++]; isTemporary = !!(raw.data[offset++] & 0x01); if (offset + count * 16 > raw.data.length) { throw new ZWaveError("Incomplete NetworkKeysAttachment", ZWaveErrorCodes.PacketFormat_Truncated); } for (let i = 0; i < count; i++) { const key = raw.data.subarray(offset, offset + 16); offset += 16; if (isTemporary) { tempKeys.push(key); } else { keys.push(key); } } return new ZLFNetworkKeysAttachment({ homeId, keys, tempKeys, }); } homeId; keys; tempKeys; } export class ZLFFrameCommentAttachment extends ZLFAttachment { constructor(options) { super({ type: AttachmentTypes.FrameComment, version: options.version || 1, data: options.data, }); this.comment = options.comment; } static from(_raw) { // TODO: Implement parsing logic throw new ZWaveError("ZLFFrameCommentAttachment parsing not yet implemented", ZWaveErrorCodes.Deserialization_NotImplemented); } comment; } export class ZLFSessionAttachment extends ZLFAttachment { constructor(options) { super({ type: AttachmentTypes.Session, version: options.version || 1, data: options.data, }); this.sessionId = options.sessionId; } static from(_raw) { // TODO: Implement parsing logic throw new ZWaveError("ZLFSessionAttachment parsing not yet implemented", ZWaveErrorCodes.Deserialization_NotImplemented); } sessionId; } //# sourceMappingURL=ZLFAttachment.js.map