Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
45610f7b19
|
@ -60,11 +60,11 @@ public partial class Battery250UpRecord
|
||||||
|
|
||||||
public readonly struct AuxBitInformation_
|
public readonly struct AuxBitInformation_
|
||||||
{
|
{
|
||||||
public Boolean DischargeEnabled => ((Self._IoStates >> 0) & 1) == 1;
|
public Boolean DischargeEnabled => ((Self._AuxBitInformation >> 0) & 1) == 1;
|
||||||
public Boolean ChargeEnabled => ((Self._IoStates >> 1) & 1) == 1;
|
public Boolean ChargeEnabled => ((Self._AuxBitInformation >> 1) & 1) == 1;
|
||||||
public Boolean WarmUpActive => ((Self._IoStates >> 2) & 1) == 1;
|
public Boolean WarmUpActive => ((Self._AuxBitInformation >> 2) & 1) == 1;
|
||||||
public Boolean TOCRequested => ((Self._IoStates >> 3) & 1) == 1;
|
public Boolean TOCRequested => ((Self._AuxBitInformation >> 3) & 1) == 1;
|
||||||
public Boolean EOCReached => ((Self._IoStates >> 4) & 1) == 1;
|
public Boolean EOCReached => ((Self._AuxBitInformation >> 4) & 1) == 1;
|
||||||
|
|
||||||
internal AuxBitInformation_(Battery250UpRecord self) => Self = self;
|
internal AuxBitInformation_(Battery250UpRecord self) => Self = self;
|
||||||
private Battery250UpRecord Self { get; }
|
private Battery250UpRecord Self { get; }
|
||||||
|
@ -134,9 +134,6 @@ public partial class Battery250UpRecord
|
||||||
if (HasBit(7) ) yield return "VBm2 : Bus voltage too low";
|
if (HasBit(7) ) yield return "VBm2 : Bus voltage too low";
|
||||||
if (HasBit(9) ) yield return "VBM2 : Bus voltage too high";
|
if (HasBit(9) ) yield return "VBM2 : Bus voltage too high";
|
||||||
if (HasBit(11)) yield return "IDM2 : Discharge current 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(15)) yield return "HTRE : Battery failed to warm up";
|
||||||
if (HasBit(16)) yield return "TCPE : Temperature sensor failure";
|
if (HasBit(16)) yield return "TCPE : Temperature sensor failure";
|
||||||
if (HasBit(17)) yield return "STRE : Voltage measurement circuit fails";
|
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(27)) yield return "iCM2 : Charge current too high";
|
||||||
if (HasBit(29)) yield return "iDM2 : Discharge 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(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(42)) yield return "HTFS : Heater Fuse Blown";
|
||||||
if (HasBit(43)) yield return "DATA : Parameters out of range";
|
if (HasBit(43)) yield return "DATA : Parameters out of range";
|
||||||
if (HasBit(45)) yield return "LMPA : Unbalance string voltages";
|
if (HasBit(45)) yield return "LMPA : Unbalance string voltages";
|
||||||
if (HasBit(46)) yield return "HEBT : Loss of heartbeat";
|
if (HasBit(54)) yield return "ULAL : The safety microprocessor intervened";
|
||||||
if (HasBit(48)) yield return "CURM : Battery charge requested after EDCH";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
||||||
|
@ -161,24 +158,12 @@ public partial class Battery250UpRecord
|
||||||
{
|
{
|
||||||
Boolean HasBit(Int16 bit) => (_WarningFlags & 1uL << bit) > 0;
|
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(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(22)) yield return "vsm1: String voltage too low";
|
||||||
if (HasBit(24)) yield return "vsM1: String voltage high";
|
if (HasBit(28)) yield return "iDM1: String discharge current high";
|
||||||
if (HasBit(26)) yield return "iCM1: Charge current high";
|
|
||||||
if (HasBit(28)) yield return "iDM1: Discharge current high";
|
|
||||||
if (HasBit(30)) yield return "MID1: String voltages unbalanced";
|
if (HasBit(30)) yield return "MID1: String voltages unbalanced";
|
||||||
if (HasBit(32)) yield return "BLPW: Not enough charging power on bus";
|
if (HasBit(32)) yield return "BLPW: Charging power is not available. Bus voltage low";
|
||||||
if (HasBit(33)) yield return "CCBF : Internal charger hardware failure";
|
if (HasBit(49)) yield return "TOCW : TOC is less than 100% from 14 days";
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,11 @@ public partial class Battery250UpRecord
|
||||||
[InputRegister(1052)] private UInt16 _TimeToTocRequest;
|
[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;
|
[InputRegister(1068)] private UInt16 _AuxBitInformation;
|
||||||
|
|
||||||
private LedState ParseLed(LedColor led) => (LedState)((_LedStates >> (Int32)led) & 3);
|
private LedState ParseLed(LedColor led) => (LedState)((_LedStates >> (Int32)led) & 3);
|
||||||
|
|
|
@ -706,24 +706,22 @@ def update_state_from_dictionaries(current_warnings, current_alarms, node_number
|
||||||
else:
|
else:
|
||||||
changed_alarms = {}
|
changed_alarms = {}
|
||||||
changed_warnings = {}
|
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()):
|
for key in current_alarms:
|
||||||
if alarm!=prev_alarm_value_list[i]:
|
current_value = current_alarms[key]
|
||||||
changed_alarms[alarm_keys[i]]=True
|
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:
|
else:
|
||||||
changed_alarms[alarm_keys[i]]=False
|
changed_alarms[key] = False
|
||||||
|
|
||||||
prev_warning_value_list=list(previous_warnings.values())
|
for key in current_warnings:
|
||||||
warning_keys=list(previous_warnings.keys())
|
current_value = current_warnings[key]
|
||||||
|
prev_value = previous_warnings.get(key, False)
|
||||||
for i, warning in enumerate(current_warnings.values()):
|
if current_value != prev_value:
|
||||||
if warning!=prev_warning_value_list[i]:
|
changed_warnings[key] = True
|
||||||
changed_warnings[warning_keys[i]]=True
|
|
||||||
else:
|
else:
|
||||||
changed_warnings[warning_keys[i]]=False
|
changed_warnings[key] = False
|
||||||
|
|
||||||
status_message = {
|
status_message = {
|
||||||
"InstallationId": INSTALLATION_ID,
|
"InstallationId": INSTALLATION_ID,
|
||||||
|
@ -915,8 +913,8 @@ def create_batch_of_csv_files():
|
||||||
# sort csv files by creation time
|
# sort csv files by creation time
|
||||||
csv_files.sort(key=lambda x: os.path.getctime(os.path.join(CSV_DIR, x)))
|
csv_files.sort(key=lambda x: os.path.getctime(os.path.join(CSV_DIR, x)))
|
||||||
|
|
||||||
# keep the 30 MOST RECENT FILES
|
# keep the 600 MOST RECENT FILES
|
||||||
recent_csv_files = csv_files[-30:] if len(csv_files) > 30 else csv_files
|
recent_csv_files = csv_files[-600:] if len(csv_files) > 600 else csv_files
|
||||||
|
|
||||||
# get the name of the first csv file
|
# get the name of the first csv file
|
||||||
if not csv_files:
|
if not csv_files:
|
||||||
|
@ -1025,7 +1023,7 @@ def create_update_task(modbus, dbus, batteries, signals, csv_signals, main_loop)
|
||||||
ALLOW = True
|
ALLOW = True
|
||||||
alive = update(modbus, batteries, dbus, signals, csv_signals)
|
alive = update(modbus, batteries, dbus, signals, csv_signals)
|
||||||
elapsed_time = time.time() - start_time
|
elapsed_time = time.time() - start_time
|
||||||
if elapsed_time >= 60:
|
if elapsed_time >= 1200:
|
||||||
create_batch_of_csv_files()
|
create_batch_of_csv_files()
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
#alive = update_for_testing(modbus, batteries, dbus, signals, csv_signals)
|
#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))
|
file_to_delete = os.path.join(directory_path, csv_files.pop(0))
|
||||||
os.remove(file_to_delete)
|
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):
|
def insert_id(path, id_number):
|
||||||
parts = path.split("/")
|
parts = path.split("/")
|
||||||
insert_position = parts.index("Devices") + 1
|
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_filename = f"{timestamp}.csv"
|
||||||
csv_path = os.path.join(CSV_DIR, csv_filename)
|
csv_path = os.path.join(CSV_DIR, csv_filename)
|
||||||
# Append values to the CSV file
|
# Append values to the CSV file
|
||||||
|
if not os.path.exists(csv_path):
|
||||||
with open(csv_path, 'a', newline='') as csvfile:
|
with open(csv_path, 'a', newline='') as csvfile:
|
||||||
csv_writer = csv.writer(csvfile, delimiter=';')
|
csv_writer = csv.writer(csvfile, delimiter=';')
|
||||||
# Add a special row for the nodes configuration
|
# Add a special row for the nodes configuration
|
||||||
|
|
|
@ -2234,7 +2234,7 @@
|
||||||
"repair": false,
|
"repair": false,
|
||||||
"outputs": 2,
|
"outputs": 2,
|
||||||
"x": 1630,
|
"x": 1630,
|
||||||
"y": 420,
|
"y": 440,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"9b93fb5a4717969a"
|
"9b93fb5a4717969a"
|
||||||
|
@ -2332,7 +2332,7 @@
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"z": "58aeeaac02a3a4c7",
|
"z": "58aeeaac02a3a4c7",
|
||||||
"name": "get_total_number_of_limb_strings",
|
"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,
|
"outputs": 1,
|
||||||
"timeout": 0,
|
"timeout": 0,
|
||||||
"noerr": 0,
|
"noerr": 0,
|
||||||
|
@ -2343,9 +2343,9 @@
|
||||||
"y": 420,
|
"y": 420,
|
||||||
"wires": [
|
"wires": [
|
||||||
[
|
[
|
||||||
"fe54eaf69a7fe10f",
|
|
||||||
"933a8eed519beb7a",
|
"933a8eed519beb7a",
|
||||||
"fcb98057e9e5a076"
|
"fcb98057e9e5a076",
|
||||||
|
"9b93fb5a4717969a"
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2604,7 +2604,7 @@
|
||||||
"rules": [
|
"rules": [
|
||||||
{
|
{
|
||||||
"t": "set",
|
"t": "set",
|
||||||
"p": "payload",
|
"p": "payload.controller_info",
|
||||||
"pt": "msg",
|
"pt": "msg",
|
||||||
"to": "Please replace battery first!",
|
"to": "Please replace battery first!",
|
||||||
"tot": "str"
|
"tot": "str"
|
||||||
|
|
|
@ -54,6 +54,6 @@ INNOVENERGY_PROTOCOL_VERSION = '48TL200V3'
|
||||||
|
|
||||||
|
|
||||||
# S3 Credentials
|
# S3 Credentials
|
||||||
S3BUCKET = "91-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
|
S3BUCKET = "114-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
|
||||||
S3KEY = "EXOe6dce12288f11a676c2025a1"
|
S3KEY = "EXO5b9198dc11544f42b44e1180"
|
||||||
S3SECRET = "xpqM4Eh0Gg1HaYVkzlR9X6PwYa-QNb-mVk0XUkwW3cc"
|
S3SECRET = "ga-mD3SYZMJUfjksmXPKAHQhVkxPZYv57jC1oD_mkC0"
|
||||||
|
|
|
@ -159,24 +159,22 @@ def update_state_from_dictionaries(current_warnings, current_alarms, node_number
|
||||||
else:
|
else:
|
||||||
changed_alarms = {}
|
changed_alarms = {}
|
||||||
changed_warnings = {}
|
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()):
|
for key in current_alarms:
|
||||||
if alarm != prev_alarm_value_list[i]:
|
current_value = current_alarms[key]
|
||||||
changed_alarms[alarm_keys[i]] = True
|
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:
|
else:
|
||||||
changed_alarms[alarm_keys[i]] = False
|
changed_alarms[key] = False
|
||||||
|
|
||||||
prev_warning_value_list=list(previous_warnings.values())
|
for key in current_warnings:
|
||||||
warning_keys=list(previous_warnings.keys())
|
current_value = current_warnings[key]
|
||||||
|
prev_value = previous_warnings.get(key, False)
|
||||||
for i, warning in enumerate(current_warnings.values()):
|
if current_value != prev_value:
|
||||||
if warning!=prev_warning_value_list[i]:
|
changed_warnings[key] = True
|
||||||
changed_warnings[warning_keys[i]]=True
|
|
||||||
else:
|
else:
|
||||||
changed_warnings[warning_keys[i]]=False
|
changed_warnings[key] = False
|
||||||
|
|
||||||
status_message = {
|
status_message = {
|
||||||
"InstallationId": INSTALLATION_ID,
|
"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)
|
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)
|
num_files_in_csv_dir = count_files_in_folder(CSV_DIR)
|
||||||
if elapsed_time >= 60:
|
if elapsed_time >= 1200:
|
||||||
create_batch_of_csv_files()
|
create_batch_of_csv_files()
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
|
@ -590,8 +588,8 @@ def create_batch_of_csv_files():
|
||||||
# sort csv files by creation time
|
# sort csv files by creation time
|
||||||
csv_files.sort(key=lambda x: os.path.getctime(os.path.join(CSV_DIR, x)))
|
csv_files.sort(key=lambda x: os.path.getctime(os.path.join(CSV_DIR, x)))
|
||||||
|
|
||||||
# keep the 30 MOST RECENT FILES
|
# keep the 600 MOST RECENT FILES
|
||||||
recent_csv_files = csv_files[-30:] if len(csv_files) > 30 else csv_files
|
recent_csv_files = csv_files[-600:] if len(csv_files) > 600 else csv_files
|
||||||
|
|
||||||
# get the name of the first csv file
|
# get the name of the first csv file
|
||||||
if not csv_files:
|
if not csv_files:
|
||||||
|
@ -691,6 +689,7 @@ def create_csv_files(signals, statuses, node_numbers, alarms_number_list, warnin
|
||||||
csv_filename = "{}.csv".format(timestamp)
|
csv_filename = "{}.csv".format(timestamp)
|
||||||
csv_path = os.path.join(CSV_DIR, csv_filename)
|
csv_path = os.path.join(CSV_DIR, csv_filename)
|
||||||
|
|
||||||
|
if not os.path.exists(csv_path):
|
||||||
with open(csv_path, 'ab') as csvfile:
|
with open(csv_path, 'ab') as csvfile:
|
||||||
csv_writer = csv.writer(csvfile, delimiter=';')
|
csv_writer = csv.writer(csvfile, delimiter=';')
|
||||||
nodes_config_path = "/Config/Devices/BatteryNodes"
|
nodes_config_path = "/Config/Devices/BatteryNodes"
|
||||||
|
|
Loading…
Reference in New Issue