R1.5.5
This commit is contained in:
parent
7f9a99b09b
commit
4cf9641ec2
303
api/api.py
303
api/api.py
|
@ -131,19 +131,19 @@ _API_ENDPOINTS = {
|
|||
"set_device_parm": "power_service/v1/site/set_site_device_param", # Apply provided settings to a device for the provided site id and param type (e.g. Schedules), NOT IMPLEMENTED YET
|
||||
"wifi_list": "power_service/v1/site/get_wifi_info_list", # List of available networks for provided site id
|
||||
"get_site_price": "power_service/v1/site/get_site_price", # List defined power price and CO2 for given site, works only for site owner account
|
||||
"update_site_price": "power_service/v1/site/update_site_price", # Update power price for given site, REQUIRED PARAMETERS UNKNOWN
|
||||
"get_auto_upgrade": "power_service/v1/app/get_auto_upgrade", # List of Auto-Upgrade configuration and enabled devices, onyl works for site owner accout
|
||||
"set_auto_upgrade": "power_service/v1/app/set_auto_upgrade", # Set/Enable Auto-Upgrade configuration, not implemented yet, REQUIRED PARAMETERS UNKNOWN
|
||||
"update_site_price": "power_service/v1/site/update_site_price", # Update power price and CO2 for given site, works only for site owner account
|
||||
"get_auto_upgrade": "power_service/v1/app/get_auto_upgrade", # List of Auto-Upgrade configuration and enabled devices, only works for site owner accout
|
||||
"set_auto_upgrade": "power_service/v1/app/set_auto_upgrade", # Set/Enable Auto-Upgrade configuration, works only for site owner account
|
||||
"bind_devices": "power_service/v1/app/get_relate_and_bind_devices", # List with details of locally connected/bound devices, includes firmware version, works only for owner account
|
||||
"get_device_load": "power_service/v1/app/device/get_device_home_load", # Get defined device schedule (same data as provided with device param query)
|
||||
"set_device_load": "power_service/v1/app/device/set_device_home_load", # Set defined device schedule (Not implemented yet, REQUIRED PARAMETERS UNKNOWN)
|
||||
"set_device_load": "power_service/v1/app/device/set_device_home_load", # Set defined device schedule, Accepts the new schedule, but does NOT change it? Maybe future use for schedules per device
|
||||
"get_ota_info": "power_service/v1/app/compatible/get_ota_info", # Get OTA status for solarbank and/or inverter serials
|
||||
"get_ota_update": "power_service/v1/app/compatible/get_ota_update", # Not clear what this does, shows some OTA settings
|
||||
"solar_info": "power_service/v1/app/compatible/get_compatible_solar_info", # Solar inverter definition for solarbanks, works only with owner account
|
||||
"get_cutoff": "power_service/v1/app/compatible/get_power_cutoff", # Get Power Cutoff settings (Min SOC) for provided site id and device sn, works only with owner account
|
||||
"set_cutoff": "power_service/v1/app/compatible/set_power_cutoff", # Set Min SOC for device, only works for onwer accounts
|
||||
"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. Solarbank/inverter responses do not contain info
|
||||
"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)
|
||||
"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
|
||||
|
@ -183,8 +183,8 @@ _API_ENDPOINTS = {
|
|||
'power_service/v1/get_message_not_disturb',
|
||||
'power_service/v1/read_message',
|
||||
'power_service/v1/del_message',
|
||||
'power_service/v1/product_categories',
|
||||
'power_service/v1/product_accessories',
|
||||
'power_service/v1/product_categories', # GET method to list all supported products with details and web picture links
|
||||
'power_service/v1/product_accessories', # GET method to list all supported products accessories with details and web picture links
|
||||
|
||||
|
||||
Structure of the JSON response for an API Login Request:
|
||||
|
@ -249,18 +249,19 @@ class SolixDeviceStatus(Enum):
|
|||
"""Enumuration for Anker Solix Device status."""
|
||||
|
||||
# TODO(3): Add descriptions once status code usage is observed/known
|
||||
off = "0"
|
||||
on = "1"
|
||||
offline = "0"
|
||||
online = "1"
|
||||
unknown = "unknown"
|
||||
|
||||
|
||||
class SolarbankStatus(Enum):
|
||||
"""Enumuration for Anker Solix Solarbank status."""
|
||||
|
||||
charging = "1"
|
||||
discharging = "2"
|
||||
bypass = "3"
|
||||
bypass_charging = "35" # pseudo state, the solarbank does not distinguish this
|
||||
detection = "0"
|
||||
bypass = "1"
|
||||
discharge = "2"
|
||||
charge = "3"
|
||||
charge_bypass = "35" # pseudo state, the solarbank does not distinguish this
|
||||
charge_priority = "37" # pseudo state, the solarbank does not distinguish this but reports 3 as seen so far
|
||||
wakeup = "4" # Not clear what happens during this state, but observed short intervals during night as well
|
||||
# TODO(3): Add descriptions once status code usage is observed/known
|
||||
|
@ -442,6 +443,24 @@ class AnkerSolixApi:
|
|||
self._logger.error(err)
|
||||
return False
|
||||
|
||||
def _update_site( # noqa: C901
|
||||
self,
|
||||
siteId: str,
|
||||
details: dict,
|
||||
) -> None:
|
||||
"""Update the internal sites dictionary with data provided for the nested site details dictionary.
|
||||
|
||||
This method is used to consolidate site details from various less frequent requests that are not covered with the update_sites method.
|
||||
"""
|
||||
# lookup old site details if any
|
||||
if siteId in self.sites:
|
||||
site_details = (self.sites[siteId]).get("site_details") or {}
|
||||
site_details.update(details)
|
||||
else:
|
||||
site_details = details
|
||||
self.sites[siteId] = {}
|
||||
self.sites[siteId]["site_details"] = site_details
|
||||
|
||||
def _update_dev( # noqa: C901
|
||||
self,
|
||||
devData: dict,
|
||||
|
@ -466,8 +485,8 @@ class AnkerSolixApi:
|
|||
elif isAdmin is False and device.get("is_admin") is None:
|
||||
device.update({"is_admin": False})
|
||||
calc_capacity = False # Flag whether capacity may need recalculation
|
||||
try:
|
||||
for key, value in devData.items():
|
||||
for key, value in devData.items():
|
||||
try:
|
||||
if key in ["product_code", "device_pn"] and value:
|
||||
device.update({"device_pn": str(value)})
|
||||
elif key in ["device_name"] and value:
|
||||
|
@ -510,7 +529,9 @@ class AnkerSolixApi:
|
|||
)
|
||||
# Value for device home load may be empty for single solarbank, use this setting also for device preset in this case
|
||||
if not device.get("set_output_power"):
|
||||
device.update({"set_output_power": str(value).replace("W", "")})
|
||||
device.update(
|
||||
{"set_output_power": str(value).replace("W", "")}
|
||||
)
|
||||
elif key in ["power_unit"]:
|
||||
device.update({"power_unit": str(value)})
|
||||
elif key in ["status"]:
|
||||
|
@ -530,21 +551,30 @@ class AnkerSolixApi:
|
|||
if str(value) == status.value:
|
||||
description = status.name
|
||||
break
|
||||
# check if battery charging during bypass and if output during bypass
|
||||
# check if battery has bypass during charge (if output during charge)
|
||||
# NOTE: charging power may be updated after initial device details update
|
||||
# NOTE: If status is 3=Bypass but nothing goes out, the charge priority is active (e.g. 0 Watt switch)
|
||||
# NOTE: If status is 3=charging and larger than preset but nothing goes out, the charge priority is active (e.g. 0 Watt switch)
|
||||
# This key can be passed separately, make sure the other values are looked up in passed data first, then in device details
|
||||
preset = devData.get("set_load_power") or device(
|
||||
"set_output_power"
|
||||
)
|
||||
out = devData.get("output_power") or device.get("output_power")
|
||||
solar = devData.get("photovoltaic_power") or device.get(
|
||||
"input_power"
|
||||
)
|
||||
if (
|
||||
description == SolarbankStatus.bypass.name
|
||||
and (charge := devData.get("charging_power"))
|
||||
and (out := devData.get("output_power"))
|
||||
description == SolarbankStatus.charge.name
|
||||
and preset is not None
|
||||
and out is not None
|
||||
and solar is not None
|
||||
):
|
||||
with contextlib.suppress(ValueError):
|
||||
if int(out) == 0:
|
||||
if int(out) == 0 and int(solar) > int(preset):
|
||||
# Bypass but 0 W output must be active charge priority
|
||||
description = SolarbankStatus.charge_priority.name
|
||||
elif int(charge) > 0:
|
||||
# Bypass with output and charge must be bypass charging
|
||||
description = SolarbankStatus.bypass_charging.name
|
||||
elif int(out) > 0:
|
||||
# Charge with output must be bypass charging
|
||||
description = SolarbankStatus.charge_bypass.name
|
||||
device.update({"charging_status_desc": description})
|
||||
elif key in ["bws_surplus"]:
|
||||
device.update({"bws_surplus": str(value)})
|
||||
|
@ -552,7 +582,10 @@ class AnkerSolixApi:
|
|||
device.update({"charge": bool(value)})
|
||||
elif key in ["auto_upgrade"]:
|
||||
device.update({"auto_upgrade": bool(value)})
|
||||
elif key in ["power_cutoff"]:
|
||||
elif (
|
||||
key in ["power_cutoff", "output_cutoff_data"]
|
||||
and str(value).isdigit()
|
||||
):
|
||||
device.update({"power_cutoff": int(value)})
|
||||
elif key in ["power_cutoff_data"] and value:
|
||||
device.update({"power_cutoff_data": list(value)})
|
||||
|
@ -585,9 +618,13 @@ class AnkerSolixApi:
|
|||
if key in ["battery_power"] or calc_capacity:
|
||||
# generate battery values when soc updated or device name changed or PN is known
|
||||
if not (cap := device.get("battery_capacity")):
|
||||
if hasattr(SolixDeviceCapacity, device.get("device_pn", "")):
|
||||
if hasattr(
|
||||
SolixDeviceCapacity, device.get("device_pn", "")
|
||||
):
|
||||
# get battery capacity from known PNs
|
||||
cap = SolixDeviceCapacity[device.get("device_pn", "")].value
|
||||
cap = SolixDeviceCapacity[
|
||||
device.get("device_pn", "")
|
||||
].value
|
||||
elif device.get("type") == SolixDeviceType.SOLARBANK.value:
|
||||
# Derive battery capacity in Wh from latest solarbank name or alias if available
|
||||
cap = (
|
||||
|
@ -603,11 +640,19 @@ class AnkerSolixApi:
|
|||
device.update(
|
||||
{
|
||||
"battery_capacity": str(cap),
|
||||
"battery_energy": str(int(int(cap) * int(soc) / 100)),
|
||||
"battery_energy": str(
|
||||
int(int(cap) * int(soc) / 100)
|
||||
),
|
||||
}
|
||||
)
|
||||
except Exception as err: #pylint: disable=broad-exception-caught
|
||||
self._logger.error("%s occured when updating device details for key %s with value %s: %s", type(err), key, value, err)
|
||||
except Exception as err: # pylint: disable=broad-exception-caught
|
||||
self._logger.error(
|
||||
"%s occured when updating device details for key %s with value %s: %s",
|
||||
type(err),
|
||||
key,
|
||||
value,
|
||||
err,
|
||||
)
|
||||
|
||||
self.devices.update({str(sn): device})
|
||||
return sn
|
||||
|
@ -876,7 +921,7 @@ class AnkerSolixApi:
|
|||
'powerpanel_list': []}}
|
||||
"""
|
||||
self._logger.debug("Updating Sites data")
|
||||
self.sites = {}
|
||||
new_sites = {}
|
||||
self._logger.debug("Getting site list")
|
||||
sites = await self.get_site_list(fromFile=fromFile)
|
||||
act_devices = []
|
||||
|
@ -898,7 +943,7 @@ class AnkerSolixApi:
|
|||
self._logger.debug("Getting scene info for site")
|
||||
scene = await self.get_scene_info(myid, fromFile=fromFile)
|
||||
mysite.update(scene)
|
||||
self.sites.update({myid: mysite})
|
||||
new_sites.update({myid: mysite})
|
||||
# Update device details from scene info
|
||||
sb_total_charge = (mysite.get("solarbank_info", {})).get(
|
||||
"total_charging_power", ""
|
||||
|
@ -943,10 +988,12 @@ class AnkerSolixApi:
|
|||
power_out = int(solarbank.get("output_power", ""))
|
||||
# power_charge = int(solarbank.get("charging_power", "")) # This value seems to reflect the output power, which is corect for status 2, but may be wrong for other states
|
||||
charge_calc = power_in - power_out
|
||||
solarbank["charging_power"] = str(charge_calc) # allow negative values
|
||||
solarbank["charging_power"] = str(
|
||||
charge_calc
|
||||
) # allow negative values
|
||||
sb_total_charge_calc += charge_calc
|
||||
mysite["solarbank_info"]["solarbank_list"][index] = solarbank
|
||||
self.sites.update({myid: mysite})
|
||||
new_sites.update({myid: mysite})
|
||||
sn = self._update_dev(
|
||||
solarbank,
|
||||
devType=SolixDeviceType.SOLARBANK.value,
|
||||
|
@ -962,8 +1009,12 @@ class AnkerSolixApi:
|
|||
if sb_total_charge_calc < 0:
|
||||
with contextlib.suppress(ValueError):
|
||||
# discharging, adjust sb total charge value in scene info and allow negativ value to indicate discharge
|
||||
sb_total_charge = float(sb_total_solar) - float(sb_total_output)
|
||||
mysite["solarbank_info"]["total_charging_power"] = str(sb_total_charge)
|
||||
sb_total_charge = float(sb_total_solar) - float(
|
||||
sb_total_output
|
||||
)
|
||||
mysite["solarbank_info"]["total_charging_power"] = str(
|
||||
sb_total_charge
|
||||
)
|
||||
for sn, charge in sb_charges.items():
|
||||
self.devices[sn]["charging_power"] = str(
|
||||
0
|
||||
|
@ -972,7 +1023,7 @@ class AnkerSolixApi:
|
|||
)
|
||||
# Update also the charge status description which may change after charging power correction
|
||||
charge_status = self.devices[sn].get("charging_status")
|
||||
if charge_status == SolarbankStatus.bypass:
|
||||
if charge_status == SolarbankStatus.charge:
|
||||
self._update_dev(
|
||||
{
|
||||
"device_sn": sn,
|
||||
|
@ -980,7 +1031,7 @@ class AnkerSolixApi:
|
|||
}
|
||||
)
|
||||
# make sure to write back any changes to the solarbank info in sites dict
|
||||
self.sites.update({myid: mysite})
|
||||
new_sites.update({myid: mysite})
|
||||
|
||||
for pps in (mysite.get("pps_info", {})).get("pps_list", []):
|
||||
# work around for device_name which is actually the device_alias in scene info
|
||||
|
@ -1024,17 +1075,34 @@ class AnkerSolixApi:
|
|||
)
|
||||
if sn:
|
||||
act_devices.append(sn)
|
||||
# Write back the updated sites
|
||||
self.sites = new_sites
|
||||
# recycle device list and remove devices no longer used in sites
|
||||
rem_devices = [dev for dev in self.devices if dev not in act_devices]
|
||||
for dev in rem_devices:
|
||||
self.devices.pop(dev)
|
||||
return self.sites
|
||||
|
||||
async def update_site_details(self, fromFile: bool = False) -> dict:
|
||||
"""Get the latest updates for additional site related details updated less frequently.
|
||||
|
||||
Most of theses requests return data only when user has admin rights for sites owning the devices.
|
||||
To limit API requests, this update site details method should be called less frequently than update site method,
|
||||
and it updates just the nested site_details dictionary in the sites dictionary.
|
||||
"""
|
||||
self._logger.debug("Updating Sites Details")
|
||||
for site_id, data in self.sites.items():
|
||||
# Fetch site price and CO2 settings
|
||||
self._logger.debug("Getting price and CO2 settings for site")
|
||||
await self.get_site_price(siteId=site_id,fromFile=fromFile)
|
||||
return self.sites
|
||||
|
||||
async def update_device_details(self, fromFile: bool = False) -> dict:
|
||||
"""Get the latest updates for additional device info updated less frequently.
|
||||
|
||||
Most of theses requests return data only when user has admin rights for sites owning the devices.
|
||||
To limit API requests, this update device details method should be called less frequently than update site method, which will also update most device details as found in the site data response.
|
||||
To limit API requests, this update device details method should be called less frequently than update site method,
|
||||
which will also update most device details as found in the site data response.
|
||||
"""
|
||||
self._logger.debug("Updating Device Details")
|
||||
# Fetch firmware version of device
|
||||
|
@ -1391,6 +1459,73 @@ class AnkerSolixApi:
|
|||
await self.get_power_cutoff(deviceSn=deviceSn)
|
||||
return True
|
||||
|
||||
async def get_site_price(self, siteId: str, fromFile: bool = False) -> dict:
|
||||
"""Get the power price set for the site.
|
||||
|
||||
Example data:
|
||||
{"site_id": "efaca6b5-f4a0-e82e-3b2e-6b9cf90ded8c","price": 0.4,"site_co2": 0,"site_price_unit": "\u20ac"}
|
||||
"""
|
||||
data = {"site_id": siteId}
|
||||
if fromFile:
|
||||
resp = self._loadFromFile(
|
||||
os.path.join(self._testdir, f"price_{siteId}.json")
|
||||
)
|
||||
else:
|
||||
resp = await self.request(
|
||||
"post", _API_ENDPOINTS["get_site_price"], json=data
|
||||
)
|
||||
data = resp.get("data", {})
|
||||
# update site details in sites dict
|
||||
details = data.copy()
|
||||
details.pop("site_id")
|
||||
self._update_site(siteId, details)
|
||||
return data
|
||||
|
||||
async def set_site_price(
|
||||
self, siteId: str, price: float = None, unit: str = None, co2: float = None
|
||||
) -> bool:
|
||||
"""Set the power price, the unit and/or CO2 for a site.
|
||||
|
||||
Example input:
|
||||
{"site_id": 'efaca6b5-f4a0-e82e-3b2e-6b9cf90ded8c', "price": 0.325, "site_price_unit": "\u20ac", "site_co2": 0}
|
||||
The id must be one of the ids listed with the get_power_cutoff endpoint
|
||||
"""
|
||||
# First get the old settings if only single setting should be updated
|
||||
details = {}
|
||||
if siteId in self.sites:
|
||||
details = (self.sites.get(siteId) or {}).get("site_details") or {}
|
||||
new_price = details.get("price") if price is None else price
|
||||
new_unit = details.get("site_price_unit") if unit is None else unit
|
||||
new_co2 = details.get("site_co2") if co2 is None else co2
|
||||
data = {}
|
||||
# Need to query old setting to avoid changing them if parameter not provided
|
||||
if new_price is None or new_unit is None or new_co2 is None:
|
||||
data = await self.get_site_price(siteId=siteId)
|
||||
if new_price is not None:
|
||||
data["price"] = new_price
|
||||
if new_unit is not None:
|
||||
data["site_price_unit"] = new_unit
|
||||
if new_co2 is not None:
|
||||
data["site_co2"] = new_co2
|
||||
else:
|
||||
data.update(
|
||||
{
|
||||
"site_id": siteId,
|
||||
"price": new_price,
|
||||
"site_price_unit": new_unit,
|
||||
"site_co2": new_co2,
|
||||
}
|
||||
)
|
||||
# Make the Api call and check for return code
|
||||
code = (
|
||||
await self.request("post", _API_ENDPOINTS["update_site_price"], json=data)
|
||||
).get("code")
|
||||
if not isinstance(code, int) or int(code) != 0:
|
||||
return False
|
||||
# update the data in api dict
|
||||
await self.get_site_price(siteId=siteId)
|
||||
return True
|
||||
|
||||
async def get_device_load(
|
||||
self, siteId: str, deviceSn: str, fromFile: bool = False
|
||||
) -> dict:
|
||||
|
@ -1414,7 +1549,8 @@ class AnkerSolixApi:
|
|||
resp = await self.request(
|
||||
"post", _API_ENDPOINTS["get_device_load"], json=data
|
||||
)
|
||||
# API Bug? home_load_data provided as string instead of object...Convert into object for proper handling
|
||||
# The home_load_data is provided as string instead of object...Convert into object for proper handling
|
||||
# It must be converted back to a string when passing this as input to set home load
|
||||
string_data = (resp.get("data") or {}).get("home_load_data") or {}
|
||||
if isinstance(string_data, str):
|
||||
resp["data"].update({"home_load_data": json.loads(string_data)})
|
||||
|
@ -1430,10 +1566,47 @@ class AnkerSolixApi:
|
|||
)
|
||||
return data
|
||||
|
||||
async def set_device_load(
|
||||
self,
|
||||
siteId: str,
|
||||
deviceSn: str,
|
||||
loadData: dict,
|
||||
) -> dict:
|
||||
"""Set device home load (e.g. solarbank schedule).
|
||||
|
||||
Example input for system with single solarbank:
|
||||
{'site_id': 'efaca6b5-f4a0-e82e-3b2e-6b9cf90ded8c', 'device_sn': '9JVB42LJK8J0P5RY',
|
||||
'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":0,"power_setting_mode":1,"device_power_loads":[{"device_sn":"9JVB42LJK8J0P5RY","power":150}]},'
|
||||
'{"id":0,"start_time":"07:30","end_time":"18:00","turn_on":false,"appliance_loads":[{"id":0,"name":"Benutzerdefiniert","power":100,"number":1}],'
|
||||
'"charge_priority":80,"power_setting_mode":1,"device_power_loads":[{"device_sn":"9JVB42LJK8J0P5RY","power":50}]},'
|
||||
'{"id":0,"start_time":"18:00","end_time":"24:00","turn_on":true,"appliance_loads":[{"id":0,"name":"Benutzerdefiniert","power":300,"number":1}],'
|
||||
'"charge_priority":0,"power_setting_mode":1,"device_power_loads":[{"device_sn":"9JVB42LJK8J0P5RY","power":150}]}],'
|
||||
'"min_load":100,"max_load":800,"step":0,"is_charge_priority":0,"default_charge_priority":0,"is_zero_output_tips":1,"display_advanced_mode":0,"advanced_mode_min_load":0}'
|
||||
}
|
||||
Attention: This method and endpoint actually accepts the inputs, but does not change anything. The set_device_parm endpoint may have to be used
|
||||
"""
|
||||
data = {
|
||||
"site_id": siteId,
|
||||
"device_sn": deviceSn,
|
||||
"home_load_data": json.dumps(loadData),
|
||||
}
|
||||
# Make the Api call and check for return code
|
||||
code = (
|
||||
await self.request("post", _API_ENDPOINTS["set_device_load"], json=data)
|
||||
).get("code")
|
||||
if not isinstance(code, int) or int(code) != 0:
|
||||
return False
|
||||
# update the data in api dict
|
||||
await self.get_device_load(siteId=siteId, deviceSn=deviceSn)
|
||||
return True
|
||||
|
||||
async def get_device_parm(
|
||||
self,
|
||||
siteId: str,
|
||||
paramType: str = SolixParmType.SOLARBANK_SCHEDULE.value,
|
||||
deviceSn: str = 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.
|
||||
|
@ -1454,10 +1627,24 @@ class AnkerSolixApi:
|
|||
resp = await self.request(
|
||||
"post", _API_ENDPOINTS["get_device_parm"], json=data
|
||||
)
|
||||
# API Bug? param_data provided as string instead of object...Convert into object for proper handling
|
||||
# The home_load_data is provided as string instead of object...Convert into object for proper handling
|
||||
# It must be converted back to a string when passing this as input to set home load
|
||||
string_data = (resp.get("data", {})).get("param_data", {})
|
||||
if isinstance(string_data, str):
|
||||
resp["data"].update({"param_data": json.loads(string_data)})
|
||||
|
||||
# update api device dict with latest data if optional device SN was provided, e.g. when called by set_device_parm for device details update
|
||||
if deviceSn:
|
||||
data = resp.get("data") or {}
|
||||
if schedule := data.get("param_data") or {}:
|
||||
self._update_dev(
|
||||
{
|
||||
"device_sn": deviceSn,
|
||||
"schedule": schedule,
|
||||
"current_home_load": data.get("current_home_load") or "",
|
||||
"parallel_home_load": data.get("parallel_home_load") or "",
|
||||
}
|
||||
)
|
||||
return resp.get("data", {})
|
||||
|
||||
async def set_device_parm(
|
||||
|
@ -1466,34 +1653,34 @@ class AnkerSolixApi:
|
|||
paramData: dict,
|
||||
paramType: str = SolixParmType.SOLARBANK_SCHEDULE.value,
|
||||
command: int = 17,
|
||||
toFile: bool = False,
|
||||
deviceSn: str = None,
|
||||
) -> dict:
|
||||
"""Set device parameters (e.g. solarbank schedule).
|
||||
|
||||
command: Must be 17 for solarbank schedule.
|
||||
paramType: was always string "4"
|
||||
Example paramData:
|
||||
{"param_data":{"ranges":[
|
||||
{"id":0,"start_time":"00:00","end_time":"08:30","turn_on":true,"appliance_loads":[{"id":0,"name":"Benutzerdefiniert","power":300,"number":1}],"charge_priority":80},
|
||||
{"id":0,"start_time":"08:30","end_time":"17:00","turn_on":false,"appliance_loads":[{"id":0,"name":"Benutzerdefiniert","power":100,"number":1}],"charge_priority":80},
|
||||
{"id":0,"start_time":"17:00","end_time":"24:00","turn_on":true,"appliance_loads":[{"id":0,"name":"Benutzerdefiniert","power":300,"number":1}],"charge_priority":0}],
|
||||
"min_load":100,"max_load":800,"step":0,"is_charge_priority":0,default_charge_priority":0}}
|
||||
{"param_data": '{"ranges":['
|
||||
'{"id":0,"start_time":"00:00","end_time":"08:30","turn_on":true,"appliance_loads":[{"id":0,"name":"Benutzerdefiniert","power":300,"number":1}],"charge_priority":80},'
|
||||
'{"id":0,"start_time":"08:30","end_time":"17:00","turn_on":false,"appliance_loads":[{"id":0,"name":"Benutzerdefiniert","power":100,"number":1}],"charge_priority":80},'
|
||||
'{"id":0,"start_time":"17:00","end_time":"24:00","turn_on":true,"appliance_loads":[{"id":0,"name":"Benutzerdefiniert","power":300,"number":1}],"charge_priority":0}],'
|
||||
'"min_load":100,"max_load":800,"step":0,"is_charge_priority":0,default_charge_priority":0}}'
|
||||
"""
|
||||
data = {
|
||||
"site_id": siteId,
|
||||
"param_type": paramType,
|
||||
"cmd": command,
|
||||
"param_data": json.dumps(paramData),
|
||||
"param_data": json.dumps(paramData), # Must be string type
|
||||
}
|
||||
if toFile:
|
||||
resp = self._saveToFile(
|
||||
os.path.join(self._testdir, f"set_device_parm_{siteId}.json"), data=data
|
||||
)
|
||||
else:
|
||||
resp = await self.request(
|
||||
"post", _API_ENDPOINTS["set_device_parm"], json=data
|
||||
)
|
||||
return resp.get("data", {})
|
||||
code = (
|
||||
await self.request("post", _API_ENDPOINTS["set_device_parm"], json=data)
|
||||
).get("code")
|
||||
if not isinstance(code, int) or int(code) != 0:
|
||||
return False
|
||||
# update the data in api dict
|
||||
if deviceSn:
|
||||
await self.get_device_parm(siteId=siteId, deviceSn=deviceSn)
|
||||
return True
|
||||
|
||||
async def get_device_fittings(
|
||||
self, siteId: str, deviceSn: str, fromFile: bool = False
|
||||
|
|
|
@ -1,33 +1,51 @@
|
|||
{
|
||||
"S8S4GS0KZKLP0BH8": {
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"AN7ZOO7INFLCIMD9": {
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"type": "solarbank",
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"is_admin": true,
|
||||
"device_pn": "A17C0",
|
||||
"battery_soc": "75",
|
||||
"battery_soc": "65",
|
||||
"battery_capacity": "1600",
|
||||
"battery_energy": "1040",
|
||||
"charging_power": "0",
|
||||
"power_unit": "W",
|
||||
"charging_status": "2",
|
||||
"charging_status_desc": "discharging",
|
||||
"status": "0",
|
||||
"status_desc": "off",
|
||||
"charging_status": "0",
|
||||
"charging_status_desc": "detection",
|
||||
"status": "1",
|
||||
"status_desc": "online",
|
||||
"wireless_type": "1",
|
||||
"input_power": "0",
|
||||
"output_power": "0",
|
||||
"alias": "Solarbank E1600",
|
||||
"bt_ble_mac": "FD49FD9BFEC1",
|
||||
"set_output_power": "0",
|
||||
"power_cutoff": 10,
|
||||
"alias": "SB E1600",
|
||||
"set_system_output_power": "0",
|
||||
"bt_ble_mac": "F24FAA9C72CF",
|
||||
"name": "Solarbank E1600",
|
||||
"battery_capacity": "1600",
|
||||
"battery_energy": "1200",
|
||||
"wifi_online": false,
|
||||
"wifi_online": true,
|
||||
"charge": false,
|
||||
"bws_surplus": "0",
|
||||
"sw_version": "v1.4.4",
|
||||
"sw_version": "v1.5.6",
|
||||
"auto_upgrade": false,
|
||||
"wifi_name": "wifi-network-1",
|
||||
"wifi_signal": "100",
|
||||
"power_cutoff": 10,
|
||||
"wifi_signal": "48",
|
||||
"power_cutoff_data": [
|
||||
{
|
||||
"id": 1,
|
||||
"is_selected": 1,
|
||||
"output_cutoff_data": 10,
|
||||
"lowpower_input_data": 5,
|
||||
"input_cutoff_data": 10
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"is_selected": 0,
|
||||
"output_cutoff_data": 5,
|
||||
"lowpower_input_data": 4,
|
||||
"input_cutoff_data": 5
|
||||
}
|
||||
],
|
||||
"solar_info": {
|
||||
"solar_brand": "ANKER",
|
||||
"solar_model": "A5140",
|
||||
|
@ -39,7 +57,7 @@
|
|||
{
|
||||
"id": 0,
|
||||
"start_time": "00:00",
|
||||
"end_time": "08:00",
|
||||
"end_time": "06:30",
|
||||
"turn_on": true,
|
||||
"appliance_loads": [
|
||||
{
|
||||
|
@ -49,19 +67,19 @@
|
|||
"number": 1
|
||||
}
|
||||
],
|
||||
"charge_priority": 80,
|
||||
"charge_priority": 0,
|
||||
"power_setting_mode": 1,
|
||||
"device_power_loads": [
|
||||
{
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"power": 150
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"start_time": "08:00",
|
||||
"end_time": "17:00",
|
||||
"start_time": "06:30",
|
||||
"end_time": "17:30",
|
||||
"turn_on": false,
|
||||
"appliance_loads": [
|
||||
{
|
||||
|
@ -75,14 +93,14 @@
|
|||
"power_setting_mode": 1,
|
||||
"device_power_loads": [
|
||||
{
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"power": 50
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"start_time": "17:00",
|
||||
"start_time": "17:30",
|
||||
"end_time": "24:00",
|
||||
"turn_on": true,
|
||||
"appliance_loads": [
|
||||
|
@ -97,7 +115,7 @@
|
|||
"power_setting_mode": 1,
|
||||
"device_power_loads": [
|
||||
{
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"power": 150
|
||||
}
|
||||
]
|
||||
|
@ -112,8 +130,6 @@
|
|||
"display_advanced_mode": 0,
|
||||
"advanced_mode_min_load": 0
|
||||
},
|
||||
"set_system_output_power": "0",
|
||||
"set_output_power": "0",
|
||||
"fittings": {}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42": {
|
||||
"a253fbdd-ab6b-048f-1887-d0bcf58ff2c5": {
|
||||
"type": "system",
|
||||
"site_info": {
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"site_name": "BKW",
|
||||
"site_img": "",
|
||||
"device_type_list": [
|
||||
|
@ -36,17 +36,17 @@
|
|||
"statistics": [
|
||||
{
|
||||
"type": "1",
|
||||
"total": "89.75",
|
||||
"total": "100.99",
|
||||
"unit": "kwh"
|
||||
},
|
||||
{
|
||||
"type": "2",
|
||||
"total": "89.48",
|
||||
"total": "100.69",
|
||||
"unit": "kg"
|
||||
},
|
||||
{
|
||||
"type": "3",
|
||||
"total": "35.90",
|
||||
"total": "33.33",
|
||||
"unit": "\u20ac"
|
||||
}
|
||||
],
|
||||
|
@ -55,37 +55,45 @@
|
|||
"solarbank_list": [
|
||||
{
|
||||
"device_pn": "A17C0",
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_name": "Solarbank E1600",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"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": "75",
|
||||
"battery_power": "65",
|
||||
"bind_site_status": "",
|
||||
"charging_power": "0",
|
||||
"power_unit": "W",
|
||||
"charging_status": "2",
|
||||
"status": "0",
|
||||
"charging_status": "0",
|
||||
"status": "1",
|
||||
"wireless_type": "1",
|
||||
"main_version": "",
|
||||
"photovoltaic_power": "0",
|
||||
"output_power": "0",
|
||||
"create_time": 1695392386,
|
||||
"set_load_power": "",
|
||||
"output_cutoff_data": 10
|
||||
"set_load_power": "0",
|
||||
"output_cutoff_data": 10,
|
||||
"is_display": true,
|
||||
"alias_name": "SB E1600",
|
||||
"current_home_load": "0"
|
||||
}
|
||||
],
|
||||
"total_charging_power": "0",
|
||||
"power_unit": "W",
|
||||
"charging_status": "0",
|
||||
"total_battery_power": "0.00",
|
||||
"updated_time": "2024-02-22 01:16:32",
|
||||
"total_battery_power": "0.65",
|
||||
"updated_time": "2024-03-07 16:10:47",
|
||||
"total_photovoltaic_power": "0",
|
||||
"total_output_power": "0.00",
|
||||
"display_set_power": false
|
||||
"display_set_power": false,
|
||||
"is_display_data": true
|
||||
},
|
||||
"retain_load": "0W",
|
||||
"updated_time": "01-01-0001 00:00:00",
|
||||
"power_site_type": 2,
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"powerpanel_list": []
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"powerpanel_list": [],
|
||||
"site_details": {
|
||||
"price": 0.33,
|
||||
"site_co2": 0,
|
||||
"site_price_unit": "\u20ac"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,13 +5,13 @@
|
|||
"main_switch": true,
|
||||
"device_list": [
|
||||
{
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"device_name": "Solarbank E1600",
|
||||
"auto_upgrade": false,
|
||||
"alias_name": "Solarbank E1600",
|
||||
"alias_name": "SB E1600",
|
||||
"icon": "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"
|
||||
}
|
||||
]
|
||||
},
|
||||
"trace_id": "466cd3eff9469c2c7deaf25f6f26ab0a"
|
||||
"trace_id": "18a4cce292c43f44034a6bd375fbeece"
|
||||
}
|
|
@ -4,15 +4,15 @@
|
|||
"data": {
|
||||
"data": [
|
||||
{
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"product_code": "A17C0",
|
||||
"bt_ble_id": "FD:49:FD:9B:FE:C1",
|
||||
"bt_ble_mac": "FD49FD9BFEC1",
|
||||
"bt_ble_id": "F2:4F:AA:9C:72:CF",
|
||||
"bt_ble_mac": "F24FAA9C72CF",
|
||||
"device_name": "Solarbank E1600",
|
||||
"alias_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",
|
||||
"link_time": 1695392302068,
|
||||
"wifi_online": false,
|
||||
"link_time": 1709743368,
|
||||
"wifi_online": true,
|
||||
"wifi_name": "",
|
||||
"relate_type": [
|
||||
"ble",
|
||||
|
@ -20,11 +20,11 @@
|
|||
],
|
||||
"charge": false,
|
||||
"bws_surplus": 0,
|
||||
"device_sw_version": "v1.4.4",
|
||||
"device_sw_version": "v1.5.6",
|
||||
"has_manual": false,
|
||||
"hes_data": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"trace_id": "731c3d838addc0fe0368cdb0c3c0c9d7"
|
||||
"trace_id": "e16b11e6cdbdef4560bbba2e513c7ccb"
|
||||
}
|
|
@ -5,5 +5,5 @@
|
|||
"device_list": null,
|
||||
"guide_txt": ""
|
||||
},
|
||||
"trace_id": "7be5820ec6c6f8d7e2fa3415e213b50b"
|
||||
"trace_id": "0ba9c2e2ecc7adbba9b4ea6adb9bfda6"
|
||||
}
|
|
@ -15,5 +15,5 @@
|
|||
"solar_model_name": "MI60 Microinverter"
|
||||
}
|
||||
},
|
||||
"trace_id": "aa0e32b025caf38eab6545a84fccb5c4"
|
||||
"trace_id": "5adcdcd9c5d644bcd1ed5ada6ccb0ccd"
|
||||
}
|
|
@ -4,5 +4,5 @@
|
|||
"data": {
|
||||
"data": []
|
||||
},
|
||||
"trace_id": "4dabbd807c0e98fe8e58ebae70910f0e"
|
||||
"trace_id": "aae331bd1ceb0982fdede5fc72eff7c4"
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"code": 0,
|
||||
"msg": "success!",
|
||||
"data": {
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"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\":0,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"AN7ZOO7INFLCIMD9\",\"power\":150}]},{\"id\":0,\"start_time\":\"06:30\",\"end_time\":\"17:30\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":100,\"number\":1}],\"charge_priority\":80,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"AN7ZOO7INFLCIMD9\",\"power\":50}]},{\"id\":0,\"start_time\":\"17:30\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":0,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"AN7ZOO7INFLCIMD9\",\"power\":150}]}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":0,\"default_charge_priority\":0,\"is_zero_output_tips\":1,\"display_advanced_mode\":0,\"advanced_mode_min_load\":0}",
|
||||
"current_home_load": "0W",
|
||||
"parallel_home_load": "",
|
||||
"parallel_display": false
|
||||
},
|
||||
"trace_id": "b2ec26d818215fdec4abdd74efefcadd"
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"code": 0,
|
||||
"msg": "success!",
|
||||
"data": {
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"home_load_data": "{\"ranges\":[{\"id\":0,\"start_time\":\"00:00\",\"end_time\":\"08:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":80,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"S8S4GS0KZKLP0BH8\",\"power\":150}]},{\"id\":0,\"start_time\":\"08:00\",\"end_time\":\"17:00\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":100,\"number\":1}],\"charge_priority\":80,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"S8S4GS0KZKLP0BH8\",\"power\":50}]},{\"id\":0,\"start_time\":\"17:00\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":0,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"S8S4GS0KZKLP0BH8\",\"power\":150}]}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":0,\"default_charge_priority\":0,\"is_zero_output_tips\":1,\"display_advanced_mode\":0,\"advanced_mode_min_load\":0}",
|
||||
"current_home_load": "0W",
|
||||
"parallel_home_load": "",
|
||||
"parallel_display": false
|
||||
},
|
||||
"trace_id": "edc0aace41b8f1dbbdd0ddb7dcbcbbc0"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"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\":0,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"AN7ZOO7INFLCIMD9\",\"power\":150}]},{\"id\":0,\"start_time\":\"06:30\",\"end_time\":\"17:30\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":100,\"number\":1}],\"charge_priority\":80,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"AN7ZOO7INFLCIMD9\",\"power\":50}]},{\"id\":0,\"start_time\":\"17:30\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":0,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"AN7ZOO7INFLCIMD9\",\"power\":150}]}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":0,\"default_charge_priority\":0,\"is_zero_output_tips\":1,\"display_advanced_mode\":0,\"advanced_mode_min_load\":0}"
|
||||
},
|
||||
"trace_id": "7d9b5fb6eca77392752c95891ef22767"
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"code": 0,
|
||||
"msg": "success!",
|
||||
"data": {
|
||||
"param_data": "{\"ranges\":[{\"id\":0,\"start_time\":\"00:00\",\"end_time\":\"08:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":80,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"S8S4GS0KZKLP0BH8\",\"power\":150}]},{\"id\":0,\"start_time\":\"08:00\",\"end_time\":\"17:00\",\"turn_on\":false,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":100,\"number\":1}],\"charge_priority\":80,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"S8S4GS0KZKLP0BH8\",\"power\":50}]},{\"id\":0,\"start_time\":\"17:00\",\"end_time\":\"24:00\",\"turn_on\":true,\"appliance_loads\":[{\"id\":0,\"name\":\"Benutzerdefiniert\",\"power\":300,\"number\":1}],\"charge_priority\":0,\"power_setting_mode\":1,\"device_power_loads\":[{\"device_sn\":\"S8S4GS0KZKLP0BH8\",\"power\":150}]}],\"min_load\":100,\"max_load\":800,\"step\":0,\"is_charge_priority\":0,\"default_charge_priority\":0,\"is_zero_output_tips\":1,\"display_advanced_mode\":0,\"advanced_mode_min_load\":0}"
|
||||
},
|
||||
"trace_id": "abe0cd159ab3d5fd1e5ed06f7bd79cbe"
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
"data": {
|
||||
"site_list": [
|
||||
{
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"site_name": "BKW",
|
||||
"site_img": "",
|
||||
"device_type_list": [
|
||||
|
@ -21,10 +21,10 @@
|
|||
"solarbank_list": [
|
||||
{
|
||||
"device_pn": "",
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_name": "Solarbank E1600",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"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": "75",
|
||||
"battery_power": "65",
|
||||
"bind_site_status": "1",
|
||||
"charging_power": "",
|
||||
"power_unit": "",
|
||||
|
@ -36,10 +36,11 @@
|
|||
"output_power": "",
|
||||
"create_time": 0,
|
||||
"set_load_power": "",
|
||||
"output_cutoff_data": 0
|
||||
"output_cutoff_data": 0,
|
||||
"is_display": false
|
||||
}
|
||||
],
|
||||
"powerpanel_list": []
|
||||
},
|
||||
"trace_id": "9a39fafe7f5c72ab4a9746a92793bf6d"
|
||||
"trace_id": "f5b4f0bd0d3dde4a93dcc131e20c4e1b"
|
||||
}
|
|
@ -19,5 +19,5 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"trace_id": "810134a03be0200fc75bf5ce15cacc3b"
|
||||
"trace_id": "13ec0de9fbc13cbe339fc2e8d0fabeda"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"code": 0,
|
||||
"msg": "success!",
|
||||
"data": {
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"price": 0.33,
|
||||
"site_co2": 0,
|
||||
"site_price_unit": "\u20ac"
|
||||
},
|
||||
"trace_id": "b3dacca456d8bd0cac185da99ac5cd75"
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"code": 0,
|
||||
"msg": "success!",
|
||||
"data": {
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"price": 0.4,
|
||||
"site_co2": 0,
|
||||
"site_price_unit": "\u20ac"
|
||||
},
|
||||
"trace_id": "3c10c236f183f13be3233f802227ffd0"
|
||||
}
|
|
@ -20,17 +20,17 @@
|
|||
"statistics": [
|
||||
{
|
||||
"type": "1",
|
||||
"total": "89.75",
|
||||
"total": "100.99",
|
||||
"unit": "kwh"
|
||||
},
|
||||
{
|
||||
"type": "2",
|
||||
"total": "89.48",
|
||||
"total": "100.69",
|
||||
"unit": "kg"
|
||||
},
|
||||
{
|
||||
"type": "3",
|
||||
"total": "35.90",
|
||||
"total": "33.33",
|
||||
"unit": "\u20ac"
|
||||
}
|
||||
],
|
||||
|
@ -39,38 +39,40 @@
|
|||
"solarbank_list": [
|
||||
{
|
||||
"device_pn": "A17C0",
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_name": "Solarbank E1600",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"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": "75",
|
||||
"battery_power": "65",
|
||||
"bind_site_status": "",
|
||||
"charging_power": "0",
|
||||
"power_unit": "W",
|
||||
"charging_status": "2",
|
||||
"status": "0",
|
||||
"charging_status": "0",
|
||||
"status": "1",
|
||||
"wireless_type": "1",
|
||||
"main_version": "",
|
||||
"photovoltaic_power": "0",
|
||||
"output_power": "0",
|
||||
"create_time": 1695392386,
|
||||
"set_load_power": "",
|
||||
"output_cutoff_data": 10
|
||||
"output_cutoff_data": 10,
|
||||
"is_display": true
|
||||
}
|
||||
],
|
||||
"total_charging_power": "0",
|
||||
"power_unit": "W",
|
||||
"charging_status": "0",
|
||||
"total_battery_power": "0.00",
|
||||
"updated_time": "2024-02-22 01:16:32",
|
||||
"total_battery_power": "0.65",
|
||||
"updated_time": "2024-03-07 16:10:47",
|
||||
"total_photovoltaic_power": "0",
|
||||
"total_output_power": "0.00",
|
||||
"display_set_power": false
|
||||
"display_set_power": false,
|
||||
"is_display_data": true
|
||||
},
|
||||
"retain_load": "0W",
|
||||
"updated_time": "01-01-0001 00:00:00",
|
||||
"power_site_type": 2,
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"powerpanel_list": []
|
||||
},
|
||||
"trace_id": "be165dce6edbfda3eef203e9f8cd3cfb"
|
||||
"trace_id": "f1db89088b5ef100b876e2dabf387b9d"
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
"msg": "success!",
|
||||
"data": {
|
||||
"site_info": {
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"site_name": "BKW",
|
||||
"site_img": "",
|
||||
"device_type_list": [
|
||||
|
@ -23,8 +23,8 @@
|
|||
"solarbank_list": [
|
||||
{
|
||||
"device_pn": "A17C0",
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_name": "Solarbank E1600",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"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": "",
|
||||
"bind_site_status": "",
|
||||
|
@ -38,10 +38,11 @@
|
|||
"output_power": "",
|
||||
"create_time": 1695392386,
|
||||
"set_load_power": "",
|
||||
"output_cutoff_data": 0
|
||||
"output_cutoff_data": 0,
|
||||
"is_display": false
|
||||
}
|
||||
],
|
||||
"powerpanel_list": []
|
||||
},
|
||||
"trace_id": "42fca6e31c7597b30ccb8bafdb5c409f"
|
||||
"trace_id": "cf2dda7f4a1db4dcbafd2314deee10c8"
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
"data": {
|
||||
"site_list": [
|
||||
{
|
||||
"site_id": "c6a3216c-b3bd-fe9a-bd00-e46bfe61ee42",
|
||||
"site_id": "a253fbdd-ab6b-048f-1887-d0bcf58ff2c5",
|
||||
"site_name": "BKW",
|
||||
"site_img": "",
|
||||
"device_type_list": [
|
||||
|
@ -21,5 +21,5 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"trace_id": "f4a07b0fc7eda9aac8a047bfe3ce0881"
|
||||
"trace_id": "5de5a4ec2ebc9f2cff1fa10f1ae98ac3"
|
||||
}
|
|
@ -8,5 +8,5 @@
|
|||
"solar_sn": "",
|
||||
"solar_model_name": "MI60 Microinverter"
|
||||
},
|
||||
"trace_id": "a982c1bc38ab3f9da5afef26e496f013"
|
||||
"trace_id": "45452d1ecaf757adaa5eaeac7e1c2abb"
|
||||
}
|
|
@ -7,25 +7,26 @@
|
|||
"solarbank_list": [
|
||||
{
|
||||
"device_pn": "A17C0",
|
||||
"device_sn": "S8S4GS0KZKLP0BH8",
|
||||
"device_name": "Solarbank E1600",
|
||||
"device_sn": "AN7ZOO7INFLCIMD9",
|
||||
"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": "",
|
||||
"bind_site_status": "1",
|
||||
"charging_power": "",
|
||||
"power_unit": "",
|
||||
"charging_status": "",
|
||||
"status": "0",
|
||||
"status": "1",
|
||||
"wireless_type": "1",
|
||||
"main_version": "",
|
||||
"photovoltaic_power": "",
|
||||
"output_power": "",
|
||||
"create_time": 0,
|
||||
"set_load_power": "",
|
||||
"output_cutoff_data": 0
|
||||
"output_cutoff_data": 0,
|
||||
"is_display": false
|
||||
}
|
||||
],
|
||||
"powerpanel_list": []
|
||||
},
|
||||
"trace_id": "e9eeb54a20b422df82fafdaedc75f21f"
|
||||
"trace_id": "6e7ce08a0a87cf45c6cba57efb68abcb"
|
||||
}
|
|
@ -5,9 +5,9 @@
|
|||
"wifi_info_list": [
|
||||
{
|
||||
"wifi_name": "wifi-network-1",
|
||||
"wifi_signal": "100"
|
||||
"wifi_signal": "48"
|
||||
}
|
||||
]
|
||||
},
|
||||
"trace_id": "0a0d59c1b266de112d9028dfcfcf5ffe"
|
||||
"trace_id": "a12c7ddfdc319ffa7ca7ae9187ecfa8d"
|
||||
}
|
|
@ -403,6 +403,7 @@ async def main() -> bool: # noqa: C901 # pylint: disable=too-many-branches,too-
|
|||
# this is more efficient and allows validation of randomized data in export files
|
||||
myapi.testDir(folder)
|
||||
await myapi.update_sites(fromFile=True)
|
||||
await myapi.update_site_details(fromFile=True)
|
||||
await myapi.update_device_details(fromFile=True)
|
||||
# avoid randomizing dictionary export twice when imported from randomized files already
|
||||
CONSOLE.info("\nExporting Api Sites overview...")
|
||||
|
|
|
@ -177,7 +177,7 @@ async def main() -> ( # noqa: C901 # pylint: disable=too-many-locals,too-many-b
|
|||
f"{'SW Version':<{col1}}: {dev.get('sw_version','Unknown'):<{col2}} {'Auto-Upgrade':<{col3}}: {'Unknown' if upgrade is None else 'Enabled' if upgrade else 'Disabled'}"
|
||||
)
|
||||
CONSOLE.info(
|
||||
f"{'Status':<{col1}}: {dev.get('status_desc','Unknown'):<{col2}} {'Status code':<{col3}}: {str(dev.get('status','-'))}"
|
||||
f"{'Cloud Status':<{col1}}: {dev.get('status_desc','Unknown'):<{col2}} {'Status code':<{col3}}: {str(dev.get('status','-'))}"
|
||||
)
|
||||
CONSOLE.info(
|
||||
f"{'Charge Status':<{col1}}: {dev.get('charging_status_desc','Unknown'):<{col2}} {'Status code':<{col3}}: {str(dev.get('charging_status','-'))}"
|
||||
|
|
Loading…
Reference in New Issue