From 4c6ddd435ce790e7adb6c13c2136de834fea5530 Mon Sep 17 00:00:00 2001 From: David Roberts Date: Wed, 5 Jun 2019 10:45:05 -0400 Subject: [PATCH] SolarEdge Local Component (#23996) * Basic local SolarEdge monitoring for energy / power * Basic local SolarEdge monitoring for energy / power * generated CODEOWNERS, requirements, excluded tests * generated CODEOWNERS, requirements, excluded tests * lint fixes, etc * lint fixes, etc * Fix docstyle for init Of course thats the file I forgot to run tests on * Load all sensors by default They use the same API endpoint. This changes was made per https://github.com/home-assistant/architecture/pull/244 * remve unneded date/time * ran hassfest again * add throttle when updating * readd solax, mistakenly removed * Update sensor.py --- .coveragerc | 1 + CODEOWNERS | 1 + .../components/solaredge_local/__init__.py | 1 + .../components/solaredge_local/manifest.json | 8 + .../components/solaredge_local/sensor.py | 159 ++++++++++++++++++ requirements_all.txt | 3 + 6 files changed, 173 insertions(+) create mode 100644 homeassistant/components/solaredge_local/__init__.py create mode 100644 homeassistant/components/solaredge_local/manifest.json create mode 100644 homeassistant/components/solaredge_local/sensor.py diff --git a/.coveragerc b/.coveragerc index 5480e0f1766..e329e2f31b9 100644 --- a/.coveragerc +++ b/.coveragerc @@ -555,6 +555,7 @@ omit = homeassistant/components/sochain/sensor.py homeassistant/components/socialblade/sensor.py homeassistant/components/solaredge/sensor.py + homeassistant/components/solaredge_local/sensor.py homeassistant/components/solax/sensor.py homeassistant/components/somfy_mylink/* homeassistant/components/sonarr/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 0fa8e54acc0..888ff2adb1c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -215,6 +215,7 @@ homeassistant/components/sma/* @kellerza homeassistant/components/smarthab/* @outadoc homeassistant/components/smartthings/* @andrewsayre homeassistant/components/smtp/* @fabaff +homeassistant/components/solaredge_local/* @drobtravels homeassistant/components/solax/* @squishykid homeassistant/components/sonos/* @amelchio homeassistant/components/spaceapi/* @fabaff diff --git a/homeassistant/components/solaredge_local/__init__.py b/homeassistant/components/solaredge_local/__init__.py new file mode 100644 index 00000000000..bf9d724dd54 --- /dev/null +++ b/homeassistant/components/solaredge_local/__init__.py @@ -0,0 +1 @@ +"""The SolarEdge Local Integration.""" diff --git a/homeassistant/components/solaredge_local/manifest.json b/homeassistant/components/solaredge_local/manifest.json new file mode 100644 index 00000000000..5fb07011983 --- /dev/null +++ b/homeassistant/components/solaredge_local/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "solaredge_local", + "name": "Solar Edge Local", + "documentation": "", + "dependencies": [], + "codeowners": ["@drobtravels"], + "requirements": ["solaredge-local==0.1.4"] + } \ No newline at end of file diff --git a/homeassistant/components/solaredge_local/sensor.py b/homeassistant/components/solaredge_local/sensor.py new file mode 100644 index 00000000000..8be4ceda7c7 --- /dev/null +++ b/homeassistant/components/solaredge_local/sensor.py @@ -0,0 +1,159 @@ +""" +Support for SolarEdge Monitoring API. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.solaredge_local/ +""" +import logging +from datetime import timedelta + +from requests.exceptions import HTTPError, ConnectTimeout +from solaredge_local import SolarEdge +import voluptuous as vol + + +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import ( + CONF_IP_ADDRESS, CONF_NAME, POWER_WATT, + ENERGY_WATT_HOUR) +import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + +DOMAIN = 'solaredge_local' +UPDATE_DELAY = timedelta(seconds=10) + +# Supported sensor types: +# Key: ['json_key', 'name', unit, icon] +SENSOR_TYPES = { + 'lifetime_energy': ['energyTotal', "Lifetime energy", + ENERGY_WATT_HOUR, 'mdi:solar-power'], + 'energy_this_year': ['energyThisYear', "Energy this year", + ENERGY_WATT_HOUR, 'mdi:solar-power'], + 'energy_this_month': ['energyThisMonth', "Energy this month", + ENERGY_WATT_HOUR, 'mdi:solar-power'], + 'energy_today': ['energyToday', "Energy today", + ENERGY_WATT_HOUR, 'mdi:solar-power'], + 'current_power': ['currentPower', "Current Power", + POWER_WATT, 'mdi:solar-power'] +} + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_IP_ADDRESS): cv.string, + vol.Optional(CONF_NAME, default='SolarEdge'): cv.string, +}) + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_entities, discovery_info=None): + """Create the SolarEdge Monitoring API sensor.""" + ip_address = config[CONF_IP_ADDRESS] + platform_name = config[CONF_NAME] + + # Create new SolarEdge object to retrieve data + api = SolarEdge("http://{}/".format(ip_address)) + + # Check if api can be reached and site is active + try: + status = api.get_status() + + status.energy # pylint: disable=pointless-statement + _LOGGER.debug("Credentials correct and site is active") + except AttributeError: + _LOGGER.error("Missing details data in solaredge response") + _LOGGER.debug("Response is: %s", status) + 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) + + # Create a new sensor for each sensor type. + entities = [] + for sensor_key in SENSOR_TYPES: + 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, + SENSOR_TYPES[self.sensor_key][1]) + + @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): + """Initialize the data object.""" + self.hass = hass + self.api = api + self.data = {} + + @Throttle(UPDATE_DELAY) + def update(self): + """Update the data from the SolarEdge Monitoring API.""" + try: + response = self.api.get_status() + _LOGGER.debug("response from SolarEdge: %s", response) + + self.data["energyTotal"] = response.energy.total + self.data["energyThisYear"] = response.energy.thisYear + self.data["energyThisMonth"] = response.energy.thisMonth + self.data["energyToday"] = response.energy.today + self.data["currentPower"] = response.powerWatt + + _LOGGER.debug("Updated SolarEdge overview data: %s", self.data) + except AttributeError: + _LOGGER.error("Missing details data in solaredge response") + _LOGGER.debug("Response is: %s", response) + return + except (ConnectTimeout, HTTPError): + _LOGGER.error("Could not retrieve data, skipping update") + return + + self.data["energyTotal"] = response.energy.total + self.data["energyThisYear"] = response.energy.thisYear + self.data["energyThisMonth"] = response.energy.thisMonth + self.data["energyToday"] = response.energy.today + self.data["currentPower"] = response.powerWatt + _LOGGER.debug("Updated SolarEdge overview data: %s", self.data) diff --git a/requirements_all.txt b/requirements_all.txt index f383cd9402c..7748fc7a4f2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1658,6 +1658,9 @@ snapcast==2.0.9 # homeassistant.components.socialblade socialbladeclient==0.2 +# homeassistant.components.solaredge_local +solaredge-local==0.1.4 + # homeassistant.components.solaredge solaredge==0.0.2