Merge pull request #280 from icanos/develop

Release 0.10.0
This commit is contained in:
Victor 2023-08-22 12:02:58 +02:00 committed by GitHub
commit d58050b521
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 348 additions and 279 deletions

14
.gitattributes vendored Normal file
View file

@ -0,0 +1,14 @@
# Set the LF line ending default behavior also on Windows, in case core.autocrlf is not set.
* text eol=lf
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
#*.c text
#*.h text
# Declare files that will always have CRLF line endings on checkout.
#*.sln text eol=crlf
# Denote all files that are truly binary and should not be modified.
#*.png binary
#*.jpg binary

View file

@ -22,7 +22,7 @@ The repository contains only one addon, [Plejd](plejd/). Please see [Plejd addon
## License ## License
``` ```
Copyright 2019 Marcus Westin <marcus@sekurbit.se> Copyright 2023 Marcus Westin <marcus@sekurbit.se>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View file

@ -13,6 +13,7 @@ module.exports = {
root: true, root: true,
extends: [ extends: [
'airbnb-base', 'airbnb-base',
'eslint-config-prettier', // Prefers Prettier's formatting
// 'prettier', // 'prettier',
// 'plugin:prettier/recommended' // 'plugin:prettier/recommended'
], ],

View file

@ -1,5 +1,41 @@
# Changelog hassio-plejd Home Assistant Plejd addon # Changelog hassio-plejd Home Assistant Plejd addon
## [0.10.0](https://github.com/icanos/hassio-plejd/tree/0.10.0)
[Full Changelog](https://github.com/icanos/hassio-plejd/compare/0.9.1...0.10.0)
**Closed issues:**
- Names doubled in 2023.8 [\#277](https://github.com/icanos/hassio-plejd/issues/277)
- HA Configuration failed [\#276](https://github.com/icanos/hassio-plejd/issues/276)
- Unable to find correct BT characteristics [\#273](https://github.com/icanos/hassio-plejd/issues/273)
- LED 75 [\#271](https://github.com/icanos/hassio-plejd/issues/271)
- \[plejd-mqtt\] Initializing MQTT connection for Plejd addon [\#262](https://github.com/icanos/hassio-plejd/issues/262)
- Problem starting up Plejd Addon [\#258](https://github.com/icanos/hassio-plejd/issues/258)
- \[installation\] Repository not showing up in Add-on Store [\#256](https://github.com/icanos/hassio-plejd/issues/256)
- Help needed [\#251](https://github.com/icanos/hassio-plejd/issues/251)
- LED-75 causes addon to fail [\#250](https://github.com/icanos/hassio-plejd/issues/250)
- Errors reported in the log. [\#249](https://github.com/icanos/hassio-plejd/issues/249)
- Devices not added as entities [\#248](https://github.com/icanos/hassio-plejd/issues/248)
- New devices [\#246](https://github.com/icanos/hassio-plejd/issues/246)
- site name [\#242](https://github.com/icanos/hassio-plejd/issues/242)
- 404 from cloud login [\#241](https://github.com/icanos/hassio-plejd/issues/241)
- Stuck in Reconnecting BLE [\#240](https://github.com/icanos/hassio-plejd/issues/240)
- BLE Connection lost after some time and can't be reestablished. [\#239](https://github.com/icanos/hassio-plejd/issues/239)
- Getting a couple off error version with the latest [\#238](https://github.com/icanos/hassio-plejd/issues/238)
- Log hardwareId of unknown devices at a lower verbosity level [\#237](https://github.com/icanos/hassio-plejd/issues/237)
- Unable to find a bluetooth adapter that is compatible [\#234](https://github.com/icanos/hassio-plejd/issues/234)
- Scences become "unavailable" at random instances [\#233](https://github.com/icanos/hassio-plejd/issues/233)
- SPR-01 dont work [\#232](https://github.com/icanos/hassio-plejd/issues/232)
- Brightness control missing for one of my devices \(DIM-01\) [\#230](https://github.com/icanos/hassio-plejd/issues/230)
- Dosn´t work after latest Hassio update [\#223](https://github.com/icanos/hassio-plejd/issues/223)
- New devices [\#220](https://github.com/icanos/hassio-plejd/issues/220)
- Unknown output id null [\#219](https://github.com/icanos/hassio-plejd/issues/219)
**Merged pull requests:**
- Update installation instructions for newer HA/clarify manual install [\#272](https://github.com/icanos/hassio-plejd/pull/272) ([timjackson](https://github.com/timjackson))
## [0.9.1](https://github.com/icanos/hassio-plejd/tree/0.9.1) ## [0.9.1](https://github.com/icanos/hassio-plejd/tree/0.9.1)
[Full Changelog](https://github.com/icanos/hassio-plejd/compare/0.9.0...0.9.1) [Full Changelog](https://github.com/icanos/hassio-plejd/compare/0.9.0...0.9.1)
@ -57,7 +93,7 @@ Recommendations to minimize impact
- WPH-01 buttons to trigger generic automations in HA [\#172](https://github.com/icanos/hassio-plejd/issues/172) - WPH-01 buttons to trigger generic automations in HA [\#172](https://github.com/icanos/hassio-plejd/issues/172)
- Scene id and device id can overlap meaning mqtt commands overlap [\#161](https://github.com/icanos/hassio-plejd/issues/161) - Scene id and device id can overlap meaning mqtt commands overlap [\#161](https://github.com/icanos/hassio-plejd/issues/161)
- Add to "Tested on" section [\#122](https://github.com/icanos/hassio-plejd/issues/122) - Add to "Tested on" section [\#122](https://github.com/icanos/hassio-plejd/issues/122)
- USB Bluetooth adapter [\#101](https://github.com/icanos/hassio-plejd/issues/101) - USB Bluetooth adapter [\#101](https://github.com/icanos/hassio-plejd/issues/101)
- Ignores devices if they have same name [\#91](https://github.com/icanos/hassio-plejd/issues/91) - Ignores devices if they have same name [\#91](https://github.com/icanos/hassio-plejd/issues/91)
- Scene does not change state [\#85](https://github.com/icanos/hassio-plejd/issues/85) - Scene does not change state [\#85](https://github.com/icanos/hassio-plejd/issues/85)
@ -65,9 +101,9 @@ Recommendations to minimize impact
- Release 0.8.0-beta [\#204](https://github.com/icanos/hassio-plejd/pull/204) ([SweVictor](https://github.com/SweVictor)) - Release 0.8.0-beta [\#204](https://github.com/icanos/hassio-plejd/pull/204) ([SweVictor](https://github.com/SweVictor))
- Added more documentation to install steps [\#201](https://github.com/icanos/hassio-plejd/pull/201) ([polyzois](https://github.com/polyzois)) - Added more documentation to install steps [\#201](https://github.com/icanos/hassio-plejd/pull/201) ([polyzois](https://github.com/polyzois))
- Fix for issue discussed in \#198. [\#199](https://github.com/icanos/hassio-plejd/pull/199) ([faanskit](https://github.com/faanskit)) - Fix for issue discussed in \#198. [\#199](https://github.com/icanos/hassio-plejd/pull/199) ([faanskit](https://github.com/faanskit))
- Suggested Area and fix for \#189 [\#192](https://github.com/icanos/hassio-plejd/pull/192) ([faanskit](https://github.com/faanskit)) - Suggested Area and fix for \#189 [\#192](https://github.com/icanos/hassio-plejd/pull/192) ([faanskit](https://github.com/faanskit))
- Support for WPH-01 and WRT-01 added. [\#188](https://github.com/icanos/hassio-plejd/pull/188) ([faanskit](https://github.com/faanskit)) - Support for WPH-01 and WRT-01 added. [\#188](https://github.com/icanos/hassio-plejd/pull/188) ([faanskit](https://github.com/faanskit))
- Refactor unique id handling throughout the addon [\#179](https://github.com/icanos/hassio-plejd/pull/179) ([SweVictor](https://github.com/SweVictor)) - Refactor unique id handling throughout the addon [\#179](https://github.com/icanos/hassio-plejd/pull/179) ([SweVictor](https://github.com/SweVictor))
- Update README.md [\#178](https://github.com/icanos/hassio-plejd/pull/178) ([zissou1](https://github.com/zissou1)) - Update README.md [\#178](https://github.com/icanos/hassio-plejd/pull/178) ([zissou1](https://github.com/zissou1))
@ -80,6 +116,7 @@ Recommendations to minimize impact
- Can't connect to device: TypeError: Cannot read property 'dimmable' [\#175](https://github.com/icanos/hassio-plejd/issues/175) - Can't connect to device: TypeError: Cannot read property 'dimmable' [\#175](https://github.com/icanos/hassio-plejd/issues/175)
**Merged pull requests:** **Merged pull requests:**
- Release 0.7.1 [\#177](https://github.com/icanos/hassio-plejd/pull/177) ([SweVictor](https://github.com/SweVictor)) - Release 0.7.1 [\#177](https://github.com/icanos/hassio-plejd/pull/177) ([SweVictor](https://github.com/SweVictor))
## [0.7.0](https://github.com/icanos/hassio-plejd/tree/0.7.0) (2021-03-23) ## [0.7.0](https://github.com/icanos/hassio-plejd/tree/0.7.0) (2021-03-23)

View file

@ -1,25 +1,21 @@
# Details regarding installation # Details regarding installation
If you can reach your Home Assistant at [http://homeassistant.local:8123](http://homeassistant.local:8123) the links below should work.
## Mosquitto ## Mosquitto
Head over to Supervisor -> Add-on Store and search for `mosquitto broker`. Head over to [Supervisor -> Add-on Store](https://my.home-assistant.io/redirect/supervisor_store/) and find the `Mosquitto broker`.
Install it and then start [mosquito addon link](http://homeassistant.local:8123/hassio/addon/core_mosquitto/info) Install and start it.
## Add api user for Mosquito ## Add api user for Mosquitto
Add a Home Assistant user for the Plejd addon to be able to connect to Mosquito [Configuration -> Users](http://homeassistant.local:8123/config/users) Add a Home Assistant user for the Plejd addon to be able to connect to Mosquitto [Configuration -> Users](https://my.home-assistant.io/redirect/users/)
Call the user e.g. `mqtt-api-user`, set a password and save Call the user e.g. `mqtt-api-user`, set a password and save
## Plejd ## Plejd
Follow the `Easy Installation` in [README.MD](plejd/README.md) Follow the `Easy Installation` in [README.MD](./README.md)And `Configuration Parameters` on the same page.The only parameters needing a value are
And `Configuration Parameters` on the same page.
The only parameters needing a value are
- site - site
- username - username (typically email address)
- password - password
- mqttUsername e.g. `mqtt-api-user` - mqttUsername e.g. `mqtt-api-user`
- mqttPassword - mqttPassword
@ -28,9 +24,8 @@ Now you can start the Plejd add-on
## Where are the lights? ## Where are the lights?
Head over to [Configuration -> Integrations](http://homeassistant.local:8123/config/integrations) and click Configure on MQTT Head over to [Configuration -> Integrations](https://my.home-assistant.io/redirect/integrations/) and the [Configure MQTT](https://my.home-assistant.io/redirect/config_mqtt/).
After this step a new `Mosquito broker` should appear on the same page. If everything was setup correctly. It will list your lights under After this step a new Mosquitto broker `core-mosquitto` should appear on the [MQTT Page](https://my.home-assistant.io/redirect/integration/?domain=mqtt). If everything was setup correctly. It will list your lights under devices/entities subheading.
`1 entity`/`n entities`
## Running the Plejd add-on in VirtualBox on Windows ## Running the Plejd add-on in VirtualBox on Windows

View file

@ -66,8 +66,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(

View file

@ -1,8 +1,6 @@
const winston = require('winston'); const winston = require('winston');
const { const { colorize, combine, label, printf, timestamp } = winston.format;
colorize, combine, label, printf, timestamp,
} = winston.format;
const Configuration = require('./Configuration'); const Configuration = require('./Configuration');
@ -34,15 +32,17 @@ class Logger {
static getLogLevel() { static getLogLevel() {
const config = Configuration.getOptions(); const config = Configuration.getOptions();
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
const level = (config.logLevel && LEVELS.find((l) => l.startsWith(config.logLevel[0].toLowerCase()))) const level =
|| 'info'; (config.logLevel && LEVELS.find((l) => l.startsWith(config.logLevel[0].toLowerCase()))) ||
'info';
return level; return level;
} }
static shouldLog(logLevel) { static shouldLog(logLevel) {
if (!Logger.shouldLogLookup[logLevel]) { if (!Logger.shouldLogLookup[logLevel]) {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
Logger.shouldLogLookup[logLevel] = Logger.logLevels().levels[logLevel] <= Logger.logLevels().levels[Logger.getLogLevel()]; Logger.shouldLogLookup[logLevel] =
Logger.logLevels().levels[logLevel] <= Logger.logLevels().levels[Logger.getLogLevel()];
} }
return Logger.shouldLogLookup[logLevel]; return Logger.shouldLogLookup[logLevel];
} }

View file

@ -27,7 +27,8 @@ const TOPIC_TYPES = {
COMMAND: 'set', COMMAND: 'set',
}; };
const getBaseTopic = (/** @type { string } */ uniqueId, /** @type { string } */ mqttDeviceType) => `${discoveryPrefix}/${mqttDeviceType}/${nodeId}/${uniqueId}`; const getBaseTopic = (/** @type { string } */ uniqueId, /** @type { string } */ mqttDeviceType) =>
`${discoveryPrefix}/${mqttDeviceType}/${nodeId}/${uniqueId}`;
const getTopicName = ( const getTopicName = (
/** @type { string } */ uniqueId, /** @type { string } */ uniqueId,
@ -35,9 +36,11 @@ const getTopicName = (
/** @type { import('./types/Mqtt').TopicType } */ topicType, /** @type { import('./types/Mqtt').TopicType } */ topicType,
) => `${getBaseTopic(uniqueId, mqttDeviceType)}/${topicType}`; ) => `${getBaseTopic(uniqueId, mqttDeviceType)}/${topicType}`;
const getButtonEventTopic = (/** @type {string} */ deviceId) => `${getTopicName(deviceId, MQTT_TYPES.DEVICE_AUTOMATION, TOPIC_TYPES.STATE)}`; const getButtonEventTopic = (/** @type {string} */ deviceId) =>
`${getTopicName(deviceId, MQTT_TYPES.DEVICE_AUTOMATION, TOPIC_TYPES.STATE)}`;
const getTriggerUniqueId = (/** @type { string } */ uniqueId) => `${uniqueId}_trig`; const getTriggerUniqueId = (/** @type { string } */ uniqueId) => `${uniqueId}_trig`;
const getSceneEventTopic = (/** @type {string} */ sceneId) => `${getTopicName(getTriggerUniqueId(sceneId), MQTT_TYPES.DEVICE_AUTOMATION, TOPIC_TYPES.STATE)}`; const getSceneEventTopic = (/** @type {string} */ sceneId) =>
`${getTopicName(getTriggerUniqueId(sceneId), MQTT_TYPES.DEVICE_AUTOMATION, TOPIC_TYPES.STATE)}`;
const getSubscribePath = () => `${discoveryPrefix}/+/${nodeId}/#`; const getSubscribePath = () => `${discoveryPrefix}/+/${nodeId}/#`;
const decodeTopicRegexp = new RegExp( const decodeTopicRegexp = new RegExp(

View file

@ -250,10 +250,9 @@ class PlejdApi {
switch (parseInt(plejdDevice.hardwareId, 10)) { switch (parseInt(plejdDevice.hardwareId, 10)) {
case 1: case 1:
case 11:
case 14:
return { return {
name: 'DIM-01', name: 'DIM-01',
description: '1-channel dimmer LED, 300 VA',
type: 'light', type: 'light',
dimmable: true, dimmable: true,
broadcastClicks: false, broadcastClicks: false,
@ -261,6 +260,7 @@ class PlejdApi {
case 2: case 2:
return { return {
name: 'DIM-02', name: 'DIM-02',
description: '2-channel dimmer LED, 2*100 VA',
type: 'light', type: 'light',
dimmable: true, dimmable: true,
broadcastClicks: false, broadcastClicks: false,
@ -268,20 +268,24 @@ class PlejdApi {
case 3: case 3:
return { return {
name: 'CTR-01', name: 'CTR-01',
description: '1-channel relay with 0-10V output, 3500 VA',
type: 'light', type: 'light',
dimmable: false, dimmable: false,
broadcastClicks: false, broadcastClicks: false,
}; };
case 4: // Gateway doesn't show up in devices list in API response
return { // case 4:
name: 'GWY-01', // return {
type: 'sensor', // name: 'GWY-01',
dimmable: false, // description: 'Gateway to enable control via internet and integrations',
broadcastClicks: false, // type: 'sensor',
}; // dimmable: false,
// broadcastClicks: false,
// };
case 5: case 5:
return { return {
name: 'LED-10', name: 'LED-10',
description: '1-channel LED dimmer/driver, 10 W',
type: 'light', type: 'light',
dimmable: true, dimmable: true,
broadcastClicks: false, broadcastClicks: false,
@ -289,60 +293,76 @@ class PlejdApi {
case 6: case 6:
return { return {
name: 'WPH-01', name: 'WPH-01',
description:
'Wireless push button, 4 buttons. 2 channels, on and off buttons for each channel',
type: 'device_automation', type: 'device_automation',
dimmable: false, dimmable: false,
broadcastClicks: true, broadcastClicks: true,
}; };
case 7: case 7:
// Unknown, pre-release (?) version, kept for backwards compatibility. See https://github.com/icanos/hassio-plejd/issues/250
return { return {
name: 'REL-01', name: 'REL-01',
description: '1 channel relay, 3500 VA',
type: 'switch', type: 'switch',
dimmable: false, dimmable: false,
broadcastClicks: false, broadcastClicks: false,
}; };
case 8: case 8:
case 9:
// Unknown
return { return {
name: '-unknown-', name: 'SPR-01',
type: 'light', description: 'Smart plug on/off with relay, 3500 VA',
type: 'switch',
dimmable: false, dimmable: false,
broadcastClicks: false, broadcastClicks: false,
}; };
case 10: case 10:
return { return {
name: 'WRT-01', name: 'WRT-01',
description: 'Wireless rotary button',
type: 'device_automation', type: 'device_automation',
dimmable: false, dimmable: false,
broadcastClicks: true, broadcastClicks: true,
}; };
case 12: case 11:
// Unknown
return { return {
name: '-unknown-', name: 'DIM-01-2P',
description: '1-channel dimmer LED with 2-pole breaking, 300 VA',
type: 'light', type: 'light',
dimmable: false, dimmable: true,
broadcastClicks: false, broadcastClicks: false,
}; };
case 13: // DAL-01 is presumably a very special device
// Please open a new issue if you have ideas on how to handel
// Below could be use as testing, but since one device can have up to 64 slaves it probably won't work
// case 12:
// return {
// name: 'DAL-01',
// description: 'Dali broadcast with dimmer and tuneable white support',
// type: 'light',
// dimmable: true,
// broadcastClicks: false,
// };
case 14:
return { return {
name: 'Generic', name: 'DIM-01',
description: '1-channel dimmer LED, 300 VA ("LC" hardware/chip version)',
type: 'light', type: 'light',
dimmable: false, dimmable: true,
broadcastClicks: false, broadcastClicks: false,
}; };
case 15: case 15:
case 16:
// Unknown
return { return {
name: '-unknown-', name: 'DIM-02',
description: '2-channel dimmer LED, 2*100 VA ("LC" hardware/chip version)',
type: 'light', type: 'light',
dimmable: false, dimmable: true,
broadcastClicks: false, broadcastClicks: false,
}; };
case 17: case 17:
return { return {
name: 'REL-01', name: 'REL-01-2P',
description: '1-channel relay with 2-pole 3500 VA',
type: 'switch', type: 'switch',
dimmable: false, dimmable: false,
broadcastClicks: false, broadcastClicks: false,
@ -350,25 +370,28 @@ class PlejdApi {
case 18: case 18:
return { return {
name: 'REL-02', name: 'REL-02',
description: '2-channel relay with combined 3500 VA',
type: 'switch', type: 'switch',
dimmable: false, dimmable: false,
broadcastClicks: false, broadcastClicks: false,
}; };
case 19:
// Unknown
return {
name: '-unknown-',
type: 'light',
dimmable: false,
broadcastClicks: false,
};
case 20: case 20:
return { return {
// Unknown, pre-release (?) version, kept for backwards compatibility. See https://github.com/icanos/hassio-plejd/issues/250
name: 'SPR-01', name: 'SPR-01',
type: 'switch', description: 'Smart plug on/off with relay, 3500 VA',
type: 'device_automation',
dimmable: false, dimmable: false,
broadcastClicks: false, broadcastClicks: false,
}; };
case 36:
return {
name: 'LED-75',
description: '1-channel LED dimmer/driver with tuneable white, 10 W',
type: 'light',
dimmable: true,
broadcastClicks: false,
};
default: default:
throw new Error(`Unknown device type with id ${plejdDevice.hardwareId}`); throw new Error(`Unknown device type with id ${plejdDevice.hardwareId}`);
} }
@ -428,34 +451,50 @@ class PlejdApi {
const dimmable = device.traits === TRAITS.DIMMABLE; const dimmable = device.traits === TRAITS.DIMMABLE;
// dimmable = settings.dimCurve !== 'NonDimmable'; // dimmable = settings.dimCurve !== 'NonDimmable';
const { name: typeName, type: deviceType } = this._getDeviceType(plejdDevice); try {
let loadType = deviceType; const decodedDeviceType = this._getDeviceType(plejdDevice);
if (device.outputType === 'RELAY') {
loadType = 'switch'; let loadType = decodedDeviceType.type;
} else if (device.outputType === 'LIGHT') { if (device.outputType === 'RELAY') {
loadType = 'light'; loadType = 'switch';
} else if (device.outputType === 'LIGHT') {
loadType = 'light';
}
const room = this.siteDetails.rooms.find((x) => x.roomId === device.roomId);
const roomTitle = room ? room.title : undefined;
/** @type {import('types/DeviceRegistry').OutputDevice} */
const outputDevice = {
bleOutputAddress,
deviceId: device.deviceId,
dimmable,
name: device.title,
output: deviceOutput,
roomId: device.roomId,
roomName: roomTitle,
state: undefined,
type: loadType,
typeDescription: decodedDeviceType.description,
typeName: decodedDeviceType.name,
version: plejdDevice.firmware.version,
uniqueId: uniqueOutputId,
};
this.deviceRegistry.addOutputDevice(outputDevice);
} catch (error) {
logger.error(`Error trying to create output device: ${error}`);
logger.warn(
`device (from API response) when error happened: ${JSON.stringify(device, null, 2)}`,
);
logger.warn(
`plejdDevice (from API response) when error happened: ${JSON.stringify(
plejdDevice,
null,
2,
)}`,
);
} }
const room = this.siteDetails.rooms.find((x) => x.roomId === device.roomId);
const roomTitle = room ? room.title : undefined;
/** @type {import('types/DeviceRegistry').OutputDevice} */
const outputDevice = {
bleOutputAddress,
deviceId: device.deviceId,
dimmable,
name: device.title,
output: deviceOutput,
roomId: device.roomId,
roomName: roomTitle,
state: undefined,
type: loadType,
typeName,
version: plejdDevice.firmware.version,
uniqueId: uniqueOutputId,
};
this.deviceRegistry.addOutputDevice(outputDevice);
} }
} else { } else {
// The device does not have an output. It can be assumed to be a WPH-01 or a WRT-01 // The device does not have an output. It can be assumed to be a WPH-01 or a WRT-01
@ -476,21 +515,38 @@ class PlejdApi {
); );
const uniqueInputId = this.deviceRegistry.getUniqueInputId(device.deviceId, input.input); const uniqueInputId = this.deviceRegistry.getUniqueInputId(device.deviceId, input.input);
const { name: typeName, type, broadcastClicks } = this._getDeviceType(plejdDevice);
if (broadcastClicks) { try {
/** @type {import('types/DeviceRegistry').InputDevice} */ const decodedDeviceType = this._getDeviceType(plejdDevice);
const inputDevice = {
bleInputAddress, if (decodedDeviceType.broadcastClicks) {
deviceId: device.deviceId, /** @type {import('types/DeviceRegistry').InputDevice} */
name: device.title, const inputDevice = {
input: input.input, bleInputAddress,
roomId: device.roomId, deviceId: device.deviceId,
type, name: device.title,
typeName, input: input.input,
version: plejdDevice.firmware.version, roomId: device.roomId,
uniqueId: uniqueInputId, type: decodedDeviceType.type,
}; typeDescription: decodedDeviceType.description,
this.deviceRegistry.addInputDevice(inputDevice); typeName: decodedDeviceType.name,
version: plejdDevice.firmware.version,
uniqueId: uniqueInputId,
};
this.deviceRegistry.addInputDevice(inputDevice);
}
} catch (error) {
logger.error(`Error trying to create input device: ${error}`);
logger.warn(
`device (from API response) when error happened: ${JSON.stringify(device, null, 2)}`,
);
logger.warn(
`plejdDevice (from API response) when error happened: ${JSON.stringify(
plejdDevice,
null,
2,
)}`,
);
} }
}); });
} }
@ -506,8 +562,9 @@ class PlejdApi {
const deviceIdsByRoom = this.deviceRegistry.getOutputDeviceIdsByRoomId(roomId); const deviceIdsByRoom = this.deviceRegistry.getOutputDeviceIdsByRoomId(roomId);
const dimmable = deviceIdsByRoom const dimmable =
&& deviceIdsByRoom.some( deviceIdsByRoom &&
deviceIdsByRoom.some(
(deviceId) => this.deviceRegistry.getOutputDevice(deviceId).dimmable, (deviceId) => this.deviceRegistry.getOutputDevice(deviceId).dimmable,
); );
@ -522,6 +579,7 @@ class PlejdApi {
roomName: undefined, roomName: undefined,
state: undefined, state: undefined,
type: 'light', type: 'light',
typeDescription: 'A Plejd room',
typeName: 'Room', typeName: 'Room',
uniqueId: roomId, uniqueId: roomId,
version: undefined, version: undefined,
@ -551,6 +609,7 @@ class PlejdApi {
roomName: undefined, roomName: undefined,
state: false, state: false,
type: 'scene', type: 'scene',
typeDescription: 'A Plejd scene',
typeName: 'Scene', typeName: 'Scene',
version: undefined, version: undefined,
uniqueId: scene.sceneId, uniqueId: scene.sceneId,

View file

@ -414,7 +414,9 @@ class PlejBLEHandler extends EventEmitter {
async _startGetPlejdDevice() { async _startGetPlejdDevice() {
logger.verbose('Setting up interfacesAdded subscription and discovery filter'); logger.verbose('Setting up interfacesAdded subscription and discovery filter');
this.objectManager.on('InterfacesAdded', (path, interfaces) => this._onInterfacesAdded(path, interfaces)); this.objectManager.on('InterfacesAdded', (path, interfaces) =>
this._onInterfacesAdded(path, interfaces),
);
this.adapter.SetDiscoveryFilter({ this.adapter.SetDiscoveryFilter({
UUIDs: new dbus.Variant('as', [PLEJD_SERVICE]), UUIDs: new dbus.Variant('as', [PLEJD_SERVICE]),
@ -873,9 +875,9 @@ 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 (
bleOutputAddress !== BLE_BROADCAST_DEVICE_ID bleOutputAddress !== BLE_BROADCAST_DEVICE_ID ||
|| Logger.shouldLog('verbose') Logger.shouldLog('verbose') ||
|| Math.abs(diffSeconds) > 60 Math.abs(diffSeconds) > 60
) { ) {
const plejdTime = new Date(plejdTimestampUTC); const plejdTime = new Date(plejdTimestampUTC);
logger.debug( logger.debug(

View file

@ -140,11 +140,11 @@ class PlejdDeviceCommunication extends EventEmitter {
const isDimmable = this.deviceRegistry.getOutputDevice(uniqueOutputId).dimmable; const isDimmable = this.deviceRegistry.getOutputDevice(uniqueOutputId).dimmable;
if ( if (
transition > 1 transition > 1 &&
&& isDimmable isDimmable &&
&& (initialBrightness || initialBrightness === 0) (initialBrightness || initialBrightness === 0) &&
&& (targetBrightness || targetBrightness === 0) (targetBrightness || targetBrightness === 0) &&
&& targetBrightness !== initialBrightness targetBrightness !== initialBrightness
) { ) {
// Transition time set, known initial and target brightness // Transition time set, known initial and target brightness
// Calculate transition interval time based on delta brightness and max steps per second // Calculate transition interval time based on delta brightness and max steps per second
@ -269,8 +269,8 @@ class PlejdDeviceCommunication extends EventEmitter {
if (this.writeQueue.some((item) => item.uniqueOutputId === queueItem.uniqueOutputId)) { if (this.writeQueue.some((item) => item.uniqueOutputId === queueItem.uniqueOutputId)) {
logger.verbose( logger.verbose(
`Skipping ${device.name} (${queueItem.uniqueOutputId}) ` `Skipping ${device.name} (${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 uniqueOutputId // Skip commands if new ones exist for the same uniqueOutputId
// still process all messages in order // still process all messages in order

View file

@ -11,8 +11,6 @@ I am in no way affiliated with Plejd and am solely doing this as a hobby project
**Did you like this? Consider helping me continue the development:** **Did you like this? Consider helping me continue the development:**
[Buy me a coffee](https://www.buymeacoffee.com/w1ANTUb) [Buy me a coffee](https://www.buymeacoffee.com/w1ANTUb)
[![Gitter](https://badges.gitter.im/hassio-plejd/community.svg)](https://gitter.im/hassio-plejd/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
## Getting started ## Getting started
To get started, make sure that the following requirements are met: To get started, make sure that the following requirements are met:
@ -86,7 +84,7 @@ However, the add-on still works as expected and this is something I'm looking in
### Simple MQTT Configurations ### Simple MQTT Configurations
When you are using the official Mosquitto Broker from Home Assistant Add-on store, minimal configuration is required. When you are using the official Mosquitto Broker from Home Assistant Add-on store, minimal configuration is required.
Create a user in [Configuration -> Users](http://homeassistant.local:8123/config/users) named e.g. mqtt-api-user Create a user in [Configuration -&gt; Users](https://my.home-assistant.io/redirect/users/) named e.g. mqtt-api-user
| Parameter | Value | | Parameter | Value |
| ------------ | ------------------------------------------------ | | ------------ | ------------------------------------------------ |
@ -116,7 +114,7 @@ The plugin needs you to configure some settings before working. You find these o
| Parameter | Value | | Parameter | Value |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| site | Name of your Plejd site, the name is displayed in the Plejd app (top bar). | | site | Name of your Plejd site, the name is displayed in the Plejd app (top bar). |
| username | Username of your Plejd account, this is used to fetch the crypto key and devices from the Plejd API. | | username | Email/username of your Plejd account, this is used to fetch the crypto key and devices from the Plejd API. |
| password | Password of your Plejd account, this is used to fetch the crypto key and devices from the Plejd API. | | password | Password of your Plejd account, this is used to fetch the crypto key and devices from the Plejd API. |
| mqttBroker | URL of the MQTT Broker, eg. mqtt:// | | mqttBroker | URL of the MQTT Broker, eg. mqtt:// |
| mqttUsername | Username of the MQTT broker | | mqttUsername | Username of the MQTT broker |
@ -131,28 +129,30 @@ The plugin needs you to configure some settings before working. You find these o
Plejd output devices typically appears as either lights or switches in Home Assistant depending on how they are configured. Plejd output devices typically appears as either lights or switches in Home Assistant depending on how they are configured.
| Device | Plejd Configuration | Home Assistant Role | Comment | | Device | Plejd Configuration | Home Assistant Role | Comment |
| ------ | ------------------- | ------------------- | --------------------------------------------------------------------- | | --------- | ------------------- | ------------------- | --------------------------------------------------------------------- |
| CTR-01 | Relay, Light | Light | | | CTR-01 | Relay, Light | Light | |
| CTR-01 | Relay, Other | Switch | | | CTR-01 | Relay, Other | Switch | |
| REL-01 | Relay, Light | Light | | | REL-01 | Relay, Light | Light | |
| REL-01 | Relay, Other | Switch | | | REL-01 | Relay, Other | Switch | |
| REL-02 | Relay, Light | Light | | | REL-02 | Relay, Light | Light | |
| REL-02 | Relay, Other | Switch | | | REL-02 | Relay, Other | Switch | |
| SPR-01 | Relay, Light | Light | Not tested, not supported | | SPR-01 | Relay, Light | Light | |
| SPR-01 | Relay, Other | Switch | Not tested, not supported | | SPR-01 | Relay, Other | Switch | |
| DIM-01 | - | Light | | | DIM-01 | - | Light | |
| DIM-02 | - | Light | | | DIM-01-2P | - | Light | |
| LED-10 | - | Light | | | DIM-02 | - | Light | |
| DAL-01 | - | - | Not tested, not supported | | LED-10 | - | Light | |
| WPH-01 | - | Device Automation | type:button_short_press, subtype:button_1, button_2,button_3,button_4 | | LED-75 | - | Light | |
| WRT-01 | - | Device Automation | type:button_short_press, subtype:button_1 | | DAL-01 | - | - | Not tested, not supported |
| GWY-01 | - | - | | | WPH-01 | - | Device Automation | type:button_short_press, subtype:button_1, button_2,button_3,button_4 |
| RTR-01 | - | - | | | WRT-01 | - | Device Automation | type:button_short_press, subtype:button_1 |
| Scene | - | Scene | | | GWY-01 | - | - | |
| Scene | - | Device Automation | type:scene, subtype:trigger | | RTR-01 | - | - | |
| Room | - | Area | Can be changed by Home Assistant | | Scene | - | Scene | |
| Room | - | Light | If includeRoomsAsLights is set to true | | Scene | - | Device Automation | type:scene, subtype:trigger |
| Room | - | Area | Can be changed by Home Assistant |
| Room | - | Light | If includeRoomsAsLights is set to true |
## Transitions ## Transitions

View file

@ -1,6 +1,6 @@
{ {
"name": "Plejd", "name": "Plejd",
"version": "0.9.1", "version": "0.10.0",
"slug": "plejd", "slug": "plejd",
"description": "Adds support for the Swedish home automation devices from Plejd.", "description": "Adds support for the Swedish home automation devices from Plejd.",
"url": "https://github.com/icanos/hassio-plejd/", "url": "https://github.com/icanos/hassio-plejd/",

View file

@ -19,12 +19,11 @@
"prettier": "~2.2.1" "prettier": "~2.2.1"
}, },
"scripts": { "scripts": {
"lint": "prettier \"../*.{js*,md}\" --check & eslint **/*.js", "lint": "npm run lint:prettier & npm run lint:scripts",
"lint:fix": "prettier .. --check --write & eslint **/*.js --fix", "lint:fix": "npm run lint:prettier:fix & npm run lint:scripts:fix",
"lint:prettier:fix": "npm run lint:prettier --write", "lint:prettier": "prettier --check --config ../.prettierrc.js \"**/*.{js*,md}\"",
"lint:errors": "npm run lint:prettier & npm run lint:styles --quiet & npm run lint:types & npm run lint:scripts --quiet", "lint:prettier:fix": "prettier --check --config ../.prettierrc.js --write \"**/*.{js*,md}\"",
"lint:errors:fix": "npm run lint:prettier --write & npm run lint:scripts --quiet --fix", "lint:scripts": "eslint --config ./.eslintrc.js \"**/*.js\"",
"lint:prettier": "prettier --check \"**/*.js\"", "lint:scripts:fix": "eslint --config ./.eslintrc.js --fix \"**/*.js\""
"lint:scripts": "eslint --config ./.eslintrc.js \"**/*.js\""
} }
} }

View file

@ -2,3 +2,4 @@
bashio::log.info 'Running add-on' bashio::log.info 'Running add-on'
exec node /plejd/main.js exec node /plejd/main.js

View file

@ -30,7 +30,7 @@ export interface ApiSite {
outputGroups: { [key: string]: OutputGroup }; outputGroups: { [key: string]: OutputGroup };
roomAddress: { [key: string]: number }; roomAddress: { [key: string]: number };
sceneIndex: { [key: string]: number }; sceneIndex: { [key: string]: number };
images: Images; images: string;
deviceLimit: number; deviceLimit: number;
} }
@ -106,7 +106,7 @@ export interface Hardware {
predefinedLoad: PredefinedLoad; predefinedLoad: PredefinedLoad;
supportedFirmware: PredefinedLoad; supportedFirmware: PredefinedLoad;
ACL: AstroEventACL; ACL: AstroEventACL;
objectId: HardwareObjectID; objectId: string;
__type: AstroEventType; __type: AstroEventType;
className: HardwareClassName; className: HardwareClassName;
} }
@ -132,7 +132,7 @@ export enum ImageType {
export interface PlejdMeshClass { export interface PlejdMeshClass {
__type: InstallerType; __type: InstallerType;
className: SiteClassName; className: SiteClassName;
objectId: ObjectID; objectId: string;
} }
export enum InstallerType { export enum InstallerType {
@ -148,28 +148,11 @@ export enum SiteClassName {
UserProfile = 'UserProfile', UserProfile = 'UserProfile',
} }
export enum ObjectID {
BBBJO2Cufm = 'BBBJO2cufm',
D4Dw87Hq21 = 'D4DW87HQ21',
FCrrS1NJHH = 'FCrrS1nJHH',
GX1W4P06QS = 'gX1W4p06QS',
Ndlvzgh4Df = 'ndlvzgh4df',
UHoKQLuXqZ = 'uHoKQLuXqZ',
VfHiawBPA8 = 'vfHiawBPA8',
WgAFPloWjK = 'wgAfPloWjK',
YkyNDotBNa = 'YkyNDotBNa',
}
export enum Name { export enum Name {
Ctr01 = 'CTR-01', Ctr01 = 'CTR-01',
Dim01 = 'DIM-01', Dim01 = 'DIM-01',
} }
export enum HardwareObjectID {
R3Gfd6ACAu = 'R3gfd6ACAu',
XjslOltgvi = 'xjslOltgvi',
}
export interface PredefinedLoad { export interface PredefinedLoad {
__type: SupportedFirmwareType; __type: SupportedFirmwareType;
className: PredefinedLoadClassName; className: PredefinedLoadClassName;
@ -204,7 +187,7 @@ export interface Gateway {
deviceId: string; deviceId: string;
siteId: string; siteId: string;
hardwareId: string; hardwareId: string;
installer: ObjectID; installer: string;
firmware: number; firmware: number;
firmwareObject: Firmware; firmwareObject: Firmware;
dirtyInstall: boolean; dirtyInstall: boolean;
@ -220,47 +203,20 @@ export interface Gateway {
} }
export interface Firmware { export interface Firmware {
notes: Notes; notes: string;
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
data: Image; data: Image;
metaData: Image; metaData: Image;
version: Version; version: string;
buildTime: number; buildTime: number;
firmwareApi: string; firmwareApi: string;
ACL: AstroEventACL; ACL: AstroEventACL;
objectId: FirmwareObjectObjectID; objectId: string;
__type: AstroEventType; __type: AstroEventType;
className: SiteClassName; className: SiteClassName;
} }
export enum Notes {
Ctr01 = 'CTR-01',
Ctr20ReleaseCandidate1 = 'Ctr 2.0 Release candidate 1',
Dim20ReleaseCandidate1 = 'Dim 2.0 Release candidate 1',
Dim221ReleaseCandidate = 'Dim 2.2.1 Release Candidate',
GWY10ReleaseCandidate = 'GWY 1.0 Release Candidate',
}
export enum FirmwareObjectObjectID {
BBBJO2Cufm = 'BBBJO2cufm',
E6YxfREDuF = 'E6yxfREDuF',
JYSZ0EvyCU = 'JYSZ0EvyCU',
Ndlvzgh4Df = 'ndlvzgh4df',
RlglTfVHDe = 'rlglTfVHDe',
}
export enum Version {
The12 = '1.2',
The20 = '2.0',
The221 = '2.2.1',
The304 = '3.0.4',
}
export interface Images {
'2afc6c6e-7a26-466a-b8ec-febbca90f5f7': string;
}
export interface InputSetting { export interface InputSetting {
deviceId: string; deviceId: string;
input: number; input: number;
@ -472,7 +428,7 @@ export interface PlejdMesh {
updatedAt: Date; updatedAt: Date;
site: PlejdMeshClass; site: PlejdMeshClass;
ACL: AstroEventACL; ACL: AstroEventACL;
objectId: ObjectID; objectId: string;
__type: AstroEventType; __type: AstroEventType;
className: SiteClassName; className: SiteClassName;
} }
@ -549,7 +505,7 @@ export interface Scene {
} }
export interface SiteDetailsSite { export interface SiteDetailsSite {
installers: ObjectID[]; installers: string[];
title: string; title: string;
siteId: string; siteId: string;
version: number; version: number;
@ -564,7 +520,7 @@ export interface SiteDetailsSite {
country: string; country: string;
previousOwners: string[]; previousOwners: string[];
ACL: AstroEventACL; ACL: AstroEventACL;
objectId: ObjectID; objectId: string;
__type: AstroEventType; __type: AstroEventType;
className: SiteClassName; className: SiteClassName;
} }
@ -581,7 +537,7 @@ export interface DeviceAstroTable {
export interface SitePermission { export interface SitePermission {
siteId: string; siteId: string;
userId: ObjectID; userId: string;
user: User; user: User;
isOwner: boolean; isOwner: boolean;
isInstaller: boolean; isInstaller: boolean;
@ -608,7 +564,7 @@ export interface User {
_failed_login_count: number; _failed_login_count: number;
hasIntegration: boolean; hasIntegration: boolean;
ACL: UserACL; ACL: UserACL;
objectId: ObjectID; objectId: string;
__type: AstroEventType; __type: AstroEventType;
className: SiteClassName; className: SiteClassName;
} }

View file

@ -13,6 +13,7 @@ export interface OutputDevice {
roomName: string | undefined; roomName: string | undefined;
state: boolean | undefined; state: boolean | undefined;
type: string; type: string;
typeDescription: string;
typeName: string; typeName: string;
version: string; version: string;
uniqueId: string; uniqueId: string;
@ -27,6 +28,7 @@ export interface InputDevice {
input: number; input: number;
roomId: string; roomId: string;
type: string; type: string;
typeDescription: string;
typeName: string; typeName: string;
version: string; version: string;
uniqueId: string; uniqueId: string;