mirror of
https://github.com/home-assistant/core.git
synced 2025-08-03 04:35:11 +02:00
move api communication to external lib
This commit is contained in:
11
homeassistant/components/solax/manifest.json
Normal file
11
homeassistant/components/solax/manifest.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"domain": "solax",
|
||||
"name": "Solax Inverter",
|
||||
"documentation": "https://www.home-assistant.io/components/solax",
|
||||
"requirements": [
|
||||
"solax==0.0.3"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": []
|
||||
}
|
||||
|
@@ -5,8 +5,6 @@ import json
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import aiohttp
|
||||
import async_timeout
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import (
|
||||
@@ -22,141 +20,37 @@ from homeassistant.helpers.event import async_track_time_interval
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# key: name of sensor
|
||||
# value.0: index
|
||||
# value.1: unit (String) or None
|
||||
# from https://github.com/GitHobi/solax/wiki/direct-data-retrieval
|
||||
INVERTER_SENSORS = {
|
||||
'PV1 Current': (0, 'A'),
|
||||
'PV2 Current': (1, 'A'),
|
||||
'PV1 Voltage': (2, 'V'),
|
||||
'PV2 Voltage': (3, 'V'),
|
||||
|
||||
'Output Current': (4, 'A'),
|
||||
'Network Voltage': (5, 'V'),
|
||||
'Power Now': (6, 'W'),
|
||||
|
||||
'Inverter Temperature': (7, TEMP_CELSIUS),
|
||||
'Today\'s Energy': (8, 'kWh'),
|
||||
'Total Energy': (9, 'kWh'),
|
||||
'Exported Power': (10, 'W'),
|
||||
'PV1 Power': (11, 'W'),
|
||||
'PV2 Power': (12, 'W'),
|
||||
|
||||
'Battery Voltage': (13, 'V'),
|
||||
'Battery Current': (14, 'A'),
|
||||
'Battery Power': (15, 'W'),
|
||||
'Battery Temperature': (16, TEMP_CELSIUS),
|
||||
'Battery Remaining Capacity': (17, '%'),
|
||||
|
||||
'Battery Energy': (19, 'kWh'),
|
||||
|
||||
'Grid Frequency': (50, 'Hz'),
|
||||
'EPS Voltage': (53, 'V'),
|
||||
'EPS Current': (54, 'A'),
|
||||
'EPS Power': (55, 'W'),
|
||||
'EPS Frequency': (56, 'Hz'),
|
||||
}
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_IP_ADDRESS): cv.string,
|
||||
})
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=30)
|
||||
REQUEST_TIMEOUT = 5
|
||||
|
||||
REAL_TIME_DATA_ENDPOINT = 'http://{ip_address}/api/realTimeData.htm'
|
||||
|
||||
DATA_SCHEMA = vol.Schema(
|
||||
vol.All([vol.Coerce(float)], vol.Length(min=68, max=68))
|
||||
)
|
||||
|
||||
REAL_TIME_DATA_SCHEMA = vol.Schema({
|
||||
vol.Required('method'): cv.string,
|
||||
vol.Required('version'): cv.string,
|
||||
vol.Required('type'): cv.string,
|
||||
vol.Required('SN'): cv.string,
|
||||
vol.Required('Data'): DATA_SCHEMA,
|
||||
vol.Required('Status'): cv.positive_int,
|
||||
}, extra=vol.REMOVE_EXTRA)
|
||||
|
||||
|
||||
class SolaxRequestError(Exception):
|
||||
"""Error to indicate a Solax API request has failed."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities,
|
||||
discovery_info=None):
|
||||
"""Platform setup."""
|
||||
endpoint = RealTimeDataEndpoint(hass, config.get(CONF_IP_ADDRESS))
|
||||
import solax
|
||||
|
||||
api = solax.solax.RealTimeAPI(config.get(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 INVERTER_SENSORS:
|
||||
devices.append(Inverter(sensor))
|
||||
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)
|
||||
|
||||
|
||||
async def async_solax_real_time_request(hass, schema, ip_address, retry,
|
||||
t_wait=0):
|
||||
"""Make call to inverter endpoint."""
|
||||
if t_wait > 0:
|
||||
msg = "Timeout connecting to Solax inverter, waiting %d to retry."
|
||||
_LOGGER.error(msg, t_wait)
|
||||
asyncio.sleep(t_wait)
|
||||
new_wait = (t_wait*2)+5
|
||||
retry = retry - 1
|
||||
try:
|
||||
session = async_get_clientsession(hass)
|
||||
|
||||
with async_timeout.timeout(REQUEST_TIMEOUT, loop=hass.loop):
|
||||
url = REAL_TIME_DATA_ENDPOINT.format(ip_address=ip_address)
|
||||
req = await session.get(url)
|
||||
garbage = await req.read()
|
||||
formatted = garbage.decode("utf-8")
|
||||
formatted = formatted.replace(",,", ",0.0,").replace(",,", ",0.0,")
|
||||
json_response = json.loads(formatted)
|
||||
return schema(json_response)
|
||||
except asyncio.TimeoutError:
|
||||
if retry > 0:
|
||||
return await async_solax_real_time_request(hass,
|
||||
schema,
|
||||
ip_address,
|
||||
retry,
|
||||
new_wait)
|
||||
_LOGGER.error("Too many timeouts connecting to Solax.")
|
||||
except (aiohttp.ClientError) as client_err:
|
||||
_LOGGER.error("Could not connect to Solax API endpoint")
|
||||
_LOGGER.error(client_err)
|
||||
except ValueError:
|
||||
_LOGGER.error("Received non-JSON data from Solax API endpoint")
|
||||
except vol.Invalid as err:
|
||||
_LOGGER.error("Received unexpected JSON from Solax"
|
||||
" API endpoint: %s", err)
|
||||
_LOGGER.error(json_response)
|
||||
raise SolaxRequestError
|
||||
|
||||
|
||||
def parse_solax_battery_response(response):
|
||||
"""Manipulate the response from solax endpoint."""
|
||||
data_list = response['Data']
|
||||
result = {}
|
||||
for name, index in INVERTER_SENSORS.items():
|
||||
response_index = index[0]
|
||||
result[name] = data_list[response_index]
|
||||
return result
|
||||
|
||||
|
||||
class RealTimeDataEndpoint:
|
||||
"""Representation of a Sensor."""
|
||||
|
||||
def __init__(self, hass, ip_address):
|
||||
def __init__(self, hass, api):
|
||||
"""Initialize the sensor."""
|
||||
self.hass = hass
|
||||
self.ip_address = ip_address
|
||||
self.api = api
|
||||
self.data = {}
|
||||
self.ready = asyncio.Event()
|
||||
self.sensors = []
|
||||
@@ -167,11 +61,7 @@ class RealTimeDataEndpoint:
|
||||
This is the only method that should fetch new data for Home Assistant.
|
||||
"""
|
||||
try:
|
||||
resp = await async_solax_real_time_request(self.hass,
|
||||
REAL_TIME_DATA_SCHEMA,
|
||||
self.ip_address,
|
||||
3)
|
||||
self.data = parse_solax_battery_response(resp)
|
||||
self.data = await self.api.get_data()
|
||||
self.ready.set()
|
||||
except SolaxRequestError:
|
||||
if now is not None:
|
||||
@@ -187,10 +77,11 @@ class RealTimeDataEndpoint:
|
||||
class Inverter(Entity):
|
||||
"""Class for a sensor."""
|
||||
|
||||
def __init__(self, key):
|
||||
def __init__(self, key, unit):
|
||||
"""Initialize an inverter sensor."""
|
||||
self.key = key
|
||||
self.value = None
|
||||
self.unit = unit
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
@@ -205,7 +96,7 @@ class Inverter(Entity):
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement."""
|
||||
return INVERTER_SENSORS[self.key][1]
|
||||
return self.unit
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
|
@@ -1595,6 +1595,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
|
||||
|
||||
|
@@ -124,6 +124,7 @@ TEST_REQUIREMENTS = (
|
||||
'simplisafe-python',
|
||||
'sleepyq',
|
||||
'smhi-pkg',
|
||||
'solax'
|
||||
'somecomfort',
|
||||
'sqlalchemy',
|
||||
'srpenergy',
|
||||
|
Reference in New Issue
Block a user