154 lines
6.4 KiB
Python
154 lines
6.4 KiB
Python
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
|