From 258fe1f09b3c41251da79e9ee409a91ebd8f2efa Mon Sep 17 00:00:00 2001 From: Gido Date: Wed, 19 Dec 2018 09:56:45 +0100 Subject: [PATCH] Add sensor platform for SolarEdge Monitoring API (#18846) * Adding sensor for SolarEdge Monitoring API support * Adding support for Rova garbage calendar * Update solaredge to pass lint and flake8 * Added solaredge.py to .coveragerc * Added extend for Voluptuous schema * Fixed styling issues * Removed rova.py for later feature * Replaced API requests with python pip package * Fixed styling issues * Updated to new async syntax Added async_update to sensor class Added Throttle to SolarEdge data update Added CONF_NAME to platform settings Added credentials check for api Minor code style changes * Remove unnecessary debug logging * Updated dict keys * Added SCAN_INTERVAL Updated platform setup * Remove DOMAIN variable Correct import for PLATFORM_SCHEMA * Change some debug to error messages Correct return statements Remove initial update call * Fix pylint and flake8 errors --- .coveragerc | 1 + homeassistant/components/sensor/solaredge.py | 165 +++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 169 insertions(+) create mode 100644 homeassistant/components/sensor/solaredge.py diff --git a/.coveragerc b/.coveragerc index 4cd75563ec7..ef8a4af5209 100644 --- a/.coveragerc +++ b/.coveragerc @@ -824,6 +824,7 @@ omit = homeassistant/components/sensor/snmp.py homeassistant/components/sensor/sochain.py homeassistant/components/sensor/socialblade.py + homeassistant/components/sensor/solaredge.py homeassistant/components/sensor/sonarr.py homeassistant/components/sensor/speedtest.py homeassistant/components/sensor/spotcrime.py diff --git a/homeassistant/components/sensor/solaredge.py b/homeassistant/components/sensor/solaredge.py new file mode 100644 index 00000000000..1cabe7c0445 --- /dev/null +++ b/homeassistant/components/sensor/solaredge.py @@ -0,0 +1,165 @@ +""" +Support for SolarEdge Monitoring API. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.solaredge/ +""" + +from datetime import timedelta +import logging + +import voluptuous as vol + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ( + CONF_API_KEY, CONF_MONITORED_CONDITIONS, CONF_NAME) +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + +REQUIREMENTS = ['solaredge==0.0.2'] + +# Config for solaredge monitoring api requests. +CONF_SITE_ID = "site_id" + +UPDATE_DELAY = timedelta(minutes=10) +SCAN_INTERVAL = timedelta(minutes=10) + +# Supported sensor types: +# Key: ['json_key', 'name', unit, icon] +SENSOR_TYPES = { + 'life_time_data': ['lifeTimeData', "Lifetime energy", 'Wh', + 'mdi:solar-power'], + 'last_year_data': ['lastYearData', "Energy this year", 'Wh', + 'mdi:solar-power'], + 'last_month_data': ['lastMonthData', "Energy this month", 'Wh', + 'mdi:solar-power'], + 'last_day_data': ['lastDayData', "Energy today", 'Wh', + 'mdi:solar-power'], + 'current_power': ['currentPower', "Current Power", 'W', + 'mdi:solar-power'] +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_API_KEY): cv.string, + vol.Required(CONF_SITE_ID): cv.string, + vol.Optional(CONF_NAME, default='SolarEdge'): cv.string, + vol.Optional(CONF_MONITORED_CONDITIONS, default=['current_power']): + vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]) +}) + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Create the SolarEdge Monitoring API sensor.""" + import solaredge + from requests.exceptions import HTTPError, ConnectTimeout + + api_key = config[CONF_API_KEY] + site_id = config[CONF_SITE_ID] + platform_name = config[CONF_NAME] + + # Create new SolarEdge object to retrieve data + api = solaredge.Solaredge(api_key) + + # Check if api can be reached and site is active + try: + response = api.get_details(site_id) + + if response['details']['status'].lower() != 'active': + _LOGGER.error("SolarEdge site is not active") + return + _LOGGER.debug("Credentials correct and site is active") + except KeyError: + _LOGGER.error("Missing details data in solaredge response") + return + except (ConnectTimeout, HTTPError): + _LOGGER.error("Could not retrieve details from SolarEdge API") + return + + # Create solaredge data service which will retrieve and update the data. + data = SolarEdgeData(hass, api, site_id) + + # Create a new sensor for each sensor type. + entities = [] + for sensor_key in config[CONF_MONITORED_CONDITIONS]: + sensor = SolarEdgeSensor(platform_name, sensor_key, data) + entities.append(sensor) + + add_entities(entities, True) + + +class SolarEdgeSensor(Entity): + """Representation of an SolarEdge Monitoring API sensor.""" + + def __init__(self, platform_name, sensor_key, data): + """Initialize the sensor.""" + self.platform_name = platform_name + self.sensor_key = sensor_key + self.data = data + self._state = None + + self._json_key = SENSOR_TYPES[self.sensor_key][0] + self._unit_of_measurement = SENSOR_TYPES[self.sensor_key][2] + + @property + def name(self): + """Return the name.""" + return "{}_{}".format(self.platform_name, self.sensor_key) + + @property + def unit_of_measurement(self): + """Return the unit of measurement.""" + return self._unit_of_measurement + + @property + def icon(self): + """Return the sensor icon.""" + return SENSOR_TYPES[self.sensor_key][3] + + @property + def state(self): + """Return the state of the sensor.""" + return self._state + + def update(self): + """Get the latest data from the sensor and update the state.""" + self.data.update() + self._state = self.data.data[self._json_key] + + +class SolarEdgeData: + """Get and update the latest data.""" + + def __init__(self, hass, api, site_id): + """Initialize the data object.""" + self.hass = hass + self.api = api + self.data = {} + self.site_id = site_id + + @Throttle(UPDATE_DELAY) + def update(self): + """Update the data from the SolarEdge Monitoring API.""" + from requests.exceptions import HTTPError, ConnectTimeout + + try: + data = self.api.get_overview(self.site_id) + overview = data['overview'] + except KeyError: + _LOGGER.error("Missing overview data, skipping update") + return + except (ConnectTimeout, HTTPError): + _LOGGER.error("Could not retrieve data, skipping update") + return + + self.data = {} + + for key, value in overview.items(): + if 'energy' in value: + self.data[key] = value['energy'] + elif 'power' in value: + self.data[key] = value['power'] + + _LOGGER.debug("Updated SolarEdge overview data: %s", self.data) diff --git a/requirements_all.txt b/requirements_all.txt index 3f4c2ba927e..dc412a9f44e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1488,6 +1488,9 @@ snapcast==2.0.9 # homeassistant.components.sensor.socialblade socialbladeclient==0.2 +# homeassistant.components.sensor.solaredge +solaredge==0.0.2 + # homeassistant.components.climate.honeywell somecomfort==0.5.2