Files
LEDMatrix/wiki/dynamic_duration.md

244 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dynamic Duration Implementation
## Overview
Dynamic Duration is a feature that calculates the exact time needed to display scrolling content (like news headlines or stock tickers) based on the content's length, scroll speed, and display characteristics, rather than using a fixed duration. This ensures optimal viewing time for users while maintaining smooth content flow.
## How It Works
The dynamic duration calculation considers several factors:
1. **Content Width**: The total width of the text/image content to be displayed
2. **Display Width**: The width of the LED matrix display
3. **Scroll Speed**: How many pixels the content moves per frame
4. **Scroll Delay**: Time between each frame update
5. **Buffer Time**: Additional time added for smooth cycling (configurable percentage)
### Calculation Formula
```
Total Scroll Distance = Display Width + Content Width
Frames Needed = Total Scroll Distance / Scroll Speed
Base Time = Frames Needed × Scroll Delay
Buffer Time = Base Time × Duration Buffer
Calculated Duration = Base Time + Buffer Time
```
The final duration is then capped between the configured minimum and maximum values.
## Configuration
Add the following settings to your `config/config.json` file:
### For Stocks (`stocks` section)
```json
{
"stocks": {
"dynamic_duration": true,
"min_duration": 30,
"max_duration": 300,
"duration_buffer": 0.1,
// ... other existing settings
}
}
```
### For Stock News (`stock_news` section)
```json
{
"stock_news": {
"dynamic_duration": true,
"min_duration": 30,
"max_duration": 300,
"duration_buffer": 0.1,
// ... other existing settings
}
}
```
### For Odds Ticker (`odds_ticker` section)
```json
{
"odds_ticker": {
"dynamic_duration": true,
"min_duration": 30,
"max_duration": 300,
"duration_buffer": 0.1,
// ... other existing settings
}
}
```
### Configuration Options
- **`dynamic_duration`** (boolean): Enable/disable dynamic duration calculation
- **`min_duration`** (seconds): Minimum display time regardless of content length
- **`max_duration`** (seconds): Maximum display time to prevent excessive delays
- **`duration_buffer`** (decimal): Additional time as a percentage of calculated time (e.g., 0.1 = 10% extra)
## Implementation Details
### StockManager Updates
The `StockManager` class has been enhanced with dynamic duration capabilities:
```python
# In __init__ method
self.dynamic_duration_enabled = self.stocks_config.get('dynamic_duration', True)
self.min_duration = self.stocks_config.get('min_duration', 30)
self.max_duration = self.stocks_config.get('max_duration', 300)
self.duration_buffer = self.stocks_config.get('duration_buffer', 0.1)
self.dynamic_duration = 60 # Default duration in seconds
self.total_scroll_width = 0 # Track total width for calculation
```
#### New Methods
**`calculate_dynamic_duration()`**
- Calculates the exact time needed to display all stock information
- Considers display width, content width, scroll speed, and delays
- Applies min/max duration limits
- Includes detailed debug logging
**`get_dynamic_duration()`**
- Returns the calculated dynamic duration for external use
- Used by the DisplayController to determine display timing
### StockNewsManager Updates
Similar enhancements have been applied to the `StockNewsManager`:
```python
# In __init__ method
self.dynamic_duration_enabled = self.stock_news_config.get('dynamic_duration', True)
self.min_duration = self.stock_news_config.get('min_duration', 30)
self.max_duration = self.stock_news_config.get('max_duration', 300)
self.duration_buffer = self.stock_news_config.get('duration_buffer', 0.1)
self.dynamic_duration = 60 # Default duration in seconds
self.total_scroll_width = 0 # Track total width for calculation
```
#### New Methods
**`calculate_dynamic_duration()`**
- Calculates display time for news headlines
- Uses the same logic as StockManager but with stock news configuration
- Handles text width calculation from cached images
**`get_dynamic_duration()`**
- Returns the calculated duration for news display
### OddsTickerManager Updates
The `OddsTickerManager` class has been enhanced with dynamic duration capabilities:
```python
# In __init__ method
self.dynamic_duration_enabled = self.odds_ticker_config.get('dynamic_duration', True)
self.min_duration = self.odds_ticker_config.get('min_duration', 30)
self.max_duration = self.odds_ticker_config.get('max_duration', 300)
self.duration_buffer = self.odds_ticker_config.get('duration_buffer', 0.1)
self.dynamic_duration = 60 # Default duration in seconds
self.total_scroll_width = 0 # Track total width for calculation
```
#### New Methods
**`calculate_dynamic_duration()`**
- Calculates display time for odds ticker content
- Uses the same logic as other managers but with odds ticker configuration
- Handles width calculation from the composite ticker image
**`get_dynamic_duration()`**
- Returns the calculated duration for odds ticker display
### DisplayController Integration
The `DisplayController` has been updated to use dynamic durations:
```python
# In get_current_duration() method
# Handle dynamic duration for stocks
if mode_key == 'stocks' and self.stocks:
try:
dynamic_duration = self.stocks.get_dynamic_duration()
logger.info(f"Using dynamic duration for stocks: {dynamic_duration} seconds")
return dynamic_duration
except Exception as e:
logger.error(f"Error getting dynamic duration for stocks: {e}")
return self.display_durations.get(mode_key, 60)
# Handle dynamic duration for stock_news
if mode_key == 'stock_news' and self.news:
try:
dynamic_duration = self.news.get_dynamic_duration()
logger.info(f"Using dynamic duration for stock_news: {dynamic_duration} seconds")
return dynamic_duration
except Exception as e:
logger.error(f"Error getting dynamic duration for stock_news: {e}")
return self.display_durations.get(mode_key, 60)
# Handle dynamic duration for odds_ticker
if mode_key == 'odds_ticker' and self.odds_ticker:
try:
dynamic_duration = self.odds_ticker.get_dynamic_duration()
logger.info(f"Using dynamic duration for odds_ticker: {dynamic_duration} seconds")
return dynamic_duration
except Exception as e:
logger.error(f"Error getting dynamic duration for odds_ticker: {e}")
return self.display_durations.get(mode_key, 60)
## Benefits
1. **Optimal Viewing Time**: Content is displayed for exactly the right amount of time
2. **Smooth Transitions**: Buffer time ensures smooth cycling between content
3. **Configurable Limits**: Min/max durations prevent too short or too long displays
4. **Consistent Experience**: All scrolling content uses the same timing logic
5. **Debug Visibility**: Detailed logging helps troubleshoot timing issues
## Testing
The implementation includes comprehensive logging to verify calculations:
```
Stock dynamic duration calculation:
Display width: 128px
Text width: 450px
Total scroll distance: 578px
Frames needed: 578.0
Base time: 5.78s
Buffer time: 0.58s (10%)
Calculated duration: 6s
Final duration: 30s (capped to minimum)
```
## Troubleshooting
### Duration Always at Minimum
If your calculated duration is always capped at the minimum value, check:
- Scroll speed settings (higher speed = shorter duration)
- Scroll delay settings (lower delay = shorter duration)
- Content width calculation
- Display width configuration
### Duration Too Long
If content displays for too long:
- Reduce the `duration_buffer` percentage
- Increase `scroll_speed` or decrease `scroll_delay`
- Lower the `max_duration` limit
### Dynamic Duration Not Working
If dynamic duration isn't being used:
- Verify `dynamic_duration: true` in configuration
- Check that the manager instances are properly initialized
- Review error logs for calculation failures
## Related Files
- `config/config.json` - Configuration settings
- `src/stock_manager.py` - Stock display with dynamic duration
- `src/stock_news_manager.py` - Stock news with dynamic duration
- `src/odds_ticker_manager.py` - Odds ticker with dynamic duration
- `src/display_controller.py` - Integration and duration management
- `src/news_manager.py` - Original implementation reference