diff --git a/api/api.py b/api/api.py index 85c9f73..33f5150 100644 --- a/api/api.py +++ b/api/api.py @@ -149,11 +149,11 @@ _API_ENDPOINTS = { "compatible_process": "power_service/v1/app/compatible/get_compatible_process", # contains solar_info plus OTA processing codes, works only with owner account "get_device_fittings": "power_service/v1/app/get_relate_device_fittings", # Device fittings for given site id and device sn. Shows Accessories like Solarbank 0W Switch info "energy_analysis": "power_service/v1/site/energy_analysis", # Fetch energy data for given time frames - "home_load_chart": "power_service/v1/site/get_home_load_chart", # Fetch data as displayed in home load chart for given site_id and optional device SN (empty if solarbank not connected) + "home_load_chart": "power_service/v1/site/get_home_load_chart", # Fetch data as displayed in home load chart for schedule adjustments for given site_id and optional device SN (empty if solarbank not connected) + "get_upgrade_record": "power_service/v1/app/get_upgrade_record", # get list of firmware update history "check_upgrade_record": "power_service/v1/app/check_upgrade_record", # show an upgrade record for the device, types 1-3 show different info, only works for owner account "get_message_unread": "power_service/v1/get_message_unread", # GET method to show if there are unread messages for account "get_message": "power_service/v1/get_message", # get list of max Messages from certain time, last_time format unknown - "get_upgrade_record": "power_service/v1/app/get_upgrade_record", # get list of firmware update history "get_mqtt_info": "app/devicemanage/get_user_mqtt_info", # get mqtt server and certificates, not explored or used } @@ -184,7 +184,7 @@ _API_ENDPOINTS = { 'power_service/v1/app/share_site/delete_inviting_member', 'power_service/v1/app/share_site/get_invited_list', 'power_service/v1/app/share_site/join_site', - 'power_service/v1/app/upgrade_event_report', + 'power_service/v1/app/upgrade_event_report', # post an entry to upgrade event report 'power_service/v1/app/get_phonecode_list', 'power_service/v1/get_message_not_disturb', # get do not disturb messages settings 'power_service/v1/message_not_disturb', # change do not disurb messages settings @@ -410,7 +410,9 @@ class RequestCounter: # limit the counter entries to 1 hour when adding new self.recycle() - def recycle(self, last_time: datetime = datetime.now() - timedelta(hours=1)) -> None: + def recycle( + self, last_time: datetime = datetime.now() - timedelta(hours=1) + ) -> None: """Remove oldest timestamps from beginning of counter until last_time is reached, default is 1 hour ago.""" self.elements = [x for x in self.elements if x > last_time] @@ -584,7 +586,7 @@ class AnkerSolixApi: self._logger.error(err) return {} - def _saveToFile(self, filename: str, data: dict = None) -> bool: + def _saveToFile(self, filename: str, data: dict | None = None) -> bool: """Save json data to given file for testing.""" if self.mask_credentials: masked_filename = filename.replace( @@ -625,9 +627,9 @@ class AnkerSolixApi: def _update_dev( # noqa: C901 self, devData: dict, - devType: str = None, - siteId: str = None, - isAdmin: bool = None, + devType: str | None = None, + siteId: str | None = None, + isAdmin: bool | None = None, ) -> str | None: """Update the internal device details dictionary with the given data. The device_sn key must be set in the data dict for the update to be applied. @@ -858,7 +860,7 @@ class AnkerSolixApi: self.devices.update({str(sn): device}) return sn - def testDir(self, subfolder: str = None) -> str: + def testDir(self, subfolder: str | None = None) -> str: """Get or set the subfolder for local API test files.""" if not subfolder or subfolder == self._testdir: return self._testdir @@ -869,35 +871,39 @@ class AnkerSolixApi: self._logger.info("Set Api test folder to: %s", subfolder) return self._testdir - def logLevel(self, level: int = None) -> int: + def logLevel(self, level: int | None = None) -> int: """Get or set the logger log level.""" if level is not None and isinstance(level, int): self._logger.setLevel(level) self._logger.info("Set log level to: %s", level) return self._logger.getEffectiveLevel() - def requestDelay(self, delay: float = None) -> float: + def requestDelay(self, delay: float | None = None) -> float: """Get or set the api request delay in seconds.""" if ( delay is not None - and isinstance(delay, (float,int)) - and delay != self._request_delay + and isinstance(delay, (float, int)) + and float(delay) != float(self._request_delay) ): - self._request_delay = min( - SolixDefaults.REQUEST_DELAY_MAX, - max(SolixDefaults.REQUEST_DELAY_MIN, delay), + self._request_delay = float( + min( + SolixDefaults.REQUEST_DELAY_MAX, + max(SolixDefaults.REQUEST_DELAY_MIN, delay), + ) ) self._logger.info( "Set api request delay to %.3f seconds", self._request_delay ) return self._request_delay - async def _wait_delay(self, delay: float = None) -> None: + async def _wait_delay(self, delay: float | None = None) -> None: """Wait at least for the defined Api request delay or for the provided delay in seconds since the last request occured.""" - if delay is not None and isinstance(delay, (float,int)): - delay = min( - SolixDefaults.REQUEST_DELAY_MAX, - max(SolixDefaults.REQUEST_DELAY_MIN, delay), + if delay is not None and isinstance(delay, (float, int)): + delay = float( + min( + SolixDefaults.REQUEST_DELAY_MAX, + max(SolixDefaults.REQUEST_DELAY_MIN, delay), + ) ) else: delay = self._request_delay @@ -934,15 +940,13 @@ class AnkerSolixApi: "%s", self.mask_values(data, "user_id", "auth_token", "email", "geo_key"), ) - self._retry_attempt = ( - False # clear retry attempt to allow retry for authentication refresh - ) + # clear retry attempt to allow retry for authentication refresh + self._retry_attempt = False else: self._logger.debug("Fetching new Login credentials from server") now = datetime.now().astimezone() - self._retry_attempt = ( - True # set retry attempt to avoid retry on failed authentication - ) + # set retry attempt to avoid retry on failed authentication + self._retry_attempt = True auth_resp = await self.request( "post", _API_LOGIN, @@ -1089,7 +1093,7 @@ class AnkerSolixApi: # get first the body text for usage in error detail logging if necessary body_text = await resp.text() data = {} - resp.raise_for_status() # any response status >= 400 + resp.raise_for_status() # any response status >= 400 if (data := await resp.json(content_type=None)) and self.encrypt_body: # TODO(#70): Test and Support optional encryption for body # data dict has to be decoded when encrypted @@ -1109,43 +1113,50 @@ class AnkerSolixApi: ) else: self._logger.debug("Response Data: %s", data) - self._retry_attempt = False # reset retry flag only when valid token received and not another login request + # reset retry flag only when valid token received and not another login request + self._retry_attempt = False - errors.raise_error(data) # check the Api response status code in the data + # check the Api response status code in the data + errors.raise_error(data) # valid response at this point, mark login and return data self._loggedIn = True return data # noqa: TRY300 - except ( - ClientError - ) as err: # Exception from ClientSession based on standard response status codes + # Exception from ClientSession based on standard response status codes + except ClientError as err: self._logger.error("Api Request Error: %s", err) self._logger.error("Response Text: %s", body_text) # Prepare data dict for Api error lookup if not data: data = {} - if not hasattr(data,"code"): + if not hasattr(data, "code"): data["code"] = resp.status - if not hasattr(data,"msg"): + if not hasattr(data, "msg"): data["msg"] = body_text - if resp.status in [401,403]: + if resp.status in [401, 403]: # Unauthorized or forbidden request - if self._retry_attempt: - errors.raise_error(data, prefix=f"Login failed for user {self._email}") - # catch error if Api code not defined - raise errors.AuthorizationError( - f"Login failed for user {self._email}" - ) from err - self._logger.warning("Login failed, retrying authentication") - if await self.async_authenticate(restart=True): - return await self.request( - method, endpoint, headers=headers, json=json - ) - self._logger.error("Re-Login failed for user %s", self._email) - elif resp.status in [429]: + # reattempt autentication with same credentials if cached token was kicked out + # retry attempt is set if login response data were not cached to fail immediately + if not self._retry_attempt: + self._logger.warning("Login failed, retrying authentication") + if await self.async_authenticate(restart=True): + return await self.request( + method, endpoint, headers=headers, json=json + ) + self._logger.error("Re-Login failed for user %s", self._email) + errors.raise_error( + data, prefix=f"Login failed for user {self._email}" + ) + # catch error if Api code not defined + raise errors.AuthorizationError( + f"Login failed for user {self._email}" + ) from err + if resp.status in [429]: # Too Many Requests, add stats to message - errors.raise_error(data, prefix=f"Too Many Requests: {self.request_count}") + errors.raise_error( + data, prefix=f"Too Many Requests: {self.request_count}" + ) else: # raise Anker Solix error if code is known errors.raise_error(data) @@ -1349,7 +1360,7 @@ class AnkerSolixApi: return self.sites async def update_site_details( - self, fromFile: bool = False, exclude: set = None + self, fromFile: bool = False, exclude: set | None = None ) -> dict: """Get the latest updates for additional site related details updated less frequently. @@ -1374,7 +1385,7 @@ class AnkerSolixApi: return self.sites async def update_device_details( - self, fromFile: bool = False, exclude: set = None + self, fromFile: bool = False, exclude: set | None = None ) -> dict: """Get the latest updates for additional device info updated less frequently. @@ -1455,7 +1466,7 @@ class AnkerSolixApi: return self.devices - async def update_device_energy(self, exclude: set = None) -> dict: + async def update_device_energy(self, exclude: set | None = None) -> dict: """Get the energy statistics for given device types from today and yesterday. Yesterday energy will be queried only once if not available yet, but not updated in subsequent refreshes. @@ -1850,7 +1861,11 @@ class AnkerSolixApi: return data async def set_site_price( - self, siteId: str, price: float = None, unit: str = None, co2: float = None + self, + siteId: str, + price: float | None = None, + unit: str | None = None, + co2: float | None = None, ) -> bool: """Set the power price, the unit and/or CO2 for a site. @@ -1984,7 +1999,7 @@ class AnkerSolixApi: self, siteId: str, paramType: str = SolixParmType.SOLARBANK_SCHEDULE.value, - deviceSn: str = None, + deviceSn: str | None = None, fromFile: bool = False, ) -> dict: r"""Get device parameters (e.g. solarbank schedule). This can be queried for each siteId listed in the homepage info site_list. The paramType is always 4, but can be modified if necessary. @@ -2040,7 +2055,7 @@ class AnkerSolixApi: paramData: dict, paramType: str = SolixParmType.SOLARBANK_SCHEDULE.value, command: int = 17, - deviceSn: str = None, + deviceSn: str | None = None, ) -> dict: """Set device parameters (e.g. solarbank schedule). @@ -2073,9 +2088,9 @@ class AnkerSolixApi: siteId: str, deviceSn: str, all_day: bool = False, - preset: int = None, - export: bool = None, - charge_prio: int = None, + preset: int | None = None, + export: bool | None = None, + charge_prio: int | None = None, set_slot: SolarbankTimeslot = None, insert_slot: SolarbankTimeslot = None, ) -> bool: @@ -2611,10 +2626,10 @@ class AnkerSolixApi: ) return resp.get("data", {}) - async def get_upgrade_record( + async def check_upgrade_record( self, recordType: int = 2, fromFile: bool = False ) -> dict: - """Get upgrade record, shows device updates with their last version. Type 0-3 work. + """Check upgrade record, shows device updates with their last version. Type 0-3 work. Example data: {"is_record": true,"device_list": [{ @@ -2624,7 +2639,7 @@ class AnkerSolixApi: data = {"type": recordType} if fromFile: resp = self._loadFromFile( - os.path.join(self._testdir, f"upgrade_record_{recordType}.json") + os.path.join(self._testdir, f"check_upgrade_record_{recordType}.json") ) else: resp = await self.request( @@ -2632,14 +2647,45 @@ class AnkerSolixApi: ) return resp.get("data", {}) + async def get_upgrade_record( + self, deviceSn: str | None = None, siteId: str | None = None, recordType: int | None = None, fromFile: bool = False + ) -> dict: + """Get upgrade record for a device serial or site ID, shows update history. Type 1 works for solarbank, type 2 for site ID. + + Example data: + {"device_sn": "9JVB42LJK8J0P5RY", "site_id": "", "upgrade_record_list": [ + {"upgrade_time": "2024-02-29 12:38:23","upgrade_version": "v1.5.6","pre_version": "v1.4.4","upgrade_type": "1","upgrade_desc": "", + "device_sn": "9JVB42LJK8J0P5RY","device_name": "9JVB42LJK8J0P5RY","child_upgrade_records": null}, + {"upgrade_time": "2023-12-29 10:23:06","upgrade_version": "v1.4.4","pre_version": "v0.0.6.6","upgrade_type": "1","upgrade_desc": "", + "device_sn": "9JVB42LJK8J0P5RY","device_name": "9JVB42LJK8J0P5RY","child_upgrade_records": null}, + {"upgrade_time": "2023-11-02 13:43:09","upgrade_version": "v1.4.1","pre_version": "v0.0.6.5","upgrade_type": "1","upgrade_desc": "", + "device_sn": "9JVB42LJK8J0P5RY","device_name": "9JVB42LJK8J0P5RY","child_upgrade_records": null}]}, + """ + if deviceSn: + data = {"device_sn": deviceSn, "type": 1 if recordType is None else recordType} + elif siteId: + data = {"site_id": siteId, "type": 2 if recordType is None else recordType} + else: + recordType = 0 if recordType is None else recordType + data = {"type": recordType} + if fromFile: + resp = self._loadFromFile( + os.path.join(self._testdir, f"get_upgrade_record_{deviceSn if deviceSn else siteId if siteId else recordType}.json") + ) + else: + resp = await self.request( + "post", _API_ENDPOINTS["get_upgrade_record"], json=data + ) + return resp.get("data", {}) + async def energy_analysis( self, siteId: str, deviceSn: str, - rangeType: str = None, - startDay: datetime = None, - endDay: datetime = None, - devType: str = None, + rangeType: str | None = None, + startDay: datetime | None = None, + endDay: datetime | None = None, + devType: str | None = None, ) -> dict: """Fetch Energy data for given device and optional time frame. @@ -2770,7 +2816,7 @@ class AnkerSolixApi: table.update({daystr: entry}) return table - async def home_load_chart(self, siteId: str, deviceSn: str = None) -> dict: + async def home_load_chart(self, siteId: str, deviceSn: str | None = None) -> dict: """Get home load chart data. Example data: diff --git a/api/errors.py b/api/errors.py index b8da130..3dc6277 100644 --- a/api/errors.py +++ b/api/errors.py @@ -75,6 +75,8 @@ ERRORS: dict[int, type[AnkerSolixError]] = { 401: AuthorizationError, 403: AuthorizationError, 429: RequestLimitError, + 502: ConnectError, + 504: ConnectError, 997: ConnectError, 998: NetworkError, 999: ServerError, diff --git a/examples/example1/api_devices.json b/examples/example1/api_devices.json index 0fe913e..2afa50a 100644 --- a/examples/example1/api_devices.json +++ b/examples/example1/api_devices.json @@ -1,27 +1,27 @@ { - "DILM86K2GJV2NRAI": { - "device_sn": "DILM86K2GJV2NRAI", + "G55HAP9LVQO2LAPM": { + "device_sn": "G55HAP9LVQO2LAPM", "type": "solarbank", - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", "is_admin": true, "device_pn": "A17C0", - "battery_soc": "6", + "battery_soc": "17", "battery_capacity": "1600", - "battery_energy": "96", - "charging_power": "64", + "battery_energy": "272", + "charging_power": "-190", "power_unit": "W", - "charging_status": "3", - "charging_status_desc": "charge_bypass", + "charging_status": "2", + "charging_status_desc": "discharge", "status": "1", "status_desc": "online", "wireless_type": "1", - "input_power": "154", - "output_power": "90", - "set_output_power": "0", + "input_power": "0", + "output_power": "190", + "set_output_power": "300", "power_cutoff": 5, "alias": "SB E1600", - "set_system_output_power": "0", - "bt_ble_mac": "3CEAAD9FDDF7", + "set_system_output_power": "300", + "bt_ble_mac": "FEDCEB33AA9A", "name": "Solarbank E1600", "wifi_online": true, "charge": false, @@ -29,7 +29,7 @@ "sw_version": "v1.5.6", "auto_upgrade": false, "wifi_name": "wifi-network-1", - "wifi_signal": "54", + "wifi_signal": "50", "power_cutoff_data": [ { "id": 1, @@ -49,7 +49,7 @@ "solar_info": { "solar_brand": "ANKER", "solar_model": "A5143", - "solar_sn": "9XK0FGWY2TWW", + "solar_sn": "YTZL4ZEJ4R5B", "solar_model_name": "MI80 Microinverter(BLE)" }, "schedule": { @@ -57,7 +57,7 @@ { "id": 0, "start_time": "00:00", - "end_time": "06:30", + "end_time": "07:20", "turn_on": true, "appliance_loads": [ { @@ -71,21 +71,21 @@ "power_setting_mode": 1, "device_power_loads": [ { - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "power": 150 } ] }, { "id": 0, - "start_time": "06:30", - "end_time": "18:30", + "start_time": "07:20", + "end_time": "19:40", "turn_on": false, "appliance_loads": [ { "id": 0, "name": "Benutzerdefiniert", - "power": 100, + "power": 140, "number": 1 } ], @@ -93,14 +93,14 @@ "power_setting_mode": 1, "device_power_loads": [ { - "device_sn": "DILM86K2GJV2NRAI", - "power": 50 + "device_sn": "G55HAP9LVQO2LAPM", + "power": 70 } ] }, { "id": 0, - "start_time": "18:30", + "start_time": "19:40", "end_time": "24:00", "turn_on": true, "appliance_loads": [ @@ -115,7 +115,7 @@ "power_setting_mode": 1, "device_power_loads": [ { - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "power": 150 } ] @@ -130,8 +130,8 @@ "display_advanced_mode": 0, "advanced_mode_min_load": 0 }, - "preset_system_output_power": 100, - "preset_allow_export": false, + "preset_system_output_power": 300, + "preset_allow_export": true, "preset_charge_priority": 10, "fittings": {} } diff --git a/examples/example1/api_sites.json b/examples/example1/api_sites.json index 8b193d4..ffbab14 100644 --- a/examples/example1/api_sites.json +++ b/examples/example1/api_sites.json @@ -1,8 +1,8 @@ { - "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23": { + "9e40dc42-adac-7fba-dead-a1bba7bff34e": { "type": "system", "site_info": { - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", "site_name": "BKW", "site_img": "", "device_type_list": [ @@ -36,17 +36,17 @@ "statistics": [ { "type": "1", - "total": "135.13", + "total": "183.54", "unit": "kwh" }, { "type": "2", - "total": "134.72", + "total": "182.99", "unit": "kg" }, { "type": "3", - "total": "44.59", + "total": "60.57", "unit": "\u20ac" } ], @@ -55,40 +55,40 @@ "solarbank_list": [ { "device_pn": "A17C0", - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "device_img": "https://public-aiot-fra-prod.s3.dualstack.eu-central-1.amazonaws.com/anker-power/public/product/anker-power/e9478c2d-e665-4d84-95d7-dd4844f82055/20230719-144818.png", - "battery_power": "6", + "battery_power": "17", "bind_site_status": "", - "charging_power": "64", + "charging_power": "-190", "power_unit": "W", - "charging_status": "3", + "charging_status": "2", "status": "1", "wireless_type": "1", "main_version": "", - "photovoltaic_power": "154", - "output_power": "90", + "photovoltaic_power": "0", + "output_power": "190", "create_time": 1695392386, - "set_load_power": "0", + "set_load_power": "300", "output_cutoff_data": 5, "is_display": true, "alias_name": "SB E1600", - "current_home_load": "0" + "current_home_load": "300" } ], - "total_charging_power": "64", + "total_charging_power": "-190.0", "power_unit": "W", "charging_status": "0", - "total_battery_power": "0.06", - "updated_time": "2024-03-27 11:49:04", - "total_photovoltaic_power": "154", - "total_output_power": "90.00", + "total_battery_power": "0.17", + "updated_time": "2024-04-24 01:33:08", + "total_photovoltaic_power": "0", + "total_output_power": "190.00", "display_set_power": false, "is_display_data": true }, - "retain_load": "0W", + "retain_load": "300W", "updated_time": "01-01-0001 00:00:00", "power_site_type": 2, - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", "powerpanel_list": [], "site_details": { "has_unread_msg": false, diff --git a/examples/example1/auto_upgrade.json b/examples/example1/auto_upgrade.json index c8c9d8f..dfd43b3 100644 --- a/examples/example1/auto_upgrade.json +++ b/examples/example1/auto_upgrade.json @@ -5,7 +5,7 @@ "main_switch": true, "device_list": [ { - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "device_name": "Solarbank E1600", "auto_upgrade": false, "alias_name": "SB E1600", @@ -13,5 +13,5 @@ } ] }, - "trace_id": "145dab32b452d3db2a81ce9506ee4010" + "trace_id": "c6f8bd0ae3dd9eb8b3dbd8c84d2afba5" } \ No newline at end of file diff --git a/examples/example1/bind_devices.json b/examples/example1/bind_devices.json index 35d761d..d58f46c 100644 --- a/examples/example1/bind_devices.json +++ b/examples/example1/bind_devices.json @@ -4,10 +4,10 @@ "data": { "data": [ { - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "product_code": "A17C0", - "bt_ble_id": "3C:EA:AD:9F:DD:F7", - "bt_ble_mac": "3CEAAD9FDDF7", + "bt_ble_id": "FE:DC:EB:33:AA:9A", + "bt_ble_mac": "FEDCEB33AA9A", "device_name": "Solarbank E1600", "alias_name": "SB E1600", "img_url": "https://public-aiot-fra-prod.s3.dualstack.eu-central-1.amazonaws.com/anker-power/public/product/anker-power/e9478c2d-e665-4d84-95d7-dd4844f82055/20230719-144818.png", @@ -26,5 +26,5 @@ } ] }, - "trace_id": "acff073fd7e842994b11373fd1d3449e" + "trace_id": "8fed8fc1bba815a1efa844983cecef9e" } \ No newline at end of file diff --git a/examples/example1/charging_devices.json b/examples/example1/charging_devices.json index 2b66404..7f7f702 100644 --- a/examples/example1/charging_devices.json +++ b/examples/example1/charging_devices.json @@ -5,5 +5,5 @@ "device_list": null, "guide_txt": "" }, - "trace_id": "c55301e2c5686c8d75bf494a91d804b6" + "trace_id": "ded0b8ad19ffe254edcf876c633e4735" } \ No newline at end of file diff --git a/examples/example1/compatible_process_DILM86K2GJV2NRAI.json b/examples/example1/compatible_process_G55HAP9LVQO2LAPM.json similarity index 86% rename from examples/example1/compatible_process_DILM86K2GJV2NRAI.json rename to examples/example1/compatible_process_G55HAP9LVQO2LAPM.json index 081d2b1..301de68 100644 --- a/examples/example1/compatible_process_DILM86K2GJV2NRAI.json +++ b/examples/example1/compatible_process_G55HAP9LVQO2LAPM.json @@ -5,7 +5,7 @@ "ota_complete_status": 2, "process_skip_type": 2, "solar_info": { - "solar_sn": "9XK0FGWY2TWW", + "solar_sn": "YTZL4ZEJ4R5B", "solar_brand": "ANKER", "solar_model": "A5143", "brand_id": "3a9930f5-74ef-4e41-a797-04e6b33d3f0f", @@ -15,5 +15,5 @@ "solar_model_name": "MI80 Microinverter(BLE)" } }, - "trace_id": "7dbfd7538ad24749c1abfcf0fd93de5f" + "trace_id": "077b4ed2b6fccac0a9dfcf8e4fdd85a6" } \ No newline at end of file diff --git a/examples/example1/device_fittings_DILM86K2GJV2NRAI.json b/examples/example1/device_fittings_G55HAP9LVQO2LAPM.json similarity index 57% rename from examples/example1/device_fittings_DILM86K2GJV2NRAI.json rename to examples/example1/device_fittings_G55HAP9LVQO2LAPM.json index fbe8928..484f73b 100644 --- a/examples/example1/device_fittings_DILM86K2GJV2NRAI.json +++ b/examples/example1/device_fittings_G55HAP9LVQO2LAPM.json @@ -4,5 +4,5 @@ "data": { "data": [] }, - "trace_id": "823ef9f8a8c4fbdbe7e4abd4232f79c4" + "trace_id": "a433dc2acdb4187e340cff4d6bb60f3c" } \ No newline at end of file diff --git a/examples/example1/device_load_DILM86K2GJV2NRAI.json b/examples/example1/device_load_G55HAP9LVQO2LAPM.json similarity index 56% rename from examples/example1/device_load_DILM86K2GJV2NRAI.json rename to examples/example1/device_load_G55HAP9LVQO2LAPM.json index df0b324..1c5829b 100644 --- a/examples/example1/device_load_DILM86K2GJV2NRAI.json +++ b/examples/example1/device_load_G55HAP9LVQO2LAPM.json @@ -2,11 +2,11 @@ "code": 0, "msg": "success!", "data": { - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", - "home_load_data": "{\"ranges\":[{\"id\":0,\"start_time\":\"00:00\",\"end_time\":\"06:30\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"DILM86K2GJV2NRAI\",\"power\":150}]},{\"id\":0,\"start_time\":\"06:30\",\"end_time\":\"18:30\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":100,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"DILM86K2GJV2NRAI\",\"power\":50}]},{\"id\":0,\"start_time\":\"18:30\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"DILM86K2GJV2NRAI\",\"power\":150}]}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":1,\"default_charge_priority\":80,\"is_zero_output_tips\":0,\"display_advanced_mode\":0,\"advanced_mode_min_load\":0}", - "current_home_load": "0W", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", + "home_load_data": "{\"ranges\":[{\"id\":0,\"start_time\":\"00:00\",\"end_time\":\"07:20\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"G55HAP9LVQO2LAPM\",\"power\":150}]},{\"id\":0,\"start_time\":\"07:20\",\"end_time\":\"19:40\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":140,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"G55HAP9LVQO2LAPM\",\"power\":70}]},{\"id\":0,\"start_time\":\"19:40\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"G55HAP9LVQO2LAPM\",\"power\":150}]}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":1,\"default_charge_priority\":80,\"is_zero_output_tips\":0,\"display_advanced_mode\":0,\"advanced_mode_min_load\":0}", + "current_home_load": "300W", "parallel_home_load": "", "parallel_display": false }, - "trace_id": "adbafcecd3cac7f6c9feda1bcbab7aea" + "trace_id": "ece0447b2ec3c1520e8ca17c1a4ce63f" } \ No newline at end of file diff --git a/examples/example1/device_parm_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json b/examples/example1/device_parm_9e40dc42-adac-7fba-dead-a1bba7bff34e.json similarity index 58% rename from examples/example1/device_parm_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json rename to examples/example1/device_parm_9e40dc42-adac-7fba-dead-a1bba7bff34e.json index 6d13eb2..d9e5f53 100644 --- a/examples/example1/device_parm_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json +++ b/examples/example1/device_parm_9e40dc42-adac-7fba-dead-a1bba7bff34e.json @@ -2,7 +2,7 @@ "code": 0, "msg": "success!", "data": { - "param_data": "{\"ranges\":[{\"id\":0,\"start_time\":\"00:00\",\"end_time\":\"06:30\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"DILM86K2GJV2NRAI\",\"power\":150}]},{\"id\":0,\"start_time\":\"06:30\",\"end_time\":\"18:30\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":100,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"DILM86K2GJV2NRAI\",\"power\":50}]},{\"id\":0,\"start_time\":\"18:30\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"DILM86K2GJV2NRAI\",\"power\":150}]}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":1,\"default_charge_priority\":80,\"is_zero_output_tips\":0,\"display_advanced_mode\":0,\"advanced_mode_min_load\":0}" + "param_data": "{\"ranges\":[{\"id\":0,\"start_time\":\"00:00\",\"end_time\":\"07:20\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"G55HAP9LVQO2LAPM\",\"power\":150}]},{\"id\":0,\"start_time\":\"07:20\",\"end_time\":\"19:40\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":140,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"G55HAP9LVQO2LAPM\",\"power\":70}]},{\"id\":0,\"start_time\":\"19:40\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":10,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"G55HAP9LVQO2LAPM\",\"power\":150}]}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":1,\"default_charge_priority\":80,\"is_zero_output_tips\":0,\"display_advanced_mode\":0,\"advanced_mode_min_load\":0}" }, - "trace_id": "2b3a35dbdeede8bbff7fba8dfeb0a3ff" + "trace_id": "87feb1cf10c4cb773ea4deb7f8eacb84" } \ No newline at end of file diff --git a/examples/example1/get_upgrade_record_9e40dc42-adac-7fba-dead-a1bba7bff34e.json b/examples/example1/get_upgrade_record_9e40dc42-adac-7fba-dead-a1bba7bff34e.json new file mode 100644 index 0000000..6a8aafb --- /dev/null +++ b/examples/example1/get_upgrade_record_9e40dc42-adac-7fba-dead-a1bba7bff34e.json @@ -0,0 +1,41 @@ +{ + "code": 0, + "msg": "success!", + "data": { + "device_sn": "", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", + "upgrade_record_list": [ + { + "upgrade_time": "2024-02-29 10:48:23", + "upgrade_version": "v1.5.6", + "pre_version": "v1.4.4", + "upgrade_type": "1", + "upgrade_desc": "", + "device_sn": "G55HAP9LVQO2LAPM", + "device_name": "G55HAP9LVQO2LAPM", + "child_upgrade_records": null + }, + { + "upgrade_time": "2023-12-28 15:57:06", + "upgrade_version": "v1.4.4", + "pre_version": "v0.0.6.6", + "upgrade_type": "1", + "upgrade_desc": "", + "device_sn": "G55HAP9LVQO2LAPM", + "device_name": "G55HAP9LVQO2LAPM", + "child_upgrade_records": null + }, + { + "upgrade_time": "2023-11-01 09:53:09", + "upgrade_version": "v1.4.1", + "pre_version": "v0.0.6.5", + "upgrade_type": "1", + "upgrade_desc": "", + "device_sn": "G55HAP9LVQO2LAPM", + "device_name": "G55HAP9LVQO2LAPM", + "child_upgrade_records": null + } + ] + }, + "trace_id": "9b3f6a74d73cbede9dcd7e3fa9f3c6de" +} \ No newline at end of file diff --git a/examples/example1/homepage.json b/examples/example1/homepage.json index d67cfd5..4a87544 100644 --- a/examples/example1/homepage.json +++ b/examples/example1/homepage.json @@ -4,7 +4,7 @@ "data": { "site_list": [ { - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", "site_name": "BKW", "site_img": "", "device_type_list": [ @@ -21,10 +21,10 @@ "solarbank_list": [ { "device_pn": "", - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "device_name": "SB E1600", "device_img": "https://public-aiot-fra-prod.s3.dualstack.eu-central-1.amazonaws.com/anker-power/public/product/anker-power/e9478c2d-e665-4d84-95d7-dd4844f82055/20230719-144818.png", - "battery_power": "6", + "battery_power": "17", "bind_site_status": "1", "charging_power": "", "power_unit": "", @@ -42,5 +42,5 @@ ], "powerpanel_list": [] }, - "trace_id": "ae8abfd363866b4cee17359fd1cd9dca" + "trace_id": "d0ee3c49869cec32cf6cf251521f29dd" } \ No newline at end of file diff --git a/examples/example1/message_unread.json b/examples/example1/message_unread.json index f3fd53f..091f04f 100644 --- a/examples/example1/message_unread.json +++ b/examples/example1/message_unread.json @@ -4,5 +4,5 @@ "data": { "has_unread_msg": false }, - "trace_id": "aec8da3373cd0e59d9db5eb52e7adbdc" + "trace_id": "a058ab399db309214abaabf12ddccaad" } \ No newline at end of file diff --git a/examples/example1/ota_update_G55HAP9LVQO2LAPM.json b/examples/example1/ota_update_G55HAP9LVQO2LAPM.json new file mode 100644 index 0000000..818fdb8 --- /dev/null +++ b/examples/example1/ota_update_G55HAP9LVQO2LAPM.json @@ -0,0 +1,11 @@ +{ + "code": 0, + "msg": "success!", + "data": { + "is_ota_update": false, + "need_retry": false, + "retry_interval": 0, + "device_list": null + }, + "trace_id": "2dcfae1f2f344d0d97ac24d74ef8fba9" +} \ No newline at end of file diff --git a/examples/example1/power_cutoff_DILM86K2GJV2NRAI.json b/examples/example1/power_cutoff_G55HAP9LVQO2LAPM.json similarity index 88% rename from examples/example1/power_cutoff_DILM86K2GJV2NRAI.json rename to examples/example1/power_cutoff_G55HAP9LVQO2LAPM.json index 7ed38cb..a618fe2 100644 --- a/examples/example1/power_cutoff_DILM86K2GJV2NRAI.json +++ b/examples/example1/power_cutoff_G55HAP9LVQO2LAPM.json @@ -19,5 +19,5 @@ } ] }, - "trace_id": "7a84aead0e446bbc85fc76ebbcb2bc01" + "trace_id": "8bb7ef048b69dcff25ae45bc3ec3fad2" } \ No newline at end of file diff --git a/examples/example1/price_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json b/examples/example1/price_9e40dc42-adac-7fba-dead-a1bba7bff34e.json similarity index 53% rename from examples/example1/price_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json rename to examples/example1/price_9e40dc42-adac-7fba-dead-a1bba7bff34e.json index d4cd227..a9d1b59 100644 --- a/examples/example1/price_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json +++ b/examples/example1/price_9e40dc42-adac-7fba-dead-a1bba7bff34e.json @@ -2,10 +2,10 @@ "code": 0, "msg": "success!", "data": { - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", "price": 0.33, "site_co2": 0, "site_price_unit": "\u20ac" }, - "trace_id": "7cfacbfca09e909cf9a8939ebddba1ac" + "trace_id": "5aae22e5adc38af4b9fdc37aa1f89cdb" } \ No newline at end of file diff --git a/examples/example1/scene_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json b/examples/example1/scene_9e40dc42-adac-7fba-dead-a1bba7bff34e.json similarity index 70% rename from examples/example1/scene_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json rename to examples/example1/scene_9e40dc42-adac-7fba-dead-a1bba7bff34e.json index 94fb8fe..4759a3d 100644 --- a/examples/example1/scene_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json +++ b/examples/example1/scene_9e40dc42-adac-7fba-dead-a1bba7bff34e.json @@ -20,17 +20,17 @@ "statistics": [ { "type": "1", - "total": "135.13", + "total": "183.54", "unit": "kwh" }, { "type": "2", - "total": "134.72", + "total": "182.99", "unit": "kg" }, { "type": "3", - "total": "44.59", + "total": "60.57", "unit": "\u20ac" } ], @@ -39,40 +39,40 @@ "solarbank_list": [ { "device_pn": "A17C0", - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "device_name": "SB E1600", "device_img": "https://public-aiot-fra-prod.s3.dualstack.eu-central-1.amazonaws.com/anker-power/public/product/anker-power/e9478c2d-e665-4d84-95d7-dd4844f82055/20230719-144818.png", - "battery_power": "6", + "battery_power": "17", "bind_site_status": "", - "charging_power": "90", + "charging_power": "190", "power_unit": "W", - "charging_status": "3", + "charging_status": "2", "status": "1", "wireless_type": "1", "main_version": "", - "photovoltaic_power": "154", - "output_power": "90", + "photovoltaic_power": "0", + "output_power": "190", "create_time": 1695392386, "set_load_power": "", "output_cutoff_data": 5, "is_display": true } ], - "total_charging_power": "64", + "total_charging_power": "0", "power_unit": "W", "charging_status": "0", - "total_battery_power": "0.06", - "updated_time": "2024-03-27 11:49:04", - "total_photovoltaic_power": "154", - "total_output_power": "90.00", + "total_battery_power": "0.17", + "updated_time": "2024-04-24 01:33:08", + "total_photovoltaic_power": "0", + "total_output_power": "190.00", "display_set_power": false, "is_display_data": true }, - "retain_load": "0W", + "retain_load": "300W", "updated_time": "01-01-0001 00:00:00", "power_site_type": 2, - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", "powerpanel_list": [] }, - "trace_id": "e6a2f3f712a7c2498a25ae7c0bafef3e" + "trace_id": "64eeaeab8d80ee6bab68bf981b9cda1d" } \ No newline at end of file diff --git a/examples/example1/site_detail_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json b/examples/example1/site_detail_9e40dc42-adac-7fba-dead-a1bba7bff34e.json similarity index 88% rename from examples/example1/site_detail_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json rename to examples/example1/site_detail_9e40dc42-adac-7fba-dead-a1bba7bff34e.json index 46f0f27..38a9813 100644 --- a/examples/example1/site_detail_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json +++ b/examples/example1/site_detail_9e40dc42-adac-7fba-dead-a1bba7bff34e.json @@ -3,7 +3,7 @@ "msg": "success!", "data": { "site_info": { - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", "site_name": "BKW", "site_img": "", "device_type_list": [ @@ -23,7 +23,7 @@ "solarbank_list": [ { "device_pn": "A17C0", - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "device_name": "SB E1600", "device_img": "https://public-aiot-fra-prod.s3.dualstack.eu-central-1.amazonaws.com/anker-power/public/product/anker-power/e9478c2d-e665-4d84-95d7-dd4844f82055/20230719-144818.png", "battery_power": "", @@ -44,5 +44,5 @@ ], "powerpanel_list": [] }, - "trace_id": "84caedc36bfe9b3f0ed1c89ceb5c0ee2" + "trace_id": "daee0eafcbcefbcafc9a0adb3519ea6f" } \ No newline at end of file diff --git a/examples/example1/site_list.json b/examples/example1/site_list.json index 57a8110..7b31863 100644 --- a/examples/example1/site_list.json +++ b/examples/example1/site_list.json @@ -4,7 +4,7 @@ "data": { "site_list": [ { - "site_id": "bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23", + "site_id": "9e40dc42-adac-7fba-dead-a1bba7bff34e", "site_name": "BKW", "site_img": "", "device_type_list": [ @@ -21,5 +21,5 @@ } ] }, - "trace_id": "b07e6dfde00e7ddfb8fa4b3a2b76ac4c" + "trace_id": "fe909473eeb4bd6ba428b4fda59aab74" } \ No newline at end of file diff --git a/examples/example1/site_rules.json b/examples/example1/site_rules.json index 97db105..302ff02 100644 --- a/examples/example1/site_rules.json +++ b/examples/example1/site_rules.json @@ -142,5 +142,5 @@ } ] }, - "trace_id": "d3dceb28da9a8f8ca2fb2ae170dc186a" + "trace_id": "f8acb37f7d12aeabe646cbd5055ebabf" } \ No newline at end of file diff --git a/examples/example1/solar_info_DILM86K2GJV2NRAI.json b/examples/example1/solar_info_G55HAP9LVQO2LAPM.json similarity index 72% rename from examples/example1/solar_info_DILM86K2GJV2NRAI.json rename to examples/example1/solar_info_G55HAP9LVQO2LAPM.json index df1e178..213f872 100644 --- a/examples/example1/solar_info_DILM86K2GJV2NRAI.json +++ b/examples/example1/solar_info_G55HAP9LVQO2LAPM.json @@ -5,8 +5,8 @@ "brand_id": "3a9930f5-74ef-4e41-a797-04e6b33d3f0f", "solar_brand": "ANKER", "solar_model": "A5143", - "solar_sn": "9XK0FGWY2TWW", + "solar_sn": "YTZL4ZEJ4R5B", "solar_model_name": "MI80 Microinverter(BLE)" }, - "trace_id": "4fddaabaeaabd39fea6d7c474fb97ad2" + "trace_id": "6b2dfaebd1abe931bcec042c1686fc4f" } \ No newline at end of file diff --git a/examples/example1/user_devices.json b/examples/example1/user_devices.json index bf6edff..1bdc08f 100644 --- a/examples/example1/user_devices.json +++ b/examples/example1/user_devices.json @@ -7,7 +7,7 @@ "solarbank_list": [ { "device_pn": "A17C0", - "device_sn": "DILM86K2GJV2NRAI", + "device_sn": "G55HAP9LVQO2LAPM", "device_name": "SB E1600", "device_img": "https://public-aiot-fra-prod.s3.dualstack.eu-central-1.amazonaws.com/anker-power/public/product/anker-power/e9478c2d-e665-4d84-95d7-dd4844f82055/20230719-144818.png", "battery_power": "", @@ -28,5 +28,5 @@ ], "powerpanel_list": [] }, - "trace_id": "3607fa3ff416d93ded855c2ee9b10bea" + "trace_id": "4acd422dafadcb3f2ccabbe1fb92ceda" } \ No newline at end of file diff --git a/examples/example1/wifi_list_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json b/examples/example1/wifi_list_9e40dc42-adac-7fba-dead-a1bba7bff34e.json similarity index 63% rename from examples/example1/wifi_list_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json rename to examples/example1/wifi_list_9e40dc42-adac-7fba-dead-a1bba7bff34e.json index 6e0678a..cffe14a 100644 --- a/examples/example1/wifi_list_bdd7d770-bcb7-d22b-cafc-d0b2eddc4e23.json +++ b/examples/example1/wifi_list_9e40dc42-adac-7fba-dead-a1bba7bff34e.json @@ -5,9 +5,9 @@ "wifi_info_list": [ { "wifi_name": "wifi-network-1", - "wifi_signal": "54" + "wifi_signal": "50" } ] }, - "trace_id": "38ec9a1a8d29dac96ac9adc12fbb41b8" + "trace_id": "af7beabd3e81cfb62be0f4abf96298fb" } \ No newline at end of file diff --git a/export_system.py b/export_system.py index bf988f1..73e4d9e 100755 --- a/export_system.py +++ b/export_system.py @@ -50,7 +50,8 @@ def randomize(val, key: str = "") -> str: if not RANDOMIZE: return str(val) randomstr = RANDOMDATA.get(val, "") - if not randomstr and val: + # generate new random string + if not randomstr and val and key not in ["device_name"]: if "_sn" in key or key in ["sn"]: randomstr = "".join( random.choices(string.ascii_uppercase + string.digits, k=len(val)) @@ -68,7 +69,7 @@ def randomize(val, key: str = "") -> str: if ":" in val: RANDOMDATA.update({temp: randomstr}) # save also key value without : randomstr = ":".join( - a + b for a, b in zip(randomstr[::2], randomstr[1::2]) + a + b for a, b in zip(randomstr[::2], randomstr[1::2], strict=False) ) elif "_id" in key: for part in val.split("-"): @@ -102,7 +103,7 @@ def randomize(val, key: str = "") -> str: # default randomize format randomstr = "".join(random.choices(string.ascii_letters, k=len(val))) RANDOMDATA.update({val: randomstr}) - return randomstr + return randomstr or str(val) def check_keys(data): @@ -125,6 +126,7 @@ def check_keys(data): "wifi_name", "home_load_data", "param_data", + "device_name" ] ) or k in ["sn"]: data[k] = randomize(v, k) @@ -133,7 +135,7 @@ def check_keys(data): def export( filename: str, - d: dict = None, + d: dict | None = None, skip_randomize: bool = False, randomkeys: bool = False, ) -> None: @@ -329,6 +331,22 @@ async def main() -> bool: # noqa: C901 # pylint: disable=too-many-branches,too- except (ClientError, errors.AnkerSolixError): if not admin: CONSOLE.warning("Query requires account of site owner!") + CONSOLE.info("Exporting site upgrade record...") + try: + export( + os.path.join( + folder, + f"get_upgrade_record_{randomize(siteId,'site_id')}.json", + ), + await myapi.request( + "post", + api._API_ENDPOINTS["get_upgrade_record"], + json={"site_id": siteId, "type": 2}, + ), + ) # works only for site owners + except (ClientError, errors.AnkerSolixError): + if not admin: + CONSOLE.warning("Query requires account of site owner!") for sn, device in myapi.devices.items(): CONSOLE.info( "\nExporting device specific data for device %s SN %s...", @@ -414,6 +432,19 @@ async def main() -> bool: # noqa: C901 # pylint: disable=too-many-branches,too- except (ClientError, errors.AnkerSolixError): if not admin: CONSOLE.warning("Query requires account of site owner!") + CONSOLE.info("Exporting OTA update info...") + try: + export( + os.path.join(folder, f"ota_update_{randomize(sn,'_sn')}.json"), + await myapi.request( + "post", + api._API_ENDPOINTS["get_ota_update"], + json={"device_sn": sn, "insert_sn": ""}, + ), + ) # works only for site owners + except (ClientError, errors.AnkerSolixError): + if not admin: + CONSOLE.warning("Query requires account of site owner!") CONSOLE.info("\nExporting site rules...") export(