diff --git a/custom_components/solaredgeoptimizers/config_flow.py b/custom_components/solaredgeoptimizers/config_flow.py index cc525ff..fc512c2 100644 --- a/custom_components/solaredgeoptimizers/config_flow.py +++ b/custom_components/solaredgeoptimizers/config_flow.py @@ -16,14 +16,13 @@ _LOGGER = logging.getLogger(__name__) - STEP_USER_DATA_SCHEMA = vol.Schema( - { - vol.Required("siteid"): str, - vol.Required("username"): str, - vol.Required("password"): str, - } -) + { + vol.Required("siteid"): str, + vol.Required("username"): str, + vol.Required("password"): str, + } + ) class SolarEdgeWebAuth: diff --git a/custom_components/solaredgeoptimizers/const.py b/custom_components/solaredgeoptimizers/const.py index efa38c7..8321df0 100644 --- a/custom_components/solaredgeoptimizers/const.py +++ b/custom_components/solaredgeoptimizers/const.py @@ -20,9 +20,11 @@ SENSOR_TYPE_OPT_VOLTAGE = "Optimizer_voltage" SENSOR_TYPE_POWER = "Power" SENSOR_TYPE_VOLTAGE = "Voltage" +SENSOR_TYPE_ENERGY = "Lifetime_energy" SENSOR_TYPE = [ SENSOR_TYPE_CURRENT, SENSOR_TYPE_OPT_VOLTAGE, SENSOR_TYPE_POWER, SENSOR_TYPE_VOLTAGE, + SENSOR_TYPE_ENERGY, ] diff --git a/custom_components/solaredgeoptimizers/manifest.json b/custom_components/solaredgeoptimizers/manifest.json index eb6dc94..f4200fb 100644 --- a/custom_components/solaredgeoptimizers/manifest.json +++ b/custom_components/solaredgeoptimizers/manifest.json @@ -13,5 +13,5 @@ "@proudelm" ], "iot_class": "cloud_polling", - "version": "1.0.4" + "version": "1.1.0" } diff --git a/custom_components/solaredgeoptimizers/sensor.py b/custom_components/solaredgeoptimizers/sensor.py index d2b3580..718e6d3 100644 --- a/custom_components/solaredgeoptimizers/sensor.py +++ b/custom_components/solaredgeoptimizers/sensor.py @@ -1,5 +1,6 @@ """Platform for sensor integration.""" from homeassistant.helpers.entity import DeviceInfo +import json from homeassistant.components.sensor import ( SensorDeviceClass, @@ -15,6 +16,7 @@ POWER_WATT, ELECTRIC_POTENTIAL_VOLT, ELECTRIC_CURRENT_AMPERE, + ENERGY_KILO_WATT_HOUR, ) from .solaredgeoptimizers import ( @@ -34,6 +36,7 @@ SENSOR_TYPE_CURRENT, SENSOR_TYPE_POWER, SENSOR_TYPE_VOLTAGE, + SENSOR_TYPE_ENERGY, ) import logging @@ -41,6 +44,8 @@ _LOGGER = logging.getLogger(__name__) +temp_paneel = None + async def async_setup_entry( hass: HomeAssistant, @@ -51,6 +56,8 @@ async def async_setup_entry( # Add the needed sensors to hass client = hass.data[DOMAIN][entry.entry_id][DATA_API_CLIENT] + # entry.data["paneel"] = "boe" + # panelen = await hass.async_add_executor_job(client.requestAllData) site = await hass.async_add_executor_job(client.requestListOfAllPanels) @@ -76,15 +83,15 @@ async def async_setup_entry( client.requestSystemData, optimizer.optimizerId ) if info is not None: - for sensortype in SENSOR_TYPE: - async_add_entities( - [ - SolarEdgeOptimizersSensor( - client, entry, info, sensortype, optimizer - ) - ], - update_before_add=False, - ) + for sensortype in SENSOR_TYPE: + async_add_entities( + [ + SolarEdgeOptimizersSensor( + hass, client, entry, info, sensortype, optimizer + ) + ], + update_before_add=False, + ) _LOGGER.info( "Done adding all optimizers. Now adding sensors, this may take some time!" @@ -98,12 +105,14 @@ class SolarEdgeOptimizersSensor(SensorEntity): def __init__( self, + hass: HomeAssistant, client: solaredgeoptimizers, entry: ConfigEntry, paneel: SolarEdgeOptimizerData, sensortype, optimizer: SolarlEdgeOptimizer, ) -> None: + self._hass = hass self._client = client self._entry = entry self._paneelobject = paneel @@ -129,6 +138,9 @@ def __init__( elif self._sensor_type is SENSOR_TYPE_POWER: self._attr_native_unit_of_measurement = POWER_WATT self._attr_device_class = SensorDeviceClass.POWER + elif self._sensor_type is SENSOR_TYPE_ENERGY: + self._attr_native_unit_of_measurement = ENERGY_KILO_WATT_HOUR + self._attr_device_class = SensorDeviceClass.ENERGY @property def device_info(self): @@ -146,27 +158,68 @@ def device_info(self): def update(self): """ddd""" - paneel_info = "" - - try: - paneel_info = self._client.requestSystemData(self._paneelobject.paneel_id) - except Exception as err: - _LOGGER.error( - "Error updating data for panel: %s", self._paneelobject.paneel_id - ) - raise err - - # print(paneel_info) - # {'Current [A]': '7.47', 'Optimizer Voltage [V]': '39.75', 'Power [W]': '253.00', 'Voltage [V]': '33.88'} + global temp_paneel + waarde = "" - if self._sensor_type is SENSOR_TYPE_VOLTAGE: - waarde = paneel_info.voltage - elif self._sensor_type is SENSOR_TYPE_CURRENT: - waarde = paneel_info.current - elif self._sensor_type is SENSOR_TYPE_OPT_VOLTAGE: - waarde = paneel_info.optimizer_voltage - elif self._sensor_type is SENSOR_TYPE_POWER: - waarde = paneel_info.power + # Voor totaal energie moeten we wat anders doen + if self._sensor_type is SENSOR_TYPE_ENERGY: + # waarde ophalen + lifetimeenergy = json.loads(self._client.getLifeTimeEnergy()) + waarde = ( + float( + lifetimeenergy[str(self._paneelobject.paneel_id)]["unscaledEnergy"] + ) + ) / 1000 + else: + + try: + + if temp_paneel == None: + paneel_info = self._client.requestSystemData( + self._paneelobject.paneel_id + ) + temp_paneel = paneel_info + _LOGGER.info( + "Paneel data opgehaald, geheugen was leeg. Paneel {}".format( + self._paneelobject.paneel_desciption + ) + ) + elif temp_paneel.paneel_id is not self._paneelobject.paneel_id: + paneel_info = self._client.requestSystemData( + self._paneelobject.paneel_id + ) + temp_paneel = paneel_info + _LOGGER.info( + "Paneel data opgehaald, verkeerd paneel in geheugen. Paneel {}".format( + self._paneelobject.paneel_desciption + ) + ) + else: + paneel_info = temp_paneel + _LOGGER.info("Paneel data uit geheugen opgehaald") + + except Exception as err: + _LOGGER.error( + "Error updating data for panel: %s", self._paneelobject.paneel_id + ) + raise err + + # print(paneel_info) + # {'Current [A]': '7.47', 'Optimizer Voltage [V]': '39.75', 'Power [W]': '253.00', 'Voltage [V]': '33.88'} + + waarde = "" + + if paneel_info is not None: + if self._sensor_type is SENSOR_TYPE_VOLTAGE: + waarde = paneel_info.voltage + elif self._sensor_type is SENSOR_TYPE_CURRENT: + waarde = paneel_info.current + elif self._sensor_type is SENSOR_TYPE_OPT_VOLTAGE: + waarde = paneel_info.optimizer_voltage + elif self._sensor_type is SENSOR_TYPE_POWER: + waarde = paneel_info.power + else: + return self._attr_native_value = waarde diff --git a/custom_components/solaredgeoptimizers/solaredgeoptimizers.py b/custom_components/solaredgeoptimizers/solaredgeoptimizers.py index 965f9e5..d3a0c1a 100644 --- a/custom_components/solaredgeoptimizers/solaredgeoptimizers.py +++ b/custom_components/solaredgeoptimizers/solaredgeoptimizers.py @@ -3,6 +3,8 @@ import json from jsonfinder import jsonfinder import logging +from requests import Session + _LOGGER = logging.getLogger(__name__) # from requests.auth import HTTPBasicAuth @@ -53,11 +55,15 @@ def requestSystemData(self, itemId): if r.status_code == 200: json_object = decodeResult(r.text) - if json_object["lastMeasurementDate"] == "": - _LOGGER.info("Skipping optimizer %s without measurements", itemId) - return None - else: - return SolarEdgeOptimizerData(itemId, json_object) + try: + if json_object["lastMeasurementDate"] == "": + _LOGGER.info("Skipping optimizer %s without measurements", itemId) + return None + else: + return SolarEdgeOptimizerData(itemId, json_object) + except Exception as errortje: + _LOGGER.error(errortje) + return None else: print("Fout bij verzenden. Status code: {}".format(r.status_code)) print(r.text) @@ -73,10 +79,84 @@ def requestAllData(self): for optimizer in string.optimizers: info = self.requestSystemData(optimizer.optimizerId) if info is not None: - data.append(info) + data.append(info) return data + def getLifeTimeEnergy(self): + session = Session() + session.head( + "https://monitoring.solaredge.com/solaredge-apigw/api/sites/1871534/layout/energy" + ) + + url = "https://monitoring.solaredge.com/solaredge-web/p/login" + + session.auth = (self.username, self.password) + + # request a login url the get the correct cookie + r1 = session.get(url) + + # Fix the cookie to get a string. + therightcookie = self.MakeStringFromCookie(session.cookies.get_dict()) + # The csrf-token is needed as a seperate header. + thecrsftoken = self.GetThecsrfToken(session.cookies.get_dict()) + + # Build up the request. + response = session.post( + url="https://monitoring.solaredge.com/solaredge-apigw/api/sites/1871534/layout/energy?timeUnit=ALL", + headers={ + "authority": "monitoring.solaredge.com", + "accept": "*/*", + "accept-language": "en-US,en;q=0.9,nl;q=0.8", + "content-type": "application/json", + "cookie": therightcookie, + "origin": "https://monitoring.solaredge.com", + "referer": "https://monitoring.solaredge.com/solaredge-web/p/site/1871534/", + "sec-ch-ua": '"Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"', + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": '"Windows"', + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36", + "x-csrf-token": thecrsftoken, + "x-kl-ajax-request": "Ajax_Request", + "x-requested-with": "XMLHttpRequest", + }, + ) + + if response.status_code == 200: + return response.text + else: + return "ERROR - HTTP CODE: {}".format(response.status_code) + + def GetThecsrfToken(self, cookies): + for cookie in cookies: + if cookie == "CSRF-TOKEN": + return cookies[cookie] + + def MakeStringFromCookie(self, cookies): + + maincookiestring = "" + for cookie in cookies: + if cookie == "CSRF-TOKEN": + maincookiestring = ( + maincookiestring + cookie + "=" + cookies[cookie] + ";" + ) + elif cookie == "JSESSIONID": + maincookiestring = ( + maincookiestring + cookie + "=" + cookies[cookie] + ";" + ) + + maincookiestring = ( + maincookiestring + + "SolarEdge_Locale=nl_NL; SolarEdge_Locale=nl_NL; solaredge_cookie_concent=1;SolarEdge_Field_ID={}".format( + self.siteid + ) + ) + + return maincookiestring + def decodeResult(result): json_result = "" @@ -198,18 +278,36 @@ class SolarEdgeOptimizerData: """boe""" def __init__(self, paneelid, json_object): - self._json_obj = json_object # Atributen die we willen zien: - self.serialnumber = json_object["serialNumber"] - self.paneel_id = paneelid - self.paneel_desciption = json_object["description"] - self.lastmeasurement = json_object["lastMeasurementDate"] - self.model = json_object["model"] - self.manufacturer = json_object["manufacturer"] + self.serialnumber = "" + self.paneel_id = "" + self.paneel_desciption = "" + self.lastmeasurement = "" + self.model = "" + self.manufacturer = "" # Waarden - self.current = json_object["measurements"]["Current [A]"] - self.optimizer_voltage = json_object["measurements"]["Optimizer Voltage [V]"] - self.power = json_object["measurements"]["Power [W]"] - self.voltage = json_object["measurements"]["Voltage [V]"] + self.current = "" + self.optimizer_voltage = "" + self.power = "" + self.voltage = "" + + if paneelid is not None: + self._json_obj = json_object + + # Atributen die we willen zien: + self.serialnumber = json_object["serialNumber"] + self.paneel_id = paneelid + self.paneel_desciption = json_object["description"] + self.lastmeasurement = json_object["lastMeasurementDate"] + self.model = json_object["model"] + self.manufacturer = json_object["manufacturer"] + + # Waarden + self.current = json_object["measurements"]["Current [A]"] + self.optimizer_voltage = json_object["measurements"][ + "Optimizer Voltage [V]" + ] + self.power = json_object["measurements"]["Power [W]"] + self.voltage = json_object["measurements"]["Voltage [V]"]