Moonlight
← back to tech

2026 年 8 月 18 日 · 3 min read

树莓派月相灯:用 Python 算月相,点亮一圈 LED

一个放在书桌上的小灯,每天晚上按真实月相亮起对应的弧度,从新月到满月。

Raspberry PiPythonNeoPixel repo

书桌上原来有一盏普通的小夜灯。后来我想:既然站点叫 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

现在每天晚上一抬头,桌角那圈灯和窗外的月亮是一样的形状。