Rewrite opentherm_gw to a component (#17133)

* Rewrite opentherm_gw to a component which loads the opentherm_gw climate platform.

* Add OpenTherm Gateway sensor platform.

* Remove library imports from platforms (use hass.data instead)
* Update .coveragerc
* Update docstrings to use new component documentation url

* Add OpenTherm Gateway binary sensor support.
Fix houndci findings.

* Revert "Add OpenTherm Gateway binary sensor support."

This reverts commit 5711dc4c25.

* Revert "Add OpenTherm Gateway sensor platform."

This reverts commit b3505ed561.

* Remove import from platform, use hass.data instead.
Update .coveragerc
Update docstrings
Update requirements_all.txt
General code cleanup

* Fix review findings.
Avoid using hass.data within connect_and_subscribe.
This commit is contained in:
mvn23
2018-10-09 21:06:24 +02:00
committed by Martin Hjelmare
parent 2aeb0efc7c
commit fc67f5eef3
4 changed files with 111 additions and 50 deletions

View File

@ -248,6 +248,9 @@ omit =
homeassistant/components/opencv.py
homeassistant/components/*/opencv.py
homeassistant/components/opentherm_gw.py
homeassistant/components/climate/opentherm_gw.py
homeassistant/components/openuv/__init__.py
homeassistant/components/*/openuv.py
@ -438,7 +441,6 @@ omit =
homeassistant/components/climate/honeywell.py
homeassistant/components/climate/knx.py
homeassistant/components/climate/oem.py
homeassistant/components/climate/opentherm_gw.py
homeassistant/components/climate/proliphix.py
homeassistant/components/climate/radiotherm.py
homeassistant/components/climate/sensibo.py

View File

@ -1,34 +1,23 @@
"""
Support for OpenTherm Gateway devices.
Support for OpenTherm Gateway climate devices.
For more details about this component, please refer to the documentation at
For more details about this platform, please refer to the documentation at
http://home-assistant.io/components/climate.opentherm_gw/
"""
import logging
import voluptuous as vol
from homeassistant.components.climate import (ClimateDevice, PLATFORM_SCHEMA,
STATE_IDLE, STATE_HEAT,
STATE_COOL,
from homeassistant.components.climate import (ClimateDevice, STATE_IDLE,
STATE_HEAT, STATE_COOL,
SUPPORT_TARGET_TEMPERATURE)
from homeassistant.const import (ATTR_TEMPERATURE, CONF_DEVICE, CONF_NAME,
PRECISION_HALVES, PRECISION_TENTHS,
TEMP_CELSIUS, PRECISION_WHOLE)
import homeassistant.helpers.config_validation as cv
from homeassistant.components.opentherm_gw import (
CONF_FLOOR_TEMP, CONF_PRECISION, DATA_DEVICE, DATA_GW_VARS,
DATA_OPENTHERM_GW, SIGNAL_OPENTHERM_GW_UPDATE)
from homeassistant.const import (ATTR_TEMPERATURE, CONF_NAME, PRECISION_HALVES,
PRECISION_TENTHS, PRECISION_WHOLE,
TEMP_CELSIUS)
from homeassistant.helpers.dispatcher import async_dispatcher_connect
REQUIREMENTS = ['pyotgw==0.1b0']
CONF_FLOOR_TEMP = "floor_temperature"
CONF_PRECISION = 'precision'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_DEVICE): cv.string,
vol.Optional(CONF_NAME, default="OpenTherm Gateway"): cv.string,
vol.Optional(CONF_PRECISION): vol.In([PRECISION_TENTHS, PRECISION_HALVES,
PRECISION_WHOLE]),
vol.Optional(CONF_FLOOR_TEMP, default=False): cv.boolean,
})
DEPENDENCIES = ['opentherm_gw']
SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE)
_LOGGER = logging.getLogger(__name__)
@ -37,19 +26,17 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_platform(hass, config, async_add_entities,
discovery_info=None):
"""Set up the opentherm_gw device."""
gateway = OpenThermGateway(config)
gateway = OpenThermGateway(hass, discovery_info)
async_add_entities([gateway])
class OpenThermGateway(ClimateDevice):
"""Representation of a climate device."""
def __init__(self, config):
"""Initialize the sensor."""
import pyotgw
self.pyotgw = pyotgw
self.gateway = self.pyotgw.pyotgw()
self._device = config[CONF_DEVICE]
def __init__(self, hass, config):
"""Initialize the device."""
self._gateway = hass.data[DATA_OPENTHERM_GW][DATA_DEVICE]
self._gw_vars = hass.data[DATA_OPENTHERM_GW][DATA_GW_VARS]
self.friendly_name = config.get(CONF_NAME)
self.floor_temp = config.get(CONF_FLOOR_TEMP)
self.temp_precision = config.get(CONF_PRECISION)
@ -63,40 +50,38 @@ class OpenThermGateway(ClimateDevice):
async def async_added_to_hass(self):
"""Connect to the OpenTherm Gateway device."""
await self.gateway.connect(self.hass.loop, self._device)
self.gateway.subscribe(self.receive_report)
_LOGGER.debug("Connected to %s on %s", self.friendly_name,
self._device)
_LOGGER.debug("Added device %s", self.friendly_name)
async_dispatcher_connect(self.hass, SIGNAL_OPENTHERM_GW_UPDATE,
self.receive_report)
async def receive_report(self, status):
"""Receive and handle a new report from the Gateway."""
_LOGGER.debug("Received report: %s", status)
ch_active = status.get(self.pyotgw.DATA_SLAVE_CH_ACTIVE)
flame_on = status.get(self.pyotgw.DATA_SLAVE_FLAME_ON)
cooling_active = status.get(self.pyotgw.DATA_SLAVE_COOLING_ACTIVE)
ch_active = status.get(self._gw_vars.DATA_SLAVE_CH_ACTIVE)
flame_on = status.get(self._gw_vars.DATA_SLAVE_FLAME_ON)
cooling_active = status.get(self._gw_vars.DATA_SLAVE_COOLING_ACTIVE)
if ch_active and flame_on:
self._current_operation = STATE_HEAT
elif cooling_active:
self._current_operation = STATE_COOL
else:
self._current_operation = STATE_IDLE
self._current_temperature = status.get(self.pyotgw.DATA_ROOM_TEMP)
self._current_temperature = status.get(self._gw_vars.DATA_ROOM_TEMP)
temp = status.get(self.pyotgw.DATA_ROOM_SETPOINT_OVRD)
temp = status.get(self._gw_vars.DATA_ROOM_SETPOINT_OVRD)
if temp is None:
temp = status.get(self.pyotgw.DATA_ROOM_SETPOINT)
temp = status.get(self._gw_vars.DATA_ROOM_SETPOINT)
self._target_temperature = temp
# GPIO mode 5: 0 == Away
# GPIO mode 6: 1 == Away
gpio_a_state = status.get(self.pyotgw.OTGW_GPIO_A)
gpio_a_state = status.get(self._gw_vars.OTGW_GPIO_A)
if gpio_a_state == 5:
self._away_mode_a = 0
elif gpio_a_state == 6:
self._away_mode_a = 1
else:
self._away_mode_a = None
gpio_b_state = status.get(self.pyotgw.OTGW_GPIO_B)
gpio_b_state = status.get(self._gw_vars.OTGW_GPIO_B)
if gpio_b_state == 5:
self._away_mode_b = 0
elif gpio_b_state == 6:
@ -104,11 +89,11 @@ class OpenThermGateway(ClimateDevice):
else:
self._away_mode_b = None
if self._away_mode_a is not None:
self._away_state_a = (status.get(self.pyotgw.OTGW_GPIO_A_STATE) ==
self._away_mode_a)
self._away_state_a = (status.get(
self._gw_vars.OTGW_GPIO_A_STATE) == self._away_mode_a)
if self._away_mode_b is not None:
self._away_state_b = (status.get(self.pyotgw.OTGW_GPIO_B_STATE) ==
self._away_mode_b)
self._away_state_b = (status.get(
self._gw_vars.OTGW_GPIO_B_STATE) == self._away_mode_b)
self.async_schedule_update_ha_state()
@property
@ -170,7 +155,7 @@ class OpenThermGateway(ClimateDevice):
"""Set new target temperature."""
if ATTR_TEMPERATURE in kwargs:
temp = float(kwargs[ATTR_TEMPERATURE])
self._target_temperature = await self.gateway.set_target_temp(
self._target_temperature = await self._gateway.set_target_temp(
temp)
self.async_schedule_update_ha_state()

View File

@ -0,0 +1,74 @@
"""
Support for OpenTherm Gateway devices.
For more details about this component, please refer to the documentation at
http://home-assistant.io/components/opentherm_gw/
"""
import logging
import voluptuous as vol
from homeassistant.const import (CONF_DEVICE, CONF_NAME, PRECISION_HALVES,
PRECISION_TENTHS, PRECISION_WHOLE)
from homeassistant.helpers.discovery import async_load_platform
from homeassistant.helpers.dispatcher import async_dispatcher_send
import homeassistant.helpers.config_validation as cv
DOMAIN = 'opentherm_gw'
CONF_CLIMATE = 'climate'
CONF_FLOOR_TEMP = 'floor_temperature'
CONF_PRECISION = 'precision'
DATA_DEVICE = 'device'
DATA_GW_VARS = 'gw_vars'
DATA_OPENTHERM_GW = 'opentherm_gw'
SIGNAL_OPENTHERM_GW_UPDATE = 'opentherm_gw_update'
CLIMATE_SCHEMA = vol.Schema({
vol.Optional(CONF_NAME, default="OpenTherm Gateway"): cv.string,
vol.Optional(CONF_PRECISION): vol.In([PRECISION_TENTHS, PRECISION_HALVES,
PRECISION_WHOLE]),
vol.Optional(CONF_FLOOR_TEMP, default=False): cv.boolean,
})
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_DEVICE): cv.string,
vol.Optional(CONF_CLIMATE, default={}): CLIMATE_SCHEMA,
}),
}, extra=vol.ALLOW_EXTRA)
REQUIREMENTS = ['pyotgw==0.1b0']
_LOGGER = logging.getLogger(__name__)
async def async_setup(hass, config):
"""Set up the OpenTherm Gateway component."""
import pyotgw
conf = config[DOMAIN]
gateway = pyotgw.pyotgw()
hass.data[DATA_OPENTHERM_GW] = {
DATA_DEVICE: gateway,
DATA_GW_VARS: pyotgw.vars,
}
hass.async_create_task(connect_and_subscribe(
hass, conf[CONF_DEVICE], gateway))
hass.async_create_task(async_load_platform(
hass, 'climate', DOMAIN, conf.get(CONF_CLIMATE)))
return True
async def connect_and_subscribe(hass, device_path, gateway):
"""Connect to serial device and subscribe report handler."""
await gateway.connect(hass.loop, device_path)
_LOGGER.debug("Connected to OpenTherm Gateway at %s", device_path)
async def handle_report(status):
"""Handle reports from the OpenTherm Gateway."""
_LOGGER.debug("Received report: %s", status)
async_dispatcher_send(hass, SIGNAL_OPENTHERM_GW_UPDATE, status)
gateway.subscribe(handle_report)

View File

@ -1027,7 +1027,7 @@ pyoppleio==1.0.5
# homeassistant.components.iota
pyota==2.0.5
# homeassistant.components.climate.opentherm_gw
# homeassistant.components.opentherm_gw
pyotgw==0.1b0
# homeassistant.auth.mfa_modules.notify