import sdtcloudpubsub import uuid from pymodbus.client import ModbusSerialClient as ModbusClient import os, json, sys, time import threading, struct import serial sdtcloud = sdtcloudpubsub.sdtcloudpubsub() sdtcloud.setClient(f"device-app-{uuid.uuid1()}") # parameter is client ID(string) def get_inverter_errorcode(data): error_code = ['Reserved', 'OVT', 'EXT-A', 'ETX(BX)', 'COL', 'GFT', 'OHT', 'ETH', 'OLT', 'Reserved', 'EXT-B', 'EEP', 'FAN', 'POT', 'IOLT', 'LVT'] result = [error_code[i] for i in range(16) if (data & (0x8000 >> i)) and error_code[i] != 'Reserved'] return ','.join(result) def get_modbus(evt, serial_obj): # global isThread, g_zero_point, pub_dict, a_col, d_col, t_col, p_col, S_col, s_col, path global isThread, g_zero_point, pub_dict, a_col, d_col, t_col, p_col, S_col, s_col cmd_status = 'none' cmd_sub_status = 'none' inverter_status = [0] * 6 valve_status = [False] * 8 pre_dict = {} init_flag = 0 while isThread: evt.wait() evt.clear() # with open(os.path.join(path, 'control.json'), 'r') as f: with open('./control.json', 'r') as f: control_data = json.load(f) try: res = serial_obj.read_holding_registers(address=0, count=2, slave=20) # print(f'humidity: {res.registers[0]/10}% / temperature: {res.registers[1]/10}°C') for i, j in enumerate(s_col): pub_dict[j] = res.registers[i] / 10 except Exception as e: print(f'Humidity/Temperature Senseor Error: {e}') # CWT-TM-320s try: tank_temperature = serial_obj.read_holding_registers(address=32, count=32, slave=2) # print(f'tank Temp: {tank_temperature.registers}') for i, j in enumerate(t_col): pub_dict[j] = tank_temperature.registers[i] * 0.1 except Exception as e: print(f'Tank Sensor Error: {e}') pass # CTT-MB307D try: cdu_analog = serial_obj.read_holding_registers(address=50, count=8, slave=5) cdu_digital = serial_obj.read_discrete_inputs(address=0, count=8, slave=5) # print(f'cdu_analog:{cdu_analog.registers}') # print(f'cdu_digital:{cdu_digital.bits}') if control_data['set_zero_flow'] == 'y': # with open(os.path.join(path, 'config.json'), 'r') as f: with open('./config.json', 'r') as f: config_data = json.load(f) for i, j in enumerate(a_col): if j == 'oilInFlowRate' or j == 'waterInFlowRate': config_data['ref_zero_point'][j] = cdu_analog.registers[i] control_data['set_zero_flow'] = 'n' # with open(os.path.join(path, 'config.json'), 'w') as f: with open('./config.json', 'w') as f: json.dump(config_data, f, indent=4) g_zero_point[0] = config_data['ref_zero_point']['oilInFlowRate'] g_zero_point[1] = config_data['ref_zero_point']['waterInFlowRate'] for i, j in enumerate(a_col): if j == 'oilInFlowRate': pub_dict[j] = ((cdu_analog.registers[i] - g_zero_point[0]) / 16000) * 300 elif j == 'waterInFlowRate': pub_dict[j] = ((cdu_analog.registers[i] - g_zero_point[1]) / 16000) * 300 elif j == 'oilInTemp' or j == 'waterInTemp': pub_dict[j] = ((cdu_analog.registers[i] - 4000) / 16000) * 100 elif j == 'oilOutTemp' or j == 'waterOutTemp': scale = ((cdu_analog.registers[i] - 4000) / 16000) # need to edit for temperature sensor pub_dict[j] = (scale * 100) - 20 elif j == 'oilInPress' or j == 'waterInPress': pub_dict[j] = ((cdu_analog.registers[i] - 4000) / 16000) # need to edit for pressure sensor for i, j in enumerate(d_col): pub_dict[j] = cdu_digital.bits[i] # print(pub_dict) except Exception as e: print(f'CDU Divecs Error: {e}') pass try: # M100 res = client1.read_holding_registers(address=9, count=6, slave=10) inverter_status[0] = res.registers[0] / 100 # frequncy inverter_status[1] = get_inverter_errorcode(res.registers[5]) # errorcode run_status = res.registers[4] # running status if run_status & 0x01: inverter_status[2] = 'stop' elif run_status & 0x02: inverter_status[2] = 'running' elif run_status & 0x08: inverter_status[2] = 'error' res = client1.read_holding_registers(address=9, count=6, slave=11) inverter_status[3] = res.registers[0] / 100 # frequncy inverter_status[4] = get_inverter_errorcode(res.registers[5]) # errorcode run_status = res.registers[4] # running status if run_status & 0x01: inverter_status[5] = 'stop' elif run_status & 0x02: inverter_status[5] = 'running' elif run_status & 0x08: inverter_status[5] = 'error' for i, j in enumerate(p_col): pub_dict[j] = inverter_status[i] except Exception as e: print(f'Inverter Status Error: {e}') try: if control_data['mode'] == 'auto': if control_data['cmd'] == 'init': if cmd_sub_status != 'workingInit': valve_status[0], valve_status[1] = True, True res = serial_obj.write_coils(address=0, values=valve_status, slave=5) client1.write_registers(address=5, values=[193], slave=10) client1.write_registers(address=5, values=[193], slave=11) cmd_status = 'init' cmd_sub_status = 'workingInit' pub_dict['cmd'] = 'workingInit' elif cmd_sub_status == 'workingInit': if (pub_dict['valve1OpenStatus'] == True and pub_dict['valve2OpenStatus'] == True and (pub_dict['pump1StatusRunning'] == 'stop') and (pub_dict['pump2StatusRunning'] == 'stop')): cmd_status = 'none' cmd_sub_status = 'doneInit' pub_dict['cmd'] = 'doneInit' control_data['cmd'] = 'none' init_flag = 1 elif control_data['cmd'] == 'emer': # 어느 조건에서든 입력되면 바로 수행 if cmd_sub_status != 'workingEmer': valve_status[0], valve_status[1] = False, False res = serial_obj.write_coils(address=0, values=valve_status, slave=5) client1.write_registers(address=5, values=[208], slave=10) client1.write_registers(address=5, values=[208], slave=11) cmd_status = 'emer' cmd_sub_status = 'workingEmer' pub_dict['cmd'] = 'emer' init_flag = 0 elif cmd_sub_status == 'workingEmer': if (pub_dict['valve1CloseStatus'] == True and pub_dict['valve2CloseStatus'] == True and (pub_dict['pump1StatusRunning'] == 'stop') and (pub_dict['pump2StatusRunning'] == 'stop')): cmd_sub_status = 'none' control_data['cmd'] = 'none' elif control_data['cmd'] == 'stop' or cmd_status == 'stop': if init_flag == 0: continue if cmd_status == 'none' or cmd_status == 'stop' or cmd_status == 'act1' or cmd_status == 'act2': client1.write_registers(address=5, values=[193], slave=10) client1.write_registers(address=5, values=[193], slave=11) if not ((pub_dict['pump1StatusRunning'] == 'stop') and (pub_dict['pump2StatusRunning'] == 'stop')): cmd_status = 'stop' cmd_sub_status = 'stopping' pub_dict['cmd'] = 'stopping' elif ((pub_dict['pump1StatusRunning'] == 'stop') and (pub_dict['pump2StatusRunning'] == 'stop')): cmd_status = 'none' cmd_sub_status = 'stop' pub_dict['cmd'] = 'stop' control_data['cmd'] = 'none' elif control_data['cmd'] == 'act1': if init_flag == 0: continue if cmd_status == 'none' or cmd_status == 'act1': if cmd_sub_status == 'doneInit' or cmd_sub_status == 'stop': cmd_status = 'act1' cmd_sub_status = 'closeValve2' pub_dict['cmd'] = 'startAct1' elif cmd_sub_status == 'workingPump2': cmd_status = 'act1' cmd_sub_status = 'stopPump2' pub_dict['cmd'] = 'startAct1' elif cmd_sub_status == 'stopPump2': if not (pub_dict['pump2StatusRunning'] == 'stop'): client1.write_registers(address=5, values=[193], slave=11) cmd_sub_status = 'stoppingPump2' else: cmd_sub_status = 'closeValve2' elif cmd_sub_status == 'stoppingPump2': if pub_dict['pump2StatusRunning'] == 'stop': cmd_sub_status = 'closeValve2' elif cmd_sub_status == 'closeValve2': if pub_dict['valve2OpenStatus'] == True: valve_status[1] = False res = serial_obj.write_coils(address=0, values=valve_status, slave=5) cmd_sub_status = 'closingValve2' elif pub_dict['valve2CloseStatus'] == True: cmd_sub_status = 'openValve1' elif cmd_sub_status == 'closingValve2': if pub_dict['valve2CloseStatus'] == True: cmd_sub_status = 'openValve1' elif cmd_sub_status == 'openValve1': if pub_dict['valve1CloseStatus'] == True: valve_status[0] = True res = serial_obj.write_coils(address=0, values=valve_status, slave=5) cmd_sub_status = 'openningValve1' elif pub_dict['valve1OpenStatus'] == True: cmd_sub_status = 'startPump1' elif cmd_sub_status == 'openningValve1': if pub_dict['valve1OpenStatus'] == True: cmd_sub_status = 'startPump1' elif cmd_sub_status == 'startPump1': frq = int(control_data['inverter']['inverter1Frq'] * 100) acc = int(control_data['inverter']['inverter1Acc'] * 10) dec = int(control_data['inverter']['inverter1Dec'] * 10) client1.write_registers(address=4, values=[frq, 194, acc, dec], slave=10) cmd_sub_status = 'startingPump1' elif cmd_sub_status == 'startingPump1': if pub_dict['pump1StatusRunning'] == 'running': cmd_status = 'none' cmd_sub_status = 'workingPump1' pub_dict['cmd'] = 'workingAct1' control_data['cmd'] = 'none' else: client1.write_registers(address=5, values=[193], slave=10) client1.write_registers(address=5, values=[193], slave=11) pub_dict['cmd'] = 'errorAct1' cmd_status = 'errorAct1' cmd_sub_status = 'errorPump1' init_flag = 0 elif control_data['cmd'] == 'act2': if init_flag == 0: continue if cmd_status == 'none' or cmd_status == 'act2': if cmd_sub_status == 'doneInit' or cmd_sub_status == 'stop': cmd_status = 'act2' cmd_sub_status = 'closeValve1' pub_dict['cmd'] = 'startAct2' elif cmd_sub_status == 'workingPump1': cmd_status = 'act2' cmd_sub_status = 'stopPump1' pub_dict['cmd'] = 'startAct2' elif cmd_sub_status == 'stopPump1': if not (pub_dict['pump1StatusRunning'] == 'stop'): client1.write_registers(address=5, values=[193], slave=10) cmd_sub_status = 'stoppingPump1' else: cmd_sub_status = 'closeValve1' elif cmd_sub_status == 'stoppingPump1': if pub_dict['pump1StatusRunning'] == 'stop': cmd_sub_status = 'closeValve1' elif cmd_sub_status == 'closeValve1': if pub_dict['valve1OpenStatus'] == True: valve_status[0] = False res = serial_obj.write_coils(address=0, values=valve_status, slave=5) cmd_sub_status = 'closingValve1' elif pub_dict['valve1CloseStatus'] == True: cmd_sub_status = 'openValve2' elif cmd_sub_status == 'closingValve1': if pub_dict['valve1CloseStatus'] == True: cmd_sub_status = 'openValve2' elif cmd_sub_status == 'openValve2': if pub_dict['valve2CloseStatus'] == True: valve_status[1] = True res = serial_obj.write_coils(address=0, values=valve_status, slave=5) cmd_sub_status = 'openningValve2' elif pub_dict['valve2OpenStatus'] == True: cmd_sub_status = 'startPump2' elif cmd_sub_status == 'openningValve2': if pub_dict['valve2OpenStatus'] == True: cmd_sub_status = 'startPump2' elif cmd_sub_status == 'startPump2': frq = int(control_data['inverter']['inverter2Frq'] * 100) acc = int(control_data['inverter']['inverter2Acc'] * 10) dec = int(control_data['inverter']['inverter2Dec'] * 10) client1.write_registers(address=4, values=[frq, 194, acc, dec], slave=11) cmd_sub_status = 'startingPump2' elif cmd_sub_status == 'startingPump2': if pub_dict['pump2StatusRunning'] == 'running': cmd_status = 'none' cmd_sub_status = 'workingPump2' pub_dict['cmd'] = 'workingAct2' control_data['cmd'] = 'none' else: client1.write_registers(address=5, values=[193], slave=10) client1.write_registers(address=5, values=[193], slave=11) pub_dict['cmd'] = 'errorAct2' cmd_status = 'errorAct2' cmd_sub_status = 'errorPump2' init_flag = 0 else: if isinstance(pub_dict['cmd'], (int, float)): pub_dict['cmd'] = 'none' elif control_data['mode'] == 'manual': if control_data != pre_dict: pub_dict['cmd'] = 'manual' if control_data['inverter']['inverter1'] == 'On' and cmd_status[0] == 0: frq = int(control_data['inverter']['inverter1Frq'] * 100) acc = int(control_data['inverter']['inverter1Acc'] * 10) dec = int(control_data['inverter']['inverter1Dec'] * 10) client1.write_registers(address=4, values=[frq, 194, acc, dec], slave=10) cmd_status[0] = 1 elif control_data['inverter']['inverter1'] == 'Off' and cmd_status[0] == 1: client1.write_registers(address=5, values=[193], slave=10) cmd_status[0] = 0 if control_data['inverter']['inverter2'] == 'On' and cmd_status[1] == 0: frq = int(control_data['inverter']['inverter1Frq'] * 100) acc = int(control_data['inverter']['inverter1Acc'] * 10) dec = int(control_data['inverter']['inverter1Dec'] * 10) client1.write_registers(address=4, values=[frq, 194, acc, dec], slave=10) cmd_status[1] = 1 elif control_data['inverter']['inverter2'] == 'Off' and cmd_status[1] == 1: client1.write_registers(address=5, values=[193], slave=10) cmd_status[1] = 0 if control_data['valve1'] == 'On' and cmd_status[2] == 0: valve_status[0] = True cmd_status[2] = 1 elif control_data['valve1'] == 'Off' and cmd_status[2] == 1: valve_status[0] = False cmd_status[2] = 0 if control_data['valve2'] == 'On' and cmd_status[3] == 0: valve_status[1] = True cmd_status[3] = 1 elif control_data['valve2'] == 'Off' and cmd_status[3] == 1: valve_status[1] = False cmd_status[3] = 0 res = serial_obj.write_coils(address=0, values=valve_status, slave=5) else: pre_dict = control_data.copy() elif control_data['mode'] == 'none': valve_status[0], valve_status[1] = False, False res = serial_obj.write_coils(address=0, values=valve_status, slave=5) client1.write_registers(address=5, values=[193], slave=10) client1.write_registers(address=5, values=[193], slave=11) else: pub_dict['cmd'] = 'none' except Exception as e: print(f'Device Setting Error: {e}') if pre_dict != control_data: # with open(os.path.join(path, 'control.json'), 'w') as f: with open('./control.json', 'w') as f: json.dump(control_data, f, indent=4) pre_dict = control_data.copy() def get_sensor(evt, serial_obj): global isThread, pub_dict, s_col while isThread: evt.wait() evt.clear() try: res = serial_obj.read_holding_registers(address=0, count=2, slave=20) # print(f'humidity: {res.registers[0]/10}% / temperature: {res.registers[1]/10}°C') for i, j in enumerate(s_col): pub_dict[j] = res.registers[i] / 10 except Exception as e: print(f'Error: {e}') def get_pdu(evt, serial_obj): global isThread, pub_dict, cp_col, tp_col pdu_dict = { 'pduCDU1': '1E', 'pduCDU2': '1F', 'pduTank1': '28', 'pduTank2': '29', 'pduTank3': '2A', 'pduTank4': '2B' } pdu_list = cp_col + tp_col pdu_list = [col for col in pdu_list if col != 0] # print(pdu_list) while isThread: evt.wait() evt.clear() for pdu in pdu_list: rcv_data = [] sum = 0 cnt = 0 command_hex = f'FEFF{pdu_dict[pdu]}01010000' # print(command_hex) command_bytes = bytes.fromhex(command_hex) for x in command_bytes[2:]: sum += x sum = sum & 0xff sum = struct.pack('>B', sum) snd_bytes = command_bytes + b'\x00' + sum + b'\xfd' # print(f'snd_bytes: {snd_bytes}') serial_obj.write(snd_bytes) while True: res = serial_obj.read(1) # print(res) if res != b'': rcv_data.append(res) else: cnt += 1 if cnt == 10: break if len(rcv_data) >= 2: if not(rcv_data[0] == b'\xfc' and rcv_data[1] == b'\xff'): rcv_data = [] break elif rcv_data[:-1] == b'\xfd': break if len(rcv_data): sum = 0 # print(f'rcv_data: {rcv_data}') for x in rcv_data[2:-3]: sum += int.from_bytes(x, byteorder='big') sum = sum & 0xff sum = struct.pack('>B', sum) # print(f'sum: {sum}') if rcv_data[-2] == sum: byte_val = rcv_data[10:12] int_val = int.from_bytes(byte_val[0] + byte_val[1], byteorder='big') int_val /= 100 pub_dict[pdu] = int_val else: continue def runAction(evt): global isThread, pub_dict cnt = 0 while isThread: evt.wait() evt.clear() if cnt: # print(pub_dict) sdtcloud.pubMessage(pub_dict) else: cnt += 1 def timer_s0(evt): global isThread while isThread: evt.set() time.sleep(0.5) def timer_s1(evt): global isThread while isThread: evt.set() time.sleep(0.5) def timer_s2(evt, interval): global isThread while isThread: evt.set() time.sleep(interval) if __name__ == "__main__": pw = 'Sdt2513!@' os.system(f'echo {pw} | sudo -S chmod 777 /dev/ttyS0') os.system(f'echo {pw} | sudo -S chmod 777 /dev/ttyS1') port_name_1 = '/dev/ttyS0' client1 = ModbusClient(port=port_name_1, baudrate=9600, parity='N', stopbits=1, bytesize=8, timeout=0.25) port_name_2 = '/dev/ttyS1' client2 = serial.Serial(port=port_name_2, baudrate=19200, parity='N', stopbits=1, bytesize=8, timeout=0.1) try: client1.connect() except: sys.exit(0) # path = '/home/sdtadmin/aquarack-sensor-collector' # with open(os.path.join(path, 'config.json'), 'r') as config: with open('./config.json', 'r') as config: cfg_data = json.load(config) g_zero_point = [cfg_data['ref_zero_point']['oilInFlowRate'], cfg_data['ref_zero_point']['waterInFlowRate']] # with open(os.path.join(path, 'control.json'), 'r') as control: with open('./control.json', 'r') as control: ctl_data = json.load(control) len_a_col = len(cfg_data['cdu_analog_list']) len_t_col = len(cfg_data['tank_device_list']) len_d_col = len(cfg_data['cdu_digital_list']) len_s_col = len(cfg_data['cdu_sensor_list']) len_p_col = len(cfg_data['cdu_device_list']) len_S_col = len(cfg_data['status']) len_cp_col = len(cfg_data['cdu_pdu_list']) len_tp_col = len(cfg_data['tank_pdu_list']) a_col = [0] * len_a_col t_col = [0] * len_t_col d_col = [0] * len_d_col s_col = [0] * len_s_col p_col = [0] * len_p_col S_col = [0] * len_S_col cp_col = [0] * len_cp_col tp_col = [0] * len_tp_col for key, value in cfg_data['cdu_analog_list'].items(): if value[1] == 'y': a_col[value[0] - 1] = key a_col = [col for col in a_col if col != 0] for key, value in cfg_data['tank_device_list'].items(): if value[1] == 'y': t_col[value[0] - 1] = key t_col = [col for col in t_col if col != 0] for key, value in cfg_data['cdu_digital_list'].items(): if value[1] == 'y': d_col[value[0] - 1] = key d_col = [col for col in d_col if col != 0] for key, value in cfg_data['cdu_sensor_list'].items(): if value[1] == 'y': s_col[value[0] - 1] = key s_col = [col for col in s_col if col != 0] for key, value in cfg_data['cdu_device_list'].items(): if value[1] == 'y': p_col[value[0] - 1] = key p_col = [col for col in p_col if col != 0] for key, value in cfg_data['status'].items(): if value[1] == 'y': S_col[value[0] - 1] = key S_col = [col for col in S_col if col != 0] for key, value in cfg_data['cdu_pdu_list'].items(): if value[1] == 'y': cp_col[value[0] - 1] = key cp_col = [col for col in cp_col if col != 0] for key, value in cfg_data['tank_pdu_list'].items(): if value[1] == 'y': tp_col[value[0] - 1] = key tp_col = [col for col in tp_col if col != 0] pub_dict = {key: 0.0 for key in (a_col+t_col+d_col+s_col+p_col+S_col+cp_col+tp_col)} # print(f'a_col: {a_col}') # print(f't_col: {t_col}') # print(f'd_col: {d_col}') # print(f's_col: {s_col}') # print(f'p_col: {p_col}') # print(f'S_col: {S_col}') # runAction() isThread = True timer_evt_s0 = threading.Event() timer_evt_s1 = threading.Event() timer_evt_s2 = threading.Event() timer_evt_s0.set() timer_evt_s1.set() timer_evt_s2.set() thr_evt_s0 = threading.Thread(target=timer_s0, args=(timer_evt_s0,)) thr_evt_s1 = threading.Thread(target=timer_s1, args=(timer_evt_s1,)) thr_evt_s2 = threading.Thread(target=timer_s2, args=(timer_evt_s2, ctl_data['get_data_interval'],)) thr_evt_s0.start() thr_evt_s1.start() thr_evt_s2.start() thr_modbus_rtu = threading.Thread(target=get_modbus, args=(timer_evt_s0, client1, )) thr_modbus_rtu.start() # thr_get_sensor = threading.Thread(target=get_sensor, args=(timer_evt_s1, client2,)) # thr_get_sensor.start() thr_get_pdu = threading.Thread(target=get_pdu, args=(timer_evt_s1, client2, )) thr_get_pdu.start() thr_run = threading.Thread(target=runAction, args=(timer_evt_s2, )) thr_run.start()