sampyo-dio/main.py

428 lines
15 KiB
Python
Raw Normal View History

2024-05-23 01:32:45 +00:00
import json
import time
import argparse
import sys, signal
import gpiod
from pymodbus.client import ModbusTcpClient
# import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
import sdtcloudnodeqmqtt
import pytz
from datetime import datetime
import threading, socket
import uuid
def Motor(chip, status, action):
if action == 'On':
status[0] = 1
else: # action == 'Off'
status[0] = 0
chip.set_values(status)
def Valve_Vent(chip, status, action):
if action == 'On':
status[1] = 1
else: # action == 'Off'
status[1] = 0
chip.set_values(status)
def Valve_MixedWater(chip, status, action):
if action == 'On':
status[2] = 1
else: # action == 'Off'
status[2] = 0
chip.set_values(status)
def Valve_PureWater(chip, status, action):
if action == 'On':
status[3] = 1
else: # action == 'Off'
status[3] = 0
chip.set_values(status)
2024-05-23 05:33:27 +00:00
def Valve_EnterWater(chip, status, action):
if action == 'On':
status[4] = 1
else: # action == 'Off'
status[4] = 0
2024-05-23 05:42:56 +00:00
2024-05-23 05:33:27 +00:00
chip.set_values(status)
2024-05-23 05:50:59 +00:00
def Measure_Weight(client):
2024-05-23 05:33:27 +00:00
# print('in')
2024-05-23 01:32:45 +00:00
val = 0
try:
result = client.read_holding_registers(1, 1)
2024-05-24 06:04:38 +00:00
if not result:
2024-05-23 01:32:45 +00:00
print(f'Error: {result}')
else:
val = result.registers[0]
val -= 1000
val /= 1000
2024-05-24 06:04:38 +00:00
# print(f'value: {val}')
2024-05-23 01:32:45 +00:00
except Exception as e:
2024-05-24 06:04:38 +00:00
print(f'Measure_Weight Error: {e}')
2024-05-23 01:32:45 +00:00
pass
2024-05-23 07:03:51 +00:00
return float(val)
2024-05-23 01:32:45 +00:00
def Calculate_Concentration(weight):
global data, volume_water
data['data']['weight'] = weight
result = (float(weight) * volume_water * 128.5) - 126.11 # 1000 / 531 = 1.883239171
data['data']['concentration'] = result
# print(f'{weight}, {result}')
def Set_Zero(client):
client.write_coil(1, 1)
def Command_Read():
2024-05-24 05:17:25 +00:00
global client
2024-05-23 01:32:45 +00:00
with open('./control.json', 'r') as f:
cmd = json.load(f)
if cmd['type'] == 'auto':
Valve_Vent(chip=output_lines, status=status, action='Off')
Motor(chip=output_lines, status=status, action='Off')
mixed_duration = int(cmd['device']['mixed']['duration'])
pure_duration = int(cmd['device']['pure']['duration'])
pure_holding = int(cmd['device']['pure']['holding'])
vent_duration = int(cmd['device']['vent']['duration'])
vent_holding = int(cmd['device']['vent']['holding'])
measure_duration = int(cmd['device']['measure']['duration'])
2024-05-23 05:42:56 +00:00
enter_duration = int(cmd['device']['enter']['duration'])
2024-05-23 01:32:45 +00:00
start = Measure_Weight(client=client)
time.sleep(5)
# input mixed water
Valve_MixedWater(chip=output_lines, status=status, action='On')
2024-05-23 05:33:27 +00:00
time.sleep(0.5)
Valve_EnterWater(chip=output_lines, status=status, action='On')
2024-05-23 06:12:49 +00:00
time.sleep(0.5)
Valve_Vent(chip=output_lines, status=status, action='On')
time.sleep(vent_holding)
Valve_Vent(chip=output_lines, status=status, action='Off')
2024-05-23 01:32:45 +00:00
time.sleep(mixed_duration)
Valve_MixedWater(chip=output_lines, status=status, action='Off')
2024-05-23 05:33:27 +00:00
time.sleep(0.5)
Valve_EnterWater(chip=output_lines, status=status, action='Off')
2024-05-23 01:32:45 +00:00
time.sleep(measure_duration)
# measure weight
end = Measure_Weight(client=client)
time.sleep(1)
Calculate_Concentration(weight=(float(end)-float(start)))
# Vent and Clear sequence
2024-05-23 06:12:49 +00:00
# 1) Motor On
2024-05-23 01:32:45 +00:00
Motor(chip=output_lines, status=status, action='On')
time.sleep(0.5)
2024-05-23 06:12:49 +00:00
# 2) Input Pure Water
2024-05-23 01:32:45 +00:00
Valve_PureWater(chip=output_lines, status=status, action='On')
2024-05-23 05:33:27 +00:00
time.sleep(0.5)
Valve_EnterWater(chip=output_lines, status=status, action='On')
2024-05-29 05:51:51 +00:00
time.sleep(0.5)
2024-05-23 06:12:49 +00:00
# 3) Open Vent
Valve_Vent(chip=output_lines, status=status, action='On')
2024-05-29 06:03:54 +00:00
time.sleep(pure_holding)
2024-05-29 05:51:51 +00:00
Valve_Vent(chip=output_lines, status=status, action='Off')
2024-05-29 06:03:54 +00:00
time.sleep(pure_duration)
2024-05-23 06:12:49 +00:00
2024-05-23 05:33:27 +00:00
Valve_PureWater(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
2024-05-23 06:12:49 +00:00
Valve_EnterWater(chip=output_lines, status=status, action='Off')
2024-05-29 06:03:54 +00:00
time.sleep(0.5)
2024-05-23 01:32:45 +00:00
# 4) Wait until empty
2024-05-29 05:51:51 +00:00
Valve_Vent(chip=output_lines, status=status, action='On')
2024-05-23 01:32:45 +00:00
time.sleep(vent_duration)
2024-05-29 05:51:51 +00:00
time.sleep(0.5)
2024-05-23 01:32:45 +00:00
# 5) Motor Off and Vent close
Motor(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
Valve_Vent(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
return 1
2024-05-29 05:51:51 +00:00
elif cmd['type'] == 'clean':
clean_system()
2024-05-23 01:32:45 +00:00
else: # cmd['type'] == 'manual'
Motor(chip=output_lines, status=status, action=cmd['device']['motor']['action'])
Valve_Vent(chip=output_lines, status=status, action=cmd['device']['vent']['action'])
Valve_MixedWater(chip=output_lines, status=status, action=cmd['device']['mixed']['action'])
Valve_PureWater(chip=output_lines, status=status, action=cmd['device']['pure']['action'])
2024-05-23 05:33:27 +00:00
Valve_EnterWater(chip=output_lines, status=status, action=cmd['device']['enter']['action'])
2024-05-23 01:32:45 +00:00
if cmd['device']['measure']['action'] == 'On':
result = Measure_Weight(client=client)
Calculate_Concentration(result)
return 1
if cmd['device']['setzero']['action'] == 'On':
Set_Zero(client=client)
return 0
2024-05-29 05:51:51 +00:00
def clean_system():
with open('./control.json', 'r') as f:
cmd = json.load(f)
clean_duration = int(cmd['maintenace']['clean']['duration'])
if cmd['type'] == 'clean':
Valve_EnterWater(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
Value_PureWater(chip=output_lines, status=status, action='On')
time.sleep(0.5)
Value_MixedWater(chip=output_lines, status=status, action='On')
time.sleep(clean_duration)
Value_PureWater(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
Value_MixedWater(chip=output_lines, status=status, action='Off')
time.sleep(6)
2024-05-23 01:32:45 +00:00
def runAction():
# Write the app's actions in the "runAction" function.
# Connect MQTT Broker
# You have to rename client id. There are special rules.
# Client Name: "device-app-*"
# For Example
# 1. device-app-test -> Good
# 2. device-app-light-app -> Good
# 3. device-test-app -> Bad
2024-05-24 06:04:38 +00:00
global data
2024-05-23 01:32:45 +00:00
sdtcloud = sdtcloudnodeqmqtt.sdtcloudnodeqmqtt()
mqttClient1 = sdtcloud.setClient(f"device-app-1{uuid.uuid1()}") # parameter is client ID(string)
mqttClient2 = sdtcloud.setClient(f"device-app-2{uuid.uuid1()}") # parameter is client ID(string)
mqttClient3 = sdtcloud.setClient(f"device-app-3{uuid.uuid1()}") # parameter is client ID(string)
mqttClient4 = sdtcloud.setClient(f"device-app-4{uuid.uuid1()}") # parameter is client ID(string)
mqttClient5 = sdtcloud.setClient(f"device-app-5{uuid.uuid1()}") # parameter is client ID(string)
mqttlist = [mqttClient1, mqttClient2, mqttClient3, mqttClient4, mqttClient5]
# If you have config's value, please make config.json file.
# - Project Code's variable: projectCode(string)
# - Asset Code's variable: assetCode(string)
# - You may need it to create a topic.
cnt = 0
2024-05-29 05:51:51 +00:00
clean_flag = 0
2024-05-23 01:32:45 +00:00
while True:
start = time.time()
result = Command_Read()
if result:
data['timestamp'] = int(time.time() * 1000)
sdtcloud.pubMessage(mqttlist[cnt], data)
cnt += 1
if cnt == 5:
cnt = 0
end = time.time()
2024-05-29 05:51:51 +00:00
try:
now = datetime.now(pytz.timezone('Asia/Seoul'))
time_str = now.strftime('%H')
time_int = int(time_str)
if time_int == int(cmd['maintenance']['clean']['time']):
if clean_flag < 3:
clean_flag += 1
clean_system()
else:
clean_flag = 0
except:
pass
2024-05-23 01:32:45 +00:00
diff = end - start
if diff < 3:
time.sleep(3 - diff)
def handle_client(conn, ip, port):
global data
while True:
try:
recv = conn.recv(100)
if not recv:
# print(f"Connection with {addr} was reset. Waiting for new connection.")
break
message = recv.decode().strip()
if message[:3] != 'STX' or message[-3:] != 'ETX':
err_msg = 'STXERRORETX'
conn.sendall(err_msg.encode("utf8"))
else:
if message[3] == 'R': # Transfer data from SDT to Sampyo
now = datetime.now(pytz.timezone('Asia/Seoul'))
time_str = now.strftime('%Y%m%d%H%M%S')
h_weight = float(data['data']['weight'])
h_concentration = float(data['data']['concentration'])
data_weight = '{:.3f}'.format(h_weight)
data_concent = '{:.3f}'.format(h_concentration)
send_msg = 'STX' + time_str + '|' + data_weight + '|' + data_concent + 'ETX'
try:
with open('./control.json', 'r') as f:
cmd = json.load(f)
cmd['device']['measure']['action'] = 'On'
with open('./control.json', 'w') as f:
json.dump(cmd, f, indent=4)
conn.sendall(send_msg.encode("utf8"))
except Exception as e:
err_msg = 'STXERRORETX'
conn.sendall(err_msg.encode("utf8"))
elif message[3] == 'S': # Start measurement
try:
with open('./control.json', 'r') as f:
cmd = json.load(f)
cmd['type'] = 'auto'
with open('./control.json', 'w') as f:
json.dump(cmd, f, indent=4)
send_msg = 'STXOKETX'
conn.sendall(send_msg.encode("utf8"))
except Exception as e:
err_msg = 'STXERRORETX'
conn.sendall(err_msg.encode("utf8"))
2024-05-29 05:51:51 +00:00
elif message[3] == 'C': # Clean sequence
try:
with open('./control.json', 'r') as f:
cmd = json.load(f)
cmd['type'] = 'clean'
with open('./control.json', 'w') as f:
json.dunp(cmd, f, indent=4)
send_msg = 'STXOKETX'
conn.sendall(send_msg.encode("utf8"))
except Exception as e:
err_msg = 'STXERRORETX'
conn.sendall(err_msg.encode("utf8"))
2024-05-23 01:32:45 +00:00
elif message[3] == 'T': # Stop measurement
try:
with open('./control.json', 'r') as f:
cmd = json.load(f)
cmd['type'] = 'manual'
cmd['device']['measure']['action'] = 'Off'
with open('./control.json', 'w') as f:
json.dump(cmd, f, indent=4)
send_msg = 'STXOKETX'
conn.sendall(send_msg.encode("utf8"))
except Exception as e:
err_msg = 'STXERRORETX'
conn.sendall(err_msg.encode("utf8"))
else:
err_msg = 'STXERRORETX'
conn.sendall(err_msg.encode("utf8"))
except ConnectionResetError:
# print("Connection with " + ip + ":" + port + " was reset. Waiting for new connection.")
break
# print("Closing the connection")
def start_server(addr, port):
2024-05-24 05:17:25 +00:00
host = addr # "172.17.16.201"
2024-05-23 01:32:45 +00:00
port = port # 5000
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
soc.bind((host, port))
except:
sys.exit()
soc.listen(1) # Only one connection at a time.
while True:
conn, addr = soc.accept()
ip, port = str(addr[0]), str(addr[1])
print("Connected with " + ip + ":" + port)
client_handler = threading.Thread(target=handle_client, args=(conn, ip, port))
client_handler.start()
soc.close()
def exit_handler(signum, frame):
Motor(chip=output_lines, status=status, action='Off')
Valve_Vent(chip=output_lines, status=status, action='Off')
Valve_MixedWater(chip=output_lines, status=status, action='Off')
Valve_PureWater(chip=output_lines, status=status, action='Off')
2024-05-24 06:04:38 +00:00
Valve_EnterWater(chip=output_lines, status=status, action='Off')
2024-05-23 01:32:45 +00:00
client.close()
sys.exit(0)
if __name__ == "__main__":
output_chip = gpiod.chip('gpiochip11')
config = gpiod.line_request()
config.consumer = 'output'
config.request_type = gpiod.line_request.DIRECTION_OUTPUT
output_lines = output_chip.get_lines([0, 1, 2, 3, 4, 5, 6, 7])
output_lines.request(config, default_vals=[0, 0, 0, 0, 0, 0, 0, 0])
status = [0, 0, 0, 0, 0, 0, 0, 0]
signal.signal(signal.SIGINT, exit_handler)
with open('./config.json', encoding='UTF-8') as f:
jsonData = json.load(f)
volume_water = 1000.0 / float(jsonData['volume-water'])
modbus_addr = jsonData['modbus-server']['address']
modbus_port = jsonData['modbus-server']['port']
client = ModbusTcpClient(modbus_addr, modbus_port)
data = {
"timestamp": 0,
"data":{
"weight": 0,
"concentration": 0
}
}
## Get ProjectCode and AssetCode
## Execution main funcion
operation_thread = threading.Thread(target=runAction, args=())
operation_thread.start()
tcp_addr = jsonData['tcp-server']['address']
tcp_port = jsonData['tcp-server']['port']
## Execution TCP/IP server
start_server(addr=tcp_addr, port=tcp_port)