def heartbeat_worker(self) -> WorkerStatus: for hb_key, hb in self._heartbeats.items(): if utime() > hb.ts + hb.period: msg = f"Watchdog timeout for '{hb.name}'. Fatal." self.log.critical(color("red", msg)) self.kill(msg) return WorkerStatus.SUCCESS
def _worker() -> None: last_scheduled = utime() while not app.killswitch.is_set(): # noinspection PyBroadException try: status = worker_method() except ignore_exc as e: app.log.debug( f"Ignored {e} in {worker_method.__name__}", stacklevel=2, ) status = WorkerStatus.SUCCESS except suppress_exc as e: app.log.warning( f"Suppressed '{e}' in {worker_method.__name__}.", stacklevel=2, ) status = WorkerStatus.ERROR except Exception as e: app.log.critical( msg := f"Uncaught {e} in {worker_method.__name__}", stacklevel=2, ) app.kill(msg) raise if hb_period is not None and status == WorkerStatus.SUCCESS: self._heartbeats[hb.id].ts = utime() if delay == 0.0: continue else: next_scheduled = last_scheduled + delay app.killswitch.wait(timeout=max(0.001, next_scheduled - utime())) last_scheduled = next_scheduled
def handle_read(self): self.recv(1024) now = int(utime()) if not (state.last_motion[0] and state.prev_motion[0]): state.last_motion[0] = now state.prev_motion[0] = state.last_motion[0] state.last_motion[0] = now print('motion event at {}'.format(state.last_motion[0])) for rule in (i for i in state.config if i.enabled): if rule.eval(): print('wake host {} up'.format(rule.host)) wakeup(rule.host)
def __init__(self, config, logger): self.__load_configs(config, logger) self.logger = logging.getLogger(self.get_settings("logger", "vkbot")) self.vk = VkApi(token=self.get_settings("access_token"), api_version=self.get_settings("version", 5.120)) self.admins = self.get_settings("admins", "").split(",") self.prefix = self.get_settings("prefix", None) self.lp = VkBotLongPoll(self.vk, self.get_settings("group_id"), int(self.get_settings("lp_wait", 5))) self.register(VkBotEventType.MESSAGE_NEW, self.cmd_event) self.cmd = CommandManager(self) self.tasks = TaskManager(self) th = threading.Thread(target=self.__exit) th.daemon = True th.start() self.logger.info( self.get_messages("start", id=self.get_settings("group_id"))) self.time = utime()
def uptime(self): time = utime() - self.time fmt = self.get_messages("time_format").split(",") months = round(time / 2592000 % 999) weeks = round(time / 604800 % 4) days = round(time / 86400 % 7) hours = round(time / 3600 % 24) minutes = round(round(time / 60) % 60) if months > 0: return "{}{} {}{}".format(months, fmt[0], weeks, fmt[1]) format = "" if days > 0: format += "{}{} ".format(days, fmt[2]) if hours > 0: format += "{}{} ".format(hours, fmt[3]) if minutes > 0: format += "{}{} ".format(minutes, fmt[4]) format += "{}{}".format(round(time % 60), fmt[5]) return format
def handle_read(self): s = str( self.recv(1024) ) if ' bytes from ' in s: state.pinglog[self.host] = int(utime())
def _check(self, now, host): if host in wakelog: return (int(utime()) - wakelog[host]) >= self.args[0]
def _check(self, now, host): return (int(utime()) - prev_motion[0]) > self.args[0]
_helper(self) return conditions class Host: def __init__(self, addr, mac): self.addr = addr self.mac = mac def __repr__(self): return '{} {}'.format(self.addr, self.mac) if __name__ == '__main__': last_motion = utime() r = Rule( Host('192.168.1.101', '00:24:1d:d9:fa:09'), HoldOff(300), When( And ( TimeBetween(time(00, 00, 00), time(12, 00, 00)), InactiveFor(300), Not (DayOfWeek(5)), ) ) ) print(r.eval())
def start_worker( self, worker_method: Callable[[], WorkerStatus], delay: float, ignore_exc: tuple[Type[Exception], ...] = (), suppress_exc: tuple[Type[Exception], ...] = (), hb_period: Opt[float] = None, ) -> Thread: """ A worker method is an operation that should be performed periodically and indefinitely in a separate thread. This method should return True on a successful run, and False on an unsuccessful run. This function takes a method that performs one iteration of the work and instruments it with the loop and thread. The worker loop checks as a stopping condition for the Event "workers_halt" to be set. This is a way to coordinate app shutdown by stopping all workers. Optionally, it also installs a "heartbeat monitor" for the worker, such that an error will be logged if the worker has not run successfully for some amount of time, whether by returning False consistently or simply not executing. Args: worker_method: the method, which should execute one iteration of the desired job. delay: the amount of time to wait between each execution of the worker. As implemented this is a simple sleep, so the actual delay between invocations will be delay + execution time. ignore_exc: a list of exception types which will be caught and ignored, and will not be considered a worker failure for the heartbeat. suppress_exc: a list of exception types that will be caught and logged with a warning. These will be considered a worker failure, but will not trigger app shutdown except potentially by causing a heartbeat timeout. Exceptions that are neither ignored nor suppressed are considered fatal and will result in app shutdown. hb_period: an optional float. If not None, this will request that a monitor thread regularly check that the worker has not failed to execute for at least this many seconds. If this check fails, the app is terminated with an appropriate message. Returns: a Thread object which when started will execute the worker in a loop. """ app: TWSApp # noinspection PyTypeChecker,PyUnresolvedReferences assert isinstance( app := worker_method.__self__, TWSApp # type: ignore ), "Preparing non-TWS method!" assert hb_period is None or hb_period > delay assert delay >= 0.0 if hb_period is not None: hb = HeartBeat(worker_method.__name__, utime(), hb_period) self._heartbeats[hb.id] = hb # kwargs to avoid late binding issues -- should not be used. @wraps(worker_method) def _worker() -> None: last_scheduled = utime() while not app.killswitch.is_set(): # noinspection PyBroadException try: status = worker_method() except ignore_exc as e: app.log.debug( f"Ignored {e} in {worker_method.__name__}", stacklevel=2, ) status = WorkerStatus.SUCCESS except suppress_exc as e: app.log.warning( f"Suppressed '{e}' in {worker_method.__name__}.", stacklevel=2, ) status = WorkerStatus.ERROR except Exception as e: app.log.critical( msg := f"Uncaught {e} in {worker_method.__name__}", stacklevel=2, ) app.kill(msg) raise if hb_period is not None and status == WorkerStatus.SUCCESS: self._heartbeats[hb.id].ts = utime() if delay == 0.0: continue else: next_scheduled = last_scheduled + delay app.killswitch.wait(timeout=max(0.001, next_scheduled - utime())) last_scheduled = next_scheduled thread = worker_thread(_worker) thread.start() self._worker_threads.add(thread) return thread