def run_sender(): """ Request a reading every 30 seconds """ global last_send_time sender_log = logging.data_logging() sender_log.log_filename = "shower_sender-" + todays_date_string() + ".csv" sender_log.auto_add_date = True sender_log.add_log("Starting Sender thread") while True: sender_log.log_filename = "shower_sender-" + todays_date_string() + ".csv" controllable = check_controller_state()['Controlled'] # Controlled is always a subset of monitored monitoring = check_controller_state()['Monitored'] sender_log.add_log(controllable) #if controllable or monitoring: # request_reading() time.sleep(reading_period) last_send_time = datetime.datetime.now() # For the watchdog
def run_check_pump_turn_on(): """ Wait until the time has elapsed, and send the on signal to the pump relay """ global current_pump_state global next_on_time pump_on_log = logging.data_logging() pump_on_log.auto_add_date = True pump_on_log.log_filename = "shower_pump_control-" + todays_date_string() + ".csv" pump_on_log.add_log("Starting pump on monitor thread") while True: current_time = datetime.datetime.now() # pump_on_log.add_log(str(current_time) + "," + str(next_on_time) + "," + str(current_pump_state)) if (current_time > next_on_time) and not current_pump_state: set_pump_state(True) pump_on_log.add_log("Turned pump on") sendmail.send("Pump turned back on", "") time.sleep(30)
def run_sender(): """ Request a reading every 30 seconds """ global last_send_time sender_log = logging.data_logging() sender_log.log_filename = "shower_sender-" + todays_date_string() + ".csv" sender_log.auto_add_date = True sender_log.add_log("Starting Sender thread") while True: sender_log.log_filename = "shower_sender-" + todays_date_string( ) + ".csv" controllable = check_controller_state()[ 'Controlled'] # Controlled is always a subset of monitored monitoring = check_controller_state()['Monitored'] sender_log.add_log(controllable) #if controllable or monitoring: # request_reading() time.sleep(reading_period) last_send_time = datetime.datetime.now() # For the watchdog
def run_check_pump_turn_on(): """ Wait until the time has elapsed, and send the on signal to the pump relay """ global current_pump_state global next_on_time pump_on_log = logging.data_logging() pump_on_log.auto_add_date = True pump_on_log.log_filename = "shower_pump_control-" + todays_date_string( ) + ".csv" pump_on_log.add_log("Starting pump on monitor thread") while True: current_time = datetime.datetime.now() # pump_on_log.add_log(str(current_time) + "," + str(next_on_time) + "," + str(current_pump_state)) if (current_time > next_on_time) and not current_pump_state: set_pump_state(True) pump_on_log.add_log("Turned pump on") sendmail.send("Pump turned back on", "") time.sleep(30)
def set_pump_state(setting): """ Turn the shower pump on or off """ pump_log = logging.data_logging() pump_log.auto_add_date = True pump_log.log_filename = "shower_pump-" + todays_date_string() + ".csv" global current_pump_state global transaction_number log_message = "pump off" switch_message = str(transaction_number) + ',' + RELAY_OFF_MESSAGE if setting: log_message = "pump on" switch_message = str(transaction_number) + ',' + RELAY_ON_MESSAGE print('Switch message ' + switch_message) try: send_socket.sendto(switch_message, LW_IP_ADDRESS) current_pump_state = setting print("Set pump to " + str(current_pump_state)) # Should get a reply with the transaction number transaction_number += 1 f = open('logs/transaction.txt', 'w') f.write(str(transaction_number) + '\n') f.close() # Send again, sometimes the signal doesn't get through time.sleep(3) send_socket.sendto(switch_message, LW_IP_ADDRESS) # Send again, sometimes the signal doesn't get through #time.sleep(3) #send_socket.sendto(switch_message, LW_IP_ADDRESS) except Exception as err: sendmail.send("Exception LightwaveRF UDP Send pump switch", str(err)) pump_log.add_log("Turned " + log_message)
def run_listener(): """ The main program to listen for sockets data """ global current_pump_state global next_on_time global max_on_time global last_receive_time global accumulated_on_time global break_count global reset_period global do_electricity_check global electricity_check_time listener_log = logging.data_logging() listener_log.auto_add_date = True listener_log.add_log("Starting Shower Listener") debug_log = logging.data_logging() debug_log.auto_add_date = True trace_log = logging.data_logging() trace_log.auto_add_date = True # The new protocol is that the wifi link sends the energy reading every 15 seconds. It is not necessary # to request a reading receive_socket.bind(('0.0.0.0', UDP_LISTEN_PORT)) receive_socket.settimeout(20) shower_state = False start_time = datetime.datetime.now() current_pump_state = False accumulated_on_time = 0 # Total number of seconds the shower is on for break_count = 0 # Keep track of break periods, if the shower is turned off reading_time = datetime.datetime.now() sent_old_message = False # Old format reading - something is wrong sent_no_use_message = False # no usage today last_string = '' data = '' while True: try: listener_log.log_filename = "shower_listener-" + todays_date_string() + ".csv" debug_log.log_filename = "pump_state-" + todays_date_string() + '.csv' trace_log.log_filename = 'data_trace-' + todays_date_string() + '.csv' # A socket is only received when the sender requests one listener_log.log_filename = "shower_listener-" + todays_date_string() + ".csv" data, address = receive_socket.recvfrom(1024) # Parameter is buffer size print(data) got_data = False current_time = datetime.datetime.now() if current_time.hour == 0: sent_no_use_message = False sent_old_message = False # Ensure sent every day until fixed if str(data).find('*!') >= 0: # Complex format got_data = True # The data contains the *! string before the main data. # We also get replies from the device such as 100,OK print('Received: ') print(data) #string format: # *!{"trans":23368,"mac":"03:34:7A","time":1415084916,"prod":"pwrMtr","serial":"8A20FE","signal":79,"type":"energy","cUse":0,"maxUse":342,"todUse":22,"yesUse":81} #region data parsing last_string = "Receive: " + data + " end" #new format is a binary representation of a dictionary #Convert from binary val = data.decode() val = val.replace('*!', '') #replace the header d = ast.literal_eval(val) #get the data as a dictionary out_string = current_time.strftime("%d-%m-%Y %h:%M%s") + "," + data print(out_string) # With the current firmware (2.91Y), once an hour the hub itself will broadcast its details: # Data: *!{"trans":51877,"mac":"03:34:7A","time":1442299077,"type":"hub","prod":"wfl","fw":"U2.91Y","uptime":781402,"timeZone":0,"lat":0.00,"long":-1.86,"duskTime":1442340358,"dawnTime":1442296750,"tmrs":1,"evns":0,"run":0,"macs":9,"ip":"192.168.1.40","devs":1} # There is no current usage in this as it is from the hub rather than the energy monitor current_power_reading = 0 try: current_power_reading = d['cUse'] today_use = d['todUse'] if current_time.hour == 23 and int(today_use) == 0 and not sent_no_use_message: sendmail.send('Shower controller problem', 'No apparent usage today, check it out') sent_no_use_message = True except KeyError as e: got_data = False last_string = "split_measurement: " + str(current_power_reading) + " end" #endregion elif str(data).find('=') > 0: # Simple format - 123,?W=0,420,32,100; trace_log.add_log('Old format data:' + str(data)) out_string = data.split('=') if len(out_string) > 1: out_string = out_string[1].split(',') trace_log.add_log('Split data reading: ' + str(out_string[0])) current_power_reading = float(out_string[0]) got_data = True if not sent_old_message: # sendmail.send('Shower problem', 'Getting old format readings from lightwave. Check batteries or link.\n\nIf link is not showing any readings, then the comms is broken.') sent_old_message = True # Turns out the wifi will send out a packet every 15 seconds, but sends 2 in succession. This is due to a bradcast and a unicast #if str(data).find('*!') != -1: if got_data: current_time = datetime.datetime.now() # Time the reading was taken last_receive_time = current_time # For the watchdog time_since_last_reading = (current_time - reading_time).seconds reading_time = current_time print (current_time), print('time since last reading {0}'.format(time_since_last_reading)) print("Current power " + str(current_power_reading)) uploadCOSM.SendToCOSM(str(current_power_reading), "YcfzZVxtMMRdD-d_GIgNinJ1x_qBh963fcORnVu_dMQ", "41189", "0002") listener_log.add_log(str(current_power_reading) + "," + str(max_on_time) + "," + str(no_repeat_period)) if check_controller_state()['Controlled']: # Controlled, not just monitored if current_power_reading > 30: #Shower is on # The shower pump when on is 340 - 342 watts. If we have a partial period where the shower was turned on # or off part way through the period, then we can use this to proportion the time based on # the energy in that period debug_log.add_log(str(current_power_reading)) time_ratio = current_power_reading / 340.0 # force float if time_ratio > 0.95: time_ratio = 1 actual_seconds = time_since_last_reading * time_ratio accumulated_on_time += actual_seconds break_count = 0 print("Current power: " + str(current_power_reading)) current_pump_state = True # Just in case overridden the setting manually if not shower_state: #Just turned it on #sendmail.send("Shower on", "") # Don't use time now, as there has been some elapsed time since getting current_time start_time = current_time listener_log.add_log("Pump On") shower_state = True pump_on_period = (datetime.datetime.now() - start_time) log_data = 'On Period,{0},accumulated,{1:.1f}'.format(pump_on_period.seconds, accumulated_on_time) listener_log.add_log(log_data) if accumulated_on_time > max_on_time: #if pump_on_period.seconds > max_on_time: sendmail.send("Shower controller", "Turning pump off. On for accumulated {0:.1f}, Max time {1}".format( accumulated_on_time, max_on_time)) set_pump_state(False) # Tuesday to friday don't turn on until 1800 #if 1 <= current_time.weekday() <= 4 and current_time.hour < 17: # new_on_time = current_time.replace(hour=18, minute=0, second=0) # next_on_time = new_on_time #else: next_on_time = current_time + timedelta(seconds=no_repeat_period) sendmail.send("Shower controller next on", str(next_on_time)) listener_log.add_log("Killing pump") else: # energy < 30 if shower_state: # Was on, now gone to off #time_on = (datetime.datetime.now() - start_time) sendmail.send("Shower off", "Number seconds on: {0:.1f}".format(accumulated_on_time)) # time_on.seconds)) listener_log.add_log( "Pump turned off,{0:.1f}".format(accumulated_on_time)) # time_on.seconds)) electricity_check_time = current_time + timedelta(minutes=10) do_electricity_check = True shower_state = False break_count += time_since_last_reading #listener_log.add_log('Break {0:.1f},Accumulated {1:.1f}'.format(break_count, accumulated_on_time)) #print('Break count ' + str(break_count)) #print('Accumulated ' + str(accumulated_on_time)) if break_count > reset_period and accumulated_on_time > 0: print('Resetting break count') accumulated_on_time = 0 break_count = 0 if current_pump_state: #sendmail.send("Shower controller Reset break", "") pass else: # not controlled accumulated_on_time = 0 break_count = 0 except Exception as listener_exception: message = "Exception details:\n" message += "Last string: " + last_string message += "\n" message += "Data: " message += data message += str(type(listener_exception)) message += str(listener_exception.args) message += str(listener_exception) message += "\n\n" message += str(traceback.print_exc()) # sendmail.send("Shower control - Exception in listener thread", message) f = open ('/home/pi/scripts/shower/logs/exceptions.txt', 'a') f.write (str(datetime.datetime.now()) + message + '\n') f.close()
def run_watchdog(): """ Monitor the other threads to make sure they are still running No longer in use """ global last_send_time global last_receive_time watchdog_log = logging.data_logging() watchdog_log.log_filename = "shower_watchdog-" + todays_date_string() + ".csv" watchdog_log.auto_add_date = True watchdog_log.add_log("Starting shower watchdog") missed_count = 0 next_check_time = datetime.datetime.now() while True: watchdog_log.log_filename = "shower_watchdog-" + todays_date_string() + ".csv" if datetime.datetime.now() > next_check_time: if check_controller_state()['Monitored']: reading_request_age = datetime.datetime.now() - last_send_time if reading_request_age.seconds > 120: print("Sender has stopped") sendmail.send("Shower monitor problem", "Sender has stopped sending") # and check the last time the listener responded # Allow a short delay for the listener socket to receive the data time.sleep(3) if last_receive_time < last_send_time: # Receive time is before send time, so the data has not been received # The occasional packet will get missed, so give a little tolerance to avoid too many emails missed_count += 1 if missed_count > 1: print("Listener has stopped") data = "Listener has stopped listening:\n\n" data += "Sender last time " + str(last_send_time) + "\n" data += "Listener last time " + str(last_receive_time) sendmail.send("Shower monitor problem", data) next_check_time = datetime.datetime.now() + datetime.timedelta(0, 0, 0, 0, 30) # Try again in 30 minutes else: missed_count = 0 # Send a message to the other Pi try: send_socket.sendto("Hello", PI_IP_ADDRESS) except Exception as err: sendmail.send("Exception LightwaveRF Watchdog Send", str(err)) time.sleep(15) watchdog_log.add_log("Watchdog checked," + str(check_controller_state()))
def check_controller_state(): """ See if we are in a controllable period """ global max_on_time global no_repeat_period controller_log = logging.data_logging() controller_log.log_filename = "controller-times.csv" controller_log.auto_add_date = True current_time = datetime.datetime.now() controllable = False # If the pump is not controlled, it should always be monitored, so that the readings can be uploaded to Xively # The monitor runs between 0600 and 2300 every day monitoring = False if 6 <= current_time.hour < 23: monitoring = True # Special file which is available to control from a web page override_filename = 'home/pi/scripts/shower/shower-override.txt' # override_filename = 'shower-override.txt' special_override = False print('checking pump state\n') print('isfile '), print(os.path.isfile(override_filename)) if os.path.isfile(override_filename): override_file = open(override_filename, 'r') override_data = override_file.readline() override_file.close() print('Override file contents ' + override_data) if override_data.startswith('On'): #Override is set on, doesn't matter about the rest controllable = False special_override = True print('override set by web') else: print('override not set by web') else: print('no override file') if not special_override: # Check the days of the week and times for enabled # Read the config file to get the settings config_file = open('/home/pi/scripts/shower/shower-times.csv', 'r') # config_file = open('shower-times.csv', 'r') config_data = config_file.readlines() line_count = 0 break_loop = False on_time = "05:30" # Need this declared, as it is used in a different iteration of the loop for line in config_data: if break_loop: break line_data = line.split(",") line_count += 1 try: setting = line_data[0].lower().strip() value = line_data[1].lower().strip() if setting == "override" and value == "on": controllable = False controller_log.add_log("Override is on") break_loop = True # If override is on, doesn't matter what the rest of the settings are break if setting == "max_on_time": max_on_time = int(value) continue if setting == "no_repeat_period": no_repeat_period = int(value) continue if setting == 'reset_period': reset_period = int(value) * 60 continue time_setting = line_data[2].strip() # Find the day setting which is today weekday_name = current_time.strftime("%A").lower() if weekday_name == setting: # There can be more than 1 time zone setting in a day, so do a compare after reading each off time # controller_log.add_log(weekday_name + "," + value + "," + time_setting) if value == "on": on_time = time_setting if value == "off": off_time = time_setting # See if the current time is between the last on and off time start_monitor_time = on_time.split(":") end_monitor_time = off_time.split(":") # Check the end time first if current_time.hour > int(end_monitor_time[0]): # Definitely not in the zone # But there could be more time periods for today controllable = False continue if current_time.hour == int(end_monitor_time[0]) and current_time.minute >= int( end_monitor_time[1]): controllable = False continue # Now the start time if current_time.hour < int(start_monitor_time[0]): controllable = False continue if current_time.hour == int(start_monitor_time[0]) and current_time.minute < int( start_monitor_time[1]): controllable = False continue # It must be within the time if it gets here controllable = True break_loop = True break except Exception: pass # Every parse of the file will throw an exception as the fields are not consistent config_file.close() return {'Controlled': controllable, 'Monitored': monitoring}
def run_listener(): """ The main program to listen for sockets data """ global current_pump_state global next_on_time global max_on_time global last_receive_time global accumulated_on_time global break_count global reset_period global do_electricity_check global electricity_check_time listener_log = logging.data_logging() listener_log.auto_add_date = True listener_log.add_log("Starting Shower Listener") debug_log = logging.data_logging() debug_log.auto_add_date = True trace_log = logging.data_logging() trace_log.auto_add_date = True # The new protocol is that the wifi link sends the energy reading every 15 seconds. It is not necessary # to request a reading receive_socket.bind(('0.0.0.0', UDP_LISTEN_PORT)) receive_socket.settimeout(20) shower_state = False start_time = datetime.datetime.now() current_pump_state = False accumulated_on_time = 0 # Total number of seconds the shower is on for break_count = 0 # Keep track of break periods, if the shower is turned off reading_time = datetime.datetime.now() sent_old_message = False # Old format reading - something is wrong sent_no_use_message = False # no usage today last_string = '' data = '' while True: try: listener_log.log_filename = "shower_listener-" + todays_date_string( ) + ".csv" debug_log.log_filename = "pump_state-" + todays_date_string( ) + '.csv' trace_log.log_filename = 'data_trace-' + todays_date_string( ) + '.csv' # A socket is only received when the sender requests one listener_log.log_filename = "shower_listener-" + todays_date_string( ) + ".csv" data, address = receive_socket.recvfrom( 1024) # Parameter is buffer size print(data) got_data = False current_time = datetime.datetime.now() if current_time.hour == 0: sent_no_use_message = False sent_old_message = False # Ensure sent every day until fixed if str(data).find('*!') >= 0: # Complex format got_data = True # The data contains the *! string before the main data. # We also get replies from the device such as 100,OK print('Received: ') print(data) #string format: # *!{"trans":23368,"mac":"03:34:7A","time":1415084916,"prod":"pwrMtr","serial":"8A20FE","signal":79,"type":"energy","cUse":0,"maxUse":342,"todUse":22,"yesUse":81} #region data parsing last_string = "Receive: " + data + " end" #new format is a binary representation of a dictionary #Convert from binary val = data.decode() val = val.replace('*!', '') #replace the header d = ast.literal_eval(val) #get the data as a dictionary out_string = current_time.strftime( "%d-%m-%Y %h:%M%s") + "," + data print(out_string) # With the current firmware (2.91Y), once an hour the hub itself will broadcast its details: # Data: *!{"trans":51877,"mac":"03:34:7A","time":1442299077,"type":"hub","prod":"wfl","fw":"U2.91Y","uptime":781402,"timeZone":0,"lat":0.00,"long":-1.86,"duskTime":1442340358,"dawnTime":1442296750,"tmrs":1,"evns":0,"run":0,"macs":9,"ip":"192.168.1.40","devs":1} # There is no current usage in this as it is from the hub rather than the energy monitor current_power_reading = 0 try: current_power_reading = d['cUse'] today_use = d['todUse'] if current_time.hour == 23 and int( today_use) == 0 and not sent_no_use_message: sendmail.send('Shower controller problem', 'No apparent usage today, check it out') sent_no_use_message = True except KeyError as e: got_data = False last_string = "split_measurement: " + str( current_power_reading) + " end" #endregion elif str(data).find('=') > 0: # Simple format - 123,?W=0,420,32,100; trace_log.add_log('Old format data:' + str(data)) out_string = data.split('=') if len(out_string) > 1: out_string = out_string[1].split(',') trace_log.add_log('Split data reading: ' + str(out_string[0])) current_power_reading = float(out_string[0]) got_data = True if not sent_old_message: # sendmail.send('Shower problem', 'Getting old format readings from lightwave. Check batteries or link.\n\nIf link is not showing any readings, then the comms is broken.') sent_old_message = True # Turns out the wifi will send out a packet every 15 seconds, but sends 2 in succession. This is due to a bradcast and a unicast #if str(data).find('*!') != -1: if got_data: current_time = datetime.datetime.now( ) # Time the reading was taken last_receive_time = current_time # For the watchdog time_since_last_reading = (current_time - reading_time).seconds reading_time = current_time print(current_time), print('time since last reading {0}'.format( time_since_last_reading)) print("Current power " + str(current_power_reading)) uploadCOSM.SendToCOSM( str(current_power_reading), "YcfzZVxtMMRdD-d_GIgNinJ1x_qBh963fcORnVu_dMQ", "41189", "0002") listener_log.add_log( str(current_power_reading) + "," + str(max_on_time) + "," + str(no_repeat_period)) if check_controller_state()['Controlled']: # Controlled, not just monitored if current_power_reading > 30: #Shower is on # The shower pump when on is 340 - 342 watts. If we have a partial period where the shower was turned on # or off part way through the period, then we can use this to proportion the time based on # the energy in that period debug_log.add_log(str(current_power_reading)) time_ratio = current_power_reading / 340.0 # force float if time_ratio > 0.95: time_ratio = 1 actual_seconds = time_since_last_reading * time_ratio accumulated_on_time += actual_seconds break_count = 0 print("Current power: " + str(current_power_reading)) current_pump_state = True # Just in case overridden the setting manually if not shower_state: #Just turned it on #sendmail.send("Shower on", "") # Don't use time now, as there has been some elapsed time since getting current_time start_time = current_time listener_log.add_log("Pump On") shower_state = True pump_on_period = (datetime.datetime.now() - start_time) log_data = 'On Period,{0},accumulated,{1:.1f}'.format( pump_on_period.seconds, accumulated_on_time) listener_log.add_log(log_data) if accumulated_on_time > max_on_time: #if pump_on_period.seconds > max_on_time: sendmail.send( "Shower controller", "Turning pump off. On for accumulated {0:.1f}, Max time {1}" .format(accumulated_on_time, max_on_time)) set_pump_state(False) # Tuesday to friday don't turn on until 1800 #if 1 <= current_time.weekday() <= 4 and current_time.hour < 17: # new_on_time = current_time.replace(hour=18, minute=0, second=0) # next_on_time = new_on_time #else: next_on_time = current_time + timedelta( seconds=no_repeat_period) sendmail.send("Shower controller next on", str(next_on_time)) listener_log.add_log("Killing pump") else: # energy < 30 if shower_state: # Was on, now gone to off #time_on = (datetime.datetime.now() - start_time) sendmail.send( "Shower off", "Number seconds on: {0:.1f}".format( accumulated_on_time)) # time_on.seconds)) listener_log.add_log( "Pump turned off,{0:.1f}".format( accumulated_on_time)) # time_on.seconds)) electricity_check_time = current_time + timedelta( minutes=10) do_electricity_check = True shower_state = False break_count += time_since_last_reading #listener_log.add_log('Break {0:.1f},Accumulated {1:.1f}'.format(break_count, accumulated_on_time)) #print('Break count ' + str(break_count)) #print('Accumulated ' + str(accumulated_on_time)) if break_count > reset_period and accumulated_on_time > 0: print('Resetting break count') accumulated_on_time = 0 break_count = 0 if current_pump_state: #sendmail.send("Shower controller Reset break", "") pass else: # not controlled accumulated_on_time = 0 break_count = 0 except Exception as listener_exception: message = "Exception details:\n" message += "Last string: " + last_string message += "\n" message += "Data: " message += data message += str(type(listener_exception)) message += str(listener_exception.args) message += str(listener_exception) message += "\n\n" message += str(traceback.print_exc()) # sendmail.send("Shower control - Exception in listener thread", message) f = open('/home/pi/scripts/shower/logs/exceptions.txt', 'a') f.write(str(datetime.datetime.now()) + message + '\n') f.close()
def run_watchdog(): """ Monitor the other threads to make sure they are still running No longer in use """ global last_send_time global last_receive_time watchdog_log = logging.data_logging() watchdog_log.log_filename = "shower_watchdog-" + todays_date_string( ) + ".csv" watchdog_log.auto_add_date = True watchdog_log.add_log("Starting shower watchdog") missed_count = 0 next_check_time = datetime.datetime.now() while True: watchdog_log.log_filename = "shower_watchdog-" + todays_date_string( ) + ".csv" if datetime.datetime.now() > next_check_time: if check_controller_state()['Monitored']: reading_request_age = datetime.datetime.now() - last_send_time if reading_request_age.seconds > 120: print("Sender has stopped") sendmail.send("Shower monitor problem", "Sender has stopped sending") # and check the last time the listener responded # Allow a short delay for the listener socket to receive the data time.sleep(3) if last_receive_time < last_send_time: # Receive time is before send time, so the data has not been received # The occasional packet will get missed, so give a little tolerance to avoid too many emails missed_count += 1 if missed_count > 1: print("Listener has stopped") data = "Listener has stopped listening:\n\n" data += "Sender last time " + str( last_send_time) + "\n" data += "Listener last time " + str(last_receive_time) sendmail.send("Shower monitor problem", data) next_check_time = datetime.datetime.now( ) + datetime.timedelta(0, 0, 0, 0, 30) # Try again in 30 minutes else: missed_count = 0 # Send a message to the other Pi try: send_socket.sendto("Hello", PI_IP_ADDRESS) except Exception as err: sendmail.send("Exception LightwaveRF Watchdog Send", str(err)) time.sleep(15) watchdog_log.add_log("Watchdog checked," + str(check_controller_state()))
def check_controller_state(): """ See if we are in a controllable period """ global max_on_time global no_repeat_period controller_log = logging.data_logging() controller_log.log_filename = "controller-times.csv" controller_log.auto_add_date = True current_time = datetime.datetime.now() controllable = False # If the pump is not controlled, it should always be monitored, so that the readings can be uploaded to Xively # The monitor runs between 0600 and 2300 every day monitoring = False if 6 <= current_time.hour < 23: monitoring = True # Special file which is available to control from a web page override_filename = 'home/pi/scripts/shower/shower-override.txt' # override_filename = 'shower-override.txt' special_override = False print('checking pump state\n') print('isfile '), print(os.path.isfile(override_filename)) if os.path.isfile(override_filename): override_file = open(override_filename, 'r') override_data = override_file.readline() override_file.close() print('Override file contents ' + override_data) if override_data.startswith('On'): #Override is set on, doesn't matter about the rest controllable = False special_override = True print('override set by web') else: print('override not set by web') else: print('no override file') if not special_override: # Check the days of the week and times for enabled # Read the config file to get the settings config_file = open('/home/pi/scripts/shower/shower-times.csv', 'r') # config_file = open('shower-times.csv', 'r') config_data = config_file.readlines() line_count = 0 break_loop = False on_time = "05:30" # Need this declared, as it is used in a different iteration of the loop for line in config_data: if break_loop: break line_data = line.split(",") line_count += 1 try: setting = line_data[0].lower().strip() value = line_data[1].lower().strip() if setting == "override" and value == "on": controllable = False controller_log.add_log("Override is on") break_loop = True # If override is on, doesn't matter what the rest of the settings are break if setting == "max_on_time": max_on_time = int(value) continue if setting == "no_repeat_period": no_repeat_period = int(value) continue if setting == 'reset_period': reset_period = int(value) * 60 continue time_setting = line_data[2].strip() # Find the day setting which is today weekday_name = current_time.strftime("%A").lower() if weekday_name == setting: # There can be more than 1 time zone setting in a day, so do a compare after reading each off time # controller_log.add_log(weekday_name + "," + value + "," + time_setting) if value == "on": on_time = time_setting if value == "off": off_time = time_setting # See if the current time is between the last on and off time start_monitor_time = on_time.split(":") end_monitor_time = off_time.split(":") # Check the end time first if current_time.hour > int(end_monitor_time[0]): # Definitely not in the zone # But there could be more time periods for today controllable = False continue if current_time.hour == int( end_monitor_time[0] ) and current_time.minute >= int(end_monitor_time[1]): controllable = False continue # Now the start time if current_time.hour < int(start_monitor_time[0]): controllable = False continue if current_time.hour == int( start_monitor_time[0] ) and current_time.minute < int(start_monitor_time[1]): controllable = False continue # It must be within the time if it gets here controllable = True break_loop = True break except Exception: pass # Every parse of the file will throw an exception as the fields are not consistent config_file.close() return {'Controlled': controllable, 'Monitored': monitoring}