Ecoal (esterownik.pl) static fuel boiler and pump controller (#18480) - matkor
* Starting work on ecoal boiler controller iface. * Sending some values/states to controller. * Basic status parsing, and simple settings. * Platform configuration. * Temp sensors seems be working. * Switch from separate h/m/s to datetime. * Vocabulary updates. * secondary_central_heating_pump -> central_heating_pump2 * Pumps as switches. * Optional enabling pumps via config. * requests==2.20.1 added to REQUIREMENTS. * Optional enabling temp sensors from configuration yaml. * autopep8, black, pylint. * flake8. * pydocstyle * All style checkers again. * requests==2.20.1 required by homeassistant.components.sensor.ecoal_boiler. * Verify / set switches in update(). Code cleanup. * script/lint + travis issues. * Cleanup, imperative mood. * pylint, travis. * Updated .coveragerc. * Using configuration consts from homeassistant.const * typo. * Replace global ECOAL_CONTR with hass.data[DATA_ECOAL_BOILER]. Remove requests from REQUIREMENTS. * Killed .update()/reread_update() in Entities __init__()s. Removed debug/comments. * Removed debug/comments. * script/lint fixes. * script/gen_requirements_all.py run. * Travis fixes. * Configuration now validated. * Split controller code to separate package. * Replace in module docs with link to https://home-assistant.io . * Correct component module path in .coveragerc. More vals from const.py. Use dict[key] for required config keys. Check if credentials are correct during component setup. Renamed add_devices to add_entities. * Sensor/switch depends on ecoal_boiler component. EcoalSwitch inherits from SwitchDevice. Killed same as default should_poll(). Remove not neede schedule_update_ha_state() calls from turn_on/off. * lint fixes. * Move sensors/switches configuration to component setup. * Lint fixes. * Invalidating ecoal iface cache instead of force read in turn_on/off(). * Fail component setup before adding any platform entities. Kill NOTE. * Disallow setting entity names from config file, use code defined default names. * Rework configuration file to use monitored_conditions like in rainmachine component. * Killed pylint exception. Log error when connection to controller fails. * A few fixes. * Linted.
This commit is contained in:
parent
f84c0ee473
commit
9b7780edf0
5 changed files with 252 additions and 0 deletions
|
@ -91,6 +91,9 @@ omit =
|
|||
homeassistant/components/eight_sleep.py
|
||||
homeassistant/components/*/eight_sleep.py
|
||||
|
||||
homeassistant/components/ecoal_boiler.py
|
||||
homeassistant/components/*/ecoal_boiler.py
|
||||
|
||||
homeassistant/components/ecobee.py
|
||||
homeassistant/components/*/ecobee.py
|
||||
|
||||
|
|
98
homeassistant/components/ecoal_boiler.py
Normal file
98
homeassistant/components/ecoal_boiler.py
Normal file
|
@ -0,0 +1,98 @@
|
|||
"""
|
||||
Component to control ecoal/esterownik.pl coal/wood boiler controller.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/ecoal_boiler/
|
||||
"""
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (CONF_HOST, CONF_PASSWORD, CONF_USERNAME,
|
||||
CONF_MONITORED_CONDITIONS, CONF_SENSORS,
|
||||
CONF_SWITCHES)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.discovery import load_platform
|
||||
|
||||
REQUIREMENTS = ['ecoaliface==0.4.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = "ecoal_boiler"
|
||||
DATA_ECOAL_BOILER = 'data_' + DOMAIN
|
||||
|
||||
DEFAULT_USERNAME = "admin"
|
||||
DEFAULT_PASSWORD = "admin"
|
||||
|
||||
|
||||
# Available pump ids with assigned HA names
|
||||
# Available as switches
|
||||
AVAILABLE_PUMPS = {
|
||||
"central_heating_pump": "Central heating pump",
|
||||
"central_heating_pump2": "Central heating pump2",
|
||||
"domestic_hot_water_pump": "Domestic hot water pump",
|
||||
}
|
||||
|
||||
# Available temp sensor ids with assigned HA names
|
||||
# Available as sensors
|
||||
AVAILABLE_SENSORS = {
|
||||
"outdoor_temp": 'Outdoor temperature',
|
||||
"indoor_temp": 'Indoor temperature',
|
||||
"indoor2_temp": 'Indoor temperature 2',
|
||||
"domestic_hot_water_temp": 'Domestic hot water temperature',
|
||||
"target_domestic_hot_water_temp": 'Target hot water temperature',
|
||||
"feedwater_in_temp": 'Feedwater input temperature',
|
||||
"feedwater_out_temp": 'Feedwater output temperature',
|
||||
"target_feedwater_temp": 'Target feedwater temperature',
|
||||
"fuel_feeder_temp": 'Fuel feeder temperature',
|
||||
"exhaust_temp": 'Exhaust temperature',
|
||||
}
|
||||
|
||||
SWITCH_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_MONITORED_CONDITIONS, default=list(AVAILABLE_PUMPS)):
|
||||
vol.All(cv.ensure_list, [vol.In(AVAILABLE_PUMPS)])
|
||||
})
|
||||
|
||||
SENSOR_SCHEMA = vol.Schema({
|
||||
vol.Optional(CONF_MONITORED_CONDITIONS, default=list(AVAILABLE_SENSORS)):
|
||||
vol.All(cv.ensure_list, [vol.In(AVAILABLE_SENSORS)])
|
||||
})
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Optional(CONF_USERNAME,
|
||||
default=DEFAULT_USERNAME): cv.string,
|
||||
vol.Optional(CONF_PASSWORD,
|
||||
default=DEFAULT_PASSWORD): cv.string,
|
||||
vol.Optional(CONF_SWITCHES, default={}): SWITCH_SCHEMA,
|
||||
vol.Optional(CONF_SENSORS, default={}): SENSOR_SCHEMA,
|
||||
})
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
def setup(hass, hass_config):
|
||||
"""Set up global ECoalController instance same for sensors and switches."""
|
||||
from ecoaliface.simple import ECoalController
|
||||
|
||||
conf = hass_config[DOMAIN]
|
||||
host = conf[CONF_HOST]
|
||||
username = conf[CONF_USERNAME]
|
||||
passwd = conf[CONF_PASSWORD]
|
||||
# Creating ECoalController instance makes HTTP request to controller.
|
||||
ecoal_contr = ECoalController(host, username, passwd)
|
||||
if ecoal_contr.version is None:
|
||||
# Wrong credentials nor network config
|
||||
_LOGGER.error("Unable to read controller status from %s@%s"
|
||||
" (wrong host/credentials)", username, host, )
|
||||
return False
|
||||
_LOGGER.debug("Detected controller version: %r @%s",
|
||||
ecoal_contr.version, host, )
|
||||
hass.data[DATA_ECOAL_BOILER] = ecoal_contr
|
||||
# Setup switches
|
||||
switches = conf[CONF_SWITCHES][CONF_MONITORED_CONDITIONS]
|
||||
load_platform(hass, 'switch', DOMAIN, switches, hass_config)
|
||||
# Setup temp sensors
|
||||
sensors = conf[CONF_SENSORS][CONF_MONITORED_CONDITIONS]
|
||||
load_platform(hass, 'sensor', DOMAIN, sensors, hass_config)
|
||||
return True
|
63
homeassistant/components/sensor/ecoal_boiler.py
Normal file
63
homeassistant/components/sensor/ecoal_boiler.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
"""
|
||||
Allows reading temperatures from ecoal/esterownik.pl controller.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/sensor.ecoal_boiler/
|
||||
"""
|
||||
import logging
|
||||
|
||||
from homeassistant.components.ecoal_boiler import (
|
||||
DATA_ECOAL_BOILER, AVAILABLE_SENSORS, )
|
||||
from homeassistant.const import TEMP_CELSIUS
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['ecoal_boiler']
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the ecoal sensors."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
devices = []
|
||||
ecoal_contr = hass.data[DATA_ECOAL_BOILER]
|
||||
for sensor_id in discovery_info:
|
||||
name = AVAILABLE_SENSORS[sensor_id]
|
||||
devices.append(EcoalTempSensor(ecoal_contr, name, sensor_id))
|
||||
add_entities(devices, True)
|
||||
|
||||
|
||||
class EcoalTempSensor(Entity):
|
||||
"""Representation of a temperature sensor using ecoal status data."""
|
||||
|
||||
def __init__(self, ecoal_contr, name, status_attr):
|
||||
"""Initialize the sensor."""
|
||||
self._ecoal_contr = ecoal_contr
|
||||
self._name = name
|
||||
self._status_attr = status_attr
|
||||
self._state = None
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement."""
|
||||
return TEMP_CELSIUS
|
||||
|
||||
def update(self):
|
||||
"""Fetch new state data for the sensor.
|
||||
|
||||
This is the only method that should fetch new data for Home Assistant.
|
||||
"""
|
||||
# Old values read 0.5 back can still be used
|
||||
status = self._ecoal_contr.get_cached_status()
|
||||
self._state = getattr(status, self._status_attr)
|
85
homeassistant/components/switch/ecoal_boiler.py
Normal file
85
homeassistant/components/switch/ecoal_boiler.py
Normal file
|
@ -0,0 +1,85 @@
|
|||
"""
|
||||
Allows to configuration ecoal (esterownik.pl) pumps as switches.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/switch.ecoal_boiler/
|
||||
"""
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
from homeassistant.components.ecoal_boiler import (
|
||||
DATA_ECOAL_BOILER, AVAILABLE_PUMPS, )
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['ecoal_boiler']
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up switches based on ecoal interface."""
|
||||
if discovery_info is None:
|
||||
return
|
||||
ecoal_contr = hass.data[DATA_ECOAL_BOILER]
|
||||
switches = []
|
||||
for pump_id in discovery_info:
|
||||
name = AVAILABLE_PUMPS[pump_id]
|
||||
switches.append(EcoalSwitch(ecoal_contr, name, pump_id))
|
||||
add_entities(switches, True)
|
||||
|
||||
|
||||
class EcoalSwitch(SwitchDevice):
|
||||
"""Representation of Ecoal switch."""
|
||||
|
||||
def __init__(self, ecoal_contr, name, state_attr):
|
||||
"""
|
||||
Initialize switch.
|
||||
|
||||
Sets HA switch to state as read from controller.
|
||||
"""
|
||||
self._ecoal_contr = ecoal_contr
|
||||
self._name = name
|
||||
self._state_attr = state_attr
|
||||
# Ecoalcotroller holds convention that same postfix is used
|
||||
# to set attribute
|
||||
# set_<attr>()
|
||||
# as attribute name in status instance:
|
||||
# status.<attr>
|
||||
self._contr_set_fun = getattr(self._ecoal_contr, "set_" + state_attr)
|
||||
# No value set, will be read from controller instead
|
||||
self._state = None
|
||||
|
||||
@property
|
||||
def name(self) -> Optional[str]:
|
||||
"""Return the name of the switch."""
|
||||
return self._name
|
||||
|
||||
def update(self):
|
||||
"""Fetch new state data for the sensor.
|
||||
|
||||
This is the only method that should fetch new data for Home Assistant.
|
||||
"""
|
||||
status = self._ecoal_contr.get_cached_status()
|
||||
self._state = getattr(status, self._state_attr)
|
||||
|
||||
def invalidate_ecoal_cache(self):
|
||||
"""Invalidate ecoal interface cache.
|
||||
|
||||
Forces that next read from ecaol interface to not use cache.
|
||||
"""
|
||||
self._ecoal_contr.status = None
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if device is on."""
|
||||
return self._state
|
||||
|
||||
def turn_on(self, **kwargs) -> None:
|
||||
"""Turn the device on."""
|
||||
self._contr_set_fun(1)
|
||||
self.invalidate_ecoal_cache()
|
||||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Turn the device off."""
|
||||
self._contr_set_fun(0)
|
||||
self.invalidate_ecoal_cache()
|
|
@ -339,6 +339,9 @@ dsmr_parser==0.12
|
|||
# homeassistant.components.sensor.dweet
|
||||
dweepy==0.3.0
|
||||
|
||||
# homeassistant.components.ecoal_boiler
|
||||
ecoaliface==0.4.0
|
||||
|
||||
# homeassistant.components.edp_redy
|
||||
edp_redy==0.0.3
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue