Files
webcal-dashboard/kindle/ascwebdash/bin/asc-webdash.py
Anthony Correa e96ef0e44e Improve Dockerfile, compose configuration, Kindle script, and UI styles for better maintainability and functionality
This commit introduces several enhancements across multiple files to improve maintainability, functionality, and overall code quality. Key updates are as follows:
	1.	.gitignore
	•	Added exclusion for kindle/data/* to prevent Kindle-specific data from being tracked.
	2.	Dockerfile
	•	Added installation of OpenMoji font:
	•	Downloads and unzips OpenMoji font to /usr/share/fonts/openmoji.
	•	Updates font cache with fc-cache.
	•	Verifies installation with fc-list | grep "OpenMoji".
	•	Improves container setup for rendering Kindle dashboards with proper font support.
	3.	compose.yml
	•	Port mapping now uses an environment variable ${HOST_PORT} instead of hardcoding 56733:80.
	•	Enhances flexibility for port management.
	4.	kindle/ascwebdash.py
	•	Significant refactoring and cleanup:
	•	Removed unused signal handling and daemonization logic.
	•	Simplified logging configuration and added optional arguments using argparse for flexibility.
	•	Abstracted repetitive paths using constants for maintainability.
	•	Consolidated functionality for fetching images and refreshing the screen.
	•	Removed unused Wi-Fi and GUI toggling code.
	•	Focused the script’s functionality on image fetching and display for Kindle extensions.
	5.	CSS (style.css)
	•	Removed visual debugging borders (red, green, yellow).
	•	Improved layout styles:
	•	Set fixed widths for better rendering of event columns.
	•	Adjusted margins and paddings for cleaner alignment.
	•	Added a new .day .events class for consistent padding.
	6.	views.py
	•	Added error handling when fetching calendar data:
	•	Ensures the application doesn’t crash if calendar URLs are inaccessible.
	•	Logs errors to console for debugging.

Impact:
	•	Maintainability: Refactored scripts, improved code structure, and enhanced readability.
	•	Flexibility: Environment variable support for ports and dynamic script arguments.
	•	Functionality: Added OpenMoji font support in the Docker container.
	•	UI/UX: Cleaned up CSS for better layout and appearance.
	•	Resilience: Improved error handling in views.py to handle calendar fetch failures gracefully.

Files Modified:
	•	.gitignore
	•	Dockerfile
	•	compose.yml
	•	kindle/ascwebdash/bin/asc-webdash.py
	•	server/app/templates/style.css
	•	server/app/views.py

This ensures better extensibility and robustness across the codebase.
2024-12-17 06:59:54 -06:00

135 lines
4.9 KiB
Python
Executable File

# bin/python3
# encoding: utf-8
import os
import time
import requests
import logging
import subprocess
import argparse
# Configuration Defaults
EXTENSION_NAME="ascwebdash"
EXTENSION_DIR=f"/mnt/us/extensions/{EXTENSION_NAME}"
LOG_FILE = f"{EXTENSION_DIR}/asc-webdash.py.log"
IMG_URL = "http://10.0.1.113:56733/image"
IMAGE_PATH = f"{EXTENSION_DIR}/received_image.png"
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 refresh_screen_with_image(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 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
lipc_bin = "lipc-set-prop"
service = "com.lab126.powerd"
prop = "preventScreenSaver"
value = "0" if enable else "1"
subprocess.run(
[lipc_bin, service, prop, 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
lipc_bin = "lipc-get-prop"
service = "com.lab126.powerd"
prop = "preventScreenSaver"
result = subprocess.run(
[lipc_bin, service, prop],
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 -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 main():
"""Main daemon process."""
parser = argparse.ArgumentParser()
# Define optional arguments
parser.add_argument("--extension-dir", type=str, default=EXTENSION_DIR,
help=f"Directory for extensions (default: {EXTENSION_DIR})")
parser.add_argument("--log-file", type=str, default=LOG_FILE,
help=f"Path to the log file (default: {LOG_FILE})")
parser.add_argument("--img-url", type=str, default=IMG_URL,
help=f"URL of the image to download (optional default:{IMG_URL})")
parser.add_argument("--image-path", type=str, default=IMAGE_PATH,
help=f"Path to save the image (default: {IMAGE_PATH})")
parser.add_argument("--refresh-seconds", type=int, default=REFRESH_SECONDS,
help=f"Time in seconds between refreshes (default: {REFRESH_SECONDS})")
logging.info("Script started")
while True:
if fetch_image_from_server(IMG_URL, IMAGE_PATH):
logging.info("Fetching image")
refresh_screen_with_image(IMAGE_PATH)
display_battery_percentage(get_battery_percentage())
else:
logging.error("Could not fetch or display image.")
time.sleep(REFRESH_SECONDS) # Sleep before fetching again
if __name__ == "__main__":
# Process command-line arguments
set_deep_sleep(False)
main()