Compare commits

..

No commits in common. "main" and "v0.0.5" have entirely different histories.
main ... v0.0.5

15 changed files with 440 additions and 1021 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

@ -1,49 +1,26 @@
{ {
"device": { "device": {
"setzero": { "setzero": {
"action": "Off" "action": "Off"
}, },
"measure": { "measure": {
"action": "On" "action": "On"
}, },
"mixed": { "mixed": {
"action": "Off" "action": "Off",
}, "duration": 15
"pure": { },
"action": "Off", "pure": {
"duration": 1.5 "action": "Off",
}, "duration": 15
"enter":{ },
"action": "Off" "vent": {
}, "action": "Off",
"vent": { "duration": 30
"action": "On" },
}, "motor": {
"motor": { "action": "Off"
"action": "Off" }
}, },
"main": { "type": "manual"
"action": "Off", }
"duration": 1.5
}
},
"working-time":{
"step0": 5,
"step1": 10,
"step2": 6,
"step3": 7,
"step4": 20,
"step5": 10,
"step6": 6,
"step7": 6,
"step8": 10,
"step9": 0.5
},
"maintenance": {
"clean": {
"duration": 20,
"time": 25
}
},
"type": "manual"
}

View File

@ -1,27 +0,0 @@
{
"device": {
"setzero": {
"action": "Off"
},
"measure": {
"action": "On"
},
"mixed": {
"action": "Off",
"duration": 15
},
"pure": {
"action": "Off",
"duration": 15
},
"vent": {
"action": "Off",
"duration": 30
},
"motor": {
"action":
"On"
}
},
"type": "manual"
}

View File

@ -1,11 +1,11 @@
version: bwc/v2 # bwc 버전 정보입니다. version: bwc/v2 # bwc 버전 정보입니다.
spec: spec:
appName: sampyo-dio-app # 앱의 이름입니다. appName: sampyo-dio-app # 앱의 이름입니다.
runFile: main.py # 앱의 실행 파일입니다. runFile: main.py # 앱의 실행 파일입니다.
env: env:
bin: python3 # 앱을 실행할 바이너라 파일 종류입니다.(장비에 따라 다르므로 확인 후 정의해야 합니다.) bin: python3 # 앱을 실행할 바이너라 파일 종류입니다.(장비에 따라 다르므로 확인 후 정의해야 합니다.)
virtualEnv: base # 사용할 가상환경 이름입니다. virtualEnv: base # 사용할 가상환경 이름입니다.
package: requirements.txt # 설치할 Python 패키지 정보 파일입니다.(기본 값은 requirement.txt 입니다.) package: requirements.txt # 설치할 Python 패키지 정보 파일입니다.(기본 값은 requirement.txt 입니다.)
stackbase: stackbase:
tagName: v0.0.49 # Stackbase(gitea)에 릴리즈 태그명 입니다. tagName: v0.0.5 # Stackbase(gitea)에 릴리즈 태그명 입니다.
repoName: sampyo-dio # Stackbase(gitea)에 저장될 저장소 이릅니다. repoName: sampyo-dio # Stackbase(gitea)에 저장될 저장소 이릅니다.

View File

@ -5,7 +5,7 @@ spec:
env: env:
bin: python3 # 앱을 실행할 바이너라 파일 종류입니다.(장비에 따라 다르므로 확인 후 정의해야 합니다.) bin: python3 # 앱을 실행할 바이너라 파일 종류입니다.(장비에 따라 다르므로 확인 후 정의해야 합니다.)
virtualEnv: base # 사용할 가상환경 이름입니다. virtualEnv: base # 사용할 가상환경 이름입니다.
package: requirements.txt # 설치할 Python 패키지 정보 파일입니다.(기본 값은 requirement.txt 입니다.) package: requirement.txt # 설치할 Python 패키지 정보 파일입니다.(기본 값은 requirement.txt 입니다.)
stackbase: stackbase:
tagName: v0.0.13 # Stackbase(gitea)에 릴리즈 태그명 입니다. tagName: v0.0.1 # Stackbase(gitea)에 릴리즈 태그명 입니다.
repoName: sampyo-dio # Stackbase(gitea)에 저장될 저장소 이릅니다. repoName: sampyo-dio # Stackbase(gitea)에 저장될 저장소 이릅니다.

923
main.py
View File

@ -1,533 +1,390 @@
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, duration=7): def Valve_PureWater(chip, status, action):
global pure_valve_status if action == 'On':
status[3] = 1
status[2] = 0 else: # action == 'Off'
status[3] = 0 status[3] = 0
chip.set_values(status)
time.sleep(0.05) chip.set_values(status)
if pure_valve_status != 0 and action == 'Off': def Measure_Weight(client):
status[2] = 0 # print('In')
status[3] = 1 try:
chip.set_values(status) result = client.read_holding_registers(1, 1)
time.sleep(7) if result.isError():
pure_valve_status = 0 print(f'Error: {result}')
elif pure_valve_status == 0 and action == 'On': else:
status[2] = 1 val = result.registers[0]
status[3] = 0 val -= 1000
chip.set_values(status) val /= 1000
time.sleep(duration)
if duration >= 7: # print(f'value: {val}')
pure_valve_status = 2 except Exception as e:
elif duration < 7: pass
pure_valve_status = 1
return val
status[2] = 0
status[3] = 0 def Calculate_Concentration(weight):
chip.set_values(status) global data
time.sleep(0.05) data['data']['weight'] = weight
result = (float(weight) * 1.883239171 * 128.5) - 126.11 # 1000 / 531 = 1.883239171
def Valve_EnterWater(chip, status, action): data['data']['concentration'] = result
if action == 'On': # print(f'{weight}, {result}')
status[4] = 1
else: # action == 'Off' def Set_Zero(client):
status[4] = 0 client.write_coil(1, 1)
chip.set_values(status) def Command_Read():
with open('./control.json', 'r') as f:
def Valve_MainWater(chip, status, action, duration=7): cmd = json.load(f)
global main_valve_status
if cmd['type'] == 'auto':
status[5] = 0
status[6] = 0 Valve_Vent(chip=output_lines, status=status, action='Off')
chip.set_values(status) Motor(chip=output_lines, status=status, action='Off')
time.sleep(0.05)
mixed_duration = int(cmd['device']['mixed']['duration'])
if main_valve_status != 0 and action == 'Off': pure_duration = int(cmd['device']['pure']['duration'])
status[5] = 0 vent_duration = int(cmd['device']['vent']['duration'])
status[6] = 1
chip.set_values(status) time.sleep(5)
time.sleep(7) start = Measure_Weight(client=client)
main_valve_status = 0 time.sleep(5)
elif main_valve_status == 0 and action == 'On':
status[5] = 1 # input mixed water
status[6] = 0 Valve_MixedWater(chip=output_lines, status=status, action='On')
chip.set_values(status) time.sleep(mixed_duration)
time.sleep(duration) Valve_MixedWater(chip=output_lines, status=status, action='Off')
if duration >= 7: time.sleep(10)
main_valve_status = 2
elif duration < 7: # measure weight
main_valve_status = 1 end = Measure_Weight(client=client)
time.sleep(1)
status[5] = 0
status[6] = 0 Calculate_Concentration(weight=(float(end)-float(start)))
chip.set_values(status)
time.sleep(0.05) # vent mixed water
Valve_Vent(chip=output_lines, status=status, action='On')
def Measure_Weight(client): time.sleep(0.5)
# print('in') Motor(chip=output_lines, status=status, action='On')
val = 0 time.sleep(vent_duration)
try: Motor(chip=output_lines, status=status, action='Off')
result = client.read_holding_registers(1, 1) time.sleep(0.5)
if not result: Valve_Vent(chip=output_lines, status=status, action='Off')
print(f'Error: {result}') time.sleep(0.5)
else:
val = result.registers[0] # input pure water
val -= 1000 Valve_PureWater(chip=output_lines, status=status, action='On')
val /= 1000 time.sleep(pure_duration)
# print(f'value: {val}') Valve_PureWater(chip=output_lines, status=status, action='Off')
except Exception as e: time.sleep(0.5)
print(f'Measure_Weight Error: {e}')
pass # vent pure water
Valve_Vent(chip=output_lines, status=status, action='On')
return float(val) time.sleep(0.5)
Motor(chip=output_lines, status=status, action='On')
def Calculate_Concentration(weight): time.sleep(vent_duration)
global data, volume_water Motor(chip=output_lines, status=status, action='Off')
data['data']['weight'] = weight time.sleep(0.5)
result = (float(weight) * volume_water * 128.5) - 126.11 # 1000 / 531 = 1.883239171 Valve_Vent(chip=output_lines, status=status, action='Off')
data['data']['concentration'] = result time.sleep(1)
# print(f'{weight}, {result}')
else: # cmd['type'] == 'manual'
def Set_Zero(client): Motor(chip=output_lines, status=status, action=cmd['device']['motor']['action'])
client.write_coil(1, 1) Valve_Vent(chip=output_lines, status=status, action=cmd['device']['vent']['action'])
Valve_MixedWater(chip=output_lines, status=status, action=cmd['device']['mixed']['action'])
def Command_Read(): Valve_PureWater(chip=output_lines, status=status, action=cmd['device']['pure']['action'])
global client, main_valve_status if cmd['device']['measure']['action'] == 'On':
result = Measure_Weight(client=client)
with open('./control.json', 'r') as f: Calculate_Concentration(result)
cmd = json.load(f) if cmd['device']['setzero']['action'] == 'On':
Set_Zero(client=client)
if cmd['type'] == 'auto':
main_duration = float(cmd['device']['main']['duration']) def connectMQTT(clientID, projectCode):
pure_duration = float(cmd['device']['pure']['duration']) CLIENT_ID = clientID
step0_duration = float(cmd['working-time']['step0']) ENDPOINT = "avk03ee629rck-ats.iot.ap-northeast-2.amazonaws.com"
step1_duration = float(cmd['working-time']['step1']) PATH_TO_CERTIFICATE = f"/etc/sdt/cert/{projectCode}-certificate.pem"
step2_duration = float(cmd['working-time']['step2']) PATH_TO_PRIVATE_KEY = f"/etc/sdt/cert/{projectCode}-private.pem"
step3_duration = float(cmd['working-time']['step3']) PATH_TO_AMAZON_ROOT_CA_1 = f"/etc/sdt/cert/AmazonRootCA1.pem"
step4_duration = float(cmd['working-time']['step4'])
step5_duration = float(cmd['working-time']['step5']) myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient(CLIENT_ID)
step6_duration = float(cmd['working-time']['step6']) myAWSIoTMQTTClient.configureEndpoint(ENDPOINT, 8883)
step7_duration = float(cmd['working-time']['step7']) myAWSIoTMQTTClient.configureCredentials(PATH_TO_AMAZON_ROOT_CA_1, PATH_TO_PRIVATE_KEY, PATH_TO_CERTIFICATE)
step8_duration = float(cmd['working-time']['step8'])
step9_duration = float(cmd['working-time']['step9']) myAWSIoTMQTTClient.configureMQTTOperationTimeout(5)
myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10)
myAWSIoTMQTTClient.configureOfflinePublishQueueing(-1) # Infinite offline Publish queueing
# Step 0. Mesure init weight before starting the sequence myAWSIoTMQTTClient.configureDrainingFrequency(2) # Draining: 2 Hz
time.sleep(step0_duration)
start = Measure_Weight(client=client) return myAWSIoTMQTTClient
# Step 1. Vent pured water before input mixed water def publishMsg(mqttClient, topic, msg):
# Target valve status: [Motor: Off, Vent: On, Pure: Off, Enter: On, Main: On] while True:
Valve_EnterWater(chip=output_lines, status=status, action='On') try:
time.sleep(0.5) mqttClient.connect()
Valve_Vent(chip=output_lines, status=status, action='On') break
time.sleep(0.5) except Exception as e:
Valve_MainWater(chip=output_lines, status=status, action='On', duration=main_duration) print(f'Connection Fail: {e}')
time.sleep(step1_duration) continue
# Step 2. Empty the remaining pure water msg['timestamp'] = int(time.time() * 1000)
# Target valve status: [Motor: Off, Vent: On, Pure: Off, Enter: Off, Main: On]
Valve_EnterWater(chip=output_lines, status=status, action='Off') # Publish message to server desired number of times.
time.sleep(step2_duration) # print('Begin Publish')
mqttClient.publish(topic=topic, payload=json.dumps(msg), QoS=1)
# Step 3. Input the mixed water
# Target valve status: [Motor: Off, Vent: Off, Pure: Off, Enter: On, Main: On] while True:
Valve_Vent(chip=output_lines, status=status, action='Off') try:
time.sleep(0.5) mqttClient.disconnect()
Valve_EnterWater(chip=output_lines, status=status, action='On') break
time.sleep(step3_duration) except Exception as e:
print(f'Disconnection Fail: {e}')
# Step 4. Mesure the weight continue
# Target valve status: [Motor: Off, Vent: Off, Pure: Off, Enter: Off, Main: Off]
Valve_EnterWater(chip=output_lines, status=status, action='Off') def runAction(projectCode, assetCode, con_info):
time.sleep(0.5) # Write the app's actions in the "runAction" function.
Valve_MainWater(chip=output_lines, status=status, action='Off')
# Connect MQTT Broker
time.sleep(step4_duration) # You have to rename client id. There are special rules.
end = Measure_Weight(client=client) # Client Name: "device-app-*"
time.sleep(1) # For Example
# 1. device-app-test -> Good
Calculate_Concentration(weight=(float(end)-float(start))) # 2. device-app-light-app -> Good
# 3. device-test-app -> Bad
# Step 5. Drain the mixed water and add pure water. sdtcloud = sdtcloudnodeqmqtt.sdtcloudnodeqmqtt()
# Target valve status: [Motor: Off, Vent: On, Pure: On, Enter: On, Main: Off] mqttClient1 = sdtcloud.setClient(f"device-app-1{uuid.uuid1()}") # parameter is client ID(string)
Valve_EnterWater(chip=output_lines, status=status, action='On') mqttClient2 = sdtcloud.setClient(f"device-app-2{uuid.uuid1()}") # parameter is client ID(string)
time.sleep(0.5) mqttClient3 = sdtcloud.setClient(f"device-app-3{uuid.uuid1()}") # parameter is client ID(string)
Valve_Vent(chip=output_lines, status=status, action='On') mqttClient4 = sdtcloud.setClient(f"device-app-4{uuid.uuid1()}") # parameter is client ID(string)
time.sleep(0.5) mqttClient5 = sdtcloud.setClient(f"device-app-5{uuid.uuid1()}") # parameter is client ID(string)
Valve_PureWater(chip=output_lines, status=status, action='On', duration=pure_duration)
time.sleep(step5_duration) # mqttClient1 = connectMQTT("device-app-test1", projectCode)
# mqttClient2 = connectMQTT("device-app-test2", projectCode)
# Step 6. Drain mixed water # mqttClient3 = connectMQTT("device-app-test3", projectCode)
# Target valve status: [Motor: Off, Vent: On, Pure: On, Enter: Off, Main: Off] # mqttClient4 = connectMQTT("device-app-test4", projectCode)
Valve_EnterWater(chip=output_lines, status=status, action='Off') # mqttClient5 = connectMQTT("device-app-test5", projectCode)
time.sleep(step6_duration) mqttlist = [mqttClient1, mqttClient2, mqttClient3, mqttClient4, mqttClient5]
# Step 7. Input pure water and clean # If you have config's value, please make config.json file.
# Target valve status: [Motor: On, Vent: Off, Pure: On, Enter: On, Main: Off] # - Project Code's variable: projectCode(string)
Valve_EnterWater(chip=output_lines, status=status, action='On') # - Asset Code's variable: assetCode(string)
time.sleep(0.5) # - You may need it to create a topic.
Valve_Vent(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
Motor(chip=output_lines, status=status, action='On') topic = f"sdtcloud/{projectCode}/{assetCode}/app/{con_info['appId']}/data"
time.sleep(step7_duration)
cnt = 0
# Step 8. Drain pure Water while True:
# Target valve status: [Motor: On, Vent: On, Pure: Off, Enter: Off, Main: Off] start = time.time()
Valve_EnterWater(chip=output_lines, status=status, action='Off') Command_Read()
time.sleep(0.5) sdtcloud.pubMessage(mqttlist[cnt], data)
Valve_Vent(chip=output_lines, status=status, action='On') end = time.time()
time.sleep(0.5)
Valve_PureWater(chip=output_lines, status=status, action='Off') cnt += 1
time.sleep(step8_duration)
if cnt == 5:
# Step 9. Stop moter cnt = 0
# Target valve status: [Motor: Off, Vent: On, Pure: Off, Enter: Off, Main: Off]
Motor(chip=output_lines, status=status, action='Off') diff = end - start
time.sleep(step9_duration) if diff < 3:
time.sleep(3 - diff)
return 1
def handle_client(conn, ip, port):
elif cmd['type'] == 'clean': global data
clean_system() while True:
time.sleep(3) try:
recv = conn.recv(100)
else: # cmd['type'] == 'manual' if not recv:
Motor(chip=output_lines, status=status, action=cmd['device']['motor']['action']) # print(f"Connection with {addr} was reset. Waiting for new connection.")
Valve_Vent(chip=output_lines, status=status, action=cmd['device']['vent']['action']) break
# Valve_MixedWater(chip=output_lines, status=status, action=cmd['device']['mixed']['action'])
# Valve_PureWater(chip=output_lines, status=status, action=cmd['device']['pure']['action']) message = recv.decode().strip()
Valve_EnterWater(chip=output_lines, status=status, action=cmd['device']['enter']['action'])
if message[:3] != 'STX' or message[-3:] != 'ETX':
if cmd['device']['pure']['duration'] == 0: err_msg = 'STXERRORETX'
Valve_PureWater(chip=output_lines, status=status, action=cmd['device']['pure']['action']) conn.sendall(err_msg.encode("utf8"))
else: else:
Valve_PureWater(chip=output_lines, status=status, action=cmd['device']['pure']['action'], duration=cmd['device']['pure']['duration']) 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')
if cmd['device']['main']['duration'] == 0:
Valve_MainWater(chip=output_lines, status=status, action=cmd['device']['main']['action']) h_weight = float(data['data']['weight'])
else: h_concentration = float(data['data']['concentration'])
Valve_MainWater(chip=output_lines, status=status, action=cmd['device']['main']['action'], duration=cmd['device']['main']['duration']) data_weight = '{:.3f}'.format(h_weight)
data_concent = '{:.3f}'.format(h_concentration)
if cmd['device']['measure']['action'] == 'On': send_msg = 'STX' + time_str + '|' + data_weight + '|' + data_concent + 'ETX'
result = Measure_Weight(client=client)
Calculate_Concentration(result) try:
return 1 with open('./control.json', 'r') as f:
cmd = json.load(f)
if cmd['device']['setzero']['action'] == 'On':
Set_Zero(client=client) cmd['device']['measure']['action'] = 'On'
return 0 with open('./control.json', 'w') as f:
json.dump(cmd, f, indent=4)
def clean_system():
global main_valve_status 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"))
clean_duration = int(cmd['maintenance']['clean']['duration'])
elif message[3] == 'S': # Start measurement
if cmd['type'] == 'clean': try:
Valve_EnterWater(chip=output_lines, status=status, action='Off') with open('./control.json', 'r') as f:
time.sleep(0.5) cmd = json.load(f)
Valve_MainWater(chip=output_lines, status=status, action='On') cmd['type'] = 'auto'
time.sleep(0.5)
Valve_PureWater(chip=output_lines, status=status, action='On') with open('./control.json', 'w') as f:
time.sleep(clean_duration) json.dump(cmd, f, indent=4)
Valve_MainWater(chip=output_lines, status=status, action='Off') send_msg = 'STXOKETX'
time.sleep(0.5) conn.sendall(send_msg.encode("utf8"))
except Exception as e:
Valve_EnterWater(chip=output_lines, status=status, action='On') err_msg = 'STXERRORETX'
time.sleep(0.5) conn.sendall(err_msg.encode("utf8"))
Valve_Vent(chip=output_lines, status=status, action='On')
time.sleep(clean_duration) elif message[3] == 'T': # Stop measurement
try:
Valve_PureWater(chip=output_lines, status=status, action='Off') with open('./control.json', 'r') as f:
time.sleep(0.5) cmd = json.load(f)
Valve_Vent(chip=output_lines, status=status, action='Off')
time.sleep(0.5) cmd['type'] = 'manual'
Valve_EnterWater(chip=output_lines, status=status, action='Off') cmd['device']['measure']['action'] = 'Off'
time.sleep(0.5)
with open('./control.json', 'w') as f:
def runAction(): json.dump(cmd, f, indent=4)
# Write the app's actions in the "runAction" function.
send_msg = 'STXOKETX'
# Connect MQTT Broker conn.sendall(send_msg.encode("utf8"))
# You have to rename client id. There are special rules. except Exception as e:
# Client Name: "device-app-*" err_msg = 'STXERRORETX'
# For Example conn.sendall(err_msg.encode("utf8"))
# 1. device-app-test -> Good
# 2. device-app-light-app -> Good else:
# 3. device-test-app -> Bad err_msg = 'STXERRORETX'
global data conn.sendall(err_msg.encode("utf8"))
sdtcloud = sdtcloudnodeqmqtt.sdtcloudnodeqmqtt() except ConnectionResetError:
mqttClient1 = sdtcloud.setClient(f"device-app-1{uuid.uuid1()}") # parameter is client ID(string) # print("Connection with " + ip + ":" + port + " was reset. Waiting for new connection.")
mqttClient2 = sdtcloud.setClient(f"device-app-2{uuid.uuid1()}") # parameter is client ID(string) break
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) # print("Closing the connection")
mqttClient5 = sdtcloud.setClient(f"device-app-5{uuid.uuid1()}") # parameter is client ID(string)
mqttlist = [mqttClient1, mqttClient2, mqttClient3, mqttClient4, mqttClient5] def start_server(addr, port):
host = addr # "25.7.57.1"
# If you have config's value, please make config.json file. port = port # 5000
# - Project Code's variable: projectCode(string)
# - Asset Code's variable: assetCode(string) soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# - You may need it to create a topic. soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
cnt = 0 try:
clean_flag = 0 soc.bind((host, port))
while True: except:
start = time.time() sys.exit()
result = Command_Read()
soc.listen(1) # Only one connection at a time.
if result:
data['timestamp'] = int(time.time() * 1000) while True:
sdtcloud.pubMessage(mqttlist[cnt], data) conn, addr = soc.accept()
cnt += 1 ip, port = str(addr[0]), str(addr[1])
if cnt == 5: print("Connected with " + ip + ":" + port)
cnt = 0
client_handler = threading.Thread(target=handle_client, args=(conn, ip, port))
end = time.time() client_handler.start()
try: soc.close()
now = datetime.now(pytz.timezone('Asia/Seoul'))
time_str = now.strftime('%H') def exit_handler(signum, frame):
time_int = int(time_str) Motor(chip=output_lines, status=status, action='Off')
Valve_Vent(chip=output_lines, status=status, action='Off')
with open('./control.json', 'r') as f: Valve_MixedWater(chip=output_lines, status=status, action='Off')
cmd = json.load(f) Valve_PureWater(chip=output_lines, status=status, action='Off')
if time_int == int(cmd['maintenance']['clean']['time']): client.close()
if clean_flag < 3:
clean_flag += 1 sys.exit(0)
clean_system()
else: if __name__ == "__main__":
clean_flag = 0 output_chip = gpiod.chip('gpiochip11')
except: config = gpiod.line_request()
pass config.consumer = 'output'
config.request_type = gpiod.line_request.DIRECTION_OUTPUT
diff = end - start
if diff < 3: output_lines = output_chip.get_lines([0, 1, 2, 3, 4, 5, 6, 7])
time.sleep(3 - diff) output_lines.request(config, default_vals=[0, 0, 0, 0, 0, 0, 0, 0])
def handle_client(conn, ip, port): status = [0, 0, 0, 0, 0, 0, 0, 0]
global data
while True: signal.signal(signal.SIGINT, exit_handler)
try:
recv = conn.recv(100) with open('./config.json', encoding='UTF-8') as f:
if not recv: jsonData = json.load(f)
# print(f"Connection with {addr} was reset. Waiting for new connection.")
break modbus_addr = jsonData['modbus-server']['address']
modbus_port = jsonData['modbus-server']['port']
message = recv.decode().strip()
client = ModbusTcpClient(modbus_addr, modbus_port)
if message[:3] != 'STX' or message[-3:] != 'ETX':
err_msg = 'STXERRORETX' parser = argparse.ArgumentParser()
conn.sendall(err_msg.encode("utf8")) parser.add_argument('-app',help='')
else: args = parser.parse_args()
if message[3] == 'R': # Transfer data from SDT to Sampyo
now = datetime.now(pytz.timezone('Asia/Seoul')) # ROOT_PATH = f'/usr/local/sdt/app/{args.app}'
time_str = now.strftime('%Y%m%d%H%M%S')
data = {
h_weight = float(data['data']['weight']) "timestamp": 0,
h_concentration = float(data['data']['concentration']) "data":{
data_weight = '{:.3f}'.format(h_weight) "weight": 0,
data_concent = '{:.3f}'.format(h_concentration) "concentration": 0
}
send_msg = 'STX' + time_str + '|' + data_weight + '|' + data_concent + 'ETX' }
try: ## Get ProjectCode and AssetCode
with open('./control.json', 'r') as f: with open(f'/etc/sdt/device.config/config.json', encoding='UTF-8') as f:
cmd = json.load(f) codeData = json.load(f)
cmd['device']['measure']['action'] = 'On' ## Execution main funcion
operation_thread = threading.Thread(target=runAction, args=(codeData["projectcode"], codeData["assetcode"], jsonData))
with open('./control.json', 'w') as f: operation_thread.start()
json.dump(cmd, f, indent=4)
tcp_addr = jsonData['tcp-server']['address']
conn.sendall(send_msg.encode("utf8")) tcp_port = jsonData['tcp-server']['port']
except Exception as e: ## Execution TCP/IP server
err_msg = 'STXERRORETX' start_server(addr=tcp_addr, port=tcp_port)
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"))
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.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"))
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):
host = addr # "172.17.16.201"
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')
Valve_EnterWater(chip=output_lines, status=status, action='Off')
Valve_MainWater(chip=output_lines, status=status, action='Off')
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)
main_valve_status = 0
pure_valve_status = 0
Valve_MainWater(chip=output_lines, status=status, action='Off')
Valve_PureWater(chip=output_lines, status=status, action='Off')
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)

375
test.py
View File

@ -1,375 +0,0 @@
import ssl
import json
import time
import argparse
import sys, signal
import gpiod
from pymodbus.client import ModbusTcpClient
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
import asyncio, pytz
from datetime import datetime
import threading, socket
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)
def Measure_Weight(client):
# print('In')
try:
result = client.read_holding_registers(1, 1)
if result.isError():
print(f'Error: {result}')
else:
val = result.registers[0]
val -= 1000
val /= 1000
# print(f'value: {val}')
except Exception as e:
pass
return val
def Calculate_Concentration(weight):
global data
data['data']['weight'] = weight
result = (float(weight) * 1.883239171 * 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():
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')
# set zero
# Set_Zero(client=client)
time.sleep(5)
start = Measure_Weight(client=client)
time.sleep(5)
# input mixed water
Valve_MixedWater(chip=output_lines, status=status, action='On')
time.sleep(19)
Valve_MixedWater(chip=output_lines, status=status, action='Off')
# time.sleep(20)
time.sleep(10)
# measure weight
end = Measure_Weight(client=client)
time.sleep(1)
Calculate_Concentration(weight=(float(end)-float(start)))
# vent mixed water
Valve_Vent(chip=output_lines, status=status, action='On')
time.sleep(0.5)
Motor(chip=output_lines, status=status, action='On')
time.sleep(40)
Motor(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
Valve_Vent(chip=output_lines, status=status, action='Off')
# input pure water
Valve_PureWater(chip=output_lines, status=status, action='On')
time.sleep(19)
Valve_PureWater(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
# vent pure water
Valve_Vent(chip=output_lines, status=status, action='On')
time.sleep(0.5)
Motor(chip=output_lines, status=status, action='On')
time.sleep(40)
Motor(chip=output_lines, status=status, action='Off')
time.sleep(0.5)
Valve_Vent(chip=output_lines, status=status, action='Off')
time.sleep(5)
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'])
if cmd['device']['measure']['action'] == 'On':
result = Measure_Weight(client=client)
Calculate_Concentration(result)
if cmd['device']['setzero']['action'] == 'On':
Set_Zero(client=client)
def connectMQTT(clientID, projectCode):
CLIENT_ID = clientID
ENDPOINT = "avk03ee629rck-ats.iot.ap-northeast-2.amazonaws.com"
PATH_TO_CERTIFICATE = f"/etc/sdt/cert/{projectCode}-certificate.pem"
PATH_TO_PRIVATE_KEY = f"/etc/sdt/cert/{projectCode}-private.pem"
PATH_TO_AMAZON_ROOT_CA_1 = f"/etc/sdt/cert/AmazonRootCA1.pem"
myAWSIoTMQTTClient = AWSIoTPyMQTT.AWSIoTMQTTClient(CLIENT_ID)
myAWSIoTMQTTClient.configureEndpoint(ENDPOINT, 8883)
myAWSIoTMQTTClient.configureCredentials(PATH_TO_AMAZON_ROOT_CA_1, PATH_TO_PRIVATE_KEY, PATH_TO_CERTIFICATE)
myAWSIoTMQTTClient.configureMQTTOperationTimeout(5)
myAWSIoTMQTTClient.configureConnectDisconnectTimeout(10)
myAWSIoTMQTTClient.configureOfflinePublishQueueing(-1) # Infinite offline Publish queueing
myAWSIoTMQTTClient.configureDrainingFrequency(2) # Draining: 2 Hz
return myAWSIoTMQTTClient
def publishMsg(mqttClient, topic, msg):
# Make the copip3 nnect() call
# mqttClient.connect()
while True:
try:
mqttClient.connect()
break
except Exception as e:
print(f'Connection Fail: {e}')
continue
msg['timestamp'] = int(time.time() * 1000)
# Publish message to server desired number of times.
# print('Begin Publish')
mqttClient.publish(topic=topic, payload=json.dumps(msg), QoS=1)
while True:
try:
mqttClient.disconnect()
break
except Exception as e:
print(f'Disconnection Fail: {e}')
continue
def runAction(projectCode, assetCode):
# 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
mqttClient1 = connectMQTT("device-app-test1", projectCode)
mqttClient2 = connectMQTT("device-app-test2", projectCode)
mqttClient3 = connectMQTT("device-app-test3", projectCode)
mqttClient4 = connectMQTT("device-app-test4", projectCode)
mqttClient5 = connectMQTT("device-app-test5", projectCode)
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.
with open('./config.json', encoding='UTF-8') as f:
jsonData = json.load(f)
topic = f"sdtcloud/{projectCode}/{assetCode}/app/{jsonData['appId']}/data"
cnt = 0
while True:
start = time.time()
Command_Read()
# publishMsg(mqttlist[cnt], topic, data)
end = time.time()
cnt += 1
if cnt == 5:
cnt = 0
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"))
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():
host = "25.7.57.1"
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')
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)
client = ModbusTcpClient('25.7.55.237', 5020)
parser = argparse.ArgumentParser()
parser.add_argument('-app',help='')
args = parser.parse_args()
# ROOT_PATH = f'/usr/local/sdt/app/{args.app}'
data = {
"timestamp": 0,
"data":{
"weight": 0,
"concentration": 0
}
}
## Get ProjectCode and AssetCode
with open(f'/etc/sdt/device.config/config.json', encoding='UTF-8') as f:
codeData = json.load(f)
## Execution main funcion
operation_thread = threading.Thread(target=runAction, args=(codeData["projectcode"], codeData["assetcode"]))
operation_thread.start()
## Execution TCP/IP server
start_server()

View File