Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions plugins.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1.0.0",
"last_updated": "2026-07-28",
"last_updated": "2026-07-29",
"plugins": [
{
"id": "cricket-scoreboard",
Expand Down Expand Up @@ -414,7 +414,7 @@
"last_updated": "2026-07-17",
"verified": true,
"screenshot": "",
"latest_version": "1.12.5"
"latest_version": "1.12.6"
},
{
"id": "march-madness",
Expand Down
13 changes: 13 additions & 0 deletions plugins/ledmatrix-flights/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog

## [1.12.6] - 2026-07-29

### Fixed
- **Vegas scroll map was missing trails, the centre marker and the aircraft
count**: `get_vegas_content()` reimplemented a cut-down version of the map
view that drew only the background and the aircraft dots, so aircraft trails
never appeared in the ticker even with `show_trails` enabled — and neither did
the white centre-position dot or the aircraft count. Both paths now share a
single `_render_map_image()`, so the ticker renders the same map as the normal
rotation and cannot drift from it again.

78 changes: 45 additions & 33 deletions plugins/ledmatrix-flights/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2558,9 +2558,6 @@ def get_vegas_content(self) -> Optional[List[Image.Image]]:
Flight tracking returns one card per tracked flight.
"""
try:
w = self.display_width
h = self.display_height

mode = self.display_mode
if mode == 'auto':
has_airborne_tracked = any(
Expand All @@ -2581,15 +2578,11 @@ def get_vegas_content(self) -> Optional[List[Image.Image]]:
mode = 'stats'

if mode == 'map':
map_bg = self._get_map_background(self.center_lat, self.center_lon)
img = map_bg.copy() if map_bg else Image.new('RGB', (w, h), (0, 0, 0))
draw = ImageDraw.Draw(img)
for aircraft in self.aircraft_data.values():
pixel = self._latlon_to_pixel(aircraft['lat'], aircraft['lon'])
if pixel:
color = tuple(min(255, int(c * 1.3)) for c in aircraft['color'])
draw.point(pixel, fill=color)
return [img]
# Shared with _display_map so the ticker gets the same map the
# rotation does — trails, centre marker and aircraft count
# included. This used to be a cut-down copy that omitted all
# three.
return [self._render_map_image()]

if mode == 'overhead':
# Render the proximity aircraft from the full pool (independent of
Expand Down Expand Up @@ -2889,82 +2882,101 @@ def _display_flight_tracking(self, force_clear: bool = False) -> None:
# Original display modes (kept in manager.py for backward compatibility)
# -------------------------------------------------------------------------

def _display_map(self, force_clear: bool = False) -> None:
"""Display the flight map with aircraft and geographical background."""
if force_clear:
self.display_manager.clear()

def _render_map_image(self) -> Image.Image:
"""Render the flight map: background, centre marker, trails, aircraft, count.

The single source of truth for the map view, shared by ``_display_map``
and ``get_vegas_content``. Vegas used to reimplement a cut-down version
of this, which drifted: it drew only the background and the aircraft
dots, so trails, the centre position marker and the aircraft count were
all silently missing from the ticker even with ``show_trails`` enabled.

Sizing comes from ``display_width``/``display_height``, which are
properties over ``matrix``. Vegas narrows the display manager while it
requests content, so the projection in ``_latlon_to_pixel`` scales to
whatever width the ticker asked for without any extra plumbing.

Returns:
The composed map as a new RGB image at the current display size
"""
# Get map background if enabled
map_bg = self._get_map_background(self.center_lat, self.center_lon)
Comment on lines 2902 to 2903

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Move tile fetching out of the render path.

_get_map_background() can synchronously fetch map tiles on cache misses, and this helper runs from both display() and get_vegas_content(). A cold cache can therefore stall a rotation/Vegas frame. Refresh tile/background data in update() through self.cache_manager; render from cached data or use the existing black fallback.

As per coding guidelines, “Fetch or refresh network data in update(), never in display(), and use the shared self.cache_manager for network-fetched data.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/ledmatrix-flights/manager.py` around lines 2902 - 2903, Move map
background retrieval out of the render path: update() should refresh
tile/background data through self.cache_manager, while display() and
get_vegas_content() should only read the cached background and retain the
existing black fallback when unavailable. Ensure _get_map_background() is no
longer invoked synchronously by either render method.

Source: Coding guidelines


# Create image with background
if map_bg:
img = map_bg.copy()
else:
self.logger.debug("[Flight Tracker] Map background unavailable; using solid background")
img = Image.new('RGB', (self.display_width, self.display_height), (0, 0, 0))

draw = ImageDraw.Draw(img)

# Draw center position marker (white dot at our lat/lon)
center_pixel = self._latlon_to_pixel(self.center_lat, self.center_lon)
if center_pixel:
x, y = center_pixel
# Draw white center dot
draw.point((x, y), fill=(255, 255, 255))

# Draw aircraft trails if enabled
if self.show_trails:
for icao, trail in self.aircraft_trails.items():
if icao not in self.aircraft_data:
continue

aircraft = self.aircraft_data[icao]
trail_pixels = []

for lat, lon, timestamp in trail:
pixel = self._latlon_to_pixel(lat, lon)
if pixel:
trail_pixels.append(pixel)

# Draw trail with fading effect
if len(trail_pixels) >= 2:
for i in range(len(trail_pixels) - 1):
# Fade from dim to bright
alpha = int(255 * (i + 1) / len(trail_pixels))
color = tuple(int(c * alpha / 255) for c in aircraft['color'])
draw.line([trail_pixels[i], trail_pixels[i + 1]], fill=color, width=1)

# Draw aircraft
for aircraft in self.aircraft_data.values():
pixel = self._latlon_to_pixel(aircraft['lat'], aircraft['lon'])
if not pixel:
continue

x, y = pixel
# Brighten the plane colors by boosting RGB values
base_color = aircraft['color']
color = tuple(min(255, int(c * 1.3)) for c in base_color)

# Draw single pixel for each aircraft
draw.point((x, y), fill=color)

# Draw info text with pixel-perfect rendering for better readability
if len(self.aircraft_data) > 0:
# Draw aircraft count
info_text = f"{len(self.aircraft_data)}"
self._draw_text_smart(draw, info_text, (2, 2), self.fonts['small'],
self._draw_text_smart(draw, info_text, (2, 2), self.fonts['small'],
fill=(200, 200, 200), use_outline=False)

# Get text width to position the airplane icon
bbox = draw.textbbox((0, 0), info_text, font=self.fonts['small'])
text_width = bbox[2] - bbox[0]

# Draw airplane icon after the count (with 2px spacing)
self._draw_airplane_icon(draw, 2 + text_width + 2, 2, color=(200, 200, 200))


return img

def _display_map(self, force_clear: bool = False) -> None:
"""Display the flight map with aircraft and geographical background."""
if force_clear:
self.display_manager.clear()

# Display the image
self.display_manager.image = img.copy()
self.display_manager.image = self._render_map_image()
self.display_manager.update_display()

def _display_overhead(self, force_clear: bool = False) -> None:
Expand Down
8 changes: 7 additions & 1 deletion plugins/ledmatrix-flights/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "ledmatrix-flights",
"name": "Flight Tracker",
"version": "1.12.5",
"version": "1.12.6",
"description": "Real-time aircraft tracking with ADS-B/FlightRadar24/OpenSky/adsb.fi/adsb.lol data, map backgrounds, area mode, flight tracking, anchor airport, flight records, and optional airport weather (METAR/TAF/PIREP/SIGMET via the free NOAA Aviation Weather Center API)",
"author": "ChuckBuilds",
"entry_point": "manager.py",
Expand Down Expand Up @@ -37,6 +37,12 @@
"min_ledmatrix_version": "2.0.0",
"max_ledmatrix_version": "3.0.0",
"versions": [
{
"released": "2026-07-29",
"version": "1.12.6",
"notes": "Fix the Vegas scroll map missing aircraft trails, the centre position marker and the aircraft count. Vegas rendered its own cut-down copy of the map that drew only the background and aircraft dots; both paths now share one renderer so the ticker shows the same map as the normal rotation.",
"ledmatrix_min": "2.0.0"
},
{
"released": "2026-07-17",
"version": "1.12.5",
Expand Down
Loading
Loading