diff --git a/src/amcrest2mqtt/interface.py b/src/amcrest2mqtt/interface.py index 63f48f8..19c02cb 100644 --- a/src/amcrest2mqtt/interface.py +++ b/src/amcrest2mqtt/interface.py @@ -52,6 +52,7 @@ class AmcrestServiceProtocol(Protocol): async def device_loop(self) -> None: ... async def get_events_from_device(self, device_id: str) -> None: ... async def get_snapshot_from_device(self, device_id: str) -> str | None: ... + async def heartbeat(self) -> None: ... async def main_loop(self) -> None: ... async def process_device_event(self, device_id: str, code: str, payload: Any) -> None: ... async def refresh_all_devices(self) -> None: ... @@ -92,10 +93,12 @@ class AmcrestServiceProtocol(Protocol): def get_storage_stats(self, device_id: str) -> dict[str, str | float]: ... def handle_device_command(self, device_id: str, handler: str, message: str) -> None: ... def handle_service_command(self, handler: str, message: str) -> None: ... + def heartbeat_ready(self) -> None: ... def is_discovered(self, device_id: str) -> bool: ... def is_ipv4(self, string: str) -> bool: ... def is_rate_limited(self) -> bool: ... def load_config(self, config_arg: Any | None) -> dict[str, Any]: ... + def mark_ready(self) -> None: ... def mb_to_b(self, total: int) -> int: ... def mqtt_on_connect( self, client: Client, userdata: dict[str, Any], flags: ConnectFlags, reason_code: ReasonCode, properties: Properties | None diff --git a/src/amcrest2mqtt/mixins/helpers.py b/src/amcrest2mqtt/mixins/helpers.py index 153ae37..9df2d8e 100644 --- a/src/amcrest2mqtt/mixins/helpers.py +++ b/src/amcrest2mqtt/mixins/helpers.py @@ -4,6 +4,7 @@ from deepmerge.merger import Merger import ipaddress import logging import os +import pathlib import signal import socket import threading @@ -85,6 +86,12 @@ class HelpersMixin: # Utility functions --------------------------------------------------------------------------- + def mark_ready(self: Amcrest2Mqtt) -> None: + pathlib.Path(READY_FILE).touch() + + def heartbeat_ready(self: Amcrest2Mqtt) -> None: + pathlib.Path(READY_FILE).touch() + def read_file(self: Amcrest2Mqtt, file_name: str) -> str: with open(file_name, "r") as file: data = file.read().replace("\n", "") diff --git a/src/amcrest2mqtt/mixins/loops.py b/src/amcrest2mqtt/mixins/loops.py index 185e7a4..75cc33a 100644 --- a/src/amcrest2mqtt/mixins/loops.py +++ b/src/amcrest2mqtt/mixins/loops.py @@ -45,6 +45,15 @@ class LoopsMixin: self.logger.debug("collect_snapshots_loop cancelled during sleep") break + async def heartbeat(self: Amcrest2Mqtt) -> None: + while self.running: + try: + await asyncio.sleep(60) + self.heartbeat_ready() + except asyncio.CancelledError: + self.logger.debug("heartbeat cancelled during sleep") + break + # main loop async def main_loop(self: Amcrest2Mqtt) -> None: await self.setup_device_list() @@ -57,12 +66,14 @@ class LoopsMixin: self.logger.debug(f"Cannot install handler for {sig}") self.running = True + self.mark_ready() tasks = [ asyncio.create_task(self.device_loop(), name="device_loop"), asyncio.create_task(self.collect_events_loop(), name="collect events loop"), asyncio.create_task(self.check_event_queue_loop(), name="check events queue loop"), asyncio.create_task(self.collect_snapshots_loop(), name="collect snapshot loop"), + asyncio.create_task(self.heartbeat(), name="heartbeat"), ] try: