aquarack-sensor-collector/main.py

627 lines
27 KiB
Python

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()