From 244a13e41b4be7ff0031b392acfea2f5498ad6d6 Mon Sep 17 00:00:00 2001 From: lgb-this Date: Mon, 30 Oct 2023 21:42:47 +0100 Subject: [PATCH 1/3] minimal release of mathplotlib added --- byd_bat/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/byd_bat/requirements.txt b/byd_bat/requirements.txt index 6ccafc3f9..11c0a0a75 100644 --- a/byd_bat/requirements.txt +++ b/byd_bat/requirements.txt @@ -1 +1 @@ -matplotlib +matplotlib>=3.8.0 From b465c3b4e77504942b8e7d31f88d0ad72828fdef Mon Sep 17 00:00:00 2001 From: lgb-this Date: Mon, 30 Oct 2023 21:45:30 +0100 Subject: [PATCH 2/3] several modifications new parameter in diagnostic added: Bat-Voltag, V-Out, Current list of converters updated delete plot-files with start of plugin modifications for mathplotlib 3.8.0 --- byd_bat/__init__.py | 222 +++++++++++++++++++++++++++++++++----------- 1 file changed, 166 insertions(+), 56 deletions(-) diff --git a/byd_bat/__init__.py b/byd_bat/__init__.py index 91594310c..5419a7224 100644 --- a/byd_bat/__init__.py +++ b/byd_bat/__init__.py @@ -37,6 +37,10 @@ # # V0.0.4 230904 - Bilder JPG in PNG konvertiert fuer user_doc.rst # +# V0.0.5 231030 - Diagnose ergaenzt: Bat-Voltag, V-Out, Current +# - Liste der Wechselrichter aktualisiert +# - Alle Plot-Dateien beim Plugin-Start loeschen +# # ----------------------------------------------------------------------- # # Als Basis fuer die Implementierung wurde die folgende Quelle verwendet: @@ -45,7 +49,10 @@ # # Diverse Notizen # -# - Datenpaket wird mit CRC16/MODBUS am Ende abgeschlossen (2 Byte, LSB,MSB) +# - Beginn Frame (Senden/Empfangen): 0x01 0x03 +# - Antwort 3.Byte (direkt nach Header): Anzahl Bytes Nutzdaten (2 Byte CRC werden mitgezaehlt) +# - Datenpaket wird mit CRC16/MODBUS am Ende abgeschlossen (2 Byte, LSB,MSB) (Nutzdaten+Längenbyte) +# - Der Server im BYD akzeptiert nur 1 Verbindung auf Port 8080/TCP ! # # ----------------------------------------------------------------------- @@ -59,6 +66,7 @@ import matplotlib import matplotlib.pyplot as plt import numpy as np +import os byd_ip_default = "192.168.16.254" @@ -72,7 +80,7 @@ byd_timeout_2s = 2.0 byd_timeout_8s = 8.0 -byd_tours_max = 3 +byd_towers_max = 3 byd_cells_max = 160 byd_temps_max = 64 @@ -122,48 +130,52 @@ "Low Temperature Discharging (Cells)" ] +byd_invs_max = 19 byd_invs = [ - "Fronius HV", - "Goodwe HV", - "Fronius HV", - "Kostal HV", - "Goodwe HV", - "SMA SBS3.7/5.0", - "Kostal HV", - "SMA SBS3.7/5.0", - "Sungrow HV", - "Sungrow HV", - "Kaco HV", - "Kaco HV", - "Ingeteam HV", - "Ingeteam HV", - "SMA SBS 2.5 HV", - "", - "SMA SBS 2.5 HV", - "Fronius HV" + "Fronius HV", # 0 + "Goodwe HV", # 1 + "Fronius HV", # 2 + "Kostal HV", # 3 + "Goodwe HV", # 4 + "SMA SBS3.7/5.0", # 5 + "Kostal HV", # 6 + "SMA SBS3.7/5.0", # 7 + "Sungrow HV", # 8 + "Sungrow HV", # 9 + "Kaco HV", # 10 + "Kaco HV", # 11 + "Ingeteam HV", # 12 + "Ingeteam HV", # 13 + "SMA SBS 2.5 HV", # 14 + "", # 15 + "SMA SBS 2.5 HV", # 16 + "Fronius HV", # 17 + "", # 18 + "SMA STPx.0-3SE-40" # 19 ] +byd_invs_lvs_max = 19 byd_invs_lvs = [ - "Fronius HV", - "Goodwe HV", - "Goodwe HV", - "Kostal HV", - "Selectronic LV", - "SMA SBS3.7/5.0", - "SMA LV", - "Victron LV", - "Suntech LV", - "Sungrow HV", - "Kaco HV", - "Studer LV", - "Solar Edge LV", - "Ingeteam HV", - "Sungrow LV", - "Schneider LV", - "SMA SBS2.5 HV", - "Solar Edge LV", - "Solar Edge LV", - "Solar Edge LV" + "Fronius HV", # 0 + "Goodwe HV", # 1 + "Goodwe HV", # 2 + "Kostal HV", # 3 + "Selectronic LV", # 4 + "SMA SBS3.7/5.0", # 5 + "SMA LV", # 6 + "Victron LV", # 7 + "Suntech LV", # 8 + "Sungrow HV", # 9 + "Kaco HV", # 10 + "Studer LV", # 11 + "Solar Edge LV", # 12 + "Ingeteam HV", # 13 + "Sungrow LV", # 14 + "Schneider LV", # 15 + "SMA SBS2.5 HV", # 16 + "Solar Edge LV", # 17 + "Solar Edge LV", # 18 + "Solar Edge LV" # 19 ] @@ -178,7 +190,7 @@ class properties and methods (class variables and class functions) are already available! """ - PLUGIN_VERSION = '0.0.4' + PLUGIN_VERSION = '0.0.5' def __init__(self,sh): """ @@ -226,6 +238,9 @@ def __init__(self,sh): self.byd_root_found = False self.byd_diag_soc = [] + self.byd_diag_bat_voltag = [] + self.byd_diag_v_out = [] + self.byd_diag_current = [] self.byd_diag_volt_max = [] self.byd_diag_volt_max_c = [] self.byd_diag_volt_min = [] @@ -234,8 +249,11 @@ def __init__(self,sh): self.byd_diag_temp_min_c = [] self.byd_volt_cell = [] self.byd_temp_cell = [] - for x in range(0,byd_tours_max + 1): + for x in range(0,byd_towers_max + 1): self.byd_diag_soc.append(0) + self.byd_diag_bat_voltag.append(0) + self.byd_diag_v_out.append(0) + self.byd_diag_current.append(0) self.byd_diag_volt_max.append(0) self.byd_diag_volt_max_c.append(0) self.byd_diag_volt_min.append(0) @@ -253,6 +271,10 @@ def __init__(self,sh): self.last_homedata = self.now_str() self.last_diagdata = self.now_str() + + self.plt_file_del() + + # self.simulate_data() # for internal tests only # Initialization code goes here @@ -507,7 +529,7 @@ def decode_0(self,data): # Anzahl Tuerme und Anzahl Module pro Turm self.byd_bms_qty = data[36] // 0x10 - if (self.byd_bms_qty == 0) or (self.byd_bms_qty > byd_tours_max): + if (self.byd_bms_qty == 0) or (self.byd_bms_qty > byd_towers_max): self.byd_bms_qty = 1 self.byd_modules = data[36] % 0x10 self.byd_batt_type_snr = data[5] @@ -541,7 +563,7 @@ def decode_1(self,data): self.byd_volt_max = self.buf2int16SI(data,5) * 1.0 / 100.0 self.byd_volt_min = self.buf2int16SI(data,7) * 1.0 / 100.0 self.byd_volt_diff = self.byd_volt_max - self.byd_volt_min - self.byd_current = self.buf2int16SI(data,11) * 1.0 / 10.0 + self.byd_current = self.buf2int16SI(data,11) * 1.0 / 10.0 # Byte 11+12 self.byd_power = self.byd_volt_out * self.byd_current if self.byd_power >= 0: self.byd_power_discharge = self.byd_power @@ -632,9 +654,15 @@ def decode_2(self,data): self.byd_inv_type = data[3] if self.byd_batt_str == "LVS": - self.byd_inv_str = byd_invs_lvs[self.byd_inv_type] + if self.byd_inv_type <= byd_invs_lvs_max: + self.byd_inv_str = byd_invs_lvs[self.byd_inv_type] + else: + self.byd_inv_str = "unknown" else: - self.byd_inv_str = byd_invs[self.byd_inv_type] + if self.byd_inv_type <= byd_invs_max: + self.byd_inv_str = byd_invs[self.byd_inv_type] + else: + self.byd_inv_str = "unknown" self.log_debug("Inv Type : " + self.byd_inv_str + " (" + str(self.byd_inv_type) + ")") self.log_debug("Batt Type : " + self.byd_batt_str + " (" + str(self.byd_batt_type) + ")") @@ -652,7 +680,10 @@ def decode_5(self,data,x): self.log_debug("decode_5 (" + str(x) + ") : " + data.hex()) - self.byd_diag_soc[x] = self.buf2int16SI(data,53) * 1.0 / 10.0 + self.byd_diag_soc[x] = self.buf2int16SI(data,53) * 1.0 / 10.0 # Byte 53+54 + self.byd_diag_bat_voltag[x] = self.buf2int16SI(data,45) * 1.0 / 10.0 # Byte 45+46 + self.byd_diag_v_out[x] = self.buf2int16SI(data,51) * 1.0 / 10.0 # Byte 51+52 + self.byd_diag_current[x] = self.buf2int16SI(data,57) * 1.0 / 10.0 # Byte 57+58 self.byd_diag_volt_max[x] = self.buf2int16SI(data,5) / 1000.0 self.byd_diag_volt_max_c[x] = data[9] self.byd_diag_volt_min[x] = self.buf2int16SI(data,7) / 1000.0 @@ -664,11 +695,14 @@ def decode_5(self,data,x): for xx in range(0,16): self.byd_volt_cell[x][xx] = self.buf2int16SI(data,101 + (xx * 2)) / 1000.0 - self.log_debug("SOC : " + str(self.byd_diag_soc[x])) - self.log_debug("Volt max : " + str(self.byd_diag_volt_max[x]) + " c=" + str(self.byd_diag_volt_max_c[x])) - self.log_debug("Volt min : " + str(self.byd_diag_volt_min[x]) + " c=" + str(self.byd_diag_volt_min_c[x])) - self.log_debug("Temp max : " + " c=" + str(self.byd_diag_temp_max_c[x])) - self.log_debug("Temp min : " + " c=" + str(self.byd_diag_temp_min_c[x])) + self.log_debug("SOC : " + str(self.byd_diag_soc[x])) + self.log_debug("Bat Voltag : " + str(self.byd_diag_bat_voltag[x])) + self.log_debug("V-Out : " + str(self.byd_diag_v_out[x])) + self.log_debug("Current : " + str(self.byd_diag_current[x])) + self.log_debug("Volt max : " + str(self.byd_diag_volt_max[x]) + " c=" + str(self.byd_diag_volt_max_c[x])) + self.log_debug("Volt min : " + str(self.byd_diag_volt_min[x]) + " c=" + str(self.byd_diag_volt_min_c[x])) + self.log_debug("Temp max : " + " c=" + str(self.byd_diag_temp_max_c[x])) + self.log_debug("Temp min : " + " c=" + str(self.byd_diag_temp_min_c[x])) # for xx in range(0,16): # self.log_debug("Turm " + str(x) + " Volt " + str(xx) + " : " + str(self.byd_volt_cell[x][xx])) @@ -781,6 +815,9 @@ def diagdata_save(self,device): def diagdata_save_one(self,device,x): device.soc(self.byd_diag_soc[x]) + device.bat_voltag(self.byd_diag_bat_voltag[x]) + device.v_out(self.byd_diag_v_out[x]) + device.current(self.byd_diag_current[x]) device.volt_max.volt(self.byd_diag_volt_max[x]) device.volt_max.cell(self.byd_diag_volt_max_c[x]) device.volt_min.volt(self.byd_diag_volt_min[x]) @@ -831,9 +868,9 @@ def diag_plot(self,x): ax.spines[:].set_visible(False) ax.set_xticks(np.arange(dd.shape[1] + 1) - .5,minor=True) - ax.set_yticks(np.arange(dd.shape[0] + 1) - .5,minor=True,size=10) + ax.set_yticks(np.arange(dd.shape[0] + 1) - .5,minor=True) ax.tick_params(which='minor',bottom=False,left=False) - ax.tick_params(axis='y',colors='white') + ax.tick_params(axis='y',colors='white',labelsize=10) textcolors = ("white","black") threshold = im.norm(dd.max()) / 2. @@ -891,9 +928,9 @@ def diag_plot(self,x): ax.spines[:].set_visible(False) ax.set_xticks(np.arange(dd.shape[1] + 1) - .5,minor=True) - ax.set_yticks(np.arange(dd.shape[0] + 1) - .5,minor=True,size=10) + ax.set_yticks(np.arange(dd.shape[0] + 1) - .5,minor=True) ax.tick_params(which='minor',bottom=False,left=False) - ax.tick_params(axis='y',colors='white') + ax.tick_params(axis='y',colors='white',labelsize=10) textcolors = ("black","white") threshold = im.norm(dd.max()) / 2. @@ -918,6 +955,55 @@ def diag_plot(self,x): plt.close('all') return + + def plt_file_del(self): + # Loescht alle Plot-Dateien + + # Spannungs-Plots + fn = self.get_plugin_dir() + byd_webif_img + byd_fname_volt + str(1) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + fn = self.get_plugin_dir() + byd_webif_img + byd_fname_volt + str(2) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + fn = self.get_plugin_dir() + byd_webif_img + byd_fname_volt + str(3) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + + if len(self.bpath) != byd_path_empty: + fn = self.bpath + byd_fname_volt + str(1) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + fn = self.bpath + byd_fname_volt + str(2) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + fn = self.bpath + byd_fname_volt + str(3) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + + # Temperatur-Plots + fn = self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(1) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + fn = self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(2) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + fn = self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(3) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + + if len(self.bpath) != byd_path_empty: + fn = self.bpath + byd_fname_temp + str(1) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + fn = self.bpath + byd_fname_temp + str(2) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + fn = self.bpath + byd_fname_temp + str(3) + byd_fname_ext + if os.path.exists(fn) == True: + os.remove(fn) + + return def buf2int16SI(self,byteArray,pos): # signed result = byteArray[pos] * 256 + byteArray[pos + 1] @@ -981,3 +1067,27 @@ def init_webinterface(self): description='') return True + + def simulate_data(self): + # For internal tests only + self.byd_modules = 7 + self.byd_batt_str = "HVM" + self.byd_capacity_module = 2.76 + self.byd_volt_n = 16 + self.byd_temp_n = 8 + self.byd_cells_n = self.byd_modules * self.byd_volt_n + self.byd_temps_n = self.byd_modules * self.byd_temp_n + + for xx in range(0,self.byd_cells_n): + if (xx % 2) == 0: + self.byd_volt_cell[1][xx] = 2.2 + else: + self.byd_volt_cell[1][xx] = 2.4 + for xx in range(0,self.byd_temps_n): + if (xx % 2) == 0: + self.byd_temp_cell[1][xx] = 23 + else: + self.byd_temp_cell[1][xx] = 26 + + self.diag_plot(1) + \ No newline at end of file From f9938b38b367f0ff3093a3e417ea17162a6b8fc4 Mon Sep 17 00:00:00 2001 From: lgb-this Date: Mon, 30 Oct 2023 21:56:19 +0100 Subject: [PATCH 3/3] minimal version of Python is 3.9 --- byd_bat/plugin.yaml | 49 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/byd_bat/plugin.yaml b/byd_bat/plugin.yaml index 305458573..8186f4e6d 100644 --- a/byd_bat/plugin.yaml +++ b/byd_bat/plugin.yaml @@ -12,10 +12,10 @@ plugin: # documentation: https://github.com/smarthomeNG/smarthome/wiki/CLI-Plugin # url of documentation (wiki) page support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1886748-support-thread-f%C3%BCr-das-byd-batterie-plugin - version: 0.0.4 # Plugin version (must match the version specified in __init__.py) + version: 0.0.5 # Plugin version (must match the version specified in __init__.py) sh_minversion: 1.9 # minimum shNG version to use this plugin # sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest) -# py_minversion: 3.6 # minimum Python version to use for this plugin + py_minversion: 3.9 # minimum Python version to use for this plugin # py_maxversion: # maximum Python version to use for this plugin (leave empty if latest) multi_instance: false # plugin supports multi instance restartable: true @@ -213,6 +213,21 @@ item_structs: visu_acl: ro database: init + bat_voltag: # BAT Voltage [V] + type: num + visu_acl: ro + database: init + + v_out: # V-Out [V] + type: num + visu_acl: ro + database: init + + current: # Current [A] (+ discharge / - charge battery) + type: num + visu_acl: ro + database: init + volt_max: volt: # max voltage [V] @@ -254,6 +269,21 @@ item_structs: visu_acl: ro database: init + bat_voltag: # BAT Voltage [V] + type: num + visu_acl: ro + database: init + + v_out: # V-Out [V] + type: num + visu_acl: ro + database: init + + current: # Current [A] (+ discharge / - charge battery) + type: num + visu_acl: ro + database: init + volt_max: volt: # max voltage [V] @@ -295,6 +325,21 @@ item_structs: visu_acl: ro database: init + bat_voltag: # BAT Voltage [V] + type: num + visu_acl: ro + database: init + + v_out: # V-Out [V] + type: num + visu_acl: ro + database: init + + current: # Current [A] (+ discharge / - charge battery) + type: num + visu_acl: ro + database: init + volt_max: volt: # max voltage [V]