Commit message

This commit is contained in:
support.sampyo 2024-05-23 01:32:45 +00:00
parent 237ec66789
commit 0a996b5b66
4 changed files with 412 additions and 384 deletions

View File

@ -1,12 +1,12 @@
{ {
"appId": "81a695f0-a990-43c8-998f-2ba1bf9c6005", "appId": "81a695f0-a990-43c8-998f-2ba1bf9c6005",
"modbus-server": { "modbus-server": {
"address": "172.17.16.202", "address": "172.17.16.202",
"port": 5020 "port": 5020
}, },
"tcp-server": { "tcp-server": {
"address": "172.17.16.201", "address": "172.17.16.201",
"port": 24 "port": 24
}, },
"volume-water": 542 "volume-water": 542
} }

View File

@ -1,27 +1,29 @@
{ {
"device": { "device": {
"setzero": { "setzero": {
"action": "Off" "action": "Off"
}, },
"measure": { "measure": {
"action": "On", "action": "On",
"duration": 20 "duration": 20
}, },
"mixed": { "mixed": {
"action": "Off", "action": "Off",
"duration": 15 "duration": 7
}, },
"pure": { "pure": {
"action": "Off", "action": "Off",
"duration": 15 "duration": 10,
}, "holding": 5
"vent": { },
"action": "Off", "vent": {
"duration": 30 "action": "Off",
}, "duration": 30,
"motor": { "holding": 2
"action": "Off" },
} "motor": {
}, "action": "Off"
"type": "manual" }
} },
"type": "manual"
}

View File

@ -7,5 +7,5 @@ spec:
virtualEnv: base # 사용할 가상환경 이름입니다. virtualEnv: base # 사용할 가상환경 이름입니다.
package: requirements.txt # 설치할 Python 패키지 정보 파일입니다.(기본 값은 requirement.txt 입니다.) package: requirements.txt # 설치할 Python 패키지 정보 파일입니다.(기본 값은 requirement.txt 입니다.)
stackbase: stackbase:
tagName: v0.0.14 # Stackbase(gitea)에 릴리즈 태그명 입니다. tagName: v0.0.15 # Stackbase(gitea)에 릴리즈 태그명 입니다.
repoName: sampyo-dio # Stackbase(gitea)에 저장될 저장소 이릅니다. repoName: sampyo-dio # Stackbase(gitea)에 저장될 저장소 이릅니다.

714
main.py
View File

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