from datetime import datetime import time import minimalmodbus from pycomm.ab_comm.clx import Driver as clx from pycomm.cip.cip_base import CommError, DataError class DataPoint(object): def __init__(self,changeThreshold=0,guaranteed=3600, name="datapoint",alertThreshold=[],alertCondition=[],alertResponse=[],alertContact=[], alertName=[],alertBuffer=[],alertReminder=[]): self.value = None self.lastvalue = None self.lastsend = 0 self.changeThreshold = changeThreshold self.guaranteed = guaranteed self.name = name self.alertThreshold = alertThreshold self.alertCondition = alertCondition self.alertResponse = alertResponse self.alertContact = alertContact self.alertName = alertName self.alertBuffer = alertBuffer self.alertReminder = alertReminder self.alerted = [False] * len(self.alertCondition) self.reminderTimer = [0] * len(self.alertCondition) self.alertTimer = [0] * len(self.alertCondition) def checkSend(self,value): if value != self.lastvalue or (time.time() - self.lastsend > self.guaranteed): self.lastsend = time.time() self.lastvalue = value return True else: return False def checkAlert(self,value): conditions = { "gt": "value > threshold", "lt": "value < threshold", "eq": "value == threshold", "gte": "value >= threshold", "lte": "value <= threshold", "not": "value != threshold", } oppositeConditions = { "gt": "lt", "lt": "gt", "gte": "lte", "lte": "gte", "eq": "not", "not": "eq" } for x in range(len(self.alerted)): #check value for alert threshold send back first alarmed value evalVars = { "value": value, "threshold": self.alertThreshold[x][0] } func = conditions.get(self.alertCondition[x]) if func == None: print("Not an available function: {}".format(self.alertCondition[x])) else: result = eval(func,evalVars) if result and not self.alerted[x]:#threshold crossed but not already alerted if self.alertTimer[x] != 0 and time.time() - self.alertTimer[x] > self.alertBuffer[x]:#timer started and crossed threshold self.alerted[x] = True self.alertTimer[x] = 0 self.reminderTimer[x] = time.time() return {"alert": self.alertName[x] + " alarm", "contact": self.alertContact[x], "response": self.alertResponse[x]} elif self.alertTimer[x] == 0:#timer not started yet self.alertTimer[x] = time.time() elif result and self.alerted[x]:#threshold crossed and already on alert if self.alertReminder[x] and time.time() - self.reminderTimer[x] > self.alertReminder[x]: #reminder threshold crossed self.reminderTimer[x] = time.time() return {"alert": self.alertName[x] + " reminder", "contact": self.alertContact[x], "response": self.alertResponse[x]} elif not result and self.alerted[x]:#threshold not crossed but previously alerted evalVars["threshold"] = self.alertThreshold[x][1] func = conditions.get(oppositeConditions.get(self.alertCondition[x])) if eval(func,evalVars):#untrigger threshold crossed if self.alertTimer[x] != 0 and time.time() - self.alertTimer[x] > self.alertBuffer[x]:#timer started and crossed threshold self.alerted[x] = False self.alertTimer[x] = 0 #Send cleared alarm message return {"alert": self.alertName[x] + " alarmed cleared", "contact": self.alertContact[x], "response": self.alertResponse[x]} elif self.alertTimer[x] == 0:#timer not started self.alertTimer[x] = time.time() return None class modbusDataPoint(DataPoint): def __init__(self,changeThreshold,guaranteed,name,register=1,baud=19200,stopBits=1,parity=None, device='/dev/ttyS0'): DataPoint.__init__(self,changeThreshold,guaranteed,name) self.register = register self.baud = baud self.stopBits = stopBits self.parity = parity self.device = device def read(self): pass def write(self): pass class plcDataPoint(DataPoint): def __init__(self,changeThreshold,guaranteed,name,plcIP='192.168.1.10',plcType='Micro800',tag=None,alertThreshold=[],alertCondition=[],alertResponse=[],alertContact=[], alertName=[],alertBuffer=[],alertReminder=[]): DataPoint.__init__(self,changeThreshold,guaranteed,name,alertThreshold,alertCondition,alertResponse,alertContact,alertName,alertBuffer,alertReminder) self.plcIP = plcIP self.plcType = plcType self.tag = tag def read(self): direct_connect = self.plcType == "Micro800" c = clx() try: if c.open(self.plcIP,direct_connect): try: val = c.read_tag(self.tag) c.close() alertMessage = self.checkAlert(val[0]) return val[0], alertMessage except DataError as derr: print("Error: {}".format(derr)) c.close() except CommError as cerr: print("Error: {}".format(cerr)) return False, None def write(self): pass class currentDataPoint(DataPoint): def __init__(self,changeThreshold,guaranteed,name, euMin=0, euMax=100, rawMin=4, rawMax=20): DataPoint.__init__(self,changeThreshold,guaranteed,name) self.euMin = euMin self.euMax = euMax self.rawMin = rawMin self.rawMax = rawMax def read(self): pass class voltageDataPoint(DataPoint): def __init__(self,changeThreshold,guaranteed,name, euMin=0, euMax=100, rawMin=0, rawMax=10): DataPoint.__init__(self,changeThreshold,guaranteed,name) self.euMin = euMin self.euMax = euMax self.rawMin = rawMin self.rawMax = rawMax def read(self): pass