2021-02-20 12:34:30 +01:00
|
|
|
const Logger = require('./Logger');
|
|
|
|
|
|
|
|
|
|
const logger = Logger.getLogger('device-registry');
|
2021-02-01 21:18:42 +01:00
|
|
|
class DeviceRegistry {
|
2021-03-29 12:51:48 +02:00
|
|
|
/** @type {string} */
|
2021-02-01 21:18:42 +01:00
|
|
|
cryptoKey = null;
|
|
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
/** @private @type {Object.<string, import('types/ApiSite').Device>} */
|
|
|
|
|
devices = {};
|
2021-04-01 13:19:02 +02:00
|
|
|
/** @private @type {Object.<string, string[]>} */
|
2021-03-31 19:57:25 +02:00
|
|
|
outputDeviceUniqueIdsByRoomId = {};
|
2021-04-01 13:19:02 +02:00
|
|
|
/** @private @type {Object.<number, string>} */
|
2021-03-31 19:57:25 +02:00
|
|
|
outputUniqueIdByBleOutputAddress = {};
|
2021-04-01 13:19:02 +02:00
|
|
|
/** @private @type {Object.<number, string>} */
|
|
|
|
|
sceneUniqueIdByBleOutputAddress = {};
|
2021-03-31 19:57:25 +02:00
|
|
|
|
|
|
|
|
/** @private @type {import('./types/ApiSite').ApiSite} */
|
|
|
|
|
apiSite;
|
2021-02-01 21:18:42 +01:00
|
|
|
|
|
|
|
|
// Dictionaries of [id]: device per type
|
2021-03-31 19:57:25 +02:00
|
|
|
/** @private @type {import('types/DeviceRegistry').OutputDevices} */
|
2021-03-29 12:51:48 +02:00
|
|
|
outputDevices = {};
|
2021-03-31 19:57:25 +02:00
|
|
|
/** @private @type {import('types/DeviceRegistry').OutputDevices} */
|
2021-02-01 21:18:42 +01:00
|
|
|
sceneDevices = {};
|
2021-05-01 19:41:29 +02:00
|
|
|
/** @private @type {import('types/DeviceRegistry').InputDevices} */
|
|
|
|
|
inputDevices = {};
|
2021-02-01 21:18:42 +01:00
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
/** @param device {import('./types/ApiSite').Device} */
|
|
|
|
|
addPhysicalDevice(device) {
|
|
|
|
|
this.devices[device.deviceId] = device;
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-01 19:41:29 +02:00
|
|
|
/** @param inputDevice {import('types/DeviceRegistry').InputDevice} */
|
|
|
|
|
addInputDevice(inputDevice) {
|
|
|
|
|
this.inputDevices = {
|
|
|
|
|
...this.inputDevices,
|
|
|
|
|
[inputDevice.uniqueId]: inputDevice,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.verbose(
|
|
|
|
|
`Added/updated input device: ${JSON.stringify(inputDevice)}. ${
|
|
|
|
|
Object.keys(this.inputDevices).length
|
|
|
|
|
} output devices in total.`,
|
|
|
|
|
);
|
2021-05-05 19:02:10 +02:00
|
|
|
this.outputUniqueIdByBleOutputAddress[`${inputDevice.bleInputAddress}_${inputDevice.input}`] = inputDevice.uniqueId;
|
2021-05-05 19:34:34 +02:00
|
|
|
}
|
2021-05-01 19:41:29 +02:00
|
|
|
|
2021-03-29 12:51:48 +02:00
|
|
|
/** @param outputDevice {import('types/DeviceRegistry').OutputDevice} */
|
|
|
|
|
addOutputDevice(outputDevice) {
|
2021-04-01 13:19:02 +02:00
|
|
|
if (outputDevice.hiddenFromIntegrations || outputDevice.hiddenFromRoomList) {
|
|
|
|
|
logger.verbose(`Device ${outputDevice.name} is hidden and will not be included.
|
|
|
|
|
Hidden from room list: ${outputDevice.hiddenFromRoomList}
|
|
|
|
|
Hidden from integrations: ${outputDevice.hiddenFromIntegrations}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 12:51:48 +02:00
|
|
|
this.outputDevices = {
|
|
|
|
|
...this.outputDevices,
|
|
|
|
|
[outputDevice.uniqueId]: outputDevice,
|
2021-02-20 12:34:30 +01:00
|
|
|
};
|
|
|
|
|
|
2021-02-20 15:33:06 +01:00
|
|
|
logger.verbose(
|
2021-03-29 12:51:48 +02:00
|
|
|
`Added/updated output device: ${JSON.stringify(outputDevice)}. ${
|
|
|
|
|
Object.keys(this.outputDevices).length
|
|
|
|
|
} output devices in total.`,
|
2021-02-20 15:33:06 +01:00
|
|
|
);
|
2021-02-20 12:34:30 +01:00
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
this.outputUniqueIdByBleOutputAddress[outputDevice.bleOutputAddress] = outputDevice.uniqueId;
|
2021-03-29 12:51:48 +02:00
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
if (!this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId]) {
|
|
|
|
|
this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId] = [];
|
2021-03-29 12:51:48 +02:00
|
|
|
}
|
|
|
|
|
if (
|
2021-03-31 20:04:45 +02:00
|
|
|
outputDevice.roomId !== outputDevice.uniqueId
|
|
|
|
|
&& !this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].includes(outputDevice.uniqueId)
|
2021-03-29 12:51:48 +02:00
|
|
|
) {
|
2021-03-31 19:57:25 +02:00
|
|
|
this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].push(outputDevice.uniqueId);
|
2021-02-20 15:33:06 +01:00
|
|
|
logger.verbose(
|
2021-03-29 12:51:48 +02:00
|
|
|
`Added device to room ${outputDevice.roomId}: ${JSON.stringify(
|
2021-03-31 19:57:25 +02:00
|
|
|
this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId],
|
2021-03-25 16:39:56 +01:00
|
|
|
)}`,
|
2021-02-20 15:33:06 +01:00
|
|
|
);
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 12:51:48 +02:00
|
|
|
/** @param scene {import('types/DeviceRegistry').OutputDevice} */
|
2021-02-20 12:34:30 +01:00
|
|
|
addScene(scene) {
|
|
|
|
|
this.sceneDevices = {
|
|
|
|
|
...this.sceneDevices,
|
2021-03-29 12:51:48 +02:00
|
|
|
[scene.uniqueId]: scene,
|
2021-02-20 12:34:30 +01:00
|
|
|
};
|
2021-04-26 13:13:10 +02:00
|
|
|
this.sceneUniqueIdByBleOutputAddress[scene.bleOutputAddress] = scene.uniqueId;
|
|
|
|
|
|
2021-02-20 15:33:06 +01:00
|
|
|
logger.verbose(
|
2021-03-29 12:51:48 +02:00
|
|
|
`Added/updated scene: ${JSON.stringify(scene)}. ${
|
2021-02-20 15:33:06 +01:00
|
|
|
Object.keys(this.sceneDevices).length
|
|
|
|
|
} scenes in total.`,
|
|
|
|
|
);
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clearPlejdDevices() {
|
2021-03-31 19:57:25 +02:00
|
|
|
this.devices = {};
|
2021-03-29 12:51:48 +02:00
|
|
|
this.outputDevices = {};
|
2021-05-01 19:41:29 +02:00
|
|
|
this.inputDevices = {};
|
2021-03-31 19:57:25 +02:00
|
|
|
this.outputDeviceUniqueIdsByRoomId = {};
|
|
|
|
|
this.outputUniqueIdByBleOutputAddress = {};
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clearSceneDevices() {
|
|
|
|
|
this.sceneDevices = {};
|
2021-04-01 13:19:02 +02:00
|
|
|
this.sceneUniqueIdByBleOutputAddress = {};
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
/**
|
|
|
|
|
* @returns {import('./types/DeviceRegistry').OutputDevice[]}
|
|
|
|
|
*/
|
|
|
|
|
getAllOutputDevices() {
|
|
|
|
|
return Object.values(this.outputDevices);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-01 19:41:29 +02:00
|
|
|
/**
|
|
|
|
|
* @returns {import('./types/DeviceRegistry').InputDevice[]}
|
|
|
|
|
*/
|
2021-05-05 19:34:34 +02:00
|
|
|
getAllInputDevices() {
|
2021-05-01 19:41:29 +02:00
|
|
|
return Object.values(this.inputDevices);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
/**
|
|
|
|
|
* @returns {import('./types/DeviceRegistry').OutputDevice[]}
|
|
|
|
|
*/
|
|
|
|
|
getAllSceneDevices() {
|
|
|
|
|
return Object.values(this.sceneDevices);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @returns {import('./types/ApiSite').ApiSite} */
|
|
|
|
|
getApiSite() {
|
|
|
|
|
return this.apiSite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param {string} uniqueOutputId
|
|
|
|
|
*/
|
2021-03-29 12:51:48 +02:00
|
|
|
getOutputDevice(uniqueOutputId) {
|
|
|
|
|
return this.outputDevices[uniqueOutputId];
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-01 19:41:29 +02:00
|
|
|
/**
|
|
|
|
|
* @param {string} uniqueInputId
|
|
|
|
|
*/
|
2021-05-05 19:34:34 +02:00
|
|
|
getInputDevice(uniqueInputId) {
|
2021-05-01 19:41:29 +02:00
|
|
|
return this.inputDevices[uniqueInputId];
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
/** @returns {import('./types/DeviceRegistry').OutputDevice} */
|
|
|
|
|
getOutputDeviceByBleOutputAddress(bleOutputAddress) {
|
|
|
|
|
return this.outputDevices[this.outputUniqueIdByBleOutputAddress[bleOutputAddress]];
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-01 19:41:29 +02:00
|
|
|
/** @returns {import('./types/DeviceRegistry').InputDevice} */
|
2021-05-05 19:02:10 +02:00
|
|
|
getInputDeviceByBleInputAddress(bleInputAddress, inputButton) {
|
2021-05-05 19:34:34 +02:00
|
|
|
return this.inputDevices[
|
|
|
|
|
this.outputUniqueIdByBleOutputAddress[`${bleInputAddress}_${inputButton}`]
|
|
|
|
|
];
|
2021-05-01 19:41:29 +02:00
|
|
|
}
|
|
|
|
|
|
2021-03-29 12:51:48 +02:00
|
|
|
/** @returns {string[]} */
|
|
|
|
|
getOutputDeviceIdsByRoomId(roomId) {
|
2021-03-31 19:57:25 +02:00
|
|
|
return this.outputDeviceUniqueIdsByRoomId[roomId];
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-29 12:51:48 +02:00
|
|
|
getOutputDeviceName(uniqueOutputId) {
|
|
|
|
|
return (this.outputDevices[uniqueOutputId] || {}).name;
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-01 19:41:29 +02:00
|
|
|
getInputDeviceName(uniqueInputId) {
|
|
|
|
|
return (this.inputDevices[uniqueInputId] || {}).name;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
/**
|
|
|
|
|
* @param {string } deviceId The physical device serial number
|
|
|
|
|
* @return {import('./types/ApiSite').Device}
|
|
|
|
|
*/
|
|
|
|
|
getPhysicalDevice(deviceId) {
|
|
|
|
|
return this.devices[deviceId];
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-01 13:19:02 +02:00
|
|
|
/**
|
|
|
|
|
* @param {string} sceneUniqueId
|
|
|
|
|
*/
|
|
|
|
|
getScene(sceneUniqueId) {
|
|
|
|
|
return this.sceneDevices[sceneUniqueId];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param {number} sceneBleAddress
|
|
|
|
|
*/
|
|
|
|
|
getSceneByBleAddress(sceneBleAddress) {
|
|
|
|
|
const sceneUniqueId = this.sceneUniqueIdByBleOutputAddress[sceneBleAddress];
|
|
|
|
|
if (!sceneUniqueId) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return this.sceneDevices[sceneUniqueId];
|
2021-02-10 10:10:28 +01:00
|
|
|
}
|
|
|
|
|
|
2021-04-01 13:19:02 +02:00
|
|
|
/**
|
|
|
|
|
* @param {string} sceneUniqueId
|
|
|
|
|
*/
|
|
|
|
|
getSceneName(sceneUniqueId) {
|
|
|
|
|
return (this.sceneDevices[sceneUniqueId] || {}).name;
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
2021-02-20 12:34:30 +01:00
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
// eslint-disable-next-line class-methods-use-this
|
|
|
|
|
getUniqueOutputId(deviceId, outputIndex) {
|
|
|
|
|
return `${deviceId}_${outputIndex}`;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-01 19:41:29 +02:00
|
|
|
// eslint-disable-next-line class-methods-use-this
|
|
|
|
|
getUniqueInputId(deviceId, inputIndex) {
|
|
|
|
|
return `${deviceId}_${inputIndex}`;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-31 19:57:25 +02:00
|
|
|
/** @param apiSite {import('./types/ApiSite').ApiSite} */
|
|
|
|
|
setApiSite(apiSite) {
|
|
|
|
|
this.apiSite = apiSite;
|
|
|
|
|
this.cryptoKey = apiSite.plejdMesh.cryptoKey;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-29 12:51:48 +02:00
|
|
|
/**
|
|
|
|
|
* @param {string} uniqueOutputId
|
|
|
|
|
* @param {boolean} state
|
|
|
|
|
* @param {number?} [dim]
|
|
|
|
|
*/
|
|
|
|
|
setOutputState(uniqueOutputId, state, dim) {
|
|
|
|
|
const device = this.getOutputDevice(uniqueOutputId);
|
|
|
|
|
if (!device) {
|
|
|
|
|
logger.warn(
|
|
|
|
|
`Trying to set state for ${uniqueOutputId} which is not in the list of known outputs.`,
|
|
|
|
|
);
|
|
|
|
|
return;
|
2021-02-20 12:34:30 +01:00
|
|
|
}
|
|
|
|
|
|
2021-02-20 15:33:06 +01:00
|
|
|
device.state = state;
|
2021-02-20 12:34:30 +01:00
|
|
|
if (dim && device.dimmable) {
|
|
|
|
|
device.dim = dim;
|
|
|
|
|
}
|
|
|
|
|
if (Logger.shouldLog('silly')) {
|
|
|
|
|
logger.silly(`Updated state: ${JSON.stringify(device)}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-01 21:18:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = DeviceRegistry;
|