Compare commits

..

44 Commits
v0.0.5 ... main

Author SHA1 Message Date
support.sampyo 50a6bf2373 Commit message 2024-07-30 05:22:35 +00:00
support.sampyo 5c1d08ee98 Commit message 2024-07-30 04:55:55 +00:00
support.sampyo 95921c49b8 Commit message 2024-07-30 04:50:07 +00:00
support.sampyo 44c6a224c2 Commit message 2024-07-04 06:19:55 +00:00
support.sampyo 797816a6f5 Commit message 2024-07-04 06:14:16 +00:00
support.sampyo 5c41e0664d Commit message 2024-07-04 05:50:25 +00:00
support.sampyo f54f9e7fb5 Commit message 2024-07-04 05:45:11 +00:00
support.sampyo ad62a2f89e Commit message 2024-07-04 05:26:04 +00:00
support.sampyo c566b4070e Commit message 2024-07-04 05:12:08 +00:00
support.sampyo 4239597f8a Commit message 2024-06-12 05:25:29 +00:00
support.sampyo a47d7c2bd9 Commit message 2024-06-12 05:16:08 +00:00
support.sampyo 1a6344fccf Commit message 2024-05-31 01:41:55 +00:00
support.sampyo a493257c17 Commit message 2024-05-30 07:20:05 +00:00
support.sampyo 696cc6f0e8 Commit message 2024-05-30 06:37:40 +00:00
support.sampyo 02a44e8478 Commit message 2024-05-29 08:13:58 +00:00
support.sampyo 3fdb92ae4d Commit message 2024-05-29 08:11:32 +00:00
support.sampyo ddc05f15ee Commit message 2024-05-29 08:09:07 +00:00
support.sampyo 944013c835 Commit message 2024-05-29 06:42:52 +00:00
support.sampyo 8efbc66164 Commit message 2024-05-29 06:30:40 +00:00
support.sampyo d18653ef71 Commit message 2024-05-29 06:15:49 +00:00
support.sampyo 4328027519 Commit message 2024-05-29 06:03:54 +00:00
support.sampyo e5d745c4e1 Commit message 2024-05-29 05:51:51 +00:00
support.sampyo d1a2dd1027 Commit message 2024-05-29 04:27:22 +00:00
support.sampyo c1f26f9340 Commit message 2024-05-24 06:04:38 +00:00
support.sampyo 370d851500 Commit message 2024-05-24 05:17:25 +00:00
support.sampyo e1d1327849 Commit message 2024-05-23 07:15:58 +00:00
support.sampyo b0b16d396c Commit message 2024-05-23 07:09:27 +00:00
support.sampyo ae42726b4d Commit message 2024-05-23 07:03:51 +00:00
support.sampyo e99f5122cb Commit message 2024-05-23 06:47:31 +00:00
support.sampyo f5f155c1bc Commit message 2024-05-23 06:12:49 +00:00
support.sampyo 3a30bba1ef Commit message 2024-05-23 05:50:59 +00:00
support.sampyo 978b40a0c4 Commit message 2024-05-23 05:45:54 +00:00
support.sampyo 0c77a24a40 Commit message 2024-05-23 05:42:56 +00:00
support.sampyo 0a351ca635 Commit message 2024-05-23 05:33:27 +00:00
support.sampyo 0a996b5b66 Commit message 2024-05-23 01:32:45 +00:00
support.sampyo 237ec66789 Commit message 2024-05-03 05:24:53 +00:00
support.sampyo 69dbc3b2e7 Commit message 2024-05-03 05:11:36 +00:00
support.sampyo c35cd3e5e5 Commit message 2024-03-26 11:11:38 +00:00
support.sampyo 1b38b348b5 Commit message 2024-03-26 11:09:36 +00:00
support.sampyo 0cbfb8de48 Commit message 2024-03-26 10:56:40 +00:00
support.sampyo ace959aee5 Commit message 2024-03-26 09:32:33 +00:00
support.sampyo b204963582 Commit message 2024-03-26 09:27:51 +00:00
support.sampyo febe5dcf33 Commit message 2024-03-26 08:41:13 +00:00
support.sampyo 3bb08fbd7b Commit message 2024-03-26 08:16:31 +00:00
15 changed files with 1021 additions and 440 deletions

BIN
.config.json.un~ Normal file

Binary file not shown.

BIN
.control.json.un~ Normal file

Binary file not shown.

Binary file not shown.

BIN
.main.py.swp Normal file

Binary file not shown.

Binary file not shown.

BIN
.test.py.un~ Normal file

Binary file not shown.

View File

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

12
config.json~ Normal file
View File

@ -0,0 +1,12 @@
{
"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,26 +1,49 @@
{ {
"device": { "device": {
"setzero": { "setzero": {
"action": "Off" "action": "Off"
}, },
"measure": { "measure": {
"action": "On" "action": "On"
}, },
"mixed": { "mixed": {
"action": "Off", "action": "Off"
"duration": 15 },
}, "pure": {
"pure": { "action": "Off",
"action": "Off", "duration": 1.5
"duration": 15 },
}, "enter":{
"vent": { "action": "Off"
"action": "Off", },
"duration": 30 "vent": {
}, "action": "On"
"motor": { },
"action": "Off" "motor": {
} "action": "Off"
}, },
"type": "manual" "main": {
} "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"
}

27
control.json~ Normal file
View File

@ -0,0 +1,27 @@
{
"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.5 # Stackbase(gitea)에 릴리즈 태그명 입니다. tagName: v0.0.49 # 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: requirement.txt # 설치할 Python 패키지 정보 파일입니다.(기본 값은 requirement.txt 입니다.) package: requirements.txt # 설치할 Python 패키지 정보 파일입니다.(기본 값은 requirement.txt 입니다.)
stackbase: stackbase:
tagName: v0.0.1 # Stackbase(gitea)에 릴리즈 태그명 입니다. tagName: v0.0.13 # Stackbase(gitea)에 릴리즈 태그명 입니다.
repoName: sampyo-dio # Stackbase(gitea)에 저장될 저장소 이릅니다. repoName: sampyo-dio # Stackbase(gitea)에 저장될 저장소 이릅니다.

923
main.py
View File

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

@ -0,0 +1,375 @@
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()

0
test.py~ Normal file
View File