diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e4373a3 --- /dev/null +++ b/.gitattributes @@ -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 \ No newline at end of file diff --git a/README.md b/README.md index 0463064..bf67a57 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The repository contains only one addon, [Plejd](plejd/). Please see [Plejd addon ## License ``` -Copyright 2019 Marcus Westin +Copyright 2023 Marcus Westin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/plejd/.eslintrc.js b/plejd/.eslintrc.js index ff88ace..fc15347 100644 --- a/plejd/.eslintrc.js +++ b/plejd/.eslintrc.js @@ -13,6 +13,7 @@ module.exports = { root: true, extends: [ 'airbnb-base', + 'eslint-config-prettier', // Prefers Prettier's formatting // 'prettier', // 'plugin:prettier/recommended' ], diff --git a/plejd/CHANGELOG.md b/plejd/CHANGELOG.md index 3d6e593..2c70ce2 100644 --- a/plejd/CHANGELOG.md +++ b/plejd/CHANGELOG.md @@ -1,5 +1,41 @@ # 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) [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) - 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) -- 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) - 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)) - 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)) -- 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)) - 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) **Merged pull requests:** + - 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) diff --git a/plejd/Details.md b/plejd/Details.md index ee49bfe..24b4238 100644 --- a/plejd/Details.md +++ b/plejd/Details.md @@ -1,25 +1,21 @@ # 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 -Head over to Supervisor -> Add-on Store and search for `mosquitto broker`. -Install it and then start [mosquito addon link](http://homeassistant.local:8123/hassio/addon/core_mosquitto/info) +Head over to [Supervisor -> Add-on Store](https://my.home-assistant.io/redirect/supervisor_store/) and find the `Mosquitto broker`. +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 ## Plejd -Follow the `Easy Installation` in [README.MD](plejd/README.md) -And `Configuration Parameters` on the same page. -The only parameters needing a value are +Follow the `Easy Installation` in [README.MD](./README.md)And `Configuration Parameters` on the same page.The only parameters needing a value are - site -- username +- username (typically email address) - password - mqttUsername e.g. `mqtt-api-user` - mqttPassword @@ -28,9 +24,8 @@ Now you can start the Plejd add-on ## Where are the lights? -Head over to [Configuration -> Integrations](http://homeassistant.local:8123/config/integrations) and click Configure on 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 -`1 entity`/`n entities` +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 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. ## Running the Plejd add-on in VirtualBox on Windows diff --git a/plejd/DeviceRegistry.js b/plejd/DeviceRegistry.js index 91efd55..951652e 100644 --- a/plejd/DeviceRegistry.js +++ b/plejd/DeviceRegistry.js @@ -66,8 +66,8 @@ class DeviceRegistry { this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId] = []; } if ( - outputDevice.roomId !== outputDevice.uniqueId - && !this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].includes(outputDevice.uniqueId) + outputDevice.roomId !== outputDevice.uniqueId && + !this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].includes(outputDevice.uniqueId) ) { this.outputDeviceUniqueIdsByRoomId[outputDevice.roomId].push(outputDevice.uniqueId); logger.verbose( diff --git a/plejd/Dockerfile b/plejd/Dockerfile index 586cc7c..89cef69 100644 --- a/plejd/Dockerfile +++ b/plejd/Dockerfile @@ -1,68 +1,68 @@ -ARG BUILD_FROM=hassioaddons/base:8.0.6 -FROM $BUILD_FROM - -ENV LANG C.UTF-8 - -# Set shell -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -# Copy data for add-on -COPY ./*.js /plejd/ -COPY ./config.json /plejd/ -COPY ./package.json /plejd/ - -ARG BUILD_ARCH - -# Install Node -RUN apk add --no-cache jq -RUN \ - apk add --no-cache --virtual .build-dependencies \ - g++ \ - gcc \ - libc-dev \ - linux-headers \ - make \ - python3 \ - bluez \ - eudev-dev \ - zlib-dev \ - \ - && apk add --no-cache \ - git \ - nodejs \ - npm \ - dbus-dev \ - glib-dev \ - \ - && npm config set unsafe-perm true - -WORKDIR /plejd -RUN npm install \ - --no-audit \ - --no-update-notifier \ - --unsafe-perm - -# Copy root filesystem -COPY rootfs / - -# Build arguments -ARG BUILD_DATE -ARG BUILD_REF -ARG BUILD_VERSION - -# Labels -LABEL \ - io.hass.name="Plejd" \ - io.hass.description="Adds support for the Swedish home automation devices from Plejd." \ - io.hass.arch="${BUILD_ARCH}" \ - io.hass.type="addon" \ - io.hass.version=${BUILD_VERSION} \ - maintainer="Marcus Westin " \ - org.label-schema.description="Adds support for the Swedish home automation devices from Plejd." \ - org.label-schema.build-date=${BUILD_DATE} \ - org.label-schema.name="Plejd" \ - org.label-schema.schema-version="1.0" \ - org.label-schema.usage="https://github.com/icanos/hassio-plejd/tree/master/README.md" \ - org.label-schema.vcs-ref=${BUILD_REF} \ - org.label-schema.vcs-url="https://github.com/icanos/hassio-plejd" - +ARG BUILD_FROM=hassioaddons/base:8.0.6 +FROM $BUILD_FROM + +ENV LANG C.UTF-8 + +# Set shell +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +# Copy data for add-on +COPY ./*.js /plejd/ +COPY ./config.json /plejd/ +COPY ./package.json /plejd/ + +ARG BUILD_ARCH + +# Install Node +RUN apk add --no-cache jq +RUN \ + apk add --no-cache --virtual .build-dependencies \ + g++ \ + gcc \ + libc-dev \ + linux-headers \ + make \ + python3 \ + bluez \ + eudev-dev \ + zlib-dev \ + \ + && apk add --no-cache \ + git \ + nodejs \ + npm \ + dbus-dev \ + glib-dev \ + \ + && npm config set unsafe-perm true + +WORKDIR /plejd +RUN npm install \ + --no-audit \ + --no-update-notifier \ + --unsafe-perm + +# Copy root filesystem +COPY rootfs / + +# Build arguments +ARG BUILD_DATE +ARG BUILD_REF +ARG BUILD_VERSION + +# Labels +LABEL \ + io.hass.name="Plejd" \ + io.hass.description="Adds support for the Swedish home automation devices from Plejd." \ + io.hass.arch="${BUILD_ARCH}" \ + io.hass.type="addon" \ + io.hass.version=${BUILD_VERSION} \ + maintainer="Marcus Westin " \ + org.label-schema.description="Adds support for the Swedish home automation devices from Plejd." \ + org.label-schema.build-date=${BUILD_DATE} \ + org.label-schema.name="Plejd" \ + org.label-schema.schema-version="1.0" \ + org.label-schema.usage="https://github.com/icanos/hassio-plejd/tree/master/README.md" \ + org.label-schema.vcs-ref=${BUILD_REF} \ + org.label-schema.vcs-url="https://github.com/icanos/hassio-plejd" + diff --git a/plejd/Logger.js b/plejd/Logger.js index 19bf436..3b6f7b7 100644 --- a/plejd/Logger.js +++ b/plejd/Logger.js @@ -1,8 +1,6 @@ const winston = require('winston'); -const { - colorize, combine, label, printf, timestamp, -} = winston.format; +const { colorize, combine, label, printf, timestamp } = winston.format; const Configuration = require('./Configuration'); @@ -34,15 +32,17 @@ class Logger { static getLogLevel() { const config = Configuration.getOptions(); // eslint-disable-next-line max-len - const level = (config.logLevel && LEVELS.find((l) => l.startsWith(config.logLevel[0].toLowerCase()))) - || 'info'; + const level = + (config.logLevel && LEVELS.find((l) => l.startsWith(config.logLevel[0].toLowerCase()))) || + 'info'; return level; } static shouldLog(logLevel) { if (!Logger.shouldLogLookup[logLevel]) { // 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]; } diff --git a/plejd/MqttClient.js b/plejd/MqttClient.js index 5be9434..57f1262 100644 --- a/plejd/MqttClient.js +++ b/plejd/MqttClient.js @@ -27,7 +27,8 @@ const TOPIC_TYPES = { 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 = ( /** @type { string } */ uniqueId, @@ -35,9 +36,11 @@ const getTopicName = ( /** @type { import('./types/Mqtt').TopicType } */ 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 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 decodeTopicRegexp = new RegExp( diff --git a/plejd/PlejdApi.js b/plejd/PlejdApi.js index 919755e..cc12990 100644 --- a/plejd/PlejdApi.js +++ b/plejd/PlejdApi.js @@ -250,10 +250,9 @@ class PlejdApi { switch (parseInt(plejdDevice.hardwareId, 10)) { case 1: - case 11: - case 14: return { name: 'DIM-01', + description: '1-channel dimmer LED, 300 VA', type: 'light', dimmable: true, broadcastClicks: false, @@ -261,6 +260,7 @@ class PlejdApi { case 2: return { name: 'DIM-02', + description: '2-channel dimmer LED, 2*100 VA', type: 'light', dimmable: true, broadcastClicks: false, @@ -268,20 +268,24 @@ class PlejdApi { case 3: return { name: 'CTR-01', + description: '1-channel relay with 0-10V output, 3500 VA', type: 'light', dimmable: false, broadcastClicks: false, }; - case 4: - return { - name: 'GWY-01', - type: 'sensor', - dimmable: false, - broadcastClicks: false, - }; + // Gateway doesn't show up in devices list in API response + // case 4: + // return { + // name: 'GWY-01', + // description: 'Gateway to enable control via internet and integrations', + // type: 'sensor', + // dimmable: false, + // broadcastClicks: false, + // }; case 5: return { name: 'LED-10', + description: '1-channel LED dimmer/driver, 10 W', type: 'light', dimmable: true, broadcastClicks: false, @@ -289,60 +293,76 @@ class PlejdApi { case 6: return { name: 'WPH-01', + description: + 'Wireless push button, 4 buttons. 2 channels, on and off buttons for each channel', type: 'device_automation', dimmable: false, broadcastClicks: true, }; case 7: + // Unknown, pre-release (?) version, kept for backwards compatibility. See https://github.com/icanos/hassio-plejd/issues/250 return { name: 'REL-01', + description: '1 channel relay, 3500 VA', type: 'switch', dimmable: false, broadcastClicks: false, }; case 8: - case 9: - // Unknown return { - name: '-unknown-', - type: 'light', + name: 'SPR-01', + description: 'Smart plug on/off with relay, 3500 VA', + type: 'switch', dimmable: false, broadcastClicks: false, }; case 10: return { name: 'WRT-01', + description: 'Wireless rotary button', type: 'device_automation', dimmable: false, broadcastClicks: true, }; - case 12: - // Unknown + case 11: return { - name: '-unknown-', + name: 'DIM-01-2P', + description: '1-channel dimmer LED with 2-pole breaking, 300 VA', type: 'light', - dimmable: false, + dimmable: true, 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 { - name: 'Generic', + name: 'DIM-01', + description: '1-channel dimmer LED, 300 VA ("LC" hardware/chip version)', type: 'light', - dimmable: false, + dimmable: true, broadcastClicks: false, }; case 15: - case 16: - // Unknown return { - name: '-unknown-', + name: 'DIM-02', + description: '2-channel dimmer LED, 2*100 VA ("LC" hardware/chip version)', type: 'light', - dimmable: false, + dimmable: true, broadcastClicks: false, }; case 17: return { - name: 'REL-01', + name: 'REL-01-2P', + description: '1-channel relay with 2-pole 3500 VA', type: 'switch', dimmable: false, broadcastClicks: false, @@ -350,25 +370,28 @@ class PlejdApi { case 18: return { name: 'REL-02', + description: '2-channel relay with combined 3500 VA', type: 'switch', dimmable: false, broadcastClicks: false, }; - case 19: - // Unknown - return { - name: '-unknown-', - type: 'light', - dimmable: false, - broadcastClicks: false, - }; case 20: return { + // Unknown, pre-release (?) version, kept for backwards compatibility. See https://github.com/icanos/hassio-plejd/issues/250 name: 'SPR-01', - type: 'switch', + description: 'Smart plug on/off with relay, 3500 VA', + type: 'device_automation', dimmable: 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: throw new Error(`Unknown device type with id ${plejdDevice.hardwareId}`); } @@ -428,34 +451,50 @@ class PlejdApi { const dimmable = device.traits === TRAITS.DIMMABLE; // dimmable = settings.dimCurve !== 'NonDimmable'; - const { name: typeName, type: deviceType } = this._getDeviceType(plejdDevice); - let loadType = deviceType; - if (device.outputType === 'RELAY') { - loadType = 'switch'; - } else if (device.outputType === 'LIGHT') { - loadType = 'light'; + try { + const decodedDeviceType = this._getDeviceType(plejdDevice); + + let loadType = decodedDeviceType.type; + if (device.outputType === 'RELAY') { + 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 { // 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 { name: typeName, type, broadcastClicks } = this._getDeviceType(plejdDevice); - if (broadcastClicks) { - /** @type {import('types/DeviceRegistry').InputDevice} */ - const inputDevice = { - bleInputAddress, - deviceId: device.deviceId, - name: device.title, - input: input.input, - roomId: device.roomId, - type, - typeName, - version: plejdDevice.firmware.version, - uniqueId: uniqueInputId, - }; - this.deviceRegistry.addInputDevice(inputDevice); + + try { + const decodedDeviceType = this._getDeviceType(plejdDevice); + + if (decodedDeviceType.broadcastClicks) { + /** @type {import('types/DeviceRegistry').InputDevice} */ + const inputDevice = { + bleInputAddress, + deviceId: device.deviceId, + name: device.title, + input: input.input, + roomId: device.roomId, + type: decodedDeviceType.type, + typeDescription: decodedDeviceType.description, + 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 dimmable = deviceIdsByRoom - && deviceIdsByRoom.some( + const dimmable = + deviceIdsByRoom && + deviceIdsByRoom.some( (deviceId) => this.deviceRegistry.getOutputDevice(deviceId).dimmable, ); @@ -522,6 +579,7 @@ class PlejdApi { roomName: undefined, state: undefined, type: 'light', + typeDescription: 'A Plejd room', typeName: 'Room', uniqueId: roomId, version: undefined, @@ -551,6 +609,7 @@ class PlejdApi { roomName: undefined, state: false, type: 'scene', + typeDescription: 'A Plejd scene', typeName: 'Scene', version: undefined, uniqueId: scene.sceneId, diff --git a/plejd/PlejdBLEHandler.js b/plejd/PlejdBLEHandler.js index 0a69961..6e943d8 100644 --- a/plejd/PlejdBLEHandler.js +++ b/plejd/PlejdBLEHandler.js @@ -414,7 +414,9 @@ class PlejBLEHandler extends EventEmitter { async _startGetPlejdDevice() { 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({ UUIDs: new dbus.Variant('as', [PLEJD_SERVICE]), @@ -873,9 +875,9 @@ class PlejBLEHandler extends EventEmitter { const plejdTimestampUTC = (decoded.readInt32LE(5) + offsetSecondsGuess) * 1000; const diffSeconds = Math.round((plejdTimestampUTC - now.getTime()) / 1000); if ( - bleOutputAddress !== BLE_BROADCAST_DEVICE_ID - || Logger.shouldLog('verbose') - || Math.abs(diffSeconds) > 60 + bleOutputAddress !== BLE_BROADCAST_DEVICE_ID || + Logger.shouldLog('verbose') || + Math.abs(diffSeconds) > 60 ) { const plejdTime = new Date(plejdTimestampUTC); logger.debug( diff --git a/plejd/PlejdDeviceCommunication.js b/plejd/PlejdDeviceCommunication.js index 8626b69..9b38604 100644 --- a/plejd/PlejdDeviceCommunication.js +++ b/plejd/PlejdDeviceCommunication.js @@ -140,11 +140,11 @@ class PlejdDeviceCommunication extends EventEmitter { const isDimmable = this.deviceRegistry.getOutputDevice(uniqueOutputId).dimmable; if ( - transition > 1 - && isDimmable - && (initialBrightness || initialBrightness === 0) - && (targetBrightness || targetBrightness === 0) - && targetBrightness !== initialBrightness + transition > 1 && + isDimmable && + (initialBrightness || initialBrightness === 0) && + (targetBrightness || targetBrightness === 0) && + targetBrightness !== initialBrightness ) { // Transition time set, known initial and target brightness // 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)) { logger.verbose( - `Skipping ${device.name} (${queueItem.uniqueOutputId}) ` - + `${queueItem.command} due to more recent command in queue.`, + `Skipping ${device.name} (${queueItem.uniqueOutputId}) ` + + `${queueItem.command} due to more recent command in queue.`, ); // Skip commands if new ones exist for the same uniqueOutputId // still process all messages in order diff --git a/plejd/README.md b/plejd/README.md index 6eda56d..7b61943 100644 --- a/plejd/README.md +++ b/plejd/README.md @@ -8,11 +8,9 @@ Thanks to [ha-plejd](https://github.com/klali/ha-plejd) for inspiration. Disclaimer: 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) -[![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 To get started, make sure that the following requirements are met: @@ -85,8 +83,8 @@ However, the add-on still works as expected and this is something I'm looking in ### Simple MQTT Configurations -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 +When you are using the official Mosquitto Broker from Home Assistant Add-on store, minimal configuration is required. +Create a user in [Configuration -> Users](https://my.home-assistant.io/redirect/users/) named e.g. mqtt-api-user | Parameter | Value | | ------------ | ------------------------------------------------ | @@ -116,7 +114,7 @@ The plugin needs you to configure some settings before working. You find these o | Parameter | Value | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 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. | | mqttBroker | URL of the MQTT Broker, eg. mqtt:// | | 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. -| Device | Plejd Configuration | Home Assistant Role | Comment | -| ------ | ------------------- | ------------------- | --------------------------------------------------------------------- | -| CTR-01 | Relay, Light | Light | | -| CTR-01 | Relay, Other | Switch | | -| REL-01 | Relay, Light | Light | | -| REL-01 | Relay, Other | Switch | | -| REL-02 | Relay, Light | Light | | -| REL-02 | Relay, Other | Switch | | -| SPR-01 | Relay, Light | Light | Not tested, not supported | -| SPR-01 | Relay, Other | Switch | Not tested, not supported | -| DIM-01 | - | Light | | -| DIM-02 | - | Light | | -| LED-10 | - | Light | | -| DAL-01 | - | - | Not tested, not supported | -| WPH-01 | - | Device Automation | type:button_short_press, subtype:button_1, button_2,button_3,button_4 | -| WRT-01 | - | Device Automation | type:button_short_press, subtype:button_1 | -| GWY-01 | - | - | | -| RTR-01 | - | - | | -| Scene | - | Scene | | -| Scene | - | Device Automation | type:scene, subtype:trigger | -| Room | - | Area | Can be changed by Home Assistant | -| Room | - | Light | If includeRoomsAsLights is set to true | +| Device | Plejd Configuration | Home Assistant Role | Comment | +| --------- | ------------------- | ------------------- | --------------------------------------------------------------------- | +| CTR-01 | Relay, Light | Light | | +| CTR-01 | Relay, Other | Switch | | +| REL-01 | Relay, Light | Light | | +| REL-01 | Relay, Other | Switch | | +| REL-02 | Relay, Light | Light | | +| REL-02 | Relay, Other | Switch | | +| SPR-01 | Relay, Light | Light | | +| SPR-01 | Relay, Other | Switch | | +| DIM-01 | - | Light | | +| DIM-01-2P | - | Light | | +| DIM-02 | - | Light | | +| LED-10 | - | Light | | +| LED-75 | - | Light | | +| DAL-01 | - | - | Not tested, not supported | +| WPH-01 | - | Device Automation | type:button_short_press, subtype:button_1, button_2,button_3,button_4 | +| WRT-01 | - | Device Automation | type:button_short_press, subtype:button_1 | +| GWY-01 | - | - | | +| RTR-01 | - | - | | +| Scene | - | Scene | | +| Scene | - | Device Automation | type:scene, subtype:trigger | +| Room | - | Area | Can be changed by Home Assistant | +| Room | - | Light | If includeRoomsAsLights is set to true | ## Transitions diff --git a/plejd/config.json b/plejd/config.json index 466b25b..36d6896 100644 --- a/plejd/config.json +++ b/plejd/config.json @@ -1,6 +1,6 @@ { "name": "Plejd", - "version": "0.9.1", + "version": "0.10.0", "slug": "plejd", "description": "Adds support for the Swedish home automation devices from Plejd.", "url": "https://github.com/icanos/hassio-plejd/", diff --git a/plejd/package.json b/plejd/package.json index c2e504a..0dc856a 100644 --- a/plejd/package.json +++ b/plejd/package.json @@ -19,12 +19,11 @@ "prettier": "~2.2.1" }, "scripts": { - "lint": "prettier \"../*.{js*,md}\" --check & eslint **/*.js", - "lint:fix": "prettier .. --check --write & eslint **/*.js --fix", - "lint:prettier:fix": "npm run lint:prettier --write", - "lint:errors": "npm run lint:prettier & npm run lint:styles --quiet & npm run lint:types & npm run lint:scripts --quiet", - "lint:errors:fix": "npm run lint:prettier --write & npm run lint:scripts --quiet --fix", - "lint:prettier": "prettier --check \"**/*.js\"", - "lint:scripts": "eslint --config ./.eslintrc.js \"**/*.js\"" + "lint": "npm run lint:prettier & npm run lint:scripts", + "lint:fix": "npm run lint:prettier:fix & npm run lint:scripts:fix", + "lint:prettier": "prettier --check --config ../.prettierrc.js \"**/*.{js*,md}\"", + "lint:prettier:fix": "prettier --check --config ../.prettierrc.js --write \"**/*.{js*,md}\"", + "lint:scripts": "eslint --config ./.eslintrc.js \"**/*.js\"", + "lint:scripts:fix": "eslint --config ./.eslintrc.js --fix \"**/*.js\"" } } diff --git a/plejd/rootfs/etc/services.d/plejd/finish b/plejd/rootfs/etc/services.d/plejd/finish index cec873a..97dd55a 100644 --- a/plejd/rootfs/etc/services.d/plejd/finish +++ b/plejd/rootfs/etc/services.d/plejd/finish @@ -5,4 +5,4 @@ if -n { s6-test $# -ne 0 } if -n { s6-test ${1} -eq 256 } -s6-svscanctl -t /var/run/s6/services \ No newline at end of file +s6-svscanctl -t /var/run/s6/services diff --git a/plejd/rootfs/etc/services.d/plejd/run b/plejd/rootfs/etc/services.d/plejd/run index a2c9c6b..14ef936 100644 --- a/plejd/rootfs/etc/services.d/plejd/run +++ b/plejd/rootfs/etc/services.d/plejd/run @@ -14,4 +14,4 @@ bashio::log.info 'Verified permissions on startup script' chmod +x /usr/bin/plejd.sh bashio::log.info 'Executing startup script' -exec /usr/bin/plejd.sh \ No newline at end of file +exec /usr/bin/plejd.sh diff --git a/plejd/rootfs/usr/bin/plejd.sh b/plejd/rootfs/usr/bin/plejd.sh index 616042e..627843e 100644 --- a/plejd/rootfs/usr/bin/plejd.sh +++ b/plejd/rootfs/usr/bin/plejd.sh @@ -2,3 +2,4 @@ bashio::log.info 'Running add-on' exec node /plejd/main.js + diff --git a/plejd/types/ApiSite.d.ts b/plejd/types/ApiSite.d.ts index 4a6e562..db0be07 100644 --- a/plejd/types/ApiSite.d.ts +++ b/plejd/types/ApiSite.d.ts @@ -30,7 +30,7 @@ export interface ApiSite { outputGroups: { [key: string]: OutputGroup }; roomAddress: { [key: string]: number }; sceneIndex: { [key: string]: number }; - images: Images; + images: string; deviceLimit: number; } @@ -106,7 +106,7 @@ export interface Hardware { predefinedLoad: PredefinedLoad; supportedFirmware: PredefinedLoad; ACL: AstroEventACL; - objectId: HardwareObjectID; + objectId: string; __type: AstroEventType; className: HardwareClassName; } @@ -132,7 +132,7 @@ export enum ImageType { export interface PlejdMeshClass { __type: InstallerType; className: SiteClassName; - objectId: ObjectID; + objectId: string; } export enum InstallerType { @@ -148,28 +148,11 @@ export enum SiteClassName { 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 { Ctr01 = 'CTR-01', Dim01 = 'DIM-01', } -export enum HardwareObjectID { - R3Gfd6ACAu = 'R3gfd6ACAu', - XjslOltgvi = 'xjslOltgvi', -} - export interface PredefinedLoad { __type: SupportedFirmwareType; className: PredefinedLoadClassName; @@ -204,7 +187,7 @@ export interface Gateway { deviceId: string; siteId: string; hardwareId: string; - installer: ObjectID; + installer: string; firmware: number; firmwareObject: Firmware; dirtyInstall: boolean; @@ -220,47 +203,20 @@ export interface Gateway { } export interface Firmware { - notes: Notes; + notes: string; createdAt: Date; updatedAt: Date; data: Image; metaData: Image; - version: Version; + version: string; buildTime: number; firmwareApi: string; ACL: AstroEventACL; - objectId: FirmwareObjectObjectID; + objectId: string; __type: AstroEventType; 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 { deviceId: string; input: number; @@ -472,7 +428,7 @@ export interface PlejdMesh { updatedAt: Date; site: PlejdMeshClass; ACL: AstroEventACL; - objectId: ObjectID; + objectId: string; __type: AstroEventType; className: SiteClassName; } @@ -549,7 +505,7 @@ export interface Scene { } export interface SiteDetailsSite { - installers: ObjectID[]; + installers: string[]; title: string; siteId: string; version: number; @@ -564,7 +520,7 @@ export interface SiteDetailsSite { country: string; previousOwners: string[]; ACL: AstroEventACL; - objectId: ObjectID; + objectId: string; __type: AstroEventType; className: SiteClassName; } @@ -581,7 +537,7 @@ export interface DeviceAstroTable { export interface SitePermission { siteId: string; - userId: ObjectID; + userId: string; user: User; isOwner: boolean; isInstaller: boolean; @@ -608,7 +564,7 @@ export interface User { _failed_login_count: number; hasIntegration: boolean; ACL: UserACL; - objectId: ObjectID; + objectId: string; __type: AstroEventType; className: SiteClassName; } diff --git a/plejd/types/DeviceRegistry.d.ts b/plejd/types/DeviceRegistry.d.ts index 7a86661..5eba5c8 100644 --- a/plejd/types/DeviceRegistry.d.ts +++ b/plejd/types/DeviceRegistry.d.ts @@ -13,6 +13,7 @@ export interface OutputDevice { roomName: string | undefined; state: boolean | undefined; type: string; + typeDescription: string; typeName: string; version: string; uniqueId: string; @@ -27,6 +28,7 @@ export interface InputDevice { input: number; roomId: string; type: string; + typeDescription: string; typeName: string; version: string; uniqueId: string;