zwave-js
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
273 lines • 11.8 kB
JavaScript
import { KeypadMode, UserIDStatus } from "@zwave-js/cc";
import { UserCodeCCAdminCodeGet, UserCodeCCAdminCodeReport, UserCodeCCAdminCodeSet, UserCodeCCCapabilitiesGet, UserCodeCCCapabilitiesReport, UserCodeCCExtendedUserCodeSet, UserCodeCCGet, UserCodeCCKeypadModeGet, UserCodeCCKeypadModeReport, UserCodeCCKeypadModeSet, UserCodeCCReport, UserCodeCCSet, UserCodeCCUserCodeChecksumGet, UserCodeCCUserCodeChecksumReport, UserCodeCCUsersNumberGet, UserCodeCCUsersNumberReport, } from "@zwave-js/cc/UserCodeCC";
import { CRC16_CCITT, CommandClasses } from "@zwave-js/core";
import { Bytes } from "@zwave-js/shared";
export const defaultCapabilities = {
numUsers: 1,
supportedASCIIChars: "0123456789",
supportsAdminCode: true,
supportsAdminCodeDeactivation: true,
supportsUserCodeChecksum: true,
supportedKeypadModes: [KeypadMode.Normal],
supportedUserIDStatuses: [
UserIDStatus.Available,
UserIDStatus.Enabled,
UserIDStatus.Disabled,
],
};
const STATE_KEY_PREFIX = "UserCode_";
const StateKeys = {
userCode: (userId) => `${STATE_KEY_PREFIX}userCode_${userId}`,
userIdStatus: (userId) => `${STATE_KEY_PREFIX}userIdStatus_${userId}`,
adminCode: `${STATE_KEY_PREFIX}adminCode`,
keypadMode: `${STATE_KEY_PREFIX}keypadMode`,
};
const respondToUsersNumberGet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCUsersNumberGet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
const cc = new UserCodeCCUsersNumberReport({
nodeId: controller.ownNodeId,
supportedUsers: capabilities.numUsers ?? 1,
});
return { action: "sendCC", cc };
}
},
};
const respondToUserGet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCGet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
const userId = receivedCC.userId;
let cc;
if (capabilities.numUsers >= userId) {
cc = new UserCodeCCReport({
nodeId: controller.ownNodeId,
userId,
userIdStatus: (self.state.get(StateKeys.userIdStatus(userId)) ?? UserIDStatus.Available),
userCode: self.state.get(StateKeys.userCode(userId)),
});
}
else {
cc = new UserCodeCCReport({
nodeId: controller.ownNodeId,
userId,
userIdStatus: UserIDStatus.StatusNotAvailable,
});
}
return { action: "sendCC", cc };
}
},
};
const respondToUserCodeSet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCSet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
const userId = receivedCC.userId;
const userIdStatus = receivedCC.userIdStatus;
if (capabilities.numUsers >= userId) {
self.state.set(StateKeys.userIdStatus(userId), userIdStatus);
const code = userIdStatus !== UserIDStatus.Available
&& userIdStatus !== UserIDStatus.StatusNotAvailable
? receivedCC.userCode
: undefined;
self.state.set(StateKeys.userCode(userId), code);
return { action: "ok" };
}
return { action: "fail" };
}
},
};
const respondToExtendedUserCodeSet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCExtendedUserCodeSet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
// Process each user code in the request
for (const userCodeData of receivedCC.userCodes) {
const userId = userCodeData.userId;
const userIdStatus = userCodeData.userIdStatus;
// Skip if userId is 0 and we're clearing all codes
if (userId === 0 && userIdStatus === UserIDStatus.Available) {
// Clear all user codes
const numUsers = capabilities.numUsers ?? 0;
for (let i = 1; i <= numUsers; i++) {
self.state.set(StateKeys.userIdStatus(i), UserIDStatus.Available);
self.state.set(StateKeys.userCode(i), undefined);
}
continue;
}
if (capabilities.numUsers != undefined
&& capabilities.numUsers >= userId) {
self.state.set(StateKeys.userIdStatus(userId), userIdStatus);
const code = userIdStatus !== UserIDStatus.Available
// @ts-expect-error Just making sure that we're not accidentally
// passing the wrong status
&& userIdStatus !== UserIDStatus.StatusNotAvailable
? userCodeData.userCode
: undefined;
self.state.set(StateKeys.userCode(userId), code);
}
else {
return { action: "fail" };
}
}
return { action: "ok" };
}
},
};
const respondToUserCodeCapabilitiesGet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCCapabilitiesGet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
const cc = new UserCodeCCCapabilitiesReport({
nodeId: controller.ownNodeId,
supportsAdminCode: capabilities.supportsAdminCode,
supportsAdminCodeDeactivation: capabilities
.supportsAdminCodeDeactivation,
supportsUserCodeChecksum: capabilities
.supportsUserCodeChecksum,
supportsMultipleUserCodeReport: false,
supportsMultipleUserCodeSet: false,
supportedUserIDStatuses: capabilities.supportedUserIDStatuses,
supportedKeypadModes: capabilities.supportedKeypadModes,
supportedASCIIChars: capabilities.supportedASCIIChars,
});
return { action: "sendCC", cc };
}
},
};
const respondToUserCodeKeypadModeGet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCKeypadModeGet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
const cc = new UserCodeCCKeypadModeReport({
nodeId: controller.ownNodeId,
keypadMode: (self.state.get(StateKeys.keypadMode)
?? capabilities.supportedKeypadModes?.[0]
?? KeypadMode.Normal),
});
return { action: "sendCC", cc };
}
},
};
const respondToUserCodeKeypadModeSet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCKeypadModeSet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
if (capabilities.supportedKeypadModes?.includes(receivedCC.keypadMode)) {
self.state.set(StateKeys.keypadMode, receivedCC.keypadMode);
return { action: "ok" };
}
return { action: "fail" };
}
},
};
const respondToUserCodeAdminCodeSet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCAdminCodeSet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
const adminCode = receivedCC.adminCode;
if (capabilities.supportsAdminCode) {
if (adminCode.length > 0
|| capabilities.supportsAdminCodeDeactivation) {
self.state.set(StateKeys.adminCode, receivedCC.adminCode);
return { action: "ok" };
}
}
return { action: "fail" };
}
},
};
const respondToUserCodeAdminCodeGet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCAdminCodeGet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
let adminCode;
if (capabilities.supportsAdminCode) {
adminCode = self.state.get(StateKeys.adminCode);
}
const cc = new UserCodeCCAdminCodeReport({
nodeId: controller.ownNodeId,
adminCode: adminCode ?? "",
});
return { action: "sendCC", cc };
}
},
};
const respondToUserCodeUserCodeChecksumGet = {
handleCC(controller, self, receivedCC) {
if (receivedCC instanceof UserCodeCCUserCodeChecksumGet) {
const capabilities = {
...defaultCapabilities,
...self.getCCCapabilities(CommandClasses["User Code"], receivedCC.endpointIndex),
};
if (capabilities.supportsUserCodeChecksum) {
let data = new Bytes();
for (let i = 1; i <= capabilities.numUsers; i++) {
const status = self.state.get(StateKeys.userIdStatus(i));
let code = (self.state.get(StateKeys.userCode(i)) ?? "");
if (status === undefined
|| status === UserIDStatus.Available
|| code.length === 0) {
continue;
}
const tmp = new Bytes(3 + code.length);
tmp.writeUInt16BE(i, 0);
tmp[2] = status;
if (typeof code === "string") {
code = Bytes.from(code, "ascii");
}
tmp.set(code, 3);
data = Bytes.concat([data, tmp]);
}
const checksum = data.length > 0 ? CRC16_CCITT(data) : 0x0000;
const cc = new UserCodeCCUserCodeChecksumReport({
nodeId: controller.ownNodeId,
userCodeChecksum: checksum,
});
return { action: "sendCC", cc };
}
return { action: "stop" };
}
},
};
export const UserCodeCCBehaviors = [
respondToUsersNumberGet,
respondToUserGet,
respondToUserCodeSet,
respondToExtendedUserCodeSet,
respondToUserCodeCapabilitiesGet,
respondToUserCodeKeypadModeGet,
respondToUserCodeKeypadModeSet,
respondToUserCodeAdminCodeGet,
respondToUserCodeAdminCodeSet,
respondToUserCodeUserCodeChecksumGet,
];
//# sourceMappingURL=UserCode.js.map