Refactor code to use plejd outputs rather than devices as main entity
This commit is contained in:
parent
ef718cf1db
commit
9a76a3ba50
10 changed files with 185 additions and 158 deletions
|
|
@ -45,8 +45,8 @@ class DeviceRegistry {
|
||||||
this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId] = [];
|
this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId] = [];
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
outputDevice.roomId !== outputDevice.uniqueId &&
|
outputDevice.roomId !== outputDevice.uniqueId
|
||||||
!this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].includes(outputDevice.uniqueId)
|
&& !this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].includes(outputDevice.uniqueId)
|
||||||
) {
|
) {
|
||||||
this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].push(outputDevice.uniqueId);
|
this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].push(outputDevice.uniqueId);
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
|
|
|
||||||
|
|
@ -65,23 +65,26 @@ class PlejdAddon extends EventEmitter {
|
||||||
});
|
});
|
||||||
|
|
||||||
// subscribe to changes from HA
|
// subscribe to changes from HA
|
||||||
this.mqttClient.on(MqttClient.EVENTS.stateChanged, (device, command) => {
|
this.mqttClient.on(
|
||||||
|
MqttClient.EVENTS.stateChanged,
|
||||||
|
/** @param device {import('./types/DeviceRegistry').OutputDevice} */
|
||||||
|
(device, command) => {
|
||||||
try {
|
try {
|
||||||
const deviceId = device.id;
|
const { uniqueId } = device;
|
||||||
|
|
||||||
if (device.typeName === 'Scene') {
|
if (device.typeName === 'Scene') {
|
||||||
// we're triggering a scene, lets do that and jump out.
|
// we're triggering a scene, lets do that and jump out.
|
||||||
// since scenes aren't "real" devices.
|
// since scenes aren't "real" devices.
|
||||||
this.sceneManager.executeScene(device.id);
|
this.sceneManager.executeScene(uniqueId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = 'OFF';
|
let state = false;
|
||||||
let commandObj = {};
|
let commandObj = {};
|
||||||
|
|
||||||
if (typeof command === 'string') {
|
if (typeof command === 'string') {
|
||||||
// switch command
|
// switch command
|
||||||
state = command;
|
state = command === 'ON';
|
||||||
commandObj = {
|
commandObj = {
|
||||||
state,
|
state,
|
||||||
};
|
};
|
||||||
|
|
@ -89,33 +92,34 @@ class PlejdAddon extends EventEmitter {
|
||||||
// since the switch doesn't get any updates on whether it's on or not,
|
// since the switch doesn't get any updates on whether it's on or not,
|
||||||
// we fake this by directly send the updateState back to HA in order for
|
// we fake this by directly send the updateState back to HA in order for
|
||||||
// it to change state.
|
// it to change state.
|
||||||
this.mqttClient.updateState(deviceId, {
|
this.mqttClient.updateOutputState(uniqueId, {
|
||||||
state: state === 'ON' ? 1 : 0,
|
state,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line prefer-destructuring
|
// eslint-disable-next-line prefer-destructuring
|
||||||
state = command.state;
|
state = command.state === 'ON';
|
||||||
commandObj = command;
|
commandObj = command;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state === 'ON') {
|
if (state) {
|
||||||
this.plejdDeviceCommunication.turnOn(deviceId, commandObj);
|
this.plejdDeviceCommunication.turnOn(uniqueId, commandObj);
|
||||||
} else {
|
} else {
|
||||||
this.plejdDeviceCommunication.turnOff(deviceId, commandObj);
|
this.plejdDeviceCommunication.turnOff(uniqueId, commandObj);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Error in MqttClient.stateChanged callback', err);
|
logger.error('Error in MqttClient.stateChanged callback', err);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this.mqttClient.init();
|
this.mqttClient.init();
|
||||||
|
|
||||||
// subscribe to changes from Plejd
|
// subscribe to changes from Plejd
|
||||||
this.plejdDeviceCommunication.on(
|
this.plejdDeviceCommunication.on(
|
||||||
PlejdDeviceCommunication.EVENTS.stateChanged,
|
PlejdDeviceCommunication.EVENTS.stateChanged,
|
||||||
(deviceId, command) => {
|
(uniqueOutputId, command) => {
|
||||||
try {
|
try {
|
||||||
this.mqttClient.updateState(deviceId, command);
|
this.mqttClient.updateOutputState(uniqueOutputId, command);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Error in PlejdService.stateChanged callback', err);
|
logger.error('Error in PlejdService.stateChanged callback', err);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,8 @@ class PlejdApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.deviceRegistry.cryptoKey = this.siteDetails.plejdMesh.cryptoKey;
|
|
||||||
|
|
||||||
|
this.deviceRegistry.setApiSite(this.siteDetails);
|
||||||
this.getDevices();
|
this.getDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,20 +300,22 @@ class PlejdApi {
|
||||||
* * `devices` - physical Plejd devices, duplicated for devices with multiple outputs
|
* * `devices` - physical Plejd devices, duplicated for devices with multiple outputs
|
||||||
* devices: [{deviceId, title, objectId, ...}, {...}]
|
* devices: [{deviceId, title, objectId, ...}, {...}]
|
||||||
* * `deviceAddress` - BLE address of each physical device
|
* * `deviceAddress` - BLE address of each physical device
|
||||||
* deviceAddress: {[deviceId]: bleDeviceId}
|
* deviceAddress: {[deviceId]: bleDeviceAddress}
|
||||||
* * `outputSettings` - lots of info about load settings, also links devices to output index
|
* * `outputSettings` - lots of info about load settings, also links devices to output index
|
||||||
* outputSettings: [{deviceId, output, deviceParseId, ...}] //deviceParseId === objectId above
|
* outputSettings: [{deviceId, output, deviceParseId, ...}] //deviceParseId === objectId above
|
||||||
* * `outputAddress`: BLE address of [0] main output and [n] other output (loads)
|
* * `outputAddress`: BLE address of [0] main output and [n] other output (loads)
|
||||||
* outputAddress: {[deviceId]: {[output]: bleDeviceId}}
|
* outputAddress: {[deviceId]: {[output]: bleDeviceAddress}}
|
||||||
* * `inputSettings` - detailed settings for inputs (buttons, RTR-01, ...), scenes triggered, ...
|
* * `inputSettings` - detailed settings for inputs (buttons, RTR-01, ...), scenes triggered, ...
|
||||||
* inputSettings: [{deviceId, input, ...}] //deviceParseId === objectId above
|
* inputSettings: [{deviceId, input, ...}] //deviceParseId === objectId above
|
||||||
* * `inputAddress` - Links inputs to what BLE device they control, or 255 for unassigned/scene
|
* * `inputAddress` - Links inputs to what BLE device they control, or 255 for unassigned/scene
|
||||||
* inputAddress: {[deviceId]: {[input]: bleDeviceId}}
|
* inputAddress: {[deviceId]: {[input]: bleDeviceAddress}}
|
||||||
*/
|
*/
|
||||||
_getPlejdDevices() {
|
_getPlejdDevices() {
|
||||||
this.deviceRegistry.clearPlejdDevices();
|
this.deviceRegistry.clearPlejdDevices();
|
||||||
|
|
||||||
this.siteDetails.devices.forEach((device) => {
|
this.siteDetails.devices.forEach((device) => {
|
||||||
|
this.deviceRegistry.addPhysicalDevice(device);
|
||||||
|
|
||||||
const outputSettings = this.siteDetails.outputSettings.find(
|
const outputSettings = this.siteDetails.outputSettings.find(
|
||||||
(x) => x.deviceParseId === device.objectId,
|
(x) => x.deviceParseId === device.objectId,
|
||||||
);
|
);
|
||||||
|
|
@ -328,7 +330,7 @@ class PlejdApi {
|
||||||
outputSettings.output,
|
outputSettings.output,
|
||||||
);
|
);
|
||||||
|
|
||||||
const bleDeviceIndex = this.siteDetails.outputAddress[device.deviceId][
|
const bleOutputAddress = this.siteDetails.outputAddress[device.deviceId][
|
||||||
outputSettings.output
|
outputSettings.output
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -343,7 +345,7 @@ class PlejdApi {
|
||||||
|
|
||||||
/** @type {import('types/DeviceRegistry').OutputDevice} */
|
/** @type {import('types/DeviceRegistry').OutputDevice} */
|
||||||
const outputDevice = {
|
const outputDevice = {
|
||||||
bleDeviceIndex,
|
bleOutputAddress,
|
||||||
deviceId: device.deviceId,
|
deviceId: device.deviceId,
|
||||||
dimmable,
|
dimmable,
|
||||||
hiddenFromRoomList: device.hiddenFromRoomList,
|
hiddenFromRoomList: device.hiddenFromRoomList,
|
||||||
|
|
@ -409,7 +411,7 @@ class PlejdApi {
|
||||||
|
|
||||||
/** @type {import('types/DeviceRegistry').OutputDevice} */
|
/** @type {import('types/DeviceRegistry').OutputDevice} */
|
||||||
const newDevice = {
|
const newDevice = {
|
||||||
bleDeviceIndex: roomAddress,
|
bleOutputAddress: roomAddress,
|
||||||
deviceId: null,
|
deviceId: null,
|
||||||
dimmable,
|
dimmable,
|
||||||
hiddenFromRoomList: false,
|
hiddenFromRoomList: false,
|
||||||
|
|
@ -431,6 +433,7 @@ class PlejdApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
_getSceneDevices() {
|
_getSceneDevices() {
|
||||||
|
this.deviceRegistry.clearSceneDevices();
|
||||||
// add scenes as switches
|
// add scenes as switches
|
||||||
const scenes = this.siteDetails.scenes.filter((x) => x.hiddenFromSceneList === false);
|
const scenes = this.siteDetails.scenes.filter((x) => x.hiddenFromSceneList === false);
|
||||||
|
|
||||||
|
|
@ -438,7 +441,7 @@ class PlejdApi {
|
||||||
const sceneNum = this.siteDetails.sceneIndex[scene.sceneId];
|
const sceneNum = this.siteDetails.sceneIndex[scene.sceneId];
|
||||||
/** @type {import('types/DeviceRegistry').OutputDevice} */
|
/** @type {import('types/DeviceRegistry').OutputDevice} */
|
||||||
const newScene = {
|
const newScene = {
|
||||||
bleDeviceIndex: sceneNum,
|
bleOutputAddress: sceneNum,
|
||||||
deviceId: undefined,
|
deviceId: undefined,
|
||||||
dimmable: false,
|
dimmable: false,
|
||||||
hiddenFromSceneList: scene.hiddenFromSceneList,
|
hiddenFromSceneList: scene.hiddenFromSceneList,
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
connectedDevice = null;
|
connectedDevice = null;
|
||||||
consecutiveWriteFails;
|
consecutiveWriteFails;
|
||||||
consecutiveReconnectAttempts = 0;
|
consecutiveReconnectAttempts = 0;
|
||||||
|
/** @type {import('./DeviceRegistry')} */
|
||||||
|
deviceRegistry;
|
||||||
discoveryTimeout = null;
|
discoveryTimeout = null;
|
||||||
plejdService = null;
|
plejdService = null;
|
||||||
pingRef = null;
|
pingRef = null;
|
||||||
|
|
@ -152,21 +154,21 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
logger.info('BLE init done, waiting for devices.');
|
logger.info('BLE init done, waiting for devices.');
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendCommand(command, deviceId, data) {
|
async sendCommand(command, uniqueOutputId, data) {
|
||||||
let payload;
|
let payload;
|
||||||
let brightnessVal;
|
let brightnessVal;
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case COMMANDS.TURN_ON:
|
case COMMANDS.TURN_ON:
|
||||||
payload = this._createHexPayload(deviceId, BLE_CMD_STATE_CHANGE, '01');
|
payload = this._createHexPayload(uniqueOutputId, BLE_CMD_STATE_CHANGE, '01');
|
||||||
break;
|
break;
|
||||||
case COMMANDS.TURN_OFF:
|
case COMMANDS.TURN_OFF:
|
||||||
payload = this._createHexPayload(deviceId, BLE_CMD_STATE_CHANGE, '00');
|
payload = this._createHexPayload(uniqueOutputId, BLE_CMD_STATE_CHANGE, '00');
|
||||||
break;
|
break;
|
||||||
case COMMANDS.DIM:
|
case COMMANDS.DIM:
|
||||||
// eslint-disable-next-line no-bitwise
|
// eslint-disable-next-line no-bitwise
|
||||||
brightnessVal = (data << 8) | data;
|
brightnessVal = (data << 8) | data;
|
||||||
payload = this._createHexPayload(
|
payload = this._createHexPayload(
|
||||||
deviceId,
|
uniqueOutputId,
|
||||||
BLE_CMD_DIM2_CHANGE,
|
BLE_CMD_DIM2_CHANGE,
|
||||||
`01${brightnessVal.toString(16).padStart(4, '0')}`,
|
`01${brightnessVal.toString(16).padStart(4, '0')}`,
|
||||||
);
|
);
|
||||||
|
|
@ -194,9 +196,9 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
plejd.instance = device;
|
plejd.instance = device;
|
||||||
|
|
||||||
const segments = plejd.path.split('/');
|
const segments = plejd.path.split('/');
|
||||||
let fixedPlejdPath = segments[segments.length - 1].replace('dev_', '');
|
let plejdSerialNumber = segments[segments.length - 1].replace('dev_', '');
|
||||||
fixedPlejdPath = fixedPlejdPath.replace(/_/g, '');
|
plejdSerialNumber = plejdSerialNumber.replace(/_/g, '');
|
||||||
plejd.device = this.deviceRegistry.getDeviceBySerialNumber(fixedPlejdPath);
|
plejd.device = this.deviceRegistry.getPhysicalDevice(plejdSerialNumber);
|
||||||
|
|
||||||
if (plejd.device) {
|
if (plejd.device) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
|
@ -204,7 +206,7 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
);
|
);
|
||||||
this.bleDevices.push(plejd);
|
this.bleDevices.push(plejd);
|
||||||
} else {
|
} else {
|
||||||
logger.warn(`Device registry does not contain device with serial ${fixedPlejdPath}`);
|
logger.warn(`Device registry does not contain device with serial ${plejdSerialNumber}`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(`Failed inspecting ${path}. `, err);
|
logger.error(`Failed inspecting ${path}. `, err);
|
||||||
|
|
@ -796,7 +798,7 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceId = decoded.readUInt8(0);
|
const bleOutputAddress = decoded.readUInt8(0);
|
||||||
// Bytes 2-3 is Command/Request
|
// Bytes 2-3 is Command/Request
|
||||||
const cmd = decoded.readUInt16BE(3);
|
const cmd = decoded.readUInt16BE(3);
|
||||||
|
|
||||||
|
|
@ -810,38 +812,41 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
logger.silly(`Dim: ${dim.toString(16)}, full precision: ${dimFull.toString(16)}`);
|
logger.silly(`Dim: ${dim.toString(16)}, full precision: ${dimFull.toString(16)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceName = this.deviceRegistry.getDeviceName(deviceId);
|
const device = this.deviceRegistry.getOutputDeviceByBleOutputAddress(bleOutputAddress);
|
||||||
|
const deviceName = device ? device.name : 'Unknown';
|
||||||
|
const outputUniqueId = device ? device.uniqueId : null;
|
||||||
|
|
||||||
if (Logger.shouldLog('verbose')) {
|
if (Logger.shouldLog('verbose')) {
|
||||||
// decoded.toString() could potentially be expensive
|
// decoded.toString() could potentially be expensive
|
||||||
logger.verbose(`Raw event received: ${decoded.toString('hex')}`);
|
logger.verbose(`Raw event received: ${decoded.toString('hex')}`);
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
`Decoded: Device ${deviceId}, cmd ${cmd.toString(16)}, state ${state}, dim ${dim}`,
|
`Decoded: Device ${outputUniqueId}, cmd ${cmd.toString(16)}, state ${state}, dim ${dim}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let command;
|
let command;
|
||||||
let data = {};
|
let data = {};
|
||||||
if (cmd === BLE_CMD_DIM_CHANGE || cmd === BLE_CMD_DIM2_CHANGE) {
|
if (cmd === BLE_CMD_DIM_CHANGE || cmd === BLE_CMD_DIM2_CHANGE) {
|
||||||
logger.debug(`${deviceName} (${deviceId}) got state+dim update. S: ${state}, D: ${dim}`);
|
logger.debug(
|
||||||
|
`${deviceName} (${outputUniqueId}) got state+dim update. S: ${state}, D: ${dim}`,
|
||||||
|
);
|
||||||
|
|
||||||
command = COMMANDS.DIM;
|
command = COMMANDS.DIM;
|
||||||
data = { state, dim };
|
data = { state, dim };
|
||||||
this.emit(PlejBLEHandler.EVENTS.commandReceived, deviceId, command, data);
|
this.emit(PlejBLEHandler.EVENTS.commandReceived, outputUniqueId, command, data);
|
||||||
} else if (cmd === BLE_CMD_STATE_CHANGE) {
|
} else if (cmd === BLE_CMD_STATE_CHANGE) {
|
||||||
logger.debug(`${deviceName} (${deviceId}) got state update. S: ${state}`);
|
logger.debug(`${deviceName} (${outputUniqueId}) got state update. S: ${state}`);
|
||||||
command = state ? COMMANDS.TURN_ON : COMMANDS.TURN_OFF;
|
command = state ? COMMANDS.TURN_ON : COMMANDS.TURN_OFF;
|
||||||
this.emit(PlejBLEHandler.EVENTS.commandReceived, deviceId, command, data);
|
this.emit(PlejBLEHandler.EVENTS.commandReceived, outputUniqueId, command, data);
|
||||||
} else if (cmd === BLE_CMD_SCENE_TRIG) {
|
} else if (cmd === BLE_CMD_SCENE_TRIG) {
|
||||||
const sceneId = state;
|
const sceneId = state;
|
||||||
const sceneName = this.deviceRegistry.getSceneName(sceneId);
|
const sceneName = this.deviceRegistry.getSceneName(sceneId);
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(`${sceneName} (${sceneId}) scene triggered (device id ${outputUniqueId}).`);
|
||||||
`${sceneName} (${sceneId}) scene triggered (device id ${deviceId}). Name can be misleading if there is a device with the same numeric id.`,
|
|
||||||
);
|
|
||||||
|
|
||||||
command = COMMANDS.TRIGGER_SCENE;
|
command = COMMANDS.TRIGGER_SCENE;
|
||||||
data = { sceneId };
|
data = { sceneId };
|
||||||
this.emit(PlejBLEHandler.EVENTS.commandReceived, deviceId, command, data);
|
this.emit(PlejBLEHandler.EVENTS.commandReceived, outputUniqueId, command, data);
|
||||||
} else if (cmd === BLE_CMD_TIME_UPDATE) {
|
} else if (cmd === BLE_CMD_TIME_UPDATE) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
// Guess Plejd timezone based on HA time zone
|
// Guess Plejd timezone based on HA time zone
|
||||||
|
|
@ -851,7 +856,7 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
const plejdTimestampUTC = (decoded.readInt32LE(5) + offsetSecondsGuess) * 1000;
|
const plejdTimestampUTC = (decoded.readInt32LE(5) + offsetSecondsGuess) * 1000;
|
||||||
const diffSeconds = Math.round((plejdTimestampUTC - now.getTime()) / 1000);
|
const diffSeconds = Math.round((plejdTimestampUTC - now.getTime()) / 1000);
|
||||||
if (
|
if (
|
||||||
deviceId !== BLE_BROADCAST_DEVICE_ID
|
bleOutputAddress !== BLE_BROADCAST_DEVICE_ID
|
||||||
|| Logger.shouldLog('verbose')
|
|| Logger.shouldLog('verbose')
|
||||||
|| Math.abs(diffSeconds) > 60
|
|| Math.abs(diffSeconds) > 60
|
||||||
) {
|
) {
|
||||||
|
|
@ -863,7 +868,7 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`Plejd clock time off by more than 1 minute. Reported time: ${plejdTime.toString()}, diff ${diffSeconds} seconds. Time will be set hourly.`,
|
`Plejd clock time off by more than 1 minute. Reported time: ${plejdTime.toString()}, diff ${diffSeconds} seconds. Time will be set hourly.`,
|
||||||
);
|
);
|
||||||
if (this.connectedDevice && deviceId === this.connectedDevice.id) {
|
if (this.connectedDevice && bleOutputAddress === this.connectedDevice.id) {
|
||||||
// Requested time sync by us
|
// Requested time sync by us
|
||||||
const newLocalTimestamp = now.getTime() / 1000 - offsetSecondsGuess;
|
const newLocalTimestamp = now.getTime() / 1000 - offsetSecondsGuess;
|
||||||
logger.info(`Setting time to ${now.toString()}`);
|
logger.info(`Setting time to ${now.toString()}`);
|
||||||
|
|
@ -881,7 +886,7 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (deviceId !== BLE_BROADCAST_DEVICE_ID) {
|
} else if (bleOutputAddress !== BLE_BROADCAST_DEVICE_ID) {
|
||||||
logger.info('Got time response. Plejd clock time in sync with Home Assistant time');
|
logger.info('Got time response. Plejd clock time in sync with Home Assistant time');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -889,19 +894,19 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
`Command ${cmd.toString(16)} unknown. ${decoded.toString(
|
`Command ${cmd.toString(16)} unknown. ${decoded.toString(
|
||||||
'hex',
|
'hex',
|
||||||
)}. Device ${deviceName} (${deviceId})`,
|
)}. Device ${deviceName} (${bleOutputAddress}: ${outputUniqueId})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_createHexPayload(
|
_createHexPayload(
|
||||||
deviceId,
|
bleOutputAddress,
|
||||||
command,
|
command,
|
||||||
hexDataString,
|
hexDataString,
|
||||||
requestResponseCommand = BLE_REQUEST_NO_RESPONSE,
|
requestResponseCommand = BLE_REQUEST_NO_RESPONSE,
|
||||||
) {
|
) {
|
||||||
return this._createPayload(
|
return this._createPayload(
|
||||||
deviceId,
|
bleOutputAddress,
|
||||||
command,
|
command,
|
||||||
5 + Math.ceil(hexDataString.length / 2),
|
5 + Math.ceil(hexDataString.length / 2),
|
||||||
(payload) => payload.write(hexDataString, 5, 'hex'),
|
(payload) => payload.write(hexDataString, 5, 'hex'),
|
||||||
|
|
@ -911,14 +916,14 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
_createPayload(
|
_createPayload(
|
||||||
deviceId,
|
bleOutputAddress,
|
||||||
command,
|
command,
|
||||||
bufferLength,
|
bufferLength,
|
||||||
payloadBufferAddDataFunc,
|
payloadBufferAddDataFunc,
|
||||||
requestResponseCommand = BLE_REQUEST_NO_RESPONSE,
|
requestResponseCommand = BLE_REQUEST_NO_RESPONSE,
|
||||||
) {
|
) {
|
||||||
const payload = Buffer.alloc(bufferLength);
|
const payload = Buffer.alloc(bufferLength);
|
||||||
payload.writeUInt8(deviceId);
|
payload.writeUInt8(bleOutputAddress);
|
||||||
payload.writeUInt16BE(requestResponseCommand, 1);
|
payload.writeUInt16BE(requestResponseCommand, 1);
|
||||||
payload.writeUInt16BE(command, 3);
|
payload.writeUInt16BE(command, 3);
|
||||||
payloadBufferAddDataFunc(payload);
|
payloadBufferAddDataFunc(payload);
|
||||||
|
|
@ -945,12 +950,12 @@ class PlejBLEHandler extends EventEmitter {
|
||||||
|
|
||||||
let ct = cipher.update(buf).toString('hex');
|
let ct = cipher.update(buf).toString('hex');
|
||||||
ct += cipher.final().toString('hex');
|
ct += cipher.final().toString('hex');
|
||||||
ct = Buffer.from(ct, 'hex');
|
const ctBuf = Buffer.from(ct, 'hex');
|
||||||
|
|
||||||
let output = '';
|
let output = '';
|
||||||
for (let i = 0, { length } = data; i < length; i++) {
|
for (let i = 0, { length } = data; i < length; i++) {
|
||||||
// eslint-disable-next-line no-bitwise
|
// eslint-disable-next-line no-bitwise
|
||||||
output += String.fromCharCode(data[i] ^ ct[i % 16]);
|
output += String.fromCharCode(data[i] ^ ctBuf[i % 16]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Buffer.from(output, 'ascii');
|
return Buffer.from(output, 'ascii');
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,13 @@ const MAX_RETRY_COUNT = 10; // Could be made a setting
|
||||||
|
|
||||||
class PlejdDeviceCommunication extends EventEmitter {
|
class PlejdDeviceCommunication extends EventEmitter {
|
||||||
bleConnected;
|
bleConnected;
|
||||||
bleDeviceTransitionTimers = {};
|
bleOutputTransitionTimers = {};
|
||||||
plejdBleHandler;
|
plejdBleHandler;
|
||||||
config;
|
config;
|
||||||
/** @type {import('./DeviceRegistry')} */
|
/** @type {import('./DeviceRegistry')} */
|
||||||
deviceRegistry;
|
deviceRegistry;
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
/** @type {{uniqueOutputId: string, command: string, data: any, shouldRetry: boolean, retryCount?: number}[]} */
|
||||||
writeQueue = [];
|
writeQueue = [];
|
||||||
writeQueueRef = null;
|
writeQueueRef = null;
|
||||||
|
|
||||||
|
|
@ -35,7 +37,7 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
Object.values(this.bleDeviceTransitionTimers).forEach((t) => clearTimeout(t));
|
Object.values(this.bleOutputTransitionTimers).forEach((t) => clearTimeout(t));
|
||||||
this.plejdBleHandler.cleanup();
|
this.plejdBleHandler.cleanup();
|
||||||
this.plejdBleHandler.removeAllListeners(PlejBLEHandler.EVENTS.commandReceived);
|
this.plejdBleHandler.removeAllListeners(PlejBLEHandler.EVENTS.commandReceived);
|
||||||
this.plejdBleHandler.removeAllListeners(PlejBLEHandler.EVENTS.connected);
|
this.plejdBleHandler.removeAllListeners(PlejBLEHandler.EVENTS.connected);
|
||||||
|
|
@ -47,7 +49,10 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
this.bleConnected = false;
|
this.bleConnected = false;
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
this.plejdBleHandler.on(PlejBLEHandler.EVENTS.commandReceived, (deviceId, command, data) => this._bleCommandReceived(deviceId, command, data));
|
this.plejdBleHandler.on(
|
||||||
|
PlejBLEHandler.EVENTS.commandReceived,
|
||||||
|
(uniqueOutputId, command, data) => this._bleCommandReceived(uniqueOutputId, command, data),
|
||||||
|
);
|
||||||
|
|
||||||
this.plejdBleHandler.on(PlejBLEHandler.EVENTS.connected, () => {
|
this.plejdBleHandler.on(PlejBLEHandler.EVENTS.connected, () => {
|
||||||
logger.info('Bluetooth connected. Plejd BLE up and running!');
|
logger.info('Bluetooth connected. Plejd BLE up and running!');
|
||||||
|
|
@ -71,42 +76,42 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
turnOn(deviceId, command) {
|
turnOn(uniqueOutputId, command) {
|
||||||
const deviceName = this.deviceRegistry.getOutputDeviceName(deviceId);
|
const deviceName = this.deviceRegistry.getOutputDeviceName(uniqueOutputId);
|
||||||
logger.info(
|
logger.info(
|
||||||
`Plejd got turn on command for ${deviceName} (${deviceId}), brightness ${command.brightness}${
|
`Plejd got turn on command for ${deviceName} (${uniqueOutputId}), brightness ${
|
||||||
|
command.brightness
|
||||||
|
}${command.transition ? `, transition: ${command.transition}` : ''}`,
|
||||||
|
);
|
||||||
|
this._transitionTo(uniqueOutputId, command.brightness, command.transition, deviceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
turnOff(uniqueOutputId, command) {
|
||||||
|
const deviceName = this.deviceRegistry.getOutputDeviceName(uniqueOutputId);
|
||||||
|
logger.info(
|
||||||
|
`Plejd got turn off command for ${deviceName} (${uniqueOutputId})${
|
||||||
command.transition ? `, transition: ${command.transition}` : ''
|
command.transition ? `, transition: ${command.transition}` : ''
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
this._transitionTo(deviceId, command.brightness, command.transition, deviceName);
|
this._transitionTo(uniqueOutputId, 0, command.transition, deviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
turnOff(deviceId, command) {
|
_bleCommandReceived(uniqueOutputId, command, data) {
|
||||||
const deviceName = this.deviceRegistry.getOutputDeviceName(deviceId);
|
|
||||||
logger.info(
|
|
||||||
`Plejd got turn off command for ${deviceName} (${deviceId})${
|
|
||||||
command.transition ? `, transition: ${command.transition}` : ''
|
|
||||||
}`,
|
|
||||||
);
|
|
||||||
this._transitionTo(deviceId, 0, command.transition, deviceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
_bleCommandReceived(deviceId, command, data) {
|
|
||||||
try {
|
try {
|
||||||
if (command === COMMANDS.DIM) {
|
if (command === COMMANDS.DIM) {
|
||||||
this.deviceRegistry.setOutputState(deviceId, data.state, data.dim);
|
this.deviceRegistry.setOutputState(uniqueOutputId, data.state, data.dim);
|
||||||
this.emit(PlejdDeviceCommunication.EVENTS.stateChanged, deviceId, {
|
this.emit(PlejdDeviceCommunication.EVENTS.stateChanged, uniqueOutputId, {
|
||||||
state: !!data.state,
|
state: !!data.state,
|
||||||
brightness: data.dim,
|
brightness: data.dim,
|
||||||
});
|
});
|
||||||
} else if (command === COMMANDS.TURN_ON) {
|
} else if (command === COMMANDS.TURN_ON) {
|
||||||
this.deviceRegistry.setOutputState(deviceId, true);
|
this.deviceRegistry.setOutputState(uniqueOutputId, true);
|
||||||
this.emit(PlejdDeviceCommunication.EVENTS.stateChanged, deviceId, {
|
this.emit(PlejdDeviceCommunication.EVENTS.stateChanged, uniqueOutputId, {
|
||||||
state: 1,
|
state: 1,
|
||||||
});
|
});
|
||||||
} else if (command === COMMANDS.TURN_OFF) {
|
} else if (command === COMMANDS.TURN_OFF) {
|
||||||
this.deviceRegistry.setOutputState(deviceId, false);
|
this.deviceRegistry.setOutputState(uniqueOutputId, false);
|
||||||
this.emit(PlejdDeviceCommunication.EVENTS.stateChanged, deviceId, {
|
this.emit(PlejdDeviceCommunication.EVENTS.stateChanged, uniqueOutputId, {
|
||||||
state: 0,
|
state: 0,
|
||||||
});
|
});
|
||||||
} else if (command === COMMANDS.TRIGGER_SCENE) {
|
} else if (command === COMMANDS.TRIGGER_SCENE) {
|
||||||
|
|
@ -119,18 +124,18 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_clearDeviceTransitionTimer(deviceId) {
|
_clearDeviceTransitionTimer(uniqueOutputId) {
|
||||||
if (this.bleDeviceTransitionTimers[deviceId]) {
|
if (this.bleOutputTransitionTimers[uniqueOutputId]) {
|
||||||
clearInterval(this.bleDeviceTransitionTimers[deviceId]);
|
clearInterval(this.bleOutputTransitionTimers[uniqueOutputId]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_transitionTo(deviceId, targetBrightness, transition, deviceName) {
|
_transitionTo(uniqueOutputId, targetBrightness, transition, deviceName) {
|
||||||
const device = this.deviceRegistry.getOutputDevice(deviceId);
|
const device = this.deviceRegistry.getOutputDevice(uniqueOutputId);
|
||||||
const initialBrightness = device ? device.state && device.dim : null;
|
const initialBrightness = device ? device.state && device.dim : null;
|
||||||
this._clearDeviceTransitionTimer(deviceId);
|
this._clearDeviceTransitionTimer(uniqueOutputId);
|
||||||
|
|
||||||
const isDimmable = this.deviceRegistry.getOutputDevice(deviceId).dimmable;
|
const isDimmable = this.deviceRegistry.getOutputDevice(uniqueOutputId).dimmable;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
transition > 1
|
transition > 1
|
||||||
|
|
@ -165,7 +170,7 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
|
|
||||||
let nSteps = 0;
|
let nSteps = 0;
|
||||||
|
|
||||||
this.bleDeviceTransitionTimers[deviceId] = setInterval(() => {
|
this.bleOutputTransitionTimers[uniqueOutputId] = setInterval(() => {
|
||||||
const tElapsedMs = new Date().getTime() - dtStart.getTime();
|
const tElapsedMs = new Date().getTime() - dtStart.getTime();
|
||||||
let tElapsed = tElapsedMs / 1000;
|
let tElapsed = tElapsedMs / 1000;
|
||||||
|
|
||||||
|
|
@ -179,20 +184,20 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
|
|
||||||
if (tElapsed === transition) {
|
if (tElapsed === transition) {
|
||||||
nSteps++;
|
nSteps++;
|
||||||
this._clearDeviceTransitionTimer(deviceId);
|
this._clearDeviceTransitionTimer(uniqueOutputId);
|
||||||
newBrightness = targetBrightness;
|
newBrightness = targetBrightness;
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Queueing finalize ${deviceName} (${deviceId}) transition from ${initialBrightness} to ${targetBrightness} in ${tElapsedMs}ms. Done steps ${nSteps}. Average interval ${
|
`Queueing finalize ${deviceName} (${uniqueOutputId}) transition from ${initialBrightness} to ${targetBrightness} in ${tElapsedMs}ms. Done steps ${nSteps}. Average interval ${
|
||||||
tElapsedMs / (nSteps || 1)
|
tElapsedMs / (nSteps || 1)
|
||||||
} ms.`,
|
} ms.`,
|
||||||
);
|
);
|
||||||
this._setBrightness(deviceId, newBrightness, true, deviceName);
|
this._setBrightness(uniqueOutputId, newBrightness, true, deviceName);
|
||||||
} else {
|
} else {
|
||||||
nSteps++;
|
nSteps++;
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
`Queueing dim transition for ${deviceName} (${deviceId}) to ${newBrightness}. Total queue length ${this.writeQueue.length}`,
|
`Queueing dim transition for ${deviceName} (${uniqueOutputId}) to ${newBrightness}. Total queue length ${this.writeQueue.length}`,
|
||||||
);
|
);
|
||||||
this._setBrightness(deviceId, newBrightness, false, deviceName);
|
this._setBrightness(uniqueOutputId, newBrightness, false, deviceName);
|
||||||
}
|
}
|
||||||
}, transitionInterval);
|
}, transitionInterval);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -201,34 +206,34 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
`Could not transition light change. Either initial value is unknown or change is too small. Requested from ${initialBrightness} to ${targetBrightness}`,
|
`Could not transition light change. Either initial value is unknown or change is too small. Requested from ${initialBrightness} to ${targetBrightness}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this._setBrightness(deviceId, targetBrightness, true, deviceName);
|
this._setBrightness(uniqueOutputId, targetBrightness, true, deviceName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_setBrightness(deviceId, brightness, shouldRetry, deviceName) {
|
_setBrightness(unqiueOutputId, brightness, shouldRetry, deviceName) {
|
||||||
if (!brightness && brightness !== 0) {
|
if (!brightness && brightness !== 0) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Queueing turn on ${deviceName} (${deviceId}). No brightness specified, setting DIM to previous.`,
|
`Queueing turn on ${deviceName} (${unqiueOutputId}). No brightness specified, setting DIM to previous.`,
|
||||||
);
|
);
|
||||||
this._appendCommandToWriteQueue(deviceId, COMMANDS.TURN_ON, null, shouldRetry);
|
this._appendCommandToWriteQueue(unqiueOutputId, COMMANDS.TURN_ON, null, shouldRetry);
|
||||||
} else if (brightness <= 0) {
|
} else if (brightness <= 0) {
|
||||||
logger.debug(`Queueing turn off ${deviceId}`);
|
logger.debug(`Queueing turn off ${unqiueOutputId}`);
|
||||||
this._appendCommandToWriteQueue(deviceId, COMMANDS.TURN_OFF, null, shouldRetry);
|
this._appendCommandToWriteQueue(unqiueOutputId, COMMANDS.TURN_OFF, null, shouldRetry);
|
||||||
} else {
|
} else {
|
||||||
if (brightness > 255) {
|
if (brightness > 255) {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
brightness = 255;
|
brightness = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`Queueing ${deviceId} set brightness to ${brightness}`);
|
logger.debug(`Queueing ${unqiueOutputId} set brightness to ${brightness}`);
|
||||||
// eslint-disable-next-line no-bitwise
|
// eslint-disable-next-line no-bitwise
|
||||||
this._appendCommandToWriteQueue(deviceId, COMMANDS.DIM, brightness, shouldRetry);
|
this._appendCommandToWriteQueue(unqiueOutputId, COMMANDS.DIM, brightness, shouldRetry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_appendCommandToWriteQueue(deviceId, command, data, shouldRetry) {
|
_appendCommandToWriteQueue(uniqueOutputId, command, data, shouldRetry) {
|
||||||
this.writeQueue.unshift({
|
this.writeQueue.unshift({
|
||||||
deviceId,
|
uniqueOutputId,
|
||||||
command,
|
command,
|
||||||
data,
|
data,
|
||||||
shouldRetry,
|
shouldRetry,
|
||||||
|
|
@ -250,28 +255,28 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const queueItem = this.writeQueue.pop();
|
const queueItem = this.writeQueue.pop();
|
||||||
const deviceName = this.deviceRegistry.getOutputDeviceName(queueItem.deviceId);
|
const deviceName = this.deviceRegistry.getOutputDeviceName(queueItem.uniqueOutputId);
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Write queue: Processing ${deviceName} (${queueItem.deviceId}). Command ${
|
`Write queue: Processing ${deviceName} (${queueItem.uniqueOutputId}). Command ${
|
||||||
queueItem.command
|
queueItem.command
|
||||||
}${queueItem.data ? ` ${queueItem.data}` : ''}. Total queue length: ${
|
}${queueItem.data ? ` ${queueItem.data}` : ''}. Total queue length: ${
|
||||||
this.writeQueue.length
|
this.writeQueue.length
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.writeQueue.some((item) => item.deviceId === queueItem.deviceId)) {
|
if (this.writeQueue.some((item) => item.uniqueOutputId === queueItem.uniqueOutputId)) {
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
`Skipping ${deviceName} (${queueItem.deviceId}) `
|
`Skipping ${deviceName} (${queueItem.uniqueOutputId}) `
|
||||||
+ `${queueItem.command} due to more recent command in queue.`,
|
+ `${queueItem.command} due to more recent command in queue.`,
|
||||||
);
|
);
|
||||||
// Skip commands if new ones exist for the same deviceId
|
// Skip commands if new ones exist for the same uniqueOutputId
|
||||||
// still process all messages in order
|
// still process all messages in order
|
||||||
} else {
|
} else {
|
||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
try {
|
try {
|
||||||
await this.plejdBleHandler.sendCommand(
|
await this.plejdBleHandler.sendCommand(
|
||||||
queueItem.command,
|
queueItem.command,
|
||||||
queueItem.deviceId,
|
queueItem.uniqueOutputId,
|
||||||
queueItem.data,
|
queueItem.data,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -282,7 +287,7 @@ class PlejdDeviceCommunication extends EventEmitter {
|
||||||
this.writeQueue.push(queueItem); // Add back to top of queue to be processed next;
|
this.writeQueue.push(queueItem); // Add back to top of queue to be processed next;
|
||||||
} else {
|
} else {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Write queue: Exceeed max retry count (${MAX_RETRY_COUNT}) for ${deviceName} (${queueItem.deviceId}). Command ${queueItem.command} failed.`,
|
`Write queue: Exceeed max retry count (${MAX_RETRY_COUNT}) for ${deviceName} (${queueItem.uniqueOutputId}). Command ${queueItem.command} failed.`,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
const SceneStep = require('./SceneStep');
|
const SceneStep = require('./SceneStep');
|
||||||
|
|
||||||
class Scene {
|
class Scene {
|
||||||
constructor(idx, scene, steps) {
|
/**
|
||||||
|
* @param {import('./DeviceRegistry')} deviceRegistry
|
||||||
|
* @param {number} idx
|
||||||
|
* @param {import("./types/ApiSite").Scene} scene
|
||||||
|
*/
|
||||||
|
constructor(deviceRegistry, idx, scene) {
|
||||||
this.id = idx;
|
this.id = idx;
|
||||||
this.title = scene.title;
|
this.title = scene.title;
|
||||||
this.sceneId = scene.sceneId;
|
this.sceneId = scene.sceneId;
|
||||||
|
|
||||||
const sceneSteps = steps.filter((x) => x.sceneId === scene.sceneId);
|
this.steps = deviceRegistry
|
||||||
this.steps = [];
|
.getApiSite()
|
||||||
|
.sceneSteps.filter((step) => step.sceneId === scene.sceneId)
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
.map((step) => new SceneStep(step));
|
||||||
for (const step of sceneSteps) {
|
|
||||||
this.steps.push(new SceneStep(step));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,28 @@ const Scene = require('./Scene');
|
||||||
|
|
||||||
const logger = Logger.getLogger('scene-manager');
|
const logger = Logger.getLogger('scene-manager');
|
||||||
class SceneManager {
|
class SceneManager {
|
||||||
|
/** @private @type {import('./DeviceRegistry')} */
|
||||||
deviceRegistry;
|
deviceRegistry;
|
||||||
plejdBle;
|
/** @private @type {import('./PlejdDeviceCommunication')} */
|
||||||
|
plejdDeviceCommunication;
|
||||||
|
/** @private @type {Object.<number,Scene>} */
|
||||||
scenes;
|
scenes;
|
||||||
|
|
||||||
constructor(deviceRegistry, plejdBle) {
|
constructor(deviceRegistry, plejdDeviceCommunication) {
|
||||||
this.deviceRegistry = deviceRegistry;
|
this.deviceRegistry = deviceRegistry;
|
||||||
this.plejdBle = plejdBle;
|
this.plejdDeviceCommunication = plejdDeviceCommunication;
|
||||||
this.scenes = {};
|
this.scenes = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
const scenes = this.deviceRegistry.apiSite.scenes.filter(
|
const scenes = this.deviceRegistry
|
||||||
(x) => x.hiddenFromSceneList === false,
|
.getApiSite()
|
||||||
);
|
.scenes.filter((x) => x.hiddenFromSceneList === false);
|
||||||
|
|
||||||
this.scenes = {};
|
this.scenes = {};
|
||||||
scenes.forEach((scene) => {
|
scenes.forEach((scene) => {
|
||||||
const idx = this.deviceRegistry.apiSite.sceneIndex[scene.sceneId];
|
const idx = this.deviceRegistry.getApiSite().sceneIndex[scene.sceneId];
|
||||||
this.scenes[idx] = new Scene(idx, scene, this.deviceRegistry.apiSite.sceneSteps);
|
this.scenes[idx] = new Scene(this.deviceRegistry, idx, scene);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,14 +37,15 @@ class SceneManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.steps.forEach((step) => {
|
scene.steps.forEach((step) => {
|
||||||
const device = this.deviceRegistry.getDeviceBySerialNumber(step.deviceId);
|
const uniqueId = this.deviceRegistry.getUniqueOutputId(step.deviceId, step.output);
|
||||||
|
const device = this.deviceRegistry.getOutputDevice(uniqueId);
|
||||||
if (device) {
|
if (device) {
|
||||||
if (device.dimmable && step.state) {
|
if (device.dimmable && step.state) {
|
||||||
this.plejdBle.turnOn(device.id, { brightness: step.brightness });
|
this.plejdDeviceCommunication.turnOn(uniqueId, { brightness: step.brightness });
|
||||||
} else if (!device.dimmable && step.state) {
|
} else if (!device.dimmable && step.state) {
|
||||||
this.plejdBle.turnOn(device.id, {});
|
this.plejdDeviceCommunication.turnOn(uniqueId, {});
|
||||||
} else if (!step.state) {
|
} else if (!step.state) {
|
||||||
this.plejdBle.turnOff(device.id, {});
|
this.plejdDeviceCommunication.turnOff(uniqueId, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
class SceneStep {
|
class SceneStep {
|
||||||
|
/**
|
||||||
|
* @param {import("./types/ApiSite").SceneStep} step
|
||||||
|
*/
|
||||||
constructor(step) {
|
constructor(step) {
|
||||||
this.sceneId = step.sceneId;
|
this.sceneId = step.sceneId;
|
||||||
this.deviceId = step.deviceId;
|
this.deviceId = step.deviceId;
|
||||||
|
this.output = step.output;
|
||||||
this.state = step.state === 'On' ? 1 : 0;
|
this.state = step.state === 'On' ? 1 : 0;
|
||||||
this.brightness = step.value;
|
this.brightness = step.value;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
plejd/types/DeviceRegistry.d.ts
vendored
4
plejd/types/DeviceRegistry.d.ts
vendored
|
|
@ -3,7 +3,7 @@
|
||||||
export type OutputDevices = { [deviceIdAndOutput: string]: OutputDevice };
|
export type OutputDevices = { [deviceIdAndOutput: string]: OutputDevice };
|
||||||
|
|
||||||
export interface OutputDevice {
|
export interface OutputDevice {
|
||||||
bleDeviceIndex: number;
|
bleOutputAddress: number;
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
dim?: number;
|
dim?: number;
|
||||||
dimmable: boolean;
|
dimmable: boolean;
|
||||||
|
|
@ -13,7 +13,7 @@ export interface OutputDevice {
|
||||||
name: string;
|
name: string;
|
||||||
output: number;
|
output: number;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
state: number | undefined;
|
state: boolean | undefined;
|
||||||
type: string;
|
type: string;
|
||||||
typeName: string;
|
typeName: string;
|
||||||
version: string;
|
version: string;
|
||||||
|
|
|
||||||
2
plejd/types/PlejdApi.d.ts
vendored
2
plejd/types/PlejdApi.d.ts
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable no-use-before-define */
|
/* eslint-disable no-use-before-define */
|
||||||
|
|
||||||
import { ApiSite } from './ApiSite';
|
import { ApiSite } from './ApiSite.d.ts';
|
||||||
|
|
||||||
export type PlejdApi = {
|
export type PlejdApi = {
|
||||||
config: any;
|
config: any;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue