def check_power_and_internet(run, notification): if run == "boot": just_booted = True elif run == "scheduled": just_booted = False if notification == "notification" or notification == "ifttt": send_notification = True ifttt_notification = False elif notification == "mail": send_notification = False ifttt_notification = False if notification == "ifttt": ifttt_notification = True config_path = os.path.join(os.path.expanduser("~"), ".config/outagedetector") log_path = os.path.join("/var/log/") address_available = False address = "" timestamp_format = "%d-%m-%Y %H-%M-%S" hour_minute_format = "%H:%M" internet_connected = check_internet_connection() if not send_notification: try: with open(os.path.join(config_path, "config.json")) as json_file: mail_json = json.load(json_file) sender = mail_json["sender"] receivers = mail_json["receivers"] smtp_server = mail_json["smtp_server"] keyring.set_keyring(PlaintextKeyring()) password = keyring.get_password("Mail-OutageDetector", sender) if password is None: print("Mail password not found, try running initial configuration again!") exit(1) address = mail_json["house_address"] except FileNotFoundError: print("Mail will not be sent, there is no config file in the folder.") except KeyError: print("Config.json file doesn't have all fields (sender, receivers, smtp_server, house address") else: if not ifttt_notification: keyring.set_keyring(PlaintextKeyring()) push_key = keyring.get_password("PushBullet-OutageDetector", "pushbullet") try: with open(os.path.join(config_path, "config.json")) as json_file: notification_json = json.load(json_file) address = notification_json["house_address"] except FileNotFoundError: print("Configuration file does not exist, try running the initial configuration again!") except KeyError: print("Config.json file doesn't have all fields, try running the initial configuration again!") else: try: with open(os.path.join(config_path, "config.json")) as json_file: notification_json = json.load(json_file) ifttt_name = notification_json["ifttt_event"] address = notification_json["house_address"] except FileNotFoundError: print("Configuration file does not exist, try running the initial configuration again!") except KeyError: print("Config.json file doesn't have all fields, try running the initial configuration again!") keyring.set_keyring(PlaintextKeyring()) api_key = keyring.get_password("IFTTT-OutageDetector", ifttt_name) if address: address_available = True current_timestamp = datetime.now() current_timestring = datetime.strftime(current_timestamp, timestamp_format) current_hour_min = datetime.strftime(current_timestamp, hour_minute_format) try: with open(os.path.join(log_path, "outagedetector_last_timestamp.txt")) as file: read_string = file.read() except FileNotFoundError: read_string = "" file_data = read_string.split(",") try: last_power_timestring = file_data[0] last_internet_timestring = file_data[1] last_argument = file_data[2] last_periodicity = int(file_data[3]) except IndexError: last_power_timestring = current_timestring last_internet_timestring = current_timestring last_argument = "N/A" last_periodicity = 0 except ValueError: last_power_timestring = current_timestring last_internet_timestring = current_timestring last_argument = "N/A" last_periodicity = 0 last_power_timestamp = datetime.strptime(last_power_timestring, timestamp_format) periodicity = extract_run_periodicity(run, last_argument, current_timestamp, last_power_timestamp, last_periodicity) with open(os.path.join(log_path, "outagedetector_last_timestamp.txt"), 'w+') as file: if internet_connected: file.write("{},{},{},{}".format(current_timestring, current_timestring, run, periodicity)) else: file.write("{},{},{},{}".format(current_timestring, last_internet_timestring, run, periodicity)) if internet_connected: if just_booted: power_outage_time = int((current_timestamp - last_power_timestamp).total_seconds() / 60) if periodicity > 0: min_outage_time = max(range(0, power_outage_time + 1, periodicity)) else: min_outage_time = 0 notification = "Power was out for {} to {} minutes at {}.".format(min_outage_time, power_outage_time, current_hour_min) if address_available: notification += " Address: {}.".format(address) print("Power was out for {} to {} minutes at {}".format(min_outage_time, power_outage_time, current_timestring)) if send_notification: if ifttt_notification: push.push_to_ifttt(ifttt_name, api_key, notification) else: push.push_to_iOS("Power outage", notification, push_key) else: mail.send_mail(sender, receivers, "Power outage", notification, smtp_server, password) if not last_power_timestring == last_internet_timestring: last_internet_timestamp = datetime.strptime(last_internet_timestring, timestamp_format) internet_downtime = int((current_timestamp - last_internet_timestamp).total_seconds() / 60) if periodicity > 0: min_outage_time = max(range(0, internet_downtime + 1, periodicity)) else: min_outage_time = 0 print("Internet was down for {} to {} minutes at {}".format(min_outage_time, internet_downtime, current_timestring)) notification = "Internet has been down for {} to {} minutes at {}.".format(min_outage_time, internet_downtime, current_hour_min) if address_available: notification += " Address: {}.".format(address) if send_notification: if ifttt_notification: push.push_to_ifttt(ifttt_name, api_key, notification) else: push.push_to_iOS("Internet down", notification, push_key) else: mail.send_mail(sender, receivers, "Internet down", notification, smtp_server, password) print("Script has run at {}. Internet connected: {}. Just booted: {}.".format(current_timestring, internet_connected, just_booted))
def initialize(): config_path = os.path.join(os.path.expanduser("~"), ".config/outagedetector") log_path = os.path.join("/var/log/") if not os.path.exists(config_path): os.makedirs(config_path) if os.path.exists(os.path.join(config_path, "config.json")): result = curate_input("Configuration file already exists. Would you like to reconfigure the script? (y/n) ", ("y", "n")) if result != "y": print("Alright, script should be ready to run. If you run into issues, run the initialization process " "again") exit(1) json_data = {} print("We are going to walk you through setting up this script!") notification_type = curate_input("Would you like to be alerted of an outage through a notification" " on your phone, through mail, or through ifttt? ", ("notification", "mail", "ifttt")) json_data["notification_type"] = notification_type if notification_type == "mail": mail_working = False failed_attempts = 0 while not mail_working: sender_mail_address = None while sender_mail_address is None: sender_mail_address = mail.check_mails(input("Please input the mail address you want to send the " "notification mail from: ")) json_data["sender"] = sender_mail_address keyring.set_keyring(PlaintextKeyring()) keyring.set_password("Mail-OutageDetector", json_data["sender"], getpass.getpass("Type in your password: "******"Please input the mail addresses " "(separated by a comma) to which you want to send " "the notification: ")) json_data["receivers"] = receiver_mail_addresses if "gmail" in json_data["sender"]: json_data["smtp_server"] = "smtp.gmail.com" json_data["port"] = 465 elif "yahoo" in json_data["sender"]: json_data["smtp_server"] = "smtp.mail.yahoo.com" json_data["port"] = 465 else: json_data["smtp_server"] = input("Please enter the SMTP server of your mail provider " "(you can look it up online): ") port_number = "" while not port_number.isdigit(): port_number = input("Type in the port number of the SMTP server: ") json_data["port"] = port_number password = keyring.get_password("Mail-OutageDetector", json_data["sender"]) try: mail.send_mail(json_data["sender"], json_data["receivers"], "Testing mail notification", "Mail sent successfully!", json_data["smtp_server"], password, json_data["port"]) mail_working = True print("Mail has been successfully sent, check your mailbox!") except mail.SMTPAuthenticationError as e: failed_attempts += 1 if failed_attempts >= 3: print("Too many failed attempts, exiting script, try again later!") exit(1) if "BadCredentials" in str(e): print(e) print("Wrong user/password or less secure apps are turned off") elif "InvalidSecondFactor" in str(e): print(e) print("Two factor authentification is not supported! Turn it off and try again!") except socket.gaierror: print("No internet connection, try again later!") exit(1) elif notification_type == "notification": pushbullet_working = False failed_attempts = 0 while not pushbullet_working: try: keyring.set_keyring(PlaintextKeyring()) keyring.set_password("PushBullet-OutageDetector", "pushbullet", getpass.getpass("Input your PushBullet API key: ")) pushbullet_key = keyring.get_password("PushBullet-OutageDetector", "pushbullet") print("Trying to send a notification through PushBullet!") push.push_to_iOS("Testing PushBullet Key", "Test is successful!", pushbullet_key) pushbullet_working = True print("Notification has been successfully sent, check your phone!") except push.errors.InvalidKeyError: failed_attempts += 1 if failed_attempts >= 3: print("Too many failed attempts, exiting script, try again later!") exit(1) print("Key is not valid, try again!") except requests.exceptions.ConnectionError: print("No internet, try reconnecting and running the script again!") exit(1) elif notification_type == "ifttt": ifttt_working = False failed_attempts = 0 while not ifttt_working: try: ifttt_name = input("Input your IFTTT event name: ") keyring.set_keyring(PlaintextKeyring()) keyring.set_password("IFTTT-OutageDetector", ifttt_name, getpass.getpass("Input your IFTTT API key: ")) api_key = keyring.get_password("IFTTT-OutageDetector", ifttt_name) print("Trying to send a notification through IFTTT!") push.push_to_ifttt(ifttt_name, api_key, "Testing IFTTT") ifttt_work = curate_input("Did you get the notification? (y/n) ", ("y", "n")) if ifttt_work == "y": ifttt_working = True else: failed_attempts += 1 if failed_attempts >= 3: print("Too many failed attempts, exiting script, try again later!") exit(1) print("Check to make sure you followed the steps correctly and try again.") except requests.exceptions.ConnectionError: print("No internet, try reconnecting and running the script again!") exit(1) json_data["ifttt_event"] = ifttt_name json_data["house_address"] = input("Enter a description of the run location (used to tell you in the " "{} where the outage happened): ".format(notification_type)) with open(os.path.join(config_path, 'config.json'), 'w+') as json_file: json.dump(json_data, json_file) crontab_edit = curate_input("Would you like to setup the script to run automatically " "(it will run at boot time and at 5 minute intervals)? (y/n)", ("y", "n")) if crontab_edit == "y": exec_path = os.path.join(os.path.dirname(sys.executable), "outage_detector") cron_scheduling.schedule_job(exec_path, "--run scheduled --notify {}".format(notification_type), log_path, 5) cron_scheduling.schedule_job(exec_path, "--run boot --notify {}".format(notification_type), log_path, at_boot=True)