From a0f876eada33cbae17999adeb21e7a4203571e76 Mon Sep 17 00:00:00 2001 From: lgb-this Date: Fri, 12 Jan 2024 17:08:51 +0100 Subject: [PATCH 1/5] Release 0.0.8 - modifications see '__init__.py' --- byd_bat/__init__.py | 2637 +++++++++++++++++++++++++++++++++++------- byd_bat/locale.yaml | 14 + byd_bat/plugin.yaml | 697 ++++++++++- byd_bat/user_doc.rst | 59 +- 4 files changed, 2982 insertions(+), 425 deletions(-) diff --git a/byd_bat/__init__.py b/byd_bat/__init__.py index ea5e2ff22..577e56dcc 100644 --- a/byd_bat/__init__.py +++ b/byd_bat/__init__.py @@ -27,6 +27,7 @@ # ----------------------------------------------------------------------- # # History +# ======= # # V0.0.1 230811 - erster Release # @@ -54,18 +55,38 @@ # - Temperatur Fehler beim Auslesen korrigiert # - Neuer Parameter 'diag_cycle' fuer Abfrage der Diagnosedaten # +# V0.0.8 240112 - Leere kleine PNG fuer nicht vorhandene Tuerme erzeugen +# - Zellen mit Balancing werden neu rot umrandet (Heatmap Spannungen) +# - Turm Diagnose Balancing neue Items 'active' und 'number' +# - Turm Diagnose neues Item 'volt_diff' fuer Spannungsdifferenz (Max-Min) +# - Turm neue Items 'soh' und 'state' +# - Neuer Parameter 'log_data' und 'log_age' +# - Neue Items 'state.charge_total', 'state.discharge_total' und 'state.eta' +# - Turm Diagnose neue Items 'charge_total' und 'discharge_total' +# - Liste der Wechselrichter aktualisiert +# - Funktion 'send_msg' mit CRC-Check ergaenzt +# - Berechnung diverser Werte fuer jedes Modul in jedem Turm 'diagnosis/towerX/modules/...' +# - Abfrage der Logdaten in BMU und BMS implementiert +# - Logdaten BYD werden in speziellen Logdateien pro Tag gespeichert +# - Logdaten werden speziell fuer Visualisierung aufbereitet 'visu/...' +# - Diverse Anpassungen in der Code-Struktur +# # ----------------------------------------------------------------------- # -# Als Basis fuer die Implementierung wurde die folgende Quelle verwendet: +# Als Basis fuer die Implementierung wurde u.a. folgende Quelle verwendet: # # https://github.com/christianh17/ioBroker.bydhvs # # Diverse Notizen # -# - 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) +# - Max. Anzahl Module: HVS=2-5, HVM=3-8, HVL=3-8, LVS=1-8 +# - Beginn Frame (Senden/Empfangen): 0x01 0x03 (Beispiel, es gibt auch andere Startsequenzen) +# - Antwort 3.Byte (direkt nach Header): Anzahl Bytes Nutzdaten (?) (2 Byte CRC werden mitgezaehlt) +# packetLength = data[2] + 5; (3 header, 2 crc) +# https://crccalc.com/ (Input=Hex, CRC-16, CRC-16/MODBUS) +# - 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 ! +# - Ein Register (Index) hat 2 Bytes und ist MSB,LSB aufgebaut # # ----------------------------------------------------------------------- @@ -78,27 +99,33 @@ import time import matplotlib import matplotlib.pyplot as plt +import matplotlib.patches as patches import numpy as np import os +import json +from datetime import datetime, timedelta +from zoneinfo import ZoneInfo +from decimal import Decimal,ROUND_DOWN -#import random # only for internal test +import random # only for internal test [TEST] byd_ip_default = "192.168.16.254" scheduler_name = 'byd_bat' -BUFFER_SIZE = 4096 - -byd_sample_basics = 60 # Abfrage fuer Basisdaten [s] -byd_sample_diag = 300 # Abfrage fuer Diagnosedaten [s] +byd_sample_basics = 60 # Abfrage fuer Basisdaten [s] +byd_sample_diag = 300 # Abfrage fuer Diagnosedaten [s] +byd_sample_log = 300 # Abfrage fuer Logdaten [s] byd_timeout_1s = 1.0 byd_timeout_2s = 2.0 byd_timeout_8s = 8.0 +byd_timeout_10s = 10.0 byd_towers_max = 3 byd_cells_max = 160 byd_temps_max = 64 +byd_module_max = 8 byd_no_of_col_7 = 7 byd_no_of_col_8 = 8 @@ -107,31 +134,87 @@ byd_webif_img = "/webif/static/img/" byd_path_empty = "x" byd_fname_volt = "bydvt" +byd_fname_volt2 = "bydvbt" byd_fname_temp = "bydtt" byd_fname_ext = ".png" +byd_ok = 1 +byd_error = 0 + +byd_module_vmin = 0 +byd_module_vmax = 1 +byd_module_vava = 2 +byd_module_vdif = 3 + +BUFFER_SIZE = 4096 # Groesse Empfangsbuffer + +byd_log_max_rows = 40 # maximale Anzahl Eintraege (html/json) +byd_log_directory = "byd_logs" +byd_log_extension = "log" +byd_log_special = "byd_special" +byd_log_newline = "\n" +byd_log_sep = "\t" + +# Log-Daten Indizes in der Liste +byd_log_year = 0 # Jahr +byd_log_month = 1 # Monat +byd_log_day = 2 # Tag +byd_log_hour = 3 # Stunde +byd_log_minute = 4 # Minute +byd_log_second = 5 # Sekunde +byd_log_codex = 6 # Code des Log-Eintrages +byd_log_data = 7 # Daten zum Log-Eintrag +byd_log_raw = 8 # Roh-Daten des Log-Eintrages +byd_log_str = 9 # 'byd_log_data' als String +byd_log_str_sep = " | " +byd_log_degree = "*C" + MESSAGE_0 = "010300000066c5e0" +MESSAGE_0_L = 209 MESSAGE_1 = "01030500001984cc" +MESSAGE_1_L = 55 MESSAGE_2 = "010300100003040e" +MESSAGE_2_L = 11 MESSAGE_3_1 = "0110055000020400018100f853" # Start Messung Turm 1 MESSAGE_3_2 = "01100550000204000281000853" # Start Messung Turm 2 MESSAGE_3_3 = "01100550000204000381005993" # Start Messung Turm 3 +MESSAGE_3_L = 8 MESSAGE_4 = "010305510001d517" +MESSAGE_4_L = 7 MESSAGE_5 = "01030558004104e5" +MESSAGE_5_L = 135 MESSAGE_6 = "01030558004104e5" +MESSAGE_6_L = 135 MESSAGE_7 = "01030558004104e5" +MESSAGE_7_L = 135 MESSAGE_8 = "01030558004104e5" +MESSAGE_8_L = 135 # to read the 5th module, the box must first be reconfigured (not tested) MESSAGE_9 = "01100100000306444542554700176f" # switch to second turn for the last few cells +MESSAGE_9_L = 0 # UNBEKANNT !! MESSAGE_10_1 = "0110055000020400018100f853" # start measuring remaining cells in tower 1 (like 3) MESSAGE_10_2 = "01100550000204000281000853" # start measuring remaining cells in tower 2 (like 3) MESSAGE_10_3 = "01100550000204000381005993" # start measuring remaining cells in tower 3 (like 3) +MESSAGE_10_L = 8 MESSAGE_11 = "010305510001d517" # (like 4) +MESSAGE_11_L = 7 MESSAGE_12 = "01030558004104e5" # (like 5) +MESSAGE_12_L = 135 MESSAGE_13 = "01030558004104e5" # (like 6) +MESSAGE_13_L = 135 MESSAGE_14 = "01030558004104e5" # (like 7) +MESSAGE_14_L = 135 MESSAGE_15 = "01030558004104e5" # (like 8) +MESSAGE_15_L = 135 + +EVT_MSG_0_0 = "011005a000020400008100A6D7" # BMU +EVT_MSG_0_1 = "011005a000020400018100f717" # BMS tower 1 +EVT_MSG_0_2 = "011005a0000204000281000717" # BMS tower 2 +EVT_MSG_0_3 = "011005a00002040003810056D7" # BMS tower 3 +EVT_MSG_0_L = 8 +EVT_MSG_1 = "010305A8004104D6" # request log-data +EVT_MSG_1_L = 135 byd_errors = [ "High Temperature Charging (Cells)", @@ -152,54 +235,279 @@ "Low Temperature Discharging (Cells)" ] -byd_invs_max = 19 -byd_invs = [ - "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 +# Liste der Wechselrichter (entnommen aus Be_Connect) +byd_inverters = [ + "Fronius HV", # 0 + "Goodwe HV/Viessmann HV", # 1 + "KOSTAL HV", # 2 + "SMA SBS3.7/5.0/6.0 HV", # 3 + "Sungrow HV", # 4 + "KACO_HV", # 5 + "Ingeteam HV", # 6 + "SMA SBS2.5 HV", # 7 + "Solis HV", # 8 + "SMA STP 5.0-10.0 SE HV", # 9 + "GE HV", # 10 + "Deye HV", # 11 + "KACO_NH", # 12 + "Solplanet", # 13 + "Western HV", # 14 + "SOSEN", # 15 + "Hoymiles HV", # 16 + "SAJ HV", # 17 + "Selectronic LV", # 18 + "SMA LV", # 19 + "Victron LV", # 20 + "Studer LV", # 21 + "Schneider LV", # 22 + "Solis LV", # 23 + "Deye LV", # 24 + "Raion LV", # 25 + "Hoymiles LV", # 26 + "Goodwe LV/Viessmann LV", # 27 + "SolarEdge LV", # 28 + "Sungrow LV Phocos LV", # 29 + "Suntech LV" # 30 (nicht im Hauptblock von Be_Connect) +] + +# Status eines Turms (2 Byte, 16 Bit) +byd_stat_tower = [ + "Battery Over Voltage", # Bit 0 + "Battery Under Voltage", # Bit 1 + "Cells OverVoltage", # Bit 2 + "Cells UnderVoltage", # Bit 3 + "Cells Imbalance", # Bit 4 + "Charging High Temperature(Cells)", # Bit 5 + "Charging Low Temperature(Cells)", # Bit 6 + "DisCharging High Temperature(Cells)", # Bit 7 + "DisCharging Low Temperature(Cells)", # Bit 8 + "Charging OverCurrent(Cells)", # Bit 9 + "DisCharging OverCurrent(Cells)", # Bit 10 + "Charging OverCurrent(Hardware)", # Bit 11 + "Short Circuit", # Bit 12 + "Inversly Connection", # Bit 13 + "Interlock switch Abnormal", # Bit 14 + "AirSwitch Abnormal" # Bit 15 +] + +byd_log_code = [ + [ 0,"Power ON"], # [ 0] + [ 1,"Power OFF"], # [ 1] + [ 2,"Events record"], # [ 2] Events appear, Events disappear + [ 3,"Timing Record"], # [ 3] + [ 4,"Start Charging"], # [ 4] + [ 5,"Stop Charging"], # [ 5] + [ 6,"Start DisCharging"], # [ 6] + [ 7,"Stop DisCharging"], # [ 7] + [ 8,"SOC calibration rough"], # [ 8] + [ 9,"??"], # [ 9] + [ 10,"SOC calibration Stop"], # [ 10] + [ 11,"CAN Communication failed"], # [ 11] + [ 12,"Serial Communication failed"], # [ 12] + [ 13,"Receive PreCharge Command"], # [ 13] + [ 14,"PreCharge Successful"], # [ 14] + [ 15,"PreCharge Failure"], # [ 15] + [ 16,"Start end SOC calibration"], # [ 16] + [ 17,"Start Balancing"], # [ 17] + [ 18,"Stop Balancing"], # [ 18] + [ 19,"Address Registered"], # [ 19] + [ 20,"System Functional Safety Fault"], # [ 20] + [ 21,"Events additional info"], # [ 21] + [ 22,"Start Firmware Update"], # [ 22] + [ 23,"Firmware Update finish"], # [ 23] + [ 24,"Firmware Update fails"], # [ 24] + [ 25,"SN Code was Changed"], # [ 25] + [ 26,"Current Calibration"], # [ 26] + [ 27,"Battery Voltage Calibration"], # [ 27] + [ 28,"PackVoltage Calibration"], # [ 28] + [ 29,"SOC/SOH Calibration"], # [ 29] + [ 30,"??"], # [ 30] + [ 31,"??"], # [ 31] + [ 32,"System status changed"], # [ 32] + [ 33,"Erase BMS Firmware"], # [ 33] + [ 34,"BMS update start"], # [ 34] + [ 35,"BMS update done"], # [ 35] + [ 36,"Functional Safety Info"], # [ 36] + [ 37,"No Defined"], # [ 37] + [ 38,"SOP Info"], # [ 38] + [ 39,"??"], # [ 39] + [ 40,"BMS Firmware list"], # [ 40] + [ 41,"MCU list of BMS"], # [ 41] + + # BCU Hardware failt + # Firmware Update failure + # Firmware Jumpinto other section + + [101,"Firmware Start to Update"], # [101] BMS: Start Firmware Update + [102,"Firmware Update Successful"], # [102] BMS: Firmware Update finish + + [105,"Parameters table Update"], # [105] + [106,"SN Code was Changed"], # [106] + + [111,"DateTime Calibration"], # [111] + [112,"BMS disconnected with BMU"], # [112] + [113,"MU F/W Reset"], # [113] + [114,"BMU Watchdog Reset"], # [114] + [115,"PreCharge Failed"], # [115] + [116,"Address registration failed"], # [116] + [117,"Parameters table Load Failed"], # [117] + [118,"System timing log"] # [118] + + # Parameters table updating done +] + +# System-Code (Log SOP Info (38), Quelle: Be_Connect 2.0.9, * = aus eigenen Log-Dateien) +byd_log_status = [ + "SYS_STANDBY", # 0 * + "SYS_INACTIVE", # 1 * + "SYS_BLACK_START", # 2 + "SYS_ACTIVE", # 3 * + "SYS_FAULT", # 4 + "SYS_UPDATING", # 5 + "SYS_SHUTDOWN", # 6 * + "SYS_PRECHARGE", # 7 * + "SYS_BATT_CHECK", # 8 * + "SYS_ASSIGN_ADDR", # 9 * + "SYS_LOAD_PARAM", # 10 * + "SYS_INIT", # 11 * + "SYS_UNKNOWN12" # 12 +] + +byd_module_type = [ + "HVL", + "HVM", + "HVS", + "Not defined" +] + +# Warnungen fuer Events record (2) (16 Bit) +byd_log_bmu_warnings = [ + "??", # 0 + "??", # 1 + "Cells OverVoltage", # 2 + "Cells UnderVoltage", # 3 + "V-sensor failure", # 4 + "??", # 5 + "??", # 6 + "Cell discharge Temp-Low", # 7 + "??", # 8 + "Cell charge Temp-Low", # 9 + "??", # 10 + "??", # 11 + "??", # 12 + "??", # 13 + "Cells imbalance", # 14 + "??" # 15 +] + +# Fehlermeldungen fuer Events record (2) (Enum) +byd_log_bmu_errors = [ + "Total Voltage too High", # 0 + "Total Voltage too Low", # 1 + "Cell Voltage too High", # 2 + "Cell Voltage too Low", # 3 + "Voltage Sensor Fault", # 4 + "Temperature Sersor Fault", # 5 + "Cell Discharging Temp. too High", # 6 + "Cell Discharging Temp. too Low", # 7 + "Cell Charging Temp. too High", # 8 + "Cell Charging Temp. too Low", # 9 + "Discharging Over Current", # 10 + "Charging Over Current", # 11 + "Major loop Fault", # 12 + "Short Circuit warning", # 13 + "Battery Imbalance", # 14 + "Current Sensor Fault", # 15 + "??", # 16 + "??", # 17 + "??", # 18 + "??", # 19 + "??", # 20 + "??", # 21 + "??", # 22 + "" # 23 (Wert, wenn keine Meldung) +] + +# Warnungen fuer BMS (16 Bit) +byd_log_bms_warnings = [ + "Battery Over Voltage", # 0 + "Battery Under Voltage", # 1 + "Cells OverVoltage", # 2 * + "Cells UnderVoltage", # 3 * + "Cells Imbalance", # 4 * + "Charging High Temperature(Cells)", # 5 + "Charging Low Temperature(Cells)", # 6 + "DisCharging High Temperature(Cells)", # 7 + "DisCharging Low Temperature(Cells)", # 8 + "Charging OverCurrent(Cells)", # 9 + "DisCharging OverCurrent(Cells)", # 10 + "Charging OverCurrent(Hardware)", # 11 + "Short Circuit", # 12 + "Inversly Connection", # 13 + "Interlock switch Abnormal", # 14 + "AirSwitch Abnormal" # 15 ] -byd_invs_lvs_max = 19 -byd_invs_lvs = [ - "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 +# Fehler fuer BMS (16 Bit) +byd_log_bms_failures = [ + "Cells Voltage Sensor Failure", # 0 * + "Temperature Sensor Failure", # 1 + "BIC Communication Failure", # 2 + "Pack Voltage Sensor Failure", # 3 + "Current Sensor Failure", # 4 + "Charging Mos Failure", # 5 + "DisCharging Mos Failure", # 6 + "PreCharging Mos Failure", # 7 + "Main Relay Failure", # 8 + "PreCharging Failed", # 9 + "Heating Device Failure", # 10 + "Radiator Failure", # 11 + "BIC Balance Failure", # 12 + "Cells Failure", # 13 + "PCB Temperature Sensor Failure", # 14 + "Functional Safety Failure" # 15 ] +# Switch Status fuer BMS (8 Bit) +byd_log_bms_switch_status_on = [ + "Charge Mos_Switch is on", # 0 + "DisCharge Mos_Switch is on", # 1 + "PreCharge Mos_Switch is on", # 2 + "Relay is on", # 3 * + "Air Switch is on", # 4 * + "PreCharge_2 Mos_Switch is on", # 5 + "??", # 6 + "??" # 7 +] + +byd_log_bms_switch_status_off = [ + "Charge Mos_Switch is off", # 0 + "DisCharge Mos_Switch is off", # 1 + "PreCharge Mos_Switch is off", # 2 + "Relay is off", # 3 * -> nur diesen Wert in einem Log gesehen + "Air Switch is off", # 4 * + "PreCharge_2 Mos_Switch is off", # 5 + "??", # 6 + "??" # 7 +] + +# Power-Off fuer BMS (Enum 1 Byte) +byd_log_bms_poweroff = [ + "" # 0 + "Press BMS LED button to Switch off", # 1 + "BMU requires to switch off", # 2 * + "BMU Power off And communication between BMU and BMS failed", # 3 * + "Power off while communication failed(after 30 minutes)", # 4 + "Premium LV BMU requires to Power off", # 5 + "Press BMS LED to Power off", # 6 + "Power off due to communication failed with BMU", # 7 + "BMS off due to battery UnderVoltage", # 8 + "??", # 9 +] + +# ----------------------------------------------------------------------- +# Plugin-Code +# ----------------------------------------------------------------------- class byd_bat(SmartPlugin): @@ -212,7 +520,8 @@ class properties and methods (class variables and class functions) are already available! """ - PLUGIN_VERSION = '0.0.7' + PLUGIN_VERSION = '0.0.8' + ALLOW_MULTIINSTANCE = False def __init__(self,sh): """ @@ -229,7 +538,7 @@ def __init__(self,sh): # Call init code of parent class (SmartPlugin) super().__init__() - + # get the parameters for the plugin (as defined in metadata plugin.yaml): if self.get_parameter_value('ip') != '': @@ -256,10 +565,30 @@ def __init__(self,sh): self.diag_cycle = byd_sample_diag if self.diag_cycle < byd_sample_basics: self.diag_cycle = byd_sample_basics + + if self.get_parameter_value('log_data') != '': + self.log_data = self.get_parameter_value('log_data') + if self.log_data is None: + self.log_data = False + else: + self.log_info("log_data not defined => log_data=false") + self.log_data = False + if self.get_parameter_value('log_age') != '': + self.log_age = self.get_parameter_value('log_age') + if self.log_age is None: + self.log_age = 365 + else: + self.log_info("no log_age defined => use default '" + str(365) + "s'") + self.log_age = 365 + if self.log_age < 0: + self.log_age = 0 + self.log_debug("BYD ip = " + self.ip) self.log_debug("BYD path = " + self.bpath) - self.log_debug("BYD diagnostic cycle = " + str(self.diag_cycle) + "s") + self.log_debug("BYD diagnostic cycle = " + f"{self.diag_cycle:.0f}" + "s") + self.log_debug("BYD log data = " + str(self.log_data)) + self.log_debug("BYD log age = " + str(self.log_age) + " days") # cycle time in seconds, only needed, if hardware/interface needs to be # polled for value changes by adding a scheduler entry in the run method of this plugin @@ -267,13 +596,24 @@ def __init__(self,sh): self._cycle = byd_sample_basics self.last_diag_secs = 9999 # erzwingt beim ersten Aufruf das Abfragen der Detaildaten + self.last_log_secs = 9999 # erzwingt beim ersten Aufruf das Abfragen der Log-Daten self.byd_root_found = False + self.byd_towers_max = byd_towers_max + self.byd_module_vmin = byd_module_vmin + self.byd_module_vmax = byd_module_vmax + self.byd_module_vava = byd_module_vava + self.byd_module_vdif = byd_module_vdif + self.byd_diag_soc = [] + self.byd_diag_soh = [] + self.byd_diag_state = [] + self.byd_diag_state_str = [] self.byd_diag_bat_voltag = [] self.byd_diag_v_out = [] self.byd_diag_current = [] + self.byd_diag_volt_diff = [] self.byd_diag_volt_max = [] self.byd_diag_volt_max_c = [] self.byd_diag_volt_min = [] @@ -282,14 +622,27 @@ def __init__(self,sh): self.byd_diag_temp_max_c = [] self.byd_diag_temp_min = [] self.byd_diag_temp_min_c = [] + self.byd_diag_charge_total = [] + self.byd_diag_discharge_total = [] + self.byd_diag_balance_active = [] + self.byd_diag_balance_number = [] + self.byd_diag_bms_log = [] # Liste der Log-Eintraege pro Turm + self.byd_diag_bms_log_html = [] # HTML-Tabelle der Log-Eintrage pro Turm + self.byd_diag_module = [] # Liste der Daten zu den Modulen pro Turm self.byd_volt_cell = [] self.byd_balance_cell = [] self.byd_temp_cell = [] + self.byd_bmu_log = [] + self.byd_bmu_log_html = "" for x in range(0,byd_towers_max + 1): # 0..3 self.byd_diag_soc.append(0) + self.byd_diag_soh.append(0) + self.byd_diag_state.append(0) + self.byd_diag_state_str.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_diff.append(0) self.byd_diag_volt_max.append(0) self.byd_diag_volt_max_c.append(0) self.byd_diag_volt_min.append(0) @@ -298,6 +651,13 @@ def __init__(self,sh): self.byd_diag_temp_max_c.append(0) self.byd_diag_temp_min.append(0) self.byd_diag_temp_min_c.append(0) + self.byd_diag_charge_total.append(0) + self.byd_diag_discharge_total.append(0) + self.byd_diag_balance_active.append(0) + self.byd_diag_balance_number.append(0) + self.byd_diag_bms_log.append([]) + self.byd_diag_bms_log_html.append("") + self.byd_diag_module.append([]) a = [] for xx in range(0,byd_cells_max + 1): # 0..160 a.append(0) @@ -315,8 +675,13 @@ def __init__(self,sh): self.last_diagdata = self.now_str() self.plt_file_del() + + # Log-Verzeichnis erstellen + if self.log_data == True: + self.log_dir = self.create_logdirectory(self.get_sh().get_basedir(),byd_log_directory) + self.log_debug("log_dir=" + self.log_dir) -# self.simulate_data() # for internal tests only +# self.simulate_data() # for internal tests only [TEST] # Initialization code goes here @@ -357,15 +722,17 @@ def parse_item(self, item): with the item, caller, source and dest as arguments and in case of the knx plugin the value can be sent to the knx with a knx write function within the knx plugin. """ - # todo - # if interesting item for sending values: - # self._itemlist.append(item) - # return self.update_item + if self.get_iattr_value(item.conf,'byd_root'): self.byd_root = item self.byd_root_found = True self.log_debug("BYD root = " + "{0}".format(self.byd_root)) + if self.has_iattr(item.conf,'byd_para'): + self._itemlist.append(item) + return self.update_item + + def parse_logic(self, logic): """ Default plugin parse_logic method @@ -377,11 +744,21 @@ def parse_logic(self, logic): def update_item(self, item, caller=None, source=None, dest=None): # Wird aufgerufen, wenn ein Item mit dem Attribut 'mmgarden' geaendert wird + self.log_debug("update_auto_item path=" + item.property.path + " name=" + item.property.name + " v=" + str(item())) + if self.alive and caller != self.get_shortname(): - # code to execute if the plugin is not stopped - # and only, if the item has not been changed by this plugin: + # code to execute if the plugin is not stopped + # and only, if the item has not been changed by this plugin: - return + s1 = item.property.path + if s1.find("enable_connection") != -1: + self.byd_root.info.connection(item()) + if item() == True: + self.log_info("communication disabled => enabled !") + else: + self.log_info("communication enabled => disabled !") + + return def poll_device(self): # Wird alle 'self._cycle' aufgerufen @@ -391,8 +768,7 @@ def poll_device(self): return if self.byd_root.enable_connection() is False: - self.byd_root.info.connection(False) - self.log_info("communication disabled !") + self.log_debug("communication disabled !") return self.log_debug("BYD Start *********************") @@ -408,43 +784,34 @@ def poll_device(self): return # 0.Befehl senden - client.send(bytes.fromhex(MESSAGE_0)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: + res,data = self.send_msg(client,MESSAGE_0,byd_timeout_1s) + if res != byd_ok: self.log_info("client.recv 0 failed") self.byd_root.info.connection(False) client.close() return - self.decode_0(data) + if self.decode_0(data) == byd_error: + return # 1.Befehl senden - client.send(bytes.fromhex(MESSAGE_1)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: + res,data = self.send_msg(client,MESSAGE_1,byd_timeout_1s) + if res != byd_ok: self.log_info("client.recv 1 failed") self.byd_root.info.connection(False) client.close() return - self.decode_1(data) + if self.decode_1(data) == byd_error: + return # 2.Befehl senden - client.send(bytes.fromhex(MESSAGE_2)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 2 failed") + res,data = self.send_msg(client,MESSAGE_2,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 1 failed") self.byd_root.info.connection(False) client.close() return - self.decode_2(data) + if self.decode_2(data) == byd_error: + return if self.byd_cells_n == 0: # Batterietyp wird nicht unterstuetzt ! self.log_info("battery type " + self.byd_batt_str + " not supported !") @@ -457,240 +824,225 @@ def poll_device(self): # Pruefe, ob die Diagnosedaten abgefragt werden sollen self.last_diag_secs = self.last_diag_secs + self._cycle - if self.last_diag_secs < self.diag_cycle: - self.byd_root.info.connection(True) - self.log_debug("BYD Basic Done ****************") - client.close() - return - - self.last_diag_secs = 0 - - # Durchlaufe alle Tuerme - for x in range(1,self.byd_bms_qty + 1): - self.log_debug("Turm " + str(x)) + if self.last_diag_secs >= self.diag_cycle: + self.last_diag_secs = 0 - # 3.Befehl senden - if x == 1: - client.send(bytes.fromhex(MESSAGE_3_1)) - elif x == 2: - client.send(bytes.fromhex(MESSAGE_3_2)) - elif x == 3: - client.send(bytes.fromhex(MESSAGE_3_3)) - client.settimeout(byd_timeout_2s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 3 failed") - self.byd_root.info.connection(False) - client.close() - return - self.decode_nop(data,x) - time.sleep(2) - - # 4.Befehl senden - client.send(bytes.fromhex(MESSAGE_4)) - client.settimeout(byd_timeout_8s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 4 failed") - self.byd_root.info.connection(False) - client.close() - return - self.decode_nop(data,x) - - # 5.Befehl senden - client.send(bytes.fromhex(MESSAGE_5)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 5 failed") - self.byd_root.info.connection(False) - client.close() - return - self.decode_5(data,x) - - # 6.Befehl senden - client.send(bytes.fromhex(MESSAGE_6)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 6 failed") - self.byd_root.info.connection(False) - client.close() - return - self.decode_6(data,x) - - # 7.Befehl senden - client.send(bytes.fromhex(MESSAGE_7)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 7 failed") - self.byd_root.info.connection(False) - client.close() - return - self.decode_7(data,x) - - # 8.Befehl senden - client.send(bytes.fromhex(MESSAGE_8)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 8 failed") - self.byd_root.info.connection(False) - client.close() - return - self.decode_8(data,x) - - if self.byd_cells_n > 128: - # Switch to second turn for the last module - 9.Befehl senden - client.send(bytes.fromhex(MESSAGE_9)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 9 failed") + # Durchlaufe alle Tuerme + for x in range(1,self.byd_bms_qty + 1): # 1 ... self.byd_bms_qty + self.log_debug("Diagnose Turm " + str(x)) + + # 3.Befehl senden + if x == 1: + m = MESSAGE_3_1 + elif x == 2: + m = MESSAGE_3_2 + elif x == 3: + m = MESSAGE_3_3 + res,data = self.send_msg(client,m,byd_timeout_2s) + if res != byd_ok: + self.log_info("client.recv 3 failed") self.byd_root.info.connection(False) client.close() return - self.decode_nop(data,x) + if self.decode_nop(data,x,MESSAGE_3_L) == byd_error: + return time.sleep(2) - - # 10.Befehl senden (wie Befehl 3) - if x == 1: - client.send(bytes.fromhex(MESSAGE_10_1)) - elif x == 2: - client.send(bytes.fromhex(MESSAGE_10_2)) - elif x == 3: - client.send(bytes.fromhex(MESSAGE_10_3)) - client.settimeout(byd_timeout_2s) - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 10 failed") + # 4.Befehl senden + res,data = self.send_msg(client,MESSAGE_4,byd_timeout_10s) + if res != byd_ok: + self.log_info("client.recv 4 failed") self.byd_root.info.connection(False) client.close() return - self.decode_nop(data,x) - time.sleep(2) - - # 11.Befehl senden (wie Befehl 4) - client.send(bytes.fromhex(MESSAGE_11)) - client.settimeout(byd_timeout_8s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 11 failed") + if self.decode_nop(data,x,MESSAGE_4_L) == byd_error: + return + + # 5.Befehl senden + res,data = self.send_msg(client,MESSAGE_5,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 5 failed") self.byd_root.info.connection(False) client.close() return - self.decode_nop(data,x) + if self.decode_5(data,x) == byd_error: + return - # 12.Befehl senden (wie Befehl 5) - client.send(bytes.fromhex(MESSAGE_12)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 12 failed") + # 6.Befehl senden + res,data = self.send_msg(client,MESSAGE_6,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 6 failed") self.byd_root.info.connection(False) client.close() return - self.decode_12(data,x) + if self.decode_6(data,x) == byd_error: + return - # 13.Befehl senden (wie Befehl 6) - client.send(bytes.fromhex(MESSAGE_13)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 13 failed") + # 7.Befehl senden + res,data = self.send_msg(client,MESSAGE_7,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 7 failed") self.byd_root.info.connection(False) client.close() return - self.decode_13(data,x) + if self.decode_7(data,x) == byd_error: + return - # 14.Befehl senden (wie Befehl 7) - client.send(bytes.fromhex(MESSAGE_14)) - client.settimeout(byd_timeout_1s) - - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 14 failed") + # 8.Befehl senden + res,data = self.send_msg(client,MESSAGE_8,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 8 failed") self.byd_root.info.connection(False) client.close() return - self.decode_14(data,x) + if self.decode_8(data,x) == byd_error: + return - # 15.Befehl senden (wie Befehl 8) - client.send(bytes.fromhex(MESSAGE_15)) - client.settimeout(byd_timeout_1s) + if self.byd_cells_n > 128: + # Switch to second turn for the last module - 9.Befehl senden + res,data = self.send_msg(client,MESSAGE_9,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 9 failed") + self.byd_root.info.connection(False) + client.close() + return + self.decode_nop(data,x) + time.sleep(2) + + # 10.Befehl senden (wie Befehl 3) + if x == 1: + m = MESSAGE_10_1 + elif x == 2: + m = MESSAGE_10_2 + elif x == 3: + m = MESSAGE_10_3 + res,data = self.send_msg(client,m,byd_timeout_2s) + if res != byd_ok: + self.log_info("client.recv 10 failed") + self.byd_root.info.connection(False) + client.close() + return + if self.decode_nop(data,x,MESSAGE_10_L) == byd_error: + return + time.sleep(2) + + # 11.Befehl senden (wie Befehl 4) + res,data = self.send_msg(client,MESSAGE_11,byd_timeout_10s) + if res != byd_ok: + self.log_info("client.recv 11 failed") + self.byd_root.info.connection(False) + client.close() + return + if self.decode_nop(data,x,MESSAGE_11_L) == byd_error: + return + + # 12.Befehl senden (wie Befehl 5) + res,data = self.send_msg(client,MESSAGE_12,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 12 failed") + self.byd_root.info.connection(False) + client.close() + return + if self.decode_12(data,x) == byd_error: + return + + # 13.Befehl senden (wie Befehl 6) + res,data = self.send_msg(client,MESSAGE_13,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 13 failed") + self.byd_root.info.connection(False) + client.close() + return + if self.decode_13(data,x) == byd_error: + return + + # 14.Befehl senden (wie Befehl 7) + res,data = self.send_msg(client,MESSAGE_14,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 14 failed") + self.byd_root.info.connection(False) + client.close() + return + if self.decode_14(data,x) == byd_error: + return + + # 15.Befehl senden (wie Befehl 8) + res,data = self.send_msg(client,MESSAGE_15,byd_timeout_1s) + if res != byd_ok: + self.log_info("client.recv 15 failed") + self.byd_root.info.connection(False) + client.close() + return + if self.decode_15(data,x) == byd_error: + return + + self.module_update(x) # Bestimme gewisse Werte zu jedem Modul im Turm + + self.diagdata_save(self.byd_root) + self.byd_root.info.connection(True) + + self.log_debug("BYD Diag Done +++++++++++++++++") - try: - data = client.recv(BUFFER_SIZE) - except: - self.log_info("client.recv 15 failed") + # Pruefe, ob die Logdaten ausgelesen werden sollen + if self.log_data == True: + self.last_log_secs = self.last_log_secs + self._cycle + if self.last_log_secs >= byd_sample_log: + self.last_log_secs = 0 + if self.read_log_data(client) == byd_error: + # Etwas ist schief gelaufen + self.log_info("read_log_data failed") self.byd_root.info.connection(False) client.close() return - self.decode_15(data,x) - - self.diagdata_save(self.byd_root) - self.byd_root.info.connection(True) - - self.log_debug("BYD Diag Done +++++++++++++++++") + client.close() return + +# ----------------------------------------------------------------------- +# Decodieren der Daten vom BYD-System (ohne Log-Daten) +# ----------------------------------------------------------------------- def decode_0(self,data): # Decodieren der Nachricht auf Befehl 'MESSAGE_0'. self.log_debug("decode_0: " + data.hex()) + if len(data) != MESSAGE_0_L: + self.log_info("MESSAGE_0 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_0_L) + ")") + return byd_error + # Serienummer self.byd_serial = "" for x in range(3,22): # 3..21 - self.byd_serial = self.byd_serial + chr(data[x]) + self.byd_serial = self.byd_serial + chr(data[x]) # Byte 3 .. 21 + # self.byd_serial = "xxxxxxxxxxxxxxxxxxx" # fuer Screenshots # Firmware-Versionen - self.byd_bmu_a = "V" + str(data[27]) + "." + str(data[28]) - self.byd_bmu_b = "V" + str(data[29]) + "." + str(data[30]) - if data[33] == 0: + self.byd_bmu_a = "V" + str(data[27]) + "." + str(data[28]) # Byte 27+28 (Register 12) + self.byd_bmu_b = "V" + str(data[29]) + "." + str(data[30]) # Byte 29+30 (Register 13) + self.byd_bms = "V" + str(data[31]) + "." + str(data[32]) + "-" + chr(data[34] + 65) # Byte 31+32+34 + if data[33] == 0: # Byte 33 self.byd_bmu = self.byd_bmu_a + "-A" else: self.byd_bmu = self.byd_bmu_b + "-B" - self.byd_bms = "V" + str(data[31]) + "." + str(data[32]) + "-" + chr(data[34] + 65) # Anzahl Tuerme und Anzahl Module pro Turm - self.byd_bms_qty = data[36] // 0x10 + self.byd_bms_qty = data[36] // 0x10 # Byte 36 Bit 4-7 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_modules = data[36] % 0x10 # Byte 36 Bit 0-3 (Anzahl Module) self.byd_batt_type_snr = data[5] # Application - if data[38] == 1: + if data[38] == 0: # Byte 38 + self.byd_application = "OffGrid" + elif data[38] == 1: self.byd_application = "OnGrid" + elif data[38] == 2: + self.byd_application = "Backup" else: - self.byd_application = "OffGrid" + self.byd_application = "unknown" self.log_debug("Serial : " + self.byd_serial) self.log_debug("BMU A : " + self.byd_bmu_a) @@ -700,22 +1052,42 @@ def decode_0(self,data): self.log_debug("BMS QTY : " + str(self.byd_bms_qty)) self.log_debug("Modules : " + str(self.byd_modules)) self.log_debug("Application : " + self.byd_application) - return + + return byd_ok def decode_1(self,data): # Decodieren der Nachricht auf Befehl 'MESSAGE_1'. self.log_debug("decode_1: " + data.hex()) - self.byd_soc = self.buf2int16SI(data,3) - self.byd_soh = self.buf2int16SI(data,9) + if len(data) != MESSAGE_1_L: + self.log_info("MESSAGE_1 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_1_L) + ")") + return byd_error + + self.byd_soc = self.buf2int16SI(data,3) # Byte 3+4 (Register 0) + self.byd_volt_max = self.buf2int16SI(data,5) * 1.0 / 100.0 # Byte 5+6 (Register 1) + self.byd_volt_min = self.buf2int16SI(data,7) * 1.0 / 100.0 # Byte 7+8 (Register 2) + self.byd_soh = self.buf2int16SI(data,9) # Byte 9+10 (Register 3) + self.byd_current = self.buf2int16SI(data,11) * 1.0 / 10.0 # Byte 11+12 (Register 4) + self.byd_volt_bat = self.buf2int16US(data,13) * 1.0 / 100.0 # Byte 13+14 (Register 5) + self.byd_temp_max = self.buf2int16SI(data,15) # Byte 15+16 (Register 6) + self.byd_temp_min = self.buf2int16SI(data,17) # Byte 17+18 (Register 7) + self.byd_temp_bat = self.buf2int16SI(data,19) # Byte 19+20 (Register 8) + + self.byd_error_nr = self.buf2int16SI(data,29) # Byte 29+30 (Register 13) + self.byd_error_str = "" + for x in range(0,16): + if (((1 << x) & self.byd_error_nr) != 0): + if len(self.byd_error_str) > 0: + self.byd_error_str = self.byd_error_str + ";" + self.byd_error_str = self.byd_error_str + byd_errors[x] + if len(self.byd_error_str) == 0: + self.byd_error_str = "no error" + + self.byd_param_t = str(data[31]) + "." + str(data[32]) # Byte 31+32 (Register 14) - self.byd_volt_bat = self.buf2int16US(data,13) * 1.0 / 100.0 - self.byd_volt_out = self.buf2int16US(data,35) * 1.0 / 100.0 - 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_out = self.buf2int16US(data,35) * 1.0 / 100.0 # Byte 35+36 (Register 16) self.byd_volt_diff = self.byd_volt_max - self.byd_volt_min - 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 @@ -724,43 +1096,39 @@ def decode_1(self,data): self.byd_power_discharge = 0 self.byd_power_charge = -self.byd_power - self.byd_temp_bat = self.buf2int16SI(data,19) - self.byd_temp_max = self.buf2int16SI(data,15) - self.byd_temp_min = self.buf2int16SI(data,17) - - self.byd_error_nr = self.buf2int16SI(data,29) - self.byd_error_str = "" - for x in range(0,16): - if (((1 << x) & self.byd_error_nr) != 0): - if len(self.byd_error_str) > 0: - self.byd_error_str = self.byd_error_str + ";" - self.byd_error_str = self.byd_error_str + byd_errors[x] - if len(self.byd_error_str) == 0: - self.byd_error_str = "no error" - - self.byd_param_t = str(data[31]) + "." + str(data[32]) - - self.log_debug("SOC : " + str(self.byd_soc)) - self.log_debug("SOH : " + str(self.byd_soh)) - self.log_debug("Volt Battery : " + str(self.byd_volt_bat)) - self.log_debug("Volt Out : " + str(self.byd_volt_out)) - self.log_debug("Volt max : " + str(self.byd_volt_max)) - self.log_debug("Volt min : " + str(self.byd_volt_min)) - self.log_debug("Volt diff : " + str(self.byd_volt_diff)) - self.log_debug("Current : " + str(self.byd_current)) - self.log_debug("Power : " + str(self.byd_power)) - self.log_debug("Temp Battery : " + str(self.byd_temp_bat)) - self.log_debug("Temp max : " + str(self.byd_temp_max)) - self.log_debug("Temp min : " + str(self.byd_temp_min)) - self.log_debug("Error : " + str(self.byd_error_nr) + " " + self.byd_error_str) - self.log_debug("ParamT : " + self.byd_param_t) - return + self.byd_charge_total = self.buf2int32US(data,37) / 10.0 # Byte 37-40 (Register 17+18) (in 100Wh in data) + self.byd_discharge_total = self.buf2int32US(data,41) / 10.0 # Byte 41-44 (Register 19+20) (in 100Wh in data) + self.byd_eta = (self.byd_discharge_total / self.byd_charge_total) * 100.0 + + self.log_debug("SOC : " + f"{self.byd_soc:.1f}") + self.log_debug("SOH : " + f"{self.byd_soh:.1f}") + self.log_debug("Volt Battery : " + f"{self.byd_volt_bat:.1f}") + self.log_debug("Volt Out : " + f"{self.byd_volt_out:.1f}") + self.log_debug("Volt max : " + f"{self.byd_volt_max:.1f}") + self.log_debug("Volt min : " + f"{self.byd_volt_min:.1f}") + self.log_debug("Volt diff : " + f"{self.byd_volt_diff:.1f}") + self.log_debug("Current : " + f"{self.byd_current:.1f}") + self.log_debug("Power : " + f"{self.byd_power:.1f}") + self.log_debug("Temp Battery : " + f"{self.byd_temp_bat:.1f}") + self.log_debug("Temp max : " + f"{self.byd_temp_max:.1f}") + self.log_debug("Temp min : " + f"{self.byd_temp_min:.1f}") + self.log_debug("Error : " + f"{self.byd_error_nr:.0f}" + " " + self.byd_error_str) + self.log_debug("ParamT : " + self.byd_param_t) + self.log_debug("Charge total : " + f"{self.byd_charge_total:.1f}") + self.log_debug("Discharge total : " + f"{self.byd_discharge_total:.1f}") + self.log_debug("ETA : " + f"{self.byd_eta:.1f}") + + return byd_ok def decode_2(self,data): # Decodieren der Nachricht auf Befehl 'MESSAGE_2'. self.log_debug("decode_2: " + data.hex()) + if len(data) != MESSAGE_2_L: + self.log_info("MESSAGE_2 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_2_L) + ")") + return byd_error + self.byd_batt_type = data[5] if self.byd_batt_type == 0: # HVL -> Lithium Iron Phosphate (LFP), 3-8 Module (12kWh-32kWh), unknown specification, so 0 cells and 0 temps @@ -805,33 +1173,29 @@ def decode_2(self,data): self.byd_capacity_total = self.byd_bms_qty * self.byd_modules * self.byd_capacity_module self.byd_inv_type = data[3] - if self.byd_batt_str == "LVS": - 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: - 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.byd_inv_str = self.get_inverter_name(self.byd_batt_str,self.byd_inv_type) 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) + ")") - self.log_debug("Cells n : " + str(self.byd_cells_n)) - self.log_debug("Temps n : " + str(self.byd_temps_n)) + self.log_debug("Cells n : " + f"{self.byd_cells_n:.0f}") + self.log_debug("Temps n : " + f"{self.byd_temps_n:.0f}") if self.byd_cells_n > byd_cells_max: self.byd_cells_n = byd_cells_max if self.byd_temps_n > byd_temps_max: self.byd_temps_n = byd_temps_max - return + + return byd_ok def decode_5(self,data,x): # Decodieren der Nachricht auf Befehl 'MESSAGE_5'. self.log_debug("decode_5 (" + str(x) + ") : " + data.hex()) + if len(data) != MESSAGE_5_L: + self.log_info("MESSAGE_5 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_5_L) + ")") + return byd_error + self.byd_diag_volt_max[x] = self.buf2int16SI(data,5) / 1000.0 # Byte 5+6 (Index 1) self.byd_diag_volt_min[x] = self.buf2int16SI(data,7) / 1000.0 # Byte 7+8 (Index 2) self.byd_diag_volt_max_c[x] = data[9] # Byte 9 (Index 3) @@ -841,59 +1205,87 @@ def decode_5(self,data,x): self.byd_diag_temp_max_c[x] = data[15] # Byte 15 (Index 6) self.byd_diag_temp_min_c[x] = data[16] # Byte 16 - # Balancing-Flags. Es folgen 8x 16-bit-Worte = 16 Byte => 0..127 Bits - i = 0 - for xx in range(17,33): # 17..32 (16 Byte) - a = data[xx] - self.log_debug("Balancing i=" + str(i) + " d=" + str(a)) + self.byd_diag_volt_diff[x] = (self.byd_diag_volt_max[x] - self.byd_diag_volt_min[x]) * 1000.0 + + # Balancing-Flags. Es folgen 8x 16-bit-Worte (MSB,LSB!) = 16 Byte => 0..127 Bits + i = 0 # Zaehlt die Bits + nnn = 0 # Zaehlt die Anzahl der Zellen mit Balancing-Modus + for xx in range(17,33): # 17..32 (16 Byte) Index 7..14 + if (xx % 2) == 1: + a = data[xx+1] # LSB, Bit 0-7 + else: + a = data[xx-1] # MSB, Bit 8-15 +# self.log_debug("Balancing i=" + f"{i:.0f}" + " d=" + f"{a:.0f}") for yy in range(0,8): # 0..7 if (int(a) & 1) == 1: self.byd_balance_cell[x][i] = 1 + nnn = nnn + 1 else: self.byd_balance_cell[x][i] = 0 a = a / 2 i = i + 1 + self.byd_diag_balance_number[x] = nnn + + self.byd_diag_charge_total[x] = self.buf2int32US(data,33) / 1000.0 # Byte 33-36 (Register 15+16) (in 1Wh in data) + self.byd_diag_discharge_total[x] = self.buf2int32US(data,37) / 1000.0 # Byte 37-41 (Register 17+18) (in 1Wh in data) - 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_soc[x] = self.buf2int16SI(data,53) * 1.0 / 10.0 # Byte 53+54 - self.byd_diag_current[x] = self.buf2int16SI(data,57) * 1.0 / 10.0 # Byte 57+58 + self.byd_diag_bat_voltag[x] = self.buf2int16SI(data,45) * 1.0 / 10.0 # Byte 45+46 (Index 21) + + self.byd_diag_v_out[x] = self.buf2int16SI(data,51) * 1.0 / 10.0 # Byte 51+52 (Index 24) + self.byd_diag_soc[x] = self.buf2int16SI(data,53) * 1.0 / 10.0 # Byte 53+54 (Index 25) + self.byd_diag_soh[x] = self.buf2int16SI(data,55) * 1.0 # Byte 55+56 (Index 26) + self.byd_diag_current[x] = self.buf2int16SI(data,57) * 1.0 / 10.0 # Byte 57+58 (Index 27) + self.byd_diag_state[x] = data[59] * 0x100 + data[60] # Byte 59+60 (Index 28) # starting with byte 101, ending with 131, Cell voltage 0-15 for xx in range(0,16): # 0..15 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("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 : " + str(self.byd_diag_temp_max[x]) + " c=" + str(self.byd_diag_temp_max_c[x])) - self.log_debug("Temp min : " + str(self.byd_diag_temp_min[x]) + " c=" + str(self.byd_diag_temp_min_c[x])) + self.log_debug("SOC : " + f"{self.byd_diag_soc[x]:.1f}") + self.log_debug("SOH : " + f"{self.byd_diag_soh[x]:.1f}") + self.log_debug("Bat Voltag : " + f"{self.byd_diag_bat_voltag[x]:.2f}") + self.log_debug("V-Out : " + f"{self.byd_diag_v_out[x]:.2f}") + self.log_debug("Current : " + f"{self.byd_diag_current[x]:.2f}") + self.log_debug("Volt max : " + f"{self.byd_diag_volt_max[x]:.3f}" + " c=" + f"{self.byd_diag_volt_max_c[x]:.0f}") + self.log_debug("Volt min : " + f"{self.byd_diag_volt_min[x]:.3f}" + " c=" + f"{self.byd_diag_volt_min_c[x]:.0f}") + self.log_debug("Volt diff : " + f"{self.byd_diag_volt_diff[x]:.1f}") + self.log_debug("Temp max : " + f"{self.byd_diag_temp_max[x]:.1f}" + " c=" + f"{self.byd_diag_temp_max_c[x]:.0f}") + self.log_debug("Temp min : " + f"{self.byd_diag_temp_min[x]:.1f}" + " c=" + f"{self.byd_diag_temp_min_c[x]:.0f}") + self.log_debug("Charge total : " + f"{self.byd_diag_charge_total[x]:.3f}") + self.log_debug("Discharge total : " + f"{self.byd_diag_discharge_total[x]:.3f}") + self.log_debug("Status : " + "0x" + f"{self.byd_diag_state[x]:04x}") + self.log_debug("Balancing : " + f"{nnn:.0f}") # for xx in range(0,16): # self.log_debug("Turm " + str(x) + " Volt " + str(xx) + " : " + str(self.byd_volt_cell[x][xx])) - return + return byd_ok def decode_6(self,data,x): # Decodieren der Nachricht auf Befehl 'MESSAGE_6'. self.log_debug("decode_6 (" + str(x) + ") : " + data.hex()) + if len(data) != MESSAGE_6_L: + self.log_info("MESSAGE_6 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_6_L) + ")") + return byd_error + for xx in range(0,64): # 0..63, Cell voltage 16-79 self.byd_volt_cell[x][16 + xx] = self.buf2int16SI(data,5 + (xx * 2)) / 1000.0 # for xx in range(0,64): # self.log_debug("Turm " + str(x) + " Volt " + str(16 + xx) + " : " + str(self.byd_volt_cell[x][16 + xx])) - return + return byd_ok def decode_7(self,data,x): # Decodieren der Nachricht auf Befehl 'MESSAGE_7'. self.log_debug("decode_7 (" + str(x) + ") : " + data.hex()) + if len(data) != MESSAGE_7_L: + self.log_info("MESSAGE_7 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_7_L) + ")") + return byd_error + # starting with byte 5, ending 101, voltage for cell 81 to 128 for xx in range(0,48): # 0..47, Cell voltage 80-127 self.byd_volt_cell[x][80 + xx] = self.buf2int16SI(data,5 + (xx * 2)) / 1000.0 @@ -907,51 +1299,69 @@ def decode_7(self,data,x): # for xx in range(0,30): # self.log_debug("Turm " + str(x) + " Temp " + str(xx) + " : " + str(self.byd_temp_cell[x][xx])) - return + return byd_ok def decode_8(self,data,x): # Decodieren der Nachricht auf Befehl 'MESSAGE_8'. self.log_debug("decode_8 (" + str(x) + ") : " + data.hex()) + if len(data) != MESSAGE_8_L: + self.log_info("MESSAGE_8 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_8_L) + ")") + return byd_error + for xx in range(0,34): # 0..33 self.byd_temp_cell[x][30 + xx] = data[5 + xx] # for xx in range(0,34): # self.log_debug("Turm " + str(x) + " Temp " + str(30 + xx) + " : " + str(self.byd_temp_cell[x][30 + xx])) - return + return byd_ok def decode_12(self,data,x): # Decodieren der Nachricht auf Befehl 'MESSAGE_12' fuer den Turm 'x'. self.log_debug("decode_12 (" + str(x) + ") : " + data.hex()) - # Balancing-Flags. Es folgen 8x 16-bit-Worte = 16 Byte => 0..127 Bits + if len(data) != MESSAGE_12_L: + self.log_info("MESSAGE_12 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_12_L) + ")") + return byd_error + + # Balancing-Flags. Es folgen 8x 16-bit-Worte (MSB,LSB!) = 16 Byte => 0..127 Bits i = 127 + nnn = self.byd_diag_balance_number[x] for xx in range(17,33): # 17..32 - a = data[xx] - self.log_debug("Balancing i=" + str(i) + " d=" + str(a)) + if (xx % 2) == 1: + a = data[xx+1] # LSB, Bit 0-7 + else: + a = data[xx-1] # MSB, Bit 8-15 +# self.log_debug("Balancing i=" + str(i) + " d=" + str(a)) for yy in range(0,8): # 0..7 if i <= byd_cells_max: if (int(a) & 1) == 1: self.byd_balance_cell[x][i] = 1 + nnn = nnn + 1 else: self.byd_balance_cell[x][i] = 0 a = a / 2 i = i + 1 + self.byd_diag_balance_number[x] = nnn # starting with byte 101, ending with 116, Cell voltage 129-144 for xx in range(0,16): # 0..15, Cell voltage 128-143 self.byd_volt_cell[x][128 + xx] = self.buf2int16SI(data,101 + (xx * 2)) / 1000.0 - return + return byd_ok def decode_13(self,data,x): # Decodieren der Nachricht auf Befehl 'MESSAGE_13'. self.log_debug("decode_13 (" + str(x) + ") : " + data.hex()) + if len(data) != MESSAGE_13_L: + self.log_info("MESSAGE_13 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_13_L) + ")") + return byd_error + # The first round measured up to 128 cells, request[12] then get another 16 # With 5 HVS Modules (max for HVS), only 16 cells are remaining @@ -959,26 +1369,906 @@ def decode_13(self,data,x): for xx in range(0,16): # 0..15, Cell voltage 144-160 self.byd_volt_cell[x][144 + xx] = self.buf2int16SI(data,5 + (xx * 2)) / 1000.0 - return + return byd_ok def decode_14(self,data,x): # Decodieren der Nachricht auf Befehl 'MESSAGE_14'. self.log_debug("decode_14 (" + str(x) + ") : " + data.hex()) - return + if len(data) != MESSAGE_14_L: + self.log_info("MESSAGE_14 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_14_L) + ")") + return byd_error + + return byd_ok def decode_15(self,data,x): # Decodieren der Nachricht auf Befehl 'MESSAGE_15'. self.log_debug("decode_15 (" + str(x) + ") : " + data.hex()) + if len(data) != MESSAGE_15_L: + self.log_info("MESSAGE_15 answer length wrong ! (" + str(len(data)) + "/" + str(MESSAGE_15_L) + ")") + return byd_error + + return byd_ok + + def decode_nop(self,data,x,lenx): +# self.log_debug("decode_nop (" + str(x) + ") : " + data.hex()) + + if len(data) != lenx: + self.log_info("MESSAGE nop answer length wrong ! (" + str(len(data)) + "/" + str(lenx) + ")") + return byd_error + + return byd_ok + + def module_update(self,xx): + # Aktualisiert die Daten zu den Modulen im Turm 'xx'. + + self.byd_diag_module[xx].clear() + + for i in range(0,self.byd_modules): # 0.. byd_modules-1 + f = True + vx = 0 + for j in range(i * self.byd_volt_n,(i + 1) * self.byd_volt_n): # Durchlaufe die Spannungswerte von Modul 'i' + vv = self.byd_volt_cell[xx][j] + if f == True: + vmin = vv + vmax = vv + f = False + if vv < vmin: + vmin = vv + if vv > vmax: + vmax = vv + vx = vx + vv + vava = vx / self.byd_volt_n + vdif = (vmax - vmin) * 1000.0 + ll = [] + ll.append(vmin) + ll.append(vmax) + ll.append(vava) + ll.append(vdif) + self.byd_diag_module[xx].append(ll) + + if self.byd_modules < byd_module_max: + for i in range(self.byd_modules,byd_module_max): + ll = [] + ll.append(0) + ll.append(0) + ll.append(0) + ll.append(0) + self.byd_diag_module[xx].append(ll) + +# for i in range(0,self.byd_modules): # 0.. byd_modules-1 +# vmin = self.byd_diag_module[xx][i][byd_module_vmin] +# vmax = self.byd_diag_module[xx][i][byd_module_vmax] +# vava = self.byd_diag_module[xx][i][byd_module_vava] +# vdif = self.byd_diag_module[xx][i][byd_module_vdif] +# self.log_debug("M" + str(i+1) + ": vmin=" + f"{vmin:.3f}" + ": vmax=" + f"{vmax:.3f}" + ": vava=" + f"{vava:.3f}" + ": vdif=" + f"{vdif:.3f}") + return + +# ----------------------------------------------------------------------- +# Decodieren der Log-Daten vom BYD-System +# ----------------------------------------------------------------------- - def decode_nop(self,data,x): -# self.log_debug("decode_nop (" + str(x) + ") : " + data.hex()) + def read_log_data(self,client): + # Einlesen/aktualisieren der BMS-Log-Eintraege von allen Tuermen + + # Log-Daten aus dem BMU (0) und jedem Turm (1-3) auslesen + for x in range(0,self.byd_bms_qty + 1): # 0 ... self.byd_bms_qty + if x == 0: + self.log_debug("read_log_data BMU") + else: + self.log_debug("read_log_data BMS tower " + str(x)) + + # Trigger zum Auslesen senden + bmu = False + if x == 0: + m = EVT_MSG_0_0 + bmu = True + if x == 1: + m = EVT_MSG_0_1 + elif x == 2: + m = EVT_MSG_0_2 + elif x == 3: + m = EVT_MSG_0_3 + res,data = self.send_msg(client,m,byd_timeout_1s) + if res == byd_error: + self.log_info("read_log_data message " + m + " failed") + return byd_error + if self.decode_log_0(data,x) == byd_error: + return + time.sleep(2) + + # Register 0x05A1 auslesen -> Log-Daten verfuerbar ? + res,r = self.read_reg(client,0x05A1,0x01) + if res == byd_error: + self.log_info("read_log_data read_reg 0x05A1 failed") + return byd_error + if (r % 0x100) == 0: + self.log_debug("read_log_data no data (" + str(x) + ")") + continue + + # 1.Paket auslesen + res,data1 = self.send_msg(client,EVT_MSG_1,byd_timeout_1s) + if res == byd_error: + self.log_info("read_log_data message " + m + " failed") + return byd_error + + # 2.Paket auslesen + res,data2 = self.send_msg(client,EVT_MSG_1,byd_timeout_1s) + if res == byd_error: + self.log_info("read_log_data message " + m + " failed") + return byd_error + + # 3.Paket auslesen + res,data3 = self.send_msg(client,EVT_MSG_1,byd_timeout_1s) + if res == byd_error: + self.log_info("read_log_data message " + m + " failed") + return byd_error + + # 4.Paket auslesen + res,data4 = self.send_msg(client,EVT_MSG_1,byd_timeout_1s) + if res == byd_error: + self.log_info("read_log_data message " + m + " failed") + return byd_error + + # 5.Paket auslesen + res,data5 = self.send_msg(client,EVT_MSG_1,byd_timeout_1s) + if res == byd_error: + self.log_info("read_log_data message " + m + " failed") + return byd_error + + # Daten extrahieren und speichern + if self.decode_log_1(bmu,data1,data2,data3,data4,data5,x) == byd_error: + return + + if self.byd_bms_qty == 1: + self.byd_root.visu.tower2_log.log_html("") + self.byd_root.visu.tower2_log.log_jsonlist([]) + self.byd_root.visu.tower3_log.log_html("") + self.byd_root.visu.tower3_log.log_jsonlist([]) + elif self.byd_bms_qty == 2: + self.byd_root.visu.tower3_log.log_html("") + self.byd_root.visu.tower3_log.log_jsonlist([]) + + return byd_ok + + def decode_log_0(self,data,x): + # Decodieren der Nachricht auf Befehl 'EVT_MSG_0_1'. + + self.log_debug("decode_log_0 (" + str(x) + ") : " + data.hex()) + + if len(data) != EVT_MSG_0_L: + self.log_info("EVT_MSG_0_x answer length wrong ! (" + str(len(data)) + "/" + str(EVT_MSG_0_L) + ")") + return byd_error + + return byd_ok + + def decode_log_1(self,bmu,d1,d2,d3,d4,d5,xx): + # Decodieren Log-Daten. + + self.log_debug("decode_log_1 (" + str(xx) + ")") + self.log_debug("1) " + d1.hex()) + self.log_debug("2) " + d2.hex()) + self.log_debug("3) " + d3.hex()) + self.log_debug("4) " + d4.hex()) + self.log_debug("5) " + d5.hex()) + + if (len(d1) != EVT_MSG_1_L) or (len(d2) != EVT_MSG_1_L) or (len(d3) != EVT_MSG_1_L) or (len(d4) != EVT_MSG_1_L) or (len(d5) != EVT_MSG_1_L): + self.log_info("EVT_MSG_1 answer length wrong ! (" + str(len(data)) + "/" + str(EVT_MSG_1_L) + ")") + return byd_error + + # Erzeuge eine Liste mit allen Datenbytes - 20 Log-Eintraege befinden sich in dieser Liste + d = [] + for x in range(1,6): # 1..5 + for y in range(5,133): # 5..132 + if x == 1: + d.append(d1[y]) + elif x == 2: + d.append(d2[y]) + elif x == 3: + d.append(d3[y]) + elif x == 4: + d.append(d4[y]) + elif x == 5: + d.append(d5[y]) + + self.log_debug("=> " + bytearray(d).hex()) + + # https://smarthomeng.github.io/smarthome/plugins/database/README.html + + # Log-Eintraege extrahieren + for x in range(0,20): # 0..19 + # Alle Bytes fuer diesen Log-Eintrag + raw = [] + for y in range(0,30): # 0..29 + raw.append(d[(x*30)+y]) + # Extrahiere Code, Datum und Uhrzeit + code = d[(x*30)+0] + year = d[(x*30)+1] # im Log ist Datum/Zeit = UTC + month = d[(x*30)+2] + day = d[(x*30)+3] + hour = d[(x*30)+4] + minute = d[(x*30)+5] + second = d[(x*30)+6] + # Extrahiere die Daten zu diesem Log-Eintrag + data = [] + for y in range(7,30): # 7..29 + data.append(d[(x*30)+y]) + # Erzeuge nun den Listeneintrag + ld = [] + ld.append(year) + ld.append(month) + ld.append(day) + ld.append(hour) + ld.append(minute) + ld.append(second) + ld.append(code) + ld.append(data) + ld.append(bytearray(raw).hex()) + ld.append(self.logdata2str(bmu,ld,xx)) + + self.log_update_list(bmu,ld,xx) + + self.log_create_html_json(bmu,xx) + self.logging_update(bmu,xx) + +# self.log_debug_list(bmu,xx) + + return byd_ok + + def log_update_list(self,bmu,ldx,x): + # Fuegt den Log-Datensatz 'ldx' in die Log-Liste ein. Der neuste Eintrag steht vorne (Index 0). + ldd = datetime(2000+ldx[byd_log_year],ldx[byd_log_month],ldx[byd_log_day],ldx[byd_log_hour],ldx[byd_log_minute],ldx[byd_log_second],0) + if bmu == True: + ld = self.byd_bmu_log + else: + ld = self.byd_diag_bms_log[x] + if len(ld) == 0: + ld.append(ldx) + return + for i in range(len(ld)): + dd = ld[i] + dt = datetime(2000+dd[byd_log_year],dd[byd_log_month],dd[byd_log_day],dd[byd_log_hour],dd[byd_log_minute],dd[byd_log_second],0) + if (ldd == dt) and (ldx[byd_log_codex] == dd[byd_log_codex]) and (set(dd[byd_log_data]) == set(ldx[byd_log_data])): + # Eintrag ist schon vorhanden +# self.log_debug("i=" + str(i) + " -> schon vorhanden " + ldd.strftime("%d.%m.%Y, %H:%M:%S") + " - " + dt.strftime("%d.%m.%Y, %H:%M:%S")) + return + elif dt < ldd: + # Index 'i' zeigt auf das Element vor dem wir das neue Element einfuegen. + ld.insert(i,ldx) +# self.log_debug("i=" + str(i) + " -> insert " + ldd.strftime("%d.%m.%Y, %H:%M:%S") + " - " + dt.strftime("%d.%m.%Y, %H:%M:%S")) + return + # Das Element 'ldx' ist aelter als alle bisherigen Elemente. + ld.append(ldx) return + + def logcode2str(self,code): + # Gibt den Text zum Logcode 'code' zurueck. + for i in range(len(byd_log_code)): + if code == byd_log_code[i][0]: + return byd_log_code[i][1] + return "??" + + def logdata2str(self,bmu,ld,xx): + # Erzeugt aus 'data' in 'ld' einen lesbaren Text (aehnlich Be_Connect). + + data = ld[byd_log_data] + s1 = "" + unknown = False + if ld[byd_log_codex] == 0: # Power ON (0) + if bmu == True: + if data[0] == 0: + s1 = s1 + "Bootloader" + byd_log_str_sep + else: + s1 = s1 + "??" + byd_log_str_sep + if data[1] == 0: + s1 = s1 + "Running section: A" + byd_log_str_sep + elif data[1] == 1: + s1 = s1 + "Running section: B" + byd_log_str_sep + else: + s1 = s1 + "??" + byd_log_str_sep + s2 = f"{data[2]:d}" + "." + f"{data[3]:d}" + s1 = s1 + "Current Version:V" + s2 + byd_log_str_sep + else: + if data[0] == 0: + s1 = s1 + "Bootloader" + byd_log_str_sep + else: + s1 = s1 + "??" + byd_log_str_sep + if data[2] == 0: + s1 = s1 + "Running section: A" + byd_log_str_sep + elif data[2] == 1: + s1 = s1 + "Running section: B" + byd_log_str_sep + else: + s1 = s1 + "??" + byd_log_str_sep + s2 = f"{data[3]:d}" + "." + f"{data[4]:d}" + s1 = s1 + "FW version:V" + s2 + byd_log_str_sep + + elif ld[byd_log_codex] == 1: # Power OFF (1) + if bmu == True: + if data[0] == 0: + s1 = s1 + "??" + byd_log_str_sep + elif data[0] == 1: + s1 = s1 + "Switch off by pressing LED button." + byd_log_str_sep + else: + s1 = s1 + "??" + byd_log_str_sep + else: + if data[1] < len(byd_log_bms_poweroff): + s1 = s1 + byd_log_bms_poweroff[data[1]] + byd_log_str_sep + else: + s1 = s1 + byd_log_bms_poweroff[len(byd_log_bms_poweroff)-1] + byd_log_str_sep + if data[2] == 0: + s1 = s1 + "Running section: A" + byd_log_str_sep + elif data[2] == 1: + s1 = s1 + "Running section: B" + byd_log_str_sep + else: + s1 = s1 + "??" + byd_log_str_sep + s2 = f"{data[3]:d}" + "." + f"{data[4]:d}" + s1 = s1 + "FW version:V" + s2 + byd_log_str_sep + + elif ld[byd_log_codex] == 2: # Events record (2) + if bmu == True: + if data[0] == 0: + s1 = s1 + "disappear" + byd_log_str_sep + else: + s1 = s1 + "appear" + byd_log_str_sep + if data[1] < len(byd_log_bmu_errors): + s2 = byd_log_bmu_errors[data[1]] + if len(s2) > 0: + s1 = s1 + s2 + byd_log_str_sep + else: + s1 = s1 + byd_log_bmu_errors[len(byd_log_bmu_errors)-1] + byd_log_str_sep + x = int(data[2] * 0x100 + data[3]) + if x == 0: + s1 = s1 + "No warning" + byd_log_str_sep + else: + s2 = "" + for i in range(0,16): # 0..15 + if (int(x) % 2) == 1: + if len(s2) > 0: + s2 = s2 + ";" + s2 = s2 + byd_log_bmu_warnings[i] + x = int(x / 2) + s1 = s1 + s2 + byd_log_str_sep + x = self.buf2int16US(data,4) + s1 = s1 + "Cell_Max._V:" + f"{x:d}" + "mV" + byd_log_str_sep + x = self.buf2int16US(data,6) + s1 = s1 + "Cell_Min._V:" + f"{x:d}" + "mV" + byd_log_str_sep + x = data[8] + s1 = s1 + "Battery_Temp_Max:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + x = data[9] + s1 = s1 + "Battery_Temp_Min:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + x = self.buf2int16US(data,10) / 10.0 + s1 = s1 + "Battery Total Voltage:" + f"{x:.1f}" + "V" + byd_log_str_sep + x = data[12] + s1 = s1 + "SOC:" + f"{x:d}" + "%" + byd_log_str_sep + x = data[13] + s1 = s1 + "SOH:" + f"{x:d}" + "%" + byd_log_str_sep + else: + s1 = self.logdatabms2str(ld,False) + + elif ld[byd_log_codex] == 3: # Timing Record (3) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 4: # Start Charging(4) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 5: # Stop Charging(5) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 6: # Start DisCharging (6) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 7: # Stop DisCharging (7) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 8: # SOC calibration rough (8) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 10: # SOC calibration Stop (10) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 13: # Receive PreCharge Command (13) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + elif ld[byd_log_codex] == 14: # PreCharge Successful (14) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 16: # Start end SOC calibration (16) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 17: # Start Balancing (17) + if bmu == False: + s2 = "" + nn = 0 + ci = 0 + for i in range(0,20): # 0..19 + x = int(data[i]) + for ii in range(0,8): # 0..7 + if (int(x) % 2) == 1: + if len(s2) > 0: + s2 = s2 + ";" + s2 = s2 + str(ci) + nn = nn + 1 + x = int(x / 2) + ci = ci + 1 + if len(s2) > 0: + s1 = s1 + "Balancing Cells:#=" + str(nn) + "[" + s2 + "]" + byd_log_str_sep + x = self.buf2int16USx(data,21) + s1 = s1 + "Cell_Min_V:" + f"{x:d}" + "mV" + byd_log_str_sep + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 18: # Stop Balancing (18) + if bmu == False: + x = self.buf2int16USx(data,21) + s1 = s1 + "Cell_Min_V:" + f"{x:d}" + "mV" + byd_log_str_sep + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 19: # Address Registered (19) + if bmu == False: + s1 = self.logdatabms2str(ld,False) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 21: # Events additional info (21) + if bmu == False: + s1 = self.logdatabms2str(ld,True) + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 32: # System status changed (32) + if bmu == True: + if data[1] < len(byd_log_status): + s1 = s1 + byd_log_status[data[1]] + " => " + else: + s1 = s1 + byd_log_status[len(byd_log_status)-1] + " => " + if data[0] < len(byd_log_status): + s1 = s1 + byd_log_status[data[0]] + else: + s1 = s1 + byd_log_status[len(byd_log_status)-1] + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 34: # BMS update start (34) + if bmu == True: + s1 = s1 + "FW Version:V" + f"{data[1]:d}" + "." + f"{data[2]:d}" + byd_log_str_sep + s1 = s1 + "MCU Type:" + f"{data[4]:d}" + byd_log_str_sep + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 35: # BMS update start (35) + if bmu == True: + s1 = s1 + "FW Version:V" + f"{data[1]:d}" + "." + f"{data[2]:d}" + byd_log_str_sep + s1 = s1 + "MCU Type:" + f"{data[4]:d}" + byd_log_str_sep + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 36: # Functional Safety Info (36) + if bmu == True: + x = data[0] * 0x01000000 + data[1] * 0x00010000 + data[2] * 0x00000100 + data[3] + s1 = s1 + "Running Time:" + f"{x:d}" + "s" + byd_log_str_sep + x = data[4] + s1 = s1 + "BMU detected Cells Qty:" + f"{x:d}" + byd_log_str_sep + x = data[5] + s1 = s1 + "BMU detected Temp. Qty:" + f"{x:d}" + byd_log_str_sep + x = self.buf2int16US(data,6) + s1 = s1 + "BMU detected Cell_V_Max:" + f"{x:d}" + "mV" + byd_log_str_sep + x = self.buf2int16US(data,8) + s1 = s1 + "BMU detected Cell_V_Min:" + f"{x:d}" + "mV" + byd_log_str_sep + x = data[10] + s1 = s1 + "BMU detected Temp_Max:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + x = data[11] + s1 = s1 + "BMU detected Temp_Min:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + x = self.buf2int16US(data,12) / 10.0 + s1 = s1 + "BMU detected Current:" + f"{x:.1f}" + "A" + byd_log_str_sep + x = self.buf2int16US(data,14) / 10.0 + s1 = s1 + "BMU detected Output_V:" + f"{x:.1f}" + "V" + byd_log_str_sep + x = self.buf2int16US(data,16) / 10.0 + s1 = s1 + "BMU detected All Cells Accum_V:" + f"{x:.1f}" + "V" + byd_log_str_sep + x = data[18] + s1 = s1 + "BMS Address:" + f"{x:d}" + byd_log_str_sep + if data[19] < len(byd_module_type): + s1 = s1 + "Module type:" + byd_module_type[data[19]] + byd_log_str_sep + else: + s1 = s1 + "Module type:" + byd_module_type[len(byd_module_type)-1] + byd_log_str_sep + x = data[20] + s1 = s1 + "Module Number:" + f"{x:d}" + byd_log_str_sep + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 37: # No Defined (37) + if bmu == True: + s1 = s1 + "not defined - " + bytearray(ld[byd_log_data]).hex() + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 38: # SOP Info + if bmu == True: + x = self.buf2int16US(data,0) / 10.0 + s1 = s1 + "Charge Max. Current:" + f"{x:.1f}" + "A" + byd_log_str_sep + x = self.buf2int16US(data,2) / 10.0 + s1 = s1 + "Discharge Max. Current:" + f"{x:.1f}" + "A" + byd_log_str_sep + x = self.buf2int16US(data,4) / 10.0 + s1 = s1 + "Charge Max. Voltage:" + f"{x:.1f}" + "V" + byd_log_str_sep + x = self.buf2int16US(data,6) / 10.0 + s1 = s1 + "Discharge Min. Voltage:" + f"{x:.1f}" + "V" + byd_log_str_sep + if data[8] < len(byd_log_status): + s1 = s1 + byd_log_status[data[8]] + byd_log_str_sep + else: + s1 = s1 + byd_log_status[len(byd_log_status)-1] + byd_log_str_sep + x = data[9] + s1 = s1 + "Battery Temperature:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + s1 = s1 + self.get_inverter_name(self.byd_batt_str,data[10]) + byd_log_str_sep + x = data[11] + s1 = s1 + "BMS Qty:" + f"{x:d}" + byd_log_str_sep + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 40: # BMS Firmware list (40) + if bmu == True: + x = data[0] + s1 = s1 + "Firmware Num:" + f"{x:d}" + byd_log_str_sep + s1 = s1 + "FW Version:V" + f"{data[1]:d}" + "." + f"{data[2]:d}" + byd_log_str_sep + x = data[3] + s1 = s1 + "Firmware Num:" + f"{x:d}" + byd_log_str_sep + s1 = s1 + "FW Version:V" + f"{data[4]:d}" + "." + f"{data[5]:d}" + byd_log_str_sep + x = data[6] + if x != 0xFF: + s1 = s1 + "Firmware Num:" + f"{x:d}" + byd_log_str_sep + s1 = s1 + "FW Version:V" + f"{data[7]:d}" + "." + f"{data[8]:d}" + byd_log_str_sep + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 41: # No Defined (41) + if bmu == True: + s1 = s1 + "not defined - " + bytearray(ld[byd_log_data]).hex() + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + elif ld[byd_log_codex] == 101: # Firmware Start to Update (101) + if bmu == True: + x = data[0] + if x == 0: + s1 = s1 + "BMS A Updating" + byd_log_str_sep + else: + s1 = s1 + "BMS B Updating" + byd_log_str_sep + s1 = s1 + "Version:V" + f"{data[1]:d}" + "." + f"{data[2]:d}" + byd_log_str_sep + else: + x = data[0] + if x == 0: + s1 = s1 + "Target Area:A" + byd_log_str_sep + else: + s1 = s1 + "Target Area:B" + byd_log_str_sep + s1 = s1 + "Before Update:V" + f"{data[2]:d}" + "." + f"{data[1]:d}" + byd_log_str_sep + s1 = s1 + "After Update:V" + f"{data[4]:d}" + "." + f"{data[3]:d}" + byd_log_str_sep + + elif ld[byd_log_codex] == 102: # Firmware Update Successful (102) + if bmu == True: + x = data[0] + if x == 0: + s1 = s1 + "BMS A Update Finish" + byd_log_str_sep + else: + s1 = s1 + "BMS B Update Finish" + byd_log_str_sep + s1 = s1 + "Version:V" + f"{data[1]:d}" + "." + f"{data[2]:d}" + byd_log_str_sep + else: + x = data[0] + if x == 0: + s1 = s1 + "Target Area:A" + byd_log_str_sep + else: + s1 = s1 + "Target Area:B" + byd_log_str_sep + s1 = s1 + "Before Update:V" + f"{data[2]:d}" + "." + f"{data[1]:d}" + byd_log_str_sep + s1 = s1 + "After Update:V" + f"{data[4]:d}" + "." + f"{data[3]:d}" + byd_log_str_sep + + elif ld[byd_log_codex] == 105: # Parameters table Update (105) + if bmu == True: + if (data[0] == 0) or (data[0] == 1) or (data[0] == 2): + s1 = s1 + "BMU Parameters table Update" + byd_log_str_sep + else: + s1 = s1 + "??" + byd_log_str_sep + s2 = f"{data[1]:d}" + "." + f"{data[2]:d}" + s1 = s1 + "Parameters table:V" + s2 + byd_log_str_sep + else: + x = self.buf2int16USx(data,0) + y = self.buf2int16USx(data,2) + s1 = s1 + "Threshold table version:V" + f"{x:d}" + "." + f"{y:d}" + byd_log_str_sep + + elif ld[byd_log_codex] == 106: # SN Code was Changed (106) + if bmu == True: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + else: + s1 = s1 + "serial number was changed" + byd_log_str_sep + + elif ld[byd_log_codex] == 111: # DateTime Calibration (111) + if bmu == True: + if data[0] == 0: + s1 = s1 + "Calibrated by Upper computer" + byd_log_str_sep + elif data[0] == 1: + s1 = s1 + "Calibrated by Inverter" + byd_log_str_sep + elif data[0] == 2: + s1 = s1 + "Calibrated by Internet" + byd_log_str_sep + else: + s1 = s1 + "??" + byd_log_str_sep + else: + dtl = self.log_datetime_2_local(ld[byd_log_year],ld[byd_log_month],ld[byd_log_day],ld[byd_log_hour],ld[byd_log_minute],ld[byd_log_second],0) + dtc = self.log_datetime_2_local(data[0],data[1],data[2],data[3],data[4],data[5],0) + dtx = dtl - dtc + x = dtx.total_seconds() +# self.log_debug("x=" + f"{x:.3f}" + " seconds=" + f"{dtx.seconds:.3f}" + " us=" + f"{dtx.microseconds:.1f}" + " - " + dtl.strftime("%d.%m.%Y %H:%M:%S") + " - " + dtc.strftime("%d.%m.%Y %H:%M:%S")) + s1 = s1 + "New Time:" + dtc.strftime("%d.%m.%Y %H:%M:%S") + " Delta:" + f"{x:.1f}" + "s" + byd_log_str_sep + + elif ld[byd_log_codex] == 118: # System timing log (118) + if bmu == True: + if data[0] < len(byd_log_status): + s1 = s1 + "System Status:" + byd_log_status[data[0]] + byd_log_str_sep + else: + s1 = s1 + "System Status:" + byd_log_status[len(byd_log_status)-1] + byd_log_str_sep + x = data[1] + s1 = s1 + "Environment_Temp_Min:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + x = data[2] + s1 = s1 + "Environment_Temp_Max:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + x = data[3] + s1 = s1 + "SOC:" + f"{x:.0f}" + "%" + byd_log_str_sep + x = data[4] + s1 = s1 + "SOH:" + f"{x:.0f}" + "%" + byd_log_str_sep + x = self.buf2int16US(data,6) / 10.0 + s1 = s1 + "Battery Total Voltage:" + f"{x:.1f}" + "V" + byd_log_str_sep + x = self.buf2int16US(data,8) + s1 = s1 + "Cell_HV:" + f"{x:d}" + "mV" + byd_log_str_sep + x = self.buf2int16US(data,10) + s1 = s1 + "Cell_LV:" + f"{x:d}" + "mV" + byd_log_str_sep + x = data[5] + s1 = s1 + "Battery Current_Temp:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + x = data[13] + s1 = s1 + "Battery_Temp_Max:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + x = data[15] + s1 = s1 + "Battery_Temp_Min:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + else: + s1 = "not implemented yet (" + bytearray(ld[byd_log_data]).hex() + ")" + unknown = True + + if unknown == True: + # Wir haben einen Log-Eintrag gefunden, den wir noch nicht decodieren + s1x = "logdata2str " + if bmu == True: + s1x = s1x + "BMU " + else: + s1x = s1x + "BMS Tower " + str(xx) + s1x = s1x + " : code " + str(ld[byd_log_codex]) + " (" + self.logcode2str(ld[byd_log_codex]) + ") not implemented yet" + s1x = s1x + " (" + f"{ld[byd_log_day]:02d}" + "." + f"{ld[byd_log_month]:02d}" + "." + f"{2000+ld[byd_log_year]:4d}" + s1x = s1x + " " + f"{ld[byd_log_hour]:2d}" + ":" + f"{ld[byd_log_minute]:02d}" + ":" + f"{ld[byd_log_second]:02d}" + ")" + s2 = "Raw Data: " + ld[byd_log_raw] + s3 = "Data: " + bytearray(ld[byd_log_data]).hex() + self.logging_special(s1x,s2,s3) + + return s1 + + def logdatabms2str(self,ld,cnr): + # Erzeugt den String fuer den Standard-BMS-Log-Eintrag. + data = ld[byd_log_data] + s1 = "" + y = int(data[1] * 0x100 + data[0]) + if y > 0: + s2 = "Warning:" + for i in range(0,16): # 0..15 + if (int(y) % 2) == 1: + if len(s2) > 0: + s2 = s2 + ";" + s2 = s2 + byd_log_bms_warnings[i] + y = int(y / 2) + s1 = s1 + s2 + byd_log_str_sep + else: + s1 = s1 + "No Warning" + byd_log_str_sep + y = int(data[7] * 0x100 + data[6]) + if y > 0: + s2 = "Fault:" + for i in range(0,16): # 0..15 + if (int(y) % 2) == 1: + if len(s2) > 0: + s2 = s2 + ";" + s2 = s2 + byd_log_bms_failures[i] + y = int(y / 2) + s1 = s1 + s2 + byd_log_str_sep + y = int(data[8]) + if y > 0: + s2 = "" + for i in range(0,8): # 0..7 + if (int(y) % 2) == 1: + if len(s2) > 0: + s2 = s2 + ";" + s2 = s2 + byd_log_bms_switch_status_on[i] + else: + if i == 3: + if len(s2) > 0: + s2 = s2 + ";" + s2 = s2 + byd_log_bms_switch_status_off[i] + y = int(y / 2) + s1 = s1 + s2 + byd_log_str_sep + x = data[9] + s1 = s1 + "SOC:" + f"{x:d}" + "%" + byd_log_str_sep + x = data[10] + s1 = s1 + "SOH:" + f"{x:d}" + "%" + byd_log_str_sep + x = self.buf2int16USx(data,11) / 10.0 + s1 = s1 + "Bat_V:" + f"{x:.1f}" + "V" + byd_log_str_sep + x = self.buf2int16USx(data,13) / 10.0 + s1 = s1 + "Output_V:" + f"{x:.1f}" + "V" + byd_log_str_sep + x = self.buf2int16SIx(data,15) / 10.0 + s1 = s1 + "Current:" + f"{x:.1f}" + "A" + byd_log_str_sep + if cnr == False: + x = self.buf2int16USx(data,17) + s1 = s1 + "Cell_Max_V:" + f"{x:d}" + "mV" + byd_log_str_sep + else: + x = data[17] + s1 = s1 + "Cell_Max_V:No" + f"{x:d}" + byd_log_str_sep + if cnr == False: + x = self.buf2int16USx(data,19) + s1 = s1 + "Cell_Min_V:" + f"{x:d}" + "mV" + byd_log_str_sep + else: + x = data[18] + s1 = s1 + "Cell_Min_V:No" + f"{x:d}" + byd_log_str_sep + if cnr == False: + x = data[21] + s1 = s1 + "Cell_Max_T:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + else: + x = data[19] + s1 = s1 + "Cell_Max_T:No" + f"{x:d}" + byd_log_str_sep + if cnr == False: + x = data[22] + s1 = s1 + "Cell_Min_T:" + f"{x:d}" + byd_log_degree + byd_log_str_sep + else: + x = data[20] + s1 = s1 + "Cell_Min_T:No" + f"{x:d}" + byd_log_str_sep + + return s1 + + def log_create_html_json(self,bmu,x): + # Erstellt fuer eine Einheit die HTML-Tabelle fuer die Anzeige in smartVISU. + + # Beispiel einer JSON-Message fuer '' in smartVISU: + # myNewMessage = {"id":6498501,"title":"Geben Sie 4 g Chlor hinzu","message":"Ich empfehle Ihnen, Chlor zuzusetzen, um eine gute Desinfektion Ihres Wassers zu gew\u00e4hrleisten.","created_at":"2022-01-23T14:30:57+0000","updated_at":"2022-01-23T14:30:57+0000","status":"waiting","deadline":"2 022-01-29T00:00:00+0000"} + + if bmu == True: + ld = self.byd_bmu_log + else: + ld = self.byd_diag_bms_log[x] + line_string = "" + json_list = [] + for i in range(len(ld)): # 0..len(ld)-1 + dd = ld[i] + dt = self.log_datetime_2_local(dd[byd_log_year],dd[byd_log_month],dd[byd_log_day],dd[byd_log_hour],dd[byd_log_minute],dd[byd_log_second],0) + # HTML + line_string = line_string + '' + line_string = line_string + '' + dt.strftime("%d.%m.%Y") + '' + line_string = line_string + '' + dt.strftime("%H:%M:%S") + '' + line_string = line_string + '' + self.logcode2str(dd[byd_log_codex]) + ' (' + f"{dd[byd_log_codex]:d}" + ')' + '' + line_string = line_string + '' + dd[byd_log_str] + '' + line_string = line_string + '' + # JSON + jd = {"id":str(i),"title":self.logcode2str(dd[byd_log_codex]) + " (" + f"{dd[byd_log_codex]:d}" + ")", + "content":dd[byd_log_str],"level":"info","date":dt.strftime("%d.%m.%Y %H:%M:%S")} + json_list.append(jd) + if i == byd_log_max_rows: + break + html_string = '' + line_string + '
' + + if bmu == True: + old = self.byd_root.visu.bmu_log.log_html() + if html_string != old: + self.byd_root.visu.bmu_log.log_html(html_string) + self.byd_bmu_log_html = html_string + old = self.byd_root.visu.bmu_log.log_jsonlist() + if json_list != old: + self.byd_root.visu.bmu_log.log_jsonlist(json_list) + else: + self.byd_diag_bms_log_html[x] = html_string + if x == 1: + old = self.byd_root.visu.tower1_log.log_html() + if html_string != old: + self.byd_root.visu.tower1_log.log_html(html_string) + old = self.byd_root.visu.tower1_log.log_jsonlist() + if json_list != old: + self.byd_root.visu.tower1_log.log_jsonlist(json_list) + elif x == 2: + old = self.byd_root.visu.tower2_log.log_html() + if html_string != old: + self.byd_root.visu.tower2_log.log_html(html_string) + old = self.byd_root.visu.tower2_log.log_jsonlist() + if json_list != old: + self.byd_root.visu.tower2_log.log_jsonlist(json_list) + elif x == 3: + old = self.byd_root.visu.tower3_log.log_html() + if html_string != old: + self.byd_root.visu.tower3_log.log_html(html_string) + old = self.byd_root.visu.tower3_log.log_jsonlist() + if json_list != old: + self.byd_root.visu.tower3_log.log_jsonlist(json_list) + return + + def log_debug_list(self,bmu,x): + # Ausgabe der aktuellen Log-Daten im Debug-Modus. + if bmu == True: + ld = self.byd_bmu_log + else: + ld = self.byd_diag_bms_log[x] + for i in range(len(ld)): + dd = ld[i] + s1 = "+ " + f"{i:2d}" + s1 = s1 + " " + f"{dd[byd_log_year]:2d}" + "." + f"{dd[byd_log_month]:02d}" + "." + f"{dd[byd_log_day]:02d}" + s1 = s1 + " " + f"{dd[byd_log_hour]:2d}" + ":" + f"{dd[byd_log_minute]:02d}" + ":" + f"{dd[byd_log_second]:02d}" + s1 = s1 + " d=" + bytearray(dd[byd_log_data]).hex() + s1 = s1 + " c=" + f"{dd[byd_log_codex]:3d}" + " - " + self.logcode2str(dd[byd_log_codex]) + self.log_debug(s1) + + def log_datetime_2_local(self,y,m,d,h,mi,s,ms): + dt = datetime(2000+y,m,d,h,mi,s,ms) + dtx = dt.replace(tzinfo=ZoneInfo('UTC')) # make aware + dtxx = dtx.astimezone(ZoneInfo('localtime')) # convert + return dtxx + +# ----------------------------------------------------------------------- +# Speichern der Daten in den Items +# ----------------------------------------------------------------------- + def basisdata_save(self,device): # Speichert die Basisdaten in der sh-Struktur. @@ -998,6 +2288,9 @@ def basisdata_save(self,device): device.state.voltmax(self.byd_volt_max) device.state.voltmin(self.byd_volt_min) device.state.voltout(self.byd_volt_out) + device.state.charge_total(self.byd_charge_total) + device.state.discharge_total(self.byd_discharge_total) + device.state.eta(self.byd_eta) device.system.bms(self.byd_bms) device.system.bmu(self.byd_bmu) @@ -1014,12 +2307,12 @@ def basisdata_save(self,device): device.system.paramt(self.byd_param_t) device.system.serial(self.byd_serial) - self.last_homedata = self.now_str() + self.last_homedata = self.now_str() # Speichert Zeitpunkt als String return def diagdata_save(self,device): - # Speichert die Diagnosedaten in der sh-Struktur. + # Speichert die Diagnosedaten in der sh-Struktur und erzeugt die Heatmaps. self.log_debug("diagdata_save") @@ -1029,16 +2322,19 @@ def diagdata_save(self,device): if self.byd_bms_qty > 2: self.diagdata_save_one(device.diagnosis.tower3,3) - self.last_diagdata = self.now_str() + self.last_diagdata = self.now_str() # Speichert Zeitpunkt als String return def diagdata_save_one(self,device,x): - + # Speichert alle Daten fuer einen Turm und erzeugt die Heatmaps. + device.soc(self.byd_diag_soc[x]) + device.soh(self.byd_diag_soh[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_diff(self.byd_diag_volt_diff[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]) @@ -1047,6 +2343,36 @@ def diagdata_save_one(self,device,x): device.temp_max.cell(self.byd_diag_temp_max_c[x]) device.temp_min.temp(self.byd_diag_temp_min[x]) device.temp_min.cell(self.byd_diag_temp_min_c[x]) + device.charge_total(self.byd_diag_charge_total[x]) + device.discharge_total(self.byd_diag_discharge_total[x]) + + self.byd_diag_balance_active[x] = False + if self.byd_diag_balance_number[x] > 0: + self.byd_diag_balance_active[x] = True + + device.balancing.active(self.byd_diag_balance_active[x]) + device.balancing.number(self.byd_diag_balance_number[x]) + + self.save_module_data(x,device.modules) + + # Status des Turms = Hex-Wert 'byd_diag_state' (2 Byte) + device.state.raw(self.byd_diag_state[x]) + if self.byd_diag_state[x] == 0: + s = "normal" + else: + # Fuege alle Bit-Texte in einem String zusammen + s = "" + xx = int() + xx = self.byd_diag_state[x] + for yy in range(0,16): # 0..15 + if (int(xx) & 1) == 1: + if len(s) != 0: + s = s + "," + s = s + byd_stat_tower[yy] # Enum mit den Bit-Texten + xx = xx / 2 + self.byd_diag_state_str[x] = s + device.state.str(s) +# self.log_debug("Status: " + s) self.diag_plot(x) @@ -1058,14 +2384,197 @@ def diagdata_save_one(self,device,x): return + def save_module_data(self,xx,m): + # Speichert die Daten fuer die Module im Turm 'x' in 'm' ab. + + m.m1.v_min(self.byd_diag_module[xx][0][byd_module_vmin]) + m.m1.v_max(self.byd_diag_module[xx][0][byd_module_vmax]) + m.m1.v_av(self.byd_diag_module[xx][0][byd_module_vava]) + m.m1.v_diff(self.byd_diag_module[xx][0][byd_module_vdif]) + + m.m2.v_min(self.byd_diag_module[xx][1][byd_module_vmin]) + m.m2.v_max(self.byd_diag_module[xx][1][byd_module_vmax]) + m.m2.v_av(self.byd_diag_module[xx][1][byd_module_vava]) + m.m2.v_diff(self.byd_diag_module[xx][1][byd_module_vdif]) + + m.m3.v_min(self.byd_diag_module[xx][2][byd_module_vmin]) + m.m3.v_max(self.byd_diag_module[xx][2][byd_module_vmax]) + m.m3.v_av(self.byd_diag_module[xx][2][byd_module_vava]) + m.m3.v_diff(self.byd_diag_module[xx][2][byd_module_vdif]) + + m.m4.v_min(self.byd_diag_module[xx][3][byd_module_vmin]) + m.m4.v_max(self.byd_diag_module[xx][3][byd_module_vmax]) + m.m4.v_av(self.byd_diag_module[xx][3][byd_module_vava]) + m.m4.v_diff(self.byd_diag_module[xx][3][byd_module_vdif]) + + m.m5.v_min(self.byd_diag_module[xx][4][byd_module_vmin]) + m.m5.v_max(self.byd_diag_module[xx][4][byd_module_vmax]) + m.m5.v_av(self.byd_diag_module[xx][4][byd_module_vava]) + m.m5.v_diff(self.byd_diag_module[xx][4][byd_module_vdif]) + + m.m6.v_min(self.byd_diag_module[xx][5][byd_module_vmin]) + m.m6.v_max(self.byd_diag_module[xx][5][byd_module_vmax]) + m.m6.v_av(self.byd_diag_module[xx][5][byd_module_vava]) + m.m6.v_diff(self.byd_diag_module[xx][5][byd_module_vdif]) + + m.m7.v_min(self.byd_diag_module[xx][6][byd_module_vmin]) + m.m7.v_max(self.byd_diag_module[xx][6][byd_module_vmax]) + m.m7.v_av(self.byd_diag_module[xx][6][byd_module_vava]) + m.m7.v_diff(self.byd_diag_module[xx][6][byd_module_vdif]) + + m.m8.v_min(self.byd_diag_module[xx][7][byd_module_vmin]) + m.m8.v_max(self.byd_diag_module[xx][7][byd_module_vmax]) + m.m8.v_av(self.byd_diag_module[xx][7][byd_module_vava]) + m.m8.v_diff(self.byd_diag_module[xx][7][byd_module_vdif]) + + return + +# ----------------------------------------------------------------------- +# Generieren der Bilder +# ----------------------------------------------------------------------- + def diag_plot(self,x): - # Erstellt die beiden Plots fuer Turm 'x'. + # Erstellt die Plots fuer Turm 'x'. + + # Saeulen-Grafik ---------------------------------------------------------------- + +# # Simulationsdaten fuer Pruefung des Plots !!!!!!!!!!!!!!! +# # - Max. Anzahl Module: HVS=2-5, HVM=3-8, HVL=3-8, LVS=1-8 +# old_n = self.byd_volt_n +# old_m = self.byd_modules +# old_x = self.byd_cells_n +# old_v = self.byd_volt_cell +# old_b = self.byd_balance_cell +# twr = 1 +# self.byd_volt_n = 8 +# self.byd_modules = 7 +# self.byd_cells_n = self.byd_volt_n * self.byd_modules +# for xx in range(0,self.byd_cells_n): +# self.byd_volt_cell[twr][xx] = round(random.uniform(3.08,3.27),2) +# self.byd_balance_cell[twr][xx] = random.randint(0,1) + + # Daten zusammenstellen + xx = np.arange(self.byd_modules) # X-Achse -> alle Module + yy = [] + for ii in range(0,self.byd_volt_n): # alle Zellen eines Moduls + zz = [] + for jj in range(0,self.byd_modules): + v = self.byd_volt_cell[x][(jj*self.byd_volt_n)+ii] + zz.append(v) + yy.append(zz) + # Min/Max bestimmen + yminl = [] + ymaxl = [] + f = True + for jj in range(0,self.byd_modules): + f1 = True + for ii in range(0,self.byd_volt_n): + v = self.byd_volt_cell[x][(jj*self.byd_volt_n)+ii] + if f == True: + ymin = v + ymax = v + f = False + else: + if v < ymin: + ymin = v + elif v > ymax: + ymax = v + if f1 == True: + ymin1 = v + ymax1 = v + ymini = ii + ymaxi = ii + f1 = False + else: + if v < ymin1: + ymin1 = v + ymini = ii + elif v > ymax1: + ymax1 = v + ymaxi = ii + yminl.append(ymini) + ymaxl.append(ymaxi) + # Balancing-Daten extrahieren + ba = [] + balance_n = 0 + for ii in range(0,self.byd_volt_n): # alle Zellen eines Moduls + zz = [] + for jj in range(0,self.byd_modules): + b = self.byd_balance_cell[x][(jj*self.byd_volt_n)+ii] * ymin * 0.999 + if b > 0: + balance_n = balance_n + 1 + zz.append(b) + ba.append(zz) + nn = [] + # Modulnamen fuer X-Achse + for jj in range(0,self.byd_modules): + nn.append("M"+str(jj+1)) + + # Berechne bestimmte Parameter fuer die optimale Darstellung + width = 1.0 / (self.byd_volt_n + 1) + ddd = width + y1 = self.round_decimal(ymax,Decimal('0.05')) + if y1 < ymax: + y1 = y1 + 0.05 + y0 = self.round_decimal(ymin,Decimal('0.05')) + if (y1 - y0) < 0.1: + yyy = (y0 + y1) / 2 + y0 = yyy - 0.05 + y1 = yyy + 0.05 + + fig,ax = plt.subplots(figsize=(10,4)) # Erzeugt ein Bitmap von 1000x400 Pixel + + x1 = -((self.byd_volt_n / 2) * ddd) + for ii in range(0,self.byd_volt_n): # alle Zellen eines Moduls + if (ii % 2) == 0: + col = '#ff0000' # 'rot' + else: + col = '#ff8c00' # 'orange' + b = plt.bar(xx+x1,yy[ii],width,color=col,zorder=3) + for jj in range(0,self.byd_modules): + if ii == yminl[jj]: + b[jj].set_color('#05b4ff') # 'blau' + elif ii == ymaxl[jj]: + b[jj].set_color('#c505ff') # 'violett' + if balance_n > 0: + plt.bar(xx+x1,ba[ii],width,color='#0000ff',zorder=4) # 'blau' + x1 = x1 + ddd + + plt.ylim(y0,y1) + plt.xticks(xx,nn) + plt.ylabel("Volt [V]") + plt.grid(axis='y',color='#999999',linestyle='dashed',zorder=0) + ax.tick_params(axis='x',colors='white') + ax.tick_params(axis='y',colors='white') + ax.yaxis.label.set_color('white') + ax.spines['bottom'].set_color('white') + ax.spines['top'].set_color('white') + ax.spines['right'].set_color('white') + ax.spines['left'].set_color('white') + ax.set_title("Turm " + str(x) + " - Spannungen [V]" + " (" + self.now_str() + ")",size=10,color='white') + + fig.tight_layout() + if len(self.bpath) != byd_path_empty: + fig.savefig(self.bpath + byd_fname_volt2 + str(x) + byd_fname_ext,format='png',transparent=True) + self.log_debug("save " + self.bpath + byd_fname_volt2 + str(x) + byd_fname_ext) + fig.savefig(self.get_plugin_dir() + byd_webif_img + byd_fname_volt2 + str(x) + byd_fname_ext,format='png',transparent=True) + self.log_debug("save " + self.get_plugin_dir() + byd_webif_img + byd_fname_volt2 + str(x) + byd_fname_ext) + plt.close('all') + +# # Simulationsdaten fuer Pruefung des Plots !!!!!!!!!!!!!!! +# self.byd_volt_n = old_n +# self.byd_modules = old_m +# self.byd_cells_n = old_x +# self.byd_volt_cell = old_v +# self.byd_balance_cell = old_b - # Heatmap der Spannungen + # Heatmap der Spannungen -------------------------------------------------------- if self.byd_volt_n == byd_no_of_col_7: no_of_col = byd_no_of_col_7 else: no_of_col = byd_no_of_col_8 + i = int() + j = int() i = 0 j = 1 rows = self.byd_cells_n // no_of_col # Anzahl Zeilen bestimmen @@ -1082,7 +2591,7 @@ def diag_plot(self,x): j = j + 1 dd = np.array(d) - fig,ax = plt.subplots(figsize=(10,4)) # Erzeugt ein Bitmap von 1000x500 Pixel + fig,ax = plt.subplots(figsize=(10,4)) # Erzeugt ein Bitmap von 1000x400 Pixel im = ax.imshow(dd) # Befehl fuer Heatmap cbar = ax.figure.colorbar(im,ax=ax,shrink=0.5) @@ -1104,41 +2613,37 @@ def diag_plot(self,x): threshold = im.norm(dd.max()) / 2.0 kw = dict(horizontalalignment="center",verticalalignment="center",size=9) valfmt = matplotlib.ticker.StrMethodFormatter("{x:.3f}") - valfmtb = matplotlib.ticker.StrMethodFormatter("{x:.3f} B") - - # Loop over data dimensions and create text annotations. + + # Loop over data dimensions and create text annotations including colored frame around balancing cells. k = 0 - for i in range(0,rows): # 0..rows-1 - for j in range(0,no_of_col): # 0..no_of_col-1 + for i in range(0,rows): # 0..rows-1 (Zeilen) + for j in range(0,no_of_col): # 0..no_of_col-1 (Spalten) kw.update(color=textcolors[int(im.norm(dd[i,j]) > threshold)]) - if self.byd_balance_cell[x][k] == 0: - text = ax.text(j,i,valfmt(dd[i,j],None),**kw) - else: - text = ax.text(j,i,valfmtb(dd[i,j],None),**kw) + text = ax.text(j,i,valfmt(dd[i,j],None),**kw) + if self.byd_balance_cell[x][k] > 0: + ax.add_patch(patches.Rectangle((-0.5+j,-0.5+i),1,1,edgecolor='red',fill=False,lw=2)) k = k + 1 - + ax.set_title("Turm " + str(x) + " - Spannungen [V]" + " (" + self.now_str() + ")",size=10,color='white') fig.tight_layout() if len(self.bpath) != byd_path_empty: fig.savefig(self.bpath + byd_fname_volt + str(x) + byd_fname_ext,format='png',transparent=True) - self.log_debug("save " + self.bpath + byd_fname_temp + str(x) + byd_fname_ext) - fig.savefig(self.get_plugin_dir() + byd_webif_img + byd_fname_volt + str(x) + byd_fname_ext, - format='png',transparent=True) - self.log_debug("save " + self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(x) + byd_fname_ext) +# self.log_debug("save " + self.bpath + byd_fname_temp + str(x) + byd_fname_ext) + fig.savefig(self.get_plugin_dir() + byd_webif_img + byd_fname_volt + str(x) + byd_fname_ext,format='png',transparent=True) +# self.log_debug("save " + self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(x) + byd_fname_ext) plt.close('all') + # Heatmap der Temperaturen ------------------------------------------------------ if self.byd_temps_n == 0: return - - # Heatmap der Temperaturen if self.byd_temp_n == byd_no_of_col_8: no_of_col = byd_no_of_col_8 else: no_of_col = byd_no_of_col_12 + rows = self.byd_temps_n // no_of_col i = 0 j = 1 - rows = self.byd_temps_n // no_of_col d = [] rt = [] for r in range(0,rows): @@ -1151,12 +2656,10 @@ def diag_plot(self,x): if ((r + 1) % (self.byd_temp_n // no_of_col)) == 0: j = j + 1 dd = np.array(d) -# self.log_info("dd.min=" + str(dd.min()) + " dd.max=" + str(dd.max())) cmap = matplotlib.colors.LinearSegmentedColormap.from_list('',['#f5f242','#ffaf38','#fc270f']) - norm = matplotlib.colors.TwoSlopeNorm(vcenter=dd.min() + (dd.max() - dd.min()) / 2, - vmin=dd.min(),vmax=dd.max()) + norm = matplotlib.colors.TwoSlopeNorm(vcenter=dd.min() + (dd.max() - dd.min()) / 2,vmin=dd.min(),vmax=dd.max()) - fig,ax = plt.subplots(figsize=(10,2.5)) # Erzeugt ein Bitmap von 1000x400 Pixel + fig,ax = plt.subplots(figsize=(10,2.5)) # Erzeugt ein Bitmap von 1000x250 Pixel im = ax.imshow(dd,cmap=cmap,norm=norm) cbar = ax.figure.colorbar(im,ax=ax,shrink=0.5) @@ -1190,17 +2693,19 @@ def diag_plot(self,x): fig.tight_layout() if len(self.bpath) != byd_path_empty: fig.savefig(self.bpath + byd_fname_temp + str(x) + byd_fname_ext,format='png',transparent=True) - self.log_debug("save " + self.bpath + byd_fname_temp + str(x) + byd_fname_ext) +# self.log_debug("save " + self.bpath + byd_fname_temp + str(x) + byd_fname_ext) fig.savefig(self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(x) + byd_fname_ext, format='png',transparent=True) - self.log_debug("save " + self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(x) + byd_fname_ext) +# self.log_debug("save " + self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(x) + byd_fname_ext) plt.close('all') return def plt_file_del_single(self,fn): + # Loescht eine vorhandene Datei 'fn' und erstellt eine leere Datei. if os.path.exists(fn) == True: os.remove(fn) + self.create_dummy_png(fn) return def plt_file_del(self): @@ -1216,6 +2721,16 @@ def plt_file_del(self): self.plt_file_del_single(self.bpath + byd_fname_volt + str(2) + byd_fname_ext) self.plt_file_del_single(self.bpath + byd_fname_volt + str(3) + byd_fname_ext) + # Spannungs-Plots + self.plt_file_del_single(self.get_plugin_dir() + byd_webif_img + byd_fname_volt2 + str(1) + byd_fname_ext) + self.plt_file_del_single(self.get_plugin_dir() + byd_webif_img + byd_fname_volt2 + str(2) + byd_fname_ext) + self.plt_file_del_single(self.get_plugin_dir() + byd_webif_img + byd_fname_volt2 + str(3) + byd_fname_ext) + + if len(self.bpath) != byd_path_empty: + self.plt_file_del_single(self.bpath + byd_fname_volt2 + str(1) + byd_fname_ext) + self.plt_file_del_single(self.bpath + byd_fname_volt2 + str(2) + byd_fname_ext) + self.plt_file_del_single(self.bpath + byd_fname_volt2 + str(3) + byd_fname_ext) + # Temperatur-Plots self.plt_file_del_single(self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(1) + byd_fname_ext) self.plt_file_del_single(self.get_plugin_dir() + byd_webif_img + byd_fname_temp + str(2) + byd_fname_ext) @@ -1228,24 +2743,366 @@ def plt_file_del(self): return + def create_dummy_png(self,fn): + fig,ax = plt.subplots(figsize=(10,0.1)) # Erzeugt ein Bitmap von 1000x10 Pixel + fig.savefig(fn,format='png',transparent=True) + plt.close('all') + return + +# ----------------------------------------------------------------------- +# Routinen fuer das Logging der Daten +# ----------------------------------------------------------------------- + + def create_logdirectory(self,base,log_directory): + # Erstellt das Verzeichnis 'log_directory' im Log-Verzeichnis von smarthomeNG. + if log_directory[0] != "/": + if base[-1] != "/": + base += "/" + log_directory = base + "var/log/" + log_directory + if not os.path.exists(log_directory): + os.makedirs(log_directory) + return log_directory + + def logging_update(self,bmu,x): + # Aktualisiert die aktuelle Logdatei. + # Fuer jeden Tag wird eine neue Log-Datei erstellt. + + # Dateiname erstellen und zugehoerige Log-Liste holen + tn = self.now() + fn = f"{tn.year-2000:2d}" + f"{tn.month:02d}" + f"{tn.day:02d}" + "_BYD_" + if bmu == True: + fn = fn + "BMU" + ld = self.byd_bmu_log + else: + fn = fn + "BMS_Tower_" + str(x) + ld = self.byd_diag_bms_log[x] + fn = self.log_dir + "/" + fn + "." + byd_log_extension +# self.log_debug("logging_update fn=" + fn) + + # Wir suchen den aeltesten Eintrag in der Liste 'ld' vom heutigen Tag + mii = -1 + for mi in range(len(ld)-1,-1,-1): # len(ld)-1 .. 0 + dd = ld[mi] + if (2000+dd[byd_log_year] == tn.year) and (dd[byd_log_month] == tn.month) and (dd[byd_log_day] == tn.day): + mii = mi + break + if mii == -1: + # In der aktuellen Liste gibt es noch keinen Eintrag vom heutigen Datum - wir warten ! + return + + if not os.path.exists(fn): + # Datei existiert noch nicht - erstellen mit Headerzeile + self.log_debug("logging_update file not exist yet => create (" + fn + ")") + f = open(fn,"wt",encoding='utf-8') + s1 = "Date/Time (local)" + byd_log_sep + "Code" + byd_log_sep + "Code Description" + byd_log_sep + "Data" + byd_log_sep + "Data Raw" + byd_log_newline + sx = [] + sx.append(s1) + f.writelines(sx) + f.close() + if bmu == True: + self.logging_del_old_files() + + # Datei oeffnen und alle Zeilen einlesen + fl = [] + with open(fn,"rt",encoding='utf-8') as f: + fl = f.readlines() + f.close() + + # Wir suchen diesen aeltesten Eintrag 'mii' in der Liste 'ld' in der Logdatei. + wl = [] + wl.append(fl[0]) # Titelzeile direkt uebernehmen + s1 = self.logging_create_str(ld[mii]) + if len(fl) > 1: + for fi in range(1,len(fl)): # 1..len(fl)-1 - ohne Titelzeile + # Durchlaufe alle Zeilen, beginnend mit der aeltesten Zeile (oben in der Datei) + if fl[fi] == s1: + # Wir haben den Eintrag im Log gefunden - hier brechen wir ab + break + else: + wl.append(fl[fi]) + + # Nun fuegen wir alle Eintraege aus 'ld' an die Datei hinzu + nn = 0 + for mi in range(mii,-1,-1): # mii .. 0 + # Durchlaufe die Eintrage im Speicher, beginnend mit der aeltesten Zeile (am Ende der Liste) + s1 = self.logging_create_str(ld[mi]) + wl.append(s1) + nn = nn + 1 + + if len(fl)-1 == nn: + # Anzahl Zeilen in der aktuellen Log unveraendert. + self.log_debug("logging_update rows not changed ! " + str(len(fl)-1) + "/" + str(nn)) + return + + # Schreibe die Log-Datei mit den neuen Daten + f = open(fn,"wt",encoding='utf-8') + f.writelines(wl) + f.close() + + def logging_create_str(self,dd): + dt = self.log_datetime_2_local(dd[byd_log_year],dd[byd_log_month],dd[byd_log_day],dd[byd_log_hour],dd[byd_log_minute],dd[byd_log_second],0) + s1 = dt.strftime("%d.%m.%Y %H:%M:%S") + byd_log_sep + f"{dd[byd_log_codex]:d}" + byd_log_sep + self.logcode2str(dd[byd_log_codex]) + byd_log_sep + s1 = s1 + dd[byd_log_str] + byd_log_sep + bytearray(dd[byd_log_data]).hex() + byd_log_newline + return s1 + + def logging_del_old_files(self): + # Alte Log-Dateien loeschen. + if self.log_age == 0: + return + tn = self.now() + files = os.listdir(self.log_dir) + ts = tn.replace(hour=0,minute=1,second=0) + tx = ts - timedelta(days=self.log_age) + tx = tx.replace(tzinfo=None) +# self.log_debug("ts=" + ts.strftime("%d.%m.%Y %H:%M:%S") + " tx=" + tx.strftime("%d.%m.%Y %H:%M:%S")) + for i in range(0,len(files)): + yy = int(files[i][0:2]) + mm = int(files[i][2:4]) + da = int(files[i][4:6]) + dt = datetime(2000+yy,mm,da,0,1,0,0) # Datum dieser Datei als 'datetime' + dx = tx - dt +# self.log_debug("i:" + str(i) + " -> " + files[i] + " / " + " y=" + str(yy) + " m=" + str(mm) + " d=" + str(da) + " - " + dt.strftime("%d.%m.%Y %H:%M:%S") + " dx=" + str(dx.total_seconds()) + " dx=" + str(dx.days)) + if dx.days > 0: + # Positiv = Datei zu alt, wird geloescht ! + os.remove(self.log_dir + "/" + files[i]) + self.log_info("Log file " + files[i] + " too old -> deleted") + + def logging_special(self,s1,s2,s3): + # Schreibt die Texte in die Spezial-Log-Datei. + fn = self.log_dir + "/" + byd_log_special + "." + byd_log_extension + if not os.path.exists(fn): + f = open(fn,"wt",encoding='utf-8') + sx = [] + sx.append("BYD_BAT Plugin - special notes" + byd_log_newline) + sx.append(byd_log_newline) + f.writelines(sx) + f.close() + + # Datei oeffnen und alle Zeilen einlesen. + fl = [] + with open(fn,"rt",encoding='utf-8') as f: + fl = f.readlines() + f.close() + + # Pruefe, ob dieser neue Eintrag schon im Log vorhanden ist. + s1 = s1 + byd_log_newline + s2 = s2 + byd_log_newline + s3 = s3 + byd_log_newline + if len(fl) >= 6: + for i in range(2,len(fl),5): + if (i+3) > len(fl)-1: + break + s1x = fl[i+1] + s2x = fl[i+2] + s3x = fl[i+3] + if (s1 == s1x) and (s2 == s2x) and (s3 == s3x): + # Eintrag ist schon vorhanden + self.log_debug("logging_special record exists ! " + s1) + return + + # Neuer Eintrag - an die Datei anfuegen. + s = [] + tn = self.now() + s.append(tn.strftime("%d.%m.%Y %H:%M:%S") + byd_log_newline) + s.append(s1) + s.append(s2) + s.append(s3) + s.append(byd_log_newline) + f = open(fn,"at",encoding='utf-8') + f.writelines(s) + f.close() + return + + def log_debug(self,s1): + self.logger.debug(s1) + + def log_info(self,s1): + self.logger.warning(s1) + +# ----------------------------------------------------------------------- +# Kommunikations-Routinen +# ----------------------------------------------------------------------- + + def read_reg(self,client,reg,xx): + # Liest ein Register (MODBUS/RTU) ein. + msg = "0103" + f"{reg:04x}" + "00" + f"{xx:02x}" +# self.log_debug("read_reg msg=" + msg) + msgb = bytes.fromhex(msg) + crc = self.modbus_crc(msgb) + ba = crc.to_bytes(2,byteorder='little') + msg = msg + f"{ba[0]:02x}" + f"{ba[1]:02x}" +# self.log_debug("read_reg msg=" + msg) + + client.send(bytes.fromhex(msg)) + client.settimeout(byd_timeout_1s) + + try: + data = client.recv(BUFFER_SIZE) + except: + self.log_info("read_reg 0x" + f"{reg:04x}" + " failed !") + return byd_error,0 + + v = data[3] * 0x100 + data[4] +# self.log_debug("read_reg : v=" + f"{v:04x}" + " - " + data.hex()) + return byd_ok,v + + def send_msg(self,client,msg,tout): + # Sendet die Nachricht 'msg' und holt die Antwort. + # Eingabe : client = Client fuer Senden/Empfangen + # msg = Nachricht zum Senden (String) + # tout = Timeout Warten auf Antwort [s] + # Ausgabe : () = result (byd_ok,byd_error) und data + client.send(bytes.fromhex(msg)) + client.settimeout(tout) + try: + data = client.recv(BUFFER_SIZE) + except: + return byd_error,0 + d = [] + for n in range(len(data)-2): # ohne CRC + d.append(data[n]) + crc = self.modbus_crc(d) + crcx = data[len(data)-1] * 0x100 + data[len(data)-2] + if crc != crcx: + self.log_info("send_msg recv crc not ok (" + f"{crc:04x}" + "/" + f"{crcx:04x}" + ")") + return byd_error,0 +# self.log_debug("send_msg crc=" + f"{crc:04x}" + " / " + f"{crcx:04x}" + " len=" + str(len(data))) + return byd_ok,data + + def modbus_crc(self,msg:str) -> int: + # Bestimmt den CRC-Wert der Nachricht 'msg'. + crc = 0xFFFF + for n in range(len(msg)): + crc ^= msg[n] + for i in range(8): + if crc & 1: + crc >>= 1 + crc ^= 0xA001 + else: + crc >>= 1 + return crc + +# ----------------------------------------------------------------------- +# Hilfsroutinen +# ----------------------------------------------------------------------- + def buf2int16SI(self,byteArray,pos): # signed - result = byteArray[pos] * 256 + byteArray[pos + 1] + try: + result = byteArray[pos] * 256 + byteArray[pos + 1] + except: + return 0 if (result > 32768): result -= 65536 return result def buf2int16US(self,byteArray,pos): # unsigned - result = byteArray[pos] * 256 + byteArray[pos + 1] + try: + result = byteArray[pos] * 256 + byteArray[pos + 1] + except: + return 0 return result - def now_str(self): - return self.now().strftime("%d.%m.%Y, %H:%M:%S") + def buf2int16SIx(self,byteArray,pos): # signed + try: + result = byteArray[pos+1] * 256 + byteArray[pos] + except: + return 0 + if (result > 32768): + result -= 65536 + return result - def log_debug(self,s1): - self.logger.debug(s1) + def buf2int16USx(self,byteArray,pos): # unsigned + try: + result = byteArray[pos+1] * 256 + byteArray[pos] + except: + return 0 + return result - def log_info(self,s1): - self.logger.warning(s1) + def buf2int32SI(self,byteArray,pos): # signed +# self.log_debug("buf2int32US 0=" + f"{byteArray[pos]:02x}" + " 1=" + f"{byteArray[pos+1]:02x}" + " 2=" + f"{byteArray[pos+2]:02x}" + " 3=" + f"{byteArray[pos+3]:02x}") + try: + result = byteArray[pos+2] * 0x01000000 + byteArray[pos+3] * 0x00010000 + byteArray[pos] * 0x00000100 + byteArray[pos+1] + except: + return 0 + if (result > 0x7FFFFFFF): + result -= 0x100000000 +# self.log_debug("buf2int32US r=" + str(result)) + return result + + def buf2int32US(self,byteArray,pos): # unsigned +# self.log_debug("buf2int32US 0=" + f"{byteArray[pos]:02x}" + " 1=" + f"{byteArray[pos+1]:02x}" + " 2=" + f"{byteArray[pos+2]:02x}" + " 3=" + f"{byteArray[pos+3]:02x}") + try: + result = byteArray[pos+2] * 0x01000000 + byteArray[pos+3] * 0x00010000 + byteArray[pos] * 0x00000100 + byteArray[pos+1] + except: + return 0 +# self.log_debug("buf2int32US r=" + str(result)) + return result + + def now_str(self): + return self.now().strftime("%d.%m.%Y, %H:%M:%S") + + def get_inverter_name(self,batt,type): + # Bestimmt den Namen des Wechselrichters. + # Das Mapping wurde Be_Connect (Hauptseite Setup) entnommen. + if batt == "LVS": # LVS + if type == 0: + return byd_inverters[0] # Fronius HV + elif (type == 1) or (type == 2): + return byd_inverters[1] # Goodwe HV/Viessmann HV + elif type == 3: + return byd_inverters[2] # KOSTAL HV + elif type == 4: + return byd_inverters[18] # Selectronic LV + elif type == 5: + return byd_inverters[3] # SMA SBS3.7/5.0/6.0 HV + elif type == 6: + return byd_inverters[19] # SMA LV + elif type == 7: + return byd_inverters[20] # Victron LV + elif type == 8: + return byd_inverters[30] # Suntech LV + elif type == 9: + return byd_inverters[4] # Sungrow HV + elif type == 10: + return byd_inverters[5] # KACO_HV + elif type == 11: + return byd_inverters[21] # Studer LV + elif type == 12: + return byd_inverters[28] # SolarEdge LV + elif type == 13: + return byd_inverters[6] # Ingeteam HV + elif batt == "HVL": # HVL + if type == 0: + return byd_inverters[1] + elif type == 1: + return byd_inverters[3] + elif type == 2: + return byd_inverters[8] + elif type == 3: + return byd_inverters[10] + elif type == 4: + return byd_inverters[17] + else: # HVM, HVS + if (type >= 0) and (type <= 16): + return byd_inverters[type] + return "unknown" + + def round_decimal(self,decimal_number,base,rounding=ROUND_DOWN): + """ + Round decimal number to the nearest base + : param decimal_number: decimal number to round to the nearest base + : type decimal_number: Decimal + : param base: rounding base, e.g. 5, Decimal('0.05') + : type base: int or Decimal + : param rounding: Decimal rounding type + : rtype: Decimal + """ +# return base * Decimal(decimal_number / base).quantize(1,rounding=rounding) + return float(base * (Decimal(decimal_number) / base).quantize(1,rounding=rounding)) + +# ----------------------------------------------------------------------- +# Webinterface +# ----------------------------------------------------------------------- # webinterface init method def init_webinterface(self): @@ -1291,6 +3148,10 @@ def init_webinterface(self): return True +# ----------------------------------------------------------------------- +# Simulations-Routinen +# ----------------------------------------------------------------------- + def simulate_data(self): # For internal tests only @@ -1331,4 +3192,8 @@ def simulate_data(self): # self.log_info("xx=" + str(xx) + " v=" + str(self.byd_temp_cell[1][xx])) self.diag_plot(twr) + +# ----------------------------------------------------------------------- +# ENDE +# ----------------------------------------------------------------------- \ No newline at end of file diff --git a/byd_bat/locale.yaml b/byd_bat/locale.yaml index 58de3c1a0..e8789cec3 100644 --- a/byd_bat/locale.yaml +++ b/byd_bat/locale.yaml @@ -5,6 +5,9 @@ plugin_translations: 'BYD Diagnose': {'de': '=', 'en': 'BYD Diagnostics'} 'BYD Spannungen': {'de': '=', 'en': 'BYD Voltages'} 'BYD Temperaturen': {'de': '=', 'en': 'BYD Temperatures'} + 'BYD Log-Daten': {'de': '=', 'en': 'BYD Log data'} + + 'Verbindung': {'de': '=', 'en': 'Connection'} 'Laden': {'de': '=', 'en': 'Loading'} 'Gesamtkapazität': {'de': '=', 'en': 'Total capacity'} @@ -34,13 +37,24 @@ plugin_translations: 'Parameter': {'de': '=', 'en': 'Parameter'} 'Fehler': {'de': '=', 'en': 'Error'} + 'Turm': {'de': '=', 'en': 'Tower'} 'Batteriespannung': {'de': '=', 'en': 'Batteryvoltage'} 'Spannung Out': {'de': '=', 'en': 'Voltage Out'} 'Strom': {'de': '=', 'en': 'Current'} 'Spannung max (Zelle)': {'de': '=', 'en': 'Voltage max (cell)'} 'Spannung min (Zelle)': {'de': '=', 'en': 'Voltage min (cell)'} + 'Spannung Differenz': {'de': '=', 'en': 'Voltage difference'} 'Temperatur max (Zelle)': {'de': '=', 'en': 'Temperature max (cell)'} 'Temperatur min (Zelle)': {'de': '=', 'en': 'Temperature min (cell)'} + 'Balancing Anzahl Zellen': {'de': '=', 'en': 'Balancing number of cells'} + 'Status': {'de': '=', 'en': 'State'} + 'Laden total': {'de': '=', 'en': 'Charge total'} + 'Entladen total': {'de': '=', 'en': 'Discharge total'} + 'Wirkungsgrad': {'de': '=', 'en': 'Efficiency'} + + 'Spannung minimal': {'de': '=', 'en': 'Voltage min'} + 'Spannung maximal': {'de': '=', 'en': 'Voltage max'} + 'Spannung Durchschnitt': {'de': '=', 'en': 'Voltage average'} # Alternative format for translations of longer texts: 'Hier kommt der Inhalt des Webinterfaces hin.': diff --git a/byd_bat/plugin.yaml b/byd_bat/plugin.yaml index 66349d240..d7c5585ca 100644 --- a/byd_bat/plugin.yaml +++ b/byd_bat/plugin.yaml @@ -12,7 +12,7 @@ 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.7 # Plugin version (must match the version specified in __init__.py) + version: 0.0.8 # 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.9 # minimum Python version to use for this plugin @@ -36,37 +36,66 @@ parameters: description: de: "Pfad fuer Heatmap-Bilder (z.Bsp. fuer smartvisu)" en: "Path for heatmap images (e.g. for smartvisu)" + + diag_cycle: + type: num + default: 300 + description: + de: "Abfrage-Zyklus fuer die Diagnosedaten (>=60s)" + en: "Query cycle for diagnostic data (>=60s)" + + log_data: + type: bool + default: false + description: + de: "Abfrage der Log-Daten" + en: "get the log data" + log_age: + type: num + default: 365 + description: + de: "Aufbewahrungsdauer der Log-Dateien in Tagen (0=kein Löschen)" + en: "Retention period of the log files in days (0=no deletion)" + item_attributes: byd_root: # only used internally - do not use for own items ! type: bool - mandatory: True + mandatory: true description: de: 'Root-Flag fuer das Plugin' en: 'Root-Flag for plugin' + byd_para: + type: bool + default: off + description: + de: 'Interner Parameter' + en: 'Internal parameter' + item_structs: byd_struct: - byd_root: true # must stay here - used by the plugin internally - do not remove ! + byd_root: true # Must stay here - used by the plugin internally - do not remove ! info: - connection: # shows connection status of plugin to battery + connection: # Shows connection status of plugin to battery type: bool initial_value: false enforce_updates: true visu_acl: ro - enable_connection: + enable_connection: # true -> communication enabled, false -> communication disabled (other software can access BYD unit) type: bool initial_value: true enforce_updates: true visu_acl: rw + byd_para: true - state: + state: # State of the BYD system (1 or more towers) current: # [A] Charge / Discharge Current type: num @@ -83,17 +112,17 @@ item_structs: visu_acl: ro database: init - power_discharge: # [W] Charge discharging + power_discharge: # [W] Power discharging type: num visu_acl: ro database: init - soc: # [%] SOC + soc: # [%] SOC (State of Charge) type: num visu_acl: ro database: init - soh: # [%] SOH + soh: # [%] SOH (State of Health) type: num visu_acl: ro database: init @@ -138,24 +167,39 @@ item_structs: visu_acl: ro database: init - system: + charge_total: # [kWh] Total charge + type: num + visu_acl: ro + database: init + + discharge_total: # [kWh] Total discharge + type: num + visu_acl: ro + database: init + + eta: # [%] ETA (Efficiency) + type: num + visu_acl: ro + database: init + + system: # Informations about the BYD system - bms: # F/W BMS + bms: # Firmware BMS Battery Management System type: str cache: true visu_acl: ro - bmu: # F/W BMU + bmu: # Firmware BMU Battery Management Unit type: str cache: true visu_acl: ro - bmubanka: # F/W BMU-BankA + bmubanka: # Firmware BMU-BankA type: str cache: true visu_acl: ro - bmubankb: # F/W BMU-BankB + bmubankb: # Firmware BMU-BankB type: str cache: true visu_acl: ro @@ -185,12 +229,12 @@ item_structs: cache: true visu_acl: ro - modules: # modules (count) + modules: # Modules (count per tower) type: num cache: true visu_acl: ro - bmsqty: # tours (count) + bmsqty: # Towers (count) type: num cache: true visu_acl: ro @@ -200,12 +244,12 @@ item_structs: cache: true visu_acl: ro - paramt: # F/W BMU + paramt: # Firmware BMU (?) type: str cache: true visu_acl: ro - serial: # Serial number + serial: # Serial number (master) type: str cache: true visu_acl: ro @@ -219,12 +263,17 @@ item_structs: visu_acl: ro database: init - bat_voltag: # BAT Voltage [V] + soh: # [%] SOH + type: num + visu_acl: ro + database: init + + bat_voltag: # Battery Voltage [V] type: num visu_acl: ro database: init - v_out: # V-Out [V] + v_out: # Voltage Out [V] type: num visu_acl: ro database: init @@ -234,6 +283,11 @@ item_structs: visu_acl: ro database: init + volt_diff: # Voltage difference (Max-Min) [mV] + type: num + visu_acl: ro + database: init + volt_max: volt: # max voltage [V] @@ -281,6 +335,177 @@ item_structs: type: num visu_acl: ro database: init + + charge_total: # [kWh] Total charge + type: num + visu_acl: ro + database: init + + discharge_total: # [kWh] Total discharge + type: num + visu_acl: ro + database: init + + balancing: # Data about the balancing of this tower + + active: # true -> 1 or more cells balancing, false -> no cell balancing + type: bool + visu_acl: ro + database: init + + number: # number of cells currently balancing + type: num + visu_acl: ro + database: init + + state: # State of the tower + + raw: # State of the tower (16 Bit, see byd_stat_tower in __init__.py) + type: num + visu_acl: ro + database: init + + str: # State as text (english) + type: str + visu_acl: ro + + modules: # Data for each module of the tower + m1: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m2: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m3: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m4: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m5: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m6: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m7: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m8: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true tower2: @@ -289,12 +514,17 @@ item_structs: visu_acl: ro database: init - bat_voltag: # BAT Voltage [V] + soh: # [%] SOH + type: num + visu_acl: ro + database: init + + bat_voltag: # Battery Voltage [V] type: num visu_acl: ro database: init - v_out: # V-Out [V] + v_out: # Voltage Out [V] type: num visu_acl: ro database: init @@ -304,6 +534,11 @@ item_structs: visu_acl: ro database: init + volt_diff: # Voltage difference (Max-Min) [mV] + type: num + visu_acl: ro + database: init + volt_max: volt: # max voltage [V] @@ -352,6 +587,177 @@ item_structs: visu_acl: ro database: init + charge_total: # [kWh] Total charge + type: num + visu_acl: ro + database: init + + discharge_total: # [kWh] Total discharge + type: num + visu_acl: ro + database: init + + balancing: # Data about the balancing of this tower + + active: # true -> 1 or more cells balancing, false -> no cell balancing + type: bool + visu_acl: ro + database: init + + number: # number of cells currently balancing + type: num + visu_acl: ro + database: init + + state: # State of the tower + + raw: # State of the tower (16 Bit, see byd_stat_tower in __init__.py) + type: num + visu_acl: ro + database: init + + str: # State as text (english) + type: str + visu_acl: ro + + modules: # Data for each module of the tower + m1: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m2: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m3: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m4: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m5: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m6: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m7: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m8: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + tower3: soc: # [%] SOC @@ -359,12 +765,17 @@ item_structs: visu_acl: ro database: init - bat_voltag: # BAT Voltage [V] + soh: # [%] SOH + type: num + visu_acl: ro + database: init + + bat_voltag: # Battery Voltage [V] type: num visu_acl: ro database: init - v_out: # V-Out [V] + v_out: # Voltage Out [V] type: num visu_acl: ro database: init @@ -373,6 +784,11 @@ item_structs: type: num visu_acl: ro database: init + + volt_diff: # Voltage difference (Max-Min) [mV] + type: num + visu_acl: ro + database: init volt_max: @@ -422,6 +838,239 @@ item_structs: visu_acl: ro database: init + charge_total: # [kWh] Total charge + type: num + visu_acl: ro + database: init + + discharge_total: # [kWh] Total discharge + type: num + visu_acl: ro + database: init + + balancing: # Data about the balancing of this tower + + active: # true -> 1 or more cells balancing, false -> no cell balancing + type: bool + visu_acl: ro + database: init + + number: # number of cells currently balancing + type: num + visu_acl: ro + database: init + + state: # State of the tower + + raw: # State of the tower (16 Bit, see byd_stat_tower in __init__.py) + type: num + visu_acl: ro + database: init + + str: # State as text (english) + type: str + visu_acl: ro + + modules: # Data for each module of the tower + m1: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m2: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m3: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m4: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m5: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m6: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m7: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + m8: + v_min: # min voltage [V] + type: num + visu_acl: ro + cache: true + v_max: # max voltage [V] + type: num + visu_acl: ro + cache: true + v_av: # average voltage [V] + type: num + visu_acl: ro + cache: true + v_diff: # voltage difference (min-max) [mV] + type: num + visu_acl: ro + cache: true + + visu: # Items for the visualisation (e.g. smartVISU) + + bmu_log: # Logd data from BMU + + log_html: # HTML table with Log-Data (smartVISU: basic.print) + + type: str + visu_acl: ro + cache: true + + log_jsonlist: # Json list with Log-Data (smartVISU: status.activelist) + + type: list + initial_value: [] + visu_acl: ro + cache: true + + tower1_log: # Log data frm BMS Tower 1 + + log_html: # HTML table with Log-Data (smartVISU: basic.print) + + type: str + visu_acl: ro + cache: true + + log_jsonlist: # Json list with Log-Data (smartVISU: status.activelist) + + type: list + initial_value: [] + visu_acl: ro + cache: true + + tower2_log: # Log data frm BMS Tower 2 + + log_html: # HTML table with Log-Data (smartVISU: basic.print) + + type: str + visu_acl: ro + cache: true + + log_jsonlist: # Json list with Log-Data (smartVISU: status.activelist) + + type: list + initial_value: [] + visu_acl: ro + cache: true + + tower3_log: # Log data frm BMS Tower 3 + + log_html: # HTML table with Log-Data (smartVISU: basic.print) + + type: str + visu_acl: ro + cache: true + + log_jsonlist: # Json list with Log-Data (smartVISU: status.activelist) + + type: list + initial_value: [] + visu_acl: ro + cache: true + logic_parameters: NONE plugin_functions: NONE diff --git a/byd_bat/user_doc.rst b/byd_bat/user_doc.rst index 1b2850071..c7aec3220 100644 --- a/byd_bat/user_doc.rst +++ b/byd_bat/user_doc.rst @@ -12,27 +12,49 @@ byd_bat :scale: 50 % :align: left -Anzeigen von Parametern eines BYD Energiespeichers. Die Parameter entsprechen den Daten, die in der Software Be_Connect_Plus_V2.0.2 angezeigt werden. +Mit Hilfe dieses Plugins können diverse Daten aus einem BYD Energiespeicher ausgelesen werden. Die Parameter entsprechen den Daten, die in der Software "Be_Connect_Plus" von BYD angezeigt werden. -Es werden 1-3 Türme unterstützt. +Es werden 1-3 Türme und die Batteriesysteme HVS, HVM und LVS unterstützt. -Die Grunddaten werden alle 60 Sekunden aktualisiert. Die Diagnosedaten werden beim Start des Plugin und gemäss dem Parameter 'diag_cycle' abgerufen. +Das Plugin benötigt nur ein Item mit der folgenden Deklaration: -Die Spannungen und Temperaturen in den Modulen werden mit Hilfe von Heatmaps dargestellt. Diese werden im Web Interface angezeigt. Zusätzlich können diese Bilder auch in ein weiteres Verzeichnis kopiert werden (z.Bsp. für smartvisu). +byd: + struct: byd_bat.byd_struct -Das Plugin benoetigt nur ein Item mit der folgenden Deklaration: +Alle verfügbaren Daten werden im Struct 'byd_struct' bereitgestellt. Diverse Parameter besitzen bereits die Eigenschaft 'database: init', so dass die Daten für die Visualisierung (z.Bsp. in smartVISU) bereitgestellt werden. -.. code-block:: yaml +Die Grunddaten des Systems werden alle 60 Sekunden aktualisiert. Die Diagnosedaten werden beim Start des Plugins und gemäss dem Parameter 'diag_cycle' abgerufen. - byd: - struct: byd_bat.byd_struct +Der BYD Energiespeicher akzeptiert nur 1 Verbindung gleichzeitig. Mit dem Item 'byd.enable_connection' kann die Verbindung pausiert werden. Im Web Interface ist dieses Item ebenfalls vorhanden. -Alle verfügbaren Daten werden im Struct 'byd_struct' bereitgestellt. Diverse Parameter besitzen bereits die Eigenschaft 'database: init', so dass die Daten für die Visualisierung bereitgestellt werden. +Die Log-Daten werden alle 300 Sekunden abgerufen, wenn der Parameter 'log_data' auf 'true' gesetzt ist. Die Logdaten werden in den Items 'visu/...' als HTML-Tabellen oder JSON-Daten bereitgestellt. Diese Items können in smartVISU wie folgt dargestellt werden: + +HTML-Tabelle: + + {{ basic.print('','byd.visu.bmu_log.log_html','html') }} + {{ basic.print('','byd.visu.tower1_log.log_html','html') }} + +JSON-Daten: + + {{ status.activelist('','byd.visu.bmu_log.log_jsonlist','title','date','content','level') }} + {{ status.activelist('','byd.visu.tower1_log.log_jsonlist','title','date','content','level') }} + +Zusätzlich werden die Log-Daten tageweise in Logdateien im Verzeichnis 'var/log/byd_logs' gespeichert. Der Parameter 'log_age' definiert, wie viele Tage die Logs gespeichert bleiben sollen. + +Das Plugin generiert aus den Spannungs- und Temperaturwerten für jeden Turm Plots als Bitmap-Dateien (in den folgenden Dateinamen ist X = Nummer des Turms [1-3]): + + * bydvtX.png : Spannungen Heatmap + * bydvbtX.png : Spannungen Balkendiagramm + * bydttX.png : Temperaturen Heatmap + +Diese Plots werden im Web Interface angezeigt. Zusätzlich können diese Bilder auch in ein weiteres Verzeichnis kopiert werden (z.Bsp. für smartVISU, siehe Parameter 'imgpath'). + +Die Änderungen im Plugin sind am Anfang der Datei '__init__.py' im Abschnitt 'History' dokumentiert. Anforderungen ============= -Der BYD Energiespeicher muss mit dem LAN verbunden sind. Die IP-Adresse des BYD wird über DHCP zugewiesen und muss ermittelt werden. Diese IP-Adresse muss in der Plugin-Konfiguration gespeichert werden. +Der BYD Energiespeicher muss mit dem LAN verbunden sind. Die IP-Adresse des BYD wird über DHCP zugewiesen und muss ermittelt werden. Diese IP-Adresse muss in der Plugin-Konfiguration gespeichert werden. In Systemen mit mehr als 1 Turm wird nur der Master mit dem LAN verbunden. Notwendige Software ------------------- @@ -42,14 +64,13 @@ Notwendige Software Unterstützte Geräte ------------------- -Folgende Typen werden unterstützt: +Folgende BYD-Typen werden unterstützt: * HVS (noch nicht getestet) * HVM (getestet mit HVM 19.3kWh und 2 Türmen) -* HVL (noch nicht getestet) * LVS (noch nicht getestet) -Bitte Debug-Daten (level: DEBUG) von noch nicht getesteten BYD Energiespeichern an Plugin-Autor senden. Beim Start von smarthomeng werden die Diagnosedaten sofort ermittelt. +Bitte Debug-Daten (level: DEBUG) von noch nicht getesteten BYD Energiespeichern an Plugin-Autor senden. Beim Start von SmartHomeNG werden die Diagnosedaten sofort ermittelt. Konfiguration ============= @@ -65,7 +86,10 @@ Ein Web Interface ist implementiert und zeigt die eingelesenen Daten an. Beispiele ========= -Oben rechts werden die wichtigsten Daten zum BYD Energiespeicher angezeigt. +Oben rechts werden die wichtigsten Daten zum BYD Energiespeicher angezeigt. Mit dem Schalter "Verbindung" kann die Kommunikation mit dem Energiespeicher pausiert werden, um beispielsweise mit einer anderen Software auf das System zugreifen zu können. + +.. image:: assets/base.png + :class: screenshot Im Tab "BYD Home" sind die Grunddaten des Energiespeichers dargestellt: @@ -77,7 +101,7 @@ Im Tab "BYD Diagnose" werden Diagnosedaten angezeigt: .. image:: assets/diag.png :class: screenshot -Im Tab "BYD Spannungen" werden die Spannungen der Module als Heatmap angezeigt: +Im Tab "BYD Spannungen" werden die Spannungen der Module als Plot angezeigt: .. image:: assets/volt.png :class: screenshot @@ -86,3 +110,8 @@ Im Tab "BYD Temperaturen" werden die Temperaturen der Module als Heatmap angezei .. image:: assets/temp.png :class: screenshot + +Im Tab "BYD Log-Daten" werden die Log-Daten angezeigt: + +.. image:: assets/logdata.png + :class: screenshot From 3cf7e50928b5bdc5423397e8284fe9a0e8dc4c35 Mon Sep 17 00:00:00 2001 From: lgb-this Date: Fri, 12 Jan 2024 17:09:19 +0100 Subject: [PATCH 2/5] Release 0.0.8 - modifications see '__init__.py' --- byd_bat/webif/__init__.py | 260 +++++++++++++++++++++++++++----------- 1 file changed, 183 insertions(+), 77 deletions(-) diff --git a/byd_bat/webif/__init__.py b/byd_bat/webif/__init__.py index 90c65a066..8e1319e9d 100644 --- a/byd_bat/webif/__init__.py +++ b/byd_bat/webif/__init__.py @@ -41,10 +41,9 @@ import csv from jinja2 import Environment, FileSystemLoader - class WebInterface(SmartPluginWebIf): - def __init__(self, webif_dir, plugin): + def __init__(self,webif_dir,plugin): """ Initialization of instance of class WebInterface @@ -61,7 +60,7 @@ def __init__(self, webif_dir, plugin): self.tplenv = self.init_template_environment() @cherrypy.expose - def index(self, reload=None): + def index(self,reload=None): """ Build index.html for cherrypy @@ -78,7 +77,7 @@ def index(self, reload=None): item_count=0) @cherrypy.expose - def get_data_html(self, dataSet=None): + def get_data_html(self,dataSet=None): """ Return data to update the webpage @@ -87,89 +86,196 @@ def get_data_html(self, dataSet=None): :param dataSet: Dataset for which the data should be returned (standard: None) :return: dict with the data needed to update the web page. """ + # get the new data data = {} + + data['batttype'] = self.plugin.byd_batt_str data['bydip'] = self.plugin.ip - data['imppath'] = self.plugin.bpath + data['soc'] = f'{self.plugin.byd_soc:.1f}' + " %" + data['capacity_total'] = f'{self.plugin.byd_capacity_total:.2f}' + " kWh" + data['power_charge'] = f'{self.plugin.byd_power_charge:.1f}' + " W" + data['power_discharge'] = f'{self.plugin.byd_power_discharge:.1f}' + " W" data['last_homedata'] = self.plugin.last_homedata data['last_diagdata'] = self.plugin.last_diagdata + data['imppath'] = self.plugin.bpath + +# self.logger.warning("c=" + str(self.plugin.byd_root.enable_connection())) + data['connection'] = self.plugin.byd_root.enable_connection() - data['current'] = f'{self.plugin.byd_current:.1f}' + " A" - data['power'] = f'{self.plugin.byd_power:.1f}' + " W" - data['power_charge'] = f'{self.plugin.byd_power_charge:.1f}' + " W" - data['power_discharge'] = f'{self.plugin.byd_power_discharge:.1f}' + " W" - data['soc'] = f'{self.plugin.byd_soc:.1f}' + " %" - data['soh'] = f'{self.plugin.byd_soh:.1f}' + " %" - data['tempbatt'] = f'{self.plugin.byd_temp_bat:.1f}' + " °C" - data['tempmax'] = f'{self.plugin.byd_temp_max:.1f}' + " °C" - data['tempmin'] = f'{self.plugin.byd_temp_min:.1f}' + " °C" - data['voltbatt'] = f'{self.plugin.byd_volt_bat:.1f}' + " V" - data['voltdiff'] = f'{self.plugin.byd_volt_diff:.3f}' + " V" - data['voltmax'] = f'{self.plugin.byd_volt_max:.3f}' + " V" - data['voltmin'] = f'{self.plugin.byd_volt_min:.3f}' + " V" - data['voltout'] = f'{self.plugin.byd_volt_out:.1f}' + " V" + for xx in range(1,self.plugin.byd_towers_max+1): + tx = 't' + str(xx) + '_' + if xx <= self.plugin.byd_bms_qty: + # Turm ist vorhanden + data[tx + 'log_html'] = self.plugin.byd_diag_bms_log_html[xx] + else: + # Turm nicht vorhanden + data[tx + 'log_html'] = "" + + # 1.Register "BYD Home" + t = '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '
SOC:' + f'{self.plugin.byd_soc:.1f}' + ' %' + '
SOH:' + f'{self.plugin.byd_soh:.1f}' + ' %' + '
' + self.translate("Leistung") + ':' + f'{self.plugin.byd_power:.1f}' + ' W' + '
' + self.translate("Ladeleistung") + ':' + f'{self.plugin.byd_power_charge:.1f}' + ' W' + '
' + self.translate("Entladeleistung") + ':' + f'{self.plugin.byd_power_discharge:.1f}' + ' W' + '
' + self.translate("Spannung Ausgang") + ':' + f'{self.plugin.byd_volt_out:.1f}' + ' V' + '
' + self.translate("Strom Ausgang") + ':' + f'{self.plugin.byd_current:.1f}' + ' A' + '
' + self.translate("Spannung Batterie") + ':' + f'{self.plugin.byd_volt_bat:.1f}' + ' V' + '
' + self.translate("Spannung Batteriezellen max") + ':' + f'{self.plugin.byd_volt_max:.3f}' + ' V' + '
' + self.translate("Spannung Batteriezellen min") + ':' + f'{self.plugin.byd_volt_min:.3f}' + ' V' + '
' + self.translate("Spannung Batteriezellen Differenz") + ':' + f'{self.plugin.byd_volt_diff * 1000:.1f}' + ' mV' + '
' + self.translate("Temperatur Batterie") + ':' + f'{self.plugin.byd_temp_bat:.1f}' + ' °C' + '
' + self.translate("Temperatur Batterie max") + ':' + f'{self.plugin.byd_temp_max:.1f}' + ' °C' + '
' + self.translate("Temperatur Batterie min") + ':' + f'{self.plugin.byd_temp_min:.1f}' + ' °C' + '
' + self.translate("Laden total") + ':' + f'{self.plugin.byd_charge_total:.1f}' + ' kWh' + '
' + self.translate("Entladen total") + ':' + f'{self.plugin.byd_discharge_total:.1f}' + ' kWh' + '
' + self.translate("Wirkungsgrad") + ':' + f'{self.plugin.byd_eta:.1f}' + ' %' + '
' + data['r1_table'] = t - data['bms'] = self.plugin.byd_bms - data['bmu'] = self.plugin.byd_bmu - data['bmubanka'] = self.plugin.byd_bmu_a - data['bmubankb'] = self.plugin.byd_bmu_b - data['batttype'] = self.plugin.byd_batt_str - data['errorstr'] = self.plugin.byd_error_str + " (" + str(self.plugin.byd_error_nr) + ")" - data['grid'] = self.plugin.byd_application - data['invtype'] = self.plugin.byd_inv_str - data['modules'] = str(self.plugin.byd_modules) - data['bmsqty'] = str(self.plugin.byd_bms_qty) - data['capacity_total'] = f'{self.plugin.byd_capacity_total:.2f}' + " kWh" - data['paramt'] = self.plugin.byd_param_t - data['serial'] = self.plugin.byd_serial + t = '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '' + '' + '' + t = t + '
' + self.translate("Wechselrichter") + ':' + self.plugin.byd_inv_str + '
' + self.translate("Batterietyp") + ':' + self.plugin.byd_batt_str + '
' + self.translate("Seriennummer") + ':' + self.plugin.byd_serial + '
' + self.translate("Türme") + ':' + str(self.plugin.byd_bms_qty) + '
' + self.translate("Module pro Turm") + ':' + str(self.plugin.byd_modules) + '
' + self.translate("Parameter") + ':' + self.plugin.byd_application + '
' + self.translate("Fehler") + ':' + self.plugin.byd_error_str + " (" + str(self.plugin.byd_error_nr) + ")" + '
' + 'BMS' + ':' + self.plugin.byd_bmu + '
' + 'BMU' + ':' + self.plugin.byd_bms + '
' + 'BMU A' + ':' + self.plugin.byd_bmu_a + '
' + 'BMU B' + ':' + self.plugin.byd_bmu_b + '
' + 'P/T' + ':' + self.plugin.byd_param_t + '
' + data['r2_table'] = t - data['t1_soc'] = f'{self.plugin.byd_diag_soc[1]:.1f}' + " %" - data['t1_bat_voltag'] = f'{self.plugin.byd_diag_bat_voltag[1]:.1f}' + " V" - data['t1_v_out'] = f'{self.plugin.byd_diag_v_out[1]:.1f}' + " V" - data['t1_current'] = f'{self.plugin.byd_diag_current[1]:.1f}' + " A" - data['t1_volt_max'] = f'{self.plugin.byd_diag_volt_max[1]:.3f}' + " V (" + str(self.plugin.byd_diag_volt_max_c[1]) + ")" - data['t1_volt_min'] = f'{self.plugin.byd_diag_volt_min[1]:.3f}' + " V (" + str(self.plugin.byd_diag_volt_min_c[1]) + ")" - data['t1_temp_max'] = f'{self.plugin.byd_diag_temp_max[1]:.1f}' + " V (" + str(self.plugin.byd_diag_temp_max_c[1]) + ")" - data['t1_temp_min'] = f'{self.plugin.byd_diag_temp_min[1]:.1f}' + " V (" + str(self.plugin.byd_diag_temp_min_c[1]) + ")" + # 2.Register "BYD Diagnose" + ds = [] + for xx in range(1,self.plugin.byd_towers_max+1): + ts = [] + if xx <= self.plugin.byd_bms_qty: + # Turm ist vorhanden + ts.append(['SOC',f'{self.plugin.byd_diag_soc[xx]:.1f}' + " %"]) + ts.append(['SOH',f'{self.plugin.byd_diag_soh[xx]:.1f}' + " %"]) + ts.append([self.translate("Batteriespannung"),f'{self.plugin.byd_diag_bat_voltag[xx]:.1f}' + " V"]) + ts.append([self.translate("Spannung Out"),f'{self.plugin.byd_diag_v_out[xx]:.1f}' + " V"]) + ts.append([self.translate("Strom"),f'{self.plugin.byd_diag_current[xx]:.1f}' + " A"]) + ts.append([self.translate("Spannung max (Zelle)"),f'{self.plugin.byd_diag_volt_max[xx]:.3f}' + " V (" + str(self.plugin.byd_diag_volt_max_c[xx]) + ")"]) + ts.append([self.translate("Spannung min (Zelle)"),f'{self.plugin.byd_diag_volt_min[xx]:.3f}' + " V (" + str(self.plugin.byd_diag_volt_min_c[xx]) + ")"]) + ts.append([self.translate("Spannung Differenz"),f'{self.plugin.byd_diag_volt_diff[xx]:.0f}' + " mV"]) + ts.append([self.translate("Temperatur max (Zelle)"),f'{self.plugin.byd_diag_temp_max[xx]:.1f}' + " V (" + str(self.plugin.byd_diag_temp_max_c[xx]) + ")"]) + ts.append([self.translate("Temperatur min (Zelle)"),f'{self.plugin.byd_diag_temp_min[xx]:.1f}' + " V (" + str(self.plugin.byd_diag_temp_min_c[xx]) + ")"]) + ts.append([self.translate("Laden total"),f'{self.plugin.byd_diag_charge_total[xx]:.3f}' + " kWh"]) + ts.append([self.translate("Entladen total"),f'{self.plugin.byd_diag_discharge_total[xx]:.3f}' + " kWh"]) + ts.append([self.translate("Balancing Anzahl Zellen"),f'{self.plugin.byd_diag_balance_number[xx]:.0f}']) + else: + for ii in range(0,13): + ts.append(['','']) + ds.append(ts) + + t = '' + t = t + '' + t = t + '' + if self.plugin.byd_bms_qty > 1: + t = t + '' + if self.plugin.byd_bms_qty > 2: + t = t + '' + t = t + '' + t = t + '' + for ii in range(0,13): + t = t + self.table_diag_row(ds[0][ii][0],ds[0][ii][1],ds[1][ii][1],ds[2][ii][1]) + t = t + '
' + self.translate("Turm") + ' 1' + self.translate("Turm") + ' 2' + self.translate("Turm") + ' 3
' + data['r3_table'] = t + + t = '

' + self.translate("Turm") + ' 1 BMS

' + t = t + self.table_diag_details(1) + t = t + '

' + self.translate("Status") + ': ' + self.plugin.byd_diag_state_str[1] + ' (0x' + f'{self.plugin.byd_diag_state[1]:04x}' + ')

' + if self.plugin.byd_bms_qty > 1: + t = t + '

' + t = t + '

' + self.translate("Turm") + ' 2 BMS

' + t = t + self.table_diag_details[2] + t = t + '

' + self.translate("Status") + ': ' + self.plugin.byd_diag_state_str[2] + ' (0x' + f'{self.plugin.byd_diag_state[2]:04x}' + ')

' + if self.plugin.byd_bms_qty > 2: + t = t + '

' + t = t + '

' + self.translate("Turm") + ' 3 BMS

' + t = t + self.table_diag_details[3] + t = t + '

' + self.translate("Status") + ': ' + self.plugin.byd_diag_state_str[3] + ' (0x' + f'{self.plugin.byd_diag_state[3]:04x}' + ')

' + data['r4_table'] = t + + # 5.Register "BYD Logdaten" + t = '

BMU

' + t = t + self.plugin.byd_bmu_log_html + t = t + '

' + t = t + '

' + self.translate("Turm") + ' 1 BMS

' + t = t + self.plugin.byd_diag_bms_log_html[1] if self.plugin.byd_bms_qty > 1: - data['t2_soc'] = f'{self.plugin.byd_diag_soc[2]:.1f}' + " %" - data['t2_bat_voltag'] = f'{self.plugin.byd_diag_bat_voltag[2]:.1f}' + " V" - data['t2_v_out'] = f'{self.plugin.byd_diag_v_out[2]:.1f}' + " V" - data['t2_current'] = f'{self.plugin.byd_diag_current[2]:.1f}' + " A" - data['t2_volt_max'] = f'{self.plugin.byd_diag_volt_max[2]:.3f}' + " V (" + str(self.plugin.byd_diag_volt_max_c[2]) + ")" - data['t2_volt_min'] = f'{self.plugin.byd_diag_volt_min[2]:.3f}' + " V (" + str(self.plugin.byd_diag_volt_min_c[2]) + ")" - data['t2_temp_max'] = f'{self.plugin.byd_diag_temp_max[2]:.1f}' + " V (" + str(self.plugin.byd_diag_temp_max_c[2]) + ")" - data['t2_temp_min'] = f'{self.plugin.byd_diag_temp_min[2]:.1f}' + " V (" + str(self.plugin.byd_diag_temp_min_c[2]) + ")" - else: - data['t2_soc'] = "-" - data['t2_bat_voltag'] = "-" - data['t2_v_out'] = "-" - data['t2_current'] = "-" - data['t2_volt_max'] = "-" - data['t2_volt_min'] = "-" - data['t2_temp_max'] = "-" - data['t2_temp_min'] = "-" - if self.plugin.byd_bms_qty > 2: - data['t3_soc'] = f'{self.plugin.byd_diag_soc[3]:.1f}' + " %" - data['t3_bat_voltag'] = f'{self.plugin.byd_diag_bat_voltag[3]:.1f}' + " V" - data['t3_v_out'] = f'{self.plugin.byd_diag_v_out[3]:.1f}' + " V" - data['t3_current'] = f'{self.plugin.byd_diag_current[3]:.1f}' + " A" - data['t3_volt_max'] = f'{self.plugin.byd_diag_volt_max[3]:.3f}' + " V (" + str(self.plugin.byd_diag_volt_max_c[3]) + ")" - data['t3_volt_min'] = f'{self.plugin.byd_diag_volt_min[3]:.3f}' + " V (" + str(self.plugin.byd_diag_volt_min_c[3]) + ")" - data['t3_temp_max'] = f'{self.plugin.byd_diag_temp_max[3]:.1f}' + " V (" + str(self.plugin.byd_diag_temp_max_c[3]) + ")" - data['t3_temp_min'] = f'{self.plugin.byd_diag_temp_min[3]:.1f}' + " V (" + str(self.plugin.byd_diag_temp_min_c[3]) + ")" - else: - data['t3_soc'] = "-" - data['t3_bat_voltag'] = "-" - data['t3_v_out'] = "-" - data['t3_current'] = "-" - data['t3_volt_max'] = "-" - data['t3_volt_min'] = "-" - data['t3_temp_max'] = "-" - data['t3_temp_min'] = "-" - - # return it as json the the web page + t = t + '

' + t = t + '

' + self.translate("Turm") + ' 2 BMS

' + t = t + self.plugin.byd_diag_bms_log_html[2] + if self.plugin.byd_bms_qty > 2: + t = t + '

' + t = t + '

' + self.translate("Turm") + ' 3 BMS

' + t = t + self.plugin.byd_diag_bms_log_html[3] + data['r5_table'] = t + +# self.logger.warning("done done") + + # return it as json to the web page try: return json.dumps(data) except Exception as e: self.logger.error("get_data_html exception: {}".format(e)) + + def table_diag_row(self,title,s1,s2,s3): + s = '' + s = s + '' + title + ':' + s = s + '' + s1 + '' + if self.plugin.byd_bms_qty > 1: + s = s + '' + s2 + '' + if self.plugin.byd_bms_qty > 2: + s = s + '' + s3 + '' + s = s + '' + return s + + def table_diag_details(self,xx): + t = '' + t = t + '''' + for i in range(0,self.plugin.byd_modules): + t = t + '' + t = t + '' + t = t + self.table_diag_details_row(self.translate("Spannung minimal") + ' [V]',xx,self.plugin.byd_module_vmin,3) + t = t + self.table_diag_details_row(self.translate("Spannung maximal") + ' [V]',xx,self.plugin.byd_module_vmax,3) + t = t + self.table_diag_details_row(self.translate("Spannung Durchschnitt") + ' [V]',xx,self.plugin.byd_module_vava,3) + t = t + self.table_diag_details_row(self.translate("Spannung Differenz") + ' [mV]',xx,self.plugin.byd_module_vdif,0) + t = t + '
' + '' + '' + 'M' + str(i+1) + '
' + return t + + def table_diag_details_row(self,txt,xx,vi,nn): + t = '' + t = t + '' + txt + '' + for i in range(0,self.plugin.byd_modules): + if nn == 1: + t = t + '' + f'{self.plugin.byd_diag_module[xx][i][vi]:.1f}' + '' + elif nn == 2: + t = t + '' + f'{self.plugin.byd_diag_module[xx][i][vi]:.2f}' + '' + elif nn == 3: + t = t + '' + f'{self.plugin.byd_diag_module[xx][i][vi]:.3f}' + '' + else: + t = t + '' + f'{self.plugin.byd_diag_module[xx][i][vi]:.0f}' + '' + t = t + '' + return t + + @cherrypy.expose + def byd_connection_true(self): + self.logger.warning("byd_connection_true") + self.plugin.byd_root.enable_connection(True) + return + + @cherrypy.expose + def byd_connection_false(self): + self.logger.warning("byd_connection_false") + self.plugin.byd_root.enable_connection(False) + return + + \ No newline at end of file From f1f0a920a311c31e96b1572ec875ad800b7224a5 Mon Sep 17 00:00:00 2001 From: lgb-this Date: Fri, 12 Jan 2024 17:09:51 +0100 Subject: [PATCH 3/5] Release 0.0.8 - modifications see '__init__.py' --- byd_bat/assets/base.png | Bin 0 -> 12383 bytes byd_bat/assets/diag.png | Bin 199480 -> 79956 bytes byd_bat/assets/home.png | Bin 355439 -> 85736 bytes byd_bat/assets/logdata.png | Bin 0 -> 136320 bytes byd_bat/assets/temp.png | Bin 226750 -> 86586 bytes byd_bat/assets/volt.png | Bin 475568 -> 239107 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 byd_bat/assets/base.png create mode 100644 byd_bat/assets/logdata.png diff --git a/byd_bat/assets/base.png b/byd_bat/assets/base.png new file mode 100644 index 0000000000000000000000000000000000000000..34c486f814de34555802ed2d920cfa187978315d GIT binary patch literal 12383 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 U|G>H^2K37z_pc7nT>TUN37yjZiU0rr literal 199480 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�ez8qNWsC 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

V)@ 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