core/homeassistant/components/fritzdect/switch.py

225 lines
7.2 KiB
Python
Raw Normal View History

"""Support for FRITZ!DECT Switches."""
import logging
from fritzhome.fritz import FritzBox
from requests.exceptions import HTTPError, RequestException
import voluptuous as vol
from homeassistant.components.switch import PLATFORM_SCHEMA, SwitchDevice
from homeassistant.const import (
ATTR_TEMPERATURE,
2019-07-31 19:25:30 +00:00
CONF_HOST,
CONF_PASSWORD,
CONF_USERNAME,
ENERGY_KILO_WATT_HOUR,
POWER_WATT,
TEMP_CELSIUS,
2019-07-31 19:25:30 +00:00
)
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
# Standard Fritz Box IP
2019-07-31 19:25:30 +00:00
DEFAULT_HOST = "fritz.box"
2019-07-31 19:25:30 +00:00
ATTR_CURRENT_CONSUMPTION = "current_consumption"
ATTR_CURRENT_CONSUMPTION_UNIT = "current_consumption_unit"
ATTR_CURRENT_CONSUMPTION_UNIT_VALUE = POWER_WATT
2019-07-31 19:25:30 +00:00
ATTR_TOTAL_CONSUMPTION = "total_consumption"
ATTR_TOTAL_CONSUMPTION_UNIT = "total_consumption_unit"
ATTR_TOTAL_CONSUMPTION_UNIT_VALUE = ENERGY_KILO_WATT_HOUR
2019-07-31 19:25:30 +00:00
ATTR_TEMPERATURE_UNIT = "temperature_unit"
2019-07-31 19:25:30 +00:00
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
}
)
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Add all switches connected to Fritz Box."""
host = config.get(CONF_HOST)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
# Log into Fritz Box
fritz = FritzBox(host, username, password)
try:
fritz.login()
except Exception: # pylint: disable=broad-except
_LOGGER.error("Login to Fritz!Box failed")
return
# Add all actors to hass
for actor in fritz.get_actors():
# Only add devices that support switching
if actor.has_switch:
data = FritzDectSwitchData(fritz, actor.actor_id)
data.is_online = True
add_entities([FritzDectSwitch(hass, data, actor.name)], True)
class FritzDectSwitch(SwitchDevice):
"""Representation of a FRITZ!DECT switch."""
def __init__(self, hass, data, name):
"""Initialize the switch."""
self.units = hass.config.units
self.data = data
self._name = name
@property
def name(self):
"""Return the name of the FRITZ!DECT switch, if any."""
return self._name
@property
def device_state_attributes(self):
"""Return the state attributes of the device."""
attrs = {}
2019-07-31 19:25:30 +00:00
if (
self.data.has_powermeter
and self.data.current_consumption is not None
and self.data.total_consumption is not None
):
attrs[ATTR_CURRENT_CONSUMPTION] = "{:.1f}".format(
2019-07-31 19:25:30 +00:00
self.data.current_consumption
)
attrs[ATTR_CURRENT_CONSUMPTION_UNIT] = "{}".format(
2019-07-31 19:25:30 +00:00
ATTR_CURRENT_CONSUMPTION_UNIT_VALUE
)
attrs[ATTR_TOTAL_CONSUMPTION] = f"{self.data.total_consumption:.3f}"
attrs[ATTR_TOTAL_CONSUMPTION_UNIT] = "{}".format(
2019-07-31 19:25:30 +00:00
ATTR_TOTAL_CONSUMPTION_UNIT_VALUE
)
2019-07-31 19:25:30 +00:00
if self.data.has_temperature and self.data.temperature is not None:
attrs[ATTR_TEMPERATURE] = "{}".format(
2019-07-31 19:25:30 +00:00
self.units.temperature(self.data.temperature, TEMP_CELSIUS)
)
attrs[ATTR_TEMPERATURE_UNIT] = f"{self.units.temperature_unit}"
return attrs
@property
def current_power_w(self):
"""Return the current power usage in Watt."""
try:
return float(self.data.current_consumption)
except ValueError:
return None
@property
def is_on(self):
"""Return true if switch is on."""
return self.data.state
def turn_on(self, **kwargs):
"""Turn the switch on."""
if not self.data.is_online:
_LOGGER.error("turn_on: Not online skipping request")
return
try:
actor = self.data.fritz.get_actor_by_ain(self.data.ain)
actor.switch_on()
except (RequestException, HTTPError):
_LOGGER.error("Fritz!Box query failed, triggering relogin")
self.data.is_online = False
def turn_off(self, **kwargs):
"""Turn the switch off."""
if not self.data.is_online:
_LOGGER.error("turn_off: Not online skipping request")
return
try:
actor = self.data.fritz.get_actor_by_ain(self.data.ain)
actor.switch_off()
except (RequestException, HTTPError):
_LOGGER.error("Fritz!Box query failed, triggering relogin")
self.data.is_online = False
def update(self):
"""Get the latest data from the fritz box and updates the states."""
if not self.data.is_online:
_LOGGER.error("update: Not online, logging back in")
try:
self.data.fritz.login()
except Exception: # pylint: disable=broad-except
_LOGGER.error("Login to Fritz!Box failed")
return
self.data.is_online = True
try:
self.data.update()
except Exception: # pylint: disable=broad-except
_LOGGER.error("Fritz!Box query failed, triggering relogin")
self.data.is_online = False
class FritzDectSwitchData:
"""Get the latest data from the fritz box."""
def __init__(self, fritz, ain):
"""Initialize the data object."""
self.fritz = fritz
self.ain = ain
self.state = None
self.temperature = None
self.current_consumption = None
self.total_consumption = None
self.has_switch = False
self.has_temperature = False
self.has_powermeter = False
self.is_online = False
def update(self):
"""Get the latest data from the fritz box."""
if not self.is_online:
_LOGGER.error("Not online skipping request")
return
try:
actor = self.fritz.get_actor_by_ain(self.ain)
except (RequestException, HTTPError):
_LOGGER.error("Request to actor registry failed")
self.state = None
self.temperature = None
self.current_consumption = None
self.total_consumption = None
2019-07-31 19:25:30 +00:00
raise Exception("Request to actor registry failed")
if actor is None:
_LOGGER.error("Actor could not be found")
self.state = None
self.temperature = None
self.current_consumption = None
self.total_consumption = None
2019-07-31 19:25:30 +00:00
raise Exception("Actor could not be found")
try:
self.state = actor.get_state()
self.current_consumption = (actor.get_power() or 0.0) / 1000
self.total_consumption = (actor.get_energy() or 0.0) / 100000
except (RequestException, HTTPError):
_LOGGER.error("Request to actor failed")
self.state = None
self.temperature = None
self.current_consumption = None
self.total_consumption = None
2019-07-31 19:25:30 +00:00
raise Exception("Request to actor failed")
self.temperature = actor.temperature
self.has_switch = actor.has_switch
self.has_temperature = actor.has_temperature
self.has_powermeter = actor.has_powermeter