From 7959c04d1efa70a7e79b0d5602b4c1b89973d2f9 Mon Sep 17 00:00:00 2001 From: Robin Wohlers-Reichel Date: Sun, 26 May 2019 12:55:30 +1000 Subject: [PATCH] Solax Inverter Sensor Component (#22579) * Solax inverter direct API * Linter compliance * lint++ * move api communication to external lib * lint++ * requirements * Revert "requirements" This reverts commit 82a6c0c095ae5d454a1a16f72a77941626fa5ea2. * potentially? * Addressing review comments * Also update CODEOWNERS * Only update sensor state if data has changed --- .coveragerc | 1 + CODEOWNERS | 1 + homeassistant/components/solax/__init__.py | 1 + homeassistant/components/solax/manifest.json | 11 ++ homeassistant/components/solax/sensor.py | 106 +++++++++++++++++++ requirements_all.txt | 3 + 6 files changed, 123 insertions(+) create mode 100644 homeassistant/components/solax/__init__.py create mode 100644 homeassistant/components/solax/manifest.json create mode 100644 homeassistant/components/solax/sensor.py diff --git a/.coveragerc b/.coveragerc index 8f32fcdbe379..20111585c15a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -546,6 +546,7 @@ omit = homeassistant/components/sochain/sensor.py homeassistant/components/socialblade/sensor.py homeassistant/components/solaredge/sensor.py + homeassistant/components/solax/sensor.py homeassistant/components/somfy_mylink/* homeassistant/components/sonarr/sensor.py homeassistant/components/songpal/media_player.py diff --git a/CODEOWNERS b/CODEOWNERS index 0207363102b4..a1581d4720c1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -210,6 +210,7 @@ homeassistant/components/sma/* @kellerza homeassistant/components/smarthab/* @outadoc homeassistant/components/smartthings/* @andrewsayre homeassistant/components/smtp/* @fabaff +homeassistant/components/solax/* @squishykid homeassistant/components/sonos/* @amelchio homeassistant/components/spaceapi/* @fabaff homeassistant/components/spider/* @peternijssen diff --git a/homeassistant/components/solax/__init__.py b/homeassistant/components/solax/__init__.py new file mode 100644 index 000000000000..3995ab10ac9e --- /dev/null +++ b/homeassistant/components/solax/__init__.py @@ -0,0 +1 @@ +"""The solax component.""" diff --git a/homeassistant/components/solax/manifest.json b/homeassistant/components/solax/manifest.json new file mode 100644 index 000000000000..8e5f9d960f02 --- /dev/null +++ b/homeassistant/components/solax/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "solax", + "name": "Solax Inverter", + "documentation": "https://www.home-assistant.io/components/solax", + "requirements": [ + "solax==0.0.3" + ], + "dependencies": [], + "codeowners": ["@squishykid"] + } + \ No newline at end of file diff --git a/homeassistant/components/solax/sensor.py b/homeassistant/components/solax/sensor.py new file mode 100644 index 000000000000..46d8722f8319 --- /dev/null +++ b/homeassistant/components/solax/sensor.py @@ -0,0 +1,106 @@ +"""Support for Solax inverter via local API.""" +import asyncio + +from datetime import timedelta +import logging + +import voluptuous as vol + +from homeassistant.const import ( + TEMP_CELSIUS, + CONF_IP_ADDRESS +) +from homeassistant.helpers.entity import Entity +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.exceptions import PlatformNotReady +from homeassistant.helpers.event import async_track_time_interval + +_LOGGER = logging.getLogger(__name__) + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_IP_ADDRESS): cv.string, +}) + +SCAN_INTERVAL = timedelta(seconds=30) + + +async def async_setup_platform(hass, config, async_add_entities, + discovery_info=None): + """Platform setup.""" + import solax + + api = solax.solax.RealTimeAPI(config[CONF_IP_ADDRESS]) + endpoint = RealTimeDataEndpoint(hass, api) + hass.async_add_job(endpoint.async_refresh) + async_track_time_interval(hass, endpoint.async_refresh, SCAN_INTERVAL) + devices = [] + for sensor in solax.INVERTER_SENSORS: + unit = solax.INVERTER_SENSORS[sensor][1] + if unit == 'C': + unit = TEMP_CELSIUS + devices.append(Inverter(sensor, unit)) + endpoint.sensors = devices + async_add_entities(devices) + + +class RealTimeDataEndpoint: + """Representation of a Sensor.""" + + def __init__(self, hass, api): + """Initialize the sensor.""" + self.hass = hass + self.api = api + self.data = {} + self.ready = asyncio.Event() + self.sensors = [] + + async def async_refresh(self, now=None): + """Fetch new state data for the sensor. + + This is the only method that should fetch new data for Home Assistant. + """ + from solax import SolaxRequestError + + try: + self.data = await self.api.get_data() + self.ready.set() + except SolaxRequestError: + if now is not None: + self.ready.clear() + else: + raise PlatformNotReady + for sensor in self.sensors: + if sensor.key in self.data: + sensor.value = self.data[sensor.key] + sensor.async_schedule_update_ha_state() + + +class Inverter(Entity): + """Class for a sensor.""" + + def __init__(self, key, unit): + """Initialize an inverter sensor.""" + self.key = key + self.value = None + self.unit = unit + + @property + def state(self): + """State of this inverter attribute.""" + return self.value + + @property + def name(self): + """Name of this inverter attribute.""" + return self.key + + @property + def unit_of_measurement(self): + """Return the unit of measurement.""" + return self.unit + + @property + def should_poll(self): + """No polling needed.""" + return False diff --git a/requirements_all.txt b/requirements_all.txt index 5288c6c90016..21bdcc6bf4cc 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1653,6 +1653,9 @@ socialbladeclient==0.2 # homeassistant.components.solaredge solaredge==0.0.2 +# homeassistant.components.solax +solax==0.0.3 + # homeassistant.components.honeywell somecomfort==0.5.2