#!/usr/bin/env python3 """ MODIFIED: PM 20190108 """ import os import sys import json import time import logging #import urllib.request DEBUG_FILE = True PACKAGE_PARENT = '..' SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__)))) sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT))) #(_path = os.path.abspath("..") #(sys.path.insert(0, _path ) import logconf logger = logging.getLogger(__name__) #(EP renamed) from utils.Device import Device from utils.DeviceSim import DeviceSim from utils.StatusManager import StatusManager #(EP renamed) class PLCSimulator(Device, StatusManager): class PLCSimulator(DeviceSim, StatusManager): # (EP) This simulator will generate some events ? EVENT_GENERATOR=False lights = "ON" shutters = "CLOSE" status ="" def __init__(self, argv): # DeviceSim init super().__init__(argv) # Listen to its own ip and port (the PLC's) self.setDevice("PLC") self.loop = self.loop_3 #PM Load PLC status in colibri-new-fixed-2.json colibri_json = open("colibri-new-fixed-2.json") colibri_struct = json.load(colibri_json) self.status = colibri_struct["statuses"][1]["entities"][0] #EP added if (len(argv) > 1): self.setStatusManager("plcSimulator", argv) self.EVENT_GENERATOR = True #self.set_status() #self.my_state.status = 'init' def plcPrint(self, string: str): if DEBUG_FILE: print("PLCSimulator : " + string) def updateStatus(self, i: int): for dic in self.sims: # ex: dic is like "plcSimulator" : {"device_name":"VantagePro", "value_name":"RainRate", "value":12.0} if (int(dic["time"]) == i): print(dic) change = dic[self.status_name] # ex: {"device_name":"VantagePro", "value_name":"RainRate", "value":12.0} device_name = change["device_name"] # ex: VantagePro devices = self.status["devices"] for device in devices: if device["device_name"] == device_name: values = device["device_values"] # ex: for VantagePro # values = # {"name": "OutsideTemp", "value": 12.45, "unit": "Celcius", "comment": ""}, # {"name": "InsideTemp", "value": 20.28, "unit": "Celcius", "comment": ""}, #... for value in values: if value["name"] == change["value_name"]: # This will indirectly update self.status value["value"] = change["value"] return 0 def handleConnections(self): print("number of connexions to handle: "+str(len(self.connections))) for conn in self.connections: print("current connexion: ") print(conn) data = self.readBytes(1024, conn) answer = "[" count = False #if data != "" and self.isError(data) is False: if data != "" and not self.isError(data): json_array = json.loads(data) command_list = json_array["command"] for command in command_list: if command["name"] == "STATUS": answer = self.get_status(count, answer) count = True elif command["name"] == "LIST": if count: answer += ',' answer += json.dumps(self.status) count = True elif command["name"] == "SWITCH LINES ON": self.lights = "ON" answer = "[Lights turned on" elif command["name"] == "SWITCH LINES OFF": self.lights = "OFF" answer = "[Lights turned off" elif command["name"] == "OPEN SHUTTERS": self.shutters = "OPEN" answer = "[Shutters opened" elif command["name"] == "CLOSE SHUTTERS": self.shutters = "CLOSE" answer = "[Shutters closed" else: print("command received by PLC simulator : [>>> "+ str(command["name"]) + " <<<] unknown") answer += ']' if len(answer) > 0 and answer != "[]": self.sendMessage(answer, conn) return (0) def loop(self): pass def loop_3(self): #from simulators.plc.guitalens_worker import WorkerState, WorkerUrl from plc.guitalens_worker import WorkerState, WorkerUrl # load guitalens_worker self.my_state = WorkerState() self.my_worker = WorkerUrl(self.my_state, self.status) self.my_worker.start() self.my_state.status = 'init' logger.info('Enter loop_3') while (self.my_state.worker == 'start'): if (self.isConnected()): self.handleConnections() time.sleep(0.5) logger.info('Exit loop_3') self.my_state.worker == 'stop' def loop_2(self): #from simulators.plc.meteo_worker import WorkerState, WorkerLog from plc.meteo_worker import WorkerState, WorkerLog # load meteo_worker self.my_state = WorkerState() self.my_worker = WorkerLog(self.my_state, self.status) self.my_worker.start() self.my_state.status = 'init' while (self.my_state.worker == 'start'): if (self.isConnected()): self.handleConnections() time.sleep(0.5) self.my_state.worker == 'stop' return True def loop_1(self): if self.EVENT_GENERATOR and not self.parse(): return False i = 0 if (self.EVENT_GENERATOR and self.ended==0): self.plcPrint("No entry for PLC found in config file : " + self.config_file) return False while (True): print("\n\n\nIteration "+str(i)+" :") if self.EVENT_GENERATOR: self.updateStatus(i) if (self.isConnected()): self.handleConnections() i += 1 if (self.EVENT_GENERATOR and i > self.ended): return (0) return True def run(self): if DEBUG_FILE: print("PLC simulator running...") #if self.EVENT_GENERATOR and not self.parse(): return False self.configSocket() return self.loop() #return (0) # deprecated def set_status(self): self.status = { "name": "STATUS", "from": "Beckhoff", "version_firmware": "20170809", "site": "OSM-Mexico", "date": "2017-03-03T13:45:00", "device": [{"name": "WXT520", "type": "meteo", "serial_number": "14656423", "valid": "yes", "values": [ {"name": "OutsideTemp", "value": 12.12, "unit": "Celcius", "comment": ""}, {"name": "OutsideHumidity", "value": 64.1, "unit": "percent", "comment": ""}, {"name": "Pressure", "value": 769.2, "unit": "mbar", "comment": "At site elevation"}, {"name": "RainRate", "value": 0.0, "unit": "mm/h", "comment": ""}, {"name": "WindSpeed", "value": 3.1, "unit": "m/s", "comment": ""}, {"name": "WindDir", "value": 202.3, "unit": "deg", "comment": "(N=0, E=90)"}, {"name": "DewPoint", "value": 8.3, "unit": "deg", "comment": ""} ] }, {"name": "DRD11", "type": "meteo", "serial_number": "RET6789", "valid": "yes", "values": [ {"name": "analog", "value": 2.345, "unit": "V", "comment": "3V=Dry <2.5V=Rain"}, {"name": "digital", "value": 1, "unit": "bool", "comment": "1=Dry 0=Rain"} ] }, {"name": "VantagePro", "type": "meteo", "serial_number": "ERTRY2344324", "valid": "no", "values": [ {"name": "OutsideTemp", "value": 12.45, "unit": "Celcius", "comment": ""}, {"name": "InsideTemp", "value": 20.28, "unit": "Celcius", "comment": ""}, {"name": "OutsideHumidity", "value": 65.3, "unit": "percent", "comment": ""}, {"name": "InsideHumidity", "value": 45.6, "unit": "percent", "comment": ""}, {"name": "Pressure", "value": 768.7, "unit": "mbar", "comment": "At site elevation"}, {"name": "RainRate", "value": 0.0, "unit": "mm/h", "comment": ""}, {"name": "WindSpeed", "value": 2.8, "unit": "m/s", "comment": ""}, {"name": "WindDir", "value": 207.0, "unit": "deg", "comment": "(N=0, E=90)"}, {"name": "WindDirCardinal", "value": "SW", "unit": "string", "comment": ""}, {"name": "DewPoint", "value": 8.5, "unit": "deg", "comment": ""} ] }, {"name": "MLX90614-1", "type": "meteo", "serial_number": "Unknown", "valid": "yes", "values": [ {"name": "SensorTemperature", "value": 23.56, "unit": "Celcius", "comment": ""}, {"name": "SkyTemperature", "value": -15.67, "unit": "Celcius", "comment": "Clear<-10 VeryCloudy>4"} ] }, {"name": "LAMP_FLAT_CAGIRE", "type": "calib", "serial_number": "REF_3434", "valid": "yes", "values": [ {"name": "status", "value": "on", "unit": "string", "comment": "on or off"}, {"name": "current", "value": 0.234, "unit": "Ampere", "comment": ""} ] }, {"name": "LAMP FLAT CAGIRE", "type": "calib", "serial_number": "REF_3434", "valid": "yes", "values": [ {"name": "status", "value": "on", "unit": "string", "comment": "on or off"}, {"name": "current", "value": 0.234, "unit": "Ampere", "comment": ""} ] }, {"name": "GLOBAL", "values": [ {"name": "mode", "value": "AUTO", "unit": "String", "comment": "AUTO OFF MANU"}, {"name": "is_safe", "value": True, "unit": "bool", "comment": "True or False"}, {"name": "LIGHTS", "value": self.lights, "unit": "String", "comment": "ON or OFF"}, {"name": "SHUTTERS", "value": self.shutters, "unit": "String", "comment": "OPEN OR CLOSE"}, ] } ], } ''' Si on veut rajouter des éléments dans les json il faut penser a ajouter les méthodes correspondantes dans models.py ''' def get_status(self, count, answer): """list = {"name": "LIST", "from": "Beckhoff", "version_firmware": "20170809", "site": "OSM-Mexico", "date": "2017-03-03T13:42:46", "command": [ {"name": "LIST", "type": "", "parameters": "" }, {"name": "SATUS", "type": "", "parameters": "" }, {"name": "LAMP_FLAT_CAGIRE", "type": "calib", "parameters": [ {"name": "value", "unit": "string", "comment": "on or off", "default": ""}, {"name": "current", "unit": "Ampere", "comment": "", "default": "0.345"} ] } ] }""" if count: answer += ',' answer += json.dumps(self.status) return answer if __name__ == "__main__": sim = PLCSimulator(sys.argv) sim.run()