foxesscloud 2.7.7__tar.gz → 2.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {foxesscloud-2.7.7/src/foxesscloud.egg-info → foxesscloud-2.8.0}/PKG-INFO +16 -2
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/README.md +15 -1
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/pyproject.toml +1 -1
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/src/foxesscloud/foxesscloud.py +30 -17
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/src/foxesscloud/openapi.py +33 -21
- {foxesscloud-2.7.7 → foxesscloud-2.8.0/src/foxesscloud.egg-info}/PKG-INFO +16 -2
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/LICENCE +0 -0
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/setup.cfg +0 -0
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/src/foxesscloud.egg-info/SOURCES.txt +0 -0
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/src/foxesscloud.egg-info/dependency_links.txt +0 -0
- {foxesscloud-2.7.7 → foxesscloud-2.8.0}/src/foxesscloud.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foxesscloud
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.8.0
|
4
4
|
Summary: library for accessing Fox ESS cloud data using Open API
|
5
5
|
Author-email: Tony Matthews <tony@quasair.co.uk>
|
6
6
|
Project-URL: Homepage, https://github.com/TonyM1958/FoxESS-Cloud
|
@@ -358,7 +358,9 @@ All the parameters are optional:
|
|
358
358
|
|
359
359
|
charge_needed() uses a number of models to better estimate the state of the battery.
|
360
360
|
|
361
|
-
**Manual Consumption:** You can provide your '
|
361
|
+
**Manual Consumption:** You can provide your expected 'consumption' in kWh e.g. 15. This figure is used directly.
|
362
|
+
|
363
|
+
**Annual Consumption:** You can provide your 'annual_consumption' in kWh e.g. 5500. This figure is factored down to a daily consumption by dividing by 365 and applying **f.seasonality**. This normally decreases consumption in the summer and increases it in winter. Seasonality is a list of weightings by month for Jan, Feb, Mar, Apr etc. Preset lists are 'f.high_seasonality' (recommend where electric heating is ued), 'f.medium_seasonality' (default) amd 'f.no_seasonality' (all months the same). The daily consumption is profiled by hour using **f.daily_consumption**. This maps your consumption for a day to the hours when more or less energy is consumed. It is a list of 24 values for the times 00, 01, 02, 03 .. 23. Preset lists are 'f.high_profile' (larger peaks at 8am and 6pm), 'f.medium_profile' (default, more balanced) and 'f.no_profile' (flat).
|
362
364
|
|
363
365
|
**Historic Consumption:** If annual_consumption is not provided, your consumption history is used. By default, this looks at your average consumption for the last 3 days using the load power reported by your inverter. For systems with multiple inverters where CT2 is not connected, the load power may not be correct. For this and other cases where you want to set your consumption, provide your annual_consumption.
|
364
366
|
|
@@ -807,6 +809,18 @@ This setting can be:
|
|
807
809
|
|
808
810
|
# Version Info
|
809
811
|
|
812
|
+
2.8.0<br>
|
813
|
+
Update from v0 to v1 for scheduler API.
|
814
|
+
PVEnergyTotal added to report variables.
|
815
|
+
Fix residual if capacity is specified for charge_needed().
|
816
|
+
|
817
|
+
2.7.9<br>
|
818
|
+
Add 'consumption' input for charge_needed().
|
819
|
+
Avoid throwing exception in battery_info() if there is no capacity info.
|
820
|
+
|
821
|
+
2.7.8<br>
|
822
|
+
Update the battery_params charge rate table to 2025 values.
|
823
|
+
|
810
824
|
2.7.7<br>
|
811
825
|
Updates to get_pvoutput() to support solar inverters that don't provide grid energy by setting tou=2.
|
812
826
|
Default tariff changed to None.
|
@@ -344,7 +344,9 @@ All the parameters are optional:
|
|
344
344
|
|
345
345
|
charge_needed() uses a number of models to better estimate the state of the battery.
|
346
346
|
|
347
|
-
**Manual Consumption:** You can provide your '
|
347
|
+
**Manual Consumption:** You can provide your expected 'consumption' in kWh e.g. 15. This figure is used directly.
|
348
|
+
|
349
|
+
**Annual Consumption:** You can provide your 'annual_consumption' in kWh e.g. 5500. This figure is factored down to a daily consumption by dividing by 365 and applying **f.seasonality**. This normally decreases consumption in the summer and increases it in winter. Seasonality is a list of weightings by month for Jan, Feb, Mar, Apr etc. Preset lists are 'f.high_seasonality' (recommend where electric heating is ued), 'f.medium_seasonality' (default) amd 'f.no_seasonality' (all months the same). The daily consumption is profiled by hour using **f.daily_consumption**. This maps your consumption for a day to the hours when more or less energy is consumed. It is a list of 24 values for the times 00, 01, 02, 03 .. 23. Preset lists are 'f.high_profile' (larger peaks at 8am and 6pm), 'f.medium_profile' (default, more balanced) and 'f.no_profile' (flat).
|
348
350
|
|
349
351
|
**Historic Consumption:** If annual_consumption is not provided, your consumption history is used. By default, this looks at your average consumption for the last 3 days using the load power reported by your inverter. For systems with multiple inverters where CT2 is not connected, the load power may not be correct. For this and other cases where you want to set your consumption, provide your annual_consumption.
|
350
352
|
|
@@ -793,6 +795,18 @@ This setting can be:
|
|
793
795
|
|
794
796
|
# Version Info
|
795
797
|
|
798
|
+
2.8.0<br>
|
799
|
+
Update from v0 to v1 for scheduler API.
|
800
|
+
PVEnergyTotal added to report variables.
|
801
|
+
Fix residual if capacity is specified for charge_needed().
|
802
|
+
|
803
|
+
2.7.9<br>
|
804
|
+
Add 'consumption' input for charge_needed().
|
805
|
+
Avoid throwing exception in battery_info() if there is no capacity info.
|
806
|
+
|
807
|
+
2.7.8<br>
|
808
|
+
Update the battery_params charge rate table to 2025 values.
|
809
|
+
|
796
810
|
2.7.7<br>
|
797
811
|
Updates to get_pvoutput() to support solar inverters that don't provide grid energy by setting tou=2.
|
798
812
|
Default tariff changed to None.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
##################################################################################################
|
2
2
|
"""
|
3
3
|
Module: Fox ESS Cloud
|
4
|
-
Updated:
|
4
|
+
Updated: 12 March 2025
|
5
5
|
By: Tony Matthews
|
6
6
|
"""
|
7
7
|
##################################################################################################
|
@@ -10,7 +10,7 @@ By: Tony Matthews
|
|
10
10
|
# ALL RIGHTS ARE RESERVED © Tony Matthews 2023
|
11
11
|
##################################################################################################
|
12
12
|
|
13
|
-
version = "1.
|
13
|
+
version = "1.9.2"
|
14
14
|
print(f"FoxESS-Cloud version {version}")
|
15
15
|
|
16
16
|
debug_setting = 1
|
@@ -590,32 +590,37 @@ battery_settings = None
|
|
590
590
|
|
591
591
|
# 1 = Residual Energy, 2 = Residual Capacity (HV), 3 = Residual Capacity per battery (Mira)
|
592
592
|
residual_handling = 1
|
593
|
+
residual_scale = 0.01
|
593
594
|
|
594
|
-
# charge rates based on residual_handling
|
595
|
+
# charge rates based on residual_handling. Index is bms temperature
|
595
596
|
battery_params = {
|
596
|
-
# cell temp -5 0 5 10 15 20 25 30 35 40 45 50 55
|
597
597
|
# bms temp 5 10 15 20 25 30 35 40 45 50 55 60 65
|
598
|
+
# cell temp -5 0 5 10 15 20 25 30 35 40 45 50 55
|
598
599
|
1: {'table': [ 0, 2, 10, 15, 25, 50, 50, 50, 50, 50, 30, 20, 0],
|
599
600
|
'step': 5,
|
600
601
|
'offset': 5,
|
601
602
|
'charge_loss': 0.974,
|
602
603
|
'discharge_loss': 0.974},
|
603
|
-
|
604
|
-
|
604
|
+
# HV BMS v2 with firmware 1.014 or later
|
605
|
+
# bms temp 10 15 20 25 30 35 40 45 50 55 60 65 70
|
606
|
+
# cell temp 0 5 10 15 20 25 30 35 40 45 50 55 60
|
607
|
+
2: {'table': [ 0, 5, 10, 15, 25, 50, 50, 50, 50, 25, 20, 3, 0],
|
605
608
|
'step': 5,
|
606
|
-
'offset':
|
609
|
+
'offset': 11,
|
607
610
|
'charge_loss': 1.08,
|
608
611
|
'discharge_loss': 0.95},
|
609
|
-
|
610
|
-
|
612
|
+
# Mira BMS with firmware 1.014 or later
|
613
|
+
# bms temp 10 15 20 25 30 35 40 45 50 55 60 65 70
|
614
|
+
# cell temp 0 5 10 15 20 25 30 35 40 45 50 55 60
|
615
|
+
3: {'table': [ 0, 5, 10, 15, 25, 50, 50, 50, 50, 25, 20, 3, 0],
|
611
616
|
'step': 5,
|
612
|
-
'offset':
|
617
|
+
'offset': 11,
|
613
618
|
'charge_loss': 0.974,
|
614
619
|
'discharge_loss': 0.974},
|
615
620
|
}
|
616
621
|
|
617
622
|
def get_battery(info=1, rated=None, count=None):
|
618
|
-
global device_id, battery, debug_setting, messages, residual_handling, battery_params
|
623
|
+
global device_id, battery, debug_setting, messages, residual_handling, battery_params, residual_scale
|
619
624
|
if get_device() is None:
|
620
625
|
return None
|
621
626
|
output(f"getting battery", 2)
|
@@ -655,7 +660,7 @@ def get_battery(info=1, rated=None, count=None):
|
|
655
660
|
output(f"** get_battery(): battery status not available")
|
656
661
|
return None
|
657
662
|
if battery.get('residual') is not None:
|
658
|
-
battery['residual']
|
663
|
+
battery['residual'] *= residual_scale / 10
|
659
664
|
if battery['residual_handling'] == 2:
|
660
665
|
capacity = battery.get('residual')
|
661
666
|
soc = battery.get('soc')
|
@@ -1822,7 +1827,7 @@ def rescale_history(data, steps):
|
|
1822
1827
|
# station = 0: use device_id, 1 = use station_id
|
1823
1828
|
##################################################################################################
|
1824
1829
|
|
1825
|
-
report_vars = ['
|
1830
|
+
report_vars = ['PVEnergyTotal', 'input','generation', 'feedin', 'loads', 'gridConsumption', 'chargeEnergyToTal', 'dischargeEnergyToTal']
|
1826
1831
|
report_names = ['PV Yield', 'Input', 'Generation', 'Grid Export', 'Consumption', 'Grid Import', 'Battery Charge', 'Battery Discharge']
|
1827
1832
|
|
1828
1833
|
# fix power values after fox corrupts high word of 32-bit energy total
|
@@ -2953,6 +2958,7 @@ charge_needed_app_key = "awcr5gro2v13oher3v1qu6hwnovp28"
|
|
2953
2958
|
|
2954
2959
|
# work out the charge times to set using the parameters:
|
2955
2960
|
# forecast: the kWh expected tomorrow. If none, forecast data is loaded from solcast etc
|
2961
|
+
# consumption: the kWh consumed. If none, consumption is loaded from history
|
2956
2962
|
# update_settings: 0 no updates, 1 update charge settings. The default is 0
|
2957
2963
|
# show_data: 1 shows battery SoC, 2 shows battery residual. Default = 0
|
2958
2964
|
# show_plot: 1 plots battery SoC, 2 plots battery residual. Default = 1
|
@@ -2960,7 +2966,7 @@ charge_needed_app_key = "awcr5gro2v13oher3v1qu6hwnovp28"
|
|
2960
2966
|
# forecast_times: list of hours when forecast can be fetched (UTC)
|
2961
2967
|
# force_charge: 1 = hold battery, 2 = charge for whole period
|
2962
2968
|
|
2963
|
-
def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=None, show_plot=None, run_after=None, reload=2,
|
2969
|
+
def charge_needed(forecast=None, consumption=None, update_settings=0, timed_mode=None, show_data=None, show_plot=None, run_after=None, reload=2,
|
2964
2970
|
forecast_times=None, force_charge=0, test_time=None, test_soc=None, test_charge=None, **settings):
|
2965
2971
|
global device, seasonality, solcast_api_key, debug_setting, tariff, solar_arrays, legend_location, time_shift, charge_needed_app_key
|
2966
2972
|
global timed_strategy, steps_per_hour, base_time, storage, battery, battery_params
|
@@ -3088,7 +3094,10 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
|
|
3088
3094
|
bat_current = battery['current']
|
3089
3095
|
temperature = battery['temperature']
|
3090
3096
|
residual = battery['residual']
|
3091
|
-
capacity =
|
3097
|
+
capacity = battery.get('capacity')
|
3098
|
+
if charge_config.get('capacity') is not None:
|
3099
|
+
capacity = charge_config['capacity']
|
3100
|
+
residual = (capacity * current_soc / 100) if capacity is not None and current_soc is not None else None
|
3092
3101
|
if capacity is None:
|
3093
3102
|
output(f"Battery capacity could not be estimated. Please add the parameter 'capacity=xx' in kWh")
|
3094
3103
|
return None
|
@@ -3172,6 +3181,9 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
|
|
3172
3181
|
consumption = annual_consumption / 365 * seasonality[now.month - 1] / sum(seasonality) * 12
|
3173
3182
|
consumption_by_hour = daily_consumption
|
3174
3183
|
output(f"\nEstimated consumption: {consumption:.1f}kWh")
|
3184
|
+
elif consumption is not None:
|
3185
|
+
consumption_by_hour = daily_consumption
|
3186
|
+
output(f"\nConsumption: {consumption:.1f}kWh")
|
3175
3187
|
else:
|
3176
3188
|
consumption_days = charge_config['consumption_days']
|
3177
3189
|
consumption_days = 3 if consumption_days > 7 or consumption_days < 1 else consumption_days
|
@@ -3633,7 +3645,7 @@ def battery_info(log=0, plot=1, rated=None, count=None, info=1, bat=None):
|
|
3633
3645
|
bat_current = bat['current']
|
3634
3646
|
bat_power = bat['power']
|
3635
3647
|
bms_temperature = bat['temperature']
|
3636
|
-
capacity = bat
|
3648
|
+
capacity = bat.get('capacity')
|
3637
3649
|
cell_volts = get_cell_volts()
|
3638
3650
|
if cell_volts is None:
|
3639
3651
|
output_close()
|
@@ -3678,7 +3690,8 @@ def battery_info(log=0, plot=1, rated=None, count=None, info=1, bat=None):
|
|
3678
3690
|
s +=f",{v:.0f}"
|
3679
3691
|
return s
|
3680
3692
|
output(f"Current SoC: {current_soc}%")
|
3681
|
-
|
3693
|
+
if capacity is not None:
|
3694
|
+
output(f"Capacity: {capacity:.2f}kWh" + (" (calculated)" if bat['residual_handling'] in [1,3] else ""))
|
3682
3695
|
output(f"Residual: {residual:.2f}kWh" + (" (calculated)" if bat['residual_handling'] in [2,3] else ""))
|
3683
3696
|
if rated_capacity is not None and bat_soh is not None:
|
3684
3697
|
output(f"Rated Capacity: {rated_capacity / 1000:.2f}kWh")
|
@@ -1,7 +1,7 @@
|
|
1
1
|
##################################################################################################
|
2
2
|
"""
|
3
3
|
Module: Fox ESS Cloud using Open API
|
4
|
-
Updated:
|
4
|
+
Updated: 12 March 2025
|
5
5
|
By: Tony Matthews
|
6
6
|
"""
|
7
7
|
##################################################################################################
|
@@ -10,7 +10,7 @@ By: Tony Matthews
|
|
10
10
|
# ALL RIGHTS ARE RESERVED © Tony Matthews 2024
|
11
11
|
##################################################################################################
|
12
12
|
|
13
|
-
version = "2.
|
13
|
+
version = "2.8.0"
|
14
14
|
print(f"FoxESS-Cloud Open API version {version}")
|
15
15
|
|
16
16
|
debug_setting = 1
|
@@ -555,25 +555,29 @@ battery_data = ['soc', 'volt', 'current', 'power', 'temperature', 'residual']
|
|
555
555
|
# 1 = Residual Energy, 2 = Residual Capacity (HV), 3 = Residual Capacity per battery (Mira)
|
556
556
|
residual_handling = 1
|
557
557
|
|
558
|
-
# charge rates based on residual_handling
|
558
|
+
# charge rates based on residual_handling. Index is bms temperature
|
559
559
|
battery_params = {
|
560
|
-
# cell temp -5 0 5 10 15 20 25 30 35 40 45 50 55
|
561
560
|
# bms temp 5 10 15 20 25 30 35 40 45 50 55 60 65
|
561
|
+
# cell temp -5 0 5 10 15 20 25 30 35 40 45 50 55
|
562
562
|
1: {'table': [ 0, 2, 10, 15, 25, 50, 50, 50, 50, 50, 30, 20, 0],
|
563
563
|
'step': 5,
|
564
564
|
'offset': 5,
|
565
565
|
'charge_loss': 0.974,
|
566
566
|
'discharge_loss': 0.974},
|
567
|
-
|
568
|
-
|
567
|
+
# HV BMS v2 with firmware 1.014 or later
|
568
|
+
# bms temp 10 15 20 25 30 35 40 45 50 55 60 65 70
|
569
|
+
# cell temp 0 5 10 15 20 25 30 35 40 45 50 55 60
|
570
|
+
2: {'table': [ 0, 5, 10, 15, 25, 50, 50, 50, 50, 25, 20, 3, 0],
|
569
571
|
'step': 5,
|
570
|
-
'offset':
|
572
|
+
'offset': 11,
|
571
573
|
'charge_loss': 1.08,
|
572
574
|
'discharge_loss': 0.95},
|
573
|
-
|
574
|
-
|
575
|
+
# Mira BMS with firmware 1.014 or later
|
576
|
+
# bms temp 10 15 20 25 30 35 40 45 50 55 60 65 70
|
577
|
+
# cell temp 0 5 10 15 20 25 30 35 40 45 50 55 60
|
578
|
+
3: {'table': [ 0, 5, 10, 15, 25, 50, 50, 50, 50, 25, 20, 3, 0],
|
575
579
|
'step': 5,
|
576
|
-
'offset':
|
580
|
+
'offset': 11,
|
577
581
|
'charge_loss': 0.974,
|
578
582
|
'discharge_loss': 0.974},
|
579
583
|
}
|
@@ -1006,7 +1010,7 @@ def get_flag():
|
|
1006
1010
|
return None
|
1007
1011
|
output(f"getting flag", 2)
|
1008
1012
|
body = {'deviceSN': device_sn}
|
1009
|
-
response = signed_post(path="/op/
|
1013
|
+
response = signed_post(path="/op/v1/device/scheduler/get/flag", body=body)
|
1010
1014
|
if response.status_code != 200:
|
1011
1015
|
output(f"** get_flag() got response code {response.status_code}: {response.reason}")
|
1012
1016
|
return None
|
@@ -1036,7 +1040,7 @@ def get_schedule():
|
|
1036
1040
|
return None
|
1037
1041
|
output(f"getting schedule", 2)
|
1038
1042
|
body = {'deviceSN': device_sn}
|
1039
|
-
response = signed_post(path="/op/
|
1043
|
+
response = signed_post(path="/op/v1/device/scheduler/get", body=body)
|
1040
1044
|
if response.status_code != 200:
|
1041
1045
|
output(f"** get_schedule() got response code {response.status_code}: {response.reason}")
|
1042
1046
|
return None
|
@@ -1129,7 +1133,7 @@ def set_period(start=None, end=None, mode=None, min_soc=None, max_soc=None, fdso
|
|
1129
1133
|
period = {'enable': enable, 'startHour': start_hour, 'startMinute': start_minute, 'endHour': end_hour, 'endMinute': end_minute, 'workMode': mode,
|
1130
1134
|
'minSocOnGrid': int(min_soc), 'fdSoc': int(fdsoc), 'fdPwr': int(fdpwr)}
|
1131
1135
|
if max_soc is not None:
|
1132
|
-
period['
|
1136
|
+
period['maxSoc'] = int(max_soc)
|
1133
1137
|
return period
|
1134
1138
|
|
1135
1139
|
# set a schedule from a period or list of time segment periods
|
@@ -1156,7 +1160,7 @@ def set_schedule(periods=None, enable=True):
|
|
1156
1160
|
output(f"** set_schedule(): maximum of 8 periods allowed, {len(periods)} provided")
|
1157
1161
|
body = {'deviceSN': device_sn, 'groups': periods[-8:]}
|
1158
1162
|
setting_delay()
|
1159
|
-
response = signed_post(path="/op/
|
1163
|
+
response = signed_post(path="/op/v1/device/scheduler/enable", body=body)
|
1160
1164
|
if response.status_code != 200:
|
1161
1165
|
output(f"** set_schedule() periods response code {response.status_code}: {response.reason}")
|
1162
1166
|
return None
|
@@ -1167,7 +1171,7 @@ def set_schedule(periods=None, enable=True):
|
|
1167
1171
|
schedule['periods'] = periods
|
1168
1172
|
body = {'deviceSN': device_sn, 'enable': 1 if enable else 0}
|
1169
1173
|
setting_delay()
|
1170
|
-
response = signed_post(path="/op/
|
1174
|
+
response = signed_post(path="/op/v1/device/scheduler/set/flag", body=body)
|
1171
1175
|
if response.status_code != 200:
|
1172
1176
|
output(f"** set_schedule() flag response code {response.status_code}: {response.reason}")
|
1173
1177
|
return None
|
@@ -1526,8 +1530,8 @@ def rescale_history(data, steps):
|
|
1526
1530
|
# plot = 0: no plot, 1 = plot variables separately, 2 = combine variables
|
1527
1531
|
##################################################################################################
|
1528
1532
|
|
1529
|
-
report_vars = ['generation', 'feedin', 'loads', 'gridConsumption', 'chargeEnergyToTal', 'dischargeEnergyToTal']
|
1530
|
-
report_names = ['Generation', 'Grid Export', 'Consumption', 'Grid Import', 'Battery Charge', 'Battery Discharge']
|
1533
|
+
report_vars = ['generation', 'feedin', 'loads', 'gridConsumption', 'chargeEnergyToTal', 'dischargeEnergyToTal', 'PVEnergyTotal']
|
1534
|
+
report_names = ['Generation', 'Grid Export', 'Consumption', 'Grid Import', 'Battery Charge', 'Battery Discharge', 'PV Yield']
|
1531
1535
|
|
1532
1536
|
# fix power values after corruption of high word of 32-bit energy total
|
1533
1537
|
fix_values = 1
|
@@ -2624,6 +2628,7 @@ charge_needed_app_key = "awcr5gro2v13oher3v1qu6hwnovp28"
|
|
2624
2628
|
|
2625
2629
|
# work out the charge times to set using the parameters:
|
2626
2630
|
# forecast: the kWh expected tomorrow. If none, forecast data is loaded from solcast etc
|
2631
|
+
# consumption: the kWh consumed. If none, consumption is loaded from history
|
2627
2632
|
# update_settings: 0 no updates, 1 update charge settings. The default is 0
|
2628
2633
|
# show_data: 1 shows battery SoC, 2 shows battery residual. Default = 0
|
2629
2634
|
# show_plot: 1 plots battery SoC, 2 plots battery residual. Default = 1
|
@@ -2631,7 +2636,7 @@ charge_needed_app_key = "awcr5gro2v13oher3v1qu6hwnovp28"
|
|
2631
2636
|
# forecast_times: list of hours when forecast can be fetched (UTC)
|
2632
2637
|
# force_charge: 1 = hold battery, 2 = charge for whole period
|
2633
2638
|
|
2634
|
-
def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=None, show_plot=None, run_after=None, reload=2,
|
2639
|
+
def charge_needed(forecast=None, consumption=None, update_settings=0, timed_mode=None, show_data=None, show_plot=None, run_after=None, reload=2,
|
2635
2640
|
forecast_times=None, force_charge=0, test_time=None, test_soc=None, test_charge=None, **settings):
|
2636
2641
|
global device, seasonality, solcast_api_key, debug_setting, tariff, solar_arrays, legend_location, time_shift, charge_needed_app_key
|
2637
2642
|
global timed_strategy, steps_per_hour, base_time, storage, battery, battery_params
|
@@ -2759,7 +2764,10 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
|
|
2759
2764
|
bat_current = battery['current']
|
2760
2765
|
temperature = battery['temperature']
|
2761
2766
|
residual = battery['residual']
|
2762
|
-
capacity =
|
2767
|
+
capacity = battery.get('capacity')
|
2768
|
+
if charge_config.get('capacity') is not None:
|
2769
|
+
capacity = charge_config['capacity']
|
2770
|
+
residual = (capacity * current_soc / 100) if capacity is not None and current_soc is not None else None
|
2763
2771
|
if capacity is None:
|
2764
2772
|
output(f"Battery capacity could not be estimated. Please add the parameter 'capacity=xx' in kWh")
|
2765
2773
|
return None
|
@@ -2847,6 +2855,9 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
|
|
2847
2855
|
consumption = annual_consumption / 365 * seasonality[now.month - 1] / sum(seasonality) * 12
|
2848
2856
|
consumption_by_hour = daily_consumption
|
2849
2857
|
output(f"\nEstimated consumption: {consumption:.1f}kWh")
|
2858
|
+
elif consumption is not None:
|
2859
|
+
consumption_by_hour = daily_consumption
|
2860
|
+
output(f"\nConsumption: {consumption:.1f}kWh")
|
2850
2861
|
else:
|
2851
2862
|
consumption_days = charge_config['consumption_days']
|
2852
2863
|
consumption_days = 3 if consumption_days > 7 or consumption_days < 1 else consumption_days
|
@@ -3305,7 +3316,7 @@ def battery_info(log=0, plot=1, rated=None, count=None, info=1, bat=None):
|
|
3305
3316
|
bat_current = bat['current']
|
3306
3317
|
bat_power = bat['power']
|
3307
3318
|
bms_temperature = bat['temperature']
|
3308
|
-
capacity = bat
|
3319
|
+
capacity = bat.get('capacity')
|
3309
3320
|
cell_volts = get_cell_volts()
|
3310
3321
|
if cell_volts is None:
|
3311
3322
|
output_close()
|
@@ -3350,7 +3361,8 @@ def battery_info(log=0, plot=1, rated=None, count=None, info=1, bat=None):
|
|
3350
3361
|
s +=f",{v:.0f}"
|
3351
3362
|
return s
|
3352
3363
|
output(f"Current SoC: {current_soc}%")
|
3353
|
-
|
3364
|
+
if capacity is not None:
|
3365
|
+
output(f"Capacity: {capacity:.2f}kWh" + (" (calculated)" if bat['residual_handling'] in [1,3] else ""))
|
3354
3366
|
output(f"Residual: {residual:.2f}kWh" + (" (calculated)" if bat['residual_handling'] in [2,3] else ""))
|
3355
3367
|
if rated_capacity is not None and bat_soh is not None:
|
3356
3368
|
output(f"Rated Capacity: {rated_capacity / 1000:.2f}kWh")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foxesscloud
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.8.0
|
4
4
|
Summary: library for accessing Fox ESS cloud data using Open API
|
5
5
|
Author-email: Tony Matthews <tony@quasair.co.uk>
|
6
6
|
Project-URL: Homepage, https://github.com/TonyM1958/FoxESS-Cloud
|
@@ -358,7 +358,9 @@ All the parameters are optional:
|
|
358
358
|
|
359
359
|
charge_needed() uses a number of models to better estimate the state of the battery.
|
360
360
|
|
361
|
-
**Manual Consumption:** You can provide your '
|
361
|
+
**Manual Consumption:** You can provide your expected 'consumption' in kWh e.g. 15. This figure is used directly.
|
362
|
+
|
363
|
+
**Annual Consumption:** You can provide your 'annual_consumption' in kWh e.g. 5500. This figure is factored down to a daily consumption by dividing by 365 and applying **f.seasonality**. This normally decreases consumption in the summer and increases it in winter. Seasonality is a list of weightings by month for Jan, Feb, Mar, Apr etc. Preset lists are 'f.high_seasonality' (recommend where electric heating is ued), 'f.medium_seasonality' (default) amd 'f.no_seasonality' (all months the same). The daily consumption is profiled by hour using **f.daily_consumption**. This maps your consumption for a day to the hours when more or less energy is consumed. It is a list of 24 values for the times 00, 01, 02, 03 .. 23. Preset lists are 'f.high_profile' (larger peaks at 8am and 6pm), 'f.medium_profile' (default, more balanced) and 'f.no_profile' (flat).
|
362
364
|
|
363
365
|
**Historic Consumption:** If annual_consumption is not provided, your consumption history is used. By default, this looks at your average consumption for the last 3 days using the load power reported by your inverter. For systems with multiple inverters where CT2 is not connected, the load power may not be correct. For this and other cases where you want to set your consumption, provide your annual_consumption.
|
364
366
|
|
@@ -807,6 +809,18 @@ This setting can be:
|
|
807
809
|
|
808
810
|
# Version Info
|
809
811
|
|
812
|
+
2.8.0<br>
|
813
|
+
Update from v0 to v1 for scheduler API.
|
814
|
+
PVEnergyTotal added to report variables.
|
815
|
+
Fix residual if capacity is specified for charge_needed().
|
816
|
+
|
817
|
+
2.7.9<br>
|
818
|
+
Add 'consumption' input for charge_needed().
|
819
|
+
Avoid throwing exception in battery_info() if there is no capacity info.
|
820
|
+
|
821
|
+
2.7.8<br>
|
822
|
+
Update the battery_params charge rate table to 2025 values.
|
823
|
+
|
810
824
|
2.7.7<br>
|
811
825
|
Updates to get_pvoutput() to support solar inverters that don't provide grid energy by setting tou=2.
|
812
826
|
Default tariff changed to None.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|