def startpump(target, activationseconds, MinAveragetemp, MaxAverageHumid): logger.info('WateringPlan Startpump evaluation: %s', target) #workmode=autowateringmod.checkworkmode(target) #if workmode=="Full Auto": if target in autowateringmod.allowwateringplan: if not autowateringmod.allowwateringplan[target]: logger.info( 'WateringPlan: %s pump activation blocked by automation', target) pumpit = False return False duration = hardwaremod.toint(activationseconds, 0) print(target, " ", duration, " ", datetime.now()) # evaluate parameters #MinAverageLight=500 not used now MinutesOfAverage = 120 #minutes in which the average data is calculated from sensor sampling print("waterpump check") logger.info('execute water pump check %s', datetime.now().strftime("%Y-%m-%d %H:%M:%S")) # then check the temperature and Humidity print("Check Humidity and Temperature") MinAveragetempnum = hardwaremod.tonumber(MinAveragetemp, "NA") MaxAverageHumidnum = hardwaremod.tonumber(MaxAverageHumid, "NA") # all the below conditions should be verified to start the PUMP pumpit = True hsensornamelist = hardwaremod.getsensornamebymeasure( hardwaremod.MEASURELIST[1]) if hsensornamelist: sensordata = [] hsensorname = hsensornamelist[0] # get first found sensor in the list sensordbmod.getsensordbdata(hsensorname, sensordata) starttimecalc = datetime.now() - timedelta( minutes=int(MinutesOfAverage)) isok, quantitylist = sensordbmod.EvaluateDataPeriod( sensordata, starttimecalc, datetime.now()) humquantity = quantitylist["average"] logger.info( 'Waterpump Check parameter if humquantity=%s < MaxAverageHumid=%s ', str(humquantity), str(MaxAverageHumid)) print('Waterpump Check parameter if humquantity=', humquantity, ' < MaxAverageHumid=', MaxAverageHumid) if (MaxAverageHumidnum != "NA"): if (humquantity < MaxAverageHumidnum): logger.info( 'Humidity check PASSED, humquantity=%s < MaxAverageHumid=%s ', str(humquantity), str(MaxAverageHumid)) else: logger.info('Humidity check FAILED') print('Humidity check FAILED') pumpit = False tsensornamelist = hardwaremod.getsensornamebymeasure( hardwaremod.MEASURELIST[0]) if tsensornamelist: sensordata = [] tsensorname = tsensornamelist[0] # get first found sensor in the list sensordbmod.getsensordbdata(tsensorname, sensordata) starttimecalc = datetime.now() - timedelta( minutes=int(MinutesOfAverage)) isok, quantitylist = sensordbmod.EvaluateDataPeriod( sensordata, starttimecalc, datetime.now()) tempquantity = quantitylist["average"] logger.info( 'Waterpump Check parameter if tempquantity=%s > MinAveragetemp=%s ', str(tempquantity), str(MinAveragetemp)) print('Waterpump Check parameter if tempquantity=', tempquantity, ' > MinAveragetemp=', MinAveragetemp) if (MinAveragetempnum != "NA"): if (tempquantity > MinAveragetempnum): logger.info( 'Temperature check PASSED, tempquantity=%s > MinAveragetemp=%s ', str(tempquantity), str(MinAveragetemp)) else: logger.info('Temperature check FAILED') print('Temperature check FAILED') pumpit = False # weather Forecast sensorname = weatherAPImod.DefaultCounterName() sensorlist = sensordbmod.gettablelist() if sensorname in sensorlist: ActiveActuatorList = weatherAPImod.ActiveActuatorList() if target in ActiveActuatorList: sensordata = [] samplesnumber = 1 sensordbmod.getsensordbdatasamplesN(sensorname, sensordata, samplesnumber) MaxPastMinutes = 1200 starttimecalc = datetime.now() - timedelta(minutes=MaxPastMinutes) isok, quantitylist = sensordbmod.EvaluateDataPeriod( sensordata, starttimecalc, datetime.now()) if isok: RainMultipier = quantitylist["average"] logger.info('Waterpump weather multiplier =%s ', str(RainMultipier)) else: logger.warning( 'Waterpump weather multiplier NOT found within 20 Hours apply 100 ' ) RainMultipier = 100 duration = int(duration * RainMultipier / 100) else: logger.warning('Weather Sensor not found, no multpilier applied ') if pumpit: # activation of the doser before the pump doseron = autofertilizermod.checkactivate(target, duration) # watering #hardwaremod.makepulse(target,duration) activateandregister(target, duration) # salva su database #logger.info('Switch Pump %s ON, optional time for sec = %s', target, duration) #print 'Pump ON, optional time for sec =', duration #actuatordbmod.insertdataintable(target,duration) return True
def mastercallback(): # clean old data of the database (pastdays) pastdays = 364 sensordbmod.RemoveSensorDataPeriod(pastdays) actuatordbmod.RemoveActuatorDataPeriod(pastdays) hardwaremod.removephotodataperiod(364) # remove all jobs except masterscheduler for job in SchedulerMod.sched.get_jobs(): if job.name != "master": try: job.remove() except: logger.error('Not able to remove Job %s', job.name) # set the individual callback of the day # info file dedicate call-back --------------------------------------------- (heartbeat) #this callback is used only for system status periodic check calltype = "periodic" global HEARTBEATINTERVAL interval = HEARTBEATINTERVAL timelist = [0, interval, 900] # 900 indicates to start after 15 minutes callback = "heartbeat" argument = [] setschedulercallback(calltype, timelist, argument, callback, callback) # info file dedicate call-back --------------------------------------------- (sensor) hwnamelist = sensordbmod.gettablelist() callback = "sensor" timeshift = 300 shiftstep = 2 #seconds for hwname in hwnamelist: calltype = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, hwname, hardwaremod.HW_FUNC_SCHEDTYPE) timelist = hardwaremod.gettimedata(hwname) timelist[2] = timelist[ 2] + timeshift # avoid all the sensor thread to be called in the same time argument = [] argument.append(hwname) setschedulercallback(calltype, timelist, argument, callback, hwname) timeshift = timeshift + shiftstep #<------> # info file dedicate quinto call-back ----------------------------------(takephoto) usedfor = "photocontrol" callback = "photo" hwnamelist = hardwaremod.searchdatalist(hardwaremod.HW_FUNC_USEDFOR, usedfor, hardwaremod.HW_INFO_NAME) for hwname in hwnamelist: calltype = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, hwname, hardwaremod.HW_FUNC_SCHEDTYPE) timelist = hardwaremod.gettimedata(hwname) argument = [] argument.append(hwname) setschedulercallback(calltype, timelist, argument, callback, hwname) # info ne file dedicate quarto call-back ---------------------------------------(sendmail) usedfor = "mailcontrol" callback = "mail" hwnamelist = hardwaremod.searchdatalist(hardwaremod.HW_FUNC_USEDFOR, usedfor, hardwaremod.HW_INFO_NAME) for hwname in hwnamelist: calltype = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, hwname, hardwaremod.HW_FUNC_SCHEDTYPE) timelist = hardwaremod.gettimedata(hwname) argument = [] argument.append(hwname) setschedulercallback(calltype, timelist, argument, callback, hwname) # info ne file dedicate quinto call-back ---------------------------------------(lightcheck) # empty #<----> # info file dedicate call-back ------------------------------------------------ (waterpump) callback = "waterpump" #water schedule table paramlist = wateringdbmod.getparamlist() # name of the months ordered elementlist = wateringdbmod.getelementlist( ) # pump ordered (based on "watercontrol" field) table = wateringdbmod.gettable( 1 ) # table, each row is a pump, each column is a month, value is watering time multiplieer table1 = wateringdbmod.gettable( 0 ) # table, each row is a pump, each column is a month, value is watering scheme table2 = wateringdbmod.gettable( 2 ) # table, each row is a pump, each column is a month, value is time delay #print paramlist #print elementlistly #print table paramlistdrop = advancedmod.getparamlist() # day of the week elementlistdrop = advancedmod.getelementlist() # drops ordered tabledrop = advancedmod.gettable( ) # table, each row is a schema number (drop number), each column is a weekday for pumpnumber in range(len(elementlist)): #print "number =",pumpnumber pumpname = elementlist[pumpnumber] todaydate = date.today() # Monday is 0 and Sunday is 6 weekday = todaydate.weekday() month = todaydate.month try: waterschemanumber = table1[pumpnumber][month - 1] waterdropnumber = hardwaremod.toint(table[pumpnumber][month - 1], 0) watertimedelaysec = hardwaremod.toint( table2[pumpnumber][month - 1], 0) except IndexError: print "EXCEPTION: index out of range" waterdropnumber = 0 watertimedelaysec = 0 if waterdropnumber > 0: #print " month " , month, " drop " , waterdropnumber calltype = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, pumpname, hardwaremod.HW_FUNC_SCHEDTYPE) for todayevent in tabledrop[waterschemanumber - 1][weekday]: timelist = hardwaremod.separatetimestringint(todayevent[0]) timelist[2] = timelist[2] + watertimedelaysec argument = [] argument.append(pumpname) durationinseconds = hardwaremod.toint(todayevent[1], 0) * waterdropnumber argument.append(durationinseconds) for i in range(2, len(todayevent)): argument.append(todayevent[i]) if durationinseconds > 0: #check if the duration in second is >0 setschedulercallback(calltype, timelist, argument, callback, pumpname) # info file dedicate call-back ------------------------------------------------ (pulsenutrient) callback = "doser" #fertilizer schedule table paramlist = fertilizerdbmod.getparamlist() # name of the months ordered elementlist = fertilizerdbmod.getelementlist( ) # element with "fertilizercontrol field" ordered table = fertilizerdbmod.gettable( 1 ) # table, each row is a doser, each column is a month, value is number of times in a month table1 = fertilizerdbmod.gettable( 0 ) # table, each row is a doser, each column is a month, value is pulse seconds for dosernumber in range(len(elementlist)): #print "number =",dosernumber dosername = elementlist[dosernumber] calltype = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, dosername, hardwaremod.HW_FUNC_SCHEDTYPE) todaydate = date.today() # Monday is 0 and Sunday is 6 year = todaydate.year month = todaydate.month day = todaydate.day fertilizerpulsenumber = hardwaremod.toint( table[dosernumber][month - 1], 0) fertilizerpulsesecond = hardwaremod.toint( table1[dosernumber][month - 1], 0) if (fertilizerpulsenumber > 0) and (fertilizerpulsesecond > 0): themonthdays = 30 #approximate number of days in a month dayinterval = themonthdays / fertilizerpulsenumber halfinterval = (dayinterval + 1) / 2 print "day=", day, " dayinterval=", dayinterval, " half=", halfinterval if ((day + int(halfinterval)) % int(dayinterval)) == 0: timelist = hardwaremod.gettimedata("06:00:00") argument = [] argument.append(dosername) argument.append(fertilizerpulsesecond) if (fertilizerpulsesecond ) > 0: #check if the duration in second is >0 setschedulercallback(calltype, timelist, argument, callback, dosername)
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 mastercallback(): # clean old data of the database (pastdays) logger.info('Remove data in exceed of one year') pastdays=364 #sensordbmod.RemoveSensorDataPeriod(pastdays) logger.info('Sensor Remove data in exceed of one year') #actuatordbmod.RemoveActuatorDataPeriod(pastdays) logger.info('Actuator Remove data in exceed of one year') #hardwaremod.removephotodataperiod(364) logger.info('Photo Remove data in exceed of one year') logger.info('Start other scheduler activities') # remove all jobs except masterscheduler #for job in SchedulerMod.sched.get_jobs(): # if job.name != "master": # try: # job.remove() # except: # logger.error('Not able to remove Job %s', job.name) # set the individual callback of the day # info file dedicate call-back --------------------------------------------- (heartbeat) #this callback is used only for system status periodic check calltype="periodic" global HEARTBEATINTERVAL interval=HEARTBEATINTERVAL timelist=[0,interval,900] # 900 indicates to start after 15 minutes callback="heartbeat" argument=[] setschedulercallback(calltype,timelist,argument,callback,callback) logger.info('Start other scheduler activities - sensor') # info file dedicate call-back --------------------------------------------- (sensor) hwnamelist=sensordbmod.gettablelist() callback="sensor" timeshift=300 shiftstep=5 #seconds # IMPORTANT # the shiftstep is necessary to avoid thread collision which brings to sqlite3 db failure "database is locked" # this number is giving a limit to the sensor reading that should be higher than 1min for hwname in hwnamelist: calltype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_FUNC_SCHEDTYPE) timelist=hardwaremod.gettimedata(hwname) timelist[2]=timeshift # avoid all the sensor thread to be called in the same time argument=[] argument.append(hwname) setschedulercallback(calltype,timelist,argument,callback,hwname) timeshift=timeshift+shiftstep logger.info('Start other scheduler activities - photo') #<------> # info file dedicate quinto call-back ----------------------------------(takephoto) usedfor="photocontrol" callback="photo" hwnamelist=hardwaremod.searchdatalist(hardwaremod.HW_FUNC_USEDFOR,usedfor,hardwaremod.HW_INFO_NAME) for hwname in hwnamelist: calltype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_FUNC_SCHEDTYPE) timelist=hardwaremod.gettimedata(hwname) argument=[] argument.append(hwname) setschedulercallback(calltype,timelist,argument,callback,hwname) logger.info('Start other scheduler activities - mail') # info ne file dedicate quarto call-back ---------------------------------------(sendmail) usedfor="mailcontrol" callback="mail" hwnamelist=hardwaremod.searchdatalist(hardwaremod.HW_FUNC_USEDFOR,usedfor,hardwaremod.HW_INFO_NAME) for hwname in hwnamelist: calltype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_FUNC_SCHEDTYPE) timelist=hardwaremod.gettimedata(hwname) argument=[] argument.append(hwname) setschedulercallback(calltype,timelist,argument,callback,hwname) # info ne file dedicate quinto call-back ---------------------------------------(lightcheck) # empty #<----> logger.info('Start other scheduler activities - pump') # info file dedicate call-back ------------------------------------------------ (waterpump) callback="waterpump" #water schedule table paramlist= wateringdbmod.getparamlist() # name of the months ordered elementlist= wateringdbmod.getelementlist() # pump ordered (based on "watercontrol" field) table=wateringdbmod.gettable(1)# table, each row is a pump, each column is a month, value is watering time multiplieer table1=wateringdbmod.gettable(0)# table, each row is a pump, each column is a month, value is watering scheme table2=wateringdbmod.gettable(2)# table, each row is a pump, each column is a month, value is time delay #print paramlist #print elementlistly #print table paramlistdrop= advancedmod.getparamlist() # day of the week elementlistdrop= advancedmod.getelementlist() # drops ordered tabledrop=advancedmod.gettable() # table, each row is a schema number (drop number), each column is a weekday for pumpnumber in range(len(elementlist)): #print "number =",pumpnumber pumpname=elementlist[pumpnumber] todaydate = date.today() # Monday is 0 and Sunday is 6 weekday = todaydate.weekday() month = todaydate.month try: waterschemanumber=table1[pumpnumber][month-1] waterdropnumber=hardwaremod.toint(table[pumpnumber][month-1],0) watertimedelaysec=hardwaremod.toint(table2[pumpnumber][month-1],0) except IndexError: print "EXCEPTION: index out of range" waterdropnumber=0 watertimedelaysec=0 if waterdropnumber>0: #print " month " , month, " drop " , waterdropnumber calltype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,pumpname,hardwaremod.HW_FUNC_SCHEDTYPE) for todayevent in tabledrop[waterschemanumber-1][weekday]: timelist=hardwaremod.separatetimestringint(todayevent[0]) timelist[2]=timelist[2]+watertimedelaysec argument=[] argument.append(pumpname) durationinseconds=hardwaremod.toint(todayevent[1],0)*waterdropnumber argument.append(durationinseconds) for i in range(2,len(todayevent)): argument.append(todayevent[i]) if durationinseconds>0: #check if the duration in second is >0 setschedulercallback(calltype,timelist,argument,callback,pumpname) logger.info('Start other scheduler activities - doser') # info file dedicate call-back ------------------------------------------------ (pulsenutrient) callback="doser" #fertilizer schedule table paramlist= fertilizerdbmod.getparamlist() # name of the months ordered elementlist= fertilizerdbmod.getelementlist() # element with "fertilizercontrol field" ordered table=fertilizerdbmod.gettable(1)# table, each row is a doser, each column is a month, value is number of times in a month table1=fertilizerdbmod.gettable(0)# table, each row is a doser, each column is a month, value is pulse seconds for dosernumber in range(len(elementlist)): #print "number =",dosernumber dosername=elementlist[dosernumber] calltype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,dosername,hardwaremod.HW_FUNC_SCHEDTYPE) todaydate = date.today() # Monday is 0 and Sunday is 6 year = todaydate.year month = todaydate.month day = todaydate.day fertilizerpulsenumber=hardwaremod.toint(table[dosernumber][month-1],0) fertilizerpulsesecond=hardwaremod.toint(table1[dosernumber][month-1],0) if (fertilizerpulsenumber>0) and (fertilizerpulsesecond>0): themonthdays=30 #approximate number of days in a month dayinterval=themonthdays/fertilizerpulsenumber halfinterval=(dayinterval+1)/2 print "day=" , day , " dayinterval=", dayinterval, " half=", halfinterval if ((day+int(halfinterval)) % int(dayinterval)) == 0: #timelist=hardwaremod.gettimedata("06:00:00") timelist=autofertilizermod.timelist(dosername) argument=[] argument.append(dosername) argument.append(fertilizerpulsesecond) if (fertilizerpulsesecond)>0: #check if the duration in second is >0 setschedulercallback(calltype,timelist,argument,callback,dosername) logger.info('Start other scheduler activities - finish') return True
def startpump(target,activationseconds,ThesholdOFFON,ThesholdONOFF): logger.info('WateringPlan Startpump evaluation: %s', target) #workmode=autowateringmod.checkworkmode(target) #if workmode=="Full Auto": if target in autowateringmod.allowwateringplan: if not autowateringmod.allowwateringplan[target]: logger.info('WateringPlan: %s pump activation blocked by automation', target) pumpit=False return False duration=hardwaremod.toint(activationseconds,0) print(target, " ",duration, " " , datetime.now()) print("waterpump check") logger.info('execute water pump check %s', datetime.now().strftime("%Y-%m-%d %H:%M:%S")) # evaluate parameters MinutesOfAverage=hardwaremod.toint(wateringplansensordbmod.getselduration(),120) #minutes in which the average data is calculated from sensor sampling tsensornamelist, hsensornamelist=wateringplansensordbmod.getactivesensor() valid1, passed1 = checksensorcondition(tsensornamelist,ThesholdOFFON, MinutesOfAverage, False) valid2, passed2 = checksensorcondition(hsensornamelist,ThesholdONOFF, MinutesOfAverage, True) # apply AND or OR condition condition=wateringplansensordbmod.getselcondition() # "AND" , "OR" pumpit=True if valid1 and valid2: if condition=="AND": pumpit=passed1 and passed2 elif condition=="OR": pumpit=passed1 or passed2 else: if valid1: pumpit=passed1 if valid2: pumpit=passed2 print('valid1= ' , valid1 , 'valid2= ' , valid2) print('passed1= ' , passed1 , 'passed2= ' , passed2) print('pumpit= ' , pumpit, 'condition= ' , condition) logger.info('Condition for activation =%s ', pumpit) # weather Forecast sensorname=weatherAPImod.DefaultCounterName() sensorlist=sensordbmod.gettablelist() if sensorname in sensorlist: ActiveActuatorList=weatherAPImod.ActiveActuatorList() if target in ActiveActuatorList: sensordata=[] samplesnumber=1 sensordbmod.getsensordbdatasamplesN(sensorname,sensordata,samplesnumber) MaxPastMinutes=1200 starttimecalc=datetime.now()-timedelta(minutes=MaxPastMinutes) isok , quantitylist=sensordbmod.EvaluateDataPeriod(sensordata,starttimecalc,datetime.now()) if isok: RainMultipier=quantitylist["average"] logger.info('Waterpump weather multiplier =%s ', str(RainMultipier)) else: logger.warning('Waterpump weather multiplier NOT found within 20 Hours apply 100 ') RainMultipier=100 duration=int(duration*RainMultipier/100) else: logger.warning('Weather Sensor not found, no multpilier applied ') if pumpit: # activation of the doser before the pump doseron=autofertilizermod.checkactivate(target,duration) # watering #hardwaremod.makepulse(target,duration) activateandregister(target,duration) # salva su database #logger.info('Switch Pump %s ON, optional time for sec = %s', target, duration) #print 'Pump ON, optional time for sec =', duration #actuatordbmod.insertdataintable(target,duration) 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