foxesscloud 2.5.5__tar.gz → 2.5.7__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foxesscloud
3
- Version: 2.5.5
3
+ Version: 2.5.7
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
@@ -783,12 +783,20 @@ This setting can be:
783
783
 
784
784
  # Version Info
785
785
 
786
+ 2.5.7<br>
787
+ Fix problem with schedules being set for plunge periods that are more than 24 hours in the future.
788
+ Add date to plunge period display.
789
+
790
+ 2.5.6<br>
791
+ Change plunge slots to 8 and plungs pricing to [3,10].
792
+ Change min_hours setting in charge_needed to 0.5 (30 minutes) and round up charge times to increments of this.
793
+ Show data and plot starting at t=0.
794
+
786
795
  2.5.5<br>
787
796
  Improve validation of plunge price periods so they don't repeat across days.
788
797
  Correct start and end soc times and values when charging using best Agile time periods.
789
798
  Extend charge times when charge needed exceeds battery capacity.
790
799
 
791
-
792
800
  2.5.4<br>
793
801
  Remove preset 'weighting' that were not used.
794
802
  Update weighting to apply the requested charge duration correctly.
@@ -769,12 +769,20 @@ This setting can be:
769
769
 
770
770
  # Version Info
771
771
 
772
+ 2.5.7<br>
773
+ Fix problem with schedules being set for plunge periods that are more than 24 hours in the future.
774
+ Add date to plunge period display.
775
+
776
+ 2.5.6<br>
777
+ Change plunge slots to 8 and plungs pricing to [3,10].
778
+ Change min_hours setting in charge_needed to 0.5 (30 minutes) and round up charge times to increments of this.
779
+ Show data and plot starting at t=0.
780
+
772
781
  2.5.5<br>
773
782
  Improve validation of plunge price periods so they don't repeat across days.
774
783
  Correct start and end soc times and values when charging using best Agile time periods.
775
784
  Extend charge times when charge needed exceeds battery capacity.
776
785
 
777
-
778
786
  2.5.4<br>
779
787
  Remove preset 'weighting' that were not used.
780
788
  Update weighting to apply the requested charge duration correctly.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "foxesscloud"
7
- version = "2.5.5"
7
+ version = "2.5.7"
8
8
  authors = [
9
9
  {name="Tony Matthews", email="tony@quasair.co.uk"},
10
10
  ]
@@ -1,7 +1,7 @@
1
1
  ##################################################################################################
2
2
  """
3
3
  Module: Fox ESS Cloud
4
- Updated: 26 September 2024
4
+ Updated: 28 September 2024
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.6.7"
13
+ version = "1.6.9"
14
14
  print(f"FoxESS-Cloud version {version}")
15
15
 
16
16
  debug_setting = 1
@@ -742,7 +742,7 @@ def charge_periods(st1=None, en1=None, st2=None, en2=None, min_soc=10, end_soc=1
742
742
  charge.append({'start': st1, 'end': st3, 'mode': 'SelfUse', 'min_soc': start_soc})
743
743
  st1 = st3
744
744
  charge.append({'start': st1, 'end': en1, 'mode': 'SelfUse', 'min_soc': min_soc})
745
- strategy = get_strategy(remove=span)[:(8 - len(charge))]
745
+ strategy = get_strategy(remove=span, limit=24)[:(8 - len(charge))]
746
746
  for c in charge:
747
747
  strategy.append(c)
748
748
  periods = []
@@ -2208,7 +2208,7 @@ test_strategy = [
2208
2208
  {'start': 21, 'end': 22, 'mode': 'ForceCharge'}]
2209
2209
 
2210
2210
  # return a strategy that has been sorted and filtered for charge times:
2211
- def get_strategy(use=None, strategy=None, quiet=1, remove=None, reserve=0):
2211
+ def get_strategy(use=None, strategy=None, quiet=1, remove=None, reserve=0, limit=None):
2212
2212
  global tariff, base_time
2213
2213
  if use is None:
2214
2214
  use = tariff
@@ -2221,8 +2221,9 @@ def get_strategy(use=None, strategy=None, quiet=1, remove=None, reserve=0):
2221
2221
  if use.get('agile') is not None and use['agile'].get('strategy') is not None:
2222
2222
  base_time_adjust = hours_difference(base_time, use['agile'].get('base_time') )
2223
2223
  for s in use['agile']['strategy']:
2224
- s['valid_for'] = [int((s['hour'] - base_time_adjust) * steps_per_hour + i) for i in range(0, steps_per_hour // 2)] if s.get('hour') is not None else None
2225
- strategy.append(s)
2224
+ if limit is None or s.get('hour') is None or s['hour'] - base_time_adjust < 24:
2225
+ s['valid_for'] = [int((s['hour'] - base_time_adjust) * steps_per_hour + i) for i in range(0, steps_per_hour // 2)] if s.get('hour') is not None else None
2226
+ strategy.append(s)
2226
2227
  if strategy is None or len(strategy) == 0:
2227
2228
  return []
2228
2229
  updated = []
@@ -2270,8 +2271,8 @@ tariff_config = {
2270
2271
  'region': "H", # region code to use for Octopus API
2271
2272
  'update_time': 16.5, # time in hours when tomrow's data can be fetched
2272
2273
  'weighting': None, # weights for weighted average
2273
- 'plunge_price': [1, 10], # plunge price in p/kWh inc VAT over 24 hours from 7am, 7pm
2274
- 'plunge_slots': 6, # number of 30 minute slots to use
2274
+ 'plunge_price': [3, 10], # plunge price in p/kWh inc VAT over 24 hours from 7am, 7pm
2275
+ 'plunge_slots': 8, # number of 30 minute slots to use
2275
2276
  'data_wrap': 6, # prices to show per line
2276
2277
  'show_data': 1, # show pricing data
2277
2278
  'show_plot': 1 # plot pricing data
@@ -2344,7 +2345,8 @@ def get_agile_times(tariff=agile_octopus, d=None):
2344
2345
  output(f"\nPlunge slots:", 1)
2345
2346
  for t in plunge:
2346
2347
  strategy.append(prices[t])
2347
- output(f" {format_period(prices[t])} at {prices[t]['price']:.1f}p", 1)
2348
+ date = (now + timedelta(hours = prices[t]['hour'])).strftime("%Y-%m-%d")
2349
+ output(f" {format_period(prices[t])} at {prices[t]['price']:.1f}p on {date}", 1)
2348
2350
  tariff['agile']['strategy'] = strategy
2349
2351
  for key in ['off_peak1', 'off_peak2', 'off_peak3', 'off_peak4']:
2350
2352
  if tariff.get(key) is None:
@@ -2681,7 +2683,7 @@ charge_config = {
2681
2683
  'consumption_days': 3, # number of days to use for average consumption (1-7)
2682
2684
  'consumption_span': 'week', # 'week' = last n days or 'weekday' = last n weekdays
2683
2685
  'use_today': 21.0, # hour when todays consumption and generation can be used
2684
- 'min_hours': 0.25, # minimum charge time in decimal hours
2686
+ 'min_hours': 0.5, # minimum charge time in decimal hours
2685
2687
  'min_kwh': 0.5, # minimum to add in kwh
2686
2688
  'forecast_selection': 1, # 0 = use available forecast / generation, 1 only update settings with forecast
2687
2689
  'annual_consumption': None, # optional annual consumption in kWh
@@ -2778,7 +2780,7 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
2778
2780
  for t in times:
2779
2781
  if hour_in(hour_now, t) and update_settings > 0:
2780
2782
  update_settings = 0
2781
- output(f"\nSettings will not be updated during a charge period")
2783
+ output(f"\nSettings will not be updated during a charge period {format_period(t)}")
2782
2784
  time_to_start = round_time(t['start'] - base_hour) * steps_per_hour
2783
2785
  time_to_start += hour_adjustment * steps_per_hour if time_to_start > time_change else 0
2784
2786
  charge_time = round_time(t['end'] - t['start'])
@@ -3069,7 +3071,7 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
3069
3071
  kwh_needed = test_charge
3070
3072
  charge_message = "** test charge **"
3071
3073
  # work out charge needed
3072
- if kwh_min > (reserve + kwh_contingency) and kwh_needed < charge_config['min_kwh'] and test_charge is None:
3074
+ if kwh_min > reserve and kwh_needed < charge_config['min_kwh'] and test_charge is None:
3073
3075
  output(f"\nNo charging needed:")
3074
3076
  output(f" SoC now: {current_soc:.0f}% at {hours_time(hour_now)} on {today}")
3075
3077
  charge_message = "no charge needed"
@@ -3089,17 +3091,18 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
3089
3091
  output(f" SoC now: {current_soc:.0f}% at {hours_time(hour_now)} on {today}")
3090
3092
  # work out time to add kwh_needed to battery
3091
3093
  charge_rate = charge_power * charge_loss
3092
- hours = round_time(kwh_needed / charge_rate)
3094
+ hours = kwh_needed / charge_rate
3093
3095
  # check if charge time exceeded or charge needed exceeds capacity
3094
- hours_to_full = round_time((capacity - start_residual) / (charge_rate) + 10)
3095
- if hours < charge_config['min_hours']:
3096
- hours = charge_config['min_hours']
3097
- elif hours > charge_time:
3096
+ hours_to_full = (capacity - start_residual) / charge_rate
3097
+ if hours > charge_time:
3098
3098
  hours = charge_time
3099
3099
  elif hours > hours_to_full:
3100
3100
  kwh_shortfall = (hours - hours_to_full) * charge_rate # amount of energy that won't be added
3101
- required = hours_to_full + charge_time * kwh_shortfall / (end_residual - start_residual) # time to recover energy not added
3102
- hours = required if required < charge_time else charge_time
3101
+ required = hours_to_full + charge_time * kwh_shortfall / abs(start_residual - end_residual) # time to recover energy not added
3102
+ hours = required if required > hours and required < charge_time else charge_time
3103
+ # round charge time
3104
+ min_hours = charge_config['min_hours']
3105
+ hours = int(hours / min_hours + 0.99) * min_hours
3103
3106
  # rework charge and discharge
3104
3107
  charge_period = get_best_charge_period(start_at, hours)
3105
3108
  charge_offset = round_time(charge_period['start'] - start_at) if charge_period is not None else 0
@@ -3109,7 +3112,7 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
3109
3112
  start_residual = interpolate(start_timed, bat_timed)
3110
3113
  end_soc = min([int((start_residual + kwh_needed) / capacity * 100 + 0.5), 100])
3111
3114
  output(f" Start SoC: {start_residual / capacity * 100:.0f}% at {hours_time(adjusted_hour(start_timed, time_line))} ({start_residual:.2f}kWh)")
3112
- output(f" Charge to: {end_soc:.0f} {hours_time(adjusted_hour(start_timed, time_line))}-{hours_time(adjusted_hour(end_timed, time_line))}" + (f" at {price:5.2f}p/kWh" if price is not None else ""))
3115
+ output(f" Charge to: {end_soc:.0f}% {hours_time(adjusted_hour(start_timed, time_line))}-{hours_time(adjusted_hour(end_timed, time_line))}" + (f" at {price:5.2f}p/kWh" if price is not None else ""))
3113
3116
  for i in range(int(time_to_start), int(end_timed) + 1):
3114
3117
  j = i + 1
3115
3118
  # work out time (fraction of hour) when charging in hour from i to j
@@ -3141,11 +3144,11 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
3141
3144
  if show_data > 0:
3142
3145
  data_wrap = charge_config['data_wrap'] if charge_config.get('data_wrap') is not None else 6
3143
3146
  s = f"\nBattery Energy kWh:" if show_data == 2 else f"\nBattery SoC:"
3144
- h = base_hour + 1
3145
- t = steps_per_hour
3147
+ h = base_hour
3148
+ t = 0
3146
3149
  while t < len(time_line) and bat_timed[t] is not None:
3147
3150
  col = h % data_wrap
3148
- s += (f"\n {hours_time(time_line[t])}" + " " * col * 6) if t == steps_per_hour or col == 0 else ""
3151
+ s += (f"\n {hours_time(time_line[t])}" + " " * col * 6) if t == 0 or col == 0 else ""
3149
3152
  s += f" {bat_timed[t]:5.2f}" if show_data == 2 else f" {bat_timed[t] / capacity * 100:3.0f}%"
3150
3153
  h += 1
3151
3154
  t += steps_per_hour
@@ -3153,8 +3156,8 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
3153
3156
  if show_plot > 0:
3154
3157
  print()
3155
3158
  plt.figure(figsize=(figure_width, figure_width/2))
3156
- x_timed = [i for i in range(steps_per_hour, run_time)]
3157
- x_ticks = [i for i in range(steps_per_hour, run_time, steps_per_hour)]
3159
+ x_timed = [i for i in range(0, run_time)]
3160
+ x_ticks = [i for i in range(0, run_time, steps_per_hour)]
3158
3161
  plt.xticks(ticks=x_ticks, labels=[hours_time(time_line[x]) for x in x_ticks], rotation=90, fontsize=8, ha='center')
3159
3162
  if show_plot == 1:
3160
3163
  title = f"Predicted Battery SoC % at {base_time}({charge_message})"
@@ -3278,11 +3281,11 @@ def charge_compare(save=None, v=None, show_data=1, show_plot=3):
3278
3281
  if show_data > 0 and plots.get('SoC') is not None:
3279
3282
  data_wrap = charge_config['data_wrap'] if charge_config.get('data_wrap') is not None else 6
3280
3283
  s = f"\nBattery Energy kWh:" if show_data == 2 else f"\nBattery SoC:"
3281
- h = base_hour + 1
3282
- t = steps_per_hour
3284
+ h = base_hour
3285
+ t = 0
3283
3286
  while t < len(time_line) and bat_timed[t] is not None:
3284
3287
  col = h % data_wrap
3285
- s += (f"\n {hours_time(time_line[t])}" + " " * col * 6) if t == steps_per_hour or col == 0 else ""
3288
+ s += (f"\n {hours_time(time_line[t])}" + " " * col * 6) if t == 0 or col == 0 else ""
3286
3289
  s += f" {plots['SoC'][t]:5.2f}" if show_data == 2 else f" {plots['SoC'][t] / capacity * 100:3.0f}%"
3287
3290
  h += 1
3288
3291
  t += steps_per_hour
@@ -3290,8 +3293,8 @@ def charge_compare(save=None, v=None, show_data=1, show_plot=3):
3290
3293
  if show_plot > 0:
3291
3294
  print()
3292
3295
  plt.figure(figsize=(figure_width, figure_width/2))
3293
- x_timed = [i for i in range(steps_per_hour, run_time)]
3294
- x_ticks = [i for i in range(steps_per_hour, run_time, steps_per_hour)]
3296
+ x_timed = [i for i in range(0, run_time)]
3297
+ x_ticks = [i for i in range(0, run_time, steps_per_hour)]
3295
3298
  plt.xticks(ticks=x_ticks, labels=[hours_time(time_line[x]) for x in x_ticks], rotation=90, fontsize=8, ha='center')
3296
3299
  if show_plot == 1:
3297
3300
  title = f"Predicted Battery SoC % at {base_time}({charge_message})"
@@ -1,7 +1,7 @@
1
1
  ##################################################################################################
2
2
  """
3
3
  Module: Fox ESS Cloud using Open API
4
- Updated: 26 September 2024
4
+ Updated: 28 September 2024
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.5.5"
13
+ version = "2.5.7"
14
14
  print(f"FoxESS-Cloud Open API version {version}")
15
15
 
16
16
  debug_setting = 1
@@ -690,7 +690,7 @@ def charge_periods(st1=None, en1=None, st2=None, en2=None, min_soc=10, end_soc=1
690
690
  charge.append({'start': st1, 'end': st3, 'mode': 'SelfUse', 'min_soc': start_soc})
691
691
  st1 = st3
692
692
  charge.append({'start': st1, 'end': en1, 'mode': 'SelfUse', 'min_soc': min_soc})
693
- strategy = get_strategy(remove=span)[:(8 - len(charge))]
693
+ strategy = get_strategy(remove=span, limit=24)[:(8 - len(charge))]
694
694
  for c in charge:
695
695
  strategy.append(c)
696
696
  periods = []
@@ -2072,7 +2072,7 @@ test_strategy = [
2072
2072
  {'start': 21, 'end': 22, 'mode': 'ForceCharge'}]
2073
2073
 
2074
2074
  # return a strategy that has been sorted and filtered for charge times:
2075
- def get_strategy(use=None, strategy=None, quiet=1, remove=None, reserve=0):
2075
+ def get_strategy(use=None, strategy=None, quiet=1, remove=None, reserve=0, limit=None):
2076
2076
  global tariff, base_time
2077
2077
  if use is None:
2078
2078
  use = tariff
@@ -2085,8 +2085,9 @@ def get_strategy(use=None, strategy=None, quiet=1, remove=None, reserve=0):
2085
2085
  if use.get('agile') is not None and use['agile'].get('strategy') is not None:
2086
2086
  base_time_adjust = hours_difference(base_time, use['agile'].get('base_time') )
2087
2087
  for s in use['agile']['strategy']:
2088
- s['valid_for'] = [int((s['hour'] - base_time_adjust) * steps_per_hour + i) for i in range(0, steps_per_hour // 2)] if s.get('hour') is not None else None
2089
- strategy.append(s)
2088
+ if limit is None or s.get('hour') is None or s['hour'] - base_time_adjust < 24:
2089
+ s['valid_for'] = [int((s['hour'] - base_time_adjust) * steps_per_hour + i) for i in range(0, steps_per_hour // 2)] if s.get('hour') is not None else None
2090
+ strategy.append(s)
2090
2091
  if strategy is None or len(strategy) == 0:
2091
2092
  return []
2092
2093
  updated = []
@@ -2134,8 +2135,8 @@ tariff_config = {
2134
2135
  'region': "H", # region code to use for Octopus API
2135
2136
  'update_time': 16.5, # time in hours when tomrow's data can be fetched
2136
2137
  'weighting': None, # weights for weighted average
2137
- 'plunge_price': [1, 10], # plunge price in p/kWh inc VAT over 24 hours from 7am, 7pm
2138
- 'plunge_slots': 6, # number of 30 minute slots to use
2138
+ 'plunge_price': [3, 10], # plunge price in p/kWh inc VAT over 24 hours from 7am, 7pm
2139
+ 'plunge_slots': 8, # number of 30 minute slots to use
2139
2140
  'data_wrap': 6, # prices to show per line
2140
2141
  'show_data': 1, # show pricing data
2141
2142
  'show_plot': 1 # plot pricing data
@@ -2208,7 +2209,8 @@ def get_agile_times(tariff=agile_octopus, d=None):
2208
2209
  output(f"\nPlunge slots:", 1)
2209
2210
  for t in plunge:
2210
2211
  strategy.append(prices[t])
2211
- output(f" {format_period(prices[t])} at {prices[t]['price']:.1f}p", 1)
2212
+ date = (now + timedelta(hours = prices[t]['hour'])).strftime("%Y-%m-%d")
2213
+ output(f" {format_period(prices[t])} at {prices[t]['price']:.1f}p on {date}", 1)
2212
2214
  tariff['agile']['strategy'] = strategy
2213
2215
  for key in ['off_peak1', 'off_peak2', 'off_peak3', 'off_peak4']:
2214
2216
  if tariff.get(key) is None:
@@ -2545,7 +2547,7 @@ charge_config = {
2545
2547
  'consumption_days': 3, # number of days to use for average consumption (1-7)
2546
2548
  'consumption_span': 'week', # 'week' = last n days or 'weekday' = last n weekdays
2547
2549
  'use_today': 21.0, # hour when todays consumption and generation can be used
2548
- 'min_hours': 0.25, # minimum charge time in decimal hours
2550
+ 'min_hours': 0.5, # minimum charge time in decimal hours
2549
2551
  'min_kwh': 0.5, # minimum to add in kwh
2550
2552
  'forecast_selection': 1, # 0 = use available forecast / generation, 1 only update settings with forecast
2551
2553
  'annual_consumption': None, # optional annual consumption in kWh
@@ -2642,7 +2644,7 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
2642
2644
  for t in times:
2643
2645
  if hour_in(hour_now, t) and update_settings > 0:
2644
2646
  update_settings = 0
2645
- output(f"\nSettings will not be updated during a charge period")
2647
+ output(f"\nSettings will not be updated during a charge period {format_period(t)}")
2646
2648
  time_to_start = round_time(t['start'] - base_hour) * steps_per_hour
2647
2649
  time_to_start += hour_adjustment * steps_per_hour if time_to_start > time_change else 0
2648
2650
  charge_time = round_time(t['end'] - t['start'])
@@ -2933,7 +2935,7 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
2933
2935
  kwh_needed = test_charge
2934
2936
  charge_message = "** test charge **"
2935
2937
  # work out charge needed
2936
- if kwh_min > (reserve + kwh_contingency) and kwh_needed < charge_config['min_kwh'] and test_charge is None:
2938
+ if kwh_min > reserve and kwh_needed < charge_config['min_kwh'] and test_charge is None:
2937
2939
  output(f"\nNo charging needed:")
2938
2940
  output(f" SoC now: {current_soc:.0f}% at {hours_time(hour_now)} on {today}")
2939
2941
  charge_message = "no charge needed"
@@ -2953,17 +2955,18 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
2953
2955
  output(f" SoC now: {current_soc:.0f}% at {hours_time(hour_now)} on {today}")
2954
2956
  # work out time to add kwh_needed to battery
2955
2957
  charge_rate = charge_power * charge_loss
2956
- hours = round_time(kwh_needed / charge_rate)
2958
+ hours = kwh_needed / charge_rate
2957
2959
  # check if charge time exceeded or charge needed exceeds capacity
2958
- hours_to_full = round_time((capacity - start_residual) / (charge_rate) + 10)
2959
- if hours < charge_config['min_hours']:
2960
- hours = charge_config['min_hours']
2961
- elif hours > charge_time:
2960
+ hours_to_full = (capacity - start_residual) / charge_rate
2961
+ if hours > charge_time:
2962
2962
  hours = charge_time
2963
2963
  elif hours > hours_to_full:
2964
2964
  kwh_shortfall = (hours - hours_to_full) * charge_rate # amount of energy that won't be added
2965
- required = hours_to_full + charge_time * kwh_shortfall / (end_residual - start_residual) # time to recover energy not added
2966
- hours = required if required < charge_time else charge_time
2965
+ required = hours_to_full + charge_time * kwh_shortfall / abs(start_residual - end_residual) # hold time to recover energy not added
2966
+ hours = required if required > hours and required < charge_time else charge_time
2967
+ # round charge time
2968
+ min_hours = charge_config['min_hours']
2969
+ hours = int(hours / min_hours + 0.99) * min_hours
2967
2970
  # rework charge and discharge
2968
2971
  charge_period = get_best_charge_period(start_at, hours)
2969
2972
  charge_offset = round_time(charge_period['start'] - start_at) if charge_period is not None else 0
@@ -3005,11 +3008,11 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
3005
3008
  if show_data > 0:
3006
3009
  data_wrap = charge_config['data_wrap'] if charge_config.get('data_wrap') is not None else 6
3007
3010
  s = f"\nBattery Energy kWh:" if show_data == 2 else f"\nBattery SoC:"
3008
- h = base_hour + 1
3009
- t = steps_per_hour
3011
+ h = base_hour
3012
+ t = 0
3010
3013
  while t < len(time_line) and bat_timed[t] is not None:
3011
3014
  col = h % data_wrap
3012
- s += (f"\n {hours_time(time_line[t])}" + " " * col * 6) if t == steps_per_hour or col == 0 else ""
3015
+ s += (f"\n {hours_time(time_line[t])}" + " " * col * 6) if t == 0 or col == 0 else ""
3013
3016
  s += f" {bat_timed[t]:5.2f}" if show_data == 2 else f" {bat_timed[t] / capacity * 100:3.0f}%"
3014
3017
  h += 1
3015
3018
  t += steps_per_hour
@@ -3017,8 +3020,8 @@ def charge_needed(forecast=None, update_settings=0, timed_mode=None, show_data=N
3017
3020
  if show_plot > 0:
3018
3021
  print()
3019
3022
  plt.figure(figsize=(figure_width, figure_width/2))
3020
- x_timed = [i for i in range(steps_per_hour, run_time)]
3021
- x_ticks = [i for i in range(steps_per_hour, run_time, steps_per_hour)]
3023
+ x_timed = [i for i in range(0, run_time)]
3024
+ x_ticks = [i for i in range(0, run_time, steps_per_hour)]
3022
3025
  plt.xticks(ticks=x_ticks, labels=[hours_time(time_line[x]) for x in x_ticks], rotation=90, fontsize=8, ha='center')
3023
3026
  if show_plot == 1:
3024
3027
  title = f"Predicted Battery SoC % at {base_time}({charge_message})"
@@ -3141,11 +3144,11 @@ def charge_compare(save=None, v=None, show_data=1, show_plot=3):
3141
3144
  if show_data > 0 and plots.get('SoC') is not None:
3142
3145
  data_wrap = charge_config['data_wrap'] if charge_config.get('data_wrap') is not None else 6
3143
3146
  s = f"\nBattery Energy kWh:" if show_data == 2 else f"\nBattery SoC:"
3144
- h = base_hour + 1
3145
- t = steps_per_hour
3147
+ h = base_hour
3148
+ t = 0
3146
3149
  while t < len(time_line) and bat_timed[t] is not None:
3147
3150
  col = h % data_wrap
3148
- s += (f"\n {hours_time(time_line[t])}" + " " * col * 6) if t == steps_per_hour or col == 0 else ""
3151
+ s += (f"\n {hours_time(time_line[t])}" + " " * col * 6) if t == 0 or col == 0 else ""
3149
3152
  s += f" {plots['SoC'][t]:5.2f}" if show_data == 2 else f" {plots['SoC'][t] / capacity * 100:3.0f}%"
3150
3153
  h += 1
3151
3154
  t += steps_per_hour
@@ -3153,8 +3156,8 @@ def charge_compare(save=None, v=None, show_data=1, show_plot=3):
3153
3156
  if show_plot > 0:
3154
3157
  print()
3155
3158
  plt.figure(figsize=(figure_width, figure_width/2))
3156
- x_timed = [i for i in range(steps_per_hour, run_time)]
3157
- x_ticks = [i for i in range(steps_per_hour, run_time, steps_per_hour)]
3159
+ x_timed = [i for i in range(0, run_time)]
3160
+ x_ticks = [i for i in range(0, run_time, steps_per_hour)]
3158
3161
  plt.xticks(ticks=x_ticks, labels=[hours_time(time_line[x]) for x in x_ticks], rotation=90, fontsize=8, ha='center')
3159
3162
  if show_plot == 1:
3160
3163
  title = f"Predicted Battery SoC % at {base_time}({charge_message})"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foxesscloud
3
- Version: 2.5.5
3
+ Version: 2.5.7
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
@@ -783,12 +783,20 @@ This setting can be:
783
783
 
784
784
  # Version Info
785
785
 
786
+ 2.5.7<br>
787
+ Fix problem with schedules being set for plunge periods that are more than 24 hours in the future.
788
+ Add date to plunge period display.
789
+
790
+ 2.5.6<br>
791
+ Change plunge slots to 8 and plungs pricing to [3,10].
792
+ Change min_hours setting in charge_needed to 0.5 (30 minutes) and round up charge times to increments of this.
793
+ Show data and plot starting at t=0.
794
+
786
795
  2.5.5<br>
787
796
  Improve validation of plunge price periods so they don't repeat across days.
788
797
  Correct start and end soc times and values when charging using best Agile time periods.
789
798
  Extend charge times when charge needed exceeds battery capacity.
790
799
 
791
-
792
800
  2.5.4<br>
793
801
  Remove preset 'weighting' that were not used.
794
802
  Update weighting to apply the requested charge duration correctly.
File without changes
File without changes