begin adding radio

This commit is contained in:
death916 2025-12-05 04:17:31 -08:00
parent bb266d405b
commit f859756f46
4 changed files with 71 additions and 17 deletions

View file

@ -12,6 +12,7 @@ from typing import Any, Dict, List
import reflex as rx import reflex as rx
from utils.news import News from utils.news import News
from utils.radio import Radio
from utils.scores import NBAScores, mlbScores, nflScores from utils.scores import NBAScores, mlbScores, nflScores
from utils.weather import Weather from utils.weather import Weather
@ -36,6 +37,8 @@ class State(rx.State):
nba_scores: List[Dict[str, Any]] = [] nba_scores: List[Dict[str, Any]] = []
mlb_scores: List[Dict[str, Any]] = [] mlb_scores: List[Dict[str, Any]] = []
nfl_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 _news_client: News | None = None # This will be set in the constructor
last_weather_update: str = "Never" last_weather_update: str = "Never"
weather_img: str = WEATHER_IMAGE_PATH weather_img: str = WEATHER_IMAGE_PATH
@ -43,6 +46,7 @@ class State(rx.State):
_mlb_client: mlbScores | None = None _mlb_client: mlbScores | None = None
_nba_client: NBAScores | None = None _nba_client: NBAScores | None = None
_nfl_client: nflScores | None = None _nfl_client: nflScores | None = None
_radio_client: Radio = Radio()
last_sports_update: float = 0.0 last_sports_update: float = 0.0
# --- Initialize Utility Client --- # --- Initialize Utility Client ---
@ -55,6 +59,8 @@ class State(rx.State):
self._mlb_client = mlbScores() self._mlb_client = mlbScores()
self._nba_client = NBAScores() self._nba_client = NBAScores()
self._nfl_client = nflScores() self._nfl_client = nflScores()
self._radio_client = Radio()
logging.info("Weather client initialized successfully.") logging.info("Weather client initialized successfully.")
except Exception as e: except Exception as e:
logging.error(f"Failed to initialize Weather client: {e}", exc_info=True) 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.theme_panel(default_open=False),
rx.flex( rx.flex(
rx.vstack( rx.vstack(
State._radio_client.radio_card(),
clock_button, clock_button,
main_flex, main_flex,
news_card, news_card,

21
shell.nix Normal file
View file

@ -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
'';
}

17
utils/radio.py Normal file
View file

@ -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

View file

@ -1,17 +1,21 @@
# /home/death916/code/python/deathclock/utils/weather.py # /home/death916/code/python/deathclock/utils/weather.py
import datetime
import logging # Optional: Use logging for better error messages
import os import os
import subprocess import subprocess
import datetime
import reflex as rx import reflex as rx
import logging # Optional: Use logging for better error messages
# Configure logging (optional but recommended) # 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 # Define the target filename consistently
WEATHER_FILENAME = "weather.jpg" WEATHER_FILENAME = "weather.jpg"
# Define the web path expected by the frontend # 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): class Weather(rx.Base):
# No __init__ needed here for Pydantic compatibility # No __init__ needed here for Pydantic compatibility
@ -23,7 +27,7 @@ class Weather(rx.Base):
script_dir = os.path.dirname(os.path.abspath(__file__)) script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(script_dir) 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 # Ensure the assets directory exists
if not os.path.exists(assets_dir): 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.""" """Deletes the specific weather file in the given 'assets' directory."""
target_file = os.path.join(assets_dir, WEATHER_FILENAME) target_file = os.path.join(assets_dir, WEATHER_FILENAME)
if os.path.exists(target_file): if os.path.exists(target_file):
try: try:
os.remove(target_file) os.remove(target_file)
logging.info(f"Deleted old weather file: {target_file}") logging.info(f"Deleted old weather file: {target_file}")
except OSError as e: except OSError as e:
logging.error(f"Failed to delete old weather file {target_file}: {e}") logging.error(f"Failed to delete old weather file {target_file}: {e}")
def get_weather_screenshot(self) -> str | None: def get_weather_screenshot(self) -> str | None:
""" """
@ -56,24 +60,29 @@ class Weather(rx.Base):
curl_command = [ curl_command = [
"curl", "curl",
"-s", # Silent mode "-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", "-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 # Delete the old file before creating the new one
self.delete_old_screenshots(assets_dir) self.delete_old_screenshots(assets_dir)
logging.info(f"Running curl command to fetch weather: {' '.join(curl_command)}") logging.info(
process = subprocess.run(curl_command, check=True, capture_output=True, text=True) 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 )
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: except subprocess.CalledProcessError as e:
logging.error(f"Curl command failed for path {screenshot_path}: {e}") logging.error(f"Curl command failed for path {screenshot_path}: {e}")
logging.error(f"Curl stderr: {e.stderr}") logging.error(f"Curl stderr: {e.stderr}")
return None return None
except Exception as e: 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 return None