From e4817279c71097974fa122e56a09ae6a975c1ec8 Mon Sep 17 00:00:00 2001 From: "support.sampyo" Date: Tue, 26 Mar 2024 07:08:25 +0000 Subject: [PATCH] Commit message --- .framework.yaml.un~ | Bin 3670 -> 5202 bytes .main.py.un~ | Bin 595 -> 1435 bytes config.json | 11 +- control.json | 26 +++ framework.yaml | 4 +- main.py | 395 ++++++++++++++++++++++++++++++++++++++++++-- main.py_back | 383 ++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 7 + 8 files changed, 810 insertions(+), 16 deletions(-) create mode 100644 control.json create mode 100644 main.py_back create mode 100644 requirements.txt diff --git a/.framework.yaml.un~ b/.framework.yaml.un~ index 684f734fc9829ddd03f4b0e5b3aa76e302d617b9..df9c1e7449f1b104dea126ebdc7554938fe8f655 100644 GIT binary patch delta 271 zcmca6b4kM`EHih0Xr4>{QwFAY$vL&XBBqRQMK>g_f4L;Dxa!R6xs+K!mKgypvk~L~ vDg&DcRnED&fd#0#xD%|Jb@C6^nS#isfs}DUOe~%NaRJ;!kn_!%p05G`3dS`_ delta 117 zcmcblaZN@)EHih0Xr4>{QwAn3zIV@8wG?haD7#$bD z(ZRs*RRU->I}iiokg*O(gQ7w&Gq)hWs6@drJlHcoB%rb+BR?lwf5*Vo$ks}q9pSY1CRRkKTiN%$9$(i{& z3I&xVRnVwI&Wj)yf-){FQ;$X+C`4!qfKhh|T0DaDBPi;)fKdl3UqQKw!L;%DDgfb& BP9OjP literal 595 zcmWH`%$*;a=aT=FfvNe%>lZpNBt@IHf7ANJ8*BdLNU4 Good + # 2. device-app-light-app -> Good + # 3. device-test-app -> Bad + sdtcloud = sdtcloudnodeqmqtt.sdtcloudnodeqmqtt() + mqttClient1 = sdtcloud.setClient(f"device-app-1{uuid.uuid1()}") # parameter is client ID(string) + mqttClient2 = sdtcloud.setClient(f"device-app-2{uuid.uuid1()}") # parameter is client ID(string) + mqttClient3 = sdtcloud.setClient(f"device-app-3{uuid.uuid1()}") # parameter is client ID(string) + mqttClient4 = sdtcloud.setClient(f"device-app-4{uuid.uuid1()}") # parameter is client ID(string) + mqttClient5 = sdtcloud.setClient(f"device-app-5{uuid.uuid1()}") # parameter is client ID(string) + + # 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. + + + topic = f"sdtcloud/{projectCode}/{assetCode}/app/{con_info['appId']}/data" + + cnt = 0 + while True: + start = time.time() + Command_Read() + sdtcloud.pubMessage(mqttlist[cnt], 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(addr, port): + host = addr # "25.7.57.1" + 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') + + client.close() + + sys.exit(0) + if __name__ == "__main__": - runAction() - + output_chip = gpiod.chip('gpiochip11') + config = gpiod.line_request() + config.consumer = 'output' + config.request_type = gpiod.line_request.DIRECTION_OUTPUT + + output_lines = output_chip.get_lines([0, 1, 2, 3, 4, 5, 6, 7]) + output_lines.request(config, default_vals=[0, 0, 0, 0, 0, 0, 0, 0]) + + status = [0, 0, 0, 0, 0, 0, 0, 0] + + signal.signal(signal.SIGINT, exit_handler) + + with open('./config.json', encoding='UTF-8') as f: + jsonData = json.load(f) + + modbus_addr = jsonData['modbus-server']['address'] + modbus_port = jsonData['modbus-server']['port'] + + client = ModbusTcpClient(modbus_addr, modbus_port) + + 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"], jsonData)) + 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) diff --git a/main.py_back b/main.py_back new file mode 100644 index 0000000..bf4cad6 --- /dev/null +++ b/main.py_back @@ -0,0 +1,383 @@ +import ssl +import json +import time +import argparse +import sys, signal +import gpiod +from pymodbus.client import ModbusTcpClient +#import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT +import sdtcloudnodeqmqtt +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') + + mixed_duration = int(cmd['device']['mixed']['duration']) + pure_duration = int(cmd['device']['pure']['duration']) + vent_duration = int(cmd['device']['vent']['duration']) + + 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(mixed_duration) + Valve_MixedWater(chip=output_lines, status=status, action='Off') + 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(vent_duration) + Motor(chip=output_lines, status=status, action='Off') + time.sleep(0.5) + Valve_Vent(chip=output_lines, status=status, action='Off') + time.sleep(0.5) + + # input pure water + Valve_PureWater(chip=output_lines, status=status, action='On') + time.sleep(pure_duration) + 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(vent_duration) + Motor(chip=output_lines, status=status, action='Off') + time.sleep(0.5) + Valve_Vent(chip=output_lines, status=status, action='Off') + time.sleep(1) + + 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): + 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, con_info): + # 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. + + + topic = f"sdtcloud/{projectCode}/{assetCode}/app/{con_info['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(addr, port): + host = addr # "25.7.57.1" + 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') + + client.close() + + sys.exit(0) + +if __name__ == "__main__": + output_chip = gpiod.chip('gpiochip11') + config = gpiod.line_request() + config.consumer = 'output' + config.request_type = gpiod.line_request.DIRECTION_OUTPUT + + output_lines = output_chip.get_lines([0, 1, 2, 3, 4, 5, 6, 7]) + output_lines.request(config, default_vals=[0, 0, 0, 0, 0, 0, 0, 0]) + + status = [0, 0, 0, 0, 0, 0, 0, 0] + + signal.signal(signal.SIGINT, exit_handler) + + with open('./config.json', encoding='UTF-8') as f: + jsonData = json.load(f) + + modbus_addr = jsonData['modbus-server']['address'] + modbus_port = jsonData['modbus-server']['port'] + + client = ModbusTcpClient(modbus_addr, modbus_port) + + 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"], jsonData)) + 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) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ece0e0e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +# Write package's name that need your app. +#awsiotsdk +pyyaml +gpiod +pymodbus +pytz +#sdtcloudpubsub \ No newline at end of file