def test_delete_not_crashing(path=None): # although in above test we just use/interact with Keyring without specifying # any custom one, there we do not change it so I guess it is ok. Here we want # a real keyring backend which we will alter from keyrings.alt.file import PlaintextKeyring kb = PlaintextKeyring() kb.filename = path keyring = Keyring(keyring_backend=kb) cred = UserPassword("test1", keyring=keyring) cred.set(user="******", password="******") ok_file_has_content(path, ".*test1.*", re_=True) # keyring backend saves where we expect # manually delete one component of the credential cred._keyring.delete(cred.name, next(iter(cred._FIELDS))) # now delete entire credential -- we must not crash cred.delete() try: ok_file_has_content(path, ".*test1.*", re_=True) # keyring backend saves where we expect raise AssertionError("keyring still has our key") except AssertionError: pass
def setup_virtual_cc(virtual_name): """ to have multiple instances running at the same time """ virtual_dir = os.path.join(os.path.expanduser('~'), 'virtual-crosscloud', virtual_name) config.log_dir = os.path.join(virtual_dir, 'log') config.sync_root = os.path.join(virtual_dir, 'sync_root') config.config_dir = os.path.join(virtual_dir, 'config') config.cache_dir = os.path.join(virtual_dir, 'cache') config.private_key_path = os.path.join(virtual_dir, 'private.pem') config.public_key_path = os.path.join(virtual_dir, 'public.pub') config.lock_file = os.path.join(virtual_dir, 'lock_file') config.config_file = os.path.join(config.config_dir, 'config.ini') plaintext = PlaintextKeyring() plaintext.file_path = os.path.join(config.config_dir, 'keyring.ini') keyring.set_keyring(plaintext)
def setup_method(self): self.PROGNAME = totp_generator.__progname__ self.VERSION = totp_generator.__version__ # force keyring to use tmpfile PlaintextKeyring.file_path = self.tmp_keyring_file = tempfile.mktemp() self.keyring_generator = KeyringTotpGenerator(force_keyring=PlaintextKeyring()) self.test_data = import_test_data()
def setUp(self): keyring.set_keyring(PlaintextKeyring()) self.env = EnvironmentVarGuard() self.temp_file = tempfile.NamedTemporaryFile() test_path = os.path.dirname(os.path.realpath(__file__)) self.env['XDG_DATA_HOME'] = test_path self.env['XDG_CONFIG_HOME'] = test_path
def save_session(self, **save_session_kwargs): if self.SESSION_ARG_KEYNAME not in save_session_kwargs: raise ValueError( '"%s" must be specified in save_session() argument.' % self.SESSION_ARG_KEYNAME) data = base64.b64encode( zlib.compress(pickle.dumps(self, self.PICKLE_PROTOCOL))).decode('utf-8') keyring.set_keyring(PlaintextKeyring()) keyring.set_password(self.KEYRING_SERVICE_NAME, save_session_kwargs[self.SESSION_ARG_KEYNAME], data)
def set_keyring(self): if platform.system() == WINDOWS: keyring.set_keyring(WinVaultKeyring()) elif os.environ.get(OVERRIDE_KEYRING_ENV_VAR ) == "true": # Used in builds when running tests keyring.set_keyring(PlaintextKeyring()) elif platform.system() == MAC: keyring.set_keyring(keyring.backends.OS_X.Keyring()) elif platform.system() == LINUX: keyring.set_keyring(FiggyKeyring()) else: Utils.stc_error_exit( "Only OSX and MAC and Linux with installed SecretStorage are supported for " "OKTA + Keyring integration.")
def load_session(**load_session_kwargs): """ :param dict[str, str] load_session_kwargs: :return onedrived.od_api_session.OneDriveAPISession: """ keyarg = OneDriveAPISession.SESSION_ARG_KEYNAME if keyarg not in load_session_kwargs: raise ValueError( '"%s" must be specified in load_session() argument.' % keyarg) keyring.set_keyring(PlaintextKeyring()) saved_data = keyring.get_password( OneDriveAPISession.KEYRING_SERVICE_NAME, load_session_kwargs[keyarg]) if saved_data is None: raise ValueError("Don't find anything") data = zlib.decompress(base64.b64decode(saved_data.encode('utf-8'))) return pickle.loads(data)
async def async_setup(hass, config): """Set up this component using YAML.""" if config.get(DOMAIN) is None: # We get her if the integration is set up using config flow return True # Print startup message # Check that all required files are present file_check = await check_files(hass) if not file_check: return False # Create DATA dict hass.data[DOMAIN_DATA] = {} # Get "global" configuration. creds = config[DOMAIN].get(CONF_CREDENTIALS_LOCATION) default_list = config[DOMAIN].get(CONF_DEFAULT_LIST) force_login = config[DOMAIN].get(CONF_FORCE_LOGIN) hass.data[DOMAIN_DATA]["default_list"] = default_list # Configure the client. try: kr = PlaintextKeyring() keyring.set_keyring(kr) _LOGGER.info('keyring : {}'.format(kr)) gtasks_obj = Gtasks(open_browser=False, force_login=force_login, credentials_location=creds, two_steps=True) hass.data[DOMAIN_DATA]["auth_url"] = gtasks_obj.auth_url() hass.data[DOMAIN_DATA]["gtasks_obj"] = gtasks_obj except Exception as e: _LOGGER.exception(e) return False return True
import test.framework.systemtools as s import test.framework.toolchain as tc import test.framework.toolchainvariables as tcv import test.framework.toy_build as t import test.framework.type_checking as et import test.framework.tweak as tw import test.framework.variables as v import test.framework.yeb as y # set plain text key ring to be used, # so a GitHub token stored in it can be obtained without having to provide a password try: # with recent versions of keyring, PlaintextKeyring comes from keyrings.alt import keyring from keyrings.alt.file import PlaintextKeyring keyring.set_keyring(PlaintextKeyring()) except ImportError: try: # with old versions of keyring, PlaintextKeyring comes from keyring.backends import keyring from keyring.backends.file import PlaintextKeyring keyring.set_keyring(PlaintextKeyring()) except ImportError: pass # disable all logging to significantly speed up tests fancylogger.disableDefaultHandlers() fancylogger.setLogLevelError() # make sure temporary files can be created/used try:
def __init__(self): keyring.set_keyring(PlaintextKeyring()) self.yag = yagmail.SMTP( {'*****@*****.**': 'RSTSolutions-IoT Hub'}) self.email_list = ['*****@*****.**']
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 _main(argv=None): if sys.version_info < (3, 5): print( "Error: Your version of Python is too old, 3.5+ is required: %d.%d.%d" % sys.version_info[:3]) return -1 try: check_runtime_requirements() except RuntimeError as e: print("Error: %s" % (e, )) return -1 # Protect access token and potentially encryption keys block_tracing() if argv is None: argv = sys.argv parser = argparse.ArgumentParser() userspacefs.add_cli_arguments(parser) parser.add_argument("-c", "--config-file", help="config file path") parser.add_argument( "-e", "--encrypted-folder", dest='encrypted_folders', type=parse_encrypted_folder_arg, default=[], action='append', help= "relative paths of encrypted folders, can be used multiple times. requires safefs" ) parser.add_argument( "--print-default-config-file", action='store_true', help="print default config file path to standard out and quit") parser.add_argument("--cache-dir", help="file cache directory") parser.add_argument("mount_point", nargs='?') args = parser.parse_args(argv[1:]) try: version = pkg_resources.require("dbxfs")[0].version except Exception: log.warning("Failed to get version", exc_info=True) version = '' if version: try: with urllib.request.urlopen( "https://pypi.org/pypi/dbxfs/json") as f: rversion = json.load(io.TextIOWrapper(f))['info']['version'] if rversion != version: print( "\033[0;31m\033[1mWarning: dbxfs is out of date (%s vs %s), upgrade with 'pip3 install --upgrade dbxfs'\033[0;0m" % (rversion, version)) except Exception: log.warning("Failed to get most recent version", exc_info=True) config_dir = appdirs.user_config_dir(APP_NAME) if args.config_file is not None: config_file = args.config_file else: config_file = os.path.join(config_dir, "config.json") if args.print_default_config_file: print(config_file) return 0 try: os.makedirs(config_dir, exist_ok=True) except OSError as e: print("Unable to create configuration directory: %s" % (e, )) return -1 config = {} try: f = open(config_file) except IOError as e: if e.errno != errno.ENOENT: raise else: try: with f: config = json.load(f) except ValueError as e: print("Config file %r is not valid json: %s" % (config_file, e)) return -1 cache_folder = args.cache_dir if cache_folder is None: cache_folder = config.get("cache_dir") mount_point = args.mount_point if mount_point is None: mount_point = config.get("mount_point") if not args.smb_no_mount and mount_point is None: parser.print_usage() print("%s: error: please provide the mount_point argument" % (os.path.basename(argv[0]), )) return 1 encrypted_folders = config.get("encrypted_folders", []) + args.encrypted_folders if safefs_wrap_create_fs is None and encrypted_folders: print( "safefs not installed, can't transparently decrypt encrypted folders" ) return 1 access_token = None save_access_token = False save_config = False access_token_command = config.get("access_token_command", None) if access_token_command is not None: print("Running %r for access token" % (' '.join(access_token_command), )) try: access_token = subprocess.check_output( access_token_command).decode("utf-8") except UnicodeDecodeError: print("Access token command output is not utf-8 encoded") return -1 except TypeError: print("Bad access token command: %r, " % (access_token_command, )) return -1 # NB: access tokens never contain white-space and the access token # command often accidentally appends a newline character. access_token = access_token.strip() if access_token is None: keyring_user = config.get("keyring_user", None) if keyring_user is not None: try: access_token = keyring.get_password(APP_NAME, keyring_user) except KeyringError as e: print("Failed to get access token from keyring: %s" % (e, )) if access_token is None: access_token_privy = config.get("access_token_privy", None) if access_token_privy is not None: passwd = None while True: passwd = getpass.getpass( "Enter access token passphrase (not your Dropbox password) (Ctrl-C to quit): " ) try: access_token = privy.peek(access_token_privy, passwd).decode('utf-8') except ValueError: if not yes_no_input( "Incorrect password, create new access token?"): continue break del passwd try_directly = False while True: if access_token is None: save_access_token = True if (access_token is None and try_directly and yes_no_input( "Want to try entering the access token directly?")): print("Go to https://dropbox.com/developers/apps to " "create an app and generate a personal access token.") while True: access_token = getpass.getpass( "Enter Access token (Ctrl-C to quit): ") if not access_token: print("Access tokens cannot be empty") continue break if access_token is None: auth_flow = dropbox.DropboxOAuth2FlowNoRedirect( APP_KEY, APP_SECRET) authorize_url = auth_flow.start() print("We need an access token. Perform the following steps:") print("1. Go to " + authorize_url) print("2. Click \"Allow\" (you may have to log in first)") print("3. Copy the authorization code.") while True: auth_code = input( "Enter authorization code (Ctrl-C to quit): ") if not auth_code: print("Authorization code cannot be empty") continue break try: oauth_result = auth_flow.finish(auth_code) except Exception as e: print("Authorization code was invalid!") try_directly = True continue access_token = oauth_result.access_token # test out access token try: dropbox.Dropbox(access_token).users_get_current_account() except (dropbox.exceptions.BadInputError, dropbox.exceptions.AuthError, ValueError) as e: print("Error using access token: %s" % (e, )) access_token = None try_directly = True except OSError: if not yes_no_input("Error connecting to Dropbox, Try again?"): return 1 else: break if save_access_token and yes_no_input( "We're all connected. Do you want to save your credentials for future runs?", default_yes=True): keyring_user = ''.join( [random.choice("asdfghjklzxcvbnmqwertyuiop") for _ in range(24)]) if not yes_no_input( "Do you want to encrypt your credentials with a password?", default_yes=True): from keyrings.alt.file import PlaintextKeyring keyring.set_keyring(PlaintextKeyring()) try: keyring.set_password(APP_NAME, keyring_user, access_token) except (KeyringError, RuntimeError) as e: print( "We need a passphrase to encrypt your access token before we can save it." ) print( "Warning: Your access token passphrase must contain enough randomness to be resistent to hacking. You can read this for more info: https://blogs.dropbox.com/tech/2012/04/zxcvbn-realistic-password-strength-estimation/" ) while True: pass_ = getpass.getpass("Enter new access token passphrase: ") pass2_ = getpass.getpass( "Enter new access token passphrase (again): ") if pass_ != pass2_: print("Passphrases didn't match, please re-enter") else: del pass2_ break config.pop('keyring_user', None) config['access_token_privy'] = privy.hide( access_token.encode('utf-8'), pass_, server=False) del pass_ save_config = True else: config.pop('access_token_privy', None) config['keyring_user'] = keyring_user save_config = True if not config.get("asked_send_error_reports", False): if yes_no_input( "Would you like to help us improve %s by providing anonymous error reports?" % (APP_NAME, ), default_yes=True): config['send_error_reports'] = True config['asked_send_error_reports'] = True save_config = True if save_access_token and yes_no_input( "Do you want \"%s\" to be the default mount point?" % (mount_point, ), default_yes=True): config['mount_point'] = mount_point save_config = True if save_config: with open(config_file, "w") as f: json.dump(config, f) log.info("Starting %s...", APP_NAME) if config.get('send_error_reports', False): try: sentry_sdk.init( "https://[email protected]/1293235", release='%s@%s' % (APP_NAME, version), with_locals=False) except Exception: log.warning("Failed to initialize sentry", exc_info=True) if cache_folder is None: cache_folder = os.path.join(appdirs.user_cache_dir(APP_NAME), "file_cache") try: os.makedirs(cache_folder, exist_ok=True) except OSError: log.warning( "Failed to create cache folder, running without file cache") cache_folder = None log.debug("Using default cache path %s", cache_folder) else: if not os.path.isdir(cache_folder): print( "User-provided \"cache_dir\" setting doesn't refer to a directory: \"%s\"" % (cache_folder, )) return 1 log.debug("Using custom cache path %s", cache_folder) def create_fs(): fs = CachingFileSystem(DropboxFileSystem(access_token), cache_folder=cache_folder) # From a purity standpoint the following layer ideally would # go between the caching fs and dropbox fs, but because the # contract between those two is highly specialized, just put # it on top fs = TranslateIgnoredFilesFileSystem(fs) if sys.platform == 'darwin': fs = DisableQuickLookFileSystem(fs) return fs if safefs_wrap_create_fs is not None: create_fs = safefs_wrap_create_fs(create_fs, encrypted_folders) if not os.path.exists(mount_point): if yes_no_input( "Mount point \"%s\" doesn't exist, do you want to create it?" % (mount_point, ), default_yes=True): try: os.makedirs(mount_point, exist_ok=True) except OSError as e: print("Unable to create mount point: %s" % (e, )) return -1 return userspacefs.simple_main( mount_point, "dbxfs", create_fs, args, on_new_process=None if BLOCK_TRACING_INHERITS else block_tracing)
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)
def main(): """ Main processing loop """ # pylint: disable=global-statement # use of global statement here is required to allow main() to set the value based on passed arguments to the program global DEBUG, INFLUX_PASSWORD # Get the passwords from the plain text keyring keyring.set_keyring(PlaintextKeyring()) mqtt_password = keyring.get_password(MQTT_HOST, MQTT_USER) INFLUX_PASSWORD = keyring.get_password(INFLUX_HOST, INFLUX_USER) try: pid_file = os.environ['PIDFILE'] except: pid_file = "null" args = parse_args() # Setup logging if args.D: DEBUG = True set_logging('debug') logging.debug("Running in debug mode, not writing data") else: DEBUG = False set_logging('info') if os.path.exists(pid_file): logging.error("PID already exists. Is getsolar already running?") logging.error( "Either, stop the running process or remove %s or run with the debug flag set (-D)", pid_file) sys.exit(2) else: write_pid_file(pid_file) # Connect to MQTT m_d = mqtt.Client(MQTT_CLIENT_NAME) m_d.connected_flag = False m_d.error_code = 0 m_d.on_connect = on_connect # bind call back function m_d.on_disconnect = on_disconnect m_d.on_log = on_log m_d.username_pw_set(MQTT_USER, mqtt_password) m_d.connect(MQTT_HOST, int(MQTT_PORT)) m_d.loop_start() retry = MAX_RETRIES while not m_d.connected_flag: if retry == 0: # wait in loop for MAX_RETRIES sys.exit("Connect failed with error", m_d.error_code) else: if m_d.error_code == 5: sys.exit("Authorisation Failure" + mqtt_password) time.sleep(1) retry -= 1 # Connect to two InfluxDB databases # DB 1 = Home Assistant database for one minute logging of power and energy data # DB 2 = Powerlogging for 10s logging of power only d_d = InfluxDBClient(INFLUX_HOST, INFLUX_PORT, INFLUX_USER, INFLUX_PASSWORD, INFLUX_DB_ALL) d_p = InfluxDBClient(INFLUX_HOST, INFLUX_PORT, INFLUX_USER, INFLUX_PASSWORD, INFLUX_DB_POWER) inv_data = InverterData() # Initialise cycle counter and number of retries counter = MAX_COUNTER retry = MAX_RETRIES # Connect to solaredge modbus inverter logging.debug("Connect to device. Host " + args.i + " Port " + str(args.p) + " Timeout " + str(args.t) + " Unit " + str(args.u)) s_d = solaredge_modbus.Inverter(host=args.i, port=args.p, timeout=args.t, unit=args.u) # s_d.connect() # Try up to MAX_RETRIES times to read data from the inverter while retry != 0: if not s_d.connected(): retry -= 1 time.sleep(WAIT_TIME) logging.debug("Retry. Connect to device. Host " + args.i + " Port " + str(args.p) + " Timeout " + str(args.t) + " Unit " + str(args.u)) s_d = solaredge_modbus.Inverter(host=args.i, port=args.p, timeout=args.t, unit=args.u) else: retry = MAX_RETRIES # Read registers logging.debug("Reading data - cycle %s", counter) inv_data.update(s_d) inv_data.write_power(d_p) if counter == 0: inv_data.write_ha(m_d, d_d) counter = 5 else: counter -= 1 time.sleep(SLEEP_TIME) logging.error("Too many retries") rm_pid_file(pid_file) sys.exit(2)