mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +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_callmonitor/sensor.py
|
||||||
homeassistant/components/fritzbox_netmonitor/sensor.py
|
homeassistant/components/fritzbox_netmonitor/sensor.py
|
||||||
homeassistant/components/fritzdect/switch.py
|
homeassistant/components/fritzdect/switch.py
|
||||||
|
homeassistant/components/fronius/sensor.py
|
||||||
homeassistant/components/frontier_silicon/media_player.py
|
homeassistant/components/frontier_silicon/media_player.py
|
||||||
homeassistant/components/futurenow/light.py
|
homeassistant/components/futurenow/light.py
|
||||||
homeassistant/components/garadget/cover.py
|
homeassistant/components/garadget/cover.py
|
||||||
|
@ -91,6 +91,7 @@ homeassistant/components/flock/* @fabaff
|
|||||||
homeassistant/components/flunearyou/* @bachya
|
homeassistant/components/flunearyou/* @bachya
|
||||||
homeassistant/components/foursquare/* @robbiet480
|
homeassistant/components/foursquare/* @robbiet480
|
||||||
homeassistant/components/freebox/* @snoof85
|
homeassistant/components/freebox/* @snoof85
|
||||||
|
homeassistant/components/fronius/* @nielstron
|
||||||
homeassistant/components/frontend/* @home-assistant/frontend
|
homeassistant/components/frontend/* @home-assistant/frontend
|
||||||
homeassistant/components/gearbest/* @HerrHofrat
|
homeassistant/components/gearbest/* @HerrHofrat
|
||||||
homeassistant/components/geniushub/* @zxdavb
|
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
|
# homeassistant.components.fritzbox
|
||||||
pyfritzhome==0.4.0
|
pyfritzhome==0.4.0
|
||||||
|
|
||||||
|
# homeassistant.components.fronius
|
||||||
|
pyfronius==0.4.6
|
||||||
|
|
||||||
# homeassistant.components.ifttt
|
# homeassistant.components.ifttt
|
||||||
pyfttt==0.3
|
pyfttt==0.3
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user