From 65e8c06d46de7a537e04c2b1f33b4d7ebd6ff3b3 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 10 Sep 2020 22:01:05 +0200 Subject: [PATCH 01/18] Initial switch-group/stretch with failing wk_lisa_battery test --- .../components/plugwise/binary_sensor.py | 23 ++++------- homeassistant/components/plugwise/climate.py | 3 ++ .../components/plugwise/config_flow.py | 21 ++++++++-- homeassistant/components/plugwise/const.py | 3 +- homeassistant/components/plugwise/sensor.py | 20 ++++----- homeassistant/components/plugwise/switch.py | 31 +++++++++++--- tests/components/plugwise/conftest.py | 29 +++++++++++++ tests/components/plugwise/test_config_flow.py | 41 +++++++++++++++++++ tests/components/plugwise/test_sensor.py | 16 +++++++- .../plugwise/stretch_v31/get_all_devices.json | 1 + .../059e4d03c7a34d278add5c7a4a781d19.json | 1 + .../5871317346d045bc9f6b987ef25ee638.json | 1 + .../aac7b735042c4832ac9ff33aae4f453b.json | 1 + .../cfe95cf3de1948c0b8955125bf754614.json | 1 + .../d950b314e9d8499f968e6db8d82ef78c.json | 1 + .../e1c884e7dede431dadee09506ec4f859.json | 1 + 16 files changed, 155 insertions(+), 39 deletions(-) create mode 100644 tests/fixtures/plugwise/stretch_v31/get_all_devices.json create mode 100644 tests/fixtures/plugwise/stretch_v31/get_device_data/059e4d03c7a34d278add5c7a4a781d19.json create mode 100644 tests/fixtures/plugwise/stretch_v31/get_device_data/5871317346d045bc9f6b987ef25ee638.json create mode 100644 tests/fixtures/plugwise/stretch_v31/get_device_data/aac7b735042c4832ac9ff33aae4f453b.json create mode 100644 tests/fixtures/plugwise/stretch_v31/get_device_data/cfe95cf3de1948c0b8955125bf754614.json create mode 100644 tests/fixtures/plugwise/stretch_v31/get_device_data/d950b314e9d8499f968e6db8d82ef78c.json create mode 100644 tests/fixtures/plugwise/stretch_v31/get_device_data/e1c884e7dede431dadee09506ec4f859.json diff --git a/homeassistant/components/plugwise/binary_sensor.py b/homeassistant/components/plugwise/binary_sensor.py index 67dcc10a2896e..743f23dfb8d7d 100644 --- a/homeassistant/components/plugwise/binary_sensor.py +++ b/homeassistant/components/plugwise/binary_sensor.py @@ -33,10 +33,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): all_devices = api.get_all_devices() for dev_id, device_properties in all_devices.items(): - if device_properties["class"] != "heater_central": + if device_properties["class"] not in ["heater_central", "gateway"]: continue data = api.get_device_data(dev_id) + for binary_sensor, dummy in BINARY_SENSOR_MAP.items(): if binary_sensor not in data: continue @@ -46,8 +47,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): api, coordinator, device_properties["name"], - binary_sensor, dev_id, + binary_sensor, device_properties["class"], ) ) @@ -58,7 +59,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class PwBinarySensor(SmileSensor, BinarySensorEntity): """Representation of a Plugwise binary_sensor.""" - def __init__(self, api, coordinator, name, binary_sensor, dev_id, model): + def __init__(self, api, coordinator, name, dev_id, binary_sensor, model): """Set up the Plugwise API.""" super().__init__(api, coordinator, name, dev_id, binary_sensor) @@ -74,11 +75,6 @@ def is_on(self): """Return true if the binary sensor is on.""" return self._is_on - @property - def icon(self): - """Return the icon to use in the frontend.""" - return self._icon - @callback def _async_process_data(self): """Update the entity.""" @@ -96,15 +92,10 @@ def _async_process_data(self): self._is_on = data[self._binary_sensor] self._state = STATE_OFF + self._state = STATE_ON if self._is_on else STATE_OFF if self._binary_sensor == "dhw_state": - self._icon = FLOW_OFF_ICON + self._icon = FLOW_ON_ICON if self._is_on else FLOW_OFF_ICON if self._binary_sensor == "slave_boiler_state": - self._icon = IDLE_ICON - if self._is_on: - self._state = STATE_ON - if self._binary_sensor == "dhw_state": - self._icon = FLOW_ON_ICON - if self._binary_sensor == "slave_boiler_state": - self._icon = FLAME_ICON + self._icon = FLAME_ICON if self._is_on else IDLE_ICON self.async_write_ha_state() diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index 7981283f27d80..43e6bd1915804 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -65,6 +65,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities): DEFAULT_MAX_TEMP, ) + if not thermostat: + continue + entities.append(thermostat) async_add_entities(entities, True) diff --git a/homeassistant/components/plugwise/config_flow.py b/homeassistant/components/plugwise/config_flow.py index 364f58007c6a0..296e1bc7b93db 100644 --- a/homeassistant/components/plugwise/config_flow.py +++ b/homeassistant/components/plugwise/config_flow.py @@ -5,7 +5,14 @@ import voluptuous as vol from homeassistant import config_entries, core, exceptions -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL +from homeassistant.const import ( + CONF_HOST, + CONF_NAME, + CONF_PASSWORD, + CONF_PORT, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) from homeassistant.core import callback from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.typing import DiscoveryInfoType @@ -28,7 +35,14 @@ def _base_gw_schema(discovery_info): base_gw_schema[vol.Required(CONF_HOST)] = str base_gw_schema[vol.Optional(CONF_PORT, default=DEFAULT_PORT)] = int - base_gw_schema[vol.Required(CONF_PASSWORD)] = str + base_gw_schema.update( + { + vol.Required( + CONF_USERNAME, default="smile", description={"suggested_value": "smile"} + ): str, + vol.Required(CONF_PASSWORD): str, + } + ) return vol.Schema(base_gw_schema) @@ -45,6 +59,7 @@ async def validate_gw_input(hass: core.HomeAssistant, data): host=data[CONF_HOST], password=data[CONF_PASSWORD], port=data[CONF_PORT], + username=data[CONF_USERNAME], timeout=30, websession=websession, ) @@ -89,7 +104,7 @@ async def async_step_zeroconf(self, discovery_info: DiscoveryInfoType): self.context["title_placeholders"] = { CONF_HOST: discovery_info[CONF_HOST], CONF_PORT: discovery_info.get(CONF_PORT, DEFAULT_PORT), - "name": _name, + CONF_NAME: _name, } return await self.async_step_user() diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 056606307e52f..0354228365843 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -8,6 +8,7 @@ SENSOR_MAP_MODEL = 0 SENSOR_MAP_UOM = 1 SENSOR_MAP_DEVICE_CLASS = 2 +SENSOR_MAP_ICON = 3 # Default directives DEFAULT_NAME = "Smile" @@ -16,7 +17,7 @@ DEFAULT_PORT = 80 DEFAULT_MIN_TEMP = 4 DEFAULT_MAX_TEMP = 30 -DEFAULT_SCAN_INTERVAL = {"thermostat": 60, "power": 10} +DEFAULT_SCAN_INTERVAL = {"power": 10, "stretch": 60, "thermostat": 60} # Configuration directives CONF_MIN_TEMP = "min_temp" diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 483153c670962..f948926cdd7c8 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -242,6 +242,7 @@ def __init__(self, api, coordinator, name, dev_id, sensor): self._sensor = sensor self._dev_class = None + self._icon = None self._state = None self._unit_of_measurement = None @@ -261,6 +262,11 @@ def device_class(self): """Device class of this entity.""" return self._dev_class + @property + def icon(self): + """Return the icon of this entity.""" + return self._icon + @property def state(self): """Device class of this entity.""" @@ -273,7 +279,7 @@ def unit_of_measurement(self): class PwThermostatSensor(SmileSensor, Entity): - """Thermostat and climate sensor entities.""" + """Thermostat or generic sensor entities.""" def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): """Set up the Plugwise API.""" @@ -296,8 +302,6 @@ def _async_process_data(self): if data.get(self._sensor) is not None: measurement = data[self._sensor] - if self._sensor == "battery" or self._sensor == "valve_position": - measurement = measurement * 100 if self._unit_of_measurement == PERCENTAGE: measurement = int(measurement) self._state = measurement @@ -307,7 +311,7 @@ def _async_process_data(self): class PwAuxDeviceSensor(SmileSensor, Entity): - """Auxiliary sensor entities for the heating/cooling device.""" + """Auxiliary Device Sensors.""" def __init__(self, api, coordinator, name, dev_id, sensor): """Set up the Plugwise API.""" @@ -315,12 +319,6 @@ def __init__(self, api, coordinator, name, dev_id, sensor): self._cooling_state = False self._heating_state = False - self._icon = None - - @property - def icon(self): - """Return the icon to use in the frontend.""" - return self._icon @callback def _async_process_data(self): @@ -380,7 +378,7 @@ def _async_process_data(self): if data.get(self._sensor) is not None: measurement = data[self._sensor] if self._unit_of_measurement == ENERGY_KILO_WATT_HOUR: - measurement = int(measurement / 1000) + measurement = round((measurement / 1000), 1) self._state = measurement self._icon = CUSTOM_ICONS.get(self._sensor, self._icon) diff --git a/homeassistant/components/plugwise/switch.py b/homeassistant/components/plugwise/switch.py index d7b45f4999afa..8dffc86eed272 100644 --- a/homeassistant/components/plugwise/switch.py +++ b/homeassistant/components/plugwise/switch.py @@ -19,12 +19,24 @@ async def async_setup_entry(hass, config_entry, async_add_entities): coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR] entities = [] + switch_classes = ["plug", "switch_group"] + all_devices = api.get_all_devices() for dev_id, device_properties in all_devices.items(): - if "plug" in device_properties["types"]: - model = "Metered Switch" + members = None + model = None + + if any(dummy in device_properties["types"] for dummy in switch_classes): + if "plug" in device_properties["types"]: + model = "Metered Switch" + if "switch_group" in device_properties["types"]: + members = device_properties["members"] + model = "Switch Group" + entities.append( - PwSwitch(api, coordinator, device_properties["name"], dev_id, model) + PwSwitch( + api, coordinator, device_properties["name"], dev_id, members, model + ) ) async_add_entities(entities, True) @@ -33,10 +45,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities): class PwSwitch(SmileGateway, SwitchEntity): """Representation of a Plugwise plug.""" - def __init__(self, api, coordinator, name, dev_id, model): + def __init__(self, api, coordinator, name, dev_id, members, model): """Set up the Plugwise API.""" super().__init__(api, coordinator, name, dev_id) + self._members = members self._model = model self._is_on = False @@ -51,7 +64,10 @@ def is_on(self): async def async_turn_on(self, **kwargs): """Turn the device on.""" try: - if await self._api.set_relay_state(self._dev_id, "on"): + state_on = await self._api.set_relay_state( + self._dev_id, self._members, "on" + ) + if state_on: self._is_on = True self.async_write_ha_state() except Smile.PlugwiseError: @@ -60,7 +76,10 @@ async def async_turn_on(self, **kwargs): async def async_turn_off(self, **kwargs): """Turn the device off.""" try: - if await self._api.set_relay_state(self._dev_id, "off"): + state_off = await self._api.set_relay_state( + self._dev_id, self._members, "off" + ) + if state_off: self._is_on = False self.async_write_ha_state() except Smile.PlugwiseError: diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 5af2bf2ccd324..c758c5d4c6885 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -178,3 +178,32 @@ def mock_smile_p1(): ) yield smile_mock.return_value + + +@pytest.fixture(name="mock_stretch") +def mock_stretch(): + """Create a Mock Stretch environment for testing exceptions.""" + chosen_env = "stretch_v31" + with patch("homeassistant.components.plugwise.Smile") as smile_mock: + smile_mock.InvalidAuthentication = Smile.InvalidAuthentication + smile_mock.ConnectionFailedError = Smile.ConnectionFailedError + smile_mock.XMLDataMissingError = Smile.XMLDataMissingError + + smile_mock.return_value.gateway_id = "259882df3c05415b99c2d962534ce820" + smile_mock.return_value.heater_id = None + smile_mock.return_value.smile_version = "3.1.11" + smile_mock.return_value.smile_type = "stretch" + + smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True) + smile_mock.return_value.full_update_device.side_effect = AsyncMock( + return_value=True + ) + + smile_mock.return_value.get_all_devices.return_value = _read_json( + chosen_env, "get_all_devices" + ) + smile_mock.return_value.get_device_data.side_effect = partial( + _get_device_data, chosen_env + ) + + yield smile_mock.return_value diff --git a/tests/components/plugwise/test_config_flow.py b/tests/components/plugwise/test_config_flow.py index 9b67f06e46900..e850cc68b14d0 100644 --- a/tests/components/plugwise/test_config_flow.py +++ b/tests/components/plugwise/test_config_flow.py @@ -18,6 +18,8 @@ TEST_HOSTNAME = "smileabcdef" TEST_PASSWORD = "test_password" TEST_PORT = 81 +TEST_USERNAME = "smile" +TEST_USERNAME2 = "stretch" TEST_DISCOVERY = { "host": TEST_HOST, @@ -76,6 +78,7 @@ async def test_form(hass): "host": TEST_HOST, "password": TEST_PASSWORD, "port": DEFAULT_PORT, + "username": TEST_USERNAME, } assert len(mock_setup.mock_calls) == 1 @@ -115,6 +118,44 @@ async def test_zeroconf_form(hass): "host": TEST_HOST, "password": TEST_PASSWORD, "port": DEFAULT_PORT, + "username": TEST_USERNAME, + } + + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_form_username(hass): + """Test we get the username data back.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["errors"] == {} + + with patch( + "homeassistant.components.plugwise.config_flow.Smile.connect", + return_value=True, + ), patch( + "homeassistant.components.plugwise.async_setup", + return_value=True, + ) as mock_setup, patch( + "homeassistant.components.plugwise.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + {"host": TEST_HOST, "password": TEST_PASSWORD, "username": TEST_USERNAME2}, + ) + + await hass.async_block_till_done() + + assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result2["data"] == { + "host": TEST_HOST, + "password": TEST_PASSWORD, + "port": DEFAULT_PORT, + "username": TEST_USERNAME2, } assert len(mock_setup.mock_calls) == 1 diff --git a/tests/components/plugwise/test_sensor.py b/tests/components/plugwise/test_sensor.py index bc586120517ad..3d77790b09b09 100644 --- a/tests/components/plugwise/test_sensor.py +++ b/tests/components/plugwise/test_sensor.py @@ -54,13 +54,25 @@ async def test_p1_dsmr_sensor_entities(hass, mock_smile_p1): assert float(state.state) == -2761.0 state = hass.states.get("sensor.p1_electricity_consumed_off_peak_cumulative") - assert int(state.state) == 551 + assert float(state.state) == 551.1 state = hass.states.get("sensor.p1_electricity_produced_peak_point") assert float(state.state) == 2761.0 state = hass.states.get("sensor.p1_electricity_consumed_peak_cumulative") - assert int(state.state) == 442 + assert float(state.state) == 442.9 state = hass.states.get("sensor.p1_gas_consumed_cumulative") assert float(state.state) == 584.9 + + +async def test_stretch_sensor_entities(hass, mock_stretch): + """Test creation of power related sensor entities.""" + entry = await async_init_integration(hass, mock_stretch) + assert entry.state == ENTRY_STATE_LOADED + + state = hass.states.get("sensor.koelkast_92c4a_electricity_consumed") + assert float(state.state) == 53.2 + + state = hass.states.get("sensor.droger_52559_electricity_consumed_interval") + assert float(state.state) == 1.06 diff --git a/tests/fixtures/plugwise/stretch_v31/get_all_devices.json b/tests/fixtures/plugwise/stretch_v31/get_all_devices.json new file mode 100644 index 0000000000000..f40e902d5a994 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_all_devices.json @@ -0,0 +1 @@ +{"cfe95cf3de1948c0b8955125bf754614": {"name": "Droger (52559)", "types": {"py/set": ["plug", "power"]}, "class": "dryer", "location": 0}, "aac7b735042c4832ac9ff33aae4f453b": {"name": "Vaatwasser (2a1ab)", "types": {"py/set": ["plug", "power"]}, "class": "dishwasher", "location": 0}, "5871317346d045bc9f6b987ef25ee638": {"name": "Boiler (1EB31)", "types": {"py/set": ["plug", "power"]}, "class": "water_heater_vessel", "location": 0}, "059e4d03c7a34d278add5c7a4a781d19": {"name": "Wasmachine (52AC1)", "types": {"py/set": ["plug", "power"]}, "class": "washingmachine", "location": 0}, "e1c884e7dede431dadee09506ec4f859": {"name": "Koelkast (92C4A)", "types": {"py/set": ["plug", "power"]}, "class": "refrigerator", "location": 0}, "d950b314e9d8499f968e6db8d82ef78c": {"name": "Stroomvreters", "types": {"py/set": ["switch_group"]}, "class": "switching", "members": [], "location": null}} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/059e4d03c7a34d278add5c7a4a781d19.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/059e4d03c7a34d278add5c7a4a781d19.json new file mode 100644 index 0000000000000..b08f6d6093adf --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/059e4d03c7a34d278add5c7a4a781d19.json @@ -0,0 +1 @@ +{"electricity_consumed": 0.0, "electricity_consumed_interval": 0.0, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/5871317346d045bc9f6b987ef25ee638.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/5871317346d045bc9f6b987ef25ee638.json new file mode 100644 index 0000000000000..529c8b76d95e9 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/5871317346d045bc9f6b987ef25ee638.json @@ -0,0 +1 @@ +{"electricity_consumed": 1.19, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/aac7b735042c4832ac9ff33aae4f453b.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/aac7b735042c4832ac9ff33aae4f453b.json new file mode 100644 index 0000000000000..35ce04f51cfc6 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/aac7b735042c4832ac9ff33aae4f453b.json @@ -0,0 +1 @@ +{"electricity_consumed": 0.0, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/cfe95cf3de1948c0b8955125bf754614.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/cfe95cf3de1948c0b8955125bf754614.json new file mode 100644 index 0000000000000..42de4d3338b35 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/cfe95cf3de1948c0b8955125bf754614.json @@ -0,0 +1 @@ +{"electricity_consumed": 0.0, "electricity_consumed_interval": 1.06, "electricity_produced": 0.0, "relay": true} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/d950b314e9d8499f968e6db8d82ef78c.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/d950b314e9d8499f968e6db8d82ef78c.json new file mode 100644 index 0000000000000..de5baf4c9a604 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/d950b314e9d8499f968e6db8d82ef78c.json @@ -0,0 +1 @@ +{"relay": false} \ No newline at end of file diff --git a/tests/fixtures/plugwise/stretch_v31/get_device_data/e1c884e7dede431dadee09506ec4f859.json b/tests/fixtures/plugwise/stretch_v31/get_device_data/e1c884e7dede431dadee09506ec4f859.json new file mode 100644 index 0000000000000..1a7249b68d509 --- /dev/null +++ b/tests/fixtures/plugwise/stretch_v31/get_device_data/e1c884e7dede431dadee09506ec4f859.json @@ -0,0 +1 @@ +{"electricity_consumed": 53.2, "electricity_produced": 0.0, "relay": true} \ No newline at end of file From 17fe12538939d984a37bd068286a466eaa4e6043 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 10 Sep 2020 22:09:15 +0200 Subject: [PATCH 02/18] Adding switch tests, but TypeErrors, needs more investigation --- tests/components/plugwise/test_switch.py | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/components/plugwise/test_switch.py b/tests/components/plugwise/test_switch.py index a58ebf83caadd..26303ac1a1ea1 100644 --- a/tests/components/plugwise/test_switch.py +++ b/tests/components/plugwise/test_switch.py @@ -48,3 +48,37 @@ async def test_adam_climate_switch_changes(hass, mock_smile_adam): ) state = hass.states.get("switch.fibaro_hc2") assert str(state.state) == "on" + + +async def test_stretch_switch_changes(hass, mock_stretch): + """Test changing of power related switch entities.""" + entry = await async_init_integration(hass, mock_stretch) + assert entry.state == ENTRY_STATE_LOADED + + await hass.services.async_call( + "switch", + "turn_off", + {"entity_id": "switch.koelkast_92c4a"}, + blocking=True, + ) + + state = hass.states.get("switch.koelkast_92c4a") + assert str(state.state) == "off" + + await hass.services.async_call( + "switch", + "toggle", + {"entity_id": "switch.droger_52559"}, + blocking=True, + ) + state = hass.states.get("switch.droger_52559") + assert str(state.state) == "on" + + await hass.services.async_call( + "switch", + "toggle", + {"entity_id": "switch.droger_52559"}, + blocking=True, + ) + state = hass.states.get("switch.droger_52559") + assert str(state.state) == "off" From f4c638e8493f88594452f51a3ea24c39f8d1e4f5 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sat, 12 Sep 2020 16:34:48 +0200 Subject: [PATCH 03/18] Fixes and tests aligned --- homeassistant/components/plugwise/sensor.py | 2 +- tests/components/plugwise/conftest.py | 3 +++ tests/components/plugwise/test_sensor.py | 2 +- tests/components/plugwise/test_switch.py | 16 ++++++++++++++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index f948926cdd7c8..d49268d229305 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -303,7 +303,7 @@ def _async_process_data(self): if data.get(self._sensor) is not None: measurement = data[self._sensor] if self._unit_of_measurement == PERCENTAGE: - measurement = int(measurement) + measurement = int(measurement * 100) self._state = measurement self._icon = CUSTOM_ICONS.get(self._sensor, self._icon) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index c758c5d4c6885..5036f2617cdd8 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -198,6 +198,9 @@ def mock_stretch(): smile_mock.return_value.full_update_device.side_effect = AsyncMock( return_value=True ) + smile_mock.return_value.set_relay_state.side_effect = AsyncMock( + return_value=True + ) smile_mock.return_value.get_all_devices.return_value = _read_json( chosen_env, "get_all_devices" diff --git a/tests/components/plugwise/test_sensor.py b/tests/components/plugwise/test_sensor.py index 3d77790b09b09..a727337d747d1 100644 --- a/tests/components/plugwise/test_sensor.py +++ b/tests/components/plugwise/test_sensor.py @@ -27,7 +27,7 @@ async def test_adam_climate_sensor_entities(hass, mock_smile_adam): ) state = hass.states.get("sensor.zone_lisa_wk_battery") - assert float(state.state) == 34 + assert int(state.state) == 34 async def test_anna_climate_sensor_entities(hass, mock_smile_anna): diff --git a/tests/components/plugwise/test_switch.py b/tests/components/plugwise/test_switch.py index 26303ac1a1ea1..ded21113f2b5c 100644 --- a/tests/components/plugwise/test_switch.py +++ b/tests/components/plugwise/test_switch.py @@ -50,6 +50,18 @@ async def test_adam_climate_switch_changes(hass, mock_smile_adam): assert str(state.state) == "on" +async def test_stretch_switch_entities(hass, mock_stretch): + """Test creation of climate related switch entities.""" + entry = await async_init_integration(hass, mock_stretch) + assert entry.state == ENTRY_STATE_LOADED + + state = hass.states.get("switch.koelkast_92c4a") + assert str(state.state) == "on" + + state = hass.states.get("switch.droger_52559") + assert str(state.state) == "on" + + async def test_stretch_switch_changes(hass, mock_stretch): """Test changing of power related switch entities.""" entry = await async_init_integration(hass, mock_stretch) @@ -72,7 +84,7 @@ async def test_stretch_switch_changes(hass, mock_stretch): blocking=True, ) state = hass.states.get("switch.droger_52559") - assert str(state.state) == "on" + assert str(state.state) == "off" await hass.services.async_call( "switch", @@ -81,4 +93,4 @@ async def test_stretch_switch_changes(hass, mock_stretch): blocking=True, ) state = hass.states.get("switch.droger_52559") - assert str(state.state) == "off" + assert str(state.state) == "on" From 91bce6258b125c9ff7a1e308f3e1ee58aecd44fa Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 14 Sep 2020 10:51:40 +0200 Subject: [PATCH 04/18] Review updates --- homeassistant/components/plugwise/__init__.py | 1 - .../components/plugwise/binary_sensor.py | 1 - .../components/plugwise/config_flow.py | 7 ++-- homeassistant/components/plugwise/const.py | 32 +++++++++++-------- .../components/plugwise/strings.json | 5 +-- homeassistant/components/plugwise/switch.py | 8 ++++- 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index ee6c44bc5587a..988bf9113be7c 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -25,7 +25,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # PLACEHOLDER USB entry setup return False - async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unload a config entry.""" unload_ok = all( diff --git a/homeassistant/components/plugwise/binary_sensor.py b/homeassistant/components/plugwise/binary_sensor.py index 743f23dfb8d7d..2e02cd4b5ed94 100644 --- a/homeassistant/components/plugwise/binary_sensor.py +++ b/homeassistant/components/plugwise/binary_sensor.py @@ -91,7 +91,6 @@ def _async_process_data(self): self._is_on = data[self._binary_sensor] - self._state = STATE_OFF self._state = STATE_ON if self._is_on else STATE_OFF if self._binary_sensor == "dhw_state": self._icon = FLOW_ON_ICON if self._is_on else FLOW_OFF_ICON diff --git a/homeassistant/components/plugwise/config_flow.py b/homeassistant/components/plugwise/config_flow.py index 296e1bc7b93db..e3c68e401c7db 100644 --- a/homeassistant/components/plugwise/config_flow.py +++ b/homeassistant/components/plugwise/config_flow.py @@ -6,6 +6,7 @@ from homeassistant import config_entries, core, exceptions from homeassistant.const import ( + CONF_BASE, CONF_HOST, CONF_NAME, CONF_PASSWORD, @@ -126,12 +127,12 @@ async def async_step_user_gateway(self, user_input=None): api = await validate_gw_input(self.hass, user_input) except CannotConnect: - errors["base"] = "cannot_connect" + errors[CONF_BASE] = "cannot_connect" except InvalidAuth: - errors["base"] = "invalid_auth" + errors[CONF_BASE] = "invalid_auth" except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected exception") - errors["base"] = "unknown" + errors[CONF_BASE] = "unknown" if not errors: await self.async_set_unique_id( api.smile_hostname or api.gateway_id, raise_on_progress=False diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 0354228365843..121736a22b8ae 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -1,54 +1,58 @@ """Constant for Plugwise component.""" DOMAIN = "plugwise" -SENSOR_PLATFORMS = ["sensor"] +SENSOR_PLATFORMS = ["sensor", "switch"] ALL_PLATFORMS = ["binary_sensor", "climate", "sensor", "switch"] # Sensor mapping -SENSOR_MAP_MODEL = 0 -SENSOR_MAP_UOM = 1 SENSOR_MAP_DEVICE_CLASS = 2 SENSOR_MAP_ICON = 3 +SENSOR_MAP_MODEL = 0 +SENSOR_MAP_UOM = 1 # Default directives -DEFAULT_NAME = "Smile" -DEFAULT_USERNAME = "smile" -DEFAULT_TIMEOUT = 10 -DEFAULT_PORT = 80 DEFAULT_MIN_TEMP = 4 DEFAULT_MAX_TEMP = 30 +DEFAULT_NAME = "Smile" +DEFAULT_PORT = 80 +DEFAULT_USERNAME = "smile" DEFAULT_SCAN_INTERVAL = {"power": 10, "stretch": 60, "thermostat": 60} +DEFAULT_TIMEOUT = 10 # Configuration directives -CONF_MIN_TEMP = "min_temp" +CONF_BASE = "base" +CONF_GAS = "gas" +CONF_HEATER = "heater" CONF_MAX_TEMP = "max_temp" -CONF_THERMOSTAT = "thermostat" +CONF_MIN_TEMP = "min_temp" CONF_POWER = "power" -CONF_HEATER = "heater" CONF_SOLAR = "solar" -CONF_GAS = "gas" +CONF_THERMOSTAT = "thermostat" ATTR_ILLUMINANCE = "illuminance" + UNIT_LUMEN = "lm" CURRENT_HVAC_DHW = "hot_water" DEVICE_STATE = "device_state" -SCHEDULE_ON = "true" SCHEDULE_OFF = "false" +SCHEDULE_ON = "true" COOL_ICON = "mdi:snowflake" FLAME_ICON = "mdi:fire" -IDLE_ICON = "mdi:circle-off-outline" FLOW_OFF_ICON = "mdi:water-pump-off" FLOW_ON_ICON = "mdi:water-pump" +IDLE_ICON = "mdi:circle-off-outline" +SWITCH_ICON = "mdi:electric-switch" -UNDO_UPDATE_LISTENER = "undo_update_listener" COORDINATOR = "coordinator" ZEROCONF_MAP = { "smile": "P1", "smile_thermo": "Anna", "smile_open_therm": "Adam", + "stretch": "Stretch", } +UNDO_UPDATE_LISTENER = "undo_update_listener" diff --git a/homeassistant/components/plugwise/strings.json b/homeassistant/components/plugwise/strings.json index 4e6ea18017bd9..2ed6721bab36d 100644 --- a/homeassistant/components/plugwise/strings.json +++ b/homeassistant/components/plugwise/strings.json @@ -20,11 +20,12 @@ }, "user_gateway": { "title": "Connect to the Smile", - "description": "Please enter:", + "description": "Please enter", "data": { "password": "Smile ID", "host": "[%key:common::config_flow::data::ip%]", - "port": "[%key:common::config_flow::data::port%]" + "port": "[%key:common::config_flow::data::port%]", + "username" : "Smile Username" } } }, diff --git a/homeassistant/components/plugwise/switch.py b/homeassistant/components/plugwise/switch.py index 8dffc86eed272..6aea776d45f4d 100644 --- a/homeassistant/components/plugwise/switch.py +++ b/homeassistant/components/plugwise/switch.py @@ -7,7 +7,7 @@ from homeassistant.components.switch import SwitchEntity from homeassistant.core import callback -from .const import COORDINATOR, DOMAIN +from .const import COORDINATOR, DOMAIN, SWITCH_ICON from .gateway import SmileGateway _LOGGER = logging.getLogger(__name__) @@ -53,6 +53,7 @@ def __init__(self, api, coordinator, name, dev_id, members, model): self._model = model self._is_on = False + self._icon = SWITCH_ICON self._unique_id = f"{dev_id}-plug" @@ -61,6 +62,11 @@ def is_on(self): """Return true if device is on.""" return self._is_on + @property + def icon(self): + """Return the icon of this entity.""" + return self._icon + async def async_turn_on(self, **kwargs): """Turn the device on.""" try: From 925722c17b0365140ac8c1df6f728a5e22792304 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 14 Sep 2020 11:56:56 +0200 Subject: [PATCH 05/18] Use const --- homeassistant/components/plugwise/__init__.py | 1 + homeassistant/components/plugwise/const.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/__init__.py b/homeassistant/components/plugwise/__init__.py index 988bf9113be7c..ee6c44bc5587a 100644 --- a/homeassistant/components/plugwise/__init__.py +++ b/homeassistant/components/plugwise/__init__.py @@ -25,6 +25,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # PLACEHOLDER USB entry setup return False + async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): """Unload a config entry.""" unload_ok = all( diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 121736a22b8ae..4e0dad9d4a8f6 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -17,7 +17,7 @@ DEFAULT_PORT = 80 DEFAULT_USERNAME = "smile" DEFAULT_SCAN_INTERVAL = {"power": 10, "stretch": 60, "thermostat": 60} -DEFAULT_TIMEOUT = 10 +DEFAULT_TIMEOUT = 60 # Configuration directives CONF_BASE = "base" From 156994381815e8069722548eda59311ea0c678c3 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 14 Sep 2020 12:13:12 +0200 Subject: [PATCH 06/18] Comments --- homeassistant/components/plugwise/sensor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index d49268d229305..3b0cbbd87f79d 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -269,7 +269,7 @@ def icon(self): @property def state(self): - """Device class of this entity.""" + """Return the state of this entity.""" return self._state @property @@ -279,7 +279,7 @@ def unit_of_measurement(self): class PwThermostatSensor(SmileSensor, Entity): - """Thermostat or generic sensor entities.""" + """Auxiliary Device sensors.""" def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): """Set up the Plugwise API.""" From bf8fcaa73d6503e0857590bc5082a8d220b66b76 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 14 Sep 2020 12:28:06 +0200 Subject: [PATCH 07/18] Add stretch hostname for testing part --- tests/components/plugwise/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 5036f2617cdd8..44953c9635b2e 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -193,6 +193,7 @@ def mock_stretch(): smile_mock.return_value.heater_id = None smile_mock.return_value.smile_version = "3.1.11" smile_mock.return_value.smile_type = "stretch" + smile_mock.return_value.smile_hostname = "stretch98765" smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True) smile_mock.return_value.full_update_device.side_effect = AsyncMock( From 383472bbab8dec1871cd890cd679cdd9d8347b1f Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 14 Sep 2020 14:12:15 +0200 Subject: [PATCH 08/18] Remove unused consts --- homeassistant/components/plugwise/const.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 4e0dad9d4a8f6..428cf616344df 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -22,19 +22,15 @@ # Configuration directives CONF_BASE = "base" CONF_GAS = "gas" -CONF_HEATER = "heater" CONF_MAX_TEMP = "max_temp" CONF_MIN_TEMP = "min_temp" CONF_POWER = "power" -CONF_SOLAR = "solar" CONF_THERMOSTAT = "thermostat" ATTR_ILLUMINANCE = "illuminance" UNIT_LUMEN = "lm" -CURRENT_HVAC_DHW = "hot_water" - DEVICE_STATE = "device_state" SCHEDULE_OFF = "false" From dda777b2cfc0e81406d2ca28b2b4d466d78f0ba5 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sun, 27 Sep 2020 17:40:37 +0200 Subject: [PATCH 09/18] Revert guardings in line with -beta --- .../components/plugwise/binary_sensor.py | 34 +++++++++---------- homeassistant/components/plugwise/climate.py | 3 -- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/plugwise/binary_sensor.py b/homeassistant/components/plugwise/binary_sensor.py index 2e02cd4b5ed94..1ec8ae1e3cea9 100644 --- a/homeassistant/components/plugwise/binary_sensor.py +++ b/homeassistant/components/plugwise/binary_sensor.py @@ -33,25 +33,23 @@ async def async_setup_entry(hass, config_entry, async_add_entities): all_devices = api.get_all_devices() for dev_id, device_properties in all_devices.items(): - if device_properties["class"] not in ["heater_central", "gateway"]: - continue - - data = api.get_device_data(dev_id) - - for binary_sensor, dummy in BINARY_SENSOR_MAP.items(): - if binary_sensor not in data: - continue - - entities.append( - PwBinarySensor( - api, - coordinator, - device_properties["name"], - dev_id, - binary_sensor, - device_properties["class"], + if device_properties["class"] == "heater_central": + data = api.get_device_data(dev_id) + + for binary_sensor, dummy in BINARY_SENSOR_MAP.items(): + if binary_sensor not in data: + continue + + entities.append( + PwBinarySensor( + api, + coordinator, + device_properties["name"], + dev_id, + binary_sensor, + device_properties["class"], + ) ) - ) async_add_entities(entities, True) diff --git a/homeassistant/components/plugwise/climate.py b/homeassistant/components/plugwise/climate.py index 43e6bd1915804..7981283f27d80 100644 --- a/homeassistant/components/plugwise/climate.py +++ b/homeassistant/components/plugwise/climate.py @@ -65,9 +65,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities): DEFAULT_MAX_TEMP, ) - if not thermostat: - continue - entities.append(thermostat) async_add_entities(entities, True) From 6c16da15a6ed7a495430c8fa5c515039577a080f Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 8 Oct 2020 08:33:53 +0200 Subject: [PATCH 10/18] Catchup with dev (mostly with ourselves from #41201) --- homeassistant/components/plugwise/config_flow.py | 2 +- homeassistant/components/plugwise/const.py | 3 +-- homeassistant/components/plugwise/gateway.py | 11 ++++++----- tests/components/plugwise/conftest.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/plugwise/config_flow.py b/homeassistant/components/plugwise/config_flow.py index e3c68e401c7db..6fd7cde44bcbd 100644 --- a/homeassistant/components/plugwise/config_flow.py +++ b/homeassistant/components/plugwise/config_flow.py @@ -50,7 +50,7 @@ def _base_gw_schema(discovery_info): async def validate_gw_input(hass: core.HomeAssistant, data): """ - Validate the user input allows us to connect to the gateray. + Validate whether the user input allows us to connect to the gateray. Data has the keys from _base_gw_schema() with values provided by the user. """ diff --git a/homeassistant/components/plugwise/const.py b/homeassistant/components/plugwise/const.py index 428cf616344df..5c0cf2b097ada 100644 --- a/homeassistant/components/plugwise/const.py +++ b/homeassistant/components/plugwise/const.py @@ -44,11 +44,10 @@ SWITCH_ICON = "mdi:electric-switch" COORDINATOR = "coordinator" - +UNDO_UPDATE_LISTENER = "undo_update_listener" ZEROCONF_MAP = { "smile": "P1", "smile_thermo": "Anna", "smile_open_therm": "Adam", "stretch": "Stretch", } -UNDO_UPDATE_LISTENER = "undo_update_listener" diff --git a/homeassistant/components/plugwise/gateway.py b/homeassistant/components/plugwise/gateway.py index 610fff18e4bac..181af02c3453b 100644 --- a/homeassistant/components/plugwise/gateway.py +++ b/homeassistant/components/plugwise/gateway.py @@ -26,6 +26,7 @@ COORDINATOR, DEFAULT_PORT, DEFAULT_SCAN_INTERVAL, + DEFAULT_TIMEOUT, DOMAIN, SENSOR_PLATFORMS, UNDO_UPDATE_LISTENER, @@ -56,15 +57,15 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: raise ConfigEntryNotReady except Smile.InvalidAuthentication: - _LOGGER.error("Invalid Smile ID") + _LOGGER.error("Invalid username or Smile ID") return False except Smile.PlugwiseError as err: - _LOGGER.error("Error while communicating to device") + _LOGGER.error("Error while communicating to device %s", api.smile_name) raise ConfigEntryNotReady from err except asyncio.TimeoutError as err: - _LOGGER.error("Timeout while connecting to Smile") + _LOGGER.error("Timeout while connecting to Smile %s", api.smile_name) raise ConfigEntryNotReady from err update_interval = timedelta( @@ -76,7 +77,7 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_update_data(): """Update data via API endpoint.""" try: - async with async_timeout.timeout(10): + async with async_timeout.timeout(DEFAULT_TIMEOUT): await api.full_update_device() return True except Smile.XMLDataMissingError as err: @@ -85,7 +86,7 @@ async def async_update_data(): coordinator = DataUpdateCoordinator( hass, _LOGGER, - name="Smile", + name=f"Smile {api.smile_name}", update_method=async_update_data, update_interval=update_interval, ) diff --git a/tests/components/plugwise/conftest.py b/tests/components/plugwise/conftest.py index 44953c9635b2e..0f0e4551b1c83 100644 --- a/tests/components/plugwise/conftest.py +++ b/tests/components/plugwise/conftest.py @@ -184,7 +184,7 @@ def mock_smile_p1(): def mock_stretch(): """Create a Mock Stretch environment for testing exceptions.""" chosen_env = "stretch_v31" - with patch("homeassistant.components.plugwise.Smile") as smile_mock: + with patch("homeassistant.components.plugwise.gateway.Smile") as smile_mock: smile_mock.InvalidAuthentication = Smile.InvalidAuthentication smile_mock.ConnectionFailedError = Smile.ConnectionFailedError smile_mock.XMLDataMissingError = Smile.XMLDataMissingError From 217eb2febfbfcc1d612cc3b17b1f7788f63670e7 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 8 Oct 2020 09:17:18 +0200 Subject: [PATCH 11/18] Update docstring --- homeassistant/components/plugwise/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 3b0cbbd87f79d..52730d1156c59 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -279,7 +279,7 @@ def unit_of_measurement(self): class PwThermostatSensor(SmileSensor, Entity): - """Auxiliary Device sensors.""" + """Thermostat (or generic) sensor devices.""" def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type): """Set up the Plugwise API.""" From 31c588f52170c0a3697111544a88c5ce27693597 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Thu, 8 Oct 2020 09:57:16 +0200 Subject: [PATCH 12/18] Remove debug logging --- homeassistant/components/plugwise/switch.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/homeassistant/components/plugwise/switch.py b/homeassistant/components/plugwise/switch.py index 6aea776d45f4d..f7b622c5473bf 100644 --- a/homeassistant/components/plugwise/switch.py +++ b/homeassistant/components/plugwise/switch.py @@ -94,8 +94,6 @@ async def async_turn_off(self, **kwargs): @callback def _async_process_data(self): """Update the data from the Plugs.""" - _LOGGER.debug("Update switch called") - data = self._api.get_device_data(self._dev_id) if not data: From d7f12b0a180839e1e377c818795afb9f26051b08 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 2 Nov 2020 14:46:27 +0100 Subject: [PATCH 13/18] Fix for #42725 (incorrect entity namingi) --- homeassistant/components/plugwise/sensor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index 52730d1156c59..b1b4081636409 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -116,22 +116,22 @@ DEVICE_CLASS_POWER, ], "electricity_produced_off_peak_point": [ - "Current Consumed Power (off peak)", + "Current Produced Power (off peak)", POWER_WATT, DEVICE_CLASS_POWER, ], "electricity_produced_peak_point": [ - "Current Consumed Power", + "Current Produced Power", POWER_WATT, DEVICE_CLASS_POWER, ], "electricity_produced_off_peak_cumulative": [ - "Cumulative Consumed Power (off peak)", + "Cumulative Produced Power (off peak)", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, ], "electricity_produced_peak_cumulative": [ - "Cumulative Consumed Power", + "Cumulative Produced Power", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, ], From 428f0397b2dff942eb65e4a07dc4819256656ca2 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Mon, 2 Nov 2020 14:49:02 +0100 Subject: [PATCH 14/18] Fix naming for gas interval --- homeassistant/components/plugwise/sensor.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/sensor.py b/homeassistant/components/plugwise/sensor.py index b1b4081636409..578f1bc7f7e48 100644 --- a/homeassistant/components/plugwise/sensor.py +++ b/homeassistant/components/plugwise/sensor.py @@ -135,7 +135,11 @@ ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_POWER, ], - "gas_consumed_interval": ["Current Consumed Gas", VOLUME_CUBIC_METERS, None], + "gas_consumed_interval": [ + "Current Consumed Gas Interval", + VOLUME_CUBIC_METERS, + None, + ], "gas_consumed_cumulative": ["Cumulative Consumed Gas", VOLUME_CUBIC_METERS, None], "net_electricity_point": ["Current net Power", POWER_WATT, DEVICE_CLASS_POWER], "net_electricity_cumulative": [ From d93557714ff00525f4120f5d79e6f15336b69c5d Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Sun, 8 Nov 2020 11:05:34 +0100 Subject: [PATCH 15/18] Add missing CONF_USERNAME and use of it --- homeassistant/components/plugwise/gateway.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/gateway.py b/homeassistant/components/plugwise/gateway.py index 181af02c3453b..21dfdf8947aa0 100644 --- a/homeassistant/components/plugwise/gateway.py +++ b/homeassistant/components/plugwise/gateway.py @@ -10,7 +10,13 @@ import voluptuous as vol from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, CONF_SCAN_INTERVAL +from homeassistant.const import ( + CONF_HOST, + CONF_PASSWORD, + CONF_PORT, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import device_registry as dr @@ -43,6 +49,7 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: api = Smile( host=entry.data[CONF_HOST], + username=entry.data[CONF_USERNAME], password=entry.data[CONF_PASSWORD], port=entry.data.get(CONF_PORT, DEFAULT_PORT), timeout=30, From 2f5e6dff304ab6a98482d4e88c20e7a6b4eda2c3 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Sun, 8 Nov 2020 11:12:05 +0100 Subject: [PATCH 16/18] Change "dummy" to "class" --- homeassistant/components/plugwise/switch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/switch.py b/homeassistant/components/plugwise/switch.py index f7b622c5473bf..6a0136446a1ba 100644 --- a/homeassistant/components/plugwise/switch.py +++ b/homeassistant/components/plugwise/switch.py @@ -26,7 +26,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): members = None model = None - if any(dummy in device_properties["types"] for dummy in switch_classes): + if any(class in device_properties["types"] for class in switch_classes): if "plug" in device_properties["types"]: model = "Metered Switch" if "switch_group" in device_properties["types"]: From 985de320d2529dbb2c8b2e27919d6810b5c118a4 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Sun, 8 Nov 2020 11:18:23 +0100 Subject: [PATCH 17/18] Don't use "class" --- homeassistant/components/plugwise/switch.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/plugwise/switch.py b/homeassistant/components/plugwise/switch.py index 6a0136446a1ba..8221bc2cb579d 100644 --- a/homeassistant/components/plugwise/switch.py +++ b/homeassistant/components/plugwise/switch.py @@ -26,7 +26,10 @@ async def async_setup_entry(hass, config_entry, async_add_entities): members = None model = None - if any(class in device_properties["types"] for class in switch_classes): + if any( + switch_class in device_properties["types"] + for switch_class in switch_classes + ): if "plug" in device_properties["types"]: model = "Metered Switch" if "switch_group" in device_properties["types"]: From 028b4896ba3096d17d7a2739f8b7dbd7ec45d525 Mon Sep 17 00:00:00 2001 From: Tom Scholten Date: Sun, 8 Nov 2020 13:28:35 +0100 Subject: [PATCH 18/18] Fix CONF_USERNAME default, dummy and other consts --- .../components/plugwise/binary_sensor.py | 2 +- homeassistant/components/plugwise/gateway.py | 3 +- tests/components/plugwise/test_config_flow.py | 53 +++++++++++-------- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/plugwise/binary_sensor.py b/homeassistant/components/plugwise/binary_sensor.py index 1ec8ae1e3cea9..2ba85326265ba 100644 --- a/homeassistant/components/plugwise/binary_sensor.py +++ b/homeassistant/components/plugwise/binary_sensor.py @@ -36,7 +36,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): if device_properties["class"] == "heater_central": data = api.get_device_data(dev_id) - for binary_sensor, dummy in BINARY_SENSOR_MAP.items(): + for binary_sensor in BINARY_SENSOR_MAP: if binary_sensor not in data: continue diff --git a/homeassistant/components/plugwise/gateway.py b/homeassistant/components/plugwise/gateway.py index 21dfdf8947aa0..5ba6eda2770ad 100644 --- a/homeassistant/components/plugwise/gateway.py +++ b/homeassistant/components/plugwise/gateway.py @@ -33,6 +33,7 @@ DEFAULT_PORT, DEFAULT_SCAN_INTERVAL, DEFAULT_TIMEOUT, + DEFAULT_USERNAME, DOMAIN, SENSOR_PLATFORMS, UNDO_UPDATE_LISTENER, @@ -49,7 +50,7 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool: api = Smile( host=entry.data[CONF_HOST], - username=entry.data[CONF_USERNAME], + username=entry.data.get(CONF_USERNAME, DEFAULT_USERNAME), password=entry.data[CONF_PASSWORD], port=entry.data.get(CONF_PORT, DEFAULT_PORT), timeout=30, diff --git a/tests/components/plugwise/test_config_flow.py b/tests/components/plugwise/test_config_flow.py index e850cc68b14d0..dea42dfb01d47 100644 --- a/tests/components/plugwise/test_config_flow.py +++ b/tests/components/plugwise/test_config_flow.py @@ -9,7 +9,14 @@ DOMAIN, ) from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF -from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_SCAN_INTERVAL +from homeassistant.const import ( + CONF_HOST, + CONF_NAME, + CONF_PASSWORD, + CONF_PORT, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) from tests.async_mock import MagicMock, patch from tests.common import MockConfigEntry @@ -68,17 +75,17 @@ async def test_form(hass): ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, ) await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["data"] == { - "host": TEST_HOST, - "password": TEST_PASSWORD, - "port": DEFAULT_PORT, - "username": TEST_USERNAME, + CONF_HOST: TEST_HOST, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: DEFAULT_PORT, + CONF_USERNAME: TEST_USERNAME, } assert len(mock_setup.mock_calls) == 1 @@ -108,17 +115,17 @@ async def test_zeroconf_form(hass): ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"password": TEST_PASSWORD}, + {CONF_PASSWORD: TEST_PASSWORD}, ) await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["data"] == { - "host": TEST_HOST, - "password": TEST_PASSWORD, - "port": DEFAULT_PORT, - "username": TEST_USERNAME, + CONF_HOST: TEST_HOST, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: DEFAULT_PORT, + CONF_USERNAME: TEST_USERNAME, } assert len(mock_setup.mock_calls) == 1 @@ -145,17 +152,21 @@ async def test_form_username(hass): ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD, "username": TEST_USERNAME2}, + { + CONF_HOST: TEST_HOST, + CONF_PASSWORD: TEST_PASSWORD, + CONF_USERNAME: TEST_USERNAME2, + }, ) await hass.async_block_till_done() assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result2["data"] == { - "host": TEST_HOST, - "password": TEST_PASSWORD, - "port": DEFAULT_PORT, - "username": TEST_USERNAME2, + CONF_HOST: TEST_HOST, + CONF_PASSWORD: TEST_PASSWORD, + CONF_PORT: DEFAULT_PORT, + CONF_USERNAME: TEST_USERNAME2, } assert len(mock_setup.mock_calls) == 1 @@ -181,7 +192,7 @@ async def test_form_username(hass): ) as mock_setup_entry: result4 = await hass.config_entries.flow.async_configure( result3["flow_id"], - {"password": TEST_PASSWORD}, + {CONF_PASSWORD: TEST_PASSWORD}, ) await hass.async_block_till_done() @@ -201,7 +212,7 @@ async def test_form_invalid_auth(hass, mock_smile): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM @@ -219,7 +230,7 @@ async def test_form_cannot_connect(hass, mock_smile): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM @@ -237,7 +248,7 @@ async def test_form_cannot_connect_port(hass, mock_smile): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD, "port": TEST_PORT}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD, CONF_PORT: TEST_PORT}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM @@ -255,7 +266,7 @@ async def test_form_other_problem(hass, mock_smile): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {"host": TEST_HOST, "password": TEST_PASSWORD}, + {CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, ) assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM