core/homeassistant/components/fronius/sensor.py

198 lines
5.9 KiB
Python

"""Support for Fronius devices."""
import copy
import logging
import voluptuous as vol
from pyfronius import Fronius
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (CONF_RESOURCE, CONF_SENSOR_TYPE, CONF_DEVICE,
CONF_MONITORED_CONDITIONS)
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
_LOGGER = logging.getLogger(__name__)
CONF_SCOPE = 'scope'
TYPE_INVERTER = 'inverter'
TYPE_STORAGE = 'storage'
TYPE_METER = 'meter'
TYPE_POWER_FLOW = 'power_flow'
SCOPE_DEVICE = 'device'
SCOPE_SYSTEM = 'system'
DEFAULT_SCOPE = SCOPE_DEVICE
DEFAULT_DEVICE = 0
DEFAULT_INVERTER = 1
SENSOR_TYPES = [TYPE_INVERTER, TYPE_STORAGE, TYPE_METER, TYPE_POWER_FLOW]
SCOPE_TYPES = [SCOPE_DEVICE, SCOPE_SYSTEM]
def _device_id_validator(config):
"""Ensure that inverters have default id 1 and other devices 0."""
config = copy.deepcopy(config)
for cond in config[CONF_MONITORED_CONDITIONS]:
if CONF_DEVICE not in cond:
if cond[CONF_SENSOR_TYPE] == TYPE_INVERTER:
cond[CONF_DEVICE] = DEFAULT_INVERTER
else:
cond[CONF_DEVICE] = DEFAULT_DEVICE
return config
PLATFORM_SCHEMA = vol.Schema(vol.All(PLATFORM_SCHEMA.extend({
vol.Required(CONF_RESOURCE):
cv.url,
vol.Required(CONF_MONITORED_CONDITIONS):
vol.All(
cv.ensure_list,
[{
vol.Required(CONF_SENSOR_TYPE): vol.In(SENSOR_TYPES),
vol.Optional(CONF_SCOPE, default=DEFAULT_SCOPE):
vol.In(SCOPE_TYPES),
vol.Optional(CONF_DEVICE):
vol.All(vol.Coerce(int), vol.Range(min=0))
}]
)
}), _device_id_validator))
async def async_setup_platform(hass,
config,
async_add_entities,
discovery_info=None):
"""Set up of Fronius platform."""
session = async_get_clientsession(hass)
fronius = Fronius(session, config[CONF_RESOURCE])
sensors = []
for condition in config[CONF_MONITORED_CONDITIONS]:
device = condition[CONF_DEVICE]
name = "Fronius {} {} {}".format(
condition[CONF_SENSOR_TYPE].replace('_', ' ').capitalize(),
device,
config[CONF_RESOURCE],
)
sensor_type = condition[CONF_SENSOR_TYPE]
scope = condition[CONF_SCOPE]
if sensor_type == TYPE_INVERTER:
if scope == SCOPE_SYSTEM:
sensor_cls = FroniusInverterSystem
else:
sensor_cls = FroniusInverterDevice
elif sensor_type == TYPE_METER:
if scope == SCOPE_SYSTEM:
sensor_cls = FroniusMeterSystem
else:
sensor_cls = FroniusMeterDevice
elif sensor_type == TYPE_POWER_FLOW:
sensor_cls = FroniusPowerFlow
else:
sensor_cls = FroniusStorage
sensors.append(sensor_cls(fronius, name, device))
async_add_entities(sensors, True)
class FroniusSensor(Entity):
"""The Fronius sensor implementation."""
def __init__(self, data, name, device):
"""Initialize the sensor."""
self.data = data
self._name = name
self._device = device
self._state = None
self._attributes = {}
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the current state."""
return self._state
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attributes
async def async_update(self):
"""Retrieve and update latest state."""
values = {}
try:
values = await self._update()
except ConnectionError:
_LOGGER.error("Failed to update: connection error")
except ValueError:
_LOGGER.error("Failed to update: invalid response returned."
"Maybe the configured device is not supported")
if values:
self._state = values['status']['Code']
attributes = {}
for key in values:
if 'value' in values[key]:
attributes[key] = values[key].get('value', 0)
self._attributes = attributes
async def _update(self):
"""Return values of interest."""
pass
class FroniusInverterSystem(FroniusSensor):
"""Sensor for the fronius inverter with system scope."""
async def _update(self):
"""Get the values for the current state."""
return await self.data.current_system_inverter_data()
class FroniusInverterDevice(FroniusSensor):
"""Sensor for the fronius inverter with device scope."""
async def _update(self):
"""Get the values for the current state."""
return await self.data.current_inverter_data(self._device)
class FroniusStorage(FroniusSensor):
"""Sensor for the fronius battery storage."""
async def _update(self):
"""Get the values for the current state."""
return await self.data.current_storage_data(self._device)
class FroniusMeterSystem(FroniusSensor):
"""Sensor for the fronius meter with system scope."""
async def _update(self):
"""Get the values for the current state."""
return await self.data.current_system_meter_data()
class FroniusMeterDevice(FroniusSensor):
"""Sensor for the fronius meter with device scope."""
async def _update(self):
"""Get the values for the current state."""
return await self.data.current_meter_data(self._device)
class FroniusPowerFlow(FroniusSensor):
"""Sensor for the fronius power flow."""
async def _update(self):
"""Get the values for the current state."""
return await self.data.current_power_flow()