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 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 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 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 MQTT_pin_level(cmd, message, recdata): msgarray = message.split(":") PIN = msgarray[1] recdata.append(msgarray[0]) PINlevel = statusdataDBmod.read_status_data(GPIO_data, PIN, "level") if PINlevel is not None: recdata.append(str(PINlevel)) return True else: recdata.append("e") return False
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 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 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 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 checkactivate(elementwater,durationwater): elementlist=fertilizerdbmod.getelementlist() waterok=False for doserelement in elementlist: # provided the waterelement, search for corresponding doserelement linkedwaterelement=autofertilizerdbmod.searchdata("element",doserelement,"waterZone") if linkedwaterelement==elementwater: waterok=True element=doserelement break if waterok: # there is a corresponding doser element minwaterduration=hardwaremod.toint(autofertilizerdbmod.searchdata("element",element,"minactivationsec"),0) if not isschedulermode(element): #setup is not for scheduled time print " Fertilizer " ,element ," set to autowater" print " Check Water duration ", durationwater ,">", minwaterduration if durationwater>minwaterduration: # watering time above the set threshold print " OK Water duration " if statusdataDBmod.read_status_data(AUTO_data,element,"tobeactivated"): #if flag is ON print " Activate ", element durationfer=statusdataDBmod.read_status_data(AUTO_data,element,"duration") activatedoser(element,durationfer) time.sleep(durationfer) #this blocks the system (and watering activation) for n seconds ... not best practice else: print " No pending request to activate ", element
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 gpio_pin_level(cmd, message, recdata): msgarray=message.split(":") PIN=msgarray[1] address=msgarray[2] if address=="": address="0x20" recdata.append(msgarray[0]) PINlevel=statusdataDBmod.read_status_data(GPIO_data,address+PIN,"level") if PINlevel is not None: recdata.append(str(PINlevel)) return True else: recdata.append("e") return False
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 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 sendcommand(cmd, sendstring, recdata, target="", priority=0): if target != "": prioritystatus = statusdataDBmod.read_status_data( Blocking_Status, target, 'priority') #print " Target output ", target , "priority status: ", prioritystatus , " Command Priority: ", priority #check if the actions are blocked if priority >= prioritystatus: return HWcontrol.sendcommand(cmd, sendstring, recdata) else: successflag = 0 recdata.append(cmd) recdata.append("blocked") recdata.append(successflag) return True else: return HWcontrol.sendcommand(cmd, sendstring, recdata)
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 MQTT_stoppulse( cmd, message, recdata ): # when ON send MQTT message with the duration in seconds of the activation, and when OFF send zero. print(" Don't stop me now ") msgarray = message.split(":") messagelen = len(msgarray) PIN = msgarray[1] logic = "pos" if messagelen > 3: logic = msgarray[3] POWERPIN = "" if messagelen > 4: POWERPIN = msgarray[4] address = "" # this is the MQTT client ID if messagelen > 7: address = msgarray[7] title = "" if messagelen > 8: title = msgarray[8] if title == "": print("missing topic") logger.error("No topic specified, please insert it in the Title field") successflag = 0 recdata.append("e") recdata.append(successflag) return recdata MQTT_CMD, MQTT_CMD_PWR = create_pulse_CMD_list(PIN, POWERPIN, title, 0) REGID = MQTT_CMD["ID"] PINthreadID = statusdataDBmod.read_status_data(GPIO_data, REGID, "threadID") if not PINthreadID == None: #print "cancel the Thread of PIN=",PIN PINthreadID.cancel() endpulse(MQTT_CMD, MQTT_CMD_PWR, address) #this also put powerpin off recdata.append(cmd) recdata.append(PIN) 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 isPinActive(address, PIN, logic): PINlevel=statusdataDBmod.read_status_data(GPIO_data,address+PIN,"level") #print " pin Level" , PINlevel if PINlevel is not None: isok=True else: return False if isok: if logic=="neg": if PINlevel: # pinlevel is integer 1 or zero activated=False else: activated=True elif logic=="pos": if PINlevel: activated=True else: activated=False return activated
def gpio_stoppulse(cmd, message, recdata): msgarray=message.split(":") messagelen=len(msgarray) PIN=msgarray[1] 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" if not isPinActive(address,PIN,logic): print("No Action, Already OFF") logger.warning("No Action, Already OFF") successflag=1 recdata.append(cmd) recdata.append(PIN) recdata.append(successflag) return True PINthreadID=statusdataDBmod.read_status_data(GPIO_data,address+PIN,"threadID") if not PINthreadID==None: #print "cancel the Thread of PIN=",PIN PINthreadID.cancel() endpulse(address, PIN,logic,POWERPIN) #this also put powerpin off recdata.append(cmd) recdata.append(PIN) return True
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 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 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 getservoduty(element): return statusdataDBmod.read_status_data(Servo_Status, element, 'duty')
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 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 MQTT_pulse(cmd, message, recdata): successflag = 0 msgarray = message.split(":") messagelen = len(msgarray) PIN = msgarray[1] testpulsetime = msgarray[2] # in seconds pulsesecond = int(testpulsetime) POWERPIN = "" if messagelen > 4: POWERPIN = msgarray[4] activationmode = "" if messagelen > 7: activationmode = msgarray[7] address = "" # this is the MQTT client ID if messagelen > 8: address = msgarray[8] title = "" if messagelen > 9: title = msgarray[9] if title == "": print("missing topic") logger.error("No topic specified, please insert it in the Title field") successflag = 0 recdata.append("e") recdata.append(successflag) recdata.append("Missing MQTT topic") return recdata MQTT_CMD, MQTT_CMD_PWR = create_pulse_CMD_list(PIN, POWERPIN, title, pulsesecond) # start pulse activation logic REGID = MQTT_CMD["ID"] ignorepowerpincount = False # in case another timer is active on this TOPIC ID it means that the PIN is activated PINthreadID = statusdataDBmod.read_status_data(GPIO_data, REGID, "threadID") if not PINthreadID == None: # pin already active if activationmode == "NOADD": # no action needed successflag = 1 recdata.append(cmd) recdata.append(PIN) recdata.append(successflag) return True PINthreadID.cancel() # cancel thread ignorepowerpincount = True # do not add levels to the powerpin powerPIN_start(MQTT_CMD_PWR["ID"], MQTT_CMD_PWR["START"], address, pulsesecond, ignorepowerpincount) level = 1 statusdataDBmod.write_status_data(GPIO_data, REGID, "level", level) logger.info("Set PIN=%s to State=%s", REGID, str(level)) print(REGID + " *********************************************** ", level) MQTT_output(MQTT_CMD["START"], address) NewPINthreadID = threading.Timer(pulsesecond, endpulse, [MQTT_CMD, MQTT_CMD_PWR, address]) NewPINthreadID.start() statusdataDBmod.write_status_data(GPIO_data, REGID, "threadID", NewPINthreadID) successflag = 1 recdata.append(cmd) recdata.append(PIN) recdata.append(successflag) return True
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 readstatus(element, item): return statusdataDBmod.read_status_data(AUTO_data, element, item)
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 getstepperposition(element): return statusdataDBmod.read_status_data(Stepper_Status, element, 'position', True, "Stepper_Status")
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 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