diff --git a/homeassistant/components/advantage_air/__init__.py b/homeassistant/components/advantage_air/__init__.py index 739baefda5d..3b5faaa1855 100644 --- a/homeassistant/components/advantage_air/__init__.py +++ b/homeassistant/components/advantage_air/__init__.py @@ -75,6 +75,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: "coordinator": coordinator, "aircon": error_handle_factory(api.aircon.async_set), "lights": error_handle_factory(api.lights.async_set), + "things": error_handle_factory(api.things.async_set), } await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) diff --git a/homeassistant/components/advantage_air/cover.py b/homeassistant/components/advantage_air/cover.py index 8d05f7e2e63..fe725256643 100644 --- a/homeassistant/components/advantage_air/cover.py +++ b/homeassistant/components/advantage_air/cover.py @@ -16,7 +16,7 @@ from .const import ( ADVANTAGE_AIR_STATE_OPEN, DOMAIN as ADVANTAGE_AIR_DOMAIN, ) -from .entity import AdvantageAirZoneEntity +from .entity import AdvantageAirThingEntity, AdvantageAirZoneEntity PARALLEL_UPDATES = 0 @@ -37,6 +37,16 @@ async def async_setup_entry( # Only add zone vent controls when zone in vent control mode. if zone["type"] == 0: entities.append(AdvantageAirZoneVent(instance, ac_key, zone_key)) + if things := instance["coordinator"].data.get("myThings"): + for thing in things["things"].values(): + if thing["channelDipState"] in [1, 2]: # 1 = "Blind", 2 = "Blind 2" + entities.append( + AdvantageAirThingCover(instance, thing, CoverDeviceClass.BLIND) + ) + elif thing["channelDipState"] == 3: # 3 = "Garage door" + entities.append( + AdvantageAirThingCover(instance, thing, CoverDeviceClass.GARAGE) + ) async_add_entities(entities) @@ -113,3 +123,32 @@ class AdvantageAirZoneVent(AdvantageAirZoneEntity, CoverEntity): } } ) + + +class AdvantageAirThingCover(AdvantageAirThingEntity, CoverEntity): + """Representation of Advantage Air Cover controlled by MyPlace.""" + + _attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE + + def __init__( + self, + instance: dict[str, Any], + thing: dict[str, Any], + device_class: CoverDeviceClass, + ) -> None: + """Initialize an Advantage Air Things Cover.""" + super().__init__(instance, thing) + self._attr_device_class = device_class + + @property + def is_closed(self) -> bool: + """Return if cover is fully closed.""" + return self._data["value"] == 0 + + async def async_open_cover(self, **kwargs: Any) -> None: + """Fully open zone vent.""" + return await self.async_turn_on() + + async def async_close_cover(self, **kwargs: Any) -> None: + """Fully close zone vent.""" + return await self.async_turn_off() diff --git a/homeassistant/components/advantage_air/entity.py b/homeassistant/components/advantage_air/entity.py index aaaa4ff5813..41e7a499caf 100644 --- a/homeassistant/components/advantage_air/entity.py +++ b/homeassistant/components/advantage_air/entity.py @@ -1,5 +1,4 @@ """Advantage Air parent entity class.""" - from typing import Any from homeassistant.helpers.entity import DeviceInfo @@ -54,3 +53,40 @@ class AdvantageAirZoneEntity(AdvantageAirAcEntity): @property def _zone(self) -> dict[str, Any]: return self.coordinator.data["aircons"][self.ac_key]["zones"][self.zone_key] + + +class AdvantageAirThingEntity(AdvantageAirEntity): + """Parent class for Advantage Air Things Entities.""" + + def __init__(self, instance: dict[str, Any], thing: dict[str, Any]) -> None: + """Initialize common aspects of an Advantage Air Things entity.""" + super().__init__(instance) + self.set = instance["things"] + self._id = thing["id"] + self._attr_unique_id += f"-{self._id}" + + self._attr_device_info = DeviceInfo( + via_device=(DOMAIN, self.coordinator.data["system"]["rid"]), + identifiers={(DOMAIN, self._attr_unique_id)}, + manufacturer="Advantage Air", + model="MyPlace", + name=thing["name"], + ) + + @property + def _data(self) -> dict: + """Return the thing data.""" + return self.coordinator.data["myThings"]["things"][self._id] + + @property + def is_on(self): + """Return if the thing is considered on.""" + return self._data["value"] > 0 + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the thing on.""" + await self.set({self._id: {"id": self._id, "value": 100}}) + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn the thing off.""" + await self.set({self._id: {"id": self._id, "value": 0}}) diff --git a/homeassistant/components/advantage_air/light.py b/homeassistant/components/advantage_air/light.py index 19918992f7e..c88bceea510 100644 --- a/homeassistant/components/advantage_air/light.py +++ b/homeassistant/components/advantage_air/light.py @@ -12,7 +12,7 @@ from .const import ( ADVANTAGE_AIR_STATE_ON, DOMAIN as ADVANTAGE_AIR_DOMAIN, ) -from .entity import AdvantageAirEntity +from .entity import AdvantageAirEntity, AdvantageAirThingEntity async def async_setup_entry( @@ -31,6 +31,12 @@ async def async_setup_entry( entities.append(AdvantageAirLight(instance, light)) else: entities.append(AdvantageAirLightDimmable(instance, light)) + if things := instance["coordinator"].data.get("myThings"): + for thing in things["things"].values(): + if thing["channelDipState"] == 4: # 4 = "Light (on/off)"" + entities.append(AdvantageAirThingLight(instance, thing)) + elif thing["channelDipState"] == 5: # 5 = "Light (Dimmable)"" + entities.append(AdvantageAirThingLightDimmable(instance, thing)) async_add_entities(entities) @@ -42,7 +48,7 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity): def __init__(self, instance: dict[str, Any], light: dict[str, Any]) -> None: """Initialize an Advantage Air Light.""" super().__init__(instance) - self.lights = instance["lights"] + self.set = instance["lights"] self._id: str = light["id"] self._attr_unique_id += f"-{self._id}" self._attr_device_info = DeviceInfo( @@ -54,24 +60,22 @@ class AdvantageAirLight(AdvantageAirEntity, LightEntity): ) @property - def _light(self) -> dict[str, Any]: + def _data(self) -> dict[str, Any]: """Return the light object.""" return self.coordinator.data["myLights"]["lights"][self._id] @property def is_on(self) -> bool: """Return if the light is on.""" - return self._light["state"] == ADVANTAGE_AIR_STATE_ON + return self._data["state"] == ADVANTAGE_AIR_STATE_ON async def async_turn_on(self, **kwargs: Any) -> None: """Turn the light on.""" - await self.lights({self._id: {"id": self._id, "state": ADVANTAGE_AIR_STATE_ON}}) + await self.set({self._id: {"id": self._id, "state": ADVANTAGE_AIR_STATE_ON}}) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the light off.""" - await self.lights( - {self._id: {"id": self._id, "state": ADVANTAGE_AIR_STATE_OFF}} - ) + await self.set({self._id: {"id": self._id, "state": ADVANTAGE_AIR_STATE_OFF}}) class AdvantageAirLightDimmable(AdvantageAirLight): @@ -82,7 +86,7 @@ class AdvantageAirLightDimmable(AdvantageAirLight): @property def brightness(self) -> int: """Return the brightness of this light between 0..255.""" - return round(self._light["value"] * 255 / 100) + return round(self._data["value"] * 255 / 100) async def async_turn_on(self, **kwargs: Any) -> None: """Turn the light on and optionally set the brightness.""" @@ -91,4 +95,32 @@ class AdvantageAirLightDimmable(AdvantageAirLight): } if ATTR_BRIGHTNESS in kwargs: data[self._id]["value"] = round(kwargs[ATTR_BRIGHTNESS] * 100 / 255) - await self.lights(data) + await self.set(data) + + +class AdvantageAirThingLight(AdvantageAirThingEntity, LightEntity): + """Representation of Advantage Air Light controlled by myThings.""" + + _attr_supported_color_modes = {ColorMode.ONOFF} + + +class AdvantageAirThingLightDimmable(AdvantageAirThingEntity, LightEntity): + """Representation of Advantage Air Dimmable Light controlled by myThings.""" + + _attr_supported_color_modes = {ColorMode.ONOFF, ColorMode.BRIGHTNESS} + + @property + def brightness(self) -> int: + """Return the brightness of this light between 0..255.""" + return round(self._data["value"] * 255 / 100) + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the light on by setting the brightness.""" + await self.set( + { + self._id: { + "id": self._id, + "value": round(kwargs.get(ATTR_BRIGHTNESS, 255) * 100 / 255), + } + } + ) diff --git a/homeassistant/components/advantage_air/select.py b/homeassistant/components/advantage_air/select.py index 742ce810011..6d28549ca41 100644 --- a/homeassistant/components/advantage_air/select.py +++ b/homeassistant/components/advantage_air/select.py @@ -42,11 +42,14 @@ class AdvantageAirMyZone(AdvantageAirAcEntity, SelectEntity): self._number_to_name = {0: ADVANTAGE_AIR_INACTIVE} self._name_to_number = {ADVANTAGE_AIR_INACTIVE: 0} - for zone in instance["coordinator"].data["aircons"][ac_key]["zones"].values(): - if zone["type"] > 0: - self._name_to_number[zone["name"]] = zone["number"] - self._number_to_name[zone["number"]] = zone["name"] - self._attr_options.append(zone["name"]) + if "aircons" in instance["coordinator"].data: + for zone in ( + instance["coordinator"].data["aircons"][ac_key]["zones"].values() + ): + if zone["type"] > 0: + self._name_to_number[zone["name"]] = zone["number"] + self._number_to_name[zone["number"]] = zone["name"] + self._attr_options.append(zone["name"]) @property def current_option(self) -> str: diff --git a/homeassistant/components/advantage_air/switch.py b/homeassistant/components/advantage_air/switch.py index e3504ab7624..3ef3dbbb74d 100644 --- a/homeassistant/components/advantage_air/switch.py +++ b/homeassistant/components/advantage_air/switch.py @@ -1,7 +1,7 @@ """Switch platform for Advantage Air integration.""" from typing import Any -from homeassistant.components.switch import SwitchEntity +from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -11,7 +11,7 @@ from .const import ( ADVANTAGE_AIR_STATE_ON, DOMAIN as ADVANTAGE_AIR_DOMAIN, ) -from .entity import AdvantageAirAcEntity +from .entity import AdvantageAirAcEntity, AdvantageAirThingEntity async def async_setup_entry( @@ -28,6 +28,10 @@ async def async_setup_entry( for ac_key, ac_device in aircons.items(): if ac_device["info"]["freshAirStatus"] != "none": entities.append(AdvantageAirFreshAir(instance, ac_key)) + if things := instance["coordinator"].data.get("myThings"): + for thing in things["things"].values(): + if thing["channelDipState"] == 8: # 8 = Other relay + entities.append(AdvantageAirRelay(instance, thing)) async_add_entities(entities) @@ -36,6 +40,7 @@ class AdvantageAirFreshAir(AdvantageAirAcEntity, SwitchEntity): _attr_icon = "mdi:air-filter" _attr_name = "Fresh air" + _attr_device_class = SwitchDeviceClass.SWITCH def __init__(self, instance: dict[str, Any], ac_key: str) -> None: """Initialize an Advantage Air fresh air control.""" @@ -58,3 +63,9 @@ class AdvantageAirFreshAir(AdvantageAirAcEntity, SwitchEntity): await self.aircon( {self.ac_key: {"info": {"freshAirStatus": ADVANTAGE_AIR_STATE_OFF}}} ) + + +class AdvantageAirRelay(AdvantageAirThingEntity, SwitchEntity): + """Representation of Advantage Air Thing.""" + + _attr_device_class = SwitchDeviceClass.SWITCH diff --git a/tests/components/advantage_air/__init__.py b/tests/components/advantage_air/__init__.py index 9b7d9705366..b826e3ac7ce 100644 --- a/tests/components/advantage_air/__init__.py +++ b/tests/components/advantage_air/__init__.py @@ -20,6 +20,9 @@ TEST_SET_URL = f"http://{USER_INPUT[CONF_IP_ADDRESS]}:{USER_INPUT[CONF_PORT]}/se TEST_SET_LIGHT_URL = ( f"http://{USER_INPUT[CONF_IP_ADDRESS]}:{USER_INPUT[CONF_PORT]}/setLights" ) +TEST_SET_THING_URL = ( + f"http://{USER_INPUT[CONF_IP_ADDRESS]}:{USER_INPUT[CONF_PORT]}/setThings" +) async def add_mock_config(hass): diff --git a/tests/components/advantage_air/fixtures/getSystemData.json b/tests/components/advantage_air/fixtures/getSystemData.json index 02d63bccb72..3548a45554f 100644 --- a/tests/components/advantage_air/fixtures/getSystemData.json +++ b/tests/components/advantage_air/fixtures/getSystemData.json @@ -220,11 +220,64 @@ } } }, + "myThings": { + "things": { + "200": { + "buttonType": "upDown", + "channelDipState": 1, + "id": "200", + "name": "Blind 1", + "value": 100 + }, + "201": { + "buttonType": "upDown", + "channelDipState": 2, + "id": "201", + "name": "Blind 2", + "value": 0 + }, + "202": { + "buttonType": "openClose", + "channelDipState": 3, + "id": "202", + "name": "Garage", + "value": 100 + }, + "203": { + "buttonType": "onOff", + "channelDipState": 4, + "id": "203", + "name": "Thing Light", + "value": 100 + }, + "204": { + "buttonType": "upDown", + "channelDipState": 5, + "id": "204", + "name": "Thing Light Dimmable", + "value": 100 + }, + "205": { + "buttonType": "onOff", + "channelDipState": 8, + "id": "205", + "name": "Relay", + "value": 100 + }, + "206": { + "buttonType": "onOff", + "channelDipState": 9, + "id": "206", + "name": "Fan", + "value": 100 + } + } + }, "system": { "hasAircons": true, "hasLights": true, "hasSensors": false, - "hasThings": false, + "hasThings": true, "hasThingsBOG": false, "hasThingsLight": false, "needsUpdate": false, diff --git a/tests/components/advantage_air/test_cover.py b/tests/components/advantage_air/test_cover.py index fd82bf94744..80162b448d1 100644 --- a/tests/components/advantage_air/test_cover.py +++ b/tests/components/advantage_air/test_cover.py @@ -19,6 +19,7 @@ from homeassistant.helpers import entity_registry as er from . import ( TEST_SET_RESPONSE, + TEST_SET_THING_URL, TEST_SET_URL, TEST_SYSTEM_DATA, TEST_SYSTEM_URL, @@ -28,7 +29,7 @@ from . import ( from tests.test_util.aiohttp import AiohttpClientMocker -async def test_cover_async_setup_entry( +async def test_ac_cover( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test cover platform.""" @@ -46,8 +47,6 @@ async def test_cover_async_setup_entry( registry = er.async_get(hass) - assert len(aioclient_mock.mock_calls) == 1 - # Test Cover Zone Entity entity_id = "cover.myauto_zone_y" state = hass.states.get(entity_id) @@ -66,7 +65,6 @@ async def test_cover_async_setup_entry( {ATTR_ENTITY_ID: [entity_id]}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 3 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setAircon" data = loads(aioclient_mock.mock_calls[-2][1].query["json"]) @@ -80,7 +78,6 @@ async def test_cover_async_setup_entry( {ATTR_ENTITY_ID: [entity_id]}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 5 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setAircon" data = loads(aioclient_mock.mock_calls[-2][1].query["json"]) @@ -95,7 +92,6 @@ async def test_cover_async_setup_entry( {ATTR_ENTITY_ID: [entity_id], ATTR_POSITION: 50}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 7 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setAircon" data = loads(aioclient_mock.mock_calls[-2][1].query["json"]) @@ -109,7 +105,6 @@ async def test_cover_async_setup_entry( {ATTR_ENTITY_ID: [entity_id], ATTR_POSITION: 0}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 9 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setAircon" data = loads(aioclient_mock.mock_calls[-2][1].query["json"]) @@ -129,7 +124,6 @@ async def test_cover_async_setup_entry( }, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 11 data = loads(aioclient_mock.mock_calls[-2][1].query["json"]) assert data["ac3"]["zones"]["z01"]["state"] == ADVANTAGE_AIR_STATE_CLOSE assert data["ac3"]["zones"]["z02"]["state"] == ADVANTAGE_AIR_STATE_CLOSE @@ -144,7 +138,65 @@ async def test_cover_async_setup_entry( }, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 13 data = loads(aioclient_mock.mock_calls[-2][1].query["json"]) assert data["ac3"]["zones"]["z01"]["state"] == ADVANTAGE_AIR_STATE_OPEN assert data["ac3"]["zones"]["z02"]["state"] == ADVANTAGE_AIR_STATE_OPEN + + +async def test_things_cover( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> None: + """Test cover platform.""" + + aioclient_mock.get( + TEST_SYSTEM_URL, + text=TEST_SYSTEM_DATA, + ) + aioclient_mock.get( + TEST_SET_THING_URL, + text=TEST_SET_RESPONSE, + ) + + await add_mock_config(hass) + + registry = er.async_get(hass) + + # Test Blind 1 Entity + entity_id = "cover.blind_1" + thing_id = "200" + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_OPEN + assert state.attributes.get("device_class") == CoverDeviceClass.BLIND + + entry = registry.async_get(entity_id) + assert entry + assert entry.unique_id == "uniqueid-200" + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_CLOSE_COVER, + {ATTR_ENTITY_ID: [entity_id]}, + blocking=True, + ) + assert aioclient_mock.mock_calls[-2][0] == "GET" + assert aioclient_mock.mock_calls[-2][1].path == "/setThings" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(thing_id) + assert data["id"] == thing_id + assert data["value"] == 0 + assert aioclient_mock.mock_calls[-1][0] == "GET" + assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" + + await hass.services.async_call( + COVER_DOMAIN, + SERVICE_OPEN_COVER, + {ATTR_ENTITY_ID: [entity_id]}, + blocking=True, + ) + assert aioclient_mock.mock_calls[-2][0] == "GET" + assert aioclient_mock.mock_calls[-2][1].path == "/setThings" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(thing_id) + assert data["id"] == thing_id + assert data["value"] == 100 + assert aioclient_mock.mock_calls[-1][0] == "GET" + assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" diff --git a/tests/components/advantage_air/test_light.py b/tests/components/advantage_air/test_light.py index 015d13867a4..80b28581d5b 100644 --- a/tests/components/advantage_air/test_light.py +++ b/tests/components/advantage_air/test_light.py @@ -11,13 +11,14 @@ from homeassistant.components.light import ( SERVICE_TURN_OFF, SERVICE_TURN_ON, ) -from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF +from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from . import ( TEST_SET_LIGHT_URL, TEST_SET_RESPONSE, + TEST_SET_THING_URL, TEST_SYSTEM_DATA, TEST_SYSTEM_URL, add_mock_config, @@ -26,9 +27,7 @@ from . import ( from tests.test_util.aiohttp import AiohttpClientMocker -async def test_light_async_setup_entry( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker -) -> None: +async def test_light(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -> None: """Test light setup.""" aioclient_mock.get( @@ -44,17 +43,16 @@ async def test_light_async_setup_entry( registry = er.async_get(hass) - assert len(aioclient_mock.mock_calls) == 1 - # Test Light Entity entity_id = "light.light_a" + light_id = "100" state = hass.states.get(entity_id) assert state assert state.state == STATE_OFF entry = registry.async_get(entity_id) assert entry - assert entry.unique_id == "uniqueid-100" + assert entry.unique_id == f"uniqueid-{light_id}" await hass.services.async_call( LIGHT_DOMAIN, @@ -62,11 +60,10 @@ async def test_light_async_setup_entry( {ATTR_ENTITY_ID: [entity_id]}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 3 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setLights" - data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get("100") - assert data["id"] == "100" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(light_id) + assert data["id"] == light_id assert data["state"] == ADVANTAGE_AIR_STATE_ON assert aioclient_mock.mock_calls[-1][0] == "GET" assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" @@ -77,21 +74,21 @@ async def test_light_async_setup_entry( {ATTR_ENTITY_ID: [entity_id]}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 5 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setLights" - data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get("100") - assert data["id"] == "100" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(light_id) + assert data["id"] == light_id assert data["state"] == ADVANTAGE_AIR_STATE_OFF assert aioclient_mock.mock_calls[-1][0] == "GET" assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" # Test Dimmable Light Entity entity_id = "light.light_b" + light_id = "101" entry = registry.async_get(entity_id) assert entry - assert entry.unique_id == "uniqueid-101" + assert entry.unique_id == f"uniqueid-{light_id}" await hass.services.async_call( LIGHT_DOMAIN, @@ -99,12 +96,69 @@ async def test_light_async_setup_entry( {ATTR_ENTITY_ID: [entity_id], ATTR_BRIGHTNESS: 128}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 7 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setLights" - data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get("101") - assert data["id"] == "101" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(light_id) + assert data["id"] == light_id assert data["value"] == 50 assert data["state"] == ADVANTAGE_AIR_STATE_ON assert aioclient_mock.mock_calls[-1][0] == "GET" assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" + + +async def test_things_light( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> None: + """Test things lights.""" + + aioclient_mock.get( + TEST_SYSTEM_URL, + text=TEST_SYSTEM_DATA, + ) + aioclient_mock.get( + TEST_SET_THING_URL, + text=TEST_SET_RESPONSE, + ) + + await add_mock_config(hass) + + registry = er.async_get(hass) + + # Test Switch Entity + entity_id = "light.thing_light_dimmable" + light_id = "204" + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_ON + + entry = registry.async_get(entity_id) + assert entry + assert entry.unique_id == "uniqueid-204" + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: [entity_id]}, + blocking=True, + ) + assert aioclient_mock.mock_calls[-2][0] == "GET" + assert aioclient_mock.mock_calls[-2][1].path == "/setThings" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(light_id) + assert data["id"] == light_id + assert data["value"] == 0 + assert aioclient_mock.mock_calls[-1][0] == "GET" + assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" + + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: [entity_id], ATTR_BRIGHTNESS: 128}, + blocking=True, + ) + assert aioclient_mock.mock_calls[-2][0] == "GET" + assert aioclient_mock.mock_calls[-2][1].path == "/setThings" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(light_id) + assert data["id"] == light_id + assert data["value"] == 50 + assert aioclient_mock.mock_calls[-1][0] == "GET" + assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" diff --git a/tests/components/advantage_air/test_switch.py b/tests/components/advantage_air/test_switch.py index 8d0be7755a5..36851037623 100644 --- a/tests/components/advantage_air/test_switch.py +++ b/tests/components/advantage_air/test_switch.py @@ -10,12 +10,13 @@ from homeassistant.components.switch import ( SERVICE_TURN_OFF, SERVICE_TURN_ON, ) -from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF +from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from . import ( TEST_SET_RESPONSE, + TEST_SET_THING_URL, TEST_SET_URL, TEST_SYSTEM_DATA, TEST_SYSTEM_URL, @@ -43,8 +44,6 @@ async def test_cover_async_setup_entry( registry = er.async_get(hass) - assert len(aioclient_mock.mock_calls) == 1 - # Test Switch Entity entity_id = "switch.myzone_fresh_air" state = hass.states.get(entity_id) @@ -61,7 +60,6 @@ async def test_cover_async_setup_entry( {ATTR_ENTITY_ID: [entity_id]}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 3 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setAircon" data = loads(aioclient_mock.mock_calls[-2][1].query["json"]) @@ -75,10 +73,67 @@ async def test_cover_async_setup_entry( {ATTR_ENTITY_ID: [entity_id]}, blocking=True, ) - assert len(aioclient_mock.mock_calls) == 5 assert aioclient_mock.mock_calls[-2][0] == "GET" assert aioclient_mock.mock_calls[-2][1].path == "/setAircon" data = loads(aioclient_mock.mock_calls[-2][1].query["json"]) assert data["ac1"]["info"]["freshAirStatus"] == ADVANTAGE_AIR_STATE_OFF assert aioclient_mock.mock_calls[-1][0] == "GET" assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" + + +async def test_things_switch( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> None: + """Test things switches.""" + + aioclient_mock.get( + TEST_SYSTEM_URL, + text=TEST_SYSTEM_DATA, + ) + aioclient_mock.get( + TEST_SET_THING_URL, + text=TEST_SET_RESPONSE, + ) + + await add_mock_config(hass) + + registry = er.async_get(hass) + + # Test Switch Entity + entity_id = "switch.relay" + thing_id = "205" + state = hass.states.get(entity_id) + assert state + assert state.state == STATE_ON + + entry = registry.async_get(entity_id) + assert entry + assert entry.unique_id == "uniqueid-205" + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: [entity_id]}, + blocking=True, + ) + assert aioclient_mock.mock_calls[-2][0] == "GET" + assert aioclient_mock.mock_calls[-2][1].path == "/setThings" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(thing_id) + assert data["id"] == thing_id + assert data["value"] == 0 + assert aioclient_mock.mock_calls[-1][0] == "GET" + assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData" + + await hass.services.async_call( + SWITCH_DOMAIN, + SERVICE_TURN_ON, + {ATTR_ENTITY_ID: [entity_id]}, + blocking=True, + ) + assert aioclient_mock.mock_calls[-2][0] == "GET" + assert aioclient_mock.mock_calls[-2][1].path == "/setThings" + data = loads(aioclient_mock.mock_calls[-2][1].query["json"]).get(thing_id) + assert data["id"] == thing_id + assert data["value"] == 100 + assert aioclient_mock.mock_calls[-1][0] == "GET" + assert aioclient_mock.mock_calls[-1][1].path == "/getSystemData"