From d16a1603f1d86ab649b8b83c2a0f83677ec782ab Mon Sep 17 00:00:00 2001 From: Xavier Moreno Date: Mon, 25 Apr 2022 22:39:01 +0200 Subject: [PATCH 1/3] feat(integration): add shelly and shellyforhass integrations related to #441 --- .vscode/settings.json | 3 +- apps/controllerx/cx_core/controller.py | 16 +++++ .../controllerx/cx_core/integration/shelly.py | 25 ++++++++ .../cx_core/integration/shellyforhass.py | 27 ++++++++ docs/docs/start/integrations.md | 10 ++- .../cx_core/integration/integration_test.py | 2 + .../cx_core/integration/shelly_test.py | 62 +++++++++++++++++++ .../cx_core/integration/shellyforhass_test.py | 56 +++++++++++++++++ tests/unit_tests/cx_devices/devices_test.py | 2 + 9 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 apps/controllerx/cx_core/integration/shelly.py create mode 100644 apps/controllerx/cx_core/integration/shellyforhass.py create mode 100644 tests/unit_tests/cx_core/integration/shelly_test.py create mode 100644 tests/unit_tests/cx_core/integration/shellyforhass_test.py diff --git a/.vscode/settings.json b/.vscode/settings.json index e2bcb022..a78e89a3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,6 +16,5 @@ "editor.codeActionsOnSave": { "source.organizeImports": true } - }, - "python.analysis.completeFunctionParens": true + } } diff --git a/apps/controllerx/cx_core/controller.py b/apps/controllerx/cx_core/controller.py index 825e3fdd..e2c2bf0b 100644 --- a/apps/controllerx/cx_core/controller.py +++ b/apps/controllerx/cx_core/controller.py @@ -586,5 +586,21 @@ def get_homematic_actions_mapping(self) -> Optional[DefaultActionsMapping]: """ return None + def get_shelly_actions_mapping(self) -> Optional[DefaultActionsMapping]: + """ + Controllers can implement this function. It should return a dict + with the command that a controller can take and the functions as values. + This is used for Shelly support. + """ + return None + + def get_shellyforhass_actions_mapping(self) -> Optional[DefaultActionsMapping]: + """ + Controllers can implement this function. It should return a dict + with the command that a controller can take and the functions as values. + This is used for Shelly for HASS support. + """ + return None + def get_predefined_actions_mapping(self) -> PredefinedActionsMapping: return {} diff --git a/apps/controllerx/cx_core/integration/shelly.py b/apps/controllerx/cx_core/integration/shelly.py new file mode 100644 index 00000000..c34ccc74 --- /dev/null +++ b/apps/controllerx/cx_core/integration/shelly.py @@ -0,0 +1,25 @@ +from typing import Any, Dict, Optional + +from appdaemon.plugins.hass.hassapi import Hass +from cx_const import DefaultActionsMapping +from cx_core.integration import EventData, Integration + + +class ShellyIntegration(Integration): + name = "shelly" + + def get_default_actions_mapping(self) -> Optional[DefaultActionsMapping]: + return self.controller.get_shelly_actions_mapping() + + async def listen_changes(self, controller_id: str) -> None: + await Hass.listen_event( + self.controller, self.event_callback, "shelly.click", device=controller_id + ) + + async def event_callback( + self, event_name: str, data: EventData, kwargs: Dict[str, Any] + ) -> None: + click_type = data["click_type"] + channel = data["channel"] + action = f"{click_type}_{channel}" + await self.controller.handle_action(action, extra=data) diff --git a/apps/controllerx/cx_core/integration/shellyforhass.py b/apps/controllerx/cx_core/integration/shellyforhass.py new file mode 100644 index 00000000..a9eb5312 --- /dev/null +++ b/apps/controllerx/cx_core/integration/shellyforhass.py @@ -0,0 +1,27 @@ +from typing import Any, Dict, Optional + +from appdaemon.plugins.hass.hassapi import Hass +from cx_const import DefaultActionsMapping +from cx_core.integration import EventData, Integration + + +class ShellyForHASSIntegration(Integration): + name = "shellyforhass" + + def get_default_actions_mapping(self) -> Optional[DefaultActionsMapping]: + return self.controller.get_shellyforhass_actions_mapping() + + async def listen_changes(self, controller_id: str) -> None: + await Hass.listen_event( + self.controller, + self.event_callback, + "shellyforhass.click", + entity_id=controller_id, + ) + + async def event_callback( + self, event_name: str, data: EventData, kwargs: Dict[str, Any] + ) -> None: + click_type = data["click_type"] + action = f"{click_type}" + await self.controller.handle_action(action, extra=data) diff --git a/docs/docs/start/integrations.md b/docs/docs/start/integrations.md index 9951a7f6..724f4d09 100644 --- a/docs/docs/start/integrations.md +++ b/docs/docs/start/integrations.md @@ -169,4 +169,12 @@ This integration(**`lutron_caseta`**) listens to `lutron_caseta_button_event` ev #### Homematic -This integration ([**`homematic`**](https://www.home-assistant.io/integrations/homematic/)) listens to `homematic.keypress` events. It created an action like `_`. It does not have any additional arguments. +This integration ([**`homematic`**](https://www.home-assistant.io/integrations/homematic)) listens to `homematic.keypress` events. It creates an action like `_`. It does not have any additional arguments. + +#### Shelly + +This integration ([**`shelly`**](https://www.home-assistant.io/integrations/shelly)) listens to `shelly.click` events. It creates an action like `_`. It does not have any additional arguments. + +#### Shelly for HASS + +This integration ([**`shellyforhass`**](https://github.com/StyraHem/ShellyForHASS)) listens to `shellyforhass.click` events. It creates an action like ``. It does not have any additional arguments. diff --git a/tests/unit_tests/cx_core/integration/integration_test.py b/tests/unit_tests/cx_core/integration/integration_test.py index e4df04d1..587ff1bf 100644 --- a/tests/unit_tests/cx_core/integration/integration_test.py +++ b/tests/unit_tests/cx_core/integration/integration_test.py @@ -13,4 +13,6 @@ def test_get_integrations(fake_controller: Controller) -> None: "mqtt", "lutron_caseta", "homematic", + "shelly", + "shellyforhass", } diff --git a/tests/unit_tests/cx_core/integration/shelly_test.py b/tests/unit_tests/cx_core/integration/shelly_test.py new file mode 100644 index 00000000..47ba16c8 --- /dev/null +++ b/tests/unit_tests/cx_core/integration/shelly_test.py @@ -0,0 +1,62 @@ +from typing import Any, Dict + +import pytest +from appdaemon.plugins.hass.hassapi import Hass +from cx_core.controller import Controller +from cx_core.integration.shelly import ShellyIntegration +from pytest_mock.plugin import MockerFixture + + +@pytest.mark.parametrize( + "data, expected", + [ + ( + { + "device_id": "e09c64a22553484d804353ef97f6fcd6", + "device": "shellybutton1-A4C12A45174", + "channel": 1, + "click_type": "single", + "generation": 1, + }, + "single_1", + ), + ( + { + "device_id": "e09d64a22553384d8043532f97f6fcd6", + "device": "shellybutton1-A4C13B45274", + "channel": 3, + "click_type": "btn_down", + "generation": 1, + }, + "btn_down_3", + ), + ], +) +async def test_callback( + fake_controller: Controller, + mocker: MockerFixture, + data: Dict[str, Any], + expected: str, +) -> None: + handle_action_patch = mocker.patch.object(fake_controller, "handle_action") + shelly_integration = ShellyIntegration(fake_controller, {}) + await shelly_integration.event_callback("test", data, {}) + handle_action_patch.assert_called_once_with(expected, extra=data) + + +async def test_listen_changes( + fake_controller: Controller, + mocker: MockerFixture, +) -> None: + controller_id = "controller_id" + listen_event_mock = mocker.patch.object(Hass, "listen_event") + shelly_integration = ShellyIntegration(fake_controller, {}) + + await shelly_integration.listen_changes(controller_id) + + listen_event_mock.assert_called_once_with( + fake_controller, + shelly_integration.event_callback, + "shelly.click", + device=controller_id, + ) diff --git a/tests/unit_tests/cx_core/integration/shellyforhass_test.py b/tests/unit_tests/cx_core/integration/shellyforhass_test.py new file mode 100644 index 00000000..cd48d612 --- /dev/null +++ b/tests/unit_tests/cx_core/integration/shellyforhass_test.py @@ -0,0 +1,56 @@ +from typing import Any, Dict + +import pytest +from appdaemon.plugins.hass.hassapi import Hass +from cx_core.controller import Controller +from cx_core.integration.shellyforhass import ShellyForHASSIntegration +from pytest_mock.plugin import MockerFixture + + +@pytest.mark.parametrize( + "data, expected", + [ + ( + { + "entity_id": "binary_sensor.shelly_shbtn_1_xxxxxx_switch", + "click_type": "single", + }, + "single", + ), + ( + { + "entity_id": "binary_sensor.shelly_shbtn_1_xxxxxx_switch", + "click_type": "double", + }, + "double", + ), + ], +) +async def test_callback( + fake_controller: Controller, + mocker: MockerFixture, + data: Dict[str, Any], + expected: str, +) -> None: + handle_action_patch = mocker.patch.object(fake_controller, "handle_action") + shellyforhass_integration = ShellyForHASSIntegration(fake_controller, {}) + await shellyforhass_integration.event_callback("test", data, {}) + handle_action_patch.assert_called_once_with(expected, extra=data) + + +async def test_listen_changes( + fake_controller: Controller, + mocker: MockerFixture, +) -> None: + controller_id = "controller_id" + listen_event_mock = mocker.patch.object(Hass, "listen_event") + shellyforhass_integration = ShellyForHASSIntegration(fake_controller, {}) + + await shellyforhass_integration.listen_changes(controller_id) + + listen_event_mock.assert_called_once_with( + fake_controller, + shellyforhass_integration.event_callback, + "shellyforhass.click", + entity_id=controller_id, + ) diff --git a/tests/unit_tests/cx_devices/devices_test.py b/tests/unit_tests/cx_devices/devices_test.py index a186853d..24067cc9 100644 --- a/tests/unit_tests/cx_devices/devices_test.py +++ b/tests/unit_tests/cx_devices/devices_test.py @@ -64,6 +64,8 @@ def test_devices(device_class: Type[Controller]) -> None: device.get_lutron_caseta_actions_mapping, device.get_state_actions_mapping, device.get_homematic_actions_mapping, + device.get_shelly_actions_mapping, + device.get_shellyforhass_actions_mapping, ] for func in integration_mappings_funcs: mappings = func() From 3a4682aca020d8f4ac78f648e748223d32aa7256 Mon Sep 17 00:00:00 2001 From: Xavier Moreno Date: Fri, 13 May 2022 22:55:39 +0200 Subject: [PATCH 2/3] feat(device): add shelly devices for shelly and shellyforhass integrations related to #441 --- apps/controllerx/controllerx.py | 1 + apps/controllerx/cx_devices/shelly.py | 47 ++++++++++++++++++ docs/docs/assets/controllers/Shelly25.jpeg | Bin 0 -> 16467 bytes docs/docs/assets/controllers/ShellyI3.jpeg | Bin 0 -> 20661 bytes .../docs/assets/controllers/ShellyPlusI4.jpeg | Bin 0 -> 20056 bytes docs/main.py | 10 ++++ 6 files changed, 58 insertions(+) create mode 100644 apps/controllerx/cx_devices/shelly.py create mode 100644 docs/docs/assets/controllers/Shelly25.jpeg create mode 100644 docs/docs/assets/controllers/ShellyI3.jpeg create mode 100644 docs/docs/assets/controllers/ShellyPlusI4.jpeg diff --git a/apps/controllerx/controllerx.py b/apps/controllerx/controllerx.py index eae0fe81..354107ca 100644 --- a/apps/controllerx/controllerx.py +++ b/apps/controllerx/controllerx.py @@ -24,6 +24,7 @@ from cx_devices.rgb_genie import * from cx_devices.robb import * from cx_devices.sengled import * +from cx_devices.shelly import * from cx_devices.smartthings import * from cx_devices.sonoff import * from cx_devices.terncy import * diff --git a/apps/controllerx/cx_devices/shelly.py b/apps/controllerx/cx_devices/shelly.py new file mode 100644 index 00000000..aa1fc35d --- /dev/null +++ b/apps/controllerx/cx_devices/shelly.py @@ -0,0 +1,47 @@ +from cx_const import DefaultActionsMapping, Light +from cx_core import LightController + + +class ShellyI3LightController(LightController): + def get_shellyforhass_actions_mapping(self) -> DefaultActionsMapping: + return { + "single": Light.CLICK_BRIGHTNESS_UP, + "long": Light.CLICK_BRIGHTNESS_DOWN, + "double": Light.ON_FULL_BRIGHTNESS, + } + + +class ShellyPlusI4LightController(LightController): + def get_shelly_actions_mapping(self) -> DefaultActionsMapping: + return { + "single_push_1": Light.ON, + "long_push_1": Light.HOLD_COLOR_UP, + "btn_up_1": Light.RELEASE, + "double_push_1": Light.ON_FULL_COLOR_TEMP, + "single_push_2": Light.OFF, + "long_push_2": Light.HOLD_COLOR_DOWN, + "btn_up_2": Light.RELEASE, + "double_push_2": Light.ON_MIN_COLOR_TEMP, + "single_push_3": Light.CLICK_BRIGHTNESS_UP, + "long_push_3": Light.HOLD_BRIGHTNESS_UP, + "btn_up_3": Light.RELEASE, + "double_push_3": Light.ON_FULL_BRIGHTNESS, + "single_push_4": Light.CLICK_BRIGHTNESS_DOWN, + "long_push_4": Light.HOLD_BRIGHTNESS_DOWN, + "btn_up_4": Light.RELEASE, + "double_push_4": Light.ON_MIN_BRIGHTNESS, + } + + +class Shelly25LightController(LightController): + def get_shelly_actions_mapping(self) -> DefaultActionsMapping: + return { + "single_push_1": Light.ON, + "long_push_1": Light.HOLD_BRIGHTNESS_UP, + "btn_up_1": Light.RELEASE, + "double_push_1": Light.ON_FULL_BRIGHTNESS, + "single_push_2": Light.OFF, + "long_push_2": Light.HOLD_BRIGHTNESS_DOWN, + "btn_up_2": Light.RELEASE, + "double_push_2": Light.ON_MIN_BRIGHTNESS, + } diff --git a/docs/docs/assets/controllers/Shelly25.jpeg b/docs/docs/assets/controllers/Shelly25.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..939f0935485169a4ec2ff556f3b16aaa94e51212 GIT binary patch literal 16467 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 literal 0 HcmV?d00001 diff --git a/docs/docs/assets/controllers/ShellyI3.jpeg b/docs/docs/assets/controllers/ShellyI3.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e2de708479369a304a53b81a784224b65ca905ab GIT binary patch literal 20661 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 literal 0 HcmV?d00001 diff --git a/docs/main.py b/docs/main.py index 7b5f9af3..a50dae35 100644 --- a/docs/main.py +++ b/docs/main.py @@ -24,6 +24,8 @@ "state": "State", "lutron": "Lutron Caseta", "homematic": "Homematic", + "shelly": "Shelly", + "shellyforhass": "ShellyForHass", } INTEGRATIONS_EXAMPLES: List[Dict[str, Any]] = [ @@ -47,6 +49,12 @@ }, {"name": "lutron", "title": "Lutron Caseta", "controller": "87654321"}, {"name": "homematic", "title": "Homematic", "controller": "my_controller"}, + {"name": "shelly", "title": "Shelly", "controller": "shellybutton-ABC123456"}, + { + "name": "shellyforhass", + "title": "ShellyForHass", + "controller": "binary_sensor.shelly_button_switch", + }, ] @@ -168,6 +176,8 @@ def get_controller_docs(controller: TypeController[Entity]) -> ControllerDocs: "state": controller.get_state_actions_mapping, "lutron": controller.get_lutron_caseta_actions_mapping, "homematic": controller.get_homematic_actions_mapping, + "shelly": controller.get_shelly_actions_mapping, + "shellyforhass": controller.get_shellyforhass_actions_mapping, } for integration, integration_mapping_func in integration_mappings_funcs.items(): mapping = integration_mapping_func() From 3df78323606326a96e7182edd442ca0775b15820 Mon Sep 17 00:00:00 2001 From: Xavier Moreno Date: Fri, 13 May 2022 23:09:12 +0200 Subject: [PATCH 3/3] docs: add missing docs for shelly integrations related to #441 --- RELEASE_NOTES.md | 5 +++++ docs/docs/others/extract-controller-id.md | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 4cdb81b6..c15c244e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -9,6 +9,8 @@ PRERELEASE_NOTE ## :pencil2: Features - Add following predefined actions `on_min_max_brightness`, `on_max_min_brightness`, `on_min_max_color_temp` and `on_max_min_color_temp`. [ #472 ] @sabaatworld +- Add [`shelly` integration](https://xaviml.github.io/controllerx/start/integrations/#shelly). +- Add [`shellyforhass` integration](https://xaviml.github.io/controllerx/start/integrations/#shellyforhass).