Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
db31864
Opening Bell
ChuckBuilds Apr 9, 2025
04cfa86
Update stock_manager.py
ChuckBuilds Apr 9, 2025
e87251c
Update stock_manager.py
ChuckBuilds Apr 9, 2025
cb8680e
Update stock_manager.py
ChuckBuilds Apr 9, 2025
bac08af
Update stock_manager.py
ChuckBuilds Apr 9, 2025
730450f
Update stock_manager.py
ChuckBuilds Apr 9, 2025
31e57ad
Update display_controller.py
ChuckBuilds Apr 9, 2025
f527f4b
Update stock_manager.py
ChuckBuilds Apr 9, 2025
a7982ba
Update stock_manager.py
ChuckBuilds Apr 9, 2025
9ea3169
Customize Display timings
ChuckBuilds Apr 9, 2025
75ff427
Update stock_manager.py
ChuckBuilds Apr 9, 2025
f6be7b5
Sizing and Spacing
ChuckBuilds Apr 9, 2025
8e98a6d
Update clock.py
ChuckBuilds Apr 9, 2025
2871766
Update stock_manager.py
ChuckBuilds Apr 9, 2025
db96c29
Update stock_manager.py
ChuckBuilds Apr 9, 2025
69ff4b3
readme update
ChuckBuilds Apr 11, 2025
21cd5c9
Update .gitignore
ChuckBuilds Apr 11, 2025
1610afd
Update config.json
ChuckBuilds Apr 11, 2025
a01c902
Stock News
ChuckBuilds Apr 11, 2025
5034913
Update config.json
ChuckBuilds Apr 11, 2025
e24c46b
Scroll Performance
ChuckBuilds Apr 11, 2025
99d9990
updating scroll direction
ChuckBuilds Apr 11, 2025
8f11ae3
News tuning
ChuckBuilds Apr 11, 2025
8a71971
Create test_news_manager.py
ChuckBuilds Apr 11, 2025
55db83d
Update test_news_manager.py
ChuckBuilds Apr 11, 2025
83d5726
troubleshooting test script
ChuckBuilds Apr 11, 2025
da4615e
Update test_news_manager.py
ChuckBuilds Apr 11, 2025
2128a2f
Update config.json
ChuckBuilds Apr 11, 2025
fd9006c
Update config.json
ChuckBuilds Apr 11, 2025
56594f9
Update config.json
ChuckBuilds Apr 11, 2025
8ec1c70
Update config.json
ChuckBuilds Apr 11, 2025
53689dc
Update config.json
ChuckBuilds Apr 11, 2025
be3c5da
Update config.json
ChuckBuilds Apr 11, 2025
80ac45c
Update test_news_manager.py
ChuckBuilds Apr 11, 2025
f3fd77c
scroll tuning
ChuckBuilds Apr 11, 2025
2a127b1
scroll logging and debugging
ChuckBuilds Apr 11, 2025
e14f7dd
Update config.json
ChuckBuilds Apr 11, 2025
ba65a2c
Update news_manager.py
ChuckBuilds Apr 11, 2025
6091c71
Update news_manager.py
ChuckBuilds Apr 11, 2025
beeeda5
Stock News manager Rename
ChuckBuilds Apr 11, 2025
013b5e2
Update display_controller.py
ChuckBuilds Apr 11, 2025
1d2bef0
Update stock_manager.py
ChuckBuilds Apr 11, 2025
5be0d59
Stock news settings
ChuckBuilds Apr 11, 2025
7925bf5
Stock news joins the lineup
ChuckBuilds Apr 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ ENV/
*.swo

# Dependencies
sports-0.0.115/
sports-reference/
72 changes: 36 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# LEDSportsMatrix
# LEDMatrix

A modular LED matrix display system for sports information using Raspberry Pi and RGB LED matrices.

Expand All @@ -11,14 +11,15 @@ A modular LED matrix display system for sports information using Raspberry Pi an

1. Clone this repository:
```bash
git clone https://github.com/yourusername/LEDSportsMatrix.git
cd LEDSportsMatrix
git clone https://github.com/ChuckBuilds/LEDMatrix.git
cd LEDMatrix
```

2. Install dependencies:
```bash
pip3 install -r requirements.txt
pip3 install --break-system-packages -r requirements.txt
```
--break-system-packages allows us to install without a virtual environment

## Configuration

Expand All @@ -29,6 +30,16 @@ cp config/config.example.json config/config.json

2. Edit `config/config.json` with your preferences

## API Keys

For sensitive settings like API keys:
1. Copy the template: `cp config/config_secrets.template.json config/config_secrets.json`

2. Edit `config/config_secrets.json` with your API keys via `sudo nano config/config_secrets.json`

3. Ctrl + X to exit, Y to overwrite, Enter to save


## Important: Sound Module Configuration

1. Remove unnecessary services that might interfere with the LED matrix:
Expand All @@ -50,6 +61,27 @@ sudo update-initramfs -u
sudo reboot
```

## Performance Optimization

To reduce flickering and improve display quality:

1. Edit `/boot/firmware/cmdline.txt`:
```bash
sudo nano /boot/firmware/cmdline.txt
```

2. Add `isolcpus=3` at the end of the line

3. Add `dtparam=audio=off` at the end of the line

4. Ctrl + X to exit, Y to save

5. Save and reboot:
```bash
sudo reboot
```


## Running the Display

From the project root directory:
Expand All @@ -76,38 +108,6 @@ LEDSportsMatrix/
└── display_controller.py # Main entry point
```

## Performance Optimization

To reduce flickering and improve display quality:

1. Edit `/boot/firmware/cmdline.txt`:
```bash
sudo nano /boot/firmware/cmdline.txt
```

2. Add `isolcpus=3` at the end of the line

3. Save and reboot:
```bash
sudo reboot
```

For sensitive settings like API keys:
1. Copy the template: `cp config/config_secrets.template.json config/config_secrets.json`
2. Edit `config/config_secrets.json` with your API keys

Note: If you still experience issues, you can additionally disable the audio hardware by editing `/boot/firmware/config.txt`:
```bash
sudo nano /boot/firmware/config.txt
```
And adding:
```
dtparam=audio=off
```

Alternatively, you can:
- Use external USB sound adapters if you need audio
- Run the program with `--led-no-hardware-pulse` flag (may cause more flicker)

## Project Structure

Expand Down
31 changes: 28 additions & 3 deletions config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,49 @@
"scan_mode": "progressive",
"pwm_bits": 8,
"pwm_dither_bits": 1,
"pwm_lsb_nanoseconds": 130,
"disable_hardware_pulsing": true,
"pwm_lsb_nanoseconds": 50,
"disable_hardware_pulsing": false,
"inverse_colors": false,
"show_refresh_rate": true,
"limit_refresh_rate_hz": 100
},
"runtime": {
"gpio_slowdown": 2
},
"rotation_interval": 15
"display_durations": {
"clock": 15,
"weather": 15,
"stocks": 45,
"hourly_forecast": 15,
"daily_forecast": 15,
"stock_news": 30
}
},
"clock": {
"enabled": true,
"format": "%H:%M:%S",
"update_interval": 1
},
"weather": {
"enabled": true,
"update_interval": 300,
"units": "imperial",
"display_format": "{temp}°F\n{condition}"
},
"stocks": {
"enabled": true,
"update_interval": 60,
"symbols": [
"ASTS", "SCHD", "INTC", "NVDA", "T", "VOO", "SPYG", "SMCI"
],
"display_format": "{symbol}: ${price} ({change}%)"
},
"stock_news": {
"enabled": true,
"update_interval": 300,
"scroll_speed": 1,
"scroll_delay": 0.0001,
"max_headlines_per_symbol": 1,
"headlines_per_rotation": 2
}
}
51 changes: 51 additions & 0 deletions integrate_news_ticker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
import time
import sys
import os
from src.config_manager import ConfigManager
from src.display_manager import DisplayManager
from src.stock_news_manager import StockNewsManager
from src.stock_manager import StockManager

def main():
"""Integrate news ticker with the existing display system."""
try:
# Load configuration
config_manager = ConfigManager()
config = config_manager.config

# Initialize display manager
display_manager = DisplayManager(config.get('display', {}))

# Initialize stock manager
stock_manager = StockManager(config, display_manager)

# Initialize news manager
news_manager = StockNewsManager(config, display_manager)

print("News ticker integration test started. Press Ctrl+C to exit.")
print("Displaying stock data and news headlines...")

# Display stock data and news headlines in a loop
while True:
# Display stock data
stock_manager.display_stocks()

# Display news headlines for a limited time (30 seconds)
start_time = time.time()
while time.time() - start_time < 30:
news_manager.display_news()

except KeyboardInterrupt:
print("\nTest interrupted by user.")
except Exception as e:
print(f"Error: {e}")
finally:
# Clean up
if 'display_manager' in locals():
display_manager.clear()
display_manager.update_display()
display_manager.cleanup()

if __name__ == "__main__":
main()
26 changes: 18 additions & 8 deletions src/clock.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,17 @@ def get_current_time(self) -> tuple:
# Get AM/PM
ampm = current.strftime('%p')

# Format date with ordinal suffix
# Format date with ordinal suffix - split into two lines
day_suffix = self._get_ordinal_suffix(current.day)
date_str = current.strftime(f'%A, %B %-d{day_suffix}')
# Full weekday on first line, full month and day on second line
weekday = current.strftime('%A')
date_str = current.strftime(f'%B %-d{day_suffix}')

return time_str, ampm, date_str
return time_str, ampm, weekday, date_str

def display_time(self, force_clear: bool = False) -> None:
"""Display the current time and date."""
time_str, ampm, date_str = self.get_current_time()
time_str, ampm, weekday, date_str = self.get_current_time()

# Only update if something has changed
if time_str != self.last_time or date_str != self.last_date or force_clear:
Expand All @@ -111,7 +113,7 @@ def display_time(self, force_clear: bool = False) -> None:
# Draw time (large, centered, near top)
self.display_manager.draw_text(
time_str,
y=3, # Move down slightly from top
y=2, # Move up slightly to make room for two lines of date
color=self.COLORS['time'],
small_font=False
)
Expand All @@ -122,15 +124,23 @@ def display_time(self, force_clear: bool = False) -> None:
self.display_manager.draw_text(
ampm,
x=ampm_x,
y=5, # Align with time
y=4, # Align with time
color=self.COLORS['ampm'],
small_font=True
)

# Draw date (small, centered below time)
# Draw weekday on first line (small font)
self.display_manager.draw_text(
weekday,
y=display_height - 18, # First line of date
color=self.COLORS['date'],
small_font=True
)

# Draw month and day on second line (small font)
self.display_manager.draw_text(
date_str,
y=display_height - 9, # Move up more from bottom
y=display_height - 9, # Second line of date
color=self.COLORS['date'],
small_font=True
)
Expand Down
7 changes: 4 additions & 3 deletions src/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ def __init__(self, config_path: str = None, secrets_path: str = None):
# Use current working directory as base
self.config_path = config_path or "config/config.json"
self.secrets_path = secrets_path or "config/config_secrets.json"

self.config: Dict[str, Any] = {}
self.load_config()

def load_config(self) -> None:
def load_config(self) -> Dict[str, Any]:
"""Load configuration from JSON files."""
try:
# Load main config
Expand All @@ -26,10 +24,13 @@ def load_config(self) -> None:
# Deep merge secrets into config
self._deep_merge(self.config, secrets)

return self.config

except FileNotFoundError as e:
if str(e).find('config_secrets.json') == -1: # Only raise if main config is missing
print(f"Configuration file not found at {os.path.abspath(self.config_path)}")
raise
return self.config
except json.JSONDecodeError:
print("Error parsing configuration file")
raise
Expand Down
Loading