Blame view

src/monitoring/tasks.py 11.5 KB
5b5566ab   haribo   added celery
1
from __future__ import absolute_import
a190892c   haribo   Date: 05/07/2016
2
from django.conf import settings
ddf59dd4   haribo   Remaniement :
3
from common.models import *
81408f10   Etienne Pallier   Added some useful...
4

eabb9310   Patrick Maeght   scan captors list...
5
from src.monitoring.plc_checker import PlcChecker
ddf59dd4   haribo   Remaniement :
6
from devices.PLC import PLCController
4cb0ff36   Jeremy   Update
7
from utils.JDManipulator import *
6c2793c2   jeremy   Update
8
import json
bca9a283   Jeremy   Reworked the sche...
9
import utils.Logger as L
c72eb17a   Jeremy   Update celery task
10
import majordome.tasks
c72eb17a   Jeremy   Update celery task
11
import alert_manager.tasks
4cb0ff36   Jeremy   Update
12
log = L.setupLogger("MonitoringTaskLogger", "Monitoring")
c5a3b4a0   haribo   Date: 05/07/2016
13

1a2dc19f   Etienne Pallier   nombreux bugfixes...
14
15
16
# EP
#DEBUG_FILE = False
DEBUG_FILE = True
ce470283   Jeremy   Plc simulator fin...
17

ce470283   Jeremy   Plc simulator fin...
18

65149de7   Jeremy   Update
19
20
'''
    Infinite task created at the program's start.
4cb0ff36   Jeremy   Update
21
    Checks the plc status, parse it, analyse it, store it in db
65149de7   Jeremy   Update
22
'''
257abe9b   Jeremy   Added comments
23
24


5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
25
class Monitoring():
ef60c3ec   Jeremy   Majordome and mon...
26
27
    timers = {}
    functions = {}
5b5566ab   haribo   added celery
28

3ed0a02b   Quentin Durand   Declaring variabl...
29
30
31
32
33
34
35
36
37
    state = None
    plcController = None
    majordome = None
    alert_manager = None
    alert_task = None
    majordome_task = None
    timer_status = None
    timer_tasks = None
    status_plc = None
eabb9310   Patrick Maeght   scan captors list...
38
    plc_checker = PlcChecker()
3ed0a02b   Quentin Durand   Declaring variabl...
39

5b5566ab   haribo   added celery
40
    def run(self):
ee2c4543   Etienne Pallier   Bugfix Monitoring...
41
        print ("AGENT ENV: startup...")
c72eb17a   Jeremy   Update celery task
42
        self.createTask()
1a2dc19f   Etienne Pallier   nombreux bugfixes...
43
44
45

        # (TRY TO) Connect to PLC
        # (non blocking if could not connect)
65149de7   Jeremy   Update
46
        self.setContext()
ee2c4543   Etienne Pallier   Bugfix Monitoring...
47
        print ("AGENT ENV: config PLC is (ip={}, port={})".format(self.plcController.ip, self.plcController.port))
630dd6e4   Etienne Pallier   Renommé script st...
48

1a2dc19f   Etienne Pallier   nombreux bugfixes...
49
50
        # (EP) self.setTime()
        self.setTimers()
ee2c4543   Etienne Pallier   Bugfix Monitoring...
51
        print("AGENT ENV: my timers (check env status every {}s, check other agents every {}s)".format(self.timer_status, self.timer_tasks))
630dd6e4   Etienne Pallier   Renommé script st...
52

c72eb17a   Jeremy   Update celery task
53
        self.setTasks()
ee2c4543   Etienne Pallier   Bugfix Monitoring...
54
        print("AGENT ENV: Other Agents id read from DB (majordome={}, alert={})".format(self.majordome_task, self.alert_task))
630dd6e4   Etienne Pallier   Renommé script st...
55

4cb0ff36   Jeremy   Update
56
        self.loop()
a190892c   haribo   Date: 05/07/2016
57

1a2dc19f   Etienne Pallier   nombreux bugfixes...
58

c72eb17a   Jeremy   Update celery task
59
60
    def createTask(self):
        try:
1a2dc19f   Etienne Pallier   nombreux bugfixes...
61
62
63
            # (EP) NO find() method available from Django ORM, c'est du n'importe quoi ce code (lastminute.com ?) !!!! 
            #TaskId.objects.find(task="monitoring").delete()
            TaskId.objects.filter(task="monitoring").delete()
c72eb17a   Jeremy   Update celery task
64
65
        except Exception as e:
            log.info(str(e))
1a2dc19f   Etienne Pallier   nombreux bugfixes...
66
67
            # (EP) return always if no monitoring task to delete, and so monitoring task id is never saved !!!
            #return 1
bd6108e3   Patrick Maeght   comment TaskId.ob...
68
69
        # PM 20190129 remove
        #TaskId.objects.create(task_id=self.request.id, task="monitoring")
c72eb17a   Jeremy   Update celery task
70
71
72
73
74
75
76
77
78
79
80
        return 0

    def setTasks(self):
        try:
            self.majordome_task = TaskId.objects.get(task="majordome")
            self.alert_task = TaskId.objects.get(task="alert_manager")
        except Exception as e:
            self.majordome_task = None
            self.alert_task = None
        return 0

65149de7   Jeremy   Update
81
    def setContext(self):
1a2dc19f   Etienne Pallier   nombreux bugfixes...
82
        self.plcController = PLCController()
4cb0ff36   Jeremy   Update
83
        self.state = "RUNNING"
65149de7   Jeremy   Update
84
        return (0)
c5a3b4a0   haribo   Date: 05/07/2016
85

1a2dc19f   Etienne Pallier   nombreux bugfixes...
86
    def setTimers(self):
ef60c3ec   Jeremy   Majordome and mon...
87
        self.timer_status = 2
c72eb17a   Jeremy   Update celery task
88
89
        self.timer_tasks = 5
        self.timers = {"timer_status": self.timer_status,
1a2dc19f   Etienne Pallier   nombreux bugfixes...
90
91
92
93
94
                       "timer_tasks": self.timer_tasks}
        # (EP)         "tasks": self.timer_tasks}
        # (EP) self.functions = {"timer_status": self.handleTimerStatus,
        self.functions = {"timer_status": self.handleStatus,
                          "timer_tasks": self.handleTasks}
4cb0ff36   Jeremy   Update
95
        return (0)
21598bc6   haribo   Date: 01/08/2016
96

975e2c98   Quentin Durand   Auto stash before...
97

bca9a283   Jeremy   Reworked the sche...
98
99
100
    def logDB(self, message: str):
        Log.objects.create(agent='Monitoring', message=message)

975e2c98   Quentin Durand   Auto stash before...
101
102
103
104
105
        '''
            Function called by the main loop to check if the majordome and alert_manager are running
        '''


c72eb17a   Jeremy   Update celery task
106
    def handleTasks(self):
1a2dc19f   Etienne Pallier   nombreux bugfixes...
107
108
109
        # Reset timer total duration
        # (EP) self.timers["tasks"] = self.timer_tasks
        self.timers["timer_tasks"] = self.timer_tasks
c72eb17a   Jeremy   Update celery task
110
111
112
        # TODO check majordome and alert_manager status
        if self.majordome_task is None:
            try:
ed1bf194   Etienne Pallier   bugfix task major...
113
114
115
                # (EP) bugfix !!!
                #self.monitoring_task = TaskId.objects.get(task="majordome")
                self.majordome_task = TaskId.objects.get(task="majordome")
c72eb17a   Jeremy   Update celery task
116
            except Exception as e:
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
117
                print("no USE_CELERY => do not create Majordome task")
1a2dc19f   Etienne Pallier   nombreux bugfixes...
118
                    
c72eb17a   Jeremy   Update celery task
119
120
121
122
        if self.alert_task is None:
            try:
                self.alert_task = TaskId.objects.get(task="alert_manager")
            except Exception as e:
ee2c4543   Etienne Pallier   Bugfix Monitoring...
123
                # Mind this will raise an Exception if RABBITMQ is not started !
5e45ba9f   Etienne Pallier   Bye Bye Celery (f...
124
                print("no USE_CELERY => do not create AlertListener task")
15e15006   Etienne Pallier   Nouvelles modifs ...
125
126
127
        # EP non car 0 = false
        #return 0
        return True
c72eb17a   Jeremy   Update celery task
128

257abe9b   Jeremy   Added comments
129
    '''
6c2793c2   jeremy   Update
130
131
        Check if all devices info are consitants
    '''
975e2c98   Quentin Durand   Auto stash before...
132

6c2793c2   jeremy   Update
133
134
135
136
137
138
139
140
    def isStatusValid(self):
        return True

    '''
        Extract content from the status dictionary
    '''
    def extractFromDict(self, status):
        synthesis = {}
d18e437e   Patrick Maeght   New json in
141
        devices = status["devices"]
f47ec727   Quentin Durand   hotfix monitoring
142
        #print(devices)
927b8599   Quentin Durand   Moving plc_mode a...
143
144
        #is_safe_str = status["is_safe"]
        #mode = status["mode"]
8c772a38   Patrick Maeght   document it
145
        # PM 20190220 try valid
6c2793c2   jeremy   Update
146
        for device in devices:
8c772a38   Patrick Maeght   document it
147
148
            if str(device['error_code']) == "0":
                #if device['valid'] == "yes":
e519f61d   Patrick Maeght   test valid device...
149
150
151
                for value in device["device_values"]:
                    synthesis[value["name"]] = value["value"]
                    synthesis[value["name"] + "_unit"] = value["unit"]
927b8599   Quentin Durand   Moving plc_mode a...
152
        return synthesis
6c2793c2   jeremy   Update
153

fe5613f5   jeremy   Update plc protocol
154
    # TODO ATTENTION SI DEUX DEVICES ONT LE MEME NOM
e519f61d   Patrick Maeght   test valid device...
155
    # TODO SAVE SYNTHESIS
927b8599   Quentin Durand   Moving plc_mode a...
156
    def saveContent(self, content):
d18e437e   Patrick Maeght   New json in
157
        devices = content[0]["devices"]
e519f61d   Patrick Maeght   test valid device...
158
        print("saveContent")
fe5613f5   jeremy   Update plc protocol
159
        for device in devices:
8c772a38   Patrick Maeght   document it
160
161
162
            # PM 20190222 try valid with error_code
            #if device['valid'] == "yes":
            if str(device['error_code']) == "0":
e519f61d   Patrick Maeght   test valid device...
163
164
165
166
                status = PlcDeviceStatus()
                try:
                    database_device = PlcDevice.objects.get(name=device["device_name"])
                except Exception as e:
8c772a38   Patrick Maeght   document it
167
168
169
170
171
                    # plc = Plc.objects.first()
                    try:
                        database_device = PlcDevice.objects.create(name=device["device_name"])
                    except Exception as e:
                        print(e)
e519f61d   Patrick Maeght   test valid device...
172
173
                status.device = database_device
                for value in device["device_values"]:
8c772a38   Patrick Maeght   document it
174
                    status.setValue(value["monitoring_name"], value["value"], value["unit"])
e519f61d   Patrick Maeght   test valid device...
175
176
177
178

                #status.setValue("mode", mode)
                #status.setValue("is_safe", is_safe_str)
                status.save()
fe5613f5   jeremy   Update plc protocol
179

6c2793c2   jeremy   Update
180
    '''
257abe9b   Jeremy   Added comments
181
182
        Parse status returned by plc
    '''
ce470283   Jeremy   Plc simulator fin...
183
184
185
    def parseStatus(self, status_plc):
        try:
            status = {}
f47ec727   Quentin Durand   hotfix monitoring
186
            dict = json.loads(status_plc)
d18e437e   Patrick Maeght   New json in
187
            if dict[0]["entity_name"] == "PLC_STATUS":
fe5613f5   jeremy   Update plc protocol
188
                if self.isStatusValid():
f47ec727   Quentin Durand   hotfix monitoring
189
                    status = self.extractFromDict(dict[0])
927b8599   Quentin Durand   Moving plc_mode a...
190
                    self.saveContent(dict)
fe5613f5   jeremy   Update plc protocol
191
192
193
                else:
                    # TODO HANDLE ERROR HERE
                    pass
ce470283   Jeremy   Plc simulator fin...
194
        except Exception as e:
f47ec727   Quentin Durand   hotfix monitoring
195

ce470283   Jeremy   Plc simulator fin...
196
197
198
199
200
201
202
            if DEBUG_FILE and settings.DEBUG:
                log.info(str(e))
            self.status_plc = {}
            return 1
        self.status_plc = status
        return 0

257abe9b   Jeremy   Added comments
203
    '''
fe5613f5   jeremy   Update plc protocol
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
        Check if string is ouside
    '''
    def isOutside(self, key):
        if key.find('Outside') != -1 or key.find('Rain') != -1\
                or key.find("Wind") != -1 or key.find("Sky") != -1:
            return True
        elif key == "Pressure":
            return True
        elif key == "DewPoint":
            return True
        return False

    def isInside(self, key):
        if key.find('Inside') != -1 or key.find('Door') != -1:
            return True
        elif key == "status":
            return True
        elif key == "current":
            return True
        return False

    '''
257abe9b   Jeremy   Added comments
226
227
        Save status returned by plc
    '''
8c772a38   Patrick Maeght   document it
228
    def old__saveStatus(self):
ce470283   Jeremy   Plc simulator fin...
229
230
231
        outside = WeatherWatch()
        inside = SiteWatch()
        for key, value in self.status_plc.items():
fe5613f5   jeremy   Update plc protocol
232
            if self.isOutside(key):
ce470283   Jeremy   Plc simulator fin...
233
                outside.setAttribute(key, value)
fe5613f5   jeremy   Update plc protocol
234
            elif self.isInside(key):
ce470283   Jeremy   Plc simulator fin...
235
236
237
238
239
                inside.setAttribute(key, value)
        outside.setGlobalStatus()
        inside.setGlobalStatus()
        outside.save()
        inside.save()
15e15006   Etienne Pallier   Nouvelles modifs ...
240
        #return 0
ce470283   Jeremy   Plc simulator fin...
241

8c772a38   Patrick Maeght   document it
242
243
244
245
246
247
248
249
250
    def saveSite(self):
        inside = SiteWatch()
        for key, value in self.status_plc.items():
            if self.isInside(key):
                inside.setAttribute(key, value)
        inside.setGlobalStatus()
        inside.save()

    def saveWeather(self):
e15030dc   Patrick Maeght   penelope work part 2
251
        outside = WeatherWatch()
8c772a38   Patrick Maeght   document it
252
        for sensor in self.plc_checker.sensors_weather.keys():
e15030dc   Patrick Maeght   penelope work part 2
253
254
255
256
257
258
            value = self.plc_checker.get_sensor(sensor)
            print(sensor, value)
            outside.setAttribute(sensor, value)
        outside.setGlobalStatus()
        outside.save()

eabb9310   Patrick Maeght   scan captors list...
259
260
    def parseNewStatus(self,status_plc ):
        # """ PM 20181009 parse new status for config
ff6e8ece   Patrick Maeght   check captors con...
261
        if status_plc.find('PLC_STATUS') >= 0:
eabb9310   Patrick Maeght   scan captors list...
262
            self.plc_checker.chk_config(status_plc)
e15030dc   Patrick Maeght   penelope work part 2
263
            return True
eabb9310   Patrick Maeght   scan captors list...
264

257abe9b   Jeremy   Added comments
265
266
267
    '''
        Function called by the main loop to handle the plc status
    '''
1a2dc19f   Etienne Pallier   nombreux bugfixes...
268
269
    def handleStatus(self):
        # Reset timer total duration
4cb0ff36   Jeremy   Update
270
        self.timers["timer_status"] = self.timer_status
1a2dc19f   Etienne Pallier   nombreux bugfixes...
271
        status_plc = self.plcController.getStatus()
eabb9310   Patrick Maeght   scan captors list...
272
        # PM 20181009 parse new status for config
e15030dc   Patrick Maeght   penelope work part 2
273
        if self.parseNewStatus(status_plc):
8c772a38   Patrick Maeght   document it
274
275
            self.saveWeather()
            #self.saveSite()
e15030dc   Patrick Maeght   penelope work part 2
276

f47ec727   Quentin Durand   hotfix monitoring
277

1a2dc19f   Etienne Pallier   nombreux bugfixes...
278
279
        # Error while READING status ?
        if (self.plcController.isError(status_plc)):
f47ec727   Quentin Durand   hotfix monitoring
280

ce470283   Jeremy   Plc simulator fin...
281
            if (settings.DEBUG and DEBUG_FILE):
1a2dc19f   Etienne Pallier   nombreux bugfixes...
282
                log.info("Invalid PLC status returned (while reading) : " + str(status_plc))
1b9ba1f6   Quentin Durand   Little update on ...
283
                Log.objects.create(message="Invalid PLC status returned (while reading) : ", agent="Monitoring")
15e15006   Etienne Pallier   Nouvelles modifs ...
284
285
            # EP Non car 1 = true
            #return (1)
f47ec727   Quentin Durand   hotfix monitoring
286

15e15006   Etienne Pallier   Nouvelles modifs ...
287
            return False
f47ec727   Quentin Durand   hotfix monitoring
288

ed1bf194   Etienne Pallier   bugfix task major...
289
        # (EP) if parseStatus() = THERE WAS AN ERROR !!!
1a2dc19f   Etienne Pallier   nombreux bugfixes...
290
        # Error while PARSING status ?
ce470283   Jeremy   Plc simulator fin...
291
292
        if self.parseStatus(status_plc):
            if (settings.DEBUG and DEBUG_FILE):
1a2dc19f   Etienne Pallier   nombreux bugfixes...
293
                log.info("Invalid PLC status returned (while parsing) : " + str(status_plc))
1b9ba1f6   Quentin Durand   Little update on ...
294
                Log.objects.create(message="Invalid PLC status returned (while parsing) : ", agent="Monitoring")
15e15006   Etienne Pallier   Nouvelles modifs ...
295
296
297
            # EP Non car 1 = true
            #return (1)
            return False
c7583f6e   Etienne Pallier   Cleaner isolation...
298
299
        print("Status received from PLC (read and parsed ok):")
        print(status_plc)
15e15006   Etienne Pallier   Nouvelles modifs ...
300
        #return self.saveStatus()
20ed1e7a   Etienne Pallier   bugfixed time sav...
301
302
        #print(datetime.datetime.now())

1b9ba1f6   Quentin Durand   Little update on ...
303
        Log.objects.create(message="Status received from PLC (read and parsed ok):", agent="Monitoring")
8c772a38   Patrick Maeght   document it
304
305

        #self.saveStatus()
15e15006   Etienne Pallier   Nouvelles modifs ...
306
        return True
21598bc6   haribo   Date: 01/08/2016
307

257abe9b   Jeremy   Added comments
308
309
310
    '''
        Main loop
    '''
4cb0ff36   Jeremy   Update
311
    def loop(self):
f47ec727   Quentin Durand   hotfix monitoring
312
        i = 0
4cb0ff36   Jeremy   Update
313
        while (self.state != "SHUTDOWN"):
c7583f6e   Etienne Pallier   Cleaner isolation...
314
315
316
317
            print("-")
            print("-")
            print("-")
            print ("AGENT Monitoring (ENV): iteration "+str(i)+", (my state is " + self.state+") :")
4cb0ff36   Jeremy   Update
318
319
320
321
            minimal_timer = min(self.timers, key=self.timers.get)
            time.sleep(self.timers[minimal_timer])
            self.timers = {key: value - self.timers[minimal_timer] for key, value in self.timers.items()}
            for timer_name, timer_value in self.timers.items():
4cb0ff36   Jeremy   Update
322
                if (timer_value <= 0):
ef60c3ec   Jeremy   Majordome and mon...
323
                    if (timer_name in self.functions):
1a2dc19f   Etienne Pallier   nombreux bugfixes...
324
                        # Handle the timer function
4cb0ff36   Jeremy   Update
325
                        self.functions[timer_name]()
1a2dc19f   Etienne Pallier   nombreux bugfixes...
326
327
                        if (settings.DEBUG and DEBUG_FILE):
                            log.info("Timer : " + str(timer_name) + " executed by monitoring")
4cb0ff36   Jeremy   Update
328
                    else:
ce470283   Jeremy   Plc simulator fin...
329
                        if (settings.DEBUG and DEBUG_FILE):
4cb0ff36   Jeremy   Update
330
                            log.info("Timer : " + str(timer_name) + "is not known by the monitoring")
bca9a283   Jeremy   Reworked the sche...
331
                        self.logDB("Timer " + str(timer_name) + " unknown")
1a2dc19f   Etienne Pallier   nombreux bugfixes...
332
333
334
                # EP : pas au bon endroit !!!
                #if (settings.DEBUG and DEBUG_FILE):
                    #log.info("Timer : " + str(timer_name) + " executed by monitoring")
c7583f6e   Etienne Pallier   Cleaner isolation...
335
            i+=1
ef60c3ec   Jeremy   Majordome and mon...
336
337
        return (0)

1a2dc19f   Etienne Pallier   nombreux bugfixes...
338
339


ef60c3ec   Jeremy   Majordome and mon...
340
341
342
if (__name__ == "__main__"):
    m = Monitoring()
    m.run()