mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Fronius (solar energy and inverter) component (#22316)
* Introduced fronius component that adds ability to track Fronius devices from Home Assistant * Use device parameter for fetching inverter data * Fixed handling of default scope * Handle exceptions from yield * Fulfill PR requirements * Fixed houndci violations * Found the last hound violation * Fixed docstring (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165776934) * Fixed import order with isort (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165776957) * CONF_DEVICE is now CONF_DEVICEID (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165777161) * Added docstring to class FroniusSensor (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165777792) * Fixed docstring for state (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165777885) * Added/fixed docstrings (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165778108 & https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165778125) * Remove redundant log entry (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165779213) * Fixed error message if sensor update fails (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165779435) * Fixed error log messages (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165779751 & https://github.com/home-assistant/home-assistant/pull/11446#discussion_r165779761) * Satisfy hound * Handle exceptions explicit (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r168940902) * Removed unnecessary call of update (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r168940894) * The point makes the difference. * Removed unrelated requirements * Remove config logging (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r168968748) * Reorder and fix imports (https://github.com/home-assistant/home-assistant/pull/11446#discussion_r168968725, https://github.com/home-assistant/home-assistant/pull/11446#discussion_r168968691) * Update fronius requirement * Various small fixes * Small fixes * Formatting * Add fronius to coverage * New structure and formatting * Add manifest.json * Fix data loading * Make pylint happy * Fix issues * Fix parse_attributes * Fix docstring and platform schema * Make use of default HA-Const config values * Change configuration setup, introducing list of monitored conditions * Change the structure slightly, allowing for a list of sensors * Remove periods from logging * Formatting * Change name generation, use variable instead of string * small fixes * Update sensor.py * Incorporate correction proposals * Setting default device inside validation * Move import on top and small format * Formatting fix * Rename validation method to _device_id_validator
This commit is contained in:
parent
3cafc1f2c6
commit
333e1d6789
@ -214,6 +214,7 @@ omit =
|
||||
homeassistant/components/fritzbox_callmonitor/sensor.py
|
||||
homeassistant/components/fritzbox_netmonitor/sensor.py
|
||||
homeassistant/components/fritzdect/switch.py
|
||||
homeassistant/components/fronius/sensor.py
|
||||
homeassistant/components/frontier_silicon/media_player.py
|
||||
homeassistant/components/futurenow/light.py
|
||||
homeassistant/components/garadget/cover.py
|
||||
|
@ -91,6 +91,7 @@ homeassistant/components/flock/* @fabaff
|
||||
homeassistant/components/flunearyou/* @bachya
|
||||
homeassistant/components/foursquare/* @robbiet480
|
||||
homeassistant/components/freebox/* @snoof85
|
||||
homeassistant/components/fronius/* @nielstron
|
||||
homeassistant/components/frontend/* @home-assistant/frontend
|
||||
homeassistant/components/gearbest/* @HerrHofrat
|
||||
homeassistant/components/geniushub/* @zxdavb
|
||||
|
1
homeassistant/components/fronius/__init__.py
Normal file
1
homeassistant/components/fronius/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""The Fronius component."""
|
8
homeassistant/components/fronius/manifest.json
Normal file
8
homeassistant/components/fronius/manifest.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"domain": "fronius",
|
||||
"name": "Fronius",
|
||||
"documentation": "https://www.home-assistant.io/components/fronius",
|
||||
"requirements": ["pyfronius==0.4.6"],
|
||||
"dependencies": [],
|
||||
"codeowners": ["@nielstron"]
|
||||
}
|
197
homeassistant/components/fronius/sensor.py
Normal file
197
homeassistant/components/fronius/sensor.py
Normal file
@ -0,0 +1,197 @@
|
||||
"""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()
|
@ -1126,6 +1126,9 @@ pyfnip==0.2
|
||||
# homeassistant.components.fritzbox
|
||||
pyfritzhome==0.4.0
|
||||
|
||||
# homeassistant.components.fronius
|
||||
pyfronius==0.4.6
|
||||
|
||||
# homeassistant.components.ifttt
|
||||
pyfttt==0.3
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user