198 lines
5.9 KiB
Python
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()
|