def __process_next_sms(self): signal_strength_percentage = '--' time_before_fetch = time.time() try: sms_fetcher = SmsFetcher(self.config['gammuConfigFile'], self.config['gammuConfigSection'], self.config['logDir'] + '/sms-delete.log') signal_strength_percentage = sms_fetcher.get_signal_strength_percentage() sms_messages = sms_fetcher.delete_get_next_sms() except (gammu.ERR_TIMEOUT, gammu.ERR_DEVICENOTEXIST, gammu.ERR_NOTCONNECTED): timeout_after_time = time.time() - time_before_fetch debug("Got exception after {} seconds while trying to fetch/delete next sms (signalStrength: {}%).".format(timeout_after_time, signal_strength_percentage)) raise # re-raise exception so we get the stacktrace to stderr absolute_script_path = os.path.abspath(__file__) if not sms_messages: # would write a log message every minute even if no sms found #debug("No sms found by {} - bye.".format(absolute_script_path)) return TemperatureController.NO_SMS_FOUND debug("Start sms processing (found {} messages) by {}".format(len(sms_messages), absolute_script_path)) sms = sms_messages[0] # set system datetime to sent/received DateTime from received sms if delta is big enough if self.config['systemDatetimeMaxDiffNoUpdateSeconds'] > 0: system_datetime = datetime.now() sms_datetime_naive = sms[0]['DateTime'] delta_datetime = sms_datetime_naive - system_datetime delta_seconds = delta_datetime.total_seconds() if abs(delta_seconds) > self.config['systemDatetimeMaxDiffNoUpdateSeconds']: # example unix date: Thu Nov 28 23:29:53 CET 2014 sms_datetime_unix = sms_datetime_naive.strftime("%a %b %d %H:%M:%S %Y") set_date_cmd = "date -s \"{0}\" > /dev/null".format(sms_datetime_unix) debug("Updating system datetime (delta: {} seconds) using cmd: {}".format(delta_seconds, set_date_cmd)) os.system(set_date_cmd) #else: #debug("system date diff ({} seconds) is not greater than configured delta ({} seconds), skipping updating.".format(delta_seconds, self.config['systemDatetimeMaxDiffNoUpdateSeconds'])) now_string = datetime.now().strftime(DATETIME_FORMAT) sender_number = sms[0]['Number'] sender_message_raw = sms[0]['Text'] sender_message = repr(sender_message_raw) debug(" got sms message from {}: {}".format(sender_number, sender_message)) if self.config['myNumber'] in sender_number: debug(" got sms from my own number - not responding in order to prevent infinite loop. Bye!") return TemperatureController.SMS_IGNORED elif self.config['blacklistSenders']: # empty strings are false in python for blacklist_sender in self.config['blacklistSenders'].split(","): if len(blacklist_sender) > 0 and blacklist_sender in sender_number: debug(" this sender is in blacklist (matched '{}') - ignoring. Bye!".format(blacklist_sender)) return TemperatureController.SMS_IGNORED if len(sms_messages) > 1: debug(" found sms consisting of {} parts - only the first part will be considered.".format(len(sms_messages))) response_message = None if sender_message_raw and sender_message_raw.lower().startswith('temp'): temp_raw = temperaturereader.read_celsius() if temp_raw: temp = round(temp_raw, 1) debug(" responding with temperature: {} Celsius.".format(temp)) response_message = u'Hi! Current temperature here is {0} Celsius ({1}).'.format(temp, now_string) else: debug(" temperature could not be read.") response_message = u'Hi! Temperature sensor is offline, check log files.' elif sender_message_raw and sender_message_raw.lower().startswith('power autocontrol '): message_payload = sender_message_raw[len('power autocontrol '):] parts = message_payload.split(None, 3) success = False if len(parts) >= 2: try: switch_on_temperature = float(parts[0].replace(',', '.')) switch_off_temperature = float(parts[1].replace(',', '.')) except Exception as e: # silently ignore, reply with help message debug(" exception occurred while trying to convert supplied args to float number, ignoring") else: pac = PowerAutocontroller(config_parser) switch_on_temp_before = pac.get_switch_on_temperature() switch_off_temp_before = pac.get_switch_off_temperature() current_temp_raw = temperaturereader.read_celsius() pac.set_switch_onoff_temperatures(CONFIG_FILEPATH, switch_on_temperature, switch_off_temperature) switch_on_temp_after = pac.get_switch_on_temperature() switch_off_temp_after = pac.get_switch_off_temperature() if current_temp_raw: current_temp = round(current_temp_raw, 1) debug(" responding with updated temperature interval [{2}:{3}] (was: [{0}:{1}]), current temperature: {4} Celsius.".format(switch_on_temp_before, switch_off_temp_before, switch_on_temp_after, switch_off_temp_after, current_temp)) response_message = u'Hi! Successfully set temperature interval to [{0}:{1}]. Current temperature is {2}.'.format(switch_on_temp_after, switch_off_temp_after, current_temp) else: debug(" responding with updated temperature interval [{2}:{3}] (was: [{0}:{1}]), current temperature could not be read.".format(switch_on_temp_before, switch_off_temp_before, switch_on_temp_after, switch_off_temp_after)) response_message = u'Hi! Successfully set temperature interval to [{0}:{1}]. Current temperature could not be read.'.format(switch_on_temp_after, switch_off_temp_after) success = True if not success: debug(" couldnt understand 'power autocontrol' message, responding with help message.") response_message = u'Hi! Didnt understand your message, use "power autocontrol 4 12" to enable power between 4 and 12 degrees.' elif sender_message_raw and sender_message_raw.lower().startswith('power'): gpio_channels = [int(channel) for channel in self.config['relayGpioChannels'].split(',')] powerswitcher = PowerSwitcher(gpio_channels=gpio_channels) power_status_before = powerswitcher.get_status_string() requested_state = '' if sender_message_raw.lower().startswith('power on'): requested_state = 'ON' elif sender_message_raw.lower().startswith('power off'): requested_state = 'OFF' manual_switching_allowed = not self.config['powerAutocontrolEnabled'] if manual_switching_allowed and requested_state and requested_state == 'ON': powerswitcher.set_status_on() debug(" power has been set ON") elif manual_switching_allowed and requested_state and requested_state == 'OFF': powerswitcher.set_status_off() debug(" power has been set OFF") else: debug(" power switching not requested/allowed (manual switching allowed? {})".format(manual_switching_allowed)) power_status = powerswitcher.get_status_string() debug(" responding with power status: {1} (was: {0}).".format(power_status_before, power_status)) if requested_state and not manual_switching_allowed: response_message = u'Hi! Power autocontrol is enabled, cannot switch power manually (currently {0}).'.format(power_status) elif requested_state: response_message = u'Hi! Power has been switched {0}, was {1} ({2}).'.format(power_status, power_status_before, now_string) else: response_message = u'Hi! Power is currently {0} ({1}).'.format(power_status, now_string) elif sender_message_raw and sender_message_raw.lower().startswith('systeminfo'): debug(" responding with system info:") up_since = systeminfo.get_last_reboot_date_time() kernelVersion = systeminfo.get_kernel_version() rpiSerialNumber = systeminfo.get_rpi_serial_number() localInetAddress = systeminfo.get_inet_address() gitRevision = systeminfo.get_git_revision() balance_info = self.__get_cached_balance_info(short=True) debug(" system datetime : {}".format(now_string)) debug(" up since : {}".format(up_since)) debug(" kernel version : {}".format(kernelVersion)) debug(" RPi serial : {}".format(rpiSerialNumber)) debug(" inet address : {}".format(localInetAddress)) debug(" git revision : {}".format(gitRevision)) debug(" Signal strength : {}%".format(signal_strength_percentage)) debug(" Balance : {}".format(balance_info)) response_message = u'Hi!\n sysTime: {0}\n uptime: {1}\n kernel: {2}\n serial: {3}\n inet: {4}\n gitRev: {5}\n signal: {6}%\n $$: {7}.'.format(now_string, up_since, kernelVersion, rpiSerialNumber, localInetAddress, gitRevision, signal_strength_percentage, balance_info) elif sender_message_raw and sender_message_raw.lower().startswith('checkbalance'): ussd = self.config['ussdCheckBalance'] self.__update_balance_if_necessary(force=True) balance_info = self.__get_cached_balance_info() debug(" responding with USSD reply for {}:".format(ussd)) debug(" " + balance_info.encode('ascii', 'replace')) response_message = u'Hi! Current balance info:\n{0}'.format(balance_info) else: debug(" not recognized, answering with help message.") response_message = u"Hi! 'temp' to get current temperature, 'power' (+' on'/' off') to get (change) power status. Other commands: 'systeminfo', 'checkbalance'." time_before_send = time.time() try: sms_sender = SmsSender(self.config['gammuConfigFile'], self.config['gammuConfigSection']) sms_sender.send_sms(response_message, sender_number) return TemperatureController.SMS_PROCESSED except (gammu.ERR_UNKNOWN): timeout_after_time = time.time() - time_before_send debug("Got exception after {} seconds while trying to send sms.".format(timeout_after_time)) raise # re-raise exception so we get the stacktrace to stderr
if uptime > uptime_threshold: # otherwise allow reboot script to run completely to clean up etc. config_parser = ConfigParser.SafeConfigParser() config_parser.read(CONFIG_FILEPATH) pgrep_pattern = 'python .*' + os.path.basename(__file__) + '\\\'' pgrep_pids = systeminfo.get_pgrep_pids(pgrep_pattern) if len(pgrep_pids) < 1: debug("pgrep pattern wrong, my own script process not found: {}". format(pgrep_pattern)) elif len(pgrep_pids) == 1 and pgrep_pids[0] == os.getpid(): debug( "START no other pid found for this script (PID: {}), going ahead with running power autocontroller..." .format(pgrep_pids)) power_autocontroller = PowerAutocontroller(config_parser) current_temp_raw = temperaturereader.read_celsius() power_autocontroller.run(current_temp_raw) debug("DONE running power autocontroller.") else: debug( "Found other processes already running this script (PIDs: {}), skipping this script run." .format(pgrep_pids)) else: debug( "Uptime ({0} seconds) is less than {1} seconds, skipping power autocontrolling." .format(uptime, uptime_threshold))