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-06 07:58:06 +02:00
this . outputUniqueIdByBleOutputAddress [
this . getUniqueBLEId ( 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 ) {
2023-10-03 21:56:04 +02:00
const alreadyExistingBLEDevice = this . getOutputDeviceByBleOutputAddress ( outputDevice . bleOutputAddress ) ;
if ( alreadyExistingBLEDevice ) {
logger . warn ( ` Device with output id ${ outputDevice . bleOutputAddress } already exists named ${ alreadyExistingBLEDevice . name } . These two devices are probably grouped in the Plejd app. If this seems to be an error, please log a GitHub issue. ` ) ;
logger . info ( ` NOT adding ${ outputDevice . name } to device registry ` ) ;
logger . verbose ( ` Details of device NOT added: ${ JSON . stringify ( outputDevice ) } ` ) ;
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 (
2023-08-16 15:32:53 +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 [
2021-05-06 07:58:06 +02:00
this . outputUniqueIdByBleOutputAddress [ this . getUniqueBLEId ( bleInputAddress , inputButton ) ]
2021-05-05 19:34:34 +02:00
] ;
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 ) {
2021-05-06 07:58:06 +02:00
return ` ${ deviceId } _I_ ${ inputIndex } ` ;
}
// eslint-disable-next-line class-methods-use-this
getUniqueBLEId ( bleAdress , inputIndex ) {
return ` ${ bleAdress } _ ${ inputIndex } ` ;
2021-05-01 19:41:29 +02:00
}
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 ;