foxesscloud 2.7.6__tar.gz → 2.7.9__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.6 → foxesscloud-2.7.9}/LICENCE +1 -1
- {foxesscloud-2.7.6 → foxesscloud-2.7.9}/PKG-INFO +17 -4
- foxesscloud-2.7.6/src/foxesscloud.egg-info/PKG-INFO → foxesscloud-2.7.9/README.md +16 -17
- {foxesscloud-2.7.6 → foxesscloud-2.7.9}/pyproject.toml +1 -1
- {foxesscloud-2.7.6 → foxesscloud-2.7.9}/src/foxesscloud/foxesscloud.py +36 -21
- {foxesscloud-2.7.6 → foxesscloud-2.7.9}/src/foxesscloud/openapi.py +36 -21
- foxesscloud-2.7.6/README.md → foxesscloud-2.7.9/src/foxesscloud.egg-info/PKG-INFO +30 -3
- {foxesscloud-2.7.6 → foxesscloud-2.7.9}/setup.cfg +0 -0
- {foxesscloud-2.7.6 → foxesscloud-2.7.9}/src/foxesscloud.egg-info/SOURCES.txt +0 -0
- {foxesscloud-2.7.6 → foxesscloud-2.7.9}/src/foxesscloud.egg-info/dependency_links.txt +0 -0
- {foxesscloud-2.7.6 → foxesscloud-2.7.9}/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.7.
|
3
|
+
Version: 2.7.9
|
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
|
|
@@ -629,7 +631,7 @@ f.get_pvoutput(d, tou)
|
|
629
631
|
```
|
630
632
|
|
631
633
|
+ d is the date or a list of dates, to get data for. The default is yesterday.
|
632
|
-
+ tou:
|
634
|
+
+ tou: the default, tou=0, does not split data and is more accurate. Setting tou=1 uploads data with time of use. Setting tou=2 integrates all values and allows set_pvoutput() to work with pv inverters that do not provide energy stats.
|
633
635
|
+ setting integrate_load_power to 1 will calculate load energy by integrating the load power instead of using data from Fox. This tries to overcome the limitation where the inverter does not track load power / energy correctly when there is secondary generation. When set to 0 (default), the Fox load energy is used.
|
634
636
|
|
635
637
|
You can copy and paste the output data to the pvoutput data CSV Loader, using the following settings:
|
@@ -652,7 +654,7 @@ f.set_pvoutput(d, system_id, tou, push, run_after)
|
|
652
654
|
|
653
655
|
+ d is optional and is the date, or a list of dates, to upload
|
654
656
|
+ system_id is optional and allow you to select where data is uploaded to (where you have more than 1 registered system)
|
655
|
-
+ tou:
|
657
|
+
+ tou: the default, tou=0, does not split data and is more accurate. Setting tou=1 uploads data with time of use. Setting tou=2 integrates all values and allows set_pvoutput() to work with pv inverters that do not provide energy stats.
|
656
658
|
+ push: optional. 0 = do not sent to pushover, 1 = send summary to pushover, 2 = send first day summary only
|
657
659
|
+ run_after: optional. Only generate data on or after this hour. Default 0.
|
658
660
|
|
@@ -807,6 +809,17 @@ This setting can be:
|
|
807
809
|
|
808
810
|
# Version Info
|
809
811
|
|
812
|
+
2.7.9<br>
|
813
|
+
Add 'consumption' input for charge_needed().
|
814
|
+
Avoid throwing exception in battery_info() if there is no capacity info.
|
815
|
+
|
816
|
+
2.7.8<br>
|
817
|
+
Update the battery_params charge rate table to 2025 values.
|
818
|
+
|
819
|
+
2.7.7<br>
|
820
|
+
Updates to get_pvoutput() to support solar inverters that don't provide grid energy by setting tou=2.
|
821
|
+
Default tariff changed to None.
|
822
|
+
|
810
823
|
2.7.6<br>
|
811
824
|
Updates to support F, G, R and S series inverters.
|
812
825
|
Updates to set_named_settings() to load metadata if not already done and save new value.
|
@@ -1,17 +1,3 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: foxesscloud
|
3
|
-
Version: 2.7.6
|
4
|
-
Summary: library for accessing Fox ESS cloud data using Open API
|
5
|
-
Author-email: Tony Matthews <tony@quasair.co.uk>
|
6
|
-
Project-URL: Homepage, https://github.com/TonyM1958/FoxESS-Cloud
|
7
|
-
Project-URL: Bug Tracker, https://github.com/TonyM1958/FoxESS-Cloud/issues
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
10
|
-
Classifier: Operating System :: OS Independent
|
11
|
-
Requires-Python: >=3.7
|
12
|
-
Description-Content-Type: text/markdown
|
13
|
-
License-File: LICENCE
|
14
|
-
|
15
1
|
# FoxESS-Cloud
|
16
2
|
|
17
3
|
<a href="https://www.buymeacoffee.com/tonym1958" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174" align="right"></a>
|
@@ -358,7 +344,9 @@ All the parameters are optional:
|
|
358
344
|
|
359
345
|
charge_needed() uses a number of models to better estimate the state of the battery.
|
360
346
|
|
361
|
-
**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).
|
362
350
|
|
363
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.
|
364
352
|
|
@@ -629,7 +617,7 @@ f.get_pvoutput(d, tou)
|
|
629
617
|
```
|
630
618
|
|
631
619
|
+ d is the date or a list of dates, to get data for. The default is yesterday.
|
632
|
-
+ tou:
|
620
|
+
+ tou: the default, tou=0, does not split data and is more accurate. Setting tou=1 uploads data with time of use. Setting tou=2 integrates all values and allows set_pvoutput() to work with pv inverters that do not provide energy stats.
|
633
621
|
+ setting integrate_load_power to 1 will calculate load energy by integrating the load power instead of using data from Fox. This tries to overcome the limitation where the inverter does not track load power / energy correctly when there is secondary generation. When set to 0 (default), the Fox load energy is used.
|
634
622
|
|
635
623
|
You can copy and paste the output data to the pvoutput data CSV Loader, using the following settings:
|
@@ -652,7 +640,7 @@ f.set_pvoutput(d, system_id, tou, push, run_after)
|
|
652
640
|
|
653
641
|
+ d is optional and is the date, or a list of dates, to upload
|
654
642
|
+ system_id is optional and allow you to select where data is uploaded to (where you have more than 1 registered system)
|
655
|
-
+ tou:
|
643
|
+
+ tou: the default, tou=0, does not split data and is more accurate. Setting tou=1 uploads data with time of use. Setting tou=2 integrates all values and allows set_pvoutput() to work with pv inverters that do not provide energy stats.
|
656
644
|
+ push: optional. 0 = do not sent to pushover, 1 = send summary to pushover, 2 = send first day summary only
|
657
645
|
+ run_after: optional. Only generate data on or after this hour. Default 0.
|
658
646
|
|
@@ -807,6 +795,17 @@ This setting can be:
|
|
807
795
|
|
808
796
|
# Version Info
|
809
797
|
|
798
|
+
2.7.9<br>
|
799
|
+
Add 'consumption' input for charge_needed().
|
800
|
+
Avoid throwing exception in battery_info() if there is no capacity info.
|
801
|
+
|
802
|
+
2.7.8<br>
|
803
|
+
Update the battery_params charge rate table to 2025 values.
|
804
|
+
|
805
|
+
2.7.7<br>
|
806
|
+
Updates to get_pvoutput() to support solar inverters that don't provide grid energy by setting tou=2.
|
807
|
+
Default tariff changed to None.
|
808
|
+
|
810
809
|
2.7.6<br>
|
811
810
|
Updates to support F, G, R and S series inverters.
|
812
811
|
Updates to set_named_settings() to load metadata if not already done and save new value.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
##################################################################################################
|
2
2
|
"""
|
3
3
|
Module: Fox ESS Cloud
|
4
|
-
Updated:
|
4
|
+
Updated: 28 January 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.0"
|
14
14
|
print(f"FoxESS-Cloud version {version}")
|
15
15
|
|
16
16
|
debug_setting = 1
|
@@ -591,25 +591,29 @@ battery_settings = None
|
|
591
591
|
# 1 = Residual Energy, 2 = Residual Capacity (HV), 3 = Residual Capacity per battery (Mira)
|
592
592
|
residual_handling = 1
|
593
593
|
|
594
|
-
# charge rates based on residual_handling
|
594
|
+
# charge rates based on residual_handling. Index is bms temperature
|
595
595
|
battery_params = {
|
596
|
-
# cell temp -5 0 5 10 15 20 25 30 35 40 45 50 55
|
597
596
|
# bms temp 5 10 15 20 25 30 35 40 45 50 55 60 65
|
597
|
+
# cell temp -5 0 5 10 15 20 25 30 35 40 45 50 55
|
598
598
|
1: {'table': [ 0, 2, 10, 15, 25, 50, 50, 50, 50, 50, 30, 20, 0],
|
599
599
|
'step': 5,
|
600
600
|
'offset': 5,
|
601
601
|
'charge_loss': 0.974,
|
602
602
|
'discharge_loss': 0.974},
|
603
|
-
|
604
|
-
|
603
|
+
# HV BMS v2 with firmware 1.014 or later
|
604
|
+
# bms temp 10 15 20 25 30 35 40 45 50 55 60 65 70
|
605
|
+
# cell temp 0 5 10 15 20 25 30 35 40 45 50 55 60
|
606
|
+
2: {'table': [ 0, 5, 10, 15, 25, 50, 50, 50, 50, 25, 20, 3, 0],
|
605
607
|
'step': 5,
|
606
|
-
'offset':
|
608
|
+
'offset': 11,
|
607
609
|
'charge_loss': 1.08,
|
608
610
|
'discharge_loss': 0.95},
|
609
|
-
|
610
|
-
|
611
|
+
# Mira BMS with firmware 1.014 or later
|
612
|
+
# bms temp 10 15 20 25 30 35 40 45 50 55 60 65 70
|
613
|
+
# cell temp 0 5 10 15 20 25 30 35 40 45 50 55 60
|
614
|
+
3: {'table': [ 0, 5, 10, 15, 25, 50, 50, 50, 50, 25, 20, 3, 0],
|
611
615
|
'step': 5,
|
612
|
-
'offset':
|
616
|
+
'offset': 11,
|
613
617
|
'charge_loss': 0.974,
|
614
618
|
'discharge_loss': 0.974},
|
615
619
|
}
|
@@ -2380,7 +2384,7 @@ custom_periods = {'name': 'Custom',
|
|
2380
2384
|
}
|
2381
2385
|
|
2382
2386
|
tariff_list = [octopus_flux, intelligent_octopus, octopus_cosy, octopus_go, agile_octopus, bg_driver, eon_drive, economy_7, custom_periods]
|
2383
|
-
tariff =
|
2387
|
+
tariff = None
|
2384
2388
|
|
2385
2389
|
##################################################################################################
|
2386
2390
|
# Strategy - schedule templates
|
@@ -2953,6 +2957,7 @@ charge_needed_app_key = "awcr5gro2v13oher3v1qu6hwnovp28"
|
|
2953
2957
|
|
2954
2958
|
# work out the charge times to set using the parameters:
|
2955
2959
|
# forecast: the kWh expected tomorrow. If none, forecast data is loaded from solcast etc
|
2960
|
+
# consumption: the kWh consumed. If none, consumption is loaded from history
|
2956
2961
|
# update_settings: 0 no updates, 1 update charge settings. The default is 0
|
2957
2962
|
# show_data: 1 shows battery SoC, 2 shows battery residual. Default = 0
|
2958
2963
|
# show_plot: 1 plots battery SoC, 2 plots battery residual. Default = 1
|
@@ -2960,7 +2965,7 @@ charge_needed_app_key = "awcr5gro2v13oher3v1qu6hwnovp28"
|
|
2960
2965
|
# forecast_times: list of hours when forecast can be fetched (UTC)
|
2961
2966
|
# force_charge: 1 = hold battery, 2 = charge for whole period
|
2962
2967
|
|
2963
|
-
def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=None, show_plot=None, run_after=None, reload=2,
|
2968
|
+
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
2969
|
forecast_times=None, force_charge=0, test_time=None, test_soc=None, test_charge=None, **settings):
|
2965
2970
|
global device, seasonality, solcast_api_key, debug_setting, tariff, solar_arrays, legend_location, time_shift, charge_needed_app_key
|
2966
2971
|
global timed_strategy, steps_per_hour, base_time, storage, battery, battery_params
|
@@ -3172,6 +3177,9 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
|
|
3172
3177
|
consumption = annual_consumption / 365 * seasonality[now.month - 1] / sum(seasonality) * 12
|
3173
3178
|
consumption_by_hour = daily_consumption
|
3174
3179
|
output(f"\nEstimated consumption: {consumption:.1f}kWh")
|
3180
|
+
elif consumption is not None:
|
3181
|
+
consumption_by_hour = daily_consumption
|
3182
|
+
output(f"\nConsumption: {consumption:.1f}kWh")
|
3175
3183
|
else:
|
3176
3184
|
consumption_days = charge_config['consumption_days']
|
3177
3185
|
consumption_days = 3 if consumption_days > 7 or consumption_days < 1 else consumption_days
|
@@ -3633,7 +3641,7 @@ def battery_info(log=0, plot=1, rated=None, count=None, info=1, bat=None):
|
|
3633
3641
|
bat_current = bat['current']
|
3634
3642
|
bat_power = bat['power']
|
3635
3643
|
bms_temperature = bat['temperature']
|
3636
|
-
capacity = bat
|
3644
|
+
capacity = bat.get('capacity')
|
3637
3645
|
cell_volts = get_cell_volts()
|
3638
3646
|
if cell_volts is None:
|
3639
3647
|
output_close()
|
@@ -3678,7 +3686,8 @@ def battery_info(log=0, plot=1, rated=None, count=None, info=1, bat=None):
|
|
3678
3686
|
s +=f",{v:.0f}"
|
3679
3687
|
return s
|
3680
3688
|
output(f"Current SoC: {current_soc}%")
|
3681
|
-
|
3689
|
+
if capacity is not None:
|
3690
|
+
output(f"Capacity: {capacity:.2f}kWh" + (" (calculated)" if bat['residual_handling'] in [1,3] else ""))
|
3682
3691
|
output(f"Residual: {residual:.2f}kWh" + (" (calculated)" if bat['residual_handling'] in [2,3] else ""))
|
3683
3692
|
if rated_capacity is not None and bat_soh is not None:
|
3684
3693
|
output(f"Rated Capacity: {rated_capacity / 1000:.2f}kWh")
|
@@ -3857,18 +3866,19 @@ integrate_load_power = 0
|
|
3857
3866
|
##################################################################################################
|
3858
3867
|
|
3859
3868
|
# get pvoutput data for upload to pvoutput api or via Bulk Loader
|
3860
|
-
# tou: 0 = no time of use, 1 = use time of use periods if available
|
3869
|
+
# tou: 0 = no time of use, 1 = use time of use periods if available, 2 = integrate all values
|
3861
3870
|
|
3862
3871
|
def get_pvoutput(d = None, tou = 0):
|
3863
3872
|
global tariff, pv_calibration, ct2_calibration, integrate_load_power
|
3864
3873
|
if d is None:
|
3865
3874
|
d = date_list()[0]
|
3866
|
-
tou = 0 if tariff is None else 1 if tou == 1 or tou == True else 0
|
3867
3875
|
if type(d) is list:
|
3868
3876
|
print(f"---------------- get_pvoutput ------------------")
|
3869
3877
|
print(f"Date range {d[0]} to {d[-1]} has {len(d)} days")
|
3870
3878
|
if tou == 1:
|
3871
3879
|
print(f"Time of use: {tariff['name']}")
|
3880
|
+
elif tou == 2:
|
3881
|
+
print(f"All values integrated from power")
|
3872
3882
|
if integrate_load_power == 1:
|
3873
3883
|
print(f"Consumption integrated from Load Power")
|
3874
3884
|
print(f"------------------------------------------------")
|
@@ -3882,12 +3892,15 @@ def get_pvoutput(d = None, tou = 0):
|
|
3882
3892
|
v = ['feedin', 'gridConsumption']
|
3883
3893
|
if integrate_load_power == 0:
|
3884
3894
|
v.append('loads')
|
3885
|
-
|
3886
|
-
|
3887
|
-
|
3895
|
+
if tou == 2:
|
3896
|
+
report_data = []
|
3897
|
+
else:
|
3898
|
+
report_data = get_report('day', d=d, v=v, summary=2)
|
3899
|
+
if report_data is None:
|
3900
|
+
return None
|
3888
3901
|
# get raw power data for the day
|
3889
|
-
v = ['pvPower', 'meterPower2', 'feedinPower', 'gridConsumptionPower'] if tou
|
3890
|
-
if integrate_load_power == 1:
|
3902
|
+
v = ['pvPower', 'meterPower2', 'feedinPower', 'gridConsumptionPower'] if tou > 0 else ['pvPower', 'meterPower2']
|
3903
|
+
if integrate_load_power == 1 or tou == 2:
|
3891
3904
|
v.append('loadsPower')
|
3892
3905
|
raw_data = get_raw('day', d=d + ' 00:00:00', v=v , summary=1)
|
3893
3906
|
if raw_data is None or len(raw_data) == 0 or raw_data[0].get('kwh') is None or raw_data[0].get('max') is None:
|
@@ -3937,10 +3950,12 @@ def get_pvoutput(d = None, tou = 0):
|
|
3937
3950
|
generate = f"{wh},"
|
3938
3951
|
power = f"{int(var['max'] * 1000)},{var['max_time']},"
|
3939
3952
|
elif var['variable'] == 'feedinPower':
|
3953
|
+
export_wh = wh if tou == 2 else export_wh
|
3940
3954
|
calibrate = export_wh / wh if wh > 0.0 else 1.0
|
3941
3955
|
export = f","
|
3942
3956
|
export_tou = f"{int(peak * calibrate)},{int(off_peak * calibrate)},{int((wh - peak - off_peak) * calibrate)},0"
|
3943
3957
|
elif var['variable'] == 'gridConsumptionPower':
|
3958
|
+
grid_wh = wh if tou == 2 else grid_wh
|
3944
3959
|
calibrate = grid_wh / wh if wh > 0.0 else 1.0
|
3945
3960
|
grid = f"{int(peak * calibrate)},{int(off_peak * calibrate)},{int((wh - peak - off_peak) * calibrate)},0,"
|
3946
3961
|
elif var['variable'] == 'loadsPower':
|
@@ -1,7 +1,7 @@
|
|
1
1
|
##################################################################################################
|
2
2
|
"""
|
3
3
|
Module: Fox ESS Cloud using Open API
|
4
|
-
Updated:
|
4
|
+
Updated: 27 January 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.7.
|
13
|
+
version = "2.7.9"
|
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
|
}
|
@@ -2052,7 +2056,7 @@ custom_periods = {'name': 'Custom',
|
|
2052
2056
|
}
|
2053
2057
|
|
2054
2058
|
tariff_list = [octopus_flux, intelligent_octopus, octopus_cosy, octopus_go, agile_octopus, bg_driver, eon_drive, economy_7, custom_periods]
|
2055
|
-
tariff =
|
2059
|
+
tariff = None
|
2056
2060
|
|
2057
2061
|
##################################################################################################
|
2058
2062
|
# Strategy - schedule templates
|
@@ -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
|
@@ -2847,6 +2852,9 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
|
|
2847
2852
|
consumption = annual_consumption / 365 * seasonality[now.month - 1] / sum(seasonality) * 12
|
2848
2853
|
consumption_by_hour = daily_consumption
|
2849
2854
|
output(f"\nEstimated consumption: {consumption:.1f}kWh")
|
2855
|
+
elif consumption is not None:
|
2856
|
+
consumption_by_hour = daily_consumption
|
2857
|
+
output(f"\nConsumption: {consumption:.1f}kWh")
|
2850
2858
|
else:
|
2851
2859
|
consumption_days = charge_config['consumption_days']
|
2852
2860
|
consumption_days = 3 if consumption_days > 7 or consumption_days < 1 else consumption_days
|
@@ -3305,7 +3313,7 @@ def battery_info(log=0, plot=1, rated=None, count=None, info=1, bat=None):
|
|
3305
3313
|
bat_current = bat['current']
|
3306
3314
|
bat_power = bat['power']
|
3307
3315
|
bms_temperature = bat['temperature']
|
3308
|
-
capacity = bat
|
3316
|
+
capacity = bat.get('capacity')
|
3309
3317
|
cell_volts = get_cell_volts()
|
3310
3318
|
if cell_volts is None:
|
3311
3319
|
output_close()
|
@@ -3350,7 +3358,8 @@ def battery_info(log=0, plot=1, rated=None, count=None, info=1, bat=None):
|
|
3350
3358
|
s +=f",{v:.0f}"
|
3351
3359
|
return s
|
3352
3360
|
output(f"Current SoC: {current_soc}%")
|
3353
|
-
|
3361
|
+
if capacity is not None:
|
3362
|
+
output(f"Capacity: {capacity:.2f}kWh" + (" (calculated)" if bat['residual_handling'] in [1,3] else ""))
|
3354
3363
|
output(f"Residual: {residual:.2f}kWh" + (" (calculated)" if bat['residual_handling'] in [2,3] else ""))
|
3355
3364
|
if rated_capacity is not None and bat_soh is not None:
|
3356
3365
|
output(f"Rated Capacity: {rated_capacity / 1000:.2f}kWh")
|
@@ -3529,18 +3538,19 @@ integrate_load_power = 0
|
|
3529
3538
|
##################################################################################################
|
3530
3539
|
|
3531
3540
|
# get pvoutput data for upload to pvoutput api or via Bulk Loader
|
3532
|
-
# tou: 0 = no time of use, 1 = use time of use periods if available
|
3541
|
+
# tou: 0 = no time of use, 1 = use time of use periods if available, 2 = integrate all values
|
3533
3542
|
|
3534
3543
|
def get_pvoutput(d = None, tou = 0):
|
3535
3544
|
global tariff, pv_calibration, ct2_calibration, integrate_load_power
|
3536
3545
|
if d is None:
|
3537
3546
|
d = date_list()[0]
|
3538
|
-
tou = 0 if tariff is None else 1 if tou == 1 or tou == True else 0
|
3539
3547
|
if type(d) is list:
|
3540
3548
|
print(f"---------------- get_pvoutput ------------------")
|
3541
3549
|
print(f"Date range {d[0]} to {d[-1]} has {len(d)} days")
|
3542
3550
|
if tou == 1:
|
3543
3551
|
print(f"Time of use: {tariff['name']}")
|
3552
|
+
elif tou == 2:
|
3553
|
+
print(f"All values integrated from power")
|
3544
3554
|
if integrate_load_power == 1:
|
3545
3555
|
print(f"Consumption integrated from Load Power")
|
3546
3556
|
print(f"------------------------------------------------")
|
@@ -3554,12 +3564,15 @@ def get_pvoutput(d = None, tou = 0):
|
|
3554
3564
|
v = ['feedin', 'gridConsumption']
|
3555
3565
|
if integrate_load_power == 0:
|
3556
3566
|
v.append('loads')
|
3557
|
-
|
3558
|
-
|
3559
|
-
|
3567
|
+
if tou == 2:
|
3568
|
+
report_data = []
|
3569
|
+
else:
|
3570
|
+
report_data = get_report('day', d=d, v=v, summary=2)
|
3571
|
+
if report_data is None:
|
3572
|
+
return None
|
3560
3573
|
# get raw power data for the day
|
3561
|
-
v = ['pvPower', 'meterPower2', 'feedinPower', 'gridConsumptionPower'] if tou
|
3562
|
-
if integrate_load_power == 1:
|
3574
|
+
v = ['pvPower', 'meterPower2', 'feedinPower', 'gridConsumptionPower'] if tou > 0 else ['pvPower', 'meterPower2']
|
3575
|
+
if integrate_load_power == 1 or tou == 2:
|
3563
3576
|
v.append('loadsPower')
|
3564
3577
|
raw_data = get_raw('day', d=d + ' 00:00:00', v=v , summary=1)
|
3565
3578
|
if raw_data is None or len(raw_data) == 0 or raw_data[0].get('kwh') is None or raw_data[0].get('max') is None:
|
@@ -3609,10 +3622,12 @@ def get_pvoutput(d = None, tou = 0):
|
|
3609
3622
|
generate = f"{wh},"
|
3610
3623
|
power = f"{int(var['max'] * 1000)},{var['max_time']},"
|
3611
3624
|
elif var['variable'] == 'feedinPower':
|
3625
|
+
export_wh = wh if tou == 2 else export_wh
|
3612
3626
|
calibrate = export_wh / wh if wh > 0.0 else 1.0
|
3613
3627
|
export = f","
|
3614
3628
|
export_tou = f"{int(peak * calibrate)},{int(off_peak * calibrate)},{int((wh - peak - off_peak) * calibrate)},0"
|
3615
3629
|
elif var['variable'] == 'gridConsumptionPower':
|
3630
|
+
grid_wh = wh if tou == 2 else grid_wh
|
3616
3631
|
calibrate = grid_wh / wh if wh > 0.0 else 1.0
|
3617
3632
|
grid = f"{int(peak * calibrate)},{int(off_peak * calibrate)},{int((wh - peak - off_peak) * calibrate)},0,"
|
3618
3633
|
elif var['variable'] == 'loadsPower':
|
@@ -1,3 +1,17 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: foxesscloud
|
3
|
+
Version: 2.7.9
|
4
|
+
Summary: library for accessing Fox ESS cloud data using Open API
|
5
|
+
Author-email: Tony Matthews <tony@quasair.co.uk>
|
6
|
+
Project-URL: Homepage, https://github.com/TonyM1958/FoxESS-Cloud
|
7
|
+
Project-URL: Bug Tracker, https://github.com/TonyM1958/FoxESS-Cloud/issues
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Requires-Python: >=3.7
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
License-File: LICENCE
|
14
|
+
|
1
15
|
# FoxESS-Cloud
|
2
16
|
|
3
17
|
<a href="https://www.buymeacoffee.com/tonym1958" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174" align="right"></a>
|
@@ -344,7 +358,9 @@ All the parameters are optional:
|
|
344
358
|
|
345
359
|
charge_needed() uses a number of models to better estimate the state of the battery.
|
346
360
|
|
347
|
-
**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).
|
348
364
|
|
349
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.
|
350
366
|
|
@@ -615,7 +631,7 @@ f.get_pvoutput(d, tou)
|
|
615
631
|
```
|
616
632
|
|
617
633
|
+ d is the date or a list of dates, to get data for. The default is yesterday.
|
618
|
-
+ tou:
|
634
|
+
+ tou: the default, tou=0, does not split data and is more accurate. Setting tou=1 uploads data with time of use. Setting tou=2 integrates all values and allows set_pvoutput() to work with pv inverters that do not provide energy stats.
|
619
635
|
+ setting integrate_load_power to 1 will calculate load energy by integrating the load power instead of using data from Fox. This tries to overcome the limitation where the inverter does not track load power / energy correctly when there is secondary generation. When set to 0 (default), the Fox load energy is used.
|
620
636
|
|
621
637
|
You can copy and paste the output data to the pvoutput data CSV Loader, using the following settings:
|
@@ -638,7 +654,7 @@ f.set_pvoutput(d, system_id, tou, push, run_after)
|
|
638
654
|
|
639
655
|
+ d is optional and is the date, or a list of dates, to upload
|
640
656
|
+ system_id is optional and allow you to select where data is uploaded to (where you have more than 1 registered system)
|
641
|
-
+ tou:
|
657
|
+
+ tou: the default, tou=0, does not split data and is more accurate. Setting tou=1 uploads data with time of use. Setting tou=2 integrates all values and allows set_pvoutput() to work with pv inverters that do not provide energy stats.
|
642
658
|
+ push: optional. 0 = do not sent to pushover, 1 = send summary to pushover, 2 = send first day summary only
|
643
659
|
+ run_after: optional. Only generate data on or after this hour. Default 0.
|
644
660
|
|
@@ -793,6 +809,17 @@ This setting can be:
|
|
793
809
|
|
794
810
|
# Version Info
|
795
811
|
|
812
|
+
2.7.9<br>
|
813
|
+
Add 'consumption' input for charge_needed().
|
814
|
+
Avoid throwing exception in battery_info() if there is no capacity info.
|
815
|
+
|
816
|
+
2.7.8<br>
|
817
|
+
Update the battery_params charge rate table to 2025 values.
|
818
|
+
|
819
|
+
2.7.7<br>
|
820
|
+
Updates to get_pvoutput() to support solar inverters that don't provide grid energy by setting tou=2.
|
821
|
+
Default tariff changed to None.
|
822
|
+
|
796
823
|
2.7.6<br>
|
797
824
|
Updates to support F, G, R and S series inverters.
|
798
825
|
Updates to set_named_settings() to load metadata if not already done and save new value.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|