Blame view

simulators/plc/plcSimulator.py 12.3 KB
20ed1e7a   Etienne Pallier   bugfixed time sav...
1
#!/usr/bin/env python3
240873f8   Patrick Maeght   date modif
2
"""
20ed1e7a   Etienne Pallier   bugfixed time sav...
3

240873f8   Patrick Maeght   date modif
4
5
6
7
MODIFIED:
PM 20190108

"""
3c179769   Jeremy   userSimulator / a...
8
import os
ce470283   Jeremy   Plc simulator fin...
9
import sys
6c2793c2   jeremy   Update
10
import json
d18e437e   Patrick Maeght   New json in
11
import time
f4465c28   Patrick Maeght   json modified fro...
12
import logging
240873f8   Patrick Maeght   date modif
13
#import urllib.request
3c179769   Jeremy   userSimulator / a...
14

75ec5b27   Etienne Pallier   bugfix simulateur...
15
DEBUG_FILE = True
3c179769   Jeremy   userSimulator / a...
16
17
18
19
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)))

f4465c28   Patrick Maeght   json modified fro...
20
21
22
23
24
#(_path = os.path.abspath("..")
#(sys.path.insert(0, _path )
import logconf
logger = logging.getLogger(__name__)

1957226d   Etienne Pallier   Renamed (simulato...
25
26
#(EP renamed) from utils.Device import Device
from utils.DeviceSim import DeviceSim
605b65e5   Jeremy   Update simulators
27
from utils.StatusManager import StatusManager
6c2793c2   jeremy   Update
28

1957226d   Etienne Pallier   Renamed (simulato...
29
30
#(EP renamed) class PLCSimulator(Device, StatusManager):
class PLCSimulator(DeviceSim, StatusManager):
75ec5b27   Etienne Pallier   bugfix simulateur...
31
32
33
    
    # (EP) This simulator will generate some events ?
    EVENT_GENERATOR=False
fc957772   Quentin Durand   Control command P...
34
35
36
37

    lights = "ON"
    shutters = "CLOSE"
    status =""
6c2793c2   jeremy   Update
38

65149de7   Jeremy   Update
39
    def __init__(self, argv):
75ec5b27   Etienne Pallier   bugfix simulateur...
40
        # DeviceSim init
605b65e5   Jeremy   Update simulators
41
        super().__init__(argv)
c7583f6e   Etienne Pallier   Cleaner isolation...
42
        # Listen to its own ip and port (the PLC's)
605b65e5   Jeremy   Update simulators
43
        self.setDevice("PLC")
f6076245   Patrick Maeght   penelope work part 1
44
        self.loop = self.loop_3
e355ba3f   Patrick Maeght   PlcSimulator with...
45
46
47
48
        #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]
75ec5b27   Etienne Pallier   bugfix simulateur...
49
50
51
52
        #EP added
        if (len(argv) > 1):
            self.setStatusManager("plcSimulator", argv)
            self.EVENT_GENERATOR = True
d18e437e   Patrick Maeght   New json in
53
        #self.set_status()
d18e437e   Patrick Maeght   New json in
54
55
        #self.my_state.status = 'init'

3c179769   Jeremy   userSimulator / a...
56

b6b0fd47   Jeremy   Added parameters ...
57
    def plcPrint(self, string: str):
3224f14a   Jeremy   Fixed some simula...
58
59
        if DEBUG_FILE:
            print("PLCSimulator : " + string)
3c179769   Jeremy   userSimulator / a...
60

6c2793c2   jeremy   Update
61
62
    def updateStatus(self, i: int):
        for dic in self.sims:
c7583f6e   Etienne Pallier   Cleaner isolation...
63
            # ex: dic is like "plcSimulator" : {"device_name":"VantagePro", "value_name":"RainRate", "value":12.0} 
6c2793c2   jeremy   Update
64
            if (int(dic["time"]) == i):
c7583f6e   Etienne Pallier   Cleaner isolation...
65
66
67
                print(dic)
                change = dic[self.status_name] # ex: {"device_name":"VantagePro", "value_name":"RainRate", "value":12.0} 
                device_name = change["device_name"] # ex: VantagePro
d18e437e   Patrick Maeght   New json in
68
                devices = self.status["devices"]
6c2793c2   jeremy   Update
69
                for device in devices:
d18e437e   Patrick Maeght   New json in
70
71
                    if device["device_name"] == device_name:
                        values = device["device_values"]
c7583f6e   Etienne Pallier   Cleaner isolation...
72
73
74
75
76
                        # ex: for VantagePro
                        # values =
                        # {"name": "OutsideTemp", "value": 12.45, "unit": "Celcius", "comment": ""},
                        # {"name": "InsideTemp", "value": 20.28, "unit": "Celcius", "comment": ""},
                        #...
6c2793c2   jeremy   Update
77
78
                        for value in values:
                            if value["name"] == change["value_name"]:
c7583f6e   Etienne Pallier   Cleaner isolation...
79
                                # This will indirectly update self.status
6c2793c2   jeremy   Update
80
81
82
                                value["value"] = change["value"]
        return 0

ce470283   Jeremy   Plc simulator fin...
83

f7dd3df1   Jeremy   Update simulators...
84
    def handleConnections(self):
c7583f6e   Etienne Pallier   Cleaner isolation...
85
86
87
88
89
        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)
6c2793c2   jeremy   Update
90
91
            answer = "["
            count = False
c7583f6e   Etienne Pallier   Cleaner isolation...
92
93
            #if data != "" and self.isError(data) is False:
            if data != "" and not self.isError(data):
fe5613f5   jeremy   Update plc protocol
94
95
96
97
                json_array = json.loads(data)
                command_list = json_array["command"]
                for command in command_list:
                    if command["name"] == "STATUS":
fc957772   Quentin Durand   Control command P...
98
                        answer = self.get_status(count, answer)
fe5613f5   jeremy   Update plc protocol
99
100
101
102
103
104
                        count = True
                    elif command["name"] == "LIST":
                        if count:
                            answer += ','
                        answer += json.dumps(self.status)
                        count = True
fc957772   Quentin Durand   Control command P...
105
106
107
108
109
110
111
112
113
114
115
116
                    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"
fe5613f5   jeremy   Update plc protocol
117
118
119
120
                    else:
                        print("command received by PLC simulator : [>>> "+ str(command["name"]) + " <<<] unknown")
                answer += ']'
                if len(answer) > 0 and answer != "[]":
c7583f6e   Etienne Pallier   Cleaner isolation...
121
                    self.sendMessage(answer, conn)
3c179769   Jeremy   userSimulator / a...
122
123
        return (0)

e355ba3f   Patrick Maeght   PlcSimulator with...
124
125
126
127
    def loop(self):
        pass

    def loop_3(self):
88e5c09f   Etienne Pallier   petit bugfix import
128
129
        #from simulators.plc.guitalens_worker import WorkerState, WorkerUrl
        from plc.guitalens_worker import WorkerState, WorkerUrl
e355ba3f   Patrick Maeght   PlcSimulator with...
130
131
132
133
        # load guitalens_worker
        self.my_state = WorkerState()
        self.my_worker = WorkerUrl(self.my_state, self.status)
        self.my_worker.start()
d18e437e   Patrick Maeght   New json in
134
        self.my_state.status = 'init'
f4465c28   Patrick Maeght   json modified fro...
135
        logger.info('Enter loop_3')
d18e437e   Patrick Maeght   New json in
136
137
138
        while (self.my_state.worker == 'start'):
            if (self.isConnected()):
                    self.handleConnections()
e355ba3f   Patrick Maeght   PlcSimulator with...
139
            time.sleep(0.5)
f4465c28   Patrick Maeght   json modified fro...
140
        logger.info('Exit loop_3')
e355ba3f   Patrick Maeght   PlcSimulator with...
141
        self.my_state.worker == 'stop'
d18e437e   Patrick Maeght   New json in
142

e355ba3f   Patrick Maeght   PlcSimulator with...
143
    def loop_2(self):
88e5c09f   Etienne Pallier   petit bugfix import
144
145
        #from simulators.plc.meteo_worker import WorkerState, WorkerLog
        from plc.meteo_worker import WorkerState, WorkerLog
e355ba3f   Patrick Maeght   PlcSimulator with...
146
147
148
149
150
151
152
153
        # 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()
d18e437e   Patrick Maeght   New json in
154
            time.sleep(0.5)
e355ba3f   Patrick Maeght   PlcSimulator with...
155
        self.my_state.worker == 'stop'
d18e437e   Patrick Maeght   New json in
156
157
        return True

e355ba3f   Patrick Maeght   PlcSimulator with...
158
159
    def loop_1(self):
        if self.EVENT_GENERATOR and not self.parse(): return False
3c179769   Jeremy   userSimulator / a...
160
        i = 0
75ec5b27   Etienne Pallier   bugfix simulateur...
161
        if (self.EVENT_GENERATOR and self.ended==0):
c7583f6e   Etienne Pallier   Cleaner isolation...
162
163
            self.plcPrint("No entry for PLC found in config file : " + self.config_file)
            return False
3c179769   Jeremy   userSimulator / a...
164
        while (True):
c7583f6e   Etienne Pallier   Cleaner isolation...
165
            print("\n\n\nIteration "+str(i)+" :")
75ec5b27   Etienne Pallier   bugfix simulateur...
166
            if self.EVENT_GENERATOR: self.updateStatus(i)
605b65e5   Jeremy   Update simulators
167
            if (self.isConnected()):
f7dd3df1   Jeremy   Update simulators...
168
                self.handleConnections()
605b65e5   Jeremy   Update simulators
169
            i += 1
75ec5b27   Etienne Pallier   bugfix simulateur...
170
            if (self.EVENT_GENERATOR and i > self.ended): return (0)
c7583f6e   Etienne Pallier   Cleaner isolation...
171
        return True
86dd6e43   Jeremy   Simulator script ...
172
173

    def run(self):
3224f14a   Jeremy   Fixed some simula...
174
        if DEBUG_FILE:
c7583f6e   Etienne Pallier   Cleaner isolation...
175
            print("PLC simulator running...")
e355ba3f   Patrick Maeght   PlcSimulator with...
176
        #if self.EVENT_GENERATOR and not self.parse(): return False
3c179769   Jeremy   userSimulator / a...
177
        self.configSocket()
e355ba3f   Patrick Maeght   PlcSimulator with...
178
        return self.loop()
c7583f6e   Etienne Pallier   Cleaner isolation...
179
        #return (0)
86dd6e43   Jeremy   Simulator script ...
180

e519f61d   Patrick Maeght   test valid device...
181
    # deprecated
e210f6ff   Patrick Maeght   plc simulator init
182
    def set_status(self):
fc957772   Quentin Durand   Control command P...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
        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
        '''

e210f6ff   Patrick Maeght   plc simulator init
251
    def get_status(self, count, answer):
e519f61d   Patrick Maeght   test valid device...
252
        """list = {"name": "LIST", "from": "Beckhoff", "version_firmware": "20170809", "site": "OSM-Mexico",
fc957772   Quentin Durand   Control command P...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
                "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"}
                     ]
                     }
                ]
e519f61d   Patrick Maeght   test valid device...
268
                }"""
fc957772   Quentin Durand   Control command P...
269
270
271
272
273
        if count:
            answer += ','
        answer += json.dumps(self.status)
        return answer

86dd6e43   Jeremy   Simulator script ...
274
275
276
if __name__ == "__main__":
    sim = PLCSimulator(sys.argv)
    sim.run()