inventoresed
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
152 lines (138 loc) • 5.17 kB
text/typescript
import {
CommandClasses,
encodeCCList,
MessageOrCCLogEntry,
MessagePriority,
parseCCList,
} from "@zwave-js/core";
import type { ZWaveHost } from "@zwave-js/host";
import {
FunctionType,
gotDeserializationOptions,
Message,
MessageBaseOptions,
MessageDeserializationOptions,
MessageType,
messageTypes,
priority,
} from "@zwave-js/serial";
import { getEnumMemberName, num2hex } from "@zwave-js/shared";
export enum SerialAPIWakeUpReason {
/** The Z-Wave API Module has been woken up by reset or external interrupt. */
Reset = 0x00,
/** The Z-Wave API Module has been woken up by a timer. */
WakeUpTimer = 0x01,
/** The Z-Wave API Module has been woken up by a Wake Up Beam. */
WakeUpBeam = 0x02,
/** The Z-Wave API Module has been woken up by a reset triggered by the watchdog. */
WatchdogReset = 0x03,
/** The Z-Wave API Module has been woken up by an external interrupt. */
ExternalInterrupt = 0x04,
/** The Z-Wave API Module has been woken up by a powering up. */
PowerUp = 0x05,
/** The Z-Wave API Module has been woken up by USB Suspend. */
USBSuspend = 0x06,
/** The Z-Wave API Module has been woken up by a reset triggered by software. */
SoftwareReset = 0x07,
/** The Z-Wave API Module has been woken up by an emergency watchdog reset. */
EmergencyWatchdogReset = 0x08,
/** The Z-Wave API Module has been woken up by a reset triggered by brownout circuit. */
BrownoutCircuit = 0x09,
/** The Z-Wave API Module has been woken up by an unknown reason. */
Unknown = 0xff,
}
export interface SerialAPIStartedRequestOptions extends MessageBaseOptions {
wakeUpReason: SerialAPIWakeUpReason;
watchdogEnabled: boolean;
genericDeviceClass: number;
specificDeviceClass: number;
isListening: boolean;
supportedCCs: CommandClasses[];
controlledCCs: CommandClasses[];
supportsLongRange: boolean;
}
// This does not expect a response. The controller sends us this when the Serial API is started
export class SerialAPIStartedRequest extends Message {
public constructor(
host: ZWaveHost,
options: MessageDeserializationOptions | SerialAPIStartedRequestOptions,
) {
super(host, options);
if (gotDeserializationOptions(options)) {
this.wakeUpReason = this.payload[0];
this.watchdogEnabled = this.payload[1] === 0x01;
const deviceOption = this.payload[2];
this.isListening = !!(deviceOption & 0b10_000_000);
this.genericDeviceClass = this.payload[3];
this.specificDeviceClass = this.payload[4];
// Parse list of CCs
const numCCBytes = this.payload[5];
const ccBytes = this.payload.slice(6, 6 + numCCBytes);
const ccList = parseCCList(ccBytes);
this.supportedCCs = ccList.supportedCCs;
this.controlledCCs = ccList.controlledCCs;
// Parse supported protocols
if (this.payload.length >= 6 + numCCBytes + 1) {
const protocols = this.payload[6 + numCCBytes];
this.supportsLongRange = !!(protocols & 0b1);
}
} else {
this.wakeUpReason = options.wakeUpReason;
this.watchdogEnabled = options.watchdogEnabled;
this.isListening = options.isListening;
this.genericDeviceClass = options.genericDeviceClass;
this.specificDeviceClass = options.specificDeviceClass;
this.supportedCCs = options.supportedCCs;
this.controlledCCs = options.controlledCCs;
this.supportsLongRange = options.supportsLongRange;
}
}
public wakeUpReason: SerialAPIWakeUpReason;
public watchdogEnabled: boolean;
public genericDeviceClass: number;
public specificDeviceClass: number;
/** Whether this node is always listening or not */
public isListening: boolean;
public supportedCCs: CommandClasses[];
public controlledCCs: CommandClasses[];
public supportsLongRange: boolean = false;
public serialize(): Buffer {
const ccList = encodeCCList(this.supportedCCs, this.controlledCCs);
const numCCBytes = ccList.length;
this.payload = Buffer.allocUnsafe(6 + numCCBytes + 1);
this.payload[0] = this.wakeUpReason;
this.payload[1] = this.watchdogEnabled ? 0b1 : 0;
this.payload[2] = this.isListening ? 0b10_000_000 : 0;
this.payload[3] = this.genericDeviceClass;
this.payload[4] = this.specificDeviceClass;
this.payload[5] = numCCBytes;
ccList.copy(this.payload, 6);
this.payload[6 + numCCBytes] = this.supportsLongRange ? 0b1 : 0;
return super.serialize();
}
public toLogEntry(): MessageOrCCLogEntry {
return {
...super.toLogEntry(),
message: {
"wake up reason": getEnumMemberName(
SerialAPIWakeUpReason,
this.wakeUpReason,
),
"watchdog enabled": this.watchdogEnabled,
"generic device class": num2hex(this.genericDeviceClass),
"specific device class": num2hex(this.specificDeviceClass),
"always listening": this.isListening,
// Not sure why this information is needed here. At the very least it stretches the log
// "supported CCs": this.supportedCCs
// .map((cc) => `\n· ${getCCName(cc)}`)
// .join(""),
// "controlled CCs": this.controlledCCs
// .map((cc) => `\n· ${getCCName(cc)}`)
// .join(""),
"supports Long Range": this.supportsLongRange,
},
};
}
}