From f859756f46422f2cc83f105b640b3214bd3143b2 Mon Sep 17 00:00:00 2001 From: death916 Date: Fri, 5 Dec 2025 04:17:31 -0800 Subject: [PATCH] begin adding radio --- deathclock/deathclock.py | 7 +++++++ shell.nix | 21 ++++++++++++++++++++ utils/radio.py | 17 ++++++++++++++++ utils/weather.py | 43 ++++++++++++++++++++++++---------------- 4 files changed, 71 insertions(+), 17 deletions(-) create mode 100644 shell.nix create mode 100644 utils/radio.py diff --git a/deathclock/deathclock.py b/deathclock/deathclock.py index 0371796..dc7a4ad 100755 --- a/deathclock/deathclock.py +++ b/deathclock/deathclock.py @@ -12,6 +12,7 @@ from typing import Any, Dict, List import reflex as rx from utils.news import News +from utils.radio import Radio from utils.scores import NBAScores, mlbScores, nflScores from utils.weather import Weather @@ -36,6 +37,8 @@ class State(rx.State): nba_scores: List[Dict[str, Any]] = [] mlb_scores: List[Dict[str, Any]] = [] nfl_scores: List[Dict[str, Any]] = [] + radio_stations: List[str] = [] + current_radio_station: str = "" _news_client: News | None = None # This will be set in the constructor last_weather_update: str = "Never" weather_img: str = WEATHER_IMAGE_PATH @@ -43,6 +46,7 @@ class State(rx.State): _mlb_client: mlbScores | None = None _nba_client: NBAScores | None = None _nfl_client: nflScores | None = None + _radio_client: Radio = Radio() last_sports_update: float = 0.0 # --- Initialize Utility Client --- @@ -55,6 +59,8 @@ class State(rx.State): self._mlb_client = mlbScores() self._nba_client = NBAScores() self._nfl_client = nflScores() + self._radio_client = Radio() + logging.info("Weather client initialized successfully.") except Exception as e: logging.error(f"Failed to initialize Weather client: {e}", exc_info=True) @@ -418,6 +424,7 @@ def index() -> rx.Component: rx.theme_panel(default_open=False), rx.flex( rx.vstack( + State._radio_client.radio_card(), clock_button, main_flex, news_card, diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..52b6715 --- /dev/null +++ b/shell.nix @@ -0,0 +1,21 @@ +let + nixconfig = builtins.getFlake "github:death916/nixconfig"; + unstable = nixconfig.inputs.nixpkgs-unstable.legacyPackages.x86_64-linux; + pkgs = nixconfig.inputs.nixpkgs.legacyPackages.x86_64-linux; +in +pkgs.mkShell { + packages = with pkgs; [ + python313Packages.uv + python313Packages.ninja + python313Packages.numpy + bun + + ]; + shellHook = '' + source .venv/bin/activate + # export PATH="${pkgs.bun}/bin:$PATH" + # export BUN_INSTALL="${pkgs.bun}/bin/bun" + export REFLEX_USE_SYSTEM_BUN=True + echo venv activated and bun version set + ''; +} diff --git a/utils/radio.py b/utils/radio.py new file mode 100644 index 0000000..8ef537a --- /dev/null +++ b/utils/radio.py @@ -0,0 +1,17 @@ +#!/usr/bin/python3 +# connect to rda5807 chip and control it and display the current station + +import reflex as rx + + +class Radio(rx.Base): + def open_radio_button(self): + return rx.button("Radio", on_click=self.open_radio_button) + + def radio_card(self): + return rx.card(title="Radio") + + +class Radio_Control: + def __init__(self): + pass diff --git a/utils/weather.py b/utils/weather.py index 9e7ca97..18136c4 100755 --- a/utils/weather.py +++ b/utils/weather.py @@ -1,17 +1,21 @@ # /home/death916/code/python/deathclock/utils/weather.py +import datetime +import logging # Optional: Use logging for better error messages import os import subprocess -import datetime + import reflex as rx -import logging # Optional: Use logging for better error messages # Configure logging (optional but recommended) -logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logging.basicConfig( + level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" +) # Define the target filename consistently WEATHER_FILENAME = "weather.jpg" # Define the web path expected by the frontend -WEATHER_WEB_PATH = f"/{WEATHER_FILENAME}" # This should be relative to the assets dir +WEATHER_WEB_PATH = f"/{WEATHER_FILENAME}" # This should be relative to the assets dir + class Weather(rx.Base): # No __init__ needed here for Pydantic compatibility @@ -23,7 +27,7 @@ class Weather(rx.Base): script_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(script_dir) - assets_dir = os.path.join(project_root, 'assets') + assets_dir = os.path.join(project_root, "assets") # Ensure the assets directory exists if not os.path.exists(assets_dir): @@ -38,11 +42,11 @@ class Weather(rx.Base): """Deletes the specific weather file in the given 'assets' directory.""" target_file = os.path.join(assets_dir, WEATHER_FILENAME) if os.path.exists(target_file): - try: - os.remove(target_file) - logging.info(f"Deleted old weather file: {target_file}") - except OSError as e: - logging.error(f"Failed to delete old weather file {target_file}: {e}") + try: + os.remove(target_file) + logging.info(f"Deleted old weather file: {target_file}") + except OSError as e: + logging.error(f"Failed to delete old weather file {target_file}: {e}") def get_weather_screenshot(self) -> str | None: """ @@ -56,24 +60,29 @@ class Weather(rx.Base): curl_command = [ "curl", "-s", # Silent mode - "v2.wttr.in/Sacramento.png?0u", # Fetch PNG, no border, no terminal escapes + "v2.wttr.in/Sacramento.png?0u", # Fetch PNG, no border, no terminal escapes "-o", - screenshot_path, # Save to the correct assets path + screenshot_path, # Save to the correct assets path ] # Delete the old file before creating the new one self.delete_old_screenshots(assets_dir) - logging.info(f"Running curl command to fetch weather: {' '.join(curl_command)}") - process = subprocess.run(curl_command, check=True, capture_output=True, text=True) - logging.info(f"Curl command successful. Weather image saved to: {screenshot_path}") # Log correct save path + logging.info( + f"Running curl command to fetch weather: {' '.join(curl_command)}" + ) + logging.info( + f"Curl command successful. Weather image saved to: {screenshot_path}" + ) # Log correct save path - return WEATHER_WEB_PATH # e.g., "/weather.jpg" + return WEATHER_WEB_PATH # e.g., "/weather.jpg" except subprocess.CalledProcessError as e: logging.error(f"Curl command failed for path {screenshot_path}: {e}") logging.error(f"Curl stderr: {e.stderr}") return None except Exception as e: - logging.error(f"An unexpected error occurred saving to {screenshot_path}: {e}") + logging.error( + f"An unexpected error occurred saving to {screenshot_path}: {e}" + ) return None