2026 年 8 月 18 日 · 3 min read
树莓派月相灯:用 Python 算月相,点亮一圈 LED
一个放在书桌上的小灯,每天晚上按真实月相亮起对应的弧度,从新月到满月。
书桌上原来有一盏普通的小夜灯。后来我想:既然站点叫 Moonlight,桌上应该有一轮真的会变的月亮。
于是有了这个小项目:树莓派 Zero + 一圈 24 颗的 NeoPixel,每天按真实月相点亮对应的弧度。
算月相
不需要联网查 API。以某个已知新月时刻为基准,月相周期取 29.530588 天,取模就行:
from datetime import datetime, timezone
SYNODIC = 29.530588853
KNOWN_NEW_MOON = datetime(2000, 1, 6, 18, 14, tzinfo=timezone.utc)
def moon_phase(now: datetime | None = None) -> float:
"""返回 0~1:0 新月,0.5 满月,1 又回到新月。"""
now = now or datetime.now(timezone.utc)
days = (now - KNOWN_NEW_MOON).total_seconds() / 86400
return (days % SYNODIC) / SYNODIC
误差在半天以内,对一盏灯来说足够了。
点灯
24 颗灯排成一圈,把相位映射成"亮几颗、从哪里开始亮":
import board, neopixel
N = 24
pixels = neopixel.NeoPixel(board.D18, N, brightness=0.25, auto_write=False)
MOON = (255, 214, 140) # 偏暖的米金,不要纯白
def render(phase: float):
lit = round(abs(phase - 0.5) * 2 * N) # 满月时 24 颗全亮
lit = N - lit
for i in range(N):
pixels[i] = MOON if i < lit else (2, 4, 3) # 暗面留一点点绿黑
pixels.show()
调"像月光"
最花时间的是颜色。纯白太像手术灯,纯黄像路灯。最后落在 (255, 214, 140) 再把亮度压到 25%,加一层描图纸做柔光罩,才有"月光落在桌上"的感觉。
硬件项目的最后 10% 全是审美。
定时
crontab 每小时跑一次就够了:
0 * * * * /usr/bin/python3 /home/pi/moonlamp/main.py >> /home/pi/moonlamp/log 2>&1
现在每天晚上一抬头,桌角那圈灯和窗外的月亮是一样的形状。