def CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue): global AUTO_data # check if time between watering events is larger that the waiting time (minutes) lastactiontime=statusdataDBmod.read_status_data(AUTO_data,element,"lastactiontime") print ' Previous action: ' , lastactiontime , ' Now: ', datetime.now() timedifference=sensordbmod.timediffinminutes(lastactiontime,datetime.now()) print 'Time interval between actions', timedifference ,'. threshold', waitingtime logger.info('Time interval between Actions %d threshold %d', timedifference,waitingtime) if timedifference>=waitingtime: # sufficient time between actions print " Sufficient waiting time" logger.info('Sufficient waiting time') # action print "Implement Actuator Value ", value logger.info('Procedure to start actuator %s, for value = %s', element, value) isok=activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype!="warningonly": textmessage="INFO: " + sensor + " value " + str(sensorvalue) + ", activating:" + element + " with Value " + str(value) emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.now()) statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",value) else: logger.info('Need to wait more time')
def saveblockingdiff( sensor ): # this function minimize the writing over the database, keep them at 1 sec distance and provides a visual pleasant graph :) global BLOCKING_data global SAVEBLOCKINGDIFFBUSY if not SAVEBLOCKINGDIFFBUSY: SAVEBLOCKINGDIFFBUSY = True threadID = statusdataDBmod.read_status_data(BLOCKING_data, sensor, "BlockingNumbersThreadID") print(" threadID ", threadID) if (threadID != None) and (threadID != ""): # thread already present print("thread present already, remove it") threadID.cancel() else: # no thread present already print("no thread present already ") x = threading.Thread(target=saveblocking, args=(sensor, False)) x.start() #logger.warning("SaveBlockDIFF ---> Sensor %s", sensor) threadID = threading.Timer(1, saveblocking, [sensor]) threadID.start() statusdataDBmod.write_status_data(BLOCKING_data, sensor, "BlockingNumbersThreadID", threadID) SAVEBLOCKINGDIFFBUSY = False else: print(" BUSYYYYY")
def on_message(self,mqttc, obj, msg): global SubscriptionLog payload=msg.payload.decode('utf-8') print(self.clientid + " " + "Message: "+ msg.topic + " " + str(msg.qos) + " " + payload) statusdataDBmod.write_status_data(SubscriptionLog,msg.topic,"jsonstring",payload) timestamp=datetime.utcnow() statusdataDBmod.write_status_data(SubscriptionLog,msg.topic,"timestamp",timestamp)
def CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue): global AUTO_data # check if time between watering events is larger that the waiting time (minutes) lastactiontime=statusdataDBmod.read_status_data(AUTO_data,element,"lastactiontime") print(' Previous action: ' , lastactiontime , ' Now: ', datetime.utcnow()) timedifference=sensordbmod.timediffinminutes(lastactiontime,datetime.utcnow()) print('Time interval between actions', timedifference ,'. threshold', waitingtime) logger.info('Time interval between Actions %d threshold %d', timedifference,waitingtime) if timedifference>=waitingtime: # sufficient time between actions print(" Sufficient waiting time") logger.info('Sufficient waiting time') # action print("Implement Actuator Value ", value) logger.info('Procedure to start actuator %s, for value = %s', element, value) isok=activateactuator(element, value) # invia mail, considered as info, not as alert if (mailtype!="warningonly")and(mailtype!="none"): textmessage="INFO: " + sensor + " value " + str(sensorvalue) + ", activating:" + element + " with Value " + str(value) emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",value) else: logger.info('Need to wait more time')
def GPIO_setup(address, PINstr, state, pull_up_down=""): isRealPIN,PIN=CheckRealHWpin(PINstr) if isRealPIN: if address in MCPDEVICES: mcp=MCPDEVICES[address] else: return False PIN=PIN-1 if state=="out": mcp.pinMode(PIN, mcp.OUTPUT) else: if pull_up_down=="pull_down": mcp.pinMode(PIN, mcp.INPUT) mcp.pullUp(PIN, 0) elif pull_up_down=="pull_up": mcp.pinMode(PIN, mcp.INPUT) mcp.pullUp(PIN, 1) else: mcp.pinMode(PIN, mcp.INPUT) #GPIO_data[PIN]["state"]=state statusdataDBmod.write_status_data(GPIO_data,PINstr,"state",state) return True
def cyclereset(element): global AUTO_data waitingtime=hardwaremod.toint(automationdbmod.searchdata("element",element,"pausebetweenwtstepsmin"),0) statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.utcnow() - timedelta(minutes=waitingtime)) statusdataDBmod.write_status_data(AUTO_data,element,"status","ok") statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",0) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"infocounter",0)
def endpulse(PIN_CMD, POWERPIN_CMD, address): REGID = PIN_CMD["ID"] statusdataDBmod.write_status_data(GPIO_data, REGID, "threadID", None) MQTT_output(PIN_CMD["STOP"], address) endwaittime = 0 powerPIN_stop(POWERPIN_CMD, endwaittime, address) #print "pulse ended", time.ctime() , " PIN=", PINstr , " Logic=", logic , " Level=", level return True
def saveblocking(sensor,cleanThreadID=True): global SAVEBLOCKINGBUSY global BLOCKING_data if not SAVEBLOCKINGBUSY: SAVEBLOCKINGBUSY=True BlockingNumbers=statusdataDBmod.read_status_data(BLOCKING_data,sensor,"BlockingNumbers") print("SAVING :::::: sensor ",sensor," BlockingNumbers " ,BlockingNumbers) savedata(sensor,BlockingNumbers) if cleanThreadID: statusdataDBmod.write_status_data(BLOCKING_data,sensor,"BlockingNumbersThreadID",None) SAVEBLOCKINGBUSY=False
def ReadInterruptFrequency(PIN): sensorinterruptcount=statusdataDBmod.read_status_data(SENSOR_data,PIN,"InterruptCount") Startcounttime=statusdataDBmod.read_status_data(SENSOR_data,PIN,"Startcounttime") nowtime=datetime.utcnow() diffseconds=(nowtime-Startcounttime).total_seconds() if diffseconds>0: Frequency=old_div(sensorinterruptcount,diffseconds) else: Frequency = 0 # azzera timer e counter statusdataDBmod.write_status_data(SENSOR_data,PIN,"InterruptCount",0) statusdataDBmod.write_status_data(SENSOR_data,PIN,"Startcounttime",nowtime) return Frequency
def WaitandRegister(element, sensor, periodsecond, counter): # this one should be dismissed, working with previous procedure if periodsecond>0: global AUTO_data t.sleep(0.05) # in case another timer is active on this element, cancel it threadID=statusdataDBmod.read_status_data(AUTO_data,element+sensor,"RegisterID") if threadID!=None and threadID!="": threadID.cancel() # activate a new time, in cas this is not cancelled then the data will be saved callin the savedata procedure threadID = threading.Timer(periodsecond, savedata, [sensor , counter]) threadID.start() statusdataDBmod.write_status_data(AUTO_data,element+sensor,"RegisterID",threadID) else: x = threading.Thread(target=savedata, args=(sensor,counter)) x.start()
def endpulse(address, PINstr,logic,POWERPIN): #GPIO_data[PIN]["threadID"]=None statusdataDBmod.write_status_data(GPIO_data,address+PINstr,"threadID",None) if logic=="pos": level=0 else: level=1 GPIO_output(address, PINstr, level) powerPIN_stop(address, POWERPIN,0) #print "pulse ended", time.ctime() , " PIN=", PINstr , " Logic=", logic , " Level=", level return True
def powerPIN_stop(CMD_PWR, waittime, address): REGID = CMD_PWR["ID"] if REGID != "": PowerPINlevel = statusdataDBmod.read_status_data( PowerPIN_Status, REGID, "level") statusdataDBmod.write_status_data(PowerPIN_Status, REGID, "level", PowerPINlevel - 1) #stop power pin if level less or equal to zero if (PowerPINlevel - 1) <= 0: time.sleep(waittime) MQTT_output(CMD_PWR["STOP"], address) return True
def CheckandFollowup(element): global AUTO_data actionmodeafterfirst=interruptdbmod.searchdata("element",element,"actionmode_afterfirst") actuatoroutputfollowup=hardwaremod.tonumber(interruptdbmod.searchdata("element",element,"folloup_output"),0) # section below is the follow-up if actionmodeafterfirst=="Follow-up action" or actionmodeafterfirst=="Remove and Follow-up" or actionmodeafterfirst=="Extend and Follow-up": # execute the action followup, no variation in the preemption period value=actuatoroutputfollowup # followup action print("Implement Actuator Value followup", value) logger.info('Procedure to start actuator followup %s, for value = %s', element, value) isok=activateactuator(element, value) if isok: statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",value) return True return False
def GPIO_output(address , PINstr, level ): isRealPIN,PIN=CheckRealHWpin(PINstr) if isRealPIN: if address in MCPDEVICES: mcp=MCPDEVICES[address] else: return False PIN=PIN-1 if level==0: mcp.output(PIN, mcp.LOW) else: mcp.output(PIN, mcp.HIGH) #GPIO_data[PIN]["level"]=level statusdataDBmod.write_status_data(GPIO_data,address+PINstr,"level",level) logger.info("Set PIN=%s to State=%s", PINstr, str(level)) #print PINstr , " ***********************************************" , level return True
def eventcallback(PIN): bouncetimeSec = statusdataDBmod.read_status_data(PIN_attributes, PIN, "bouncetimeSec") t.sleep(bouncetimeSec) reading = hardwaremod.readinputpin(PIN) refsensor = statusdataDBmod.read_status_data(PIN_attributes, PIN, "refsensor") logic = statusdataDBmod.read_status_data(PIN_attributes, PIN, "logic") #print "reference sensor:" , refsensor, "logic ", logic #print PIN_attributes # first Edge detection, can have two impleemntations depend on the "logic" setting # in case logic=pos we have pull-down resistor, so the normal state is LOW, the first edge will be from LOW to HIGH # in case logic<>pos we have pull-up resistor, so the normal state is High, the first edge will be from HIGH to LOW if refsensor != "": #["First Edge" , "First Edge + Level", "Second Edge" , "Second Edge + Level (inv)", "both Edges"] #print "Logic " , logic , " reading ", reading , " bouncetimeSec " , bouncetimeSec #detecting first edge if logic == "pos": if reading == "1": #print "************************* First edge detected on PIN:", PIN mode = "First Edge" elif reading == "0": #print "************************* Second edge detected on PIN:", PIN mode = "Second Edge" else: if reading == "0": #print "************************* First edge detected on PIN:", PIN mode = "First Edge" elif reading == "1": #print "************************* Second edge detected on PIN:", PIN mode = "Second Edge" #print "interrupt --------------------> ", mode interruptcheck(refsensor, mode, PIN) # update status variables for the frequency sensor ---- sensorinterruptcount = statusdataDBmod.read_status_data( SENSOR_data, PIN, "InterruptCount") sensorinterruptcount = sensorinterruptcount + 1 statusdataDBmod.write_status_data(SENSOR_data, PIN, "InterruptCount", sensorinterruptcount)
def CounterOnly(element,sensor,interrupt_validinterval): # this one should be dismissed, anyway it works isok=False global AUTO_data lastinterrupttime=statusdataDBmod.read_status_data(AUTO_data,element,"lastinterrupttime") nowtime=datetime.utcnow() #print ' Previous interrupt: ' , lastinterrupttime , ' Now: ', nowtime diffseconds=(nowtime-lastinterrupttime).total_seconds() statusdataDBmod.write_status_data(AUTO_data,element,"lastinterrupttime",nowtime) validinterruptcount=statusdataDBmod.read_status_data(AUTO_data,element,"validinterruptcount") if diffseconds<=interrupt_validinterval: #valid interval between interrupt, increase counter validinterruptcount=validinterruptcount+1 statusdataDBmod.write_status_data(AUTO_data,element,"validinterruptcount",validinterruptcount) else: # time between interrupt too long, restart counter # save on database #x = threading.Thread(target=savedata, args=(sensor,validinterruptcount)) #x.start() #reset counter and events validinterruptcount=1 statusdataDBmod.write_status_data(AUTO_data,element,"validinterruptcount",validinterruptcount) WaitandRegister(element, sensor, interrupt_validinterval, validinterruptcount) return isok
def powerPIN_start( REGID, CMD, address, pulsesecond, ignorepowerpincount=False ): # powerpin will work only with same address and same topic/"powerpin number" if REGID != "": PowerPINlevel = statusdataDBmod.read_status_data( PowerPIN_Status, REGID, "level") #start power pin if PowerPINlevel < 1: PowerPINlevel == 0 if not ignorepowerpincount: statusdataDBmod.write_status_data(PowerPIN_Status, REGID, "level", PowerPINlevel + 1) # complication below is necessary. timeZero = int(time.time()) + pulsesecond Lasttimezero = statusdataDBmod.read_status_data( PowerPIN_Status, REGID, "timeZero") if Lasttimezero: if timeZero > Lasttimezero: statusdataDBmod.write_status_data(PowerPIN_Status, REGID, "timeZero", timeZero) MQTT_output(CMD, address) else: statusdataDBmod.write_status_data(PowerPIN_Status, REGID, "timeZero", timeZero) if PowerPINlevel == 0: time.sleep(0.2) return True
def CounterOnlyNew(element, sensor, periodsecond): # this one should be dismissed isok = False global AUTO_data if periodsecond > 0: # in case another timer is active on this element, cancel it threadID = statusdataDBmod.read_status_data(AUTO_data, element + sensor, "RegisterID") if threadID != None and threadID != "": threadID.cancel() validinterruptcount = statusdataDBmod.read_status_data( AUTO_data, element, "validinterruptcount") validinterruptcount = validinterruptcount + 1 statusdataDBmod.write_status_data(AUTO_data, element, "validinterruptcount", validinterruptcount) else: # time between interrupt exceeded, restart counter validinterruptcount = 1 statusdataDBmod.write_status_data(AUTO_data, element, "validinterruptcount", validinterruptcount) # activate a new time, in cas this is not cancelled then the data will be saved callin the savedata procedure threadID = threading.Timer(periodsecond, WaitandRegisterNew, [element, sensor, validinterruptcount]) threadID.start() statusdataDBmod.write_status_data(AUTO_data, element + sensor, "RegisterID", threadID) return isok
def setActivationDurationDate(element, tobeactivated, duration, triggerdate): global AUTO_data statusdataDBmod.write_status_data(AUTO_data, element, "tobeactivated", tobeactivated) #true or false statusdataDBmod.write_status_data(AUTO_data, element, "duration", duration) statusdataDBmod.write_status_data(AUTO_data, element, "triggerdate", triggerdate)
def startblockingstate(element, periodsecond, saveend=True): #logger.warning("StartBOLCKINGSTATE Started ---> Period %d", periodsecond) global BLOCKING_data sensor = interruptdbmod.searchdata("element", element, "sensor") #save data print("first save in database") if saveend: saveblockingdiff(sensor) #-- if periodsecond > 0: global AUTO_data # in case another timer is active on this element, cancel it threadID = statusdataDBmod.read_status_data(AUTO_data, element, "threadID") if threadID != None and threadID != "": #print "cancel the Thread of element=",element threadID.cancel() else: # change blocking counter BlockingNumbers = statusdataDBmod.read_status_data( BLOCKING_data, sensor, "BlockingNumbers") BlockingNumbers = BlockingNumbers + 1 statusdataDBmod.write_status_data(BLOCKING_data, sensor, "BlockingNumbers", BlockingNumbers) #-- #save data if saveend: saveblockingdiff(sensor) #-- statusdataDBmod.write_status_data(AUTO_data, element, "blockingstate", True) statusdataDBmod.write_status_data( hardwaremod.Blocking_Status, element, "priority", ACTIONPRIORITYLEVEL) #increse the priority to execute a command nonblockingpriority = 0 #logger.warning("Trigger EndblockingStart ---> Period %d", periodsecond) threadID = threading.Timer(periodsecond, endblocking, [element, saveend]) threadID.start() statusdataDBmod.write_status_data(AUTO_data, element, "threadID", threadID)
def activatedoser(element, duration): print element, " ",duration, " " , datetime.now() logger.info('Doser Pulse, pulse time for ms = %s', duration) pulseok=hardwaremod.makepulse(element,duration) # salva su database actuatordbmod.insertdataintable(element,duration) # put flag down global AUTO_data statusdataDBmod.write_status_data(AUTO_data,element,"tobeactivated",False) statusdataDBmod.write_status_data(AUTO_data,element,"duration",0) statusdataDBmod.write_status_data(AUTO_data,element,"triggerdate",datetime.now())
def endblocking(element, saveend=True): sensor = interruptdbmod.searchdata("element", element, "sensor") if checkstopcondition(element): global AUTO_data #save data if saveend: saveblockingdiff(sensor) #-- threadID = statusdataDBmod.read_status_data(AUTO_data, element, "threadID") if threadID != None and threadID != "": #print "cancel the Thread of element=",element threadID.cancel() global BLOCKING_data # change blocking counter BlockingNumbers = statusdataDBmod.read_status_data( BLOCKING_data, sensor, "BlockingNumbers") BlockingNumbers = BlockingNumbers - 1 statusdataDBmod.write_status_data(BLOCKING_data, sensor, "BlockingNumbers", BlockingNumbers) #-- #save data saveblockingdiff(sensor) #-- #print "Start removing blocking status" statusdataDBmod.write_status_data( hardwaremod.Blocking_Status, element, "priority", NONBLOCKINGPRIORITY) #put the priority to lower levels statusdataDBmod.write_status_data(AUTO_data, element, "threadID", None) statusdataDBmod.write_status_data(AUTO_data, element, "blockingstate", False) else: # renew the blocking status print("Interrupt LEVEL High, Do not stop blocking period, Extend it") # reload the period in case this is chnaged preemptiontimemin = hardwaremod.toint( interruptdbmod.searchdata("element", element, "preemptive_period"), 0) period = preemptiontimemin * 60 if period > 0: startblockingstate(element, period)
def powerPIN_start(address, POWERPIN,logic,waittime): if POWERPIN!="": PowerPINlevel=statusdataDBmod.read_status_data(PowerPIN_Status,address+POWERPIN,"level") statusdataDBmod.write_status_data(PowerPIN_Status,address+POWERPIN,"level",PowerPINlevel+1) #PowerPIN_Status[POWERPIN]["level"]+=1 #start power pin PowerPINstate=statusdataDBmod.read_status_data(PowerPIN_Status,address+POWERPIN,"state") if PowerPINstate=="off": GPIO_setup(address, POWERPIN, "out") if logic=="pos": GPIO_output(address, POWERPIN, 1) statusdataDBmod.write_status_data(PowerPIN_Status,address+POWERPIN,"pinstate","1") #PowerPIN_Status[POWERPIN]["pinstate"]="1" else: GPIO_output(address, POWERPIN, 0) statusdataDBmod.write_status_data(PowerPIN_Status,address+POWERPIN,"pinstate","0") #PowerPIN_Status[POWERPIN]["pinstate"]="0" statusdataDBmod.write_status_data(PowerPIN_Status,address+POWERPIN,"state","on") #PowerPIN_Status[POWERPIN]["state"]="on" #print "PowerPin activated ", POWERPIN time.sleep(waittime) return True
def powerPIN_stop(address, POWERPIN,waittime): if POWERPIN!="": #set powerpin to zero again in case this is the last thread PowerPINlevel=statusdataDBmod.read_status_data(PowerPIN_Status,address+POWERPIN,"level") statusdataDBmod.write_status_data(PowerPIN_Status,address+POWERPIN,"level",PowerPINlevel-1) #PowerPIN_Status[POWERPIN]["level"]-=1 #stop power pin if (PowerPINlevel-1)<=0: PowerPINstate=statusdataDBmod.read_status_data(PowerPIN_Status,address+POWERPIN,"state") if PowerPINstate=="on": time.sleep(waittime) PowerPINpinstate=statusdataDBmod.read_status_data(PowerPIN_Status,address+POWERPIN,"pinstate") if PowerPINpinstate=="1": GPIO_output(address,POWERPIN, 0) statusdataDBmod.write_status_data(PowerPIN_Status,address+POWERPIN,"pinstate","0") #PowerPIN_Status[POWERPIN]["pinstate"]="0" elif PowerPINpinstate=="0": GPIO_output(address,POWERPIN, 1) statusdataDBmod.write_status_data(PowerPIN_Status,address+POWERPIN,"pinstate","1") #PowerPIN_Status[POWERPIN]["pinstate"]="1" statusdataDBmod.write_status_data(PowerPIN_Status,address+POWERPIN,"state","off") #PowerPIN_Status[POWERPIN]["state"]="off" return True
def endblocking(element, period): if checkstopcondition(element): global AUTO_data threadID = statusdataDBmod.read_status_data(AUTO_data, element, "threadID") if threadID != None and threadID != "": print "cancel the Thread of element=", element threadID.cancel() print "Start removing blocking status" statusdataDBmod.write_status_data( hardwaremod.Blocking_Status, element, "priority", NONBLOCKINGPRIORITY) #put the priority to lower levels statusdataDBmod.write_status_data(AUTO_data, element, "threadID", None) statusdataDBmod.write_status_data(AUTO_data, element, "blockingstate", False) else: print "Interrupt LEVEL High, Do not stop blocking period, Extend it" startblockingstate(element, period)
def startblockingstate(element, periodsecond): if periodsecond > 0: global AUTO_data # in case another timer is active on this element, cancel it threadID = statusdataDBmod.read_status_data(AUTO_data, element, "threadID") if threadID != None and threadID != "": print "cancel the Thread of element=", element threadID.cancel() statusdataDBmod.write_status_data(AUTO_data, element, "blockingstate", True) statusdataDBmod.write_status_data( hardwaremod.Blocking_Status, element, "priority", ACTIONPRIORITYLEVEL) #increse the priority to execute a command nonblockingpriority = 0 threadID = threading.Timer(periodsecond, endblocking, [element, periodsecond]) threadID.start() statusdataDBmod.write_status_data(AUTO_data, element, "threadID", threadID)
def automationexecute(refsensor, element): sensor = automationdbmod.searchdata("element", element, "sensor") # check the sensor if refsensor == sensor: logger.info('automation Pairing OK ---> Actuator: %s , Sensor: %s', element, sensor) # check the watering mode modelist = ["None", "Full Auto", "Emergency Activation", "Alert Only"] workmode = checkworkmode(element) if (workmode == "None"): # None case print "No Action required, workmode set to None, element: ", element logger.info( "No Action required, workmode set to None, element: %s ", element) return if (workmode == ""): logger.info("Not able to get the workmode: %s ", element) return logger.info('Automantion, Get all the parameters') sensormaxthreshold = hardwaremod.tonumber( automationdbmod.searchdata("element", element, "sensor_threshold")[1], 0) sensorminthreshold = hardwaremod.tonumber( automationdbmod.searchdata("element", element, "sensor_threshold")[0], sensormaxthreshold) actuatormaxthreshold = hardwaremod.tonumber( automationdbmod.searchdata("element", element, "actuator_threshold")[1], 0) actuatorminthreshold = hardwaremod.tonumber( automationdbmod.searchdata("element", element, "actuator_threshold")[0], actuatormaxthreshold) # evaluate variables for operational period check starttime = datetime.strptime( automationdbmod.searchdata("element", element, "allowedperiod")[0], '%H:%M').time() endtime = datetime.strptime( automationdbmod.searchdata("element", element, "allowedperiod")[1], '%H:%M').time() # get other parameters maxstepnumber = hardwaremod.toint( automationdbmod.searchdata("element", element, "stepnumber"), 1) waitingtime = hardwaremod.toint( automationdbmod.searchdata("element", element, "pausebetweenwtstepsmin"), 1) mailtype = automationdbmod.searchdata("element", element, "mailalerttype") averageminutes = hardwaremod.tonumber( automationdbmod.searchdata("element", element, "averagesample"), 1) mathoperation = automationdbmod.searchdata("element", element, "mathoperation") # check sensor timetrigger sensorcontrolcommand = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, refsensor, hardwaremod.HW_CTRL_CMD) logger.info('Sensor control command: %s , Sensor: %s', sensorcontrolcommand, sensor) if sensorcontrolcommand == "returnzero": logger.info('Modify parameter for the timetrigger') #adjust the parameters in the way the activation condition is always obtained sensormaxthreshold = 1 sensorminthreshold = -1 maxstepnumber = 1 averageminutes = 0 # Calculated Variables if maxstepnumber < 1: # not possible to proceed print "No Action required, maxstepnumber <1, element: ", element logger.info("No Action required, maxstepnumber <1, element: %s ", element) return interval = (sensormaxthreshold - sensorminthreshold) / maxstepnumber actuatorinterval = (actuatormaxthreshold - actuatorminthreshold) / maxstepnumber P = [] for I in range(0, maxstepnumber + 1): P.append(actuatorminthreshold + I * actuatorinterval) # ------------------------ Automation alghoritm if workmode == "Full Auto": # check if inside the allowed time period print "full Auto Mode" logger.info('full auto mode --> %s', element) timeok = isNowInTimePeriod( starttime, endtime, datetime.now().time()) # don't use UTC here! print "inside allowed time ", timeok, " starttime ", starttime, " endtime ", endtime if timeok: logger.info('inside allowed time') isok, sensorvalue = sensorreading( sensor, averageminutes, mathoperation ) # operation of sensor readings for a number of sample if isok: print "Sensor Value ", sensorvalue if sensorminthreshold <= sensormaxthreshold: print "Algorithm , element: ", element logger.info("Forward algorithm , element: %s ", element) Inde = 0 maxs = sensorminthreshold + Inde * interval if sensorvalue <= maxs: status = "belowthreshold" logger.info('below Minthreshold') value = P[Inde] # do relevant stuff CheckActivateNotify(element, waitingtime, value, mailtype, sensor, sensorvalue) Inde = 1 for I in range(Inde, maxstepnumber): mins = sensorminthreshold + (I - 1) * interval maxs = sensorminthreshold + I * interval if mins < sensorvalue <= maxs: value = P[I] logger.info('inside Range') # do relevant stuff CheckActivateNotify(element, waitingtime, value, mailtype, sensor, sensorvalue) Inde = maxstepnumber mins = sensorminthreshold + (Inde - 1) * interval if mins < sensorvalue: print "INDE:", Inde value = P[Inde] logger.info('beyond Range') # do relevant stuff CheckActivateNotify(element, waitingtime, value, mailtype, sensor, sensorvalue) # END MAIN ALGORITHM else: # to be added case of inverse sensor condition, where the sensorminthreshold is higher than the sensormaxthreshold print "Reverse Algorithm , element: ", element logger.info("Reverse Algorithm , element: %s ", element) Inde = 0 maxs = sensorminthreshold + Inde * interval if sensorvalue >= maxs: status = "belowthreshold" logger.info('Above MAXthreshold') value = P[Inde] # do relevant stuff CheckActivateNotify(element, waitingtime, value, mailtype, sensor, sensorvalue) Inde = Inde + 1 for I in range(Inde, maxstepnumber): mins = sensorminthreshold + (I - 1) * interval maxs = sensorminthreshold + I * interval if mins > sensorvalue >= maxs: value = P[I] # do relevant stuff CheckActivateNotify(element, waitingtime, value, mailtype, sensor, sensorvalue) Inde = maxstepnumber mins = sensorminthreshold + (Inde - 1) * interval if mins > sensorvalue: print "INDE:", Inde value = P[Inde] # do relevant stuff CheckActivateNotify(element, waitingtime, value, mailtype, sensor, sensorvalue) # END MAIN ALGORITHM - Reverse else: logger.error( 'No valid calculation operation on the stored sensor data' ) else: logger.info('Outside allowed Time, Stop') elif workmode == "Emergency Activation": print "Emergency Activation" elif workmode == "Alert Only": print "Alert Only" # implment Critical alert message in case the sensor value is one interval more than Max_threshold isok, sensorvalue = sensorreading( sensor, averageminutes, mathoperation ) # operation of sensor readings for a number of sample if isok: if sensorminthreshold <= sensormaxthreshold: if sensorvalue > sensormaxthreshold + interval: logger.info('sensor %s exceeding limits', sensor) textmessage = "CRITICAL: " + sensor + " reading " + str( sensorvalue ) + " exceeding threshold limits, need to check the " + element print textmessage #send alert mail notification alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 2: if (mailtype != "none"): emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) else: if sensorvalue < sensormaxthreshold + interval: logger.info('sensor %s exceeding limits', sensor) textmessage = "CRITICAL: " + sensor + " reading " + str( sensorvalue ) + " exceeding threshold limits, need to check the " + element print textmessage #send alert mail notification alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 2: if (mailtype != "none"): emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) return
def gpio_pulse(cmd, message, recdata): successflag=0 msgarray=message.split(":") messagelen=len(msgarray) PIN=msgarray[1] testpulsetime=msgarray[2] pulsesecond=int(testpulsetime) logic="pos" if messagelen>3: logic=msgarray[3] POWERPIN="" if messagelen>4: POWERPIN=msgarray[4] address="" # this is the default address of the MCP 23017 if messagelen>5: address=msgarray[5] if address=="": address="0x20" activationmode="" if messagelen>7: activationmode=msgarray[7] if isPinActive(address,PIN,logic): if activationmode=="NOADD": # no action needed print("No Action, pulse activated when PIN already active and activationmode is NOADD") logger.warning("No Action, pulse activated when PIN already active and activationmode is NOADD") successflag=1 recdata.append(cmd) recdata.append(PIN) recdata.append(successflag) return True # in case another timer is active on this PIN, cancel it PINthreadID=statusdataDBmod.read_status_data(GPIO_data,address+PIN,"threadID") if not PINthreadID==None: #print "cancel the Thread of PIN=",PIN PINthreadID.cancel() else: powerPIN_start(address, POWERPIN,logic,0.2) # it is assumed that the logic (pos,neg) of the powerpin is the same of the pin to pulse, in the future it might be useful to specify the powerpin logic separately GPIO_setup(address, PIN, "out") if logic=="pos": level=1 else: level=0 pulseok=GPIO_output(address, PIN, level) if not pulseok: msg="Not able to activate the pulse in GPIO Expansion, Address I2C: " + address + " PIN: "+ PIN print(msg) logger.error(msg) recdata.append(cmd) recdata.append(msg) recdata.append(0) return True NewPINthreadID=threading.Timer(pulsesecond, endpulse, [address, PIN , logic , POWERPIN ]) NewPINthreadID.start() statusdataDBmod.write_status_data(GPIO_data,address+PIN,"threadID",NewPINthreadID) #print "pulse started", time.ctime() , " PIN=", PIN , " Logic=", logic successflag=1 recdata.append(cmd) recdata.append(PIN) recdata.append(successflag) return True
def automationexecute(refsensor,element): sensor=automationdbmod.searchdata("element",element,"sensor") # check the sensor if refsensor==sensor: logger.info('automation Pairing OK ---> Actuator: %s , Sensor: %s', element, sensor) # check the watering mode modelist=["None", "Full Auto" , "Emergency Activation" , "Alert Only"] workmode=checkworkmode(element) if (workmode=="None"): # None case print "No Action required, workmode set to None, element: " , element logger.info("No Action required, workmode set to None, element: %s " , element) return if (workmode==""): logger.info("Not able to get the workmode: %s " , element) return logger.info('Automantion, Get all the parameters') sensormaxthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"sensor_threshold")[1],0) sensorminthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"sensor_threshold")[0],sensormaxthreshold) actuatormaxthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"actuator_threshold")[1],0) actuatorminthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"actuator_threshold")[0],actuatormaxthreshold) # evaluate variables for operational period check now = datetime.now() nowtime = now.time() starttimeh=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[0].split(":")[0],0) starttimem=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[0].split(":")[1],0) endtimeh=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[1].split(":")[0],1) endtimem=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[1].split(":")[1],0) starttime=time(starttimeh,starttimem) endtime=time(endtimeh,endtimem) # get other parameters maxstepnumber=hardwaremod.toint(automationdbmod.searchdata("element",element,"stepnumber"),1) waitingtime=hardwaremod.toint(automationdbmod.searchdata("element",element,"pausebetweenwtstepsmin"),1) mailtype=automationdbmod.searchdata("element",element,"mailalerttype") averageminutes=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"averagesample"),1) mathoperation=automationdbmod.searchdata("element",element,"mathoperation") # check sensor timetrigger sensorcontrolcommand=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,refsensor,hardwaremod.HW_CTRL_CMD) logger.info('Sensor control command: %s , Sensor: %s', sensorcontrolcommand, sensor) if sensorcontrolcommand=="returnzero": logger.info('Modify parameter for the timetrigger') #adjust the parameters in the way the activation condition is always obtained sensormaxthreshold=1 sensorminthreshold=-1 maxstepnumber=1 averageminutes=0 # Calculated Variables if maxstepnumber<1: # not possible to proceed print "No Action required, maxstepnumber <1, element: " , element logger.info("No Action required, maxstepnumber <1, element: %s " , element) return interval=(sensormaxthreshold-sensorminthreshold)/maxstepnumber actuatorinterval=(actuatormaxthreshold-actuatorminthreshold)/maxstepnumber P=[] for I in range(0, maxstepnumber+1): P.append(actuatorminthreshold+I*actuatorinterval) # ------------------------ Automation alghoritm if workmode=="Full Auto": # check if inside the allowed time period print "full Auto Mode" logger.info('full auto mode --> %s', element) timeok=isNowInTimePeriod(starttime, endtime, nowtime) print "inside allowed time ", timeok , " starttime ", starttime , " endtime ", endtime if timeok: logger.info('inside allowed time') isok,sensorvalue=sensorreading(sensor,averageminutes,mathoperation) # operation of sensor readings for a number of sample if isok: print "Sensor Value ", sensorvalue if sensorminthreshold<=sensormaxthreshold: print "Algorithm , element: " , element logger.info("Forward algorithm , element: %s " , element) Inde=0 maxs=sensorminthreshold+Inde*interval if sensorvalue<=maxs: status="belowthreshold" logger.info('below Minthreshold') value=P[Inde] # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) Inde=1 for I in range(Inde, maxstepnumber): mins=sensorminthreshold+(I-1)*interval maxs=sensorminthreshold+I*interval if mins<sensorvalue<=maxs: value=P[I] logger.info('inside Range') # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) Inde=maxstepnumber mins=sensorminthreshold+(Inde-1)*interval if mins<sensorvalue: print "INDE:",Inde value=P[Inde] logger.info('beyond Range') # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) # END MAIN ALGORITHM else: # to be added case of inverse sensor condition, where the sensorminthreshold is higher than the sensormaxthreshold print "Reverse Algorithm , element: " , element logger.info("Reverse Algorithm , element: %s " , element) Inde=0 maxs=sensorminthreshold+Inde*interval if sensorvalue>=maxs: status="belowthreshold" logger.info('Above MAXthreshold') value=P[Inde] # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) Inde=Inde+1 for I in range(Inde, maxstepnumber): mins=sensorminthreshold+(I-1)*interval maxs=sensorminthreshold+I*interval if mins>sensorvalue>=maxs: value=P[I] # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) Inde=maxstepnumber mins=sensorminthreshold+(Inde-1)*interval if mins>sensorvalue: print "INDE:",Inde value=P[Inde] # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) # END MAIN ALGORITHM - Reverse else: logger.info('No valid calculation operation on the stored sensor data') elif workmode=="Emergency Activation": print "Emergency Activation" elif workmode=="Alert Only": print "Alert Only" # implment Critical alert message in case the sensor value is one interval more than Max_threshold isok,sensorvalue=sensorreading(sensor,averageminutes,mathoperation) # operation of sensor readings for a number of sample if isok: if sensorminthreshold<=sensormaxthreshold: if sensorvalue>sensormaxthreshold+interval: logger.info('sensor %s exceeding limits', sensor) textmessage="CRITICAL: "+ sensor + " reading " + str(sensorvalue) + " exceeding threshold limits, need to check the " + element print textmessage #send alert mail notification alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<2: emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) else: if sensorvalue<sensormaxthreshold+interval: logger.info('sensor %s exceeding limits', sensor) textmessage="CRITICAL: "+ sensor + " reading " + str(sensorvalue) + " exceeding threshold limits, need to check the " + element print textmessage #send alert mail notification alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<2: emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) return
def autowateringexecute(refsensor,element): global AUTO_data sensor=autowateringdbmod.searchdata("element",element,"sensor") # check the sensor if refsensor==sensor: print "auto watering check -----------------------------------------> ", element logger.info('auto watering check --------------------------> %s', element) # check the watering mode modelist=["None", "Full Auto" , "Emergency Activation" , "Alert Only"] workmode=checkworkmode(element) if not(sensor in sensordbmod.gettablelist()): print "Sensor does not exist " ,sensor , ", element: " , element logger.error("Sensor does not exist %s , element: %s " ,sensor, element) return "sensor not Exist" maxthreshold=hardwaremod.tonumber(autowateringdbmod.searchdata("element",element,"threshold")[1],0) minthreshold=hardwaremod.tonumber(autowateringdbmod.searchdata("element",element,"threshold")[0],maxthreshold) # exit condition in case of data inconsistency if minthreshold>=maxthreshold: print "Data inconsistency , element: " , element logger.error("Data inconsistency , element: %s " , element) return "data inconsistency" now = datetime.now() nowtime = now.time() starttimeh=hardwaremod.toint(autowateringdbmod.searchdata("element",element,"allowedperiod")[0].split(":")[0],0) starttimem=hardwaremod.toint(autowateringdbmod.searchdata("element",element,"allowedperiod")[0].split(":")[1],0) endtimeh=hardwaremod.toint(autowateringdbmod.searchdata("element",element,"allowedperiod")[1].split(":")[0],1) endtimem=hardwaremod.toint(autowateringdbmod.searchdata("element",element,"allowedperiod")[1].split(":")[1],0) starttime=time(starttimeh,starttimem) endtime=time(endtimeh,endtimem) duration=1000*hardwaremod.toint(autowateringdbmod.searchdata("element",element,"wtstepsec"),0) maxstepnumber=hardwaremod.toint(autowateringdbmod.searchdata("element",element,"maxstepnumber"),0) maxdays=hardwaremod.toint(autowateringdbmod.searchdata("element",element,"maxdaysbetweencycles"),0) waitingtime=hardwaremod.toint(autowateringdbmod.searchdata("element",element,"pausebetweenwtstepsmin"),0) mailtype=autowateringdbmod.searchdata("element",element,"mailalerttype") minaccepted=hardwaremod.tonumber(autowateringdbmod.searchdata("element",element,"sensorminacceptedvalue"),0.1) # ------------------------ Workmode split if workmode=="Full Auto": # block the wateringplan activation as by definition of "Full Auto" allowwateringplan[element]=False # check if inside the allowed time period print "full Auto Mode" logger.info('full auto mode --> %s', element) timeok=isNowInTimePeriod(starttime, endtime, nowtime) print "inside allowed time ", timeok , " starttime ", starttime , " endtime ", endtime logger.info('full auto mode') if timeok: logger.info('inside allowed time') belowthr,valid=checkminthreshold(sensor,minthreshold,minaccepted) if valid: if belowthr: status="lowthreshold" logger.info('below threshold') # wait to seek a more stable reading of hygrometer # check if time between watering events is larger that the waiting time (minutes) lastwateringtime=statusdataDBmod.read_status_data(AUTO_data,element,"lastwateringtime") print ' Previous watering: ' , lastwateringtime , ' Now: ', datetime.now() timedifference=sensordbmod.timediffinminutes(lastwateringtime,datetime.now()) print 'Time interval between watering steps', timedifference ,'. threshold', waitingtime logger.info('Time interval between watering steps %d threshold %d', timedifference,waitingtime) if timedifference>waitingtime: print " Sufficient waiting time" logger.info('Sufficient waiting time') # activate watering in case the maxstepnumber is not exceeded watercounter=statusdataDBmod.read_status_data(AUTO_data,element,"watercounter") if maxstepnumber>watercounter: #activate pump activatewater(element, duration) # invia mail, considered as info, not as alert if mailtype!="warningonly": textmessage="INFO: " + sensor + " value below the minimum threshold " + str(minthreshold) + ", activating the watering :" + element emailmod.sendallmail("alert", textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",watercounter+1) statusdataDBmod.write_status_data(AUTO_data,element,"lastwateringtime",datetime.now()) else: # critical, sensor below minimum after all watering activations are done logger.info('Number of watering time per cycle has been exceeeded') # read hystory data and calculate the slope timelist=hardwaremod.gettimedata(sensor) cyclestartdate=statusdataDBmod.read_status_data(AUTO_data,element,"cyclestartdate") lastwateringtime=statusdataDBmod.read_status_data(AUTO_data,element,"lastwateringtime") startdate=cyclestartdate - timedelta(minutes=timelist[1]) enddate=lastwateringtime + timedelta(minutes=waitingtime) isslopeok=checkinclination(sensor,startdate,enddate) # still to decide if use the enddate if isslopeok: # invia mail if couner alert is lower than 1 alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<1: textmessage="WARNING: Please consider to increase the amount of water per cycle, the "+ sensor + " value below the MINIMUM threshold " + str(minthreshold) + " still after activating the watering :" + element + " for " + str(maxstepnumber) + " times. System will automatically reset the watering cycle to allow more water" print textmessage #send alert mail notification emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) # reset watering cycle status="done" statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",-1) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"cyclestartdate",datetime.now()) else: # slope not OK, probable hardware problem alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<3: textmessage="CRITICAL: Possible hardware problem, "+ sensor + " value below the MINIMUM threshold " + str(minthreshold) + " still after activating the watering :" + element + " for " + str(maxstepnumber) + " times" print textmessage #send alert mail notification emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) # update the status checkcounter=statusdataDBmod.read_status_data(AUTO_data,element,"checkcounter") statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus",status) statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",checkcounter+1) # RAMPUP case above threshold but below maxthreshold elif sensorreading(sensor)<maxthreshold: # intermediate state where the sensor is above the minthreshold but lower than the max threshold # check the status of the automatic cycle cyclestatus=statusdataDBmod.read_status_data(AUTO_data,element,"cyclestatus") if cyclestatus!="done": status="rampup" # wait to seek a more stable reading of hygrometer # check if time between watering events is larger that the waiting time (minutes) lastwateringtime=statusdataDBmod.read_status_data(AUTO_data,element,"lastwateringtime") if sensordbmod.timediffinminutes(lastwateringtime,datetime.now())>waitingtime: watercounter=statusdataDBmod.read_status_data(AUTO_data,element,"watercounter") if maxstepnumber>watercounter: #activate pump activatewater(element, duration) # invia mail, considered as info, not as alert if mailtype!="warningonly": textmessage="INFO: " + sensor + " value below the Maximum threshold " + str(maxthreshold) + ", activating the watering :" + element emailmod.sendallmail("alert", textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",watercounter+1) statusdataDBmod.write_status_data(AUTO_data,element,"lastwateringtime",datetime.now()) else: # give up to reache the maximum threshold, proceed as done, send alert logger.info('Number of watering time per cycle has been exceeeded') # invia mail if couner alert is lower than 1 -------------- # only if the info is activated if mailtype!="warningonly": alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<2: textmessage="INFO "+ sensor + " value below the Maximum threshold " + str(maxthreshold) + " still after activating the watering :" + element + " for " + str(maxstepnumber) + " times" print textmessage #send alert mail notification emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) # reset watering cycle status="done" statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",-1) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"cyclestartdate",datetime.now()) # update the status checkcounter=statusdataDBmod.read_status_data(AUTO_data,element,"checkcounter") statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus",status) statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",checkcounter+1) else: # update the status, reset cycle statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus","done") statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) elif workmode=="Emergency Activation": # check if inside the allow time period logger.info('Emergency Mode') timeok=isNowInTimePeriod(starttime, endtime, nowtime) print "inside allowed time ", timeok , " starttime ", starttime , " endtime ", endtime if timeok: belowthr,valid=checkminthreshold(sensor,minthreshold,minaccepted) if valid: if belowthr: # wait to seek a more stable reading of hygrometer # check if time between watering events is larger that the waiting time (minutes) lastwateringtime=statusdataDBmod.read_status_data(AUTO_data,element,"lastwateringtime") if sensordbmod.timediffinminutes(lastwateringtime,datetime.now())>waitingtime: # activate watering in case the maxstepnumber is not exceeded watercounter=statusdataDBmod.read_status_data(AUTO_data,element,"watercounter") if maxstepnumber>watercounter: #activate pump activatewater(element, duration) # invia mail, considered as info, not as alert if mailtype!="warningonly": textmessage="INFO: " + sensor + " value below the minimum threshold " + str(minthreshold) + ", activating the watering :" + element emailmod.sendallmail("alert", textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",watercounter+1) statusdataDBmod.write_status_data(AUTO_data,element,"lastwateringtime",datetime.now()) else: logger.info('Number of watering time per cycle has been exceeeded') # read hystory data and calculate the slope timelist=hardwaremod.gettimedata(sensor) cyclestartdate=statusdataDBmod.read_status_data(AUTO_data,element,"cyclestartdate") lastwateringtime=statusdataDBmod.read_status_data(AUTO_data,element,"lastwateringtime") startdate=cyclestartdate - timedelta(minutes=timelist[1]) enddate=lastwateringtime + timedelta(minutes=waitingtime) isslopeok=checkinclination(sensor,startdate,enddate) if isslopeok: # invia mail if couner alert is lower than 1 alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<1: textmessage="WARNING: Please consider to increase the amount of water per cycle, the "+ sensor + " value below the MINIMUM threshold " + str(minthreshold) + " still after activating the watering :" + element + " for " + str(maxstepnumber) + " times. System will automatically reset the watering cycle to allow more water" print textmessage #send alert mail notification alertcounter emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) # reset watering cycle status="done" statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",-1) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"cyclestartdate",datetime.now()) else: # slope not OK, probable hardware problem alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<3: textmessage="CRITICAL: Possible hardware problem, "+ sensor + " value below the MINIMUM threshold " + str(minthreshold) + " still after activating the watering :" + element + " for " + str(maxstepnumber) + " times" print textmessage #send alert mail notification emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) # update the status checkcounter=statusdataDBmod.read_status_data(AUTO_data,element,"checkcounter") statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus","lowthreshold") statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",checkcounter+1) else: # update the status statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus","done") statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) elif workmode=="under MIN over MAX": logger.info('under MIN over MAX') # normally watering plan is allowed unless over MAX threshold allowwateringplan[element]=True # check if inside the allow time period timeok=isNowInTimePeriod(starttime, endtime, nowtime) print "inside allowed time ", timeok , " starttime ", starttime , " endtime ", endtime if timeok: logger.info('Insede operative time') belowthr,valid=checkminthreshold(sensor,minthreshold,minaccepted) if valid: logger.info('valid sensor reading') if belowthr: logger.info('sensor reading below threshold') # wait to seek a more stable reading of hygrometer # check if time between watering events is larger that the waiting time (minutes) lastwateringtime=statusdataDBmod.read_status_data(AUTO_data,element,"lastwateringtime") if sensordbmod.timediffinminutes(lastwateringtime,datetime.now())>waitingtime: # activate watering in case the maxstepnumber is not exceeded watercounter=statusdataDBmod.read_status_data(AUTO_data,element,"watercounter") if maxstepnumber>watercounter: logger.info('water Count not exceeded') #activate pump activatewater(element, duration) # invia mail, considered as info, not as alert if mailtype!="warningonly": textmessage="INFO: " + sensor + " value below the minimum threshold " + str(minthreshold) + ", activating the watering :" + element emailmod.sendallmail("alert", textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",watercounter+1) statusdataDBmod.write_status_data(AUTO_data,element,"lastwateringtime",datetime.now()) else: logger.info('Number of watering time per cycle has been exceeeded') # read hystory data and calculate the slope timelist=hardwaremod.gettimedata(sensor) cyclestartdate=statusdataDBmod.read_status_data(AUTO_data,element,"cyclestartdate") lastwateringtime=statusdataDBmod.read_status_data(AUTO_data,element,"lastwateringtime") startdate=cyclestartdate - timedelta(minutes=timelist[1]) enddate=lastwateringtime + timedelta(minutes=waitingtime) isslopeok=checkinclination(sensor,startdate,enddate) if isslopeok: # invia mail if couner alert is lower than 1 alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<1: textmessage="WARNING: Please consider to increase the amount of water per cycle, the "+ sensor + " value below the MINIMUM threshold " + str(minthreshold) + " still after activating the watering :" + element + " for " + str(maxstepnumber) + " times. System will automatically reset the watering cycle to allow more water" print textmessage #send alert mail notification emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) # reset watering cycle status="done" statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",-1) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"cyclestartdate",datetime.now()) else: # slope not OK, probable hardware problem alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<3: textmessage="CRITICAL: Possible hardware problem, "+ sensor + " value below the MINIMUM threshold " + str(minthreshold) + " still after activating the watering :" + element + " for " + str(maxstepnumber) + " times" print textmessage #send alert mail notification emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) # update the status checkcounter=statusdataDBmod.read_status_data(AUTO_data,element,"checkcounter") statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus","lowthreshold") statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",checkcounter+1) else: # above minimum threshold logger.info('sensor reading above min threshold') # update the status statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus","done") statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) if sensorreading(sensor)>maxthreshold: logger.info('sensor reading above MAX threshold, deactivate scheduled irrigation') # do not activate the irrigation scheduled in the time plan allowwateringplan[element]=False elif workmode=="Alert Only": belowthr,valid=checkminthreshold(sensor,minthreshold,minaccepted) if valid: if belowthr: # invia mail if couter alert is lower than alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<2: textmessage="WARNING "+ sensor + " value below the minimum threshold " + str(minthreshold) + " watering system: " + element print textmessage #send alert mail notification emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) # update the status checkcounter=statusdataDBmod.read_status_data(AUTO_data,element,"checkcounter") statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus","lowthreshold") statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",checkcounter+1) else: # update the status statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus","done") statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) else: # None case print "No Action required, workmode set to None, element: " , element logger.info("No Action required, workmode set to None, element: %s " , element) cyclestatus=statusdataDBmod.read_status_data(AUTO_data,element,"cyclestatus") if cyclestatus=="lowthreshold": checkcounter=statusdataDBmod.read_status_data(AUTO_data,element,"checkcounter") if checkcounter==1: statusdataDBmod.write_status_data(AUTO_data,element,"cyclestartdate",datetime.now()) # implment alert message for the cycle exceeding days, and reset the cycle if workmode!="None": cyclestartdate=statusdataDBmod.read_status_data(AUTO_data,element,"cyclestartdate") timedeltadays=sensordbmod.timediffdays(datetime.now(),cyclestartdate) if (timedeltadays > maxdays): #the upper limit is set in case of abrupt time change textmessage="WARNING "+ sensor + " watering cycle is taking too many days, watering system: " + element + ". Reset watering cycle" print textmessage # in case of full Auto, activate pump for minimum pulse period if workmode=="Full Auto": if (timedeltadays < maxdays+2): #the upper limit is set in case of abrupt time change textmessage="WARNING "+ sensor + " watering cycle is taking too many days, watering system: " + element + ". Activate Min pulse + Reset watering cycle" activatewater(element, duration) #send alert mail notification if mailtype!="warningonly": emailmod.sendallmail("alert", textmessage) logger.error(textmessage) logger.error("Cycle started %s, Now is %s ", cyclestartdate.strftime("%Y-%m-%d %H:%M:%S"), datetime.now().strftime("%Y-%m-%d %H:%M:%S")) # reset cycle statusdataDBmod.write_status_data(AUTO_data,element,"cyclestatus","done") statusdataDBmod.write_status_data(AUTO_data,element,"checkcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"watercounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",0) statusdataDBmod.write_status_data(AUTO_data,element,"cyclestartdate",datetime.now()) # implment Critical alert message in case the threshold is below the 0.5 of the minimum if workmode!="None": belowthr,valid=checkminthreshold(sensor,minthreshold*0.5,minaccepted) if valid: if belowthr: logger.info('sensor %s below half of the actual set threshold', sensor) textmessage="CRITICAL: Plant is dying, "+ sensor + " reading below half of the minimum threshold, need to check the " + element print textmessage #send alert mail notification alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<5: emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) else: logger.info('sensor %s below valid data', sensor) textmessage="WARNING: "+ sensor + " below valid data range, need to check sensor" print textmessage #send alert mail notification alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<3: emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) return
def cyclereset(element): #AUTO_data["default"]={"lasteventtime":datetime.utcnow()- timedelta(minutes=waitingtime),"lastinterrupttime":datetime.utcnow(), #"validinterruptcount":0,"eventactivated":False,"lastactiontime":datetime.utcnow()- timedelta(minutes=waitingtime), #"actionvalue":0, "alertcounter":0, "infocounter":0, "status":"ok" , "threadID":None , "blockingstate":False} #SENSOR_data["default"]={"Startcounttime":datetime.utcnow(),"InterruptCount":0} # this is for the actual frequency sensor #PIN_attributes["default"]={"logic":"pos","refsensor":"","bouncetimeSec":0.001} # this is relebant to the PINs #BLOCKING_data["default"]={"BlockingNumbers":0,"BlockingNumbersThreadID":None} # tihs is relenat to the Interrupt trigger global AUTO_data waitingtime = hardwaremod.toint( interruptdbmod.searchdata("element", element, "preemptive_period"), 0) statusdataDBmod.write_status_data( AUTO_data, element, "lastactiontime", datetime.utcnow() - timedelta(minutes=waitingtime)) statusdataDBmod.write_status_data( AUTO_data, element, "lasteventtime", datetime.utcnow() - timedelta(minutes=waitingtime)) statusdataDBmod.write_status_data(AUTO_data, element, "status", "ok") statusdataDBmod.write_status_data(AUTO_data, element, "actionvalue", 0) statusdataDBmod.write_status_data(AUTO_data, element, "alertcounter", 0) statusdataDBmod.write_status_data(AUTO_data, element, "infocounter", 0) statusdataDBmod.write_status_data(AUTO_data, element, "validinterruptcount", 0) # start procedure to stop blocking on this element endblocking(element) # reassess all the interrupt sensor related shit elementlist = interruptdbmod.getelementlist() sensorblockingcounter = {} #print "elementlist" , elementlist #print elementlist for element in elementlist: #print " ELEMENT " , element workmode = checkworkmode(element) if (workmode != "None") and (workmode != ""): sensor = interruptdbmod.searchdata("element", element, "sensor") #print " SENSOR " , sensor if sensor != "": #print "Blocking starte " , statusdataDBmod.read_status_data(AUTO_data,element,"blockingstate") if statusdataDBmod.read_status_data( AUTO_data, element, "blockingstate"): # blocking state is TRUE #print " TRUE ------------------------------------------------------- " , element if sensor in sensorblockingcounter: sensorblockingcounter[ sensor] = sensorblockingcounter[sensor] + 1 else: sensorblockingcounter[sensor] = 1 print(sensorblockingcounter) global BLOCKING_data for sensor in sensorblockingcounter: statusdataDBmod.write_status_data(BLOCKING_data, sensor, "BlockingNumbers", sensorblockingcounter[sensor])
def CheckActivateNotify(element, sensor, preemptiontime, actuatoroutput, actionmodeafterfirst, actuatoroutputfollowup, mailtype, interrupt_triggernumber, interrupt_validinterval, triggermode): value = actuatoroutput isok = False global AUTO_data # check if in blocking state lasteventtime = statusdataDBmod.read_status_data(AUTO_data, element, "lasteventtime") blockingstate = statusdataDBmod.read_status_data(AUTO_data, element, "blockingstate") #print ' Previous event: ' , lasteventtime , ' Now: ', datetime.utcnow() #timedifference=sensordbmod.timediffinminutes(lasteventtime,datetime.utcnow()) #print 'Time interval between actions', timedifference ,'. threshold', preemptiontime #logger.info('Time interval between Actions %d threshold %d', timedifference,preemptiontime) # count the interrupt that are fast enough to stay in the valid interrupt period #print "autodata" ,AUTO_data[element] lastinterrupttime = statusdataDBmod.read_status_data( AUTO_data, element, "lastinterrupttime") nowtime = datetime.utcnow() # ------------ Frequency if triggermode == "Frequency": # triggermode=="Frequency": NOWTIMELIST.append(nowtime) validinterruptcount = statusdataDBmod.read_status_data( AUTO_data, element, "validinterruptcount") diffseconds = (nowtime - NOWTIMELIST[0]).total_seconds() if diffseconds <= interrupt_validinterval: #valid interval between interrupt, increase counter validinterruptcount = validinterruptcount + 1 else: while (diffseconds > interrupt_validinterval) and (len(NOWTIMELIST) > 1): validinterruptcount = validinterruptcount - 1 diffseconds = (nowtime - NOWTIMELIST.pop(0)).total_seconds() validinterruptcount = len(NOWTIMELIST) statusdataDBmod.write_status_data(AUTO_data, element, "validinterruptcount", validinterruptcount) #-------------Counter else: # triggermode=="Counter": #print ' Previous interrupt: ' , lastinterrupttime , ' Now: ', nowtime diffseconds = (nowtime - lastinterrupttime).total_seconds() statusdataDBmod.write_status_data(AUTO_data, element, "lastinterrupttime", nowtime) validinterruptcount = statusdataDBmod.read_status_data( AUTO_data, element, "validinterruptcount") if diffseconds <= interrupt_validinterval: #valid interval between interrupt, increase counter validinterruptcount = validinterruptcount + 1 else: # time between interrupt too long, restart counter # save on database #x = threading.Thread(target=savedata, args=(sensor,validinterruptcount)) #x.start() #reset counter and events validinterruptcount = 1 statusdataDBmod.write_status_data(AUTO_data, element, "validinterruptcount", validinterruptcount) #print(" validinterruptcount --------------------->", validinterruptcount) #print "********" ,validinterruptcount , "******" if validinterruptcount >= interrupt_triggernumber: # set the validinterruptcount to zero statusdataDBmod.write_status_data(AUTO_data, element, "validinterruptcount", 0) if not blockingstate: # outside the preemption period , first activation #print " outside the preemption period " #logger.info('outside the preemption period') # before action, evaluate if trigger number is reached print("Implement Actuator Value ", value) logger.info('Procedure to start actuator %s, for value = %s', element, value) isok = activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype != "none": if mailtype != "warningonly": textmessage = "INFO: " + sensor + " event , activating:" + element + " with Value " + str( value) #send mail using thread to avoid blocking x = threading.Thread(target=emailmod.sendallmail, args=("alert", textmessage)) x.start() #emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data, element, "lasteventtime", datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data, element, "lastactiontime", datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data, element, "actionvalue", value) # start the blocking state print("Start blocking state") startblockingstate(element, preemptiontime) else: # inside blocking state, this is the follow-up #print " inside the preemption period, starting followup actions: " , actionmodeafterfirst #logger.info('inside the preemption period, check followup actions %s :', actionmodeafterfirst) if actionmodeafterfirst == "None": return if actionmodeafterfirst == "Extend blocking state": # extend only the pre-emption blocking period, no action print("Extend blocking state") startblockingstate(element, preemptiontime) if actionmodeafterfirst == "Remove blocking state" or actionmodeafterfirst == "Remove and Follow-up": # remove the pre-emption blocking period, no action print("Remove blocking state") endblocking(element) if actionmodeafterfirst == "Follow-up action" or actionmodeafterfirst == "Remove and Follow-up": # execute the action followup, no variation in the preemption period value = actuatoroutputfollowup # followup action print("Implement Actuator Value followup", value) logger.info( 'Procedure to start actuator followup %s, for value = %s', element, value) isok = activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype != "none": if mailtype != "warningonly": textmessage = "INFO: " + sensor + " event , activating:" + element + " with Value " + str( value) x = threading.Thread(target=emailmod.sendallmail, args=("alert", textmessage)) x.start() #emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data( AUTO_data, element, "lastactiontime", datetime.utcnow()) statusdataDBmod.write_status_data( AUTO_data, element, "actionvalue", value) return isok
def WaitandRegisterNew(element, sensor, counter): global AUTO_data savedata(sensor, counter) statusdataDBmod.write_status_data(AUTO_data, element + sensor, "RegisterID", None)