def sensorsysinfomatrix(): # first row includes headers matrix=[] row=[] row.append("Name") row.append("Use") row.append("Unit") row.append("Average 24H") matrix.append(row) namelist=hardwaremod.searchdatalist(hardwaremod.HW_CTRL_CMD,"pulse",hardwaremod.HW_INFO_NAME) for name in namelist: row=[] row.append(name) row.append(hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,name,hardwaremod.HW_FUNC_USEDFOR)) row.append(hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,name,hardwaremod.HW_INFO_MEASUREUNIT)) endtime=datetime.now() starttime= endtime - timedelta(days=1) data=[] getActuatordbdata(name,data) evaluateddata=EvaluateDataPeriod(data,starttime,endtime) #set date interval for average row.append(str('%.1f' % (evaluateddata["sum"]/1000))) matrix.append(row) return matrix
def checkstopcondition(element): print "Evaluating End of Blocking period ++++++++++++" actionmodeafterfirst = interruptdbmod.searchdata("element", element, "actionmode_afterfirst") print actionmodeafterfirst if actionmodeafterfirst == "Extend blocking state" or actionmodeafterfirst == "Extend and Follo-up": # extend only the pre-emption blocking period, no action seonsormode = interruptdbmod.searchdata("element", element, "sensor_mode") print seonsormode if seonsormode == "Edge + Level": sensor = interruptdbmod.searchdata("element", element, "sensor") recordkey = hardwaremod.HW_INFO_NAME recordvalue = sensor keytosearch = hardwaremod.HW_CTRL_PIN PIN = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) reading = hardwaremod.readinputpin(PIN) keytosearch = hardwaremod.HW_CTRL_LOGIC logic = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) # pin high according to the set logic print "logic:", logic, " reading:", reading if logic == "pos" and reading == "1": return False if logic == "neg" and reading == "0": return False return True
def sensorsysinfomatrix(): # first row includes headers matrix = [] row = [] row.append("Name") row.append("Use") row.append("Unit") row.append("Average 24H") matrix.append(row) namelist = hardwaremod.searchdatalist(hardwaremod.HW_CTRL_CMD, "pulse", hardwaremod.HW_INFO_NAME) for name in namelist: row = [] row.append(name) row.append( hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, name, hardwaremod.HW_FUNC_USEDFOR)) row.append( hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, name, hardwaremod.HW_INFO_MEASUREUNIT)) endtime = datetime.now() starttime = endtime - timedelta(days=1) data = [] getActuatordbdata(name, data) isok, evaluateddata = EvaluateDataPeriod( data, starttime, endtime) #set date interval for average row.append(str('%.1f' % (evaluateddata["sum"]))) matrix.append(row) return matrix
def sensorsysinfomatrix(): # first row includes headers matrix = [] row = [] row.append("Sensor Name") row.append("Measure") row.append("Unit") row.append("Average 24H") row.append("Min 24H") row.append("Max 24H") matrix.append(row) namelist = gettablelist() for name in namelist: row = [] row.append(name) row.append( hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, name, hardwaremod.HW_INFO_MEASURE)) row.append( hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, name, hardwaremod.HW_INFO_MEASUREUNIT)) sensordata = [] getsensordbdatadays(name, sensordata, 1) #set date interval for average endtime = datetime.now() starttime = endtime - timedelta(days=1) evaluateddata = EvaluateDataPeriod(sensordata, starttime, endtime) row.append(str('%.1f' % evaluateddata["average"])) row.append(str('%.1f' % evaluateddata["min"])) row.append(str('%.1f' % evaluateddata["max"])) matrix.append(row) return matrix
def checkstopcondition(element): #print "Evaluating End of Blocking period ++++++++++++" actionmodeafterfirst=interruptdbmod.searchdata("element",element,"actionmode_afterfirst") #print "actionafter " , actionmodeafterfirst sensor=interruptdbmod.searchdata("element",element,"sensor") if actionmodeafterfirst=="Extend blocking state" or actionmodeafterfirst=="Extend and Follow-up": # extend the pre-emption blocking period seonsormode=interruptdbmod.searchdata("element",element,"sensor_mode") #print "SENSORMODE" , seonsormode recordkey=hardwaremod.HW_INFO_NAME recordvalue=sensor keytosearch=hardwaremod.HW_CTRL_PIN PIN=hardwaremod.searchdata(recordkey,recordvalue,keytosearch) reading=hardwaremod.readinputpin(PIN) if seonsormode=="First Edge + Level": keytosearch=hardwaremod.HW_CTRL_LOGIC logic=hardwaremod.searchdata(recordkey,recordvalue,keytosearch) # pin high according to the set logic #print "logic:", logic , " reading:" ,reading if (logic=="pos" and reading=="1")or(logic=="neg" and reading=="0"): return False elif seonsormode=="Second Edge + Level (inv)": keytosearch=hardwaremod.HW_CTRL_LOGIC logic=hardwaremod.searchdata(recordkey,recordvalue,keytosearch) #pin LOW according to the set logic #print "logic:", logic , " reading:" ,reading if (logic=="pos" and reading=="0")or(logic=="neg" and reading=="1"): return False return True
def sendmail(hwname,mailtype,intromessage,bodytextlist=[]): address=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_CTRL_ADDR) if not address=="": print "mail recipient ", address title=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_CTRL_TITLE) print "mail title " , title cmd=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_CTRL_CMD) print "mail type " , cmd issent=send_email_main(address,title,cmd,mailtype,intromessage,bodytextlist) return issent else: print "No address specified" logger.warning('No address specified') return False
def sendmail(hwname,mailtype,intromessage,bodytextlist=[]): address=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_CTRL_MAILADDR) if not address=="": print "mail recipient ", address title=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_CTRL_MAILTITLE) print "mail title " , title cmd=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,hwname,hardwaremod.HW_CTRL_CMD) print "mail type " , cmd issent=send_email_main(address,title,cmd,mailtype,intromessage,bodytextlist) return issent else: print "No address specified" logger.error('No address specified') return False
def activateactuator(target, value): # return true in case the state change: activation is >0 or a different position from prevoius position. # check the actuator isok=False actuatortype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,target,hardwaremod.HW_CTRL_CMD) supportedactuators=["pulse","servo","stepper"] # stepper motor if actuatortype=="stepper": out, isok = hardwaremod.GO_stepper_position(target,value) if isok: actuatordbmod.insertdataintable(target,value) # pulse if actuatortype=="pulse": duration=1000*hardwaremod.toint(value,0) # check the fertilizer doser flag before activating the pulse doseron=autofertilizermod.checkactivate(target,duration) # start pulse pulseok=hardwaremod.makepulse(target,duration) # salva su database if "Started" in pulseok: actuatordbmod.insertdataintable(target,duration) isok=True # servo motor if actuatortype=="servo": out, isok = hardwaremod.servoangle(target,value,0.5) if isok: actuatordbmod.insertdataintable(target,value) return isok
def activateactuator( target, value ): # return true in case the state change: activation is >0 or a different position from prevoius position. # check the actuator isok = False actuatortype = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, target, hardwaremod.HW_CTRL_CMD) supportedactuators = ["pulse", "servo", "stepper"] # stepper motor if actuatortype == "stepper": out, isok = hardwaremod.GO_stepper_position(target, value) if isok: actuatordbmod.insertdataintable(target, value) # pulse if actuatortype == "pulse": duration = 1000 * hardwaremod.toint(value, 0) # check the fertilizer doser flag before activating the pulse doseron = autofertilizermod.checkactivate(element, duration) # start pulse pulseok = hardwaremod.makepulse(target, duration) # salva su database if "Started" in pulseok: actuatordbmod.insertdataintable(target, duration) isok = True # servo motor if actuatortype == "servo": out, isok = hardwaremod.servoangle(target, value, 0.5) if isok: actuatordbmod.insertdataintable(target, value) return isok
def activateactuator(target, value): # return true in case the state change: activation is >0 or a different position from prevoius position. # check the actuator isok=False actuatortype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,target,hardwaremod.HW_CTRL_CMD) actuatortypelist=actuatortype.split("/") if actuatortypelist: actuatortype=actuatortypelist[0] print (" Automation Actuator " + actuatortype + " target " + target) supportedactuators=["pulse","servo","stepper"] # stepper motor if actuatortype=="stepper": out, isok = hardwaremod.GO_stepper_position(target,value) if isok: actuatordbmod.insertdataintable(target,value) # hbridge motor if actuatortype=="hbridge": out, isok = hardwaremod.GO_hbridge_position(target,value) if isok: actuatordbmod.insertdataintable(target,value) # pulse if actuatortype=="pulse": duration=hardwaremod.toint(value,0) # check the fertilizer doser flag before activating the pulse doseron=autofertilizermod.checkactivate(target,duration) # start pulse pulseok=hardwaremod.makepulse(target,duration) # salva su database if "Started" in pulseok: actuatordbmod.insertdataintable(target,duration) isok=True # servo motor if actuatortype=="servo": out, isok = hardwaremod.servoangle(target,value,0.5) if isok: actuatordbmod.insertdataintable(target,value) # photo if actuatortype=="photo": duration=hardwaremod.toint(value,0) if duration>0: isok=hardwaremod.takephoto(True) # save action in database if isok: actuatordbmod.insertdataintable(target,1) # mail if (actuatortype=="mail+info+link")or(actuatortype=="mail+info"): if value>0: mailtext=str(value) isok=emailmod.sendmail(target,"info","Automation Value:" + mailtext) # save action in database if isok: actuatordbmod.insertdataintable(target,1) return isok
def activateactuator(target, value): # return true in case the state change: activation is >0 or a different position from prevoius position. # check the actuator isok=False actuatortype=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,target,hardwaremod.HW_CTRL_CMD) supportedactuators=["pulse","servo","stepper"] # stepper motor if actuatortype=="stepper": out, isok = hardwaremod.GO_stepper_position(target,value,priority=ACTIONPRIORITYLEVEL) if isok: actuatordbmod.insertdataintable(target,value) # hbridge motor if actuatortype=="hbridge": out, isok = hardwaremod.GO_hbridge_position(target,value) if isok: actuatordbmod.insertdataintable(target,value) # pulse if actuatortype=="pulse": duration=hardwaremod.toint(value,0) if duration>0: # check the fertilizer doser flag before activating the pulse doseron=autofertilizermod.checkactivate(target,duration) # start pulse pulseok=hardwaremod.makepulse(target,duration,priority=ACTIONPRIORITYLEVEL) # salva su database if "Started" in pulseok: actuatordbmod.insertdataintable(target,duration) isok=True else: pulseok=hardwaremod.stoppulse(target) # servo motor if actuatortype=="servo": out, isok = hardwaremod.servoangle(target,value,0.5,priority=ACTIONPRIORITYLEVEL) if isok: actuatordbmod.insertdataintable(target,value) # photo if actuatortype=="photo": duration=hardwaremod.toint(value,0) if duration>0: isok=hardwaremod.takephoto(True) # True override the daily activation # save action in database if isok: actuatordbmod.insertdataintable(target,1) # mail if (actuatortype=="mail+info+link")or(actuatortype=="mail+info"): if value>0: mailtext=str(value) isok=emailmod.sendmail(target,"info","Interrupt Value:" + mailtext) # save action in database if isok: actuatordbmod.insertdataintable(target,1) return isok
def getsensordbdatadays(selsensor, sensordata, days): fieldlist = [] fieldlist.append(TIMEFIELD) fieldlist.append(DATAFIELD) sampletime = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, selsensor, hardwaremod.HW_FUNC_TIME) samplingintervalminutes = int(sampletime.split(":")[1]) samplesnumber = (days * 24 * 60) / samplingintervalminutes databasemod.getdatafromfieldslimit(DBFILENAME, selsensor, fieldlist, sensordata, samplesnumber)
def getsensordbdatadays(selsensor, sensordata, days): fieldlist = [] fieldlist.append(TIMEFIELD) fieldlist.append(DATAFIELD) sampletime = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, selsensor, hardwaremod.HW_FUNC_TIME) schedtype = hardwaremod.searchdata( hardwaremod.HW_INFO_NAME, selsensor, hardwaremod.HW_FUNC_SCHEDTYPE ) # ["oneshot", "periodic"] #scheduling type if (sampletime != "") and (schedtype == "periodic"): samplingintervalminutes = int(sampletime.split(":")[1]) if samplingintervalminutes >= 1: samplesnumber = old_div((days * 24 * 60), samplingintervalminutes) databasemod.getdatafromfieldslimit(DBFILENAME, selsensor, fieldlist, sensordata, samplesnumber) else: databasemod.getdatafromfields(DBFILENAME, selsensor, fieldlist, sensordata) else: databasemod.getdatafromfields(DBFILENAME, selsensor, fieldlist, sensordata)
def setinterruptevents(): hardwaremod.removeallinterruptevents() print "load interrupt list " interruptlist = interruptdbmod.sensorlist() print "len interrupt list ", len(interruptlist) for item in interruptlist: print "got into the loop " # get PIN number recordkey = hardwaremod.HW_INFO_NAME recordvalue = item keytosearch = hardwaremod.HW_CTRL_PIN PINstr = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) print "set event for the PIN ", PINstr PIN = hardwaremod.toint(PINstr, -1) if PIN > -1: keytosearch = hardwaremod.HW_CTRL_LOGIC logic = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) # set Sw pull up / down mode if logic == "pos": hardwaremod.GPIO_setup(PIN, "in", "pull_down") evenslopetype = "both" else: hardwaremod.GPIO_setup(PIN, "in", "pull_up") evenslopetype = "both" #GPIO.RISING, GPIO.FALLING or GPIO.BOTH. # ignoring further edges for 200ms for switch bounce handling # link to the callback function hardwaremod.GPIO_add_event_detect(PIN, evenslopetype, eventcallback) return ""
def eventcallback(PIN): t.sleep(0.05) reading = hardwaremod.readinputpin(PIN) recordkey = hardwaremod.HW_CTRL_PIN recordvalue = str(PIN) keytosearch = hardwaremod.HW_INFO_NAME refsensor = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) print "reference sensor:", refsensor if reading == "1": print "************************* Rising edge detected on PIN:", PIN if refsensor != "": interruptcheck(refsensor) else: print "Falling edge detected on PIN", PIN if refsensor != "": x = threading.Thread(target=savedata, args=(refsensor, reading)) x.start()
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 getsensordbdatadaysV2(selsensor, sensordata, startdate, enddate): # V2 try to optimize access to database fieldlist = [] fieldlist.append(TIMEFIELD) fieldlist.append(DATAFIELD) #sampletime=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,selsensor,hardwaremod.HW_FUNC_TIME) timelist = hardwaremod.gettimedata( selsensor) # return list of int [0] sec, [1] min, [2] hours samplingintervalminutes = timelist[0] * 60 + timelist[1] schedtype = hardwaremod.searchdata( hardwaremod.HW_INFO_NAME, selsensor, hardwaremod.HW_FUNC_SCHEDTYPE ) # ["oneshot", "periodic"] #scheduling type #samplingintervalminutes=hardwaremod.toint(sampletime.split(":")[1],0) # return zero in case of problems if (samplingintervalminutes >= 1) and (schedtype == "periodic"): #minutessperiod=((enddate-startdate).total_seconds()+1 ) // 60 minutessperiod = ((datetime.now() - startdate).total_seconds() + 1) // 60 # sub optima approach # in this case we know the number of samples per day, so we query only the last samples of the database, this makes query way faster samplesnumber = minutessperiod // samplingintervalminutes # WARNING: with offset, there is an issue, every day the system loose some saple at midnight rescheduling only if the sample interval is less than 5 min. # in case of holes in the data sampling, it also provides wrong offset. Decided to use the non optimal approach offset = 0 #lastdata=databasemod.returnrowdatafromfieldslimitV2(DBFILENAME,selsensor,fieldlist,1,0) #if lastdata: # dateref=datetime.strptime(lastdata[0][0].split(".")[0],'%Y-%m-%d %H:%M:%S') # print( " dataref ", dateref , " enddate ", enddate) # if dateref>enddate: # minutessoffset=int( (dateref-enddate).total_seconds() / 60) # dayssoffset=minutessoffset//(24*60) # print ("dayssoffset", dayssoffset , " minutessoffset ", minutessoffset) # offset=int(minutessoffset/samplingintervalminutes) - (dayssoffset*10) # assume to loose max 10 samples per day # samplesnumber=samplesnumber+ 2 * (dayssoffset*10) # allunga il periodo di samples # offset=max(offset,0) # print ("Defined samplesnumber ", samplesnumber , " offset ", offset) print(selsensor, " Get Database Data : samplesnumber ", samplesnumber, " offset ", offset, " Type ", schedtype, "samplingintervalminutes ", samplingintervalminutes) rowdata = databasemod.returnrowdatafromfieldslimitV2( DBFILENAME, selsensor, fieldlist, samplesnumber, offset) #print( " rowdata ", rowdata) else: # no info about number of samples per day try with a number samplingintervalminutes = 5 # assumption #samplesnumber=int(days*24*60/samplingintervalminutes) samplesnumber = 1000 offset = 0 lastitem = 2 dateref = enddate rowdata = [] while (dateref > startdate) and (lastitem > 0): print(selsensor, " Get Database Data : samplesnumber ", samplesnumber, " offset ", offset) partrowdata = databasemod.returnrowdatafromfieldslimitV2( DBFILENAME, selsensor, fieldlist, samplesnumber, offset) lastitem = len(partrowdata) if lastitem >= samplesnumber: offset = offset + lastitem dateref = datetime.strptime( partrowdata[lastitem - 1][0].split(".")[0], '%Y-%m-%d %H:%M:%S') else: lastitem = 0 #print( " dataref ", dateref) #print( " rowdata ", rowdata) print(selsensor, " Get Database Data : dateref ", dateref, " DB part lenght ", lastitem) rowdata.extend(partrowdata) # check the last value of the returned array # return only the data in right datetime interval and in list form (instead of tuple) for data in rowdata: try: dateref = datetime.strptime(data[0].split(".")[0], '%Y-%m-%d %H:%M:%S') if (dateref >= startdate) and (dateref <= enddate): value = float(data[1]) templist = [data[0], value] sensordata.append(templist) except: print("Error in database reading ")
def mastercallback(fromscheduledtime=False): print("master callback") if fromscheduledtime: # check if the time this function is called is the same as the expected time it should be called (solar/legal time might mess with it) logger.info( 'Master scheduler call at scheduled local time, expected time %s', MASTERSCHEDULERTIME) thedateloc = datetime.now() timelist = hardwaremod.separatetimestringint(MASTERSCHEDULERTIME) masterschedtime = thedateloc.replace(hour=timelist[0], minute=timelist[1], second=timelist[2]) secondsdifference = abs((thedateloc - masterschedtime).total_seconds()) logger.info( 'Master scheduler, difference between expected time and local time %d', secondsdifference) if secondsdifference > 300: # more than 5 minutes logger.warning( 'Master scheduler, difference between expected time and local time greater than 5 minutes, RESET MASTER SCHEDULER' ) resetmastercallback() return # clean old data of the database (pastdays) logger.info('Remove data exceeding one year') pastdays = hardwaremod.toint(STOREPASTDAYS, 364) logger.info('Sensor Remove data exceeding one year') sensordbmod.RemoveSensorDataPeriod(pastdays) logger.info('Actuator Remove data exceeding one year') actuatordbmod.RemoveActuatorDataPeriod(pastdays) logger.info('Photo Remove data exceeding one year') hardwaremod.removephotodataperiod(pastdays) else: logger.info('Master scheduler call not coming from scheduler') logger.info('Scheduling main 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 logger.info('Start other scheduler activities - heartbeat') # 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] # 20 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 = hardwaremod.searchdatalist(hardwaremod.HW_INFO_IOTYPE, "input", hardwaremod.HW_INFO_NAME) # GPIO input can be considered at all the aspects a binary input, therefor their stat collection are possible as any other input # the input should be time periodic and time should be more than one minute callback = "sensor" timeshift = 300 # after wifi activation because of possible clock adjustment shiftstep = 7 #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) if calltype == "periodic": #check the input to be periodic 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 else: logger.warning( 'The scheduler for the input %s is not set to PERIODIC, no log record of this input will be taken', hwname) 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 = old_div(themonthdays, fertilizerpulsenumber) halfinterval = old_div((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 interruptexecute(refsensor, element): sensor = refsensor #logger.info('interrupt Pairing OK ---> Actuator: %s , Sensor: %s', element, sensor) 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('Interrupt, Get all the parameters') interrupt_validinterval = hardwaremod.tonumber( interruptdbmod.searchdata("element", element, "interrupt_validinterval"), 0) #"Counter Only" if workmode == "Counter Only": CounterOnlyNew(element, sensor, interrupt_validinterval) return interrupt_triggernumber = hardwaremod.tonumber( interruptdbmod.searchdata("element", element, "interrupt_triggernumber"), 1) actuatoroutput = hardwaremod.tonumber( interruptdbmod.searchdata("element", element, "actuator_output"), 0) actuatoroutputfollowup = hardwaremod.tonumber( interruptdbmod.searchdata("element", element, "folloup_output"), 0) # evaluate variables for operational period check starttime = datetime.strptime( interruptdbmod.searchdata("element", element, "allowedperiod")[0], '%H:%M').time() endtime = datetime.strptime( interruptdbmod.searchdata("element", element, "allowedperiod")[1], '%H:%M').time() # get other parameters seonsormode = interruptdbmod.searchdata("element", element, "sensor_mode") triggermode = interruptdbmod.searchdata("element", element, "trigger_mode") preemptiontimemin = hardwaremod.toint( interruptdbmod.searchdata("element", element, "preemptive_period"), 0) if preemptiontimemin == 0: # if relay, meaning cmd = pulse actuatortype = hardwaremod.searchdata(hardwaremod.HW_INFO_NAME, element, hardwaremod.HW_CTRL_CMD) if actuatortype == "pulse": preemptiontime = actuatoroutput # if set to zero then get the time as the actuator (in case of relay) else: preemptiontime = 0 else: preemptiontime = preemptiontimemin * 60 mailtype = interruptdbmod.searchdata("element", element, "mailalerttype") actionmodeafterfirst = interruptdbmod.searchdata("element", element, "actionmode_afterfirst") # time check # ------------------------ interrupt alghoritm if workmode == "Pre-emptive Blocking": # check if inside the allowed time period #print "Pre-emptive Blocking Mode" #logger.info('Pre-emptive Blocking 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: CheckActivateNotify(element, sensor, preemptiontime, actuatoroutput, actionmodeafterfirst, actuatoroutputfollowup, mailtype, interrupt_triggernumber, interrupt_validinterval, triggermode) else: logger.info('out of allowed operational time') # implment Critical alert message in case the sensor value is one interval more than Max_threshold return
def setinterruptevents(): hardwaremod.removeallinterruptevents() print("load interrupt list ") interruptlist = interruptdbmod.sensorlist() print("len interrupt list ", len(interruptlist)) for item in interruptlist: print("got into the loop ") # get PIN number recordkey = hardwaremod.HW_INFO_NAME recordvalue = item keytosearch = hardwaremod.HW_CTRL_PIN PINstr = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) print("set event for the PIN ", PINstr) if not PINstr == "": keytosearch = hardwaremod.HW_CTRL_LOGIC logic = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) # set Sw pull up / down mode if logic == "pos": hardwaremod.GPIO_setup(PINstr, "in", "pull_down") evenslopetype = "both" else: hardwaremod.GPIO_setup(PINstr, "in", "pull_up") evenslopetype = "both" #GPIO.RISING, GPIO.FALLING or GPIO.BOTH. # link to the callback function # the bouncetime is set by the frequency parameter, if this parameter is empty, the default bouncetime would be 200 keytosearch = hardwaremod.HW_CTRL_FREQ frequency = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) if frequency == "": bouncetimeINT = 200 else: frequencyINT = hardwaremod.toint(frequency, 5) bouncetimeINT = old_div( 1000, frequencyINT ) # in ms. this is ok to be trunk of the int. For frequencies higher than 1000 the bouncetime is exactly zero # RPI.GPIO library does not accept bouncetime=0, it gives runtime error if bouncetimeINT <= 0: bouncetimeINT = 1 #ms hardwaremod.GPIO_add_event_detect(PINstr, evenslopetype, eventcallback, bouncetimeINT) # set fast reference call indexed with the PIN number which is the variable used when interrupt is called: # search now to avoid searching later global PIN_attributes PIN = hardwaremod.toint(PINstr, 0) statusdataDBmod.write_status_data(PIN_attributes, PIN, "logic", logic) recordkey = hardwaremod.HW_CTRL_PIN recordvalue = PINstr keytosearch = hardwaremod.HW_INFO_NAME refsensor = hardwaremod.searchdata( recordkey, recordvalue, keytosearch) # return first occurence statusdataDBmod.write_status_data(PIN_attributes, PIN, "refsensor", refsensor) statusdataDBmod.write_status_data( PIN_attributes, PIN, "bouncetimeSec", 0.4 * float(bouncetimeINT) / 1000) # code below to enable blocking for N sec, it is necessary to trigger the bloccking status in case of levels already present when starting. elementlist = interruptdbmod.getelementlist() #print elementlist for element in elementlist: workmode = checkworkmode(element) if (workmode != "None") and (workmode != ""): sensor = interruptdbmod.searchdata("element", element, "sensor") #saveblockingdiff(sensor) print(" what a sensor ", sensor) if sensor != "": startblockingstate(element, 10, False) t.sleep(0.02) return ""
def setinterruptevents(): hardwaremod.removeallinterruptevents() print "load interrupt list " interruptlist = interruptdbmod.sensorlist() print "len interrupt list ", len(interruptlist) for item in interruptlist: print "got into the loop " # get PIN number recordkey = hardwaremod.HW_INFO_NAME recordvalue = item keytosearch = hardwaremod.HW_CTRL_PIN PINstr = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) print "set event for the PIN ", PINstr if not PINstr == "": keytosearch = hardwaremod.HW_CTRL_LOGIC logic = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) # set Sw pull up / down mode if logic == "pos": hardwaremod.GPIO_setup(PINstr, "in", "pull_down") evenslopetype = "both" else: hardwaremod.GPIO_setup(PINstr, "in", "pull_up") evenslopetype = "both" #GPIO.RISING, GPIO.FALLING or GPIO.BOTH. # link to the callback function # the bouncetime is set by the frequency parameter, if this parameter is empty, the default bouncetime would be 200 keytosearch = hardwaremod.HW_CTRL_FREQ frequency = hardwaremod.searchdata(recordkey, recordvalue, keytosearch) if frequency == "": bouncetimeINT = 200 else: frequencyINT = hardwaremod.toint(frequency, 5) bouncetimeINT = 1000 / frequencyINT # this is ok to be trunk of the int. For frequencies higher than 1000 the bouncetime is exactly zero # RPI.GPIO library does not accept bouncetime=0, it gives runtime error if bouncetimeINT <= 0: bouncetimeINT = 1 hardwaremod.GPIO_add_event_detect(PINstr, evenslopetype, eventcallback, bouncetimeINT) # set fast reference call indexed with the PIN number which is the variable used when interrupt is called: # search now to avoid searching later global PIN_attributes PIN = hardwaremod.toint(PINstr, 0) statusdataDBmod.write_status_data(PIN_attributes, PIN, "logic", logic) recordkey = hardwaremod.HW_CTRL_PIN recordvalue = PINstr keytosearch = hardwaremod.HW_INFO_NAME refsensor = hardwaremod.searchdata( recordkey, recordvalue, keytosearch) # return first occurence statusdataDBmod.write_status_data(PIN_attributes, PIN, "refsensor", refsensor) return ""
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 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 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