def set_time_filter(self, value): """ Interval in seconds before a new position should be sent to server """ from cp_lib.parse_duration import TimeDuration # handle the "null" or 0 times, as disable value = self._test_value_as_none(value) if value is None: # then disable the distance filter if self.time_filter is not None: self.logger.debug("Disable time_filter") self.time_filter = None else: try: duration = TimeDuration(value) except AttributeError: raise ValueError("Bad Time Filter Value:{}".format(value)) value = duration.get_seconds() # test Min/Max, clamp or throw ValueError value = self._test_value_limits(value, self.TIME_FILTER_LIMITS) if value != self.time_filter: self.time_filter = value self.logger.debug("Set time_filter = {} sec".format(value)) return
def main(self, app_main): """ :param str app_main: the file name, such as "network.tcp_echo" :return int: code for sys.exit() """ # in windows, safer to use time.clock(), but is useless in Linux start_time = time.time() logging.info("Router APP starting: {}".format(app_main)) # follow SDK design to load settings, should be in root of tar.gzip self.settings = load_settings_json() # delay until all desired conditions are met self.start_delay() app_mod = importlib.import_module(app_main) app_base = app_mod.RouterApp(app_main) if True: # app_mod = importlib.import_module(app_main, "RouterApp") # app_mod = importlib.import_module("network.tcp_echo.tcp_echo") # print(app_mod) result = app_base.run() else: result = 0 # see if we should delay before existing exit_delay = self.DEFAULT_EXIT_DELAY if self.SECTION_STARTUP in self.settings: # then we do have a [startup] section in settings.json if self.SETS_EXIT_DELAY in self.settings[self.SECTION_STARTUP]: # how many seconds to wait for boot conditions to be satisfied # here is string, we don't care what yet exit_delay = self.settings[self.SECTION_STARTUP][ self.SETS_EXIT_DELAY].lower() if exit_delay in ('forever', 'loop', 'true'): # we loop forever - use 'uninstall' action to stop while True: app_base.logger.debug("App Finished - Looping forever") time.sleep(self.EXIT_DELAY_PERIOD) elif exit_delay in (None, 'none', 'null', 'false'): # default - no delay at all app_base.logger.info("App exited - MAIN Exiting without delay") else: # if this throws exception, well we exit anyway # use time_duration to handle "300" or "5 min" time_duration = TimeDuration(exit_delay) exit_delay = time_duration.get_seconds() time_diff = time.time() - start_time if time_diff >= exit_delay: # app took longer than 'min delay', so just exist app_base.logger.info("No need for exit delay") else: # else, app was short/fast, delay to reduce restart thrashing app_base.logger.info( "Exit Delay for at least {} seconds".format(exit_delay)) while time_diff < exit_delay: app_base.logger.debug( "Exit Delay, wait at least %d seconds more" % int(exit_delay - time_diff)) time.sleep(self.EXIT_DELAY_PERIOD) time_diff = time.time() - start_time app_base.logger.info("Exit Delay finished") return result
def start_delay(self): """ Delay up to config seconds, waiting for boot conditions to be true :return: None """ # we only delay if at least ONE condition is still not satisfied wait_conditions = 0 time_duration = TimeDuration() # start with the defaults # use time_duration to handle "300" or "5 min" time_duration.parse_time_duration_to_seconds(self.DEF_BOOT_DELAY_SEC) delay_seconds = time_duration.get_seconds() delay_for_valid_time = self.DEF_DELAY_FOR_TIME delay_for_uplink = self.DEF_DELAY_FOR_WAN if self.SECTION_STARTUP in self.settings: # then we do have a [startup] section in settings.json if self.SET_BOOT_DELAY_SEC in self.settings[self.SECTION_STARTUP]: # how many seconds to wait for boot conditions to be satisfied time_duration.parse_time_duration_to_seconds(self.settings[ self.SECTION_STARTUP][self.SET_BOOT_DELAY_SEC]) delay_seconds = time_duration.get_seconds() if self.SET_DELAY_FOR_TIME in self.settings[self.SECTION_STARTUP]: # see if we delay until time.time() is returning valid info, # which prevents initial time-series data from being # generated with bogus 1-1-1970 time-stamps delay_for_valid_time = \ self.settings[self.SECTION_STARTUP][self.SET_DELAY_FOR_TIME] if self.SET_DELAY_FOR_WAN in self.settings[self.SECTION_STARTUP]: # see if we delay until router has a valid WAN uplink, which # prevents cloud clients from mistakenly flipping into # FAULT/RECOVERY modes because they tried to connect to fast delay_for_uplink = self.settings[self.SECTION_STARTUP][ self.SET_DELAY_FOR_WAN] if delay_for_valid_time: wait_conditions += 1 if delay_for_uplink: wait_conditions += 1 # we cannot use clock() because under Linux it means nothing # TODO - what happens when time() jumps? start_time = time.time() while (wait_conditions > 0) and \ (time.time() - start_time) < delay_seconds: # loop until end of time period, or all conditions are okay if delay_for_valid_time and hw_status.router_time_is_valid(): # then check on time, if okay neutralize our conditions delay_for_valid_time = False wait_conditions -= 1 else: logging.debug("Delay - waiting for valid time") if delay_for_uplink and hw_status.router_wan_online(): # then check on wan-uplink, is okay neutralize our conditions delay_for_uplink = False wait_conditions -= 1 else: logging.debug("Delay - waiting for WAN uplink") if wait_conditions > 0: time.sleep(self.BOOT_DELAY_SLEEP) # else we'll break / leave the WHILE loop return
def run_router_app(app_base): """ :param CradlepointAppBase app_base: prepared resources: logger, cs_client :return: """ # logger.debug("Settings({})".format(sets)) # first, confirm no other function using serial value = SerialRedirectorConfig(app_base) value.refresh() if value.enabled(): app_base.logger.error("Serial Redirector Function is Active!") app_base.logger.error("Aborting SDK application") return -3 app_base.logger.debug("Good: Serial Redirector Function is Disabled.") value = SerialGpsConfig(app_base) value.refresh() if value.enabled(): app_base.logger.error("Serial GPS Echo Function is Active!") app_base.logger.error("Aborting SDK application") return -4 app_base.logger.debug("Good: Serial GPS Function is Disabled.") value = SerialGPIOConfig(app_base) value.refresh() if value.enabled(): app_base.logger.error("Serial GPIO Function is Active!") app_base.logger.error("Aborting SDK application") return -5 app_base.logger.debug("Good: Serial GPIO Function is Disabled.") server_loop = ModbusBridge() server_loop.logger = app_base.logger if "modbus_ip" in app_base.settings: temp = app_base.settings["modbus_ip"] if "host_ip" in temp: # assume is string of correct format server_loop.host_ip = clean_string(temp["host_ip"]) if "host_port" in temp: # force to integer server_loop.host_port = parse_integer(temp["host_port"]) if "idle_timeout" in temp: # support seconds, or like '5 min' duration = TimeDuration(clean_string(temp["idle_timeout"])) server_loop.idle_timeout = duration.get_seconds() if "protocol" in temp: value = validate_ia_protocol(clean_string(temp["protocol"])) if value not in (IA_PROTOCOL_MBTCP, IA_PROTOCOL_MBRTU, IA_PROTOCOL_MBASC): raise ValueError("Invalid IP-packed Modbus Protocol {}".format( type(value))) server_loop.host_protocol = value if "modbus_serial" in app_base.settings: temp = app_base.settings["modbus_serial"] if "port_name" in temp: server_loop.serial_name = clean_string(temp["port_name"]) if "baud_rate" in temp: server_loop.serial_baud = parse_integer(temp["baud_rate"]) if "parity" in temp: server_loop.serial_baud = parse_integer(temp["baud_rate"]) if "protocol" in temp: value = validate_ia_protocol(clean_string(temp["protocol"])) # confirm is serial, so RTU or ASCII if value not in (IA_PROTOCOL_MBRTU, IA_PROTOCOL_MBASC): raise ValueError("Invalid Serial Modbus Protocol {}".format( type(value))) server_loop.serial_protocol = value # this should run forever try: result = server_loop.run_loop() except KeyboardInterrupt: result = 0 return result
from cp_lib.load_settings_ini import copy_config_ini_to_json, \ load_sdk_ini_as_dict from cp_lib.parse_duration import TimeDuration copy_config_ini_to_json() app_path = "demo/gps_replay" my_app = CradlepointAppBase(app_path, call_router=False) # force a heavy reload of INI (app base normally only finds JSON) my_app.settings = load_sdk_ini_as_dict(app_path) if len(sys.argv) == 2: # assume is numeric seconds shifter = parse_float(sys.argv[1]) elif len(sys.argv) >= 3: # assume is tagged time, like "15 min" period = TimeDuration(sys.argv[1] + ' ' + sys.argv[2]) shifter = parse_float(period.get_seconds()) else: my_app.logger.warning("You need to append the time in seconds") sys.exit(-1) my_app.logger.info("Time shifter = {} seconds".format(shifter)) _result = run_router_app(my_app, shifter) my_app.logger.info("Exiting, status code is {}".format(_result)) sys.exit(_result)
def __init__(self, name, app_base): """ prep our thread, but do not start yet :param str name: name for the thread :param CradlepointAppBase app_base: prepared resources: logger, etc """ threading.Thread.__init__(self, name=name) self.app_base = app_base self.app_base.logger.info("started INIT") # how long to delay between checking the GPIO self.loop_delay = self.app_base.settings["power_loss"].get( "check_input_delay", 15) # support things like '1 min' or 15 duration = TimeDuration(self.loop_delay) self.loop_delay = float(duration.get_seconds()) # how long to wait, to double-check LOSS self.loss_delay = self.app_base.settings["power_loss"].get( "loss_delay", 1) self.loss_delay = duration.parse_time_duration_to_seconds( self.loss_delay) # how long to wait, to double-check RESTORE self.restore_delay = self.app_base.settings["power_loss"].get( "restore_delay", 1) self.restore_delay = duration.parse_time_duration_to_seconds( self.restore_delay) # when GPIO matches this state, then power is lost self.state_in_alarm = self.app_base.settings["power_loss"].get( "match_on_power_loss", False) # support 'true', '1' etc - but finally is True/False self.state_in_alarm = parse_boolean(self.state_in_alarm) # when 'power is lost', send to LED self.led_in_alarm = self.app_base.settings["power_loss"].get( "led_on_power_loss", None) try: # see if the setting is None, to disable self.led_in_alarm = parse_none(self.led_in_alarm) except ValueError: # support 'true', '1' etc - but finally is True/False self.led_in_alarm = parse_boolean(self.led_in_alarm) # when GPIO matches this state, then power is lost self.site_name = self.app_base.settings["power_loss"].get( "site_name", "My Site") # create an event to manage our stopping # (Note: on CP router, this isn't strictly true, as when the parent is # stopped/halted, the child dies as well. However, you may want # your sub task to clean up before it exists self.keep_running = threading.Event() self.keep_running.set() # hold the .get_power_loss_status() self.last_state = None # special tweak to announce 'first poll' more smartly self.starting_up = True self.email_settings = dict() self.prep_email_settings() return