예제 #1
0
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))
예제 #2
0
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)