Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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, dummy in BINARY_SENSOR_MAP.items():
Comment thread
CoMPaTech marked this conversation as resolved.
Outdated
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",
}
11 changes: 6 additions & 5 deletions homeassistant/components/plugwise/gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
COORDINATOR,
DEFAULT_PORT,
DEFAULT_SCAN_INTERVAL,
DEFAULT_TIMEOUT,
Comment thread
CoMPaTech marked this conversation as resolved.
DOMAIN,
SENSOR_PLATFORMS,
UNDO_UPDATE_LISTENER,
Expand Down Expand Up @@ -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(
Expand All @@ -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:
Expand All @@ -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,
)
Expand Down
38 changes: 20 additions & 18 deletions homeassistant/components/plugwise/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,26 +116,30 @@
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,
],
"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": [
Expand Down Expand Up @@ -242,6 +246,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

Expand All @@ -261,9 +266,14 @@ 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."""
"""Return the state of this entity."""
return self._state

@property
Expand All @@ -273,7 +283,7 @@ def unit_of_measurement(self):


class PwThermostatSensor(SmileSensor, Entity):
"""Thermostat and climate sensor entities."""
"""Thermostat (or generic) sensor devices."""

def __init__(self, api, coordinator, name, dev_id, sensor, sensor_type):
"""Set up the Plugwise API."""
Expand All @@ -296,31 +306,23 @@ 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)
measurement = int(measurement * 100)
self._state = measurement
self._icon = CUSTOM_ICONS.get(self._sensor, self._icon)

self.async_write_ha_state()


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."""
super().__init__(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):
Expand Down Expand Up @@ -380,7 +382,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)

Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/plugwise/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Comment thread
ctalkington marked this conversation as resolved.
}
}
},
Expand Down
Loading