"""Entrypoint: initializes the display, config, and screens, starts the scheduler in the background, and serves the web UI in the foreground. Usage: python3 main.py # real Waveshare epd4in0e hardware python3 main.py --mock # save frames as PNGs instead (dev off the Pi) """ import argparse import logging import sys from config import Config from scheduler import Scheduler from screens import create_screens from web.app import create_app logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", ) logger = logging.getLogger(__name__) def build_display(mock: bool, mock_resolution: tuple[int, int]): if mock: from display.mock_driver import MockDisplay return MockDisplay(resolution=mock_resolution) from display.epd4in0e_driver import EPD4in0eDisplay return EPD4in0eDisplay() def main(): parser = argparse.ArgumentParser() parser.add_argument("--mock", action="store_true", help="Use the mock display driver instead of real hardware") parser.add_argument("--mock-width", type=int, default=600) parser.add_argument("--mock-height", type=int, default=400) parser.add_argument("--host", default="0.0.0.0") parser.add_argument("--port", type=int, default=8080) args = parser.parse_args() display = build_display(args.mock, (args.mock_width, args.mock_height)) display.init() screens = create_screens() config = Config(screens) scheduler = Scheduler(config, screens, display) scheduler.start() app = create_app(config, screens, scheduler) try: app.run(host=args.host, port=args.port) except KeyboardInterrupt: pass finally: logger.info("Shutting down") scheduler.stop() if __name__ == "__main__": sys.exit(main())