def CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue): global AUTO_data # check if time between watering events is larger that the waiting time (minutes) lastactiontime=statusdataDBmod.read_status_data(AUTO_data,element,"lastactiontime") print(' Previous action: ' , lastactiontime , ' Now: ', datetime.utcnow()) timedifference=sensordbmod.timediffinminutes(lastactiontime,datetime.utcnow()) print('Time interval between actions', timedifference ,'. threshold', waitingtime) logger.info('Time interval between Actions %d threshold %d', timedifference,waitingtime) if timedifference>=waitingtime: # sufficient time between actions print(" Sufficient waiting time") logger.info('Sufficient waiting time') # action print("Implement Actuator Value ", value) logger.info('Procedure to start actuator %s, for value = %s', element, value) isok=activateactuator(element, value) # invia mail, considered as info, not as alert if (mailtype!="warningonly")and(mailtype!="none"): textmessage="INFO: " + sensor + " value " + str(sensorvalue) + ", activating:" + element + " with Value " + str(value) emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",value) else: logger.info('Need to wait more time')
def CheckActivateNotify(element, waitingtime, value, mailtype, sensor, sensorvalue): global AUTO_data # check if time between watering events is larger that the waiting time (minutes) print ' Previous action: ', AUTO_data[element][ "lastactiontime"], ' Now: ', datetime.now() timedifference = sensordbmod.timediffinminutes( AUTO_data[element]["lastactiontime"], datetime.now()) print 'Time interval between actions', timedifference, '. threshold', waitingtime logger.info('Time interval between Actions %d threshold %d', timedifference, waitingtime) if timedifference >= waitingtime: # sufficient time between actions print " Sufficient waiting time" logger.info('Sufficient waiting time') # action print "Implement Actuator Value ", value logger.info('Procedure to start actuator %s, for value = %s', element, value) isok = activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype != "warningonly": textmessage = "INFO: " + sensor + " value " + str( sensorvalue ) + ", activating:" + element + " with Value " + str(value) emailmod.sendallmail("alert", textmessage) if isok: AUTO_data[element]["lastactiontime"] = datetime.now() AUTO_data[element]["actionvalue"] = value else: logger.info('Need to wait more time')
def CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue): global AUTO_data # check if time between watering events is larger that the waiting time (minutes) lastactiontime=statusdataDBmod.read_status_data(AUTO_data,element,"lastactiontime") print ' Previous action: ' , lastactiontime , ' Now: ', datetime.now() timedifference=sensordbmod.timediffinminutes(lastactiontime,datetime.now()) print 'Time interval between actions', timedifference ,'. threshold', waitingtime logger.info('Time interval between Actions %d threshold %d', timedifference,waitingtime) if timedifference>=waitingtime: # sufficient time between actions print " Sufficient waiting time" logger.info('Sufficient waiting time') # action print "Implement Actuator Value ", value logger.info('Procedure to start actuator %s, for value = %s', element, value) isok=activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype!="warningonly": textmessage="INFO: " + sensor + " value " + str(sensorvalue) + ", activating:" + element + " with Value " + str(value) emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data,element,"lastactiontime",datetime.now()) statusdataDBmod.write_status_data(AUTO_data,element,"actionvalue",value) else: logger.info('Need to wait more time')
def heartbeat(): print("start heartbeat check", " ", datetime.now()) logger.info('Start heartbeat routine %s', datetime.now().strftime("%Y-%m-%d %H:%M:%S")) # check wifi connection connectedssid = networkmod.connectedssid() connected = False if len(connectedssid) == 0: if not networkmod.WIFIENDIS == "Disabled": logger.warning( 'Heartbeat check , no network connected -------------- try to connect' ) print( 'Heartbeat check , no network connected -------------- try to connect' ) connected = networkmod.connect_network() else: logger.info('Heartbeat check , wifi disabled') else: logger.info('Heartbeat check , Connected Wifi Network: %s ', connectedssid[0]) if connectedssid[0] == networkmod.localwifisystem: logger.info( 'Heartbeat check , Configured as wifi access point, check if possible to connect to wifi network' ) connected = networkmod.connect_network() networkmod.DHCP_COUNTER = 0 else: # Connected to wifi network reachgoogle = networkmod.check_internet_connection(1) if not reachgoogle: logger.warning( 'Heartbeat check wifi SSID ok, but test ping not able to reach Google' ) print('Heartbeat check , no IP connection') #connected=networkmod.connect_network() # use this in case you require the system to try connect wifi again in case no internet is reached #logger.warning('Heartbeat check , DHCP reset counter %s' , str(networkmod.DHCP_COUNTER)) # DHCP reset #if (networkmod.DHCP_COUNTER % 16)==0: # try to reset every 16x15min =4 hours # try to reset DHCP #logger.warning('Heartbeat check , reset DHCP') #print 'Heartbeat check , reset DHCP' #networkmod.resetDHCP() #networkmod.DHCP_COUNTER=networkmod.DHCP_COUNTER+1 goON, GWipaddr = networkmod.checkGWsubnet("wlan0") if GWipaddr == "": logger.info( 'Gateway IP address NOT found, back to AP mode') # back to AP mode! kind of risky business networkmod.connect_AP() else: logger.info('Gateway IP address found %s', GWipaddr) connected = False else: logger.info('Heartbeat check , wifi connection OK') print('Heartbeat check , wifi connection OK') #networkmod.DHCP_COUNTER=0 connected = True if connected: # Check if remote IP address is changed compared to previous communication and in such case resend the mail ipext = networkmod.get_external_ip() logger.info( 'Heartbeat check , Check IP address change -%s- and previously sent -%s-', ipext, emailmod.IPEXTERNALSENT) if (ipext != ""): if (emailmod.IPEXTERNALSENT != ""): if ipext != emailmod.IPEXTERNALSENT: print( "Heartbeat check, IP address change detected. Send email with updated IP address" ) logger.info( 'Heartbeat check, IP address change detected. Send email with updated IP address' ) emailmod.sendallmail( "alert", "System detected IP address change, below the updated links" ) else: logger.info('Heartbeat check, IP address unchanged') else: # first mail has not been sent succesfully of IPEXTERNALSENT was not available by the time print("System has been reconnected") logger.info( "System has been reconnected, IPEXTERNALSENT was empty") emailmod.sendallmail("alert", "System has been reconnected") else: print("not able to establish an internet connection") logger.warning("not able to establish an internet connection") # check clock with NTP and reset master scheduler in case of clock change if CheckNTPandAdjustClockandResetSched(): return True #check the static IP address currentipaddr = networkmod.get_local_ip_raw() logger.info('Target IP address= %s. Current access point IP addresses= %s', networkmod.IPADDRESS, currentipaddr) if networkmod.IPADDRESS not in currentipaddr: #set IP address logger.warning( 'Local Static IP address not in the list, Set Target IP address') networkmod.addIP("wlan0") else: logger.info('Local Statip IP address OK') # check master job has a next run" isok, datenextrun = SchedulerMod.get_next_run_time("master") if isok: datenow = datetime.utcnow() datenextrun = datenextrun.replace(tzinfo=None) print("Master Scheduler Next run ", datenextrun, " Now (UTC) ", datenow) if datenextrun > datenow: print("Masterschedule next RUN confirmed") logger.info('Heartbeat check , Master Scheduler OK') else: isok = False if not isok: print("No next run for master scheduler") logger.warning('Heartbeat check , Master Scheduler Interrupted') #emailmod.sendallmail("alert","Master Scheduler has been interrupted, try to restart scheduler") resetmastercallback() return True # check if there have been errors in Syslog if DEBUGMODE: logger.info('Heartbeat check , check errors in Syslog file') Errortextlist = debuggingmod.searchsyslogkeyword("error") if Errortextlist: print("found error in syslog") logger.warning( "ERROR: found error in syslog -------------------------") #send notification mail if debuggingmod.SENTERRORTEXT != Errortextlist[0]: emailmod.sendallmail("alert", "Error found in Syslog", Errortextlist) debuggingmod.SENTERRORTEXT = Errortextlist[0] else: print("No error found in syslog") logger.info('Heartbeat check , SYSLOG ok') # check if there have been errors in Schedulerlog if DEBUGMODE: logger.info('Heartbeat check , check errors in Sched log file') filename = "logfiles/apscheduler_hydrosystem.log" MYPATH = hardwaremod.get_path() filenameandpath = os.path.join(MYPATH, filename) Errortextlist = debuggingmod.searchLOGkeyword(filenameandpath, "error") if Errortextlist: print("found error in LOG ", filename) logger.warning( "ERROR: found error in LOG , %s -------------------------", filename) #send notification mail if debuggingmod.SENTERRORTEXT != Errortextlist[0]: emailmod.sendallmail("alert", "Error found in LOG", Errortextlist) debuggingmod.SENTERRORTEXT = Errortextlist[0] else: print("No error found in LOG", filename) logger.info('Heartbeat check , LOG ok') return True
def connect_network(internetcheck=False, backtoAP=False): # this is the procedure that disable the AP and connect to wifi network connected=False print " try to connect to wifi network" thessid=connect_preconditions() # get the first SSID of saved wifi network to connect with and see if the SSID is on air if not thessid=="": print "preconditions to connect to wifi network are met" logger.info('preconditions to connect to wifi network are met') ssids=connectedssid() # get the SSID currently connected if len(ssids)>0: ssid=ssids[0] else: ssid="" if not ssid==thessid: print "try to connect to wifi network" logger.info('try to connect to wifi network %s ' ,thessid) print "try to stop AP services, hostapd, dnsmasq" logger.info('try to stop AP services, hostapd, dnsmasq ') i=0 done=False while (i<2) and (not done): done=stop_hostapd() i=i+1 i=0 done=False while (i<2) and (not done): done=stop_dnsmasq() i=i+1 done=False ssids=[] i=0 while (i<3) and (len(ssids)==0): done=connect_savedwifi(thessid) # return true when the command is executed i=i+1 if done: time.sleep(1+i*5) print "wifi connection attempt ",i print "check connected SSID" logger.info('Connection command executed attempt %d, check connected SSID ',i) else: print "Connection command NOT executed properly , attempt ",i logger.info('Connection command NOT executed properly , attempt %d ',i) ssids=connectedssid() if len(ssids)>0: ssid=ssids[0] else: ssid="" logger.info('NO connected SSID') print "Connected to the SSID ", ssid logger.info('Connected SSID: %s -- ', ssid) else: print "already connected to the SSID ", ssid if len(ssids)==0: print "No SSID established, fallback to AP mode" # go back and connect in Access point Mode logger.info('No Wifi Network connected, no AP connected, going back to Access Point mode') connect_AP() connected=False else: logger.info('Connected to Wifi Network %s' , ssid ) print 'Connected to Wifi Network ' , ssid # here it is needed to have a real check of the internet connection as for example google if internetcheck: connected=check_internet_connection(3) if connected: print "Google is reacheable !" logger.info('Google is reacheable ! ') #send first mail print "Send first mail !" logger.info('Send first mail ! ') emailmod.sendallmail("alert", "System has been reconnected to wifi network") else: if backtoAP: print "Connectivity problem with WiFi network " ,ssid[0] , "going back to wifi access point mode" logger.info('Connectivity problem with WiFi network, %s, gong back to wifi access point mode' ,ssid ) connect_AP() else: connected=True logger.info('wait and check if the heartbeat job is still scheduled') #pulsesecond=180 #selectedplanmod.waitandcheckheartbeat(pulsesecond) #use CPU cycles as way to delay, cannot be based on clock info, clock jumps happen as soon as NTP is providing the datatime to the system pausecycles=10000000 for i in range(1,pausecycles): b=i*0.1 selectedplanmod.checkheartbeat() else: print "No Saved Wifi Network available" logger.info('No Saved Wifi Network available') print "try to fallback to AP mode" # go back and connect in Access point Mode #logger.info('Going back to Access Point mode') #connect_AP() connected=False return connected
def connect_network(): # this is the procedure that disable the AP and connect to wifi network connected = False print " try to connect to wifi network" thessid = connect_preconditions( ) # get the first SSID of saved wifi network to connect with if not thessid == "": print "preconditions to connect to wifi network are met" logger.info('preconditions to connect to wifi network are met') ssids = connectedssid() # get the SSID currently connected if len(ssids) > 0: ssid = ssids[0] else: ssid = "" if not ssid == thessid: print "try to connect to wifi network" print "try to stop AP services, hostapd, dnsmasq" i = 0 done = False while (i < 2) and (not done): done = stop_hostapd() i = i + 1 i = 0 done = False while (i < 2) and (not done): done = stop_dnsmasq() i = i + 1 i = 0 done = False while (i < 3) and (not done): done = connect_savedwifi(thessid) i = i + 1 print " wifi connection attempt ", i print "check connected SSID" logger.info('check connected SSID ') ssids = connectedssid() i = 0 while (i < 2) and (len(ssids) == 0): time.sleep(1 + i * 5) ssids = connectedssid() i = i + 1 if len(ssids) > 0: ssid = ssids[0] else: ssid = "" print "connected to the SSID ", ssid logger.info('connected SSID %s ', ssid) else: print "already connected to the SSID ", ssid if len(ssids) == 0: print "No SSID established, fallback to AP mode" # go back and connect in Access point Mode logger.info( 'No Wifi Network connected, no AP connected, going back to Access Point mode' ) connect_AP() connected = False else: logger.info( 'Connected to Wifi Network %s, now testing connectivity', ssid) print 'Connected to Wifi Network ', ssid, ' now testing connectivity' # here it is needed to have a real check of the internet connection as for example google connected = check_internet_connection(3) if connected: print "Google is reacheable !" logger.info('Google is reacheable ! ') #send first mail print "Send first mail !" logger.info('Send first mail ! ') emailmod.sendallmail( "alert", "System has been reconnected to wifi network") else: print "Connectivity problem with WiFi network ", ssid[ 0], "going back to wifi access point mode" logger.info( 'Connectivity problem with WiFi network, %s, gong back to wifi access point mode', ssid) connect_AP() else: print "No Saved Wifi Network available" logger.info('No Saved Wifi Network available') print "try to fallback to AP mode" # go back and connect in Access point Mode logger.info('Going back to Access Point mode') connect_AP() connected = False return connected
def heartbeat(): print "start heartbeat check", " ", datetime.now() logger.info('Start heartbeat routine %s', datetime.now().strftime("%Y-%m-%d %H:%M:%S")) connectedssid = networkmod.connectedssid() connected = False if len(connectedssid) == 0: logger.warning( 'Heartbeat check , no network connected -------------- try to connect' ) print 'Heartbeat check , no network connected -------------- try to connect' connected = networkmod.connect_network() else: logger.info('Heartbeat check , Connected Wifi Network: %s ', connectedssid[0]) if connectedssid[0] == networkmod.localwifisystem: logger.info( 'Heartbeat check , Configured as wifi access point, check if possible to connect to wifi network' ) connected = networkmod.connect_network() else: reachgoogle = networkmod.check_internet_connection(3) if not reachgoogle: logger.warning( 'Heartbeat check , test ping not able to reach Google -------------- try to connect' ) print 'Heartbeat check , no IP connection-------------- try to connect' connected = networkmod.connect_network() else: logger.info('Heartbeat check , wifi connection OK') print 'Heartbeat check , wifi connection OK' connected = True if connected: # Check if remote IP address is changed compared to previous communication and in such case resend the mail ipext = networkmod.get_external_ip() logger.info('Heartbeat check , Check IP address change %s', ipext) if ipext != "": if ipext != emailmod.IPEXTERNALSENT: print "Heartbeat check, IP address change detected. Send email with updated IP address" logger.info( 'Heartbeat check, IP address change detected. Send email with updated IP address' ) emailmod.sendallmail( "alert", "System detected IP address change, below the updated links" ) # Check current time is less than 60 second different from NTP information # try to get the clock from network print "check system clock" logger.info('Heartbeat check, check clock') networktime = clockmod.getNTPTime() logger.info('Heartbeat check , Network time NTP: %s ', networktime) systemtime = clockmod.readsystemdatetime() logger.info('Heartbeat check , System time NTP: %s ', systemtime) if not networktime == '': diffsec = clockmod.timediffinsec(networktime, systemtime) logger.info( 'Heartbeat check , difference between system time and network time, diffsec = %d ', diffsec) if diffsec > 60: print "Heartbeat check , warning difference between system time and network time >60 sec, diffsec = ", diffsec logger.warning( 'Heartbeat check , warning difference between system time and network time >60 sec, diffsec = %d ', diffsec) print "Heartbeat check , Apply network datetime to system" logger.warning( 'Heartbeat check , Apply network datetime to system ') clockmod.setHWclock(networktime) clockmod.setsystemclock(networktime) else: print "Heartbeat check , Clock OK" logger.info('Heartbeat check , Clock OK') else: print "not able to get network time" logger.warning('Heartbeat check , not able to get network time') else: print "not able to establish an internet connection" logger.warning("not able to establish an internet connection") # check master job has a next run" isok, datenextrun = SchedulerMod.get_next_run_time("master") if isok: datenow = datetime.utcnow() datenextrun = datenextrun.replace(tzinfo=None) print "Master Scheduler Next run ", datenextrun, " Now (UTC) ", datenow if datenextrun > datenow: print "Masterschedule next RUN confirmed" logger.info('Heartbeat check , Master Scheduler OK') else: isok = False if not isok: print "No next run for master scheduler" logger.warning('Heartbeat check , Master Scheduler Interrupted') emailmod.sendallmail( "alert", "Master Scheduler has been interrupted, try to restart scheduler") setmastercallback() return True
def autowateringexecute(refsensor, element): global AUTO_data sensor = autowateringdbmod.searchdata("element", element, "sensor") # check the sensor if refsensor == sensor: print "auto watering check -----------------------------------------> ", element logger.info('auto watering check --------------------------> %s', element) # check the watering mode modelist = ["None", "Full Auto", "Emergency Activation", "Alert Only"] workmode = checkworkmode(element) if not (sensor in sensordbmod.gettablelist()): print "Sensor does not exist ", sensor, ", element: ", element logger.error("Sensor does not exist %s , element: %s ", sensor, element) return "sensor not Exist" maxthreshold = hardwaremod.tonumber( autowateringdbmod.searchdata("element", element, "threshold")[1], 0) minthreshold = hardwaremod.tonumber( autowateringdbmod.searchdata("element", element, "threshold")[0], maxthreshold) # exit condition in case of data inconsistency if minthreshold >= maxthreshold: print "Data inconsistency , element: ", element logger.error("Data inconsistency , element: %s ", element) return "data inconsistency" now = datetime.now() nowtime = now.time() starttimeh = hardwaremod.toint( autowateringdbmod.searchdata("element", element, "allowedperiod")[0].split(":")[0], 0) starttimem = hardwaremod.toint( autowateringdbmod.searchdata("element", element, "allowedperiod")[0].split(":")[1], 0) endtimeh = hardwaremod.toint( autowateringdbmod.searchdata("element", element, "allowedperiod")[1].split(":")[0], 1) endtimem = hardwaremod.toint( autowateringdbmod.searchdata("element", element, "allowedperiod")[1].split(":")[1], 0) starttime = time(starttimeh, starttimem) endtime = time(endtimeh, endtimem) duration = 1000 * hardwaremod.toint( autowateringdbmod.searchdata("element", element, "wtstepsec"), 0) maxstepnumber = hardwaremod.toint( autowateringdbmod.searchdata("element", element, "maxstepnumber"), 0) maxdays = hardwaremod.toint( autowateringdbmod.searchdata("element", element, "maxdaysbetweencycles"), 0) waitingtime = hardwaremod.toint( autowateringdbmod.searchdata("element", element, "pausebetweenwtstepsmin"), 0) mailtype = autowateringdbmod.searchdata("element", element, "mailalerttype") minaccepted = hardwaremod.tonumber( autowateringdbmod.searchdata("element", element, "sensorminacceptedvalue"), 0.1) # ------------------------ Workmode split if workmode == "Full Auto": # block the wateringplan activation as by definition of "Full Auto" allowwateringplan[element] = False # check if inside the allowed time period print "full Auto Mode" logger.info('full auto mode --> %s', element) timeok = isNowInTimePeriod(starttime, endtime, nowtime) print "inside allowed time ", timeok, " starttime ", starttime, " endtime ", endtime logger.info('full auto mode') if timeok: logger.info('inside allowed time') belowthr, valid = checkminthreshold(sensor, minthreshold, minaccepted) if valid: if belowthr: status = "lowthreshold" logger.info('below threshold') # wait to seek a more stable reading of hygrometer # check if time between watering events is larger that the waiting time (minutes) lastwateringtime = statusdataDBmod.read_status_data( AUTO_data, element, "lastwateringtime") print ' Previous watering: ', lastwateringtime, ' Now: ', datetime.now( ) timedifference = sensordbmod.timediffinminutes( lastwateringtime, datetime.now()) print 'Time interval between watering steps', timedifference, '. threshold', waitingtime logger.info( 'Time interval between watering steps %d threshold %d', timedifference, waitingtime) if timedifference > waitingtime: print " Sufficient waiting time" logger.info('Sufficient waiting time') # activate watering in case the maxstepnumber is not exceeded watercounter = statusdataDBmod.read_status_data( AUTO_data, element, "watercounter") if maxstepnumber > watercounter: #activate pump activatewater(element, duration) # invia mail, considered as info, not as alert if mailtype != "warningonly": textmessage = "INFO: " + sensor + " value below the minimum threshold " + str( minthreshold ) + ", activating the watering :" + element emailmod.sendallmail("alert", textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", watercounter + 1) statusdataDBmod.write_status_data( AUTO_data, element, "lastwateringtime", datetime.now()) else: # critical, sensor below minimum after all watering activations are done logger.info( 'Number of watering time per cycle has been exceeeded' ) # read hystory data and calculate the slope timelist = hardwaremod.gettimedata(sensor) cyclestartdate = statusdataDBmod.read_status_data( AUTO_data, element, "cyclestartdate") lastwateringtime = statusdataDBmod.read_status_data( AUTO_data, element, "lastwateringtime") startdate = cyclestartdate - timedelta( minutes=timelist[1]) enddate = lastwateringtime + timedelta( minutes=waitingtime) isslopeok = checkinclination( sensor, startdate, enddate ) # still to decide if use the enddate if isslopeok: # invia mail if couner alert is lower than 1 alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 1: textmessage = "WARNING: Please consider to increase the amount of water per cycle, the " + sensor + " value below the MINIMUM threshold " + str( minthreshold ) + " still after activating the watering :" + element + " for " + str( maxstepnumber ) + " times. System will automatically reset the watering cycle to allow more water" print textmessage #send alert mail notification emailmod.sendallmail( "alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) # reset watering cycle status = "done" statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", -1) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "cyclestartdate", datetime.now()) else: # slope not OK, probable hardware problem alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 3: textmessage = "CRITICAL: Possible hardware problem, " + sensor + " value below the MINIMUM threshold " + str( minthreshold ) + " still after activating the watering :" + element + " for " + str( maxstepnumber) + " times" print textmessage #send alert mail notification emailmod.sendallmail( "alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) # update the status checkcounter = statusdataDBmod.read_status_data( AUTO_data, element, "checkcounter") statusdataDBmod.write_status_data( AUTO_data, element, "cyclestatus", status) statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", checkcounter + 1) # RAMPUP case above threshold but below maxthreshold elif sensorreading( sensor ) < maxthreshold: # intermediate state where the sensor is above the minthreshold but lower than the max threshold # check the status of the automatic cycle cyclestatus = statusdataDBmod.read_status_data( AUTO_data, element, "cyclestatus") if cyclestatus != "done": status = "rampup" # wait to seek a more stable reading of hygrometer # check if time between watering events is larger that the waiting time (minutes) lastwateringtime = statusdataDBmod.read_status_data( AUTO_data, element, "lastwateringtime") if sensordbmod.timediffinminutes( lastwateringtime, datetime.now()) > waitingtime: watercounter = statusdataDBmod.read_status_data( AUTO_data, element, "watercounter") if maxstepnumber > watercounter: #activate pump activatewater(element, duration) # invia mail, considered as info, not as alert if mailtype != "warningonly": textmessage = "INFO: " + sensor + " value below the Maximum threshold " + str( maxthreshold ) + ", activating the watering :" + element emailmod.sendallmail( "alert", textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", watercounter + 1) statusdataDBmod.write_status_data( AUTO_data, element, "lastwateringtime", datetime.now()) else: # give up to reache the maximum threshold, proceed as done, send alert logger.info( 'Number of watering time per cycle has been exceeeded' ) # invia mail if couner alert is lower than 1 -------------- # only if the info is activated if mailtype != "warningonly": alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 2: textmessage = "INFO " + sensor + " value below the Maximum threshold " + str( maxthreshold ) + " still after activating the watering :" + element + " for " + str( maxstepnumber) + " times" print textmessage #send alert mail notification emailmod.sendallmail( "alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) # reset watering cycle status = "done" statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", -1) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "cyclestartdate", datetime.now()) # update the status checkcounter = statusdataDBmod.read_status_data( AUTO_data, element, "checkcounter") statusdataDBmod.write_status_data( AUTO_data, element, "cyclestatus", status) statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", checkcounter + 1) else: # update the status, reset cycle statusdataDBmod.write_status_data( AUTO_data, element, "cyclestatus", "done") statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", 0) elif workmode == "Emergency Activation": # check if inside the allow time period logger.info('Emergency Mode') timeok = isNowInTimePeriod(starttime, endtime, nowtime) print "inside allowed time ", timeok, " starttime ", starttime, " endtime ", endtime if timeok: belowthr, valid = checkminthreshold(sensor, minthreshold, minaccepted) if valid: if belowthr: # wait to seek a more stable reading of hygrometer # check if time between watering events is larger that the waiting time (minutes) lastwateringtime = statusdataDBmod.read_status_data( AUTO_data, element, "lastwateringtime") if sensordbmod.timediffinminutes( lastwateringtime, datetime.now()) > waitingtime: # activate watering in case the maxstepnumber is not exceeded watercounter = statusdataDBmod.read_status_data( AUTO_data, element, "watercounter") if maxstepnumber > watercounter: #activate pump activatewater(element, duration) # invia mail, considered as info, not as alert if mailtype != "warningonly": textmessage = "INFO: " + sensor + " value below the minimum threshold " + str( minthreshold ) + ", activating the watering :" + element emailmod.sendallmail("alert", textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", watercounter + 1) statusdataDBmod.write_status_data( AUTO_data, element, "lastwateringtime", datetime.now()) else: logger.info( 'Number of watering time per cycle has been exceeeded' ) # read hystory data and calculate the slope timelist = hardwaremod.gettimedata(sensor) cyclestartdate = statusdataDBmod.read_status_data( AUTO_data, element, "cyclestartdate") lastwateringtime = statusdataDBmod.read_status_data( AUTO_data, element, "lastwateringtime") startdate = cyclestartdate - timedelta( minutes=timelist[1]) enddate = lastwateringtime + timedelta( minutes=waitingtime) isslopeok = checkinclination( sensor, startdate, enddate) if isslopeok: # invia mail if couner alert is lower than 1 alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 1: textmessage = "WARNING: Please consider to increase the amount of water per cycle, the " + sensor + " value below the MINIMUM threshold " + str( minthreshold ) + " still after activating the watering :" + element + " for " + str( maxstepnumber ) + " times. System will automatically reset the watering cycle to allow more water" print textmessage #send alert mail notification alertcounter emailmod.sendallmail( "alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) # reset watering cycle status = "done" statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", -1) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "cyclestartdate", datetime.now()) else: # slope not OK, probable hardware problem alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 3: textmessage = "CRITICAL: Possible hardware problem, " + sensor + " value below the MINIMUM threshold " + str( minthreshold ) + " still after activating the watering :" + element + " for " + str( maxstepnumber) + " times" print textmessage #send alert mail notification emailmod.sendallmail( "alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) # update the status checkcounter = statusdataDBmod.read_status_data( AUTO_data, element, "checkcounter") statusdataDBmod.write_status_data( AUTO_data, element, "cyclestatus", "lowthreshold") statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", checkcounter + 1) else: # update the status statusdataDBmod.write_status_data( AUTO_data, element, "cyclestatus", "done") statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", 0) elif workmode == "under MIN over MAX": logger.info('under MIN over MAX') # normally watering plan is allowed unless over MAX threshold allowwateringplan[element] = True # check if inside the allow time period timeok = isNowInTimePeriod(starttime, endtime, nowtime) print "inside allowed time ", timeok, " starttime ", starttime, " endtime ", endtime if timeok: logger.info('Insede operative time') belowthr, valid = checkminthreshold(sensor, minthreshold, minaccepted) if valid: logger.info('valid sensor reading') if belowthr: logger.info('sensor reading below threshold') # wait to seek a more stable reading of hygrometer # check if time between watering events is larger that the waiting time (minutes) lastwateringtime = statusdataDBmod.read_status_data( AUTO_data, element, "lastwateringtime") if sensordbmod.timediffinminutes( lastwateringtime, datetime.now()) > waitingtime: # activate watering in case the maxstepnumber is not exceeded watercounter = statusdataDBmod.read_status_data( AUTO_data, element, "watercounter") if maxstepnumber > watercounter: logger.info('water Count not exceeded') #activate pump activatewater(element, duration) # invia mail, considered as info, not as alert if mailtype != "warningonly": textmessage = "INFO: " + sensor + " value below the minimum threshold " + str( minthreshold ) + ", activating the watering :" + element emailmod.sendallmail("alert", textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", watercounter + 1) statusdataDBmod.write_status_data( AUTO_data, element, "lastwateringtime", datetime.now()) else: logger.info( 'Number of watering time per cycle has been exceeeded' ) # read hystory data and calculate the slope timelist = hardwaremod.gettimedata(sensor) cyclestartdate = statusdataDBmod.read_status_data( AUTO_data, element, "cyclestartdate") lastwateringtime = statusdataDBmod.read_status_data( AUTO_data, element, "lastwateringtime") startdate = cyclestartdate - timedelta( minutes=timelist[1]) enddate = lastwateringtime + timedelta( minutes=waitingtime) isslopeok = checkinclination( sensor, startdate, enddate) if isslopeok: # invia mail if couner alert is lower than 1 alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 1: textmessage = "WARNING: Please consider to increase the amount of water per cycle, the " + sensor + " value below the MINIMUM threshold " + str( minthreshold ) + " still after activating the watering :" + element + " for " + str( maxstepnumber ) + " times. System will automatically reset the watering cycle to allow more water" print textmessage #send alert mail notification emailmod.sendallmail( "alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) # reset watering cycle status = "done" statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", -1) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "cyclestartdate", datetime.now()) else: # slope not OK, probable hardware problem alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 3: textmessage = "CRITICAL: Possible hardware problem, " + sensor + " value below the MINIMUM threshold " + str( minthreshold ) + " still after activating the watering :" + element + " for " + str( maxstepnumber) + " times" print textmessage #send alert mail notification emailmod.sendallmail( "alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) # update the status checkcounter = statusdataDBmod.read_status_data( AUTO_data, element, "checkcounter") statusdataDBmod.write_status_data( AUTO_data, element, "cyclestatus", "lowthreshold") statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", checkcounter + 1) else: # above minimum threshold logger.info('sensor reading above min threshold') # update the status statusdataDBmod.write_status_data( AUTO_data, element, "cyclestatus", "done") statusdataDBmod.write_status_data( AUTO_data, element, "checkcounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", 0) if sensorreading(sensor) > maxthreshold: logger.info( 'sensor reading above MAX threshold, deactivate scheduled irrigation' ) # do not activate the irrigation scheduled in the time plan allowwateringplan[element] = False elif workmode == "Alert Only": belowthr, valid = checkminthreshold(sensor, minthreshold, minaccepted) if valid: if belowthr: # invia mail if couter alert is lower than alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 2: textmessage = "WARNING " + sensor + " value below the minimum threshold " + str( minthreshold) + " watering system: " + element print textmessage #send alert mail notification emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) # update the status checkcounter = statusdataDBmod.read_status_data( AUTO_data, element, "checkcounter") statusdataDBmod.write_status_data(AUTO_data, element, "cyclestatus", "lowthreshold") statusdataDBmod.write_status_data(AUTO_data, element, "checkcounter", checkcounter + 1) else: # update the status statusdataDBmod.write_status_data(AUTO_data, element, "cyclestatus", "done") statusdataDBmod.write_status_data(AUTO_data, element, "checkcounter", 0) statusdataDBmod.write_status_data(AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data(AUTO_data, element, "alertcounter", 0) else: # None case print "No Action required, workmode set to None, element: ", element logger.info( "No Action required, workmode set to None, element: %s ", element) cyclestatus = statusdataDBmod.read_status_data(AUTO_data, element, "cyclestatus") if cyclestatus == "lowthreshold": checkcounter = statusdataDBmod.read_status_data( AUTO_data, element, "checkcounter") if checkcounter == 1: statusdataDBmod.write_status_data(AUTO_data, element, "cyclestartdate", datetime.now()) # implment alert message for the cycle exceeding days, and reset the cycle if workmode != "None": cyclestartdate = statusdataDBmod.read_status_data( AUTO_data, element, "cyclestartdate") timedeltadays = sensordbmod.timediffdays(datetime.now(), cyclestartdate) if (timedeltadays > maxdays ): #the upper limit is set in case of abrupt time change textmessage = "WARNING " + sensor + " watering cycle is taking too many days, watering system: " + element + ". Reset watering cycle" print textmessage # in case of full Auto, activate pump for minimum pulse period if workmode == "Full Auto": if ( timedeltadays < maxdays + 2 ): #the upper limit is set in case of abrupt time change textmessage = "WARNING " + sensor + " watering cycle is taking too many days, watering system: " + element + ". Activate Min pulse + Reset watering cycle" activatewater(element, duration) #send alert mail notification if mailtype != "warningonly": emailmod.sendallmail("alert", textmessage) logger.error(textmessage) logger.error("Cycle started %s, Now is %s ", cyclestartdate.strftime("%Y-%m-%d %H:%M:%S"), datetime.now().strftime("%Y-%m-%d %H:%M:%S")) # reset cycle statusdataDBmod.write_status_data(AUTO_data, element, "cyclestatus", "done") statusdataDBmod.write_status_data(AUTO_data, element, "checkcounter", 0) statusdataDBmod.write_status_data(AUTO_data, element, "watercounter", 0) statusdataDBmod.write_status_data(AUTO_data, element, "alertcounter", 0) statusdataDBmod.write_status_data(AUTO_data, element, "cyclestartdate", datetime.now()) # implment Critical alert message in case the threshold is below the 0.5 of the minimum if workmode != "None": belowthr, valid = checkminthreshold(sensor, minthreshold * 0.5, minaccepted) if valid: if belowthr: logger.info( 'sensor %s below half of the actual set threshold', sensor) textmessage = "CRITICAL: Plant is dying, " + sensor + " reading below half of the minimum threshold, need to check the " + element print textmessage #send alert mail notification alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 5: emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data( AUTO_data, element, "alertcounter", alertcounter + 1) else: logger.info('sensor %s below valid data', sensor) textmessage = "WARNING: " + sensor + " below valid data range, need to check sensor" print textmessage #send alert mail notification alertcounter = statusdataDBmod.read_status_data( AUTO_data, element, "alertcounter") if alertcounter < 3: emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data, element, "alertcounter", alertcounter + 1) return
def CheckActivateNotify(element, sensor, preemptiontime, actuatoroutput, actionmodeafterfirst, actuatoroutputfollowup, mailtype, interrupt_triggernumber, interrupt_validinterval): value = actuatoroutput isok = False global AUTO_data # check if in blocking state lasteventtime = statusdataDBmod.read_status_data(AUTO_data, element, "lasteventtime") blockingstate = statusdataDBmod.read_status_data(AUTO_data, element, "blockingstate") #print ' Previous event: ' , lasteventtime , ' Now: ', datetime.utcnow() #timedifference=sensordbmod.timediffinminutes(lasteventtime,datetime.utcnow()) #print 'Time interval between actions', timedifference ,'. threshold', preemptiontime #logger.info('Time interval between Actions %d threshold %d', timedifference,preemptiontime) # count the interrupt that are fast enough to stay in the valid interrupt period #print "autodata" ,AUTO_data[element] lastinterrupttime = statusdataDBmod.read_status_data( AUTO_data, element, "lastinterrupttime") nowtime = datetime.utcnow() #print ' Previous interrupt: ' , lastinterrupttime , ' Now: ', nowtime diffseconds = (nowtime - lastinterrupttime).total_seconds() statusdataDBmod.write_status_data(AUTO_data, element, "lastinterrupttime", nowtime) validinterruptcount = statusdataDBmod.read_status_data( AUTO_data, element, "validinterruptcount") if diffseconds <= interrupt_validinterval: #valid interval between interrupt, increase counter validinterruptcount = validinterruptcount + 1 statusdataDBmod.write_status_data(AUTO_data, element, "validinterruptcount", validinterruptcount) else: # time between interrupt too long, restart counter # save on database #x = threading.Thread(target=savedata, args=(sensor,validinterruptcount)) #x.start() #reset counter and events validinterruptcount = 1 statusdataDBmod.write_status_data(AUTO_data, element, "validinterruptcount", validinterruptcount) WaitandRegister(element, sensor, interrupt_validinterval, validinterruptcount) #print "********" ,validinterruptcount , "******" if not blockingstate: # outside the preemption period , first activation #print " outside the preemption period " #logger.info('outside the preemption period') # before action, evaluate if trigger number is reached if validinterruptcount == interrupt_triggernumber: # action print "Implement Actuator Value ", value logger.info('Procedure to start actuator %s, for value = %s', element, value) isok = activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype != "none": if mailtype != "warningonly": textmessage = "INFO: " + sensor + " event , activating:" + element + " with Value " + str( value) emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data, element, "lasteventtime", datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data, element, "lastactiontime", datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data, element, "actionvalue", value) # start the blocking state print "Start blocking state" startblockingstate(element, preemptiontime) else: # inside blocking state #print " inside the preemption period, starting followup actions: " , actionmodeafterfirst #logger.info('inside the preemption period, check followup actions %s :', actionmodeafterfirst) if actionmodeafterfirst == "None": return if actionmodeafterfirst == "Extend blocking state": # extend only the pre-emption blocking period, no action print "Extend blocking state" startblockingstate(element, preemptiontime) if actionmodeafterfirst == "Remove blocking state" or actionmodeafterfirst == "Remove and Follow-up": # remove the pre-emption blocking period, no action print "Remove blocking state" endblocking(element, preemptiontime) if actionmodeafterfirst == "Follow-up action" or actionmodeafterfirst == "Remove and Follow-up": # execute the action followup, no variation in the preemption period value = actuatoroutputfollowup # followup action print "Implement Actuator Value followup", value logger.info( 'Procedure to start actuator followup %s, for value = %s', element, value) isok = activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype != "none": if mailtype != "warningonly": textmessage = "INFO: " + sensor + " event , activating:" + element + " with Value " + str( value) emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data, element, "lastactiontime", datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data, element, "actionvalue", value) return isok
def heartbeat(): print "start heartbeat check", " " , datetime.now() logger.info('Start heartbeat routine %s', datetime.now().strftime("%Y-%m-%d %H:%M:%S")) connectedssid=networkmod.connectedssid() connected=False if len(connectedssid)==0: logger.warning('Heartbeat check , no network connected -------------- try to connect') print 'Heartbeat check , no network connected -------------- try to connect' connected=networkmod.connect_network() else: logger.info('Heartbeat check , Connected Wifi Network: %s ', connectedssid[0]) if connectedssid[0]==networkmod.localwifisystem: logger.info('Heartbeat check , Configured as wifi access point, check if possible to connect to wifi network') connected=networkmod.connect_network() else: reachgoogle=networkmod.check_internet_connection(1) if not reachgoogle: logger.warning('Heartbeat check , test ping not able to reach Google -------------- No action') print 'Heartbeat check , no IP connection-------------- No action' #connected=networkmod.connect_network() # use this in case you require the system to try connect wifi again in case no internet is reached connected=False else: logger.info('Heartbeat check , wifi connection OK') print 'Heartbeat check , wifi connection OK' connected=True if connected: # Check if remote IP address is changed compared to previous communication and in such case resend the mail ipext=networkmod.get_external_ip() logger.info('Heartbeat check , Check IP address change -%s- and previously sent -%s-', ipext , emailmod.IPEXTERNALSENT) if (ipext!=""): if (emailmod.IPEXTERNALSENT!=""): if ipext!=emailmod.IPEXTERNALSENT: print "Heartbeat check, IP address change detected. Send email with updated IP address" logger.info('Heartbeat check, IP address change detected. Send email with updated IP address') emailmod.sendallmail("alert","System detected IP address change, below the updated links") else: logger.info('Heartbeat check, IP address unchanged') else: # first mail has not been sent succesfully of IPEXTERNALSENT was not available by the time print "System has been reconnected" logger.info("System has been reconnected, IPEXTERNALSENT was empty") emailmod.sendallmail("alert","System has been reconnected") # Check current time is less than 60 second different from NTP information # try to get the clock from network print "check system clock" logger.info('Heartbeat check, check clock') networktime=clockmod.getNTPTime() logger.info('Heartbeat check , Network time NTP: %s ', networktime) systemtime=clockmod.readsystemdatetime() logger.info('Heartbeat check , System time NTP: %s ', systemtime) if not networktime=='': diffsec=clockmod.timediffinsec(networktime, systemtime) logger.info('Heartbeat check , difference between system time and network time, diffsec = %d ', diffsec) if diffsec>60: print "Heartbeat check , warning difference between system time and network time >60 sec, diffsec = " , diffsec logger.warning('Heartbeat check , warning difference between system time and network time >60 sec, diffsec = %d ', diffsec) print "Heartbeat check , Apply network datetime to system" logger.warning('Heartbeat check , Apply network datetime to system ') clockmod.setHWclock(networktime) clockmod.setsystemclock(networktime) else: print "Heartbeat check , Clock OK" logger.info('Heartbeat check , Clock OK') else: print "not able to get network time" logger.warning('Heartbeat check , not able to get network time') else: print "not able to establish an internet connection" logger.warning("not able to establish an internet connection") # check master job has a next run" isok, datenextrun = SchedulerMod.get_next_run_time("master") if isok: datenow=datetime.utcnow() datenextrun = datenextrun.replace(tzinfo=None) print "Master Scheduler Next run " , datenextrun , " Now (UTC) ", datenow if datenextrun>datenow: print "Masterschedule next RUN confirmed" logger.info('Heartbeat check , Master Scheduler OK') else: isok=False if not isok: print "No next run for master scheduler" logger.warning('Heartbeat check , Master Scheduler Interrupted') emailmod.sendallmail("alert","Master Scheduler has been interrupted, try to restart scheduler") resetmastercallback() # check if there have been errors in Syslog if DEBUGMODE: Errortextlist=debuggingmod.searchsyslogkeyword("error") if Errortextlist: print "found error in syslog" logger.warning("ERROR: found error in syslog -------------------------") #send notification mail if debuggingmod.SENTERRORTEXT!=Errortextlist[0]: emailmod.sendallmail("alert","Error found in Syslog",Errortextlist) debuggingmod.SENTERRORTEXT=Errortextlist[0] else: print "No error found in syslog" logger.info('Heartbeat check , SYSLOG ok') # check if there have been errors in Schedulerlog if DEBUGMODE: filename="logfiles/apscheduler_hydrosystem.log" MYPATH=hardwaremod.get_path() filenameandpath=os.path.join(MYPATH, filename) Errortextlist=debuggingmod.searchLOGkeyword(filenameandpath,"error") if Errortextlist: print "found error in LOG ",filename logger.warning("ERROR: found error in LOG , %s -------------------------",filename) #send notification mail if debuggingmod.SENTERRORTEXT!=Errortextlist[0]: emailmod.sendallmail("alert","Error found in LOG",Errortextlist) debuggingmod.SENTERRORTEXT=Errortextlist[0] else: print "No error found in LOG", filename logger.info('Heartbeat check , LOG ok') return True
def heartbeat(): print "start heartbeat check", " ", datetime.now() logger.info('Start heartbeat routine %s', datetime.now().strftime("%Y-%m-%d %H:%M:%S")) connectedssid = networkmod.connectedssid() connected = False if len(connectedssid) == 0: logger.warning( 'Heartbeat check , no network connected -------------- try to connect' ) print 'Heartbeat check , no network connected -------------- try to connect' connected = networkmod.connect_network() else: logger.info('Heartbeat check , Connected Wifi Network: %s ', connectedssid[0]) if connectedssid[0] == networkmod.localwifisystem: logger.info( 'Heartbeat check , Configured as wifi access point, check if possible to connect to wifi network' ) connected = networkmod.connect_network() else: reachgoogle = networkmod.check_internet_connection(1) if not reachgoogle: logger.warning( 'Heartbeat check , test ping not able to reach Google -------------- No action' ) print 'Heartbeat check , no IP connection-------------- No action' #connected=networkmod.connect_network() # use this in case you require the system to try connect wifi again in case no internet is reached connected = False else: logger.info('Heartbeat check , wifi connection OK') print 'Heartbeat check , wifi connection OK' connected = True if connected: # Check if remote IP address is changed compared to previous communication and in such case resend the mail ipext = networkmod.get_external_ip() logger.info( 'Heartbeat check , Check IP address change -%s- and previously sent -%s-', ipext, emailmod.IPEXTERNALSENT) if (ipext != ""): if (emailmod.IPEXTERNALSENT != ""): if ipext != emailmod.IPEXTERNALSENT: print "Heartbeat check, IP address change detected. Send email with updated IP address" logger.info( 'Heartbeat check, IP address change detected. Send email with updated IP address' ) emailmod.sendallmail( "alert", "System detected IP address change, below the updated links" ) else: logger.info('Heartbeat check, IP address unchanged') else: # first mail has not been sent succesfully of IPEXTERNALSENT was not available by the time print "System has been reconnected" logger.info( "System has been reconnected, IPEXTERNALSENT was empty") emailmod.sendallmail("alert", "System has been reconnected") # Check current time is less than 60 second different from NTP information # try to get the clock from network print "check system clock" logger.info('Heartbeat check, check clock') networktime = clockmod.getNTPTime() logger.info('Heartbeat check , Network time NTP: %s ', networktime) systemtime = clockmod.readsystemdatetime() logger.info('Heartbeat check , System time NTP: %s ', systemtime) if not networktime == '': diffsec = clockmod.timediffinsec(networktime, systemtime) logger.info( 'Heartbeat check , difference between system time and network time, diffsec = %d ', diffsec) if diffsec > 60: print "Heartbeat check , warning difference between system time and network time >60 sec, diffsec = ", diffsec logger.warning( 'Heartbeat check , warning difference between system time and network time >60 sec, diffsec = %d ', diffsec) print "Heartbeat check , Apply network datetime to system" logger.warning( 'Heartbeat check , Apply network datetime to system ') clockmod.setHWclock(networktime) clockmod.setsystemclock(networktime) else: print "Heartbeat check , Clock OK" logger.info('Heartbeat check , Clock OK') else: print "not able to get network time" logger.warning('Heartbeat check , not able to get network time') else: print "not able to establish an internet connection" logger.warning("not able to establish an internet connection") # check master job has a next run" isok, datenextrun = SchedulerMod.get_next_run_time("master") if isok: datenow = datetime.utcnow() datenextrun = datenextrun.replace(tzinfo=None) print "Master Scheduler Next run ", datenextrun, " Now (UTC) ", datenow if datenextrun > datenow: print "Masterschedule next RUN confirmed" logger.info('Heartbeat check , Master Scheduler OK') else: isok = False if not isok: print "No next run for master scheduler" logger.warning('Heartbeat check , Master Scheduler Interrupted') emailmod.sendallmail( "alert", "Master Scheduler has been interrupted, try to restart scheduler") resetmastercallback() # check if there have been errors in Syslog if DEBUGMODE: Errortextlist = debuggingmod.searchsyslogkeyword("error") if Errortextlist: print "found error in syslog" logger.warning( "ERROR: found error in syslog -------------------------") #send notification mail if debuggingmod.SENTERRORTEXT != Errortextlist[0]: emailmod.sendallmail("alert", "Error found in Syslog", Errortextlist) debuggingmod.SENTERRORTEXT = Errortextlist[0] else: print "No error found in syslog" logger.info('Heartbeat check , SYSLOG ok') # check if there have been errors in Schedulerlog if DEBUGMODE: filename = "logfiles/apscheduler_hydrosystem.log" MYPATH = hardwaremod.get_path() filenameandpath = os.path.join(MYPATH, filename) Errortextlist = debuggingmod.searchLOGkeyword(filenameandpath, "error") if Errortextlist: print "found error in LOG ", filename logger.warning( "ERROR: found error in LOG , %s -------------------------", filename) #send notification mail if debuggingmod.SENTERRORTEXT != Errortextlist[0]: emailmod.sendallmail("alert", "Error found in LOG", Errortextlist) debuggingmod.SENTERRORTEXT = Errortextlist[0] else: print "No error found in LOG", filename logger.info('Heartbeat check , LOG ok') return True
def CheckActivateNotify(element, sensor, preemptiontime, actuatoroutput, actionmodeafterfirst, actuatoroutputfollowup, mailtype): value = actuatoroutput isok = False global AUTO_data # check if in blocking state lasteventtime = statusdataDBmod.read_status_data(AUTO_data, element, "lasteventtime") blockingstate = statusdataDBmod.read_status_data(AUTO_data, element, "blockingstate") print ' Previous event: ', lasteventtime, ' Now: ', datetime.utcnow() #timedifference=sensordbmod.timediffinminutes(lasteventtime,datetime.utcnow()) #print 'Time interval between actions', timedifference ,'. threshold', preemptiontime #logger.info('Time interval between Actions %d threshold %d', timedifference,preemptiontime) if not blockingstate: # outside the preemption period , first activation print " outside the preemption period " logger.info('outside the preemption period') # action print "Implement Actuator Value ", value logger.info('Procedure to start actuator %s, for value = %s', element, value) isok = activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype != "warningonly": textmessage = "INFO: " + sensor + " event , activating:" + element + " with Value " + str( value) emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data, element, "lasteventtime", datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data, element, "lastactiontime", datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data, element, "actionvalue", value) # start the blocking state startblockingstate(element, preemptiontime) else: # inside blocking state print " inside the preemption period, starting followup actions: ", actionmodeafterfirst logger.info( 'inside the preemption period, check followup actions %s :', actionmodeafterfirst) if actionmodeafterfirst == "None": return if actionmodeafterfirst == "Extend blocking state" or actionmodeafterfirst == "Extend and Follow-up": # extend only the pre-emption blocking period, no action print "Extend blocking state" startblockingstate(element, preemptiontime) if actionmodeafterfirst == "Remove blocking state" or actionmodeafterfirst == "Remove and Follow-up": # remove the pre-emption blocking period, no action print "Remove blocking state" endblocking(element, preemptiontime) if actionmodeafterfirst == "Follow-up action" or actionmodeafterfirst == "Extend and Follow-up" or actionmodeafterfirst == "Remove and Follow-up": # execute the action followup, no variation in the preemption period value = actuatoroutputfollowup # followup action print "Implement Actuator Value followup", value logger.info( 'Procedure to start actuator followup %s, for value = %s', element, value) isok = activateactuator(element, value) # invia mail, considered as info, not as alert if mailtype != "warningonly": textmessage = "INFO: " + sensor + " event , activating:" + element + " with Value " + str( value) emailmod.sendallmail("alert", textmessage) if isok: statusdataDBmod.write_status_data(AUTO_data, element, "lastactiontime", datetime.utcnow()) statusdataDBmod.write_status_data(AUTO_data, element, "actionvalue", value) return isok
def automationexecute(refsensor,element): sensor=automationdbmod.searchdata("element",element,"sensor") # check the sensor if refsensor==sensor: logger.info('automation Pairing OK ---> Actuator: %s , Sensor: %s', element, sensor) # check the watering mode modelist=["None", "Full Auto" , "Emergency Activation" , "Alert Only"] workmode=checkworkmode(element) if (workmode=="None"): # None case print "No Action required, workmode set to None, element: " , element logger.info("No Action required, workmode set to None, element: %s " , element) return if (workmode==""): logger.info("Not able to get the workmode: %s " , element) return logger.info('Automantion, Get all the parameters') sensormaxthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"sensor_threshold")[1],0) sensorminthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"sensor_threshold")[0],sensormaxthreshold) actuatormaxthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"actuator_threshold")[1],0) actuatorminthreshold=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"actuator_threshold")[0],actuatormaxthreshold) # evaluate variables for operational period check now = datetime.now() nowtime = now.time() starttimeh=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[0].split(":")[0],0) starttimem=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[0].split(":")[1],0) endtimeh=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[1].split(":")[0],1) endtimem=hardwaremod.toint(automationdbmod.searchdata("element",element,"allowedperiod")[1].split(":")[1],0) starttime=time(starttimeh,starttimem) endtime=time(endtimeh,endtimem) # get other parameters maxstepnumber=hardwaremod.toint(automationdbmod.searchdata("element",element,"stepnumber"),1) waitingtime=hardwaremod.toint(automationdbmod.searchdata("element",element,"pausebetweenwtstepsmin"),1) mailtype=automationdbmod.searchdata("element",element,"mailalerttype") averageminutes=hardwaremod.tonumber(automationdbmod.searchdata("element",element,"averagesample"),1) mathoperation=automationdbmod.searchdata("element",element,"mathoperation") # check sensor timetrigger sensorcontrolcommand=hardwaremod.searchdata(hardwaremod.HW_INFO_NAME,refsensor,hardwaremod.HW_CTRL_CMD) logger.info('Sensor control command: %s , Sensor: %s', sensorcontrolcommand, sensor) if sensorcontrolcommand=="returnzero": logger.info('Modify parameter for the timetrigger') #adjust the parameters in the way the activation condition is always obtained sensormaxthreshold=1 sensorminthreshold=-1 maxstepnumber=1 averageminutes=0 # Calculated Variables if maxstepnumber<1: # not possible to proceed print "No Action required, maxstepnumber <1, element: " , element logger.info("No Action required, maxstepnumber <1, element: %s " , element) return interval=(sensormaxthreshold-sensorminthreshold)/maxstepnumber actuatorinterval=(actuatormaxthreshold-actuatorminthreshold)/maxstepnumber P=[] for I in range(0, maxstepnumber+1): P.append(actuatorminthreshold+I*actuatorinterval) # ------------------------ Automation alghoritm if workmode=="Full Auto": # check if inside the allowed time period print "full Auto Mode" logger.info('full auto mode --> %s', element) timeok=isNowInTimePeriod(starttime, endtime, nowtime) print "inside allowed time ", timeok , " starttime ", starttime , " endtime ", endtime if timeok: logger.info('inside allowed time') isok,sensorvalue=sensorreading(sensor,averageminutes,mathoperation) # operation of sensor readings for a number of sample if isok: print "Sensor Value ", sensorvalue if sensorminthreshold<=sensormaxthreshold: print "Algorithm , element: " , element logger.info("Forward algorithm , element: %s " , element) Inde=0 maxs=sensorminthreshold+Inde*interval if sensorvalue<=maxs: status="belowthreshold" logger.info('below Minthreshold') value=P[Inde] # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) Inde=1 for I in range(Inde, maxstepnumber): mins=sensorminthreshold+(I-1)*interval maxs=sensorminthreshold+I*interval if mins<sensorvalue<=maxs: value=P[I] logger.info('inside Range') # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) Inde=maxstepnumber mins=sensorminthreshold+(Inde-1)*interval if mins<sensorvalue: print "INDE:",Inde value=P[Inde] logger.info('beyond Range') # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) # END MAIN ALGORITHM else: # to be added case of inverse sensor condition, where the sensorminthreshold is higher than the sensormaxthreshold print "Reverse Algorithm , element: " , element logger.info("Reverse Algorithm , element: %s " , element) Inde=0 maxs=sensorminthreshold+Inde*interval if sensorvalue>=maxs: status="belowthreshold" logger.info('Above MAXthreshold') value=P[Inde] # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) Inde=Inde+1 for I in range(Inde, maxstepnumber): mins=sensorminthreshold+(I-1)*interval maxs=sensorminthreshold+I*interval if mins>sensorvalue>=maxs: value=P[I] # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) Inde=maxstepnumber mins=sensorminthreshold+(Inde-1)*interval if mins>sensorvalue: print "INDE:",Inde value=P[Inde] # do relevant stuff CheckActivateNotify(element,waitingtime,value,mailtype,sensor,sensorvalue) # END MAIN ALGORITHM - Reverse else: logger.info('No valid calculation operation on the stored sensor data') elif workmode=="Emergency Activation": print "Emergency Activation" elif workmode=="Alert Only": print "Alert Only" # implment Critical alert message in case the sensor value is one interval more than Max_threshold isok,sensorvalue=sensorreading(sensor,averageminutes,mathoperation) # operation of sensor readings for a number of sample if isok: if sensorminthreshold<=sensormaxthreshold: if sensorvalue>sensormaxthreshold+interval: logger.info('sensor %s exceeding limits', sensor) textmessage="CRITICAL: "+ sensor + " reading " + str(sensorvalue) + " exceeding threshold limits, need to check the " + element print textmessage #send alert mail notification alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<2: emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) else: if sensorvalue<sensormaxthreshold+interval: logger.info('sensor %s exceeding limits', sensor) textmessage="CRITICAL: "+ sensor + " reading " + str(sensorvalue) + " exceeding threshold limits, need to check the " + element print textmessage #send alert mail notification alertcounter=statusdataDBmod.read_status_data(AUTO_data,element,"alertcounter") if alertcounter<2: emailmod.sendallmail("alert", textmessage) logger.error(textmessage) statusdataDBmod.write_status_data(AUTO_data,element,"alertcounter",alertcounter+1) return
def 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 connect_network(internetcheck=False, backtoAP=False): # this is the procedure that disable the AP and connect to wifi network connected = False print " try to connect to wifi network" thessid = connect_preconditions( ) # get the first SSID of saved wifi network to connect with and see if the SSID is on air if not thessid == "": print "preconditions to connect to wifi network are met" logger.info('preconditions to connect to wifi network are met') ssids = connectedssid() # get the SSID currently connected if len(ssids) > 0: ssid = ssids[0] else: ssid = "" if not ssid == thessid: print "try to connect to wifi network" logger.info('try to connect to wifi network %s ', thessid) print "try to stop AP services, hostapd, dnsmasq" logger.info('try to stop AP services, hostapd, dnsmasq ') i = 0 done = False while (i < 2) and (not done): done = stop_hostapd() i = i + 1 i = 0 done = False while (i < 2) and (not done): done = stop_dnsmasq() i = i + 1 done = False ssids = [] i = 0 while (i < 3) and (len(ssids) == 0): done = connect_savedwifi( thessid) # return true when the command is executed i = i + 1 if done: time.sleep(1 + i * 5) print "wifi connection attempt ", i print "check connected SSID" logger.info( 'Connection command executed attempt %d, check connected SSID ', i) else: print "Connection command NOT executed properly , attempt ", i logger.info( 'Connection command NOT executed properly , attempt %d ', i) ssids = connectedssid() if len(ssids) > 0: ssid = ssids[0] else: ssid = "" logger.info('NO connected SSID') print "Connected to the SSID ", ssid logger.info('Connected SSID: %s -- ', ssid) addIP("wlan0") else: print "already connected to the SSID ", ssid if len(ssids) == 0: print "No SSID established, fallback to AP mode" # go back and connect in Access point Mode logger.info( 'No Wifi Network connected, no AP connected, going back to Access Point mode' ) connect_AP() connected = False else: logger.info('Connected to Wifi Network %s', ssid) print 'Connected to Wifi Network ', ssid # here it is needed to have a real check of the internet connection as for example google if internetcheck: connected = check_internet_connection(3) if connected: print "Google is reacheable !" logger.info('Google is reacheable ! ') #send first mail print "Send first mail !" logger.info('Send first mail ! ') emailmod.sendallmail( "alert", "System has been reconnected to wifi network") else: if backtoAP: print "Connectivity problem with WiFi network ", ssid[ 0], "going back to wifi access point mode" logger.info( 'Connectivity problem with WiFi network, %s, gong back to wifi access point mode', ssid) connect_AP() else: connected = True logger.info( 'wait and check if the heartbeat job is still scheduled') #pulsesecond=180 #selectedplanmod.waitandcheckheartbeat(pulsesecond) #use CPU cycles as way to delay, cannot be based on clock info, clock jumps happen as soon as NTP is providing the datatime to the system pausecycles = 10000000 for i in range(1, pausecycles): b = i * 0.1 selectedplanmod.checkheartbeat() else: print "No Saved Wifi Network available" logger.info('No Saved Wifi Network available') print "try to fallback to AP mode" # go back and connect in Access point Mode #logger.info('Going back to Access Point mode') #connect_AP() connected = False return connected
def connect_network(internetcheck=False, backtoAP=False): # this is the procedure that disable the AP and connect to wifi network connected = False print " try to connect to wifi network" thessid = connect_preconditions( ) # get the first SSID of saved wifi network to connect with and see if the SSID is on air if not thessid == "": print "preconditions to connect to wifi network are met" logger.info('preconditions to connect to wifi network are met') ssids = connectedssid() # get the SSID currently connected if len(ssids) > 0: ssid = ssids[0] else: ssid = "" if not ssid == thessid: print "try to connect to wifi network" logger.info('try to connect to wifi network %s ', thessid) print "try to stop AP services, hostapd, dnsmasq" logger.info('try to stop AP services, hostapd, dnsmasq ') i = 0 done = False while (i < 2) and (not done): done = stop_hostapd() i = i + 1 i = 0 done = False while (i < 2) and (not done): done = stop_dnsmasq() i = i + 1 done = False ssids = [] i = 0 while (i < 3) and (len(ssids) == 0): done = connect_savedwifi( thessid) # return true when the command is executed i = i + 1 if done: time.sleep(1 + i * 5) print "wifi connection attempt ", i print "check connected SSID" logger.info( 'Connection command executed attempt %d, check connected SSID ', i) else: print "Connection command NOT executed properly , attempt ", i logger.info( 'Connection command NOT executed properly , attempt %d ', i) ssids = connectedssid() if len(ssids) > 0: ssid = ssids[0] else: ssid = "" logger.info('NO connected SSID') print "Connected to the SSID ", ssid logger.info('Connected SSID: %s -- ', ssid) addIP("wlan0") else: print "already connected to the SSID ", ssid if len(ssids) == 0: print "No SSID established, fallback to AP mode" # go back and connect in Access point Mode logger.info( 'No Wifi Network connected, no AP connected, going back to Access Point mode' ) connect_AP() connected = False else: logger.info('Connected to Wifi Network %s', ssid) print 'Connected to Wifi Network ', ssid # here it is needed to have a real check of the internet connection as for example google if internetcheck: connected = check_internet_connection(3) if connected: print "Google is reacheable !" logger.info('Google is reacheable ! ') #send first mail print "Send first mail !" logger.info('Send first mail ! ') emailmod.sendallmail( "alert", "System has been reconnected to wifi network") else: if backtoAP: print "Connectivity problem with WiFi network ", ssid[ 0], "going back to wifi access point mode" logger.info( 'Connectivity problem with WiFi network, %s, gong back to wifi access point mode', ssid) connect_AP() else: connected = True # ALL below not needed anymore since I disabled the NTP network time protocal daemon ***** else: print "No Saved Wifi Network available" logger.info('No Saved Wifi Network available') print "try to fallback to AP mode" # go back and connect in Access point Mode #logger.info('Going back to Access Point mode') #connect_AP() connected = False return connected
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