Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ omit =
homeassistant/components/ecobee/weather.py
homeassistant/components/econet/__init__.py
homeassistant/components/econet/binary_sensor.py
homeassistant/components/econet/climate.py
homeassistant/components/econet/const.py
homeassistant/components/econet/sensor.py
homeassistant/components/econet/water_heater.py
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/econet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

_LOGGER = logging.getLogger(__name__)

PLATFORMS = ["binary_sensor", "sensor", "water_heater"]
PLATFORMS = ["climate", "binary_sensor", "sensor", "water_heater"]
PUSH_UPDATE = "econet.push_update"

INTERVAL = timedelta(minutes=60)
Expand Down
63 changes: 32 additions & 31 deletions homeassistant/components/econet/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,51 @@
from pyeconet.equipment import EquipmentType

from homeassistant.components.binary_sensor import (
DEVICE_CLASS_LOCK,
DEVICE_CLASS_OPENING,
DEVICE_CLASS_POWER,
DEVICE_CLASS_SOUND,
BinarySensorEntity,
)

from . import EcoNetEntity
from .const import DOMAIN, EQUIPMENT

_LOGGER = logging.getLogger(__name__)

SENSOR_NAME_RUNNING = "running"
SENSOR_NAME_SHUTOFF_VALVE = "shutoff_valve"
SENSOR_NAME_VACATION = "vacation"
SENSOR_NAME_RUNNING = "running"
SENSOR_NAME_SCREEN_LOCKED = "screen_locked"
SENSOR_NAME_BEEP_ENABLED = "beep_enabled"

SENSOR_NAMES_TO_ATTRIBUTES = {
Comment thread
MartinHjelmare marked this conversation as resolved.
Outdated
SENSOR_NAME_SHUTOFF_VALVE: "shutoff_valve_open",
SENSOR_NAME_RUNNING: "running",
SENSOR_NAME_SCREEN_LOCKED: "screen_locked",
SENSOR_NAME_BEEP_ENABLED: "beep_enabled",
}

SENSOR_NAMES_TO_DEVICE_CLASS = {
SENSOR_NAME_SHUTOFF_VALVE: DEVICE_CLASS_OPENING,
SENSOR_NAME_RUNNING: DEVICE_CLASS_POWER,
SENSOR_NAME_BEEP_ENABLED: DEVICE_CLASS_SOUND,
SENSOR_NAME_SCREEN_LOCKED: DEVICE_CLASS_LOCK,
}

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass, entry, async_add_entities):
"""Set up EcoNet binary sensor based on a config entry."""
equipment = hass.data[DOMAIN][EQUIPMENT][entry.entry_id]
binary_sensors = []
for water_heater in equipment[EquipmentType.WATER_HEATER]:
if water_heater.has_shutoff_valve:
binary_sensors.append(
EcoNetBinarySensor(
water_heater,
SENSOR_NAME_SHUTOFF_VALVE,
)
)
if water_heater.running is not None:
binary_sensors.append(EcoNetBinarySensor(water_heater, SENSOR_NAME_RUNNING))
if water_heater.vacation is not None:
binary_sensors.append(
EcoNetBinarySensor(water_heater, SENSOR_NAME_VACATION)
)
async_add_entities(binary_sensors)
all_equipment = equipment[EquipmentType.WATER_HEATER]
all_equipment.extend(equipment[EquipmentType.THERMOSTAT])
for _equip in all_equipment:
for name, attribute in SENSOR_NAMES_TO_ATTRIBUTES.items():
if getattr(_equip, attribute, None) is not None:
binary_sensors.append(EcoNetBinarySensor(_equip, name))
async_add_entities(
binary_sensors,
)
Comment thread
frenck marked this conversation as resolved.
Outdated


class EcoNetBinarySensor(EcoNetEntity, BinarySensorEntity):
Expand All @@ -52,22 +63,12 @@ def __init__(self, econet_device, device_name):
@property
def is_on(self):
"""Return true if the binary sensor is on."""
if self._device_name == SENSOR_NAME_SHUTOFF_VALVE:
return self._econet.shutoff_valve_open
if self._device_name == SENSOR_NAME_RUNNING:
return self._econet.running
if self._device_name == SENSOR_NAME_VACATION:
return self._econet.vacation
return False
return getattr(self._econet, SENSOR_NAMES_TO_ATTRIBUTES[self._device_name])

@property
def device_class(self):
"""Return the class of this sensor, from DEVICE_CLASSES."""
if self._device_name == SENSOR_NAME_SHUTOFF_VALVE:
return DEVICE_CLASS_OPENING
if self._device_name == SENSOR_NAME_RUNNING:
return DEVICE_CLASS_POWER
return None
return SENSOR_NAMES_TO_DEVICE_CLASS[self._device_name]

@property
def name(self):
Expand Down
251 changes: 251 additions & 0 deletions homeassistant/components/econet/climate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
"""Support for Rheem EcoNet thermostats."""
import logging

from pyeconet.equipment import EquipmentType
from pyeconet.equipment.thermostat import ThermostatFanMode, ThermostatOperationMode

from homeassistant.components.climate import ClimateEntity
from homeassistant.components.climate.const import (
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
FAN_AUTO,
FAN_HIGH,
FAN_LOW,
FAN_MEDIUM,
HVAC_MODE_AUTO,
HVAC_MODE_COOL,
HVAC_MODE_FAN_ONLY,
HVAC_MODE_HEAT,
HVAC_MODE_OFF,
SUPPORT_AUX_HEAT,
SUPPORT_FAN_MODE,
SUPPORT_TARGET_HUMIDITY,
SUPPORT_TARGET_TEMPERATURE,
SUPPORT_TARGET_TEMPERATURE_RANGE,
)
from homeassistant.const import ATTR_TEMPERATURE

from . import EcoNetEntity
from .const import DOMAIN, EQUIPMENT

_LOGGER = logging.getLogger(__name__)

ECONET_STATE_TO_HA = {
ThermostatOperationMode.HEATING: HVAC_MODE_HEAT,
ThermostatOperationMode.COOLING: HVAC_MODE_COOL,
ThermostatOperationMode.OFF: HVAC_MODE_OFF,
ThermostatOperationMode.AUTO: HVAC_MODE_AUTO,
Comment thread
w1ll1am23 marked this conversation as resolved.
Outdated
ThermostatOperationMode.FAN_ONLY: HVAC_MODE_FAN_ONLY,
}
HA_STATE_TO_ECONET = {value: key for key, value in ECONET_STATE_TO_HA.items()}

# TODO: How to handle medlo and medhi
Comment thread
w1ll1am23 marked this conversation as resolved.
Outdated
# ThermostatFanMode.MEDHI: FAN_HIGH,
# ThermostatFanMode.MEDLO: FAN_MEDIUM,
ECONET_FAN_STATE_TO_HA = {
ThermostatFanMode.AUTO: FAN_AUTO,
ThermostatFanMode.LOW: FAN_LOW,
ThermostatFanMode.MEDIUM: FAN_MEDIUM,
ThermostatFanMode.HIGH: FAN_HIGH,
}
HA_FAN_STATE_TO_ECONET = {value: key for key, value in ECONET_FAN_STATE_TO_HA.items()}

SUPPORT_FLAGS_THERMOSTAT = (
SUPPORT_TARGET_TEMPERATURE
| SUPPORT_TARGET_TEMPERATURE_RANGE
| SUPPORT_FAN_MODE
| SUPPORT_AUX_HEAT
)


async def async_setup_entry(hass, entry, async_add_entities):
"""Set up EcoNet thermostat based on a config entry."""
equipment = hass.data[DOMAIN][EQUIPMENT][entry.entry_id]
async_add_entities(
[
EcoNetThermostat(thermostat)
for thermostat in equipment[EquipmentType.THERMOSTAT]
],
)


class EcoNetThermostat(EcoNetEntity, ClimateEntity):
"""Define a Econet thermostat."""

def __init__(self, thermostat):
"""Initialize."""
super().__init__(thermostat)
self._running = thermostat.running
self._poll = True
self.thermostat = thermostat
Comment thread
w1ll1am23 marked this conversation as resolved.
Outdated
self.econet_state_to_ha = {}
self.ha_state_to_econet = {}

@property
def supported_features(self):
"""Return the list of supported features."""
if self.thermostat.supports_humidifier:
return SUPPORT_FLAGS_THERMOSTAT | SUPPORT_TARGET_HUMIDITY
else:
return SUPPORT_FLAGS_THERMOSTAT

@property
def current_temperature(self):
"""Return the current temperature."""
return self.thermostat.set_point

@property
def current_humidity(self):
"""Return the current humidity."""
return self.thermostat.humidity

@property
def target_humidity(self):
"""Return the humidity we try to reach."""
if self.thermostat.supports_humidifier:
return self.thermostat.dehumidifier_set_point
else:
return None

@property
def target_temperature(self):
"""Return the temperature we try to reach."""
if self.hvac_mode == HVAC_MODE_COOL:
return self.thermostat.cool_set_point
elif self.hvac_mode == HVAC_MODE_HEAT:
return self.thermostat.heat_set_point
else:
return None

@property
def target_temperature_low(self):
"""Return the lower bound temperature we try to reach."""
if self.hvac_mode == HVAC_MODE_AUTO:
return self.thermostat.heat_set_point
else:
return None

@property
def target_temperature_high(self):
"""Return the higher bound temperature we try to reach."""
if self.hvac_mode == HVAC_MODE_AUTO:
return self.thermostat.cool_set_point
else:
return None

def set_temperature(self, **kwargs):
"""Set new target temperature."""
target_temp = kwargs.get(ATTR_TEMPERATURE)
target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW)
target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
if target_temp:
self.thermostat.set_set_point(target_temp, None, None)
elif target_temp_low or target_temp_high:
self.thermostat.set_set_point(None, target_temp_high, target_temp_low)
else:
_LOGGER.error("Something went wrong")

@property
def is_aux_heat(self):
"""Return true if aux heater."""
return self.thermostat.mode == ThermostatOperationMode.EMERGENCY_HEAT

@property
def hvac_modes(self):
"""Return hvac operation ie. heat, cool mode.

Needs to be one of HVAC_MODE_*.
"""
econet_modes = self.thermostat.modes
op_list = []
for mode in econet_modes:
if mode not in [
ThermostatOperationMode.UNKNOWN,
ThermostatOperationMode.EMERGENCY_HEAT,
]:
ha_mode = ECONET_STATE_TO_HA[mode]
op_list.append(ha_mode)
Comment thread
w1ll1am23 marked this conversation as resolved.
Outdated
return op_list

@property
def hvac_mode(self) -> str:
"""Return hvac operation ie. heat, cool, mode.

Needs to be one of HVAC_MODE_*.
"""
econet_mode = self.thermostat.mode
_current_op = HVAC_MODE_OFF
if econet_mode is not None:
_current_op = ECONET_STATE_TO_HA[econet_mode]

return _current_op

def set_hvac_mode(self, hvac_mode):
"""Set new target hvac mode."""
hvac_mode_to_set = HA_STATE_TO_ECONET.get(hvac_mode)
self.thermostat.set_mode(hvac_mode_to_set)
Comment thread
MartinHjelmare marked this conversation as resolved.
Outdated

def set_humidity(self, humidity: int):
"""Set new target humidity."""
self.thermostat.set_dehumidifier_set_point(humidity)

@property
def fan_mode(self):
"""Return the current fan mode."""
econet_fan_mode = self.thermostat.fan_mode

# Remove this after we figure out how to handle med lo and med hi
if econet_fan_mode in [ThermostatFanMode.MEDHI, ThermostatFanMode.MEDLO]:
econet_fan_mode = ThermostatFanMode.MEDIUM

_current_fan_mode = FAN_AUTO
if econet_fan_mode is not None:
_current_fan_mode = ECONET_FAN_STATE_TO_HA[econet_fan_mode]
return _current_fan_mode

@property
def fan_modes(self):
"""Return the fan modes."""
econet_fan_modes = self.thermostat.fan_modes
fan_list = []
for mode in econet_fan_modes:
# Remove the MEDLO MEDHI once we figure out how to handle it
if mode not in [
ThermostatFanMode.UNKNOWN,
ThermostatFanMode.MEDLO,
ThermostatFanMode.MEDHI,
]:
fan_list.append(ECONET_FAN_STATE_TO_HA[mode])
return fan_list

def set_fan_mode(self, fan_mode):
"""Set the fan mode."""
self.thermostat.set_fan_mode(HA_FAN_STATE_TO_ECONET[fan_mode])

def turn_aux_heat_on(self):
"""Turn auxiliary heater on."""
self.thermostat.set_mode(ThermostatOperationMode.EMERGENCY_HEAT)

def turn_aux_heat_off(self):
"""Turn auxiliary heater off."""
self.thermostat.set_mode(ThermostatOperationMode.HEATING)

@property
def min_temp(self):
"""Return the minimum temperature."""
return self.thermostat.set_point_limits[0]

@property
def max_temp(self):
"""Return the maximum temperature."""
return self.thermostat.set_point_limits[1]

@property
def min_humidity(self) -> int:
"""Return the minimum humidity."""
return self.thermostat.dehumidifier_set_point_limits[0]

@property
def max_humidity(self) -> int:
"""Return the maximum humidity."""
return self.thermostat.dehumidifier_set_point_limits[1]
Loading