Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 20 additions & 32 deletions homeassistant/components/plugwise/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,32 +33,31 @@ 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":
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"],
binary_sensor,
dev_id,
device_properties["class"],
if device_properties["class"] == "heater_central":
data = api.get_device_data(dev_id)

for binary_sensor in BINARY_SENSOR_MAP:
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)


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)

Expand All @@ -74,11 +73,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."""
Expand All @@ -95,16 +89,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()
30 changes: 23 additions & 7 deletions homeassistant/components/plugwise/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@
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_BASE,
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
Expand All @@ -28,14 +36,21 @@ 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)


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.
"""
Expand All @@ -45,6 +60,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,
)
Expand Down Expand Up @@ -89,7 +105,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()

Expand All @@ -111,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
Expand Down
36 changes: 18 additions & 18 deletions homeassistant/components/plugwise/const.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,53 @@
"""Constant for Plugwise component."""
DOMAIN = "plugwise"

SENSOR_PLATFORMS = ["sensor"]
SENSOR_PLATFORMS = ["sensor", "switch"]
ALL_PLATFORMS = ["binary_sensor", "climate", "sensor", "switch"]

# Sensor mapping
SENSOR_MAP_DEVICE_CLASS = 2
SENSOR_MAP_ICON = 3
SENSOR_MAP_MODEL = 0
SENSOR_MAP_UOM = 1
SENSOR_MAP_DEVICE_CLASS = 2

# Default directives
DEFAULT_NAME = "Smile"
DEFAULT_USERNAME = "smile"
DEFAULT_TIMEOUT = 10
DEFAULT_PORT = 80
DEFAULT_MIN_TEMP = 4
DEFAULT_MAX_TEMP = 30
DEFAULT_SCAN_INTERVAL = {"thermostat": 60, "power": 10}
DEFAULT_NAME = "Smile"
DEFAULT_PORT = 80
DEFAULT_USERNAME = "smile"
DEFAULT_SCAN_INTERVAL = {"power": 10, "stretch": 60, "thermostat": 60}
DEFAULT_TIMEOUT = 60

# Configuration directives
CONF_MIN_TEMP = "min_temp"
CONF_BASE = "base"
CONF_GAS = "gas"
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"
UNIT_LUMEN = "lm"

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"

UNDO_UPDATE_LISTENER = "undo_update_listener"
ZEROCONF_MAP = {
"smile": "P1",
"smile_thermo": "Anna",
"smile_open_therm": "Adam",
"stretch": "Stretch",
}
21 changes: 15 additions & 6 deletions homeassistant/components/plugwise/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -26,6 +32,8 @@
COORDINATOR,
DEFAULT_PORT,
DEFAULT_SCAN_INTERVAL,
DEFAULT_TIMEOUT,
DEFAULT_USERNAME,
DOMAIN,
SENSOR_PLATFORMS,
UNDO_UPDATE_LISTENER,
Expand All @@ -42,6 +50,7 @@ async def async_setup_entry_gw(hass: HomeAssistant, entry: ConfigEntry) -> bool:

api = Smile(
host=entry.data[CONF_HOST],
username=entry.data.get(CONF_USERNAME, DEFAULT_USERNAME),
password=entry.data[CONF_PASSWORD],
port=entry.data.get(CONF_PORT, DEFAULT_PORT),
timeout=30,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the default timeout be used here as well? can be done in new PR if so.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll have a look at this, thanks!

Expand All @@ -56,15 +65,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(
Expand All @@ -76,7 +85,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:
Expand All @@ -85,7 +94,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,
)
Expand Down
Loading