From d5eb7a500dce97b44d3862aa30d80606e5523263 Mon Sep 17 00:00:00 2001 From: MarkusBiggus <6531552+MarkusBiggus@users.noreply.github.com> Date: Tue, 3 Dec 2024 08:03:49 +1000 Subject: [PATCH 1/4] tweek --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cf40bf9..51c68ea 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ Install this wrapper package with sonnen_api_v2 package to use Home Assistant cu sonnen_api_v2 uses only the API read token from sonnen batterie admin portal. Differs from weltmeter package in that it does not use the default user login older batterie's have setup. There are no API V1 calls, response is faked using API V2 results. -Notably, serial number and model number are not avaiable from any API V2 endpoint. + +Notably, serial number and model number are not available from any API V2 endpoint. pip install "git+https://github.com/MarkusBiggus/sonnen_api_v2.git" From 433c9c67391c5d6a9d2d0bb304512f3074154450 Mon Sep 17 00:00:00 2001 From: MarkusBiggus <6531552+MarkusBiggus@users.noreply.github.com> Date: Tue, 3 Dec 2024 08:06:17 +1000 Subject: [PATCH 2/4] tweek --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 51c68ea..11c6df9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ -# python_sonnenbatterie compatible (readonly) wrapper for python_sonnnen_api_v2 +# python_sonnenbatterie compatible (readonly) wrapper for package sonnnen_api_v2 Install this wrapper package with sonnen_api_v2 package to use Home Assistant custom component "sonnenbatterie" by weltmeyer. -sonnen_api_v2 uses only the API read token from sonnen batterie admin portal. Differs from weltmeter package in that it does not use the default user login older batterie's have setup. +sonnen_api_v2 uses only the API read token from sonnen batterie admin portal. + +Differs from weltmeter package in that it does not use the default user login setup in older batteries. + There are no API V1 calls, response is faked using API V2 results. Notably, serial number and model number are not available from any API V2 endpoint. From 3e54cec79441d05a6c2db81df380dd35b4a7e8a8 Mon Sep 17 00:00:00 2001 From: MarkusBiggus <6531552+MarkusBiggus@users.noreply.github.com> Date: Tue, 3 Dec 2024 18:07:07 +1000 Subject: [PATCH 3/4] expose methods --- sonnenbatterie/__init__.py | 33 ++++++++++++++++++++++++++++++++ sonnenbatterie/const.py | 8 ++++---- sonnenbatterie/sonnenbatterie.py | 3 ++- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/sonnenbatterie/__init__.py b/sonnenbatterie/__init__.py index cf4cc49..30fd452 100644 --- a/sonnenbatterie/__init__.py +++ b/sonnenbatterie/__init__.py @@ -1,2 +1,35 @@ """ SonnenBatterie API V2 component """ from .sonnenbatterie import sonnenbatterie +__all__ = ( + "set_login_timeout", + "get_login_timeout", + "set_request_connect_timeout", + "get_request_connect_timeout", + "set_request_read_timeout", + "get_request_read_timeout", + "get_powermeter", + "get_batterysystem", + "get_inverter", + "get_systemdata", + "get_status", + "get_battery", + "get_latest_data", + "get_configurations", + "get_configuration", + "get_current_charge_level", + "get_operating_mode", + "get_operating_mode_name", + "get_battery_reserve", + "get_time_of_use_schedule_as_string", + "get_time_of_use_schedule_as_json_objects", + "get_time_of_use_schedule_as_schedule", + "set_manual_flowrate", + "set_discharge", + "set_charge", + "set_configuration", + "set_operating_mode", + "set_operating_mode_by_name", + "set_battery_reserve", + "set_battery_reserve_relative_to_currentCharge", + "set_time_of_use_schedule_from_json_objects", +) diff --git a/sonnenbatterie/const.py b/sonnenbatterie/const.py index 5321724..261b227 100644 --- a/sonnenbatterie/const.py +++ b/sonnenbatterie/const.py @@ -1,6 +1,4 @@ -from datetime import time -#from requests import Timeout - +import logging DEFAULT_BATTERY_LOGIN_TIMEOUT=120 DEFAULT_CONNECT_TO_BATTERY_TIMEOUT=60 @@ -32,4 +30,6 @@ SONNEN_API_PATH_BATTERY="battery" SONNEN_CHARGE_PATH="charge" -SONNEN_DISCHARGE_PATH="discharge" \ No newline at end of file +SONNEN_DISCHARGE_PATH="discharge" + +LOGGER = logging.getLogger(__package__) diff --git a/sonnenbatterie/sonnenbatterie.py b/sonnenbatterie/sonnenbatterie.py index 9f98b21..51e0296 100644 --- a/sonnenbatterie/sonnenbatterie.py +++ b/sonnenbatterie/sonnenbatterie.py @@ -17,7 +17,7 @@ class sonnenbatterie: - def __init__(self,username,token,ipaddress) -> None: + def __init__(self, username, token, ipaddress) -> None: # self.username=username self.token=token self.ipaddress=ipaddress @@ -29,6 +29,7 @@ def __init__(self,username,token,ipaddress) -> None: # self._batteryRequestTimeout = (self._batteryConnectTimeout, self._batteryReadTimeout) self._batteryRequestTimeout = (DEFAULT_CONNECT_TO_BATTERY_TIMEOUT, DEFAULT_READ_FROM_BATTERY_TIMEOUT) self.batterie = Batterie(self.token, self.ipaddress) +# LOGGER.error(f'Unable to connect to sonnenbatterie: {e}') self.batterie.set_request_connect_timeouts(self._batteryRequestTimeout) self._battery_serial_number = os.getenv("BATTERIE_SN", "unknown") self._battery_model = os.getenv("BATTERIE_MODEL", "unknown") From aed655c40d6611f5ce8ece63406b630afb203494 Mon Sep 17 00:00:00 2001 From: MarkusBiggus <6531552+MarkusBiggus@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:55:28 +1000 Subject: [PATCH 4/4] refactored some responsibilities and mock data - all tests pass --- sonnenbatterie/__init__.py | 2 +- sonnenbatterie/sonnenbatterie.py | 76 +++++- test/mock_battery.py | 32 --- test/mock_configurations.py | 25 -- test/mock_inverter.py | 18 -- test/mock_powermeter.py | 49 ---- test/mock_sonnenbatterie_v2_charging.py | 257 ++++++++++++++++++ ...nenbatterie_v2_charging.py:Zone.Identifier | 2 + ... => mock_sonnenbatterie_v2_discharging.py} | 56 +++- test/mock_status_charging.py | 34 --- test/test_battery_devinfo.py | 3 +- test/test_battery_mock.py | 19 +- 12 files changed, 374 insertions(+), 199 deletions(-) delete mode 100644 test/mock_battery.py delete mode 100644 test/mock_configurations.py delete mode 100644 test/mock_inverter.py delete mode 100644 test/mock_powermeter.py create mode 100644 test/mock_sonnenbatterie_v2_charging.py create mode 100644 test/mock_sonnenbatterie_v2_charging.py:Zone.Identifier rename test/{mock_latest_charging.py => mock_sonnenbatterie_v2_discharging.py} (73%) delete mode 100644 test/mock_status_charging.py diff --git a/sonnenbatterie/__init__.py b/sonnenbatterie/__init__.py index 30fd452..21f9577 100644 --- a/sonnenbatterie/__init__.py +++ b/sonnenbatterie/__init__.py @@ -1,4 +1,4 @@ -""" SonnenBatterie API V2 component """ +""" SonnenBatterie API V2 package """ from .sonnenbatterie import sonnenbatterie __all__ = ( "set_login_timeout", diff --git a/sonnenbatterie/sonnenbatterie.py b/sonnenbatterie/sonnenbatterie.py index 51e0296..ba31959 100644 --- a/sonnenbatterie/sonnenbatterie.py +++ b/sonnenbatterie/sonnenbatterie.py @@ -1,22 +1,20 @@ -import os +#import os +#from dotenv import load_dotenv #import hashlib +from typing import Union import requests import json -# pylint: disable=unused-wildcard-import from .const import * -# pylint: enable=unused-wildcard-import from .timeofuse import timeofuseschedule -from sonnen_api_v2.sonnen import Sonnen as Batterie -from dotenv import load_dotenv +from sonnen_api_v2.sonnen import Sonnen as Batterie, BatterieError # indexes for _batteryRequestTimeout TIMEOUT_CONNECT=0 TIMEOUT_REQUEST=1 -load_dotenv() +#load_dotenv() class sonnenbatterie: - def __init__(self, username, token, ipaddress) -> None: # self.username=username self.token=token @@ -29,10 +27,13 @@ def __init__(self, username, token, ipaddress) -> None: # self._batteryRequestTimeout = (self._batteryConnectTimeout, self._batteryReadTimeout) self._batteryRequestTimeout = (DEFAULT_CONNECT_TO_BATTERY_TIMEOUT, DEFAULT_READ_FROM_BATTERY_TIMEOUT) self.batterie = Batterie(self.token, self.ipaddress) -# LOGGER.error(f'Unable to connect to sonnenbatterie: {e}') + batterie_status = self.batterie.get_status() + if batterie_status is False: + LOGGER.error('Unable to connect to sonnenbatterie!') + raise BatterieError('Unable to connect to sonnenbatterie!') self.batterie.set_request_connect_timeouts(self._batteryRequestTimeout) - self._battery_serial_number = os.getenv("BATTERIE_SN", "unknown") - self._battery_model = os.getenv("BATTERIE_MODEL", "unknown") + self._battery_serial_number = 'unknown' #os.getenv("BATTERIE_SN", "unknown") + self._battery_model = 'unknown' #os.getenv("BATTERIE_MODEL", "unknown") # self._login() @@ -143,10 +144,6 @@ def get_powermeter(self): # return self._get(SONNEN_API_PATH_POWER_METER) return self.batterie.get_powermeter() - def get_batterysystem(self): - '''battery_system not in V2 - fake it for required component attributes''' - return self.batterie.get_batterysystem() - def get_inverter(self): # return self._get(SONNEN_API_PATH_INVERTER) return self.batterie.get_inverter() @@ -161,13 +158,62 @@ def get_systemdata(self): # return self._get(SONNEN_API_PATH_SYSTEM_DATA) return systemdata + def get_batterysystem(self)-> Union[str, bool]: + """battery_system not in V2 - fake it for required component attributes""" + + configurations_data = self.batterie.get_configurations() + if configurations_data is None: + return None + systemdata = {'modules': + configurations_data.get('IC_BatteryModules'), + 'battery_system': + { + 'system': + { + 'storage_capacity_per_module': configurations_data.get('CM_MarketingModuleCapacity'), + 'depthofdischargelimit': configurations_data.get('DepthOfDischargeLimit'), + } + } + + } + return systemdata + def get_status(self): # return self._get(SONNEN_API_PATH_STATUS) return self.batterie.get_status() def get_battery(self): + """Battery status for sonnenbatterie wrapper + Fake V1 API data used by ha sonnenbatterie component + Returns: + json response + """ # return self._get(SONNEN_API_PATH_BATTERY) - return self.batterie.get_battery() + battery_status = self.batterie.get_battery() + + configurations_data = self.batterie.get_configurations() + if configurations_data is None: + return None + + """ current_state index of: ["standby", "charging", "discharging", "charged", "discharged"] """ + if self.batterie.status_battery_charging: + battery_status['current_state'] = "charging" + elif self.batterie.status_battery_discharging: + battery_status['current_state'] = "discharging" + elif self.batterie.battery_rsoc > 98: + battery_status['current_state'] = "charged" + elif self.batterie.battery_usable_remaining_capacity < 2: + battery_status['current_state'] = "discharged" + else: + battery_status['current_state'] = "standby" + + measurements = {'battery_status': {'cyclecount': self.batterie.battery_cycle_count, + 'stateofhealth': int(battery_status.get('systemstatus')) + } + } + battery_status['measurements'] = measurements + + return battery_status def get_latest_data(self): # return self._get(SONNEN_API_PATH_LATEST_DATA) diff --git a/test/mock_battery.py b/test/mock_battery.py deleted file mode 100644 index 46faebd..0000000 --- a/test/mock_battery.py +++ /dev/null @@ -1,32 +0,0 @@ -import json -def mock_battery()-> json: - return { - "balancechargerequest":0.0, - "chargecurrentlimit":39.97, - "cyclecount":30.0, - "dischargecurrentlimit":39.97, - "fullchargecapacity":201.98, - "fullchargecapacitywh":20683.490, - "maximumcelltemperature":19.95, - "maximumcellvoltage":3.257, - "maximumcellvoltagenum":0.0, - "maximummodulecurrent":0.0, - "maximummoduledcvoltage":104.15, - "maximummoduletemperature":-273.15, - "minimumcelltemperature":18.95, - "minimumcellvoltage":3.251, - "minimumcellvoltagenum":0.0, - "minimummodulecurrent":0.0, - "minimummoduledcvoltage":104.15, - "minimummoduletemperature":-273.15, - "nominalmoduledcvoltage":102.4, - "relativestateofcharge":98.0, - "remainingcapacity":197.94, - "systemalarm":0.0, - "systemcurrent":0.0, - "systemdcvoltage":208.3, - "systemstatus":49.0, - "systemtime":0.0, - "systemwarning":0.0, - "usableremainingcapacity":183.80 - } \ No newline at end of file diff --git a/test/mock_configurations.py b/test/mock_configurations.py deleted file mode 100644 index ab7a783..0000000 --- a/test/mock_configurations.py +++ /dev/null @@ -1,25 +0,0 @@ -import json -def mock_configurations()-> json: -# Economical Charging (default) - return { - "EM_RE_ENABLE_MICROGRID": 'False', - "NVM_PfcIsFixedCosPhiActive": 0, - "NVM_PfcFixedCosPhi": 0.8, - "IC_BatteryModules": 4, - "EM_ToU_Schedule": [], - "DE_Software":"1.14.5", - "EM_USER_INPUT_TIME_ONE": 0, - "NVM_PfcIsFixedCosPhiLagging": 0, - "EM_Prognosis_Charging": 1, - "EM_USOC": 20, - "EM_USER_INPUT_TIME_TWO": 0, - "EM_OperatingMode": "2", - "SH_HeaterTemperatureMax": 80, - "SH_HeaterOperatingMode": 0, - "IC_InverterMaxPower_w": 5000, - "SH_HeaterTemperatureMin": 0 , - "CM_MarketingModuleCapacity": 5000, - "EM_USER_INPUT_TIME_THREE": 0, - "CN_CascadingRole": "none", - "EM_US_GEN_POWER_SET_POINT": 0 - } \ No newline at end of file diff --git a/test/mock_inverter.py b/test/mock_inverter.py deleted file mode 100644 index a32e3f9..0000000 --- a/test/mock_inverter.py +++ /dev/null @@ -1,18 +0,0 @@ -import json -def mock_inverter()-> json: - return { - "fac": 0.0, - "iac_total": 0.39, - "ibat": 0.01, - "ipv": 0.0, - "pac_microgrid": 0.0, - "pac_total": -1394.33, - "pbat": -0.14, - "phi": -0.82, - "ppv": 0.0, - "sac_total": 0.0, - "tmax": 55.53, - "uac": 233.55, - "ubat": 209.18, - "upv": 0.0 - } \ No newline at end of file diff --git a/test/mock_powermeter.py b/test/mock_powermeter.py deleted file mode 100644 index 1799240..0000000 --- a/test/mock_powermeter.py +++ /dev/null @@ -1,49 +0,0 @@ -import json -def mock_powermeter()-> json: - return [ - { - 'a_l1': 2.4730000495910645, 'a_l2': 0, - 'a_l3': 0, - 'channel': 1, - 'deviceid': 4, - 'direction': 'production', - 'error': 0, - 'kwh_exported': 0, - 'kwh_imported': 3969.800048828125, - 'v_l1_l2': 0, - 'v_l1_n': 246.60000610351562, - 'v_l2_l3': 0, - 'v_l2_n': 0, - 'v_l3_l1': 0, - 'v_l3_n': 0, - 'va_total': 609.5, - 'var_total': 0, - 'w_l1': 609.5, - 'w_l2': 0, - 'w_l3': 0, - 'w_total': 609.5 - }, - { - 'a_l1': 2.0929999351501465, - 'a_l2': 0, - 'a_l3': 0, - 'channel': 2, - 'deviceid': 4, - 'direction': 'consumption', - 'error': 0, - 'kwh_exported': 0, - 'kwh_imported': 816.5, - 'v_l1_l2': 0, - 'v_l1_n': 246.6999969482422, - 'v_l2_l3': 0, - 'v_l2_n': 0, - 'v_l3_l1': 0, - 'v_l3_n': 0, - 'va_total': 516.2000122070312, - 'var_total': -512.7999877929688, - 'w_l1': 59.29999923706055, - 'w_l2': 0, - 'w_l3': 0, - 'w_total': 59.29999923706055 - } - ] \ No newline at end of file diff --git a/test/mock_sonnenbatterie_v2_charging.py b/test/mock_sonnenbatterie_v2_charging.py new file mode 100644 index 0000000..0dd8387 --- /dev/null +++ b/test/mock_sonnenbatterie_v2_charging.py @@ -0,0 +1,257 @@ +"""Mock batterie data also used in package sonnenbatterie_api_v2 & ha component sonnenenbatterie""" +import json +def __mock_status_charging()-> json: + return { + 'Apparent_output': 98, + 'BackupBuffer': '20', + 'BatteryCharging': True, + 'BatteryDischarging': False, + 'Consumption_Avg': 486, + 'Consumption_W': 403, + 'Fac': 50.05781555175781, + 'FlowConsumptionBattery': False, + 'FlowConsumptionGrid': False, + 'FlowConsumptionProduction': True, + 'FlowGridBattery': False, + 'FlowProductionBattery': True, + 'FlowProductionGrid': True, + 'GridFeedIn_W': 54, + 'IsSystemInstalled': 1, + 'OperatingMode': '2', + 'Pac_total_W': -95, + 'Production_W': 578, + 'RSOC': 98, + 'RemainingCapacity_Wh': 68781, + 'Sac1': 98, + 'Sac2': None, + 'Sac3': None, + 'SystemStatus': 'OnGrid', + 'Timestamp': '2022-04-30 17:00:58', + 'USOC': 98, + 'Uac': 245, + 'Ubat': 212, + 'dischargeNotAllowed': False, + 'generator_autostart': False + } + +def __mock_configurations()-> json: +# Economical Charging (default) + return { + "EM_RE_ENABLE_MICROGRID": 'False', + "NVM_PfcIsFixedCosPhiActive": 0, + "NVM_PfcFixedCosPhi": 0.8, + "IC_BatteryModules": 4, + "EM_ToU_Schedule": [], + "DE_Software":"1.14.5", + "EM_USER_INPUT_TIME_ONE": 0, + "NVM_PfcIsFixedCosPhiLagging": 0, + "EM_Prognosis_Charging": 1, + "EM_USOC": 20, + "EM_USER_INPUT_TIME_TWO": 0, + "EM_OperatingMode": "2", + "SH_HeaterTemperatureMax": 80, + "SH_HeaterOperatingMode": 0, + "IC_InverterMaxPower_w": 5000, + "SH_HeaterTemperatureMin": 0 , + "CM_MarketingModuleCapacity": 5000, + "EM_USER_INPUT_TIME_THREE": 0, + "CN_CascadingRole": "none", + "EM_US_GEN_POWER_SET_POINT": 0, + "DepthOfDischargeLimit" : 7 + } + +def __mock_battery()-> json: + return { + "balancechargerequest":0.0, + "chargecurrentlimit":39.97, + "cyclecount":30.0, + "dischargecurrentlimit":39.97, + "fullchargecapacity":201.98, + "fullchargecapacitywh":20683.490, + "maximumcelltemperature":19.95, + "maximumcellvoltage":3.257, + "maximumcellvoltagenum":0.0, + "maximummodulecurrent":0.0, + "maximummoduledcvoltage":104.15, + "maximummoduletemperature":-273.15, + "minimumcelltemperature":18.95, + "minimumcellvoltage":3.251, + "minimumcellvoltagenum":0.0, + "minimummodulecurrent":0.0, + "minimummoduledcvoltage":104.15, + "minimummoduletemperature":-273.15, + "nominalmoduledcvoltage":102.4, + "relativestateofcharge":98.0, + "remainingcapacity":197.94, + "systemalarm":0.0, + "systemcurrent":0.0, + "systemdcvoltage":208.3, + "systemstatus":49.0, + "systemtime":0.0, + "systemwarning":0.0, + "usableremainingcapacity":183.80 + } + +def __mock_latest_charging()-> json: + return { + 'FullChargeCapacity': 20683.490, + 'GridFeedIn_W': 0, + 'Production_W': 2972, + 'Consumption_W': 1578, + 'Pac_total_W': -1394, + 'RSOC': 98, + 'SetPoint_W': -145, + 'Timestamp': '2022-04-30 17:00:58', + 'USOC': 98, + 'UTC_Offet': 2, + 'ic_status': { + 'DC Shutdown Reason': { + 'Critical BMS Alarm': False, + 'Electrolyte Leakage': False, + 'Error condition in BMS initialization': False, + 'HW_Shutdown': False, + 'HardWire Over Voltage': False, + 'HardWired Dry Signal A': False, + 'HardWired Under Voltage': False, + 'Holding Circuit Error': False, + 'Initialization Timeout': False, + 'Initialization of AC contactor failed': False, + 'Initialization of BMS hardware failed': False, + 'Initialization of DC contactor failed': False, + 'Initialization of Inverter failed': False, + 'Invalid or no SystemType was set': False, + 'Inverter Over Temperature': False, + 'Inverter Under Voltage': False, + 'Inverter Version Too Low For Dc-Module': False, + 'Manual shutdown by user': False, + 'Minimum rSOC of System reached': False, + 'Modules voltage out of range': False, + 'No Setpoint received by HC': False, + 'Odd number of battery modules': False, + 'One single module detected and module voltage is out of range': False, + 'Only one single module detected': False, + 'Shutdown Timer started': False, + 'System Validation failed': False, + 'Voltage Monitor Changed': False + }, + 'Eclipse Led': { + 'Blinking Red': False, + 'Pulsing Green': False, + 'Pulsing Orange': False, + 'Pulsing White': True, + 'Solid Red': False + }, + 'MISC Status Bits': { + 'Discharge not allowed': False, + 'F1 open': False, + 'Min System SOC': False, + 'Min User SOC': False, + 'Setpoint Timeout': False + }, + 'Microgrid Status': { + 'Continious Power Violation': False, + 'Discharge Current Limit Violation': False, + 'Low Temperature': False, + 'Max System SOC': False, + 'Max User SOC': False, + 'Microgrid Enabled': False, + 'Min System SOC': False, + 'Min User SOC': False, + 'Over Charge Current': False, + 'Over Discharge Current': False, + 'Peak Power Violation': False, + 'Protect is activated': False, + 'Transition to Ongrid Pending': False + }, + 'Setpoint Priority': { + 'BMS': False, + 'Energy Manager': True, + 'Full Charge Request': False, + 'Inverter': False, + 'Min User SOC': False, + 'Trickle Charge': False + }, + 'System Validation': { + 'Country Code Set status flag 1': False, + 'Country Code Set status flag 2': False, + 'Self test Error DC Wiring': False, + 'Self test Postponed': False, + 'Self test Precondition not met': False, + 'Self test Running': False, + 'Self test successful finished': False + }, + 'nrbatterymodules': 4, + 'secondssincefullcharge': 3720, + 'statebms': 'ready', + 'statecorecontrolmodule': 'ongrid', + 'stateinverter': 'running', + 'timestamp': 'Sat Apr 30 17:00:57 2022' + } + } + +def __mock_powermeter()-> json: + return [ + { + 'a_l1': 2.4730000495910645, 'a_l2': 0, + 'a_l3': 0, + 'channel': 1, + 'deviceid': 4, + 'direction': 'production', + 'error': 0, + 'kwh_exported': 0, + 'kwh_imported': 3969.800048828125, + 'v_l1_l2': 0, + 'v_l1_n': 246.60000610351562, + 'v_l2_l3': 0, + 'v_l2_n': 0, + 'v_l3_l1': 0, + 'v_l3_n': 0, + 'va_total': 609.5, + 'var_total': 0, + 'w_l1': 609.5, + 'w_l2': 0, + 'w_l3': 0, + 'w_total': 609.5 + }, + { + 'a_l1': 2.0929999351501465, + 'a_l2': 0, + 'a_l3': 0, + 'channel': 2, + 'deviceid': 4, + 'direction': 'consumption', + 'error': 0, + 'kwh_exported': 0, + 'kwh_imported': 816.5, + 'v_l1_l2': 0, + 'v_l1_n': 246.6999969482422, + 'v_l2_l3': 0, + 'v_l2_n': 0, + 'v_l3_l1': 0, + 'v_l3_n': 0, + 'va_total': 516.2000122070312, + 'var_total': -512.7999877929688, + 'w_l1': 59.29999923706055, + 'w_l2': 0, + 'w_l3': 0, + 'w_total': 59.29999923706055 + } + ] + +def __mock_inverter()-> json: + return { + "fac": 0.0, + "iac_total": 0.39, + "ibat": 0.01, + "ipv": 0.0, + "pac_microgrid": 0.0, + "pac_total": -1394.33, + "pbat": -0.14, + "phi": -0.82, + "ppv": 0.0, + "sac_total": 0.0, + "tmax": 55.53, + "uac": 233.55, + "ubat": 209.18, + "upv": 0.0 + } \ No newline at end of file diff --git a/test/mock_sonnenbatterie_v2_charging.py:Zone.Identifier b/test/mock_sonnenbatterie_v2_charging.py:Zone.Identifier new file mode 100644 index 0000000..a45e1ac --- /dev/null +++ b/test/mock_sonnenbatterie_v2_charging.py:Zone.Identifier @@ -0,0 +1,2 @@ +[ZoneTransfer] +ZoneId=3 diff --git a/test/mock_latest_charging.py b/test/mock_sonnenbatterie_v2_discharging.py similarity index 73% rename from test/mock_latest_charging.py rename to test/mock_sonnenbatterie_v2_discharging.py index dbc298b..69ed40e 100644 --- a/test/mock_latest_charging.py +++ b/test/mock_sonnenbatterie_v2_discharging.py @@ -1,15 +1,49 @@ import json -def latest_charging()-> json: +def __mock_status_discharging()-> json: + return { + 'Apparent_output': 438, + 'BackupBuffer': '20', + 'BatteryCharging': False, + 'BatteryDischarging': True, + 'Consumption_Avg': 563, + 'Consumption_W': 541, + 'Fac': 50.0167121887207, + 'FlowConsumptionBattery': True, + 'FlowConsumptionGrid': False, + 'FlowConsumptionProduction': True, + 'FlowGridBattery': False, + 'FlowProductionBattery': False, + 'FlowProductionGrid': False, + 'GridFeedIn_W': -20, + 'IsSystemInstalled': 1, + 'OperatingMode': '2', + 'Pac_total_W': 438, + 'Production_W': 102, + 'RSOC': 99, + 'RemainingCapacity_Wh': 40181, + 'Sac1': 438, + 'Sac2': None, + 'Sac3': None, + 'SystemStatus': 'OnGrid', + 'Timestamp': '2022-05-06 20:24:39', + 'USOC': 99, + 'Uac': 237, + 'Ubat': 211, + 'dischargeNotAllowed': False, + 'generator_autostart': False + } + +def __mock_latest_discharging()-> json: return { 'FullChargeCapacity': 20683.490, 'GridFeedIn_W': 0, - 'Production_W': 2972, - 'Consumption_W': 1578, - 'Pac_total_W': -1394, - 'RSOC': 98, - 'SetPoint_W': -145, - 'Timestamp': '2022-04-30 17:00:58', - 'USOC': 98, + 'Pac_total_W': 1439, + 'Consumption_W': 1541, + 'Production_W': 102, + 'RSOC': 99, + 'SetPoint_W': 439, + 'Timestamp': '2022-05-06 20:24:38', + 'USOC': 99, 'UTC_Offet': 2, 'ic_status': { 'DC Shutdown Reason': { @@ -88,10 +122,10 @@ def latest_charging()-> json: 'Self test successful finished': False }, 'nrbatterymodules': 4, - 'secondssincefullcharge': 3720, + 'secondssincefullcharge': 574, 'statebms': 'ready', 'statecorecontrolmodule': 'ongrid', 'stateinverter': 'running', - 'timestamp': 'Sat Apr 30 17:00:57 2022' + 'timestamp': 'Fri May 6 20:24:36 2022' } - } \ No newline at end of file + } diff --git a/test/mock_status_charging.py b/test/mock_status_charging.py deleted file mode 100644 index 79b072b..0000000 --- a/test/mock_status_charging.py +++ /dev/null @@ -1,34 +0,0 @@ -import json -def status_charging()-> json: - return { - 'Apparent_output': 98, - 'BackupBuffer': '20', - 'BatteryCharging': True, - 'BatteryDischarging': False, - 'Consumption_Avg': 486, - 'Consumption_W': 403, - 'Fac': 50.05781555175781, - 'FlowConsumptionBattery': False, - 'FlowConsumptionGrid': False, - 'FlowConsumptionProduction': True, - 'FlowGridBattery': False, - 'FlowProductionBattery': True, - 'FlowProductionGrid': True, - 'GridFeedIn_W': 54, - 'IsSystemInstalled': 1, - 'OperatingMode': '2', - 'Pac_total_W': -95, - 'Production_W': 578, - 'RSOC': 98, - 'RemainingCapacity_Wh': 68781, - 'Sac1': 98, - 'Sac2': None, - 'Sac3': None, - 'SystemStatus': 'OnGrid', - 'Timestamp': '2022-04-30 17:00:58', - 'USOC': 98, - 'Uac': 245, - 'Ubat': 212, - 'dischargeNotAllowed': False, - 'generator_autostart': False - } \ No newline at end of file diff --git a/test/test_battery_devinfo.py b/test/test_battery_devinfo.py index b35c9bf..097a7d1 100644 --- a/test/test_battery_devinfo.py +++ b/test/test_battery_devinfo.py @@ -1,6 +1,5 @@ """Verify package sonnenbatterie V2 API used by sonnenbatterie component works.""" """pytest test/test_battery_devinfo.py -s -v -x """ - import os import pytest @@ -33,7 +32,7 @@ def test_devinfo() -> None: name=f"{DOMAIN} {system_data.get('DE_Ticket_Number', 'unknown')}" sw_version = system_data.get("software_version", "unknown") print(f"model: {model} name: {name} sw_version: {sw_version}") - assert system_data.get('DE_Ticket_Number') == '263291' + assert system_data.get('DE_Ticket_Number') == 'unknown' def test_batterysystem() -> None: _battery = sonnenbatterie( diff --git a/test/test_battery_mock.py b/test/test_battery_mock.py index 9453f30..90ee098 100644 --- a/test/test_battery_mock.py +++ b/test/test_battery_mock.py @@ -14,12 +14,7 @@ from sonnen_api_v2.sonnen import Sonnen as Batterie -from . mock_status_charging import status_charging -from . mock_latest_charging import latest_charging -from . mock_powermeter import mock_powermeter -from . mock_battery import mock_battery -from . mock_inverter import mock_inverter -from . mock_configurations import mock_configurations +from . mock_sonnenbatterie_v2_charging import __mock_status_charging, __mock_latest_charging, __mock_configurations, __mock_battery, __mock_powermeter, __mock_inverter load_dotenv() @@ -62,12 +57,12 @@ async def test_get_batterie_charging(mocker): """Batterie charging using mock data""" - mocker.patch.object(Batterie, "fetch_configurations", AsyncMock(return_value=mock_configurations())) - mocker.patch.object(Batterie, "fetch_status", AsyncMock(return_value=status_charging())) - mocker.patch.object(Batterie, "fetch_latest_details", AsyncMock(return_value=latest_charging())) - mocker.patch.object(Batterie, "fetch_powermeter", AsyncMock(return_value=mock_powermeter())) - mocker.patch.object(Batterie, "fetch_battery_status", AsyncMock(return_value=mock_battery())) - mocker.patch.object(Batterie, "fetch_inverter_data", AsyncMock(return_value=mock_inverter())) + mocker.patch.object(Batterie, "fetch_configurations", AsyncMock(return_value=__mock_configurations())) + mocker.patch.object(Batterie, "fetch_status", AsyncMock(return_value=__mock_status_charging())) + mocker.patch.object(Batterie, "fetch_latest_details", AsyncMock(return_value=__mock_latest_charging())) + mocker.patch.object(Batterie, "fetch_powermeter", AsyncMock(return_value=__mock_powermeter())) + mocker.patch.object(Batterie, "fetch_battery_status", AsyncMock(return_value=__mock_battery())) + mocker.patch.object(Batterie, "fetch_inverter_data", AsyncMock(return_value=__mock_inverter())) _battery = Batterie(API_READ_TOKEN, BATTERIE_HOST, BATTERIE_PORT, LOGGER_NAME) # Batterie online