foxesscloud 2.8.3__py3-none-any.whl → 2.8.5__py3-none-any.whl

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,7 +1,7 @@
1
1
  ##################################################################################################
2
2
  """
3
3
  Module: Fox ESS Cloud
4
- Updated: 16 April 2025
4
+ Updated: 21 May 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.9.5"
13
+ version = "1.9.6"
14
14
  print(f"FoxESS-Cloud version {version}")
15
15
 
16
16
  debug_setting = 1
@@ -971,6 +971,7 @@ merge_settings = { # keys to add
971
971
  'h115__': 'operation_mode__work_mode',
972
972
  'h116__': 'operation_mode__work_mode',
973
973
  'h117__': 'operation_mode__work_mode',
974
+ 'h118__': 'operation_mode__work_mode',
974
975
  # 'k106__': 'operation_mode__work_mode',
975
976
  # 'k110__': 'operation_mode__work_mode',
976
977
  },
@@ -979,6 +980,7 @@ merge_settings = { # keys to add
979
980
  'h115__': 'basic2__05',
980
981
  'h116__': 'basic2__05',
981
982
  'h117__': 'basic2__05',
983
+ 'h118__': 'basic2__05',
982
984
  # 'k106__': 'basic2__05',
983
985
  # 'k1110__': 'basic2__05',
984
986
  },
@@ -987,6 +989,7 @@ merge_settings = { # keys to add
987
989
  'h115__': ['h115__14', 'h115__15', 'h115__16'],
988
990
  'h116__': ['h116__15', 'h116__16', 'h116__17'],
989
991
  'h117__': ['h117__15', 'h117__16', 'h117__17'],
992
+ 'h118__': ['h118__15', 'h118__16', 'h118__17'],
990
993
  # 'k106__': ['k106__xx', 'k106__xx', 'k106__xx'],
991
994
  # 'k110__': ['k110__xx', 'k110__xx', 'k110__xx'],
992
995
  },
@@ -997,6 +1000,7 @@ merge_settings = { # keys to add
997
1000
  'h115__': 'h115__17',
998
1001
  'h116__': 'h116__18',
999
1002
  'h117__': 'h117__18',
1003
+ 'h118__': 'h118__18',
1000
1004
  # 'k106__': 'k106__xx',
1001
1005
  # 'k110__': 'k110__xx',
1002
1006
  },
@@ -3894,7 +3898,7 @@ def get_pvoutput(d = None, tou = 0):
3894
3898
  if type(d) is list:
3895
3899
  print(f"---------------- get_pvoutput ------------------")
3896
3900
  print(f"Date range {d[0]} to {d[-1]} has {len(d)} days")
3897
- if tou == 1:
3901
+ if tou == 1 and tariff is not None:
3898
3902
  print(f"Time of use: {tariff['name']}")
3899
3903
  elif tou == 2:
3900
3904
  print(f"All values integrated from power")
foxesscloud/openapi.py CHANGED
@@ -1,7 +1,7 @@
1
1
  ##################################################################################################
2
2
  """
3
3
  Module: Fox ESS Cloud using Open API
4
- Updated: 16 April 2025
4
+ Updated: 28 May 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.8.3"
13
+ version = "2.8.5"
14
14
  print(f"FoxESS-Cloud Open API version {version}")
15
15
 
16
16
  debug_setting = 1
@@ -549,8 +549,8 @@ def get_generation(update=1):
549
549
  battery = None
550
550
  batteries = None
551
551
  battery_settings = None
552
- battery_vars = ['SoC', 'invBatVolt', 'invBatCurrent', 'invBatPower', 'batTemperature', 'ResidualEnergy' ]
553
- battery_data = ['soc', 'volt', 'current', 'power', 'temperature', 'residual']
552
+ battery_vars = ['SoC', 'invBatVolt', 'invBatCurrent', 'invBatPower', 'batTemperature', 'ResidualEnergy','SOH' ]
553
+ battery_data = ['soc', 'volt', 'current', 'power', 'temperature', 'residual', 'soh']
554
554
 
555
555
  # 1 = Residual Energy, 2 = Residual Capacity (HV), 3 = Residual Capacity per battery (Mira)
556
556
  residual_handling = 1
@@ -837,6 +837,33 @@ def get_settings():
837
837
  get_min()
838
838
  return battery_settings
839
839
 
840
+ ##################################################################################################
841
+ # get peak shaving settings
842
+ ##################################################################################################
843
+
844
+ def get_peakshaving():
845
+ global device_sn, debug_setting
846
+ if get_device() is None:
847
+ return None
848
+ output(f"getting peak shaving", 2)
849
+ body = {'sn': device_sn}
850
+ response = signed_post(path="/op/v0/device/peakShaving/get", body=body)
851
+ if response.status_code != 200:
852
+ output(f"** get_peakshaving() got response code {response.status_code}: {response.reason}")
853
+ return None
854
+ errno = response.json().get('errno')
855
+ if errno != 0:
856
+ if errno == 40257:
857
+ output(f"** Peak Shaving is not available")
858
+ else:
859
+ output(f"** get_peakshaving(), {errno_message(response)}")
860
+ return None
861
+ result = response.json().get('result')
862
+ if result is None:
863
+ output(f"** get_peakshaving(), no result data, {errno_message(response)}")
864
+ return None
865
+ return result
866
+
840
867
  ##################################################################################################
841
868
  # get remote settings
842
869
  ##################################################################################################
@@ -1191,20 +1218,21 @@ def set_schedule(periods=None, enable=True):
1191
1218
  residual_scale = 0.01
1192
1219
 
1193
1220
  # get real time data
1194
- def get_real(v = None):
1221
+ def get_real(v = None, sns = None, version = 0):
1195
1222
  global device_sn, debug_setting, device, power_vars, invert_ct2, residual_scale
1196
- if get_device() is None:
1197
- return None
1198
- if device['status'] > 1:
1199
- status_code = device['status']
1200
- state = 'fault' if status_code == 2 else 'off-line' if status_code == 3 else 'unknown'
1201
- output(f"** get_real(): device {device_sn} is not on-line, status = {state} ({device['status']})")
1202
- return None
1223
+ if sns is None:
1224
+ if get_device() is None:
1225
+ return None
1226
+ if device['status'] > 1:
1227
+ status_code = device['status']
1228
+ state = 'fault' if status_code == 2 else 'off-line' if status_code == 3 else 'unknown'
1229
+ output(f"** get_real(): device {device_sn} is not on-line, status = {state} ({device['status']})")
1230
+ return None
1203
1231
  output(f"getting real-time data", 2)
1204
- body = {'deviceSN': device_sn}
1232
+ body = {'sns': sns if sns is not None and type(sns) is list else [sns] if sns is not None else [device_sn]}
1205
1233
  if v is not None:
1206
1234
  body['variables'] = v if type(v) is list else [v]
1207
- response = signed_post(path="/op/v0/device/real/query", body=body)
1235
+ response = signed_post(path="/op/v1/device/real/query", body=body)
1208
1236
  if response.status_code != 200:
1209
1237
  output(f"** get_real() got response code {response.status_code}: {response.reason}")
1210
1238
  return None
@@ -1214,17 +1242,18 @@ def get_real(v = None):
1214
1242
  return None
1215
1243
  if len(result) < 1:
1216
1244
  return None
1217
- elif len(result) > 1:
1218
- output(f"** get_real(), more than 1 value returned: {result}")
1219
- result = result[0]['datas']
1220
- for var in result:
1221
- if var.get('variable') == 'meterPower2' and invert_ct2 == 1:
1222
- var['value'] *= -1
1223
- elif var.get('variable') == 'ResidualEnergy':
1224
- var['unit'] = 'kWh'
1225
- var['value'] = var['value'] * residual_scale
1226
- elif var.get('unit') is None:
1227
- var['unit'] = ''
1245
+ for r in result:
1246
+ datas = r['datas']
1247
+ for var in datas:
1248
+ if var.get('variable') == 'meterPower2' and invert_ct2 == 1:
1249
+ var['value'] *= -1
1250
+ elif var.get('variable') == 'ResidualEnergy':
1251
+ var['unit'] = 'kWh'
1252
+ var['value'] = var['value'] * residual_scale
1253
+ elif var.get('unit') is None:
1254
+ var['unit'] = ''
1255
+ if version == 0 and type(sns) is not list:
1256
+ result = result[0]['datas']
1228
1257
  return result
1229
1258
 
1230
1259
 
@@ -3550,7 +3579,7 @@ def get_pvoutput(d = None, tou = 0):
3550
3579
  if type(d) is list:
3551
3580
  print(f"---------------- get_pvoutput ------------------")
3552
3581
  print(f"Date range {d[0]} to {d[-1]} has {len(d)} days")
3553
- if tou == 1:
3582
+ if tou == 1 and tariff is not None:
3554
3583
  print(f"Time of use: {tariff['name']}")
3555
3584
  elif tou == 2:
3556
3585
  print(f"All values integrated from power")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foxesscloud
3
- Version: 2.8.3
3
+ Version: 2.8.5
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
@@ -15,7 +15,7 @@ License-File: LICENCE
15
15
  # FoxESS-Cloud
16
16
 
17
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>
18
- This site contains sample python code for accessing the Fox cloud data via the REST API used by the Fox ESS Cloud web site and app.
18
+ This site contains sample python code for accessing the Fox cloud data via the REST API.
19
19
 
20
20
  There is also a number of Jupyter Lab notebooks with examples of how to run the sample code.
21
21
 
@@ -109,6 +109,7 @@ f.get_batteries(info, rated, count)
109
109
  f.get_settings()
110
110
  f.get_charge()
111
111
  f.get_min()
112
+ f.get_peakshaving()
112
113
  f.get_flag()
113
114
  f.get_schedule()
114
115
  f.get_named_settings(name)
@@ -132,6 +133,8 @@ Additional battery attributes provided include:
132
133
 
133
134
  get_settings() will return the battery settings and is equivalent to get_charge() and get_min(). The results are stored in f.battery_settings. The settings include minSoc, minSocOnGrid, enable charge from grid and the charge times.
134
135
 
136
+ get_peakshaving() will return the current peak shaving settings for inverters that support this work mode.
137
+
135
138
  get_flag() returns the current scheduler enable / support / maxsoc flags. By default support for Max Soc is set to False.
136
139
 
137
140
  get_schedule() returns the current work mode / soc schedule settings. The result is stored in f.schedule.
@@ -205,7 +208,7 @@ Real time data reports the latest values for inverter variables, collected every
205
208
  ```
206
209
  f.invert_ct2 = 1
207
210
  f.get_vars()
208
- f.get_real(v)
211
+ f.get_real(v, sns, version)
209
212
  ```
210
213
 
211
214
  f.invert_ct2 determines how the meterPower2 data is handled. When invert_ct2 = 0, meterPower2 produces +ve power values during secondary generation. If meterPower2 produces -ve power values during secondary generation, setting invert_ct2 = 1 will flip the values so they are +ve when generating. The default setting is 1 (invert).
@@ -220,6 +223,8 @@ There are also pre-defined lists:
220
223
 
221
224
  f.get_real returns the latest values for a list of variables.
222
225
  + v is a variable, or list of variables. The default is to return the latest value for all available variables
226
+ + sns is an optional inverter serial number or a list of inverter serial numbers to get data for. The default is the current device
227
+ + version determines the format of the output. By default, get_real() returns a list of variables for a single inverter (legacy mode). Setting version=1 returns a list of inverter results using the v1 Open API format.
223
228
 
224
229
 
225
230
  ## History Data
@@ -821,6 +826,14 @@ This setting can be:
821
826
 
822
827
  # Version Info
823
828
 
829
+ 2.8.5<br>
830
+ Update battery variables to include SOH.
831
+ Add get_peakshaving().
832
+ Update get_real() to support a list of inverters using Open API v1.
833
+
834
+ 2.8.4<br>
835
+ Fix exception when calling pvoutput with tou=1 but no tariff set.
836
+
824
837
  2.8.3<br>
825
838
  Update to support setting Max Soc in schedules now this is supported by Fox using Open API.
826
839
 
@@ -0,0 +1,7 @@
1
+ foxesscloud/foxesscloud.py,sha256=_Su3Dcs0CSM2TlbAmCtouM4LkhYfYZ2Bk70eVgZqBJg,225011
2
+ foxesscloud/openapi.py,sha256=fRW2f2kIsvib3Y8reYXIegqQBBkMFgqjHhy1n29uzoY,209773
3
+ foxesscloud-2.8.5.dist-info/LICENCE,sha256=8JF-24QkE8UfdII-g6RaIEvM-PZ9zwaEcxlwYUDMt-4,1079
4
+ foxesscloud-2.8.5.dist-info/METADATA,sha256=b5LAyooq_E3GPMcDXEwb-ghyxbYOs4Ughah03NH7I78,65861
5
+ foxesscloud-2.8.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
6
+ foxesscloud-2.8.5.dist-info/top_level.txt,sha256=IWOrKSNZCLU6IDXSX_b4_bqCfbZoWAT4CC0w0Lg7PuU,12
7
+ foxesscloud-2.8.5.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- foxesscloud/foxesscloud.py,sha256=E48TEwk75XrLcJNXNvuMwG93VjjIYknuPERqSYGhRDE,224825
2
- foxesscloud/openapi.py,sha256=d-qKK_XjpnRQpnAQ7HcLZSP7hbViHQ9tckM5o4Xf0eE,208484
3
- foxesscloud-2.8.3.dist-info/LICENCE,sha256=8JF-24QkE8UfdII-g6RaIEvM-PZ9zwaEcxlwYUDMt-4,1079
4
- foxesscloud-2.8.3.dist-info/METADATA,sha256=ECLbKmesBVJ5HRnvGXTw842d9q8XPhAc2y0MKuP9AyE,65179
5
- foxesscloud-2.8.3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
6
- foxesscloud-2.8.3.dist-info/top_level.txt,sha256=IWOrKSNZCLU6IDXSX_b4_bqCfbZoWAT4CC0w0Lg7PuU,12
7
- foxesscloud-2.8.3.dist-info/RECORD,,