from __future__ import absolute_import from django.conf import settings from common.models import * from celery.task import Task from devices.PLC import PLCController from utils.JDManipulator import * import json import utils.Logger as L import majordome.tasks import alert_manager.tasks log = L.setupLogger("MonitoringTaskLogger", "Monitoring") DEBUG_FILE = False ''' Infinite task created at the program's start. Checks the plc status, parse it, analyse it, store it in db ''' class Monitoring(Task): timers = {} functions = {} def run(self): self.createTask() self.setContext() self.setTime() self.setTasks() self.loop() def createTask(self): try: TaskId.objects.find(task="monitoring").delete() except Exception as e: log.info(str(e)) return 1 TaskId.objects.create(task_id=self.request.id, task="monitoring") 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 def setContext(self): self.plc = PLCController() self.state = "RUNNING" return (0) def setTime(self): self.timer_status = 2 self.timer_tasks = 5 self.timers = {"timer_status": self.timer_status, "tasks": self.timer_tasks} self.functions = {"timer_status": self.handleTimerStatus, "tasks": self.handleTasks} return (0) def logDB(self, message: str): Log.objects.create(agent='Monitoring', message=message) ''' Function called by the main loop to check if the majordome and alert_manager are running ''' def handleTasks(self): self.timers["tasks"] = self.timer_tasks # TODO check majordome and alert_manager status if self.majordome_task is None: try: # (EP) bugfix !!! #self.monitoring_task = TaskId.objects.get(task="majordome") self.majordome_task = TaskId.objects.get(task="majordome") except Exception as e: majordome.tasks.Majordome.apply_async() if settings.DEBUG and DEBUG_FILE: log.info(str(e)) if self.alert_task is None: try: self.alert_task = TaskId.objects.get(task="alert_manager") except Exception as e: alert_manager.tasks.AlertListener.apply_async() if settings.DEBUG and DEBUG_FILE: log.info(str(e)) return 0 ''' Check if all devices info are consitants ''' def isStatusValid(self): return True ''' Extract content from the status dictionary ''' def extractFromDict(self, status): synthesis = {} devices = status["device"] for device in devices: for value in device["values"]: synthesis[value["name"]] = value["value"] synthesis[value["name"] + "_unit"] = value["unit"] return synthesis # TODO ATTENTION SI DEUX DEVICES ONT LE MEME NOM def saveContent(self, content): devices = content["device"] for device in devices: status = PlcDeviceStatus() try: database_device = PlcDevice.objects.get(name=device["name"]) except Exception as e: plc = Plc.objects.first() database_device = PlcDevice.objects.create(device=plc, name=device["name"]) status.device = database_device for value in device["values"]: status.setValue(value["name"], value["value"], value["unit"]) status.save() ''' Parse status returned by plc ''' def parseStatus(self, status_plc): try: status = {} dict = json.loads(status_plc)[0] if dict["name"] == "STATUS": if self.isStatusValid(): status = self.extractFromDict(dict) self.saveContent(dict) else: # TODO HANDLE ERROR HERE pass except Exception as e: if DEBUG_FILE and settings.DEBUG: log.info(str(e)) self.status_plc = {} return 1 self.status_plc = status return 0 ''' 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 ''' Save status returned by plc ''' def saveStatus(self): outside = WeatherWatch() inside = SiteWatch() for key, value in self.status_plc.items(): if self.isOutside(key): outside.setAttribute(key, value) elif self.isInside(key): inside.setAttribute(key, value) outside.setGlobalStatus() inside.setGlobalStatus() outside.save() inside.save() return 0 ''' Function called by the main loop to handle the plc status ''' def handleTimerStatus(self): self.timers["timer_status"] = self.timer_status status_plc = self.plc.getStatus() if (self.plc.isError(status_plc)): if (settings.DEBUG and DEBUG_FILE): log.info("Invalid status returned : " + str(self.status_plc)) return (1) # (EP) if parseStatus() = THERE WAS AN ERROR !!! if self.parseStatus(status_plc): if (settings.DEBUG and DEBUG_FILE): log.info("Invalid status returned : " + str(self.status_plc)) return 1 return self.saveStatus() ''' Main loop ''' def loop(self): while (self.state != "SHUTDOWN"): 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(): if (timer_value <= 0): if (timer_name in self.functions): self.functions[timer_name]() else: if (settings.DEBUG and DEBUG_FILE): log.info("Timer : " + str(timer_name) + "is not known by the monitoring") self.logDB("Timer " + str(timer_name) + " unknown") if (settings.DEBUG and DEBUG_FILE): log.info("Timer : " + str(timer_name) + " executed by monitoring") return (0) if (__name__ == "__main__"): m = Monitoring() m.run()