foxesscloud 2.8.4__py3-none-any.whl → 2.8.6__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.
foxesscloud/openapi.py CHANGED
@@ -1,7 +1,7 @@
1
1
  ##################################################################################################
2
2
  """
3
3
  Module: Fox ESS Cloud using Open API
4
- Updated: 20 May 2025
4
+ Updated: 5 July 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.4"
13
+ version = "2.8.6"
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
  ##################################################################################################
@@ -923,8 +950,6 @@ def get_work_mode():
923
950
  global work_mode
924
951
  if get_device() is None:
925
952
  return None
926
- # not implemented by Open API, skip to avoid error
927
- return None
928
953
  work_mode = get_named_settings('WorkMode')
929
954
  return work_mode
930
955
 
@@ -1191,20 +1216,21 @@ def set_schedule(periods=None, enable=True):
1191
1216
  residual_scale = 0.01
1192
1217
 
1193
1218
  # get real time data
1194
- def get_real(v = None):
1219
+ def get_real(v = None, sns = None, version = 0):
1195
1220
  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
1221
+ if sns is None:
1222
+ if get_device() is None:
1223
+ return None
1224
+ if device['status'] > 1:
1225
+ status_code = device['status']
1226
+ state = 'fault' if status_code == 2 else 'off-line' if status_code == 3 else 'unknown'
1227
+ output(f"** get_real(): device {device_sn} is not on-line, status = {state} ({device['status']})")
1228
+ return None
1203
1229
  output(f"getting real-time data", 2)
1204
- body = {'deviceSN': device_sn}
1230
+ body = {'sns': sns if sns is not None and type(sns) is list else [sns] if sns is not None else [device_sn]}
1205
1231
  if v is not None:
1206
1232
  body['variables'] = v if type(v) is list else [v]
1207
- response = signed_post(path="/op/v0/device/real/query", body=body)
1233
+ response = signed_post(path="/op/v1/device/real/query", body=body)
1208
1234
  if response.status_code != 200:
1209
1235
  output(f"** get_real() got response code {response.status_code}: {response.reason}")
1210
1236
  return None
@@ -1214,17 +1240,18 @@ def get_real(v = None):
1214
1240
  return None
1215
1241
  if len(result) < 1:
1216
1242
  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'] = ''
1243
+ for r in result:
1244
+ datas = r['datas']
1245
+ for var in datas:
1246
+ if var.get('variable') == 'meterPower2' and invert_ct2 == 1:
1247
+ var['value'] *= -1
1248
+ elif var.get('variable') == 'ResidualEnergy':
1249
+ var['unit'] = 'kWh'
1250
+ var['value'] = var['value'] * residual_scale
1251
+ elif var.get('unit') is None:
1252
+ var['unit'] = ''
1253
+ if version == 0 and type(sns) is not list:
1254
+ result = result[0]['datas']
1228
1255
  return result
1229
1256
 
1230
1257
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foxesscloud
3
- Version: 2.8.4
3
+ Version: 2.8.6
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.6<br>#
830
+ Update to charge_needed() to get current work mode.
831
+
832
+ 2.8.5<br>
833
+ Update battery variables to include SOH.
834
+ Add get_peakshaving().
835
+ Update get_real() to support a list of inverters using Open API v1.
836
+
824
837
  2.8.4<br>
825
838
  Fix exception when calling pvoutput with tou=1 but no tariff set.
826
839
 
@@ -0,0 +1,7 @@
1
+ foxesscloud/foxesscloud.py,sha256=_Su3Dcs0CSM2TlbAmCtouM4LkhYfYZ2Bk70eVgZqBJg,225011
2
+ foxesscloud/openapi.py,sha256=ftS5WZ838P3kSbjoHB0Ypcb6MYV-ePGX6nDbhpEpf0I,209702
3
+ foxesscloud-2.8.6.dist-info/LICENCE,sha256=8JF-24QkE8UfdII-g6RaIEvM-PZ9zwaEcxlwYUDMt-4,1079
4
+ foxesscloud-2.8.6.dist-info/METADATA,sha256=YceASwn6QpmzkI1IXtC33PQ-lBW0XWZU6YbmxYj3eMo,65928
5
+ foxesscloud-2.8.6.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
6
+ foxesscloud-2.8.6.dist-info/top_level.txt,sha256=IWOrKSNZCLU6IDXSX_b4_bqCfbZoWAT4CC0w0Lg7PuU,12
7
+ foxesscloud-2.8.6.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- foxesscloud/foxesscloud.py,sha256=_Su3Dcs0CSM2TlbAmCtouM4LkhYfYZ2Bk70eVgZqBJg,225011
2
- foxesscloud/openapi.py,sha256=HNpg7Uh1PNoNI9Tvq3-bng7dX7_h9Woz2VTh0lL68R4,208505
3
- foxesscloud-2.8.4.dist-info/LICENCE,sha256=8JF-24QkE8UfdII-g6RaIEvM-PZ9zwaEcxlwYUDMt-4,1079
4
- foxesscloud-2.8.4.dist-info/METADATA,sha256=nzqI_BgDTsAYr8rFWDKd7kX8sCBf9yy1IvmSbFc8bZ0,65259
5
- foxesscloud-2.8.4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
6
- foxesscloud-2.8.4.dist-info/top_level.txt,sha256=IWOrKSNZCLU6IDXSX_b4_bqCfbZoWAT4CC0w0Lg7PuU,12
7
- foxesscloud-2.8.4.dist-info/RECORD,,