Merge remote-tracking branch 'origin/main'

This commit is contained in:
atef 2024-08-08 10:18:31 +02:00
commit 45610f7b19
6 changed files with 90 additions and 108 deletions

View File

@ -60,11 +60,11 @@ public partial class Battery250UpRecord
public readonly struct AuxBitInformation_
{
public Boolean DischargeEnabled => ((Self._IoStates >> 0) & 1) == 1;
public Boolean ChargeEnabled => ((Self._IoStates >> 1) & 1) == 1;
public Boolean WarmUpActive => ((Self._IoStates >> 2) & 1) == 1;
public Boolean TOCRequested => ((Self._IoStates >> 3) & 1) == 1;
public Boolean EOCReached => ((Self._IoStates >> 4) & 1) == 1;
public Boolean DischargeEnabled => ((Self._AuxBitInformation >> 0) & 1) == 1;
public Boolean ChargeEnabled => ((Self._AuxBitInformation >> 1) & 1) == 1;
public Boolean WarmUpActive => ((Self._AuxBitInformation >> 2) & 1) == 1;
public Boolean TOCRequested => ((Self._AuxBitInformation >> 3) & 1) == 1;
public Boolean EOCReached => ((Self._AuxBitInformation >> 4) & 1) == 1;
internal AuxBitInformation_(Battery250UpRecord self) => Self = self;
private Battery250UpRecord Self { get; }
@ -134,9 +134,6 @@ public partial class Battery250UpRecord
if (HasBit(7) ) yield return "VBm2 : Bus voltage too low";
if (HasBit(9) ) yield return "VBM2 : Bus voltage too high";
if (HasBit(11)) yield return "IDM2 : Discharge current too high";
if (HasBit(12)) yield return "ISOB : Electrical insulation failure";
if (HasBit(13)) yield return "MSWE : Main switch failure";
if (HasBit(14)) yield return "FUSE : Main fuse blown";
if (HasBit(15)) yield return "HTRE : Battery failed to warm up";
if (HasBit(16)) yield return "TCPE : Temperature sensor failure";
if (HasBit(17)) yield return "STRE : Voltage measurement circuit fails";
@ -149,11 +146,11 @@ public partial class Battery250UpRecord
if (HasBit(27)) yield return "iCM2 : Charge current too high";
if (HasBit(29)) yield return "iDM2 : Discharge current too high";
if (HasBit(31)) yield return "MID2 : String voltage unbalance too high";
if (HasBit(33)) yield return "CCBF : Charger Circuit not working";
if (HasBit(42)) yield return "HTFS : Heater Fuse Blown";
if (HasBit(43)) yield return "DATA : Parameters out of range";
if (HasBit(45)) yield return "LMPA : Unbalance string voltages";
if (HasBit(46)) yield return "HEBT : Loss of heartbeat";
if (HasBit(48)) yield return "CURM : Battery charge requested after EDCH";
if (HasBit(54)) yield return "ULAL : The safety microprocessor intervened";
}
[SuppressMessage("ReSharper", "StringLiteralTypo")]
@ -161,24 +158,12 @@ public partial class Battery250UpRecord
{
Boolean HasBit(Int16 bit) => (_WarningFlags & 1uL << bit) > 0;
if (HasBit(1) ) yield return "TaM1: BMS temperature high";
if (HasBit(4) ) yield return "TbM1: Battery temperature high";
if (HasBit(6) ) yield return "VBm1: Bus voltage low";
if (HasBit(8) ) yield return "VBM1: Bus voltage high";
if (HasBit(10)) yield return "IDM1: Discharge current high";
if (HasBit(22)) yield return "vsm1: String voltage too low";
if (HasBit(24)) yield return "vsM1: String voltage high";
if (HasBit(26)) yield return "iCM1: Charge current high";
if (HasBit(28)) yield return "iDM1: Discharge current high";
if (HasBit(28)) yield return "iDM1: String discharge current high";
if (HasBit(30)) yield return "MID1: String voltages unbalanced";
if (HasBit(32)) yield return "BLPW: Not enough charging power on bus";
if (HasBit(33)) yield return "CCBF : Internal charger hardware failure";
if (HasBit(35)) yield return "Ah_W: String SOC low";
if (HasBit(38)) yield return "MPMM: Midpoint wiring problem";
if (HasBit(40)) yield return "TCdi: Temperature difference between strings high";
if (HasBit(44)) yield return "LMPW : String voltages unbalance warning";
if (HasBit(47)) yield return "TOCW : Top of Charge requested";
if (HasBit(49)) yield return "BUSL : Bus lower than string";
if (HasBit(32)) yield return "BLPW: Charging power is not available. Bus voltage low";
if (HasBit(49)) yield return "TOCW : TOC is less than 100% from 14 days";
}

View File

@ -54,7 +54,11 @@ public partial class Battery250UpRecord
[InputRegister(1052)] private UInt16 _TimeToTocRequest;
//[InputRegister(1063)] private UInt16 _TotalBatteryCycle;
[InputRegister(1063)] private UInt16 _TotalBatteryCycle;
[InputRegister(1064, Scale = 1, Offset = -1000)] private UInt16 _DC_Discharge_Current_Limit;
[InputRegister(1065, Scale = 1, Offset = -1000)] private UInt16 _DC_Charge_Current_Limit;
[InputRegister(1066, Scale = 0.1)] private UInt16 _Voltage_Charge_Setpoint;
[InputRegister(1067, Scale = 0.1)] private UInt16 _DC_Min_Voltage_Limit;
[InputRegister(1068)] private UInt16 _AuxBitInformation;
private LedState ParseLed(LedColor led) => (LedState)((_LedStates >> (Int32)led) & 3);

View File

@ -704,26 +704,24 @@ def update_state_from_dictionaries(current_warnings, current_alarms, node_number
changed_alarms = current_alarms
is_first_update = False
else:
changed_alarms={}
changed_warnings={}
# calculate the diff in warnings and alarms
prev_alarm_value_list=list(previous_alarms.values())
alarm_keys=list(previous_alarms.keys())
changed_alarms = {}
changed_warnings = {}
for i, alarm in enumerate(current_alarms.values()):
if alarm!=prev_alarm_value_list[i]:
changed_alarms[alarm_keys[i]]=True
for key in current_alarms:
current_value = current_alarms[key]
prev_value = previous_alarms.get(key, False) # Use False if the key doesn't exist
if current_value != prev_value:
changed_alarms[key] = True
else:
changed_alarms[alarm_keys[i]]=False
changed_alarms[key] = False
prev_warning_value_list=list(previous_warnings.values())
warning_keys=list(previous_warnings.keys())
for i, warning in enumerate(current_warnings.values()):
if warning!=prev_warning_value_list[i]:
changed_warnings[warning_keys[i]]=True
for key in current_warnings:
current_value = current_warnings[key]
prev_value = previous_warnings.get(key, False)
if current_value != prev_value:
changed_warnings[key] = True
else:
changed_warnings[warning_keys[i]]=False
changed_warnings[key] = False
status_message = {
"InstallationId": INSTALLATION_ID,
@ -915,8 +913,8 @@ def create_batch_of_csv_files():
# sort csv files by creation time
csv_files.sort(key=lambda x: os.path.getctime(os.path.join(CSV_DIR, x)))
# keep the 30 MOST RECENT FILES
recent_csv_files = csv_files[-30:] if len(csv_files) > 30 else csv_files
# keep the 600 MOST RECENT FILES
recent_csv_files = csv_files[-600:] if len(csv_files) > 600 else csv_files
# get the name of the first csv file
if not csv_files:
@ -1025,7 +1023,7 @@ def create_update_task(modbus, dbus, batteries, signals, csv_signals, main_loop)
ALLOW = True
alive = update(modbus, batteries, dbus, signals, csv_signals)
elapsed_time = time.time() - start_time
if elapsed_time >= 60:
if elapsed_time >= 1200:
create_batch_of_csv_files()
start_time = time.time()
#alive = update_for_testing(modbus, batteries, dbus, signals, csv_signals)
@ -1067,11 +1065,6 @@ def manage_csv_files(directory_path, max_files=20):
file_to_delete = os.path.join(directory_path, csv_files.pop(0))
os.remove(file_to_delete)
def serialize_for_csv(value):
if isinstance(value, (dict, list, tuple)):
return json.dumps(value, ensure_ascii=False)
return str(value)
def insert_id(path, id_number):
parts = path.split("/")
insert_position = parts.index("Devices") + 1
@ -1089,6 +1082,7 @@ def create_csv_files(signals, statuses, node_numbers, alarms_number_list, warnin
csv_filename = f"{timestamp}.csv"
csv_path = os.path.join(CSV_DIR, csv_filename)
# Append values to the CSV file
if not os.path.exists(csv_path):
with open(csv_path, 'a', newline='') as csvfile:
csv_writer = csv.writer(csvfile, delimiter=';')
# Add a special row for the nodes configuration

View File

@ -2234,7 +2234,7 @@
"repair": false,
"outputs": 2,
"x": 1630,
"y": 420,
"y": 440,
"wires": [
[
"9b93fb5a4717969a"
@ -2332,7 +2332,7 @@
"type": "function",
"z": "58aeeaac02a3a4c7",
"name": "get_total_number_of_limb_strings",
"func": "let total_num_limb_string=0;\nlimb_string_list = msg.payload.limb_string_list;\nmain_switch_state_list = msg.payload.main_switch_state;\nbattery_health = [];\nif (limb_string_list == null){\n msg.payload.battery_health = \"BMS connection lost!\";\n msg.payload.num_limb_string = -1\n return msg;\n}\n\nfor (let i = 0; i < limb_string_list.length; i++) {\n num_limb_string = limb_string_list[i][1][0];\n \n if(num_limb_string>1){\n total_num_limb_string = -1;//if there are more than 1 limb string in a battery, should give alarm to stop use this battery\n battery_health.push(\"Battery \"+(i+2)+\" has more than 1 limb string!\");\n }\n \n if(num_limb_string<=1){\n total_num_limb_string+=num_limb_string;\n battery_health.push(\"Battery \"+(i+2)+\" has \" + num_limb_string+ \" limb strings.\");\n }\n}\nmsg.payload.num_limb_string = total_num_limb_string;\nmsg.payload.battery_health = battery_health;\n\nreturn msg;",
"func": "let total_num_limb_string=0;\nlimb_string_list = msg.payload.limb_string_list;\nmain_switch_state_list = msg.payload.main_switch_state;\nbattery_health = [];\nflag = 1;\nif (limb_string_list == null){\n msg.payload.battery_health = \"BMS connection lost!\";\n msg.payload.num_limb_string = -1\n return msg;\n}\n\nfor (let i = 0; i < limb_string_list.length; i++) {\n num_limb_string = limb_string_list[i][1][0];\n \n if(num_limb_string>1){\n flag = -1;\n }\n \n if(num_limb_string<=1){\n total_num_limb_string+=num_limb_string;\n }\n \n battery_health.push(\"Battery \"+(i+2)+\" has \" + num_limb_string+ \" limb strings.\");\n}\n\nconst updateNumLimbString = (total, flag) => flag === 1 ? total : -1;\nmsg.payload.num_limb_string = updateNumLimbString(total_num_limb_string, flag);\nmsg.payload.battery_health = battery_health;\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
@ -2343,9 +2343,9 @@
"y": 420,
"wires": [
[
"fe54eaf69a7fe10f",
"933a8eed519beb7a",
"fcb98057e9e5a076"
"fcb98057e9e5a076",
"9b93fb5a4717969a"
]
]
},
@ -2604,7 +2604,7 @@
"rules": [
{
"t": "set",
"p": "payload",
"p": "payload.controller_info",
"pt": "msg",
"to": "Please replace battery first!",
"tot": "str"

View File

@ -54,6 +54,6 @@ INNOVENERGY_PROTOCOL_VERSION = '48TL200V3'
# S3 Credentials
S3BUCKET = "91-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
S3KEY = "EXOe6dce12288f11a676c2025a1"
S3SECRET = "xpqM4Eh0Gg1HaYVkzlR9X6PwYa-QNb-mVk0XUkwW3cc"
S3BUCKET = "114-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
S3KEY = "EXO5b9198dc11544f42b44e1180"
S3SECRET = "ga-mD3SYZMJUfjksmXPKAHQhVkxPZYv57jC1oD_mkC0"

View File

@ -159,24 +159,22 @@ def update_state_from_dictionaries(current_warnings, current_alarms, node_number
else:
changed_alarms = {}
changed_warnings = {}
# calculate the diff in warnings and alarms
prev_alarm_value_list = list(previous_alarms.values())
alarm_keys = list(previous_alarms.keys())
for i, alarm in enumerate(current_alarms.values()):
if alarm != prev_alarm_value_list[i]:
changed_alarms[alarm_keys[i]] = True
for key in current_alarms:
current_value = current_alarms[key]
prev_value = previous_alarms.get(key, False) # Use False if the key doesn't exist
if current_value != prev_value:
changed_alarms[key] = True
else:
changed_alarms[alarm_keys[i]] = False
changed_alarms[key] = False
prev_warning_value_list=list(previous_warnings.values())
warning_keys=list(previous_warnings.keys())
for i, warning in enumerate(current_warnings.values()):
if warning!=prev_warning_value_list[i]:
changed_warnings[warning_keys[i]]=True
for key in current_warnings:
current_value = current_warnings[key]
prev_value = previous_warnings.get(key, False)
if current_value != prev_value:
changed_warnings[key] = True
else:
changed_warnings[warning_keys[i]]=False
changed_warnings[key] = False
status_message = {
"InstallationId": INSTALLATION_ID,
@ -552,7 +550,7 @@ def create_update_task(modbus, service, batteries):
create_csv_files(csv_signals, statuses, node_numbers, alarms_number_list, warnings_number_list)
num_files_in_csv_dir = count_files_in_folder(CSV_DIR)
if elapsed_time >= 60:
if elapsed_time >= 1200:
create_batch_of_csv_files()
start_time = time.time()
@ -590,8 +588,8 @@ def create_batch_of_csv_files():
# sort csv files by creation time
csv_files.sort(key=lambda x: os.path.getctime(os.path.join(CSV_DIR, x)))
# keep the 30 MOST RECENT FILES
recent_csv_files = csv_files[-30:] if len(csv_files) > 30 else csv_files
# keep the 600 MOST RECENT FILES
recent_csv_files = csv_files[-600:] if len(csv_files) > 600 else csv_files
# get the name of the first csv file
if not csv_files:
@ -685,12 +683,13 @@ def create_batch_of_csv_files():
def create_csv_files(signals, statuses, node_numbers, alarms_number_list, warnings_number_list):
timestamp = int(time.time())
if timestamp % 2 != 0:
timestamp-=1
timestamp -= 1
if not os.path.exists(CSV_DIR):
os.makedirs(CSV_DIR)
csv_filename = "{}.csv".format(timestamp)
csv_path = os.path.join(CSV_DIR, csv_filename)
if not os.path.exists(csv_path):
with open(csv_path, 'ab') as csvfile:
csv_writer = csv.writer(csvfile, delimiter=';')
nodes_config_path = "/Config/Devices/BatteryNodes"