From dfaa241bae350af08733f242393d3a72fc469c82 Mon Sep 17 00:00:00 2001 From: Mike Gray Date: Wed, 7 Aug 2024 22:51:22 -0500 Subject: [PATCH] fix: correct name for self.silent_entities --- neon_homeassistant_skill/__init__.py | 26 +++++++---- poetry.lock | 18 +++++++- pyproject.toml | 3 +- test/e2e/test_e2e.py | 13 ++++-- test/test_skill.py | 69 ++++++++++++++++++++++++---- 5 files changed, 105 insertions(+), 24 deletions(-) diff --git a/neon_homeassistant_skill/__init__.py b/neon_homeassistant_skill/__init__.py index b185580..d4664df 100644 --- a/neon_homeassistant_skill/__init__.py +++ b/neon_homeassistant_skill/__init__.py @@ -70,12 +70,18 @@ def initialize(self): self.handle_set_light_color_response, ) self.settings.merge(DEFAULT_SETTINGS, new_only=True) - self.verbose = self.settings.get("verbose", True) - self.silent_entities = set(self.settings.get("silent_entities", [])) if self.disable_intents: self.log.info("User has indicated they do not want to use Home Assistant intents. Disabling.") self.disable_ha_intents() + @property + def verbose(self): + return self.settings.get("verbose", False) + + @property + def silent_entities(self): + return self.settings.get("silent_entities", []) + @property def disable_intents(self): setting = self.settings.get("disable_intents", False) @@ -175,9 +181,8 @@ def handle_turn_on_response(self, message: Message) -> None: """Handle turn on intent response.""" self.log.debug(f"Handling turn on response to {message.data}") device = message.data.get("device", "") - if device: - if device not in self.silent_devices: - self.speak_dialog("device.turned.on", data={"device": device}) + if device and device not in self.silent_entities: + self.speak_dialog("device.turned.on", data={"device": device}) else: self.speak_dialog("no.parsed.device") @@ -204,9 +209,8 @@ def handle_turn_off_intent(self, message: Message) -> None: def handle_turn_off_response(self, message: Message) -> None: self.log.debug(f"Handling turn off response to {message.data}") device = message.data.get("device", "") - if device: - if device not in self.silent_devices: - self.speak_dialog("device.turned.off", data={"device": device}) + if device and device not in self.silent_entities: + self.speak_dialog("device.turned.off", data={"device": device}) else: self.speak_dialog("no.parsed.device") @@ -286,7 +290,7 @@ def handle_set_light_brightness_response(self, message: Message): brightness = message.data.get("brightness") device = message.data.get("device") self.log.info(f"Device {device} brightness is now {brightness}") - if brightness and device not in self.silent_devices: + if brightness and device not in self.silent_entities: return self.speak_dialog( "lights.current.brightness", data={ @@ -294,6 +298,8 @@ def handle_set_light_brightness_response(self, message: Message): "device": device, }, ) + if device in self.silent_entities: + return if message.data.get("response"): return self.speak_dialog("device.not.found", data={"device": device}) else: @@ -408,6 +414,8 @@ def handle_set_light_color_response(self, message: Message): "device": device, }, ) + if device in self.silent_entities: + return if message.data.get("response"): return self.speak_dialog("device.not.found", data={"device": device}) else: diff --git a/poetry.lock b/poetry.lock index d1ab800..c52f828 100644 --- a/poetry.lock +++ b/poetry.lock @@ -781,6 +781,22 @@ files = [ {file = "memory_tempfile-2.2.3-py3-none-any.whl", hash = "sha256:dcea50b967f75b494fae8e242dc095e97280cfe6a53631473887b05f943cafeb"}, ] +[[package]] +name = "mock" +version = "5.1.0" +description = "Rolling backport of unittest.mock for all Pythons" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mock-5.1.0-py3-none-any.whl", hash = "sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744"}, + {file = "mock-5.1.0.tar.gz", hash = "sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d"}, +] + +[package.extras] +build = ["blurb", "twine", "wheel"] +docs = ["sphinx"] +test = ["pytest", "pytest-cov"] + [[package]] name = "mycroft-messagebus-client" version = "0.10.1" @@ -2256,4 +2272,4 @@ test = ["neon-minerva"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "c189dcbf7c9d27483d4c0cc0d79438ca9457083d67881766e689cad008059862" +content-hash = "e4c7b3330fa30c884ebaff5901d9935c38d37a0e277cde9ebdf47b85838c0893" diff --git a/pyproject.toml b/pyproject.toml index 6f4b925..7886137 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "neon-homeassistant-skill" -version = "0.0.21" +version = "0.0.22" description = "An OVOS/Neon.AI Skill for Home Assistant, which integrates with ovos-PHAL-plugin-homeassistant." authors = ["Mike Gray "] readme = "README.md" @@ -51,6 +51,7 @@ poethepoet = "^0.24.4" pytest-cov = "^4.1.0" setuptools = "^69.0.3" toml = "^0.10.2" +mock = "^5.1.0" [tool.ruff] line-length = 119 diff --git a/test/e2e/test_e2e.py b/test/e2e/test_e2e.py index 46125ee..31dee37 100644 --- a/test/e2e/test_e2e.py +++ b/test/e2e/test_e2e.py @@ -8,20 +8,25 @@ def test_default_enabled_state(): skill = NeonHomeAssistantSkill(bus=bus, skill_id="neon_homeassistant_skill.test") assert set(skill.connected_intents).issubset({intent[0] for intent in skill.intent_service.registered_intents}) assert skill._intents_enabled is True - return bus, skill + def test_intent_disable_setting(): bus = FakeBus() - skill = NeonHomeAssistantSkill(bus=bus, skill_id="neon_homeassistant_skill.test", settings={"disable_intents": True}) + skill = NeonHomeAssistantSkill( + bus=bus, skill_id="neon_homeassistant_skill.test", settings={"disable_intents": True} + ) assert skill._intents_enabled is False assert not set(skill.connected_intents).issubset({intent[0] for intent in skill.intent_service.registered_intents}) + def test_reenabling(): bus = FakeBus() - skill = NeonHomeAssistantSkill(bus=bus, skill_id="neon_homeassistant_skill.test", settings={"disable_intents": True}) + skill = NeonHomeAssistantSkill( + bus=bus, skill_id="neon_homeassistant_skill.test", settings={"disable_intents": True} + ) assert skill._intents_enabled is False assert not set(skill.connected_intents).issubset({intent[0] for intent in skill.intent_service.registered_intents}) skill.settings["disable_intents"] = False assert skill.disable_intents is False assert skill._intents_enabled is True - assert set(skill.connected_intents).issubset({intent[0] for intent in skill.intent_service.registered_intents}) \ No newline at end of file + assert set(skill.connected_intents).issubset({intent[0] for intent in skill.intent_service.registered_intents}) diff --git a/test/test_skill.py b/test/test_skill.py index 019e927..76a8b03 100644 --- a/test/test_skill.py +++ b/test/test_skill.py @@ -2,11 +2,13 @@ # pylint: disable=invalid-name,protected-access import unittest from os import getenv -from yaml import safe_load -from mycroft.skills.intent_service import IntentService +from mock import Mock, call +from ovos_bus_client import Message from ovos_utils.messagebus import FakeBus from padacioso import IntentContainer +from yaml import safe_load + from neon_homeassistant_skill import NeonHomeAssistantSkill BRANCH = "main" @@ -30,20 +32,15 @@ class TestSkillIntentMatching(unittest.TestCase): u = [] for sentence, entity in utt[0].items(): if "entity" in entity[0].keys(): - revised_intent = sentence.replace( - entity[0].get("entity"), "{entity}" - ) + revised_intent = sentence.replace(entity[0].get("entity"), "{entity}") if len(entity[0].keys()) > 1 and entity[0].get("color"): - revised_intent = revised_intent.replace( - entity[0].get("color"), "{color}" - ) + revised_intent = revised_intent.replace(entity[0].get("color"), "{color}") u.append(revised_intent) elif "area" in entity[0].keys(): u.append(sentence.replace(entity[0].get("area"), "{area}")) ha_intents.add_intent(name, u) bus = FakeBus() - intent_service = IntentService(bus) test_skill_id = "test_skill.test" @classmethod @@ -64,3 +61,57 @@ def test_intents(self): result = self.ha_intents.calc_intent(u) if len(utt[u]) > 1: self.assertTrue(list(utt[u][1].values())[0] in u) + + def test_turn_on_silent_entities(self): + self.skill.speak_dialog = Mock() + self.skill.settings["silent_entities"] = ["emergency switch", "freezer switch"] + self.skill.handle_turn_on_response(Message(msg_type="test", data={"device": "emergency switch"})) + self.skill.speak_dialog.assert_has_calls([call("no.parsed.device")]) + self.skill.speak_dialog.reset_mock() + self.skill.handle_turn_on_response(Message(msg_type="test", data={"device": "freezer switch"})) + self.skill.speak_dialog.assert_has_calls([call("no.parsed.device")]) + self.skill.speak_dialog.reset_mock() + self.skill.handle_turn_on_response(Message(msg_type="test", data={"device": "ambiance"})) + self.skill.speak_dialog.assert_has_calls([call("device.turned.on", data={"device": "ambiance"})]) + + def test_turn_off_silent_entities(self): + self.skill.speak_dialog = Mock() + self.skill.settings["silent_entities"] = ["emergency switch", "freezer switch"] + self.skill.handle_turn_off_response(Message(msg_type="test", data={"device": "emergency switch"})) + self.skill.speak_dialog.assert_has_calls([call("no.parsed.device")]) + self.skill.speak_dialog.reset_mock() + self.skill.handle_turn_off_response(Message(msg_type="test", data={"device": "freezer switch"})) + self.skill.speak_dialog.assert_has_calls([call("no.parsed.device")]) + self.skill.speak_dialog.reset_mock() + self.skill.handle_turn_off_response(Message(msg_type="test", data={"device": "ambiance"})) + self.skill.speak_dialog.assert_has_calls([call("device.turned.off", data={"device": "ambiance"})]) + + def test_light_brightness_response_silent_entities(self): + self.skill.speak_dialog = Mock() + self.skill.settings["silent_entities"] = ["ignore bulb"] + self.skill.handle_set_light_brightness_response( + Message(msg_type="test", data={"device": "ignore bulb", "brightness": 50}) + ) + self.skill.speak_dialog.assert_not_called() + self.skill.speak_dialog.reset_mock() + self.skill.handle_set_light_brightness_response( + Message(msg_type="test", data={"device": "bunny", "brightness": 50}) + ) + self.skill.speak_dialog.assert_has_calls( + [call("lights.current.brightness", data={"device": "bunny", "brightness": 50})] + ) + + def test_set_light_color_response_silent_entities(self): + self.skill.speak_dialog = Mock() + self.skill.settings["silent_entities"] = ["ignore bulb"] + self.skill.handle_set_light_color_response( + Message(msg_type="test", data={"device": "ignore bulb", "color": "chartreuse"}) + ) + self.skill.speak_dialog.assert_not_called() + self.skill.speak_dialog.reset_mock() + self.skill.handle_set_light_color_response( + Message(msg_type="test", data={"device": "bunny", "color": "mauve"}) + ) + self.skill.speak_dialog.assert_has_calls( + [call("lights.current.color", data={"device": "bunny", "color": "mauve"})] + )