mirror of
https://github.com/lynchaos/ashvale-station.git
synced 2026-09-12 12:47:49 +00:00
Make the matrix frame rate configurable
24 fps costs about 11% of one core on a Zero 2 W, measured on the board. That is a reasonable default for something you look at, but it is a decorative load sharing a 512 MB machine with the forecaster, so it should be the owner's choice. server.led_fps is clamped to 4..30. Particle fall speed now divides by the configured rate rather than the module constant, so rain falls at the same real-world speed whatever the frame rate, instead of slowing down when you turn the frame rate down.
This commit is contained in:
+1
-1
@@ -60,7 +60,7 @@ async def lifespan(app: FastAPI):
|
|||||||
station.sample_once()
|
station.sample_once()
|
||||||
station.start()
|
station.start()
|
||||||
if CONFIG.server.led_enabled:
|
if CONFIG.server.led_enabled:
|
||||||
display = LedDisplay(station, CONFIG.server.led_cycle_s)
|
display = LedDisplay(station, CONFIG.server.led_cycle_s, CONFIG.server.led_fps)
|
||||||
display.start()
|
display.start()
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
|
|||||||
@@ -118,6 +118,11 @@ class ServerConfig:
|
|||||||
port: int = 8000
|
port: int = 8000
|
||||||
led_enabled: bool = True
|
led_enabled: bool = True
|
||||||
led_cycle_s: float = 0.4
|
led_cycle_s: float = 0.4
|
||||||
|
# Matrix frame rate. 24 is smooth and costs about 11% of one core on a
|
||||||
|
# Zero 2 W. 16 is still fluid and roughly a third cheaper; below about 12
|
||||||
|
# the crossfades and sub-pixel motion start to judder, which defeats the
|
||||||
|
# point. Set 0 to keep the panel enabled but static-cheap.
|
||||||
|
led_fps: float = 24.0
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
+5
-3
@@ -344,7 +344,7 @@ class Precipitation(Scene):
|
|||||||
colour = (0.80, 0.88, 1.00) if snowing else (0.20, 0.55, 1.00)
|
colour = (0.80, 0.88, 1.00) if snowing else (0.20, 0.55, 1.00)
|
||||||
|
|
||||||
for d in self.drops:
|
for d in self.drops:
|
||||||
d[1] += speed / FPS
|
d[1] += speed / max(s.get('_fps', FPS), 1.0)
|
||||||
if d[1] > N + 1:
|
if d[1] > N + 1:
|
||||||
d[0] = np.random.uniform(0, N)
|
d[0] = np.random.uniform(0, N)
|
||||||
d[1] = np.random.uniform(-2.0, -0.2)
|
d[1] = np.random.uniform(-2.0, -0.2)
|
||||||
@@ -491,9 +491,10 @@ class LedDisplay:
|
|||||||
|
|
||||||
CROSSFADE = 1.3
|
CROSSFADE = 1.3
|
||||||
|
|
||||||
def __init__(self, station, cycle_s: float = 0.4):
|
def __init__(self, station, cycle_s: float = 0.4, fps: float = FPS):
|
||||||
self.station = station
|
self.station = station
|
||||||
self.cycle_s = float(cycle_s)
|
self.cycle_s = float(cycle_s)
|
||||||
|
self.fps = float(np.clip(fps, 4.0, 30.0))
|
||||||
self.enabled = True
|
self.enabled = True
|
||||||
self._stop = asyncio.Event()
|
self._stop = asyncio.Event()
|
||||||
self._task = None
|
self._task = None
|
||||||
@@ -540,6 +541,7 @@ class LedDisplay:
|
|||||||
"forecast": series,
|
"forecast": series,
|
||||||
"health": self.station.monitor.health.overall,
|
"health": self.station.monitor.health.overall,
|
||||||
"retrain": bool(self.station.monitor.retrain_requested),
|
"retrain": bool(self.station.monitor.retrain_requested),
|
||||||
|
"_fps": self.fps,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _brightness(self, s: Dict) -> float:
|
def _brightness(self, s: Dict) -> float:
|
||||||
@@ -575,7 +577,7 @@ class LedDisplay:
|
|||||||
return self.alert if self._alerting else self.scenes[self._idx]
|
return self.alert if self._alerting else self.scenes[self._idx]
|
||||||
|
|
||||||
async def _run(self) -> None:
|
async def _run(self) -> None:
|
||||||
period = 1.0 / FPS
|
period = 1.0 / self.fps
|
||||||
t0 = time.monotonic()
|
t0 = time.monotonic()
|
||||||
while not self._stop.is_set():
|
while not self._stop.is_set():
|
||||||
frame_start = time.monotonic()
|
frame_start = time.monotonic()
|
||||||
|
|||||||
Reference in New Issue
Block a user