# bin/python3 # encoding: utf-8 import os import sys import time import signal import requests import logging import subprocess # Configuration LOG_FILE = "/tmp/daemon.log" IMG_URL = "http://10.0.1.113:56733/image" IMAGE_PATH = "/mnt/us/extensions/ascwebdash/data/received_image.png" PID_FILE = "/tmp/mydaemon.pid" REFRESH_SECONDS=1800 # Configure logging logging.basicConfig( filename=LOG_FILE, level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) def fetch_image_from_server(url, save_path): """Fetch a IMG file from an HTTP server.""" logging.info(f"Fetching IMG from {url}") try: response = requests.get(url, stream=True) response.raise_for_status() # Raise HTTP errors with open(save_path, "wb") as image_file: for chunk in response.iter_content(1024): image_file.write(chunk) logging.info(f"Image saved to {save_path}") return True except Exception as e: logging.error(f"Failed to fetch IMG: {e}") return False def display_image_with_fbink(image_path): """Display the IMG image on the Kindle using FBInk.""" logging.info(f"Displaying image: {image_path}") try: os.system(f"fbink -i {image_path} > /dev/null 2>&1") logging.info("Image displayed successfully.") except Exception as e: logging.error(f"Failed to display image: {e}") def write_pid(): with open(PID_FILE, "w") as f: f.write(str(os.getpid())) def handle_signal(signum, frame): """Handle incoming signals.""" if signum == signal.SIGHUP: logging.info("Received SIGHUP signal: Refreshing state...") set_wifi(True) logging.info("Fetching image") display_image_with_fbink(IMAGE_PATH) display_battery_percentage(get_battery_percentage()) set_wifi(False) elif signum == signal.SIGTERM: logging.info("Received SIGTERM signal: Exiting daemon...") sys.exit(0) def set_deep_sleep(enable: bool): """ Enable or disable deep sleep on the Kindle. Args: enable (bool): If True, enables deep sleep. If False, disables deep sleep. """ try: # Map boolean argument to corresponding lipc-set-prop value value = "0" if enable else "1" subprocess.run( ["lipc-set-prop", "com.lab126.powerd", "preventScreenSaver", value], check=True, ) action = "enabled" if enable else "disabled" logging.info(f"Deep sleep {action} successfully.") logging.debug(f"Deep sleep {action} successfully.") except subprocess.CalledProcessError as e: action = "enable" if enable else "disable" logging.error(f"Failed to {action} deep sleep: {e}") logging.debug(f"Failed to {action} deep sleep: {e}") def get_battery_percentage(): """Retrieve the Kindle's battery percentage.""" try: # Run the command to get battery percentage result = subprocess.run( ["lipc-get-prop", "com.lab126.powerd", "battLevel"], capture_output=True, text=True, check=True, ) # Extract and return the percentage as an integer return int(result.stdout.strip()) except Exception as e: logging.debug(f"Error retrieving battery percentage: {e}") return None def display_battery_percentage(battery_percentage): """Display the battery percentage on the screen using FBInk.""" try: # Construct the message message = f"{battery_percentage}%" # Display the message using FBInk os.system(f"fbink -x 10 -p {message} > /dev/null 2>&1") logging.debug("Battery percentage displayed successfully.") except Exception as e: logging.debug(f"Error displaying battery percentage: {e}") def send_sighup(): """Send SIGHUP signal to the daemon.""" if not os.path.exists(PID_FILE): logging.debug("Daemon is not running (PID file not found).") return try: # Read the PID from the file with open(PID_FILE, "r") as f: pid = int(f.read().strip()) # Send the SIGHUP signal os.kill(pid, signal.SIGHUP) logging.debug("SIGHUP signal sent to the daemon.") except Exception as e: logging.debug(f"Failed to send SIGHUP: {e}") def set_gui(enable: bool): """ Start or stop the Kindle GUI based on the enable input. Args: enable (bool): If True, starts the GUI. If False, stops the GUI. """ action = "start" if enable else "stop" try: subprocess.run([action, "lab126_gui"], check=True) logging.info(f"GUI {action}ped successfully.") except subprocess.CalledProcessError as e: logging.info(f"Failed to {action} GUI: {e}") def set_wifi(enable: bool): """ Toggle Wi-Fi on or off based on the `enable` boolean input. Args: enable (bool): If True, Wi-Fi will be turned on. If False, Wi-Fi will be turned off. """ try: if enable: # Enable Wi-Fi # logging.info("Starting Wi-Fi...") # subprocess.run(["lipc-set-prop", "com.lab126.cmd", "wirelessEnable", "1"], check=True) # time.sleep(60) # logging.info("Wi-Fi has been enabled.") pass else: # Disable Wi-Fi # subprocess.run(["lipc-set-prop", "com.lab126.cmd", "wirelessEnable", "0"], check=True) # logging.info("Wi-Fi has been disabled.") pass except subprocess.CalledProcessError as e: logging.error(f"Failed to toggle Wi-Fi: {e}") def main(): """Main daemon process.""" logging.info("Daemon started") while True: if fetch_image_from_server(IMG_URL, IMAGE_PATH): set_wifi(True) logging.info("Fetching image") display_image_with_fbink(IMAGE_PATH) display_battery_percentage(get_battery_percentage()) set_wifi(False) else: logging.error("Could not fetch or display image.") time.sleep(REFRESH_SECONDS) # Sleep before fetching again if __name__ == "__main__": # Handle termination signals signal.signal(signal.SIGTERM, handle_signal) signal.signal(signal.SIGINT, handle_signal) signal.signal(signal.SIGHUP, handle_signal) # Process command-line arguments if len(sys.argv) > 1: if sys.argv[1] == "start": # Write PID file and start the daemon write_pid() set_deep_sleep(False) set_gui(False) main() elif sys.argv[1] == "stop": # Stop the daemon if os.path.exists(PID_FILE): with open(PID_FILE, "r") as f: pid = int(f.read()) os.kill(pid, signal.SIGTERM) os.remove(PID_FILE) set_deep_sleep(True) set_gui(True) logging.debug("Daemon stopped.") else: logging.debug("PID file not found. Is the daemon running?") elif sys.argv[1] == "refresh": if os.path.exists(PID_FILE): send_sighup() else: logging.debug("PID file not found. Is the daemon running?") elif sys.argv[1] == "restart": # Restart the daemon if os.path.exists(PID_FILE): with open(PID_FILE, "r") as f: pid = int(f.read()) os.kill(pid, signal.SIGTERM) os.remove(PID_FILE) logging.debug("Daemon stopped.") # Start the daemon write_pid() main() else: logging.debug("Invalid command. Use 'start', 'stop', or 'restart'.") else: logging.debug("Usage: python3 mydaemon.py [start|stop|restart]")