Skip to content
Closed
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
28 changes: 17 additions & 11 deletions plugins/ledmatrix-flights/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2406,17 +2406,23 @@ def _get_map_background(self, center_lat: float, center_lon: float,
self.logger.debug(f"[Flight Tracker] Map displays {desired_miles_wide:.1f} miles wide x {desired_miles_high:.1f} miles high (no stretching)")
self.logger.debug(f"[Flight Tracker] Native tile scale: {pixels_per_mile_at_zoom:.3f} pixels/mile, cropped {crop_width_needed}x{crop_height_needed} pixels, scaled to {self.display_width}x{self.display_height}")

# Debug: Save composite image to see what's happening
try:
debug_composite = Path("debug_composite.png")
composite.save(debug_composite)
self.logger.debug(f"[Flight Tracker] Saved composite to: {debug_composite}")

debug_cropped = Path("debug_cropped.png")
cropped.save(debug_cropped)
self.logger.debug(f"[Flight Tracker] Saved cropped to: {debug_cropped}")
except Exception as e:
self.logger.debug(f"[Flight Tracker] Could not save debug images: {e}")
# Dump the composite and the crop for inspection -- but only when debug
# logging is on. These were unconditional, so every map rebuild wrote
# two PNGs (~27KB) into the process's working directory: SD-card wear
# on a device that has nothing to gain from it, and two untracked files
# appearing in the checkout the service runs from. There is no config
# flag for them, so nobody could turn them off either.
if self.logger.isEnabledFor(logging.DEBUG):
try:
debug_composite = Path("debug_composite.png")
composite.save(debug_composite)
self.logger.debug(f"[Flight Tracker] Saved composite to: {debug_composite}")

debug_cropped = Path("debug_cropped.png")
cropped.save(debug_cropped)
self.logger.debug(f"[Flight Tracker] Saved cropped to: {debug_cropped}")
except Exception as e:
self.logger.debug(f"[Flight Tracker] Could not save debug images: {e}")

return cropped

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.13",
"version": "1.12.14",
"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": [
{
"version": "1.12.14",
"released": "2026-08-22",
"ledmatrix_min_version": "2.0.0",
"notes": "Stop writing debug PNGs on every map rebuild. _get_map_background saved debug_composite.png and debug_cropped.png unconditionally, so each composite cost ~27KB of SD-card writes and dropped two untracked files into whatever directory the service runs from -- for a normal install, the checkout itself. There was no config flag, so they could not be turned off. They are still written when debug logging is on, which is when they are actually wanted."
},
{
"version": "1.12.13",
"released": "2026-08-19",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""Building a map must not write PNGs into the working directory.

_get_map_background() saved debug_composite.png and debug_cropped.png on every
composite, unconditionally. On a Pi that is pointless SD-card wear (~27KB a
time), and the files land in whatever directory the service runs from -- for a
normal install, the checkout itself, where they show up as untracked files.
There was no config flag, so they could not be turned off.

They are useful when you are debugging the map, so they are kept behind the
debug log level rather than deleted.
"""
import ast
import logging
from pathlib import Path

MANAGER = Path(__file__).resolve().parent / "manager.py"
TREE = ast.parse(MANAGER.read_text(encoding="utf-8"))


def _save_calls():
"""(lineno, unparsed) for every .save(...) writing a debug_* path."""
out = []
for n in ast.walk(TREE):
if isinstance(n, ast.Call) and isinstance(n.func, ast.Attribute) \
and n.func.attr == "save":
src = ast.unparse(n)
if "debug_" in src:
out.append((n.lineno, src))
return out


def _enclosing_tests(lineno):
"""Source of every `if` test whose body contains this line."""
parents = {}
for node in ast.walk(TREE):
for child in ast.iter_child_nodes(node):
parents[child] = node
out = []
for node in ast.walk(TREE):
if isinstance(node, ast.If) and any(
s.lineno <= lineno <= (s.end_lineno or s.lineno) for s in node.body):
out.append(ast.unparse(node.test))
return out


def test_the_debug_saves_still_exist():
"""Pin the premise -- if they are removed entirely this file is obsolete."""
calls = _save_calls()
assert calls, "no debug image saves found; delete this test if that was deliberate"


def test_every_debug_save_is_behind_a_debug_check():
offenders = []
for lineno, src in _save_calls():
guards = " ".join(_enclosing_tests(lineno))
if "isEnabledFor" not in guards and "DEBUG" not in guards:
offenders.append((lineno, src[:60]))
assert not offenders, (
f"unconditional debug image write(s) at {offenders} -- these run on "
"every map composite, wearing the SD card and dropping untracked PNGs "
"into the service's working directory")


def test_the_guard_uses_the_real_logging_level():
"""isEnabledFor, not a hand-rolled flag that can drift from the log config."""
src = MANAGER.read_text(encoding="utf-8")
assert "self.logger.isEnabledFor(logging.DEBUG)" in src
assert logging.DEBUG < logging.INFO # sanity: DEBUG really is the quiet level
Loading