248 lines
7.8 KiB
Python
248 lines
7.8 KiB
Python
"""Support for Rheem EcoNet water heaters."""
|
|
import datetime
|
|
import logging
|
|
|
|
from pyeconet.api import PyEcoNet
|
|
import voluptuous as vol
|
|
|
|
from homeassistant.components.water_heater import (
|
|
PLATFORM_SCHEMA,
|
|
STATE_ECO,
|
|
STATE_ELECTRIC,
|
|
STATE_GAS,
|
|
STATE_HEAT_PUMP,
|
|
STATE_HIGH_DEMAND,
|
|
STATE_OFF,
|
|
STATE_PERFORMANCE,
|
|
SUPPORT_OPERATION_MODE,
|
|
SUPPORT_TARGET_TEMPERATURE,
|
|
WaterHeaterEntity,
|
|
)
|
|
from homeassistant.const import (
|
|
ATTR_ENTITY_ID,
|
|
ATTR_TEMPERATURE,
|
|
CONF_PASSWORD,
|
|
CONF_USERNAME,
|
|
TEMP_FAHRENHEIT,
|
|
)
|
|
import homeassistant.helpers.config_validation as cv
|
|
|
|
from .const import DOMAIN, SERVICE_ADD_VACATION, SERVICE_DELETE_VACATION
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
ATTR_VACATION_START = "next_vacation_start_date"
|
|
ATTR_VACATION_END = "next_vacation_end_date"
|
|
ATTR_ON_VACATION = "on_vacation"
|
|
ATTR_TODAYS_ENERGY_USAGE = "todays_energy_usage"
|
|
ATTR_IN_USE = "in_use"
|
|
|
|
ATTR_START_DATE = "start_date"
|
|
ATTR_END_DATE = "end_date"
|
|
|
|
ATTR_LOWER_TEMP = "lower_temp"
|
|
ATTR_UPPER_TEMP = "upper_temp"
|
|
ATTR_IS_ENABLED = "is_enabled"
|
|
|
|
SUPPORT_FLAGS_HEATER = SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE
|
|
|
|
ADD_VACATION_SCHEMA = vol.Schema(
|
|
{
|
|
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
|
vol.Optional(ATTR_START_DATE): cv.positive_int,
|
|
vol.Required(ATTR_END_DATE): cv.positive_int,
|
|
}
|
|
)
|
|
|
|
DELETE_VACATION_SCHEMA = vol.Schema({vol.Optional(ATTR_ENTITY_ID): cv.entity_ids})
|
|
|
|
ECONET_DATA = "econet"
|
|
|
|
ECONET_STATE_TO_HA = {
|
|
"Energy Saver": STATE_ECO,
|
|
"gas": STATE_GAS,
|
|
"High Demand": STATE_HIGH_DEMAND,
|
|
"Off": STATE_OFF,
|
|
"Performance": STATE_PERFORMANCE,
|
|
"Heat Pump Only": STATE_HEAT_PUMP,
|
|
"Electric-Only": STATE_ELECTRIC,
|
|
"Electric": STATE_ELECTRIC,
|
|
"Heat Pump": STATE_HEAT_PUMP,
|
|
}
|
|
|
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
{vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string}
|
|
)
|
|
|
|
|
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
|
"""Set up the EcoNet water heaters."""
|
|
|
|
hass.data[ECONET_DATA] = {}
|
|
hass.data[ECONET_DATA]["water_heaters"] = []
|
|
|
|
username = config.get(CONF_USERNAME)
|
|
password = config.get(CONF_PASSWORD)
|
|
|
|
econet = PyEcoNet(username, password)
|
|
water_heaters = econet.get_water_heaters()
|
|
hass_water_heaters = [
|
|
EcoNetWaterHeater(water_heater) for water_heater in water_heaters
|
|
]
|
|
add_entities(hass_water_heaters)
|
|
hass.data[ECONET_DATA]["water_heaters"].extend(hass_water_heaters)
|
|
|
|
def service_handle(service):
|
|
"""Handle the service calls."""
|
|
entity_ids = service.data.get("entity_id")
|
|
all_heaters = hass.data[ECONET_DATA]["water_heaters"]
|
|
_heaters = [
|
|
x for x in all_heaters if not entity_ids or x.entity_id in entity_ids
|
|
]
|
|
|
|
for _water_heater in _heaters:
|
|
if service.service == SERVICE_ADD_VACATION:
|
|
start = service.data.get(ATTR_START_DATE)
|
|
end = service.data.get(ATTR_END_DATE)
|
|
_water_heater.add_vacation(start, end)
|
|
if service.service == SERVICE_DELETE_VACATION:
|
|
for vacation in _water_heater.water_heater.vacations:
|
|
vacation.delete()
|
|
|
|
_water_heater.schedule_update_ha_state(True)
|
|
|
|
hass.services.register(
|
|
DOMAIN, SERVICE_ADD_VACATION, service_handle, schema=ADD_VACATION_SCHEMA
|
|
)
|
|
|
|
hass.services.register(
|
|
DOMAIN, SERVICE_DELETE_VACATION, service_handle, schema=DELETE_VACATION_SCHEMA
|
|
)
|
|
|
|
|
|
class EcoNetWaterHeater(WaterHeaterEntity):
|
|
"""Representation of an EcoNet water heater."""
|
|
|
|
def __init__(self, water_heater):
|
|
"""Initialize the water heater."""
|
|
self.water_heater = water_heater
|
|
self.supported_modes = self.water_heater.supported_modes
|
|
self.econet_state_to_ha = {}
|
|
self.ha_state_to_econet = {}
|
|
for mode in ECONET_STATE_TO_HA:
|
|
if mode in self.supported_modes:
|
|
self.econet_state_to_ha[mode] = ECONET_STATE_TO_HA.get(mode)
|
|
for key, value in self.econet_state_to_ha.items():
|
|
self.ha_state_to_econet[value] = key
|
|
for mode in self.supported_modes:
|
|
if mode not in ECONET_STATE_TO_HA:
|
|
error = f"Invalid operation mode mapping. {mode} doesn't map. Please report this."
|
|
_LOGGER.error(error)
|
|
|
|
@property
|
|
def name(self):
|
|
"""Return the device name."""
|
|
return self.water_heater.name
|
|
|
|
@property
|
|
def available(self):
|
|
"""Return if the the device is online or not."""
|
|
return self.water_heater.is_connected
|
|
|
|
@property
|
|
def temperature_unit(self):
|
|
"""Return the unit of measurement."""
|
|
return TEMP_FAHRENHEIT
|
|
|
|
@property
|
|
def device_state_attributes(self):
|
|
"""Return the optional device state attributes."""
|
|
data = {}
|
|
vacations = self.water_heater.get_vacations()
|
|
if vacations:
|
|
data[ATTR_VACATION_START] = vacations[0].start_date
|
|
data[ATTR_VACATION_END] = vacations[0].end_date
|
|
data[ATTR_ON_VACATION] = self.water_heater.is_on_vacation
|
|
todays_usage = self.water_heater.total_usage_for_today
|
|
if todays_usage:
|
|
data[ATTR_TODAYS_ENERGY_USAGE] = todays_usage
|
|
data[ATTR_IN_USE] = self.water_heater.in_use
|
|
|
|
if self.water_heater.lower_temp is not None:
|
|
data[ATTR_LOWER_TEMP] = round(self.water_heater.lower_temp, 2)
|
|
if self.water_heater.upper_temp is not None:
|
|
data[ATTR_UPPER_TEMP] = round(self.water_heater.upper_temp, 2)
|
|
if self.water_heater.is_enabled is not None:
|
|
data[ATTR_IS_ENABLED] = self.water_heater.is_enabled
|
|
|
|
return data
|
|
|
|
@property
|
|
def current_operation(self):
|
|
"""
|
|
Return current operation as one of the following.
|
|
|
|
["eco", "heat_pump", "high_demand", "electric_only"]
|
|
"""
|
|
current_op = self.econet_state_to_ha.get(self.water_heater.mode)
|
|
return current_op
|
|
|
|
@property
|
|
def operation_list(self):
|
|
"""List of available operation modes."""
|
|
op_list = []
|
|
for mode in self.supported_modes:
|
|
ha_mode = self.econet_state_to_ha.get(mode)
|
|
if ha_mode is not None:
|
|
op_list.append(ha_mode)
|
|
return op_list
|
|
|
|
@property
|
|
def supported_features(self):
|
|
"""Return the list of supported features."""
|
|
return SUPPORT_FLAGS_HEATER
|
|
|
|
def set_temperature(self, **kwargs):
|
|
"""Set new target temperature."""
|
|
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
|
if target_temp is not None:
|
|
self.water_heater.set_target_set_point(target_temp)
|
|
else:
|
|
_LOGGER.error("A target temperature must be provided")
|
|
|
|
def set_operation_mode(self, operation_mode):
|
|
"""Set operation mode."""
|
|
op_mode_to_set = self.ha_state_to_econet.get(operation_mode)
|
|
if op_mode_to_set is not None:
|
|
self.water_heater.set_mode(op_mode_to_set)
|
|
else:
|
|
_LOGGER.error("An operation mode must be provided")
|
|
|
|
def add_vacation(self, start, end):
|
|
"""Add a vacation to this water heater."""
|
|
if not start:
|
|
start = datetime.datetime.now()
|
|
else:
|
|
start = datetime.datetime.fromtimestamp(start)
|
|
end = datetime.datetime.fromtimestamp(end)
|
|
self.water_heater.set_vacation_mode(start, end)
|
|
|
|
def update(self):
|
|
"""Get the latest date."""
|
|
self.water_heater.update_state()
|
|
|
|
@property
|
|
def target_temperature(self):
|
|
"""Return the temperature we try to reach."""
|
|
return self.water_heater.set_point
|
|
|
|
@property
|
|
def min_temp(self):
|
|
"""Return the minimum temperature."""
|
|
return self.water_heater.min_set_point
|
|
|
|
@property
|
|
def max_temp(self):
|
|
"""Return the maximum temperature."""
|
|
return self.water_heater.max_set_point
|