
Een van de populairste websites van NASA is de Astronomy Picture of the Day ook wel APOD genoemd. Deze website is een van de populairste websites van alle federale instanties van de VS. Ik wilde al een tijd geautomatiseerd astronomische afbeeldingen downloaden omdat ik de achtergrond van mijn desktop ermee wil voorzien. Met mijn sidekick Claude is dit eenvoudig te bouwen.
In deze tutorial leg ik uit hoe je (geautomatiseerd) afbeeldingen met behulp van een API van de NASA APOD-website naar je Raspberry Pi kunt downloaden en de afbeelding automatisch in de achtergrond van je desktop plaatst.
APOD is bedoeld voor gebruikers die content willen ophalen voor gebruik op een andere website, een mirrorsite, in een tool, feedreader of contentarchief. Het doel van deze feeds is om het APOD-archief gemakkelijker herbruikbaar te maken.
Geen video’s
Als de APOD van die dag een video is (dat gebeurt af en toe, meestal een paar keer per maand), slaat het script alleen de metadata (titel, uitleg, URL) op in een .json bestand — de video zelf wordt niet gedownload. Je kunt de video afspelen door de URL in het JSON-bestand te gebruiken.
NASA’s “video’s” zijn meestal geen directe videobestanden, maar embeds/links naar YouTube of Vimeo. Om die daadwerkelijk te downloaden heb je een extra tool nodig zoals yt-dlp, en dat werkt niet voor elke soort link (sommige zijn bijvoorbeeld interactieve Vimeo-embeds zonder downloadbare bron). Daarnaast kunnen video’s aanzienlijk veel opslagruimte innemen.
Het script haalt via de officiële NASA APOD API de foto van de dag op en slaat zowel de afbeelding als de metadata (titel, uitleg, datum) lokaal en stelt de afbeelding daarna ook automatisch in als bureaubladachtergrond op de Raspberry Pi.
Belangrijkste punten:
- Standaard gebruikt het script
DEMO_KEY, maar die heeft een lage limiet van 30 afbeeldingen/uur of maximaal 50 afbeeldingen/dag. Vraag daarom de persoonlijke GRATIS key aan via api.nasa.gov en geef die in het script of bij het opstarten mee met--api-keyof via de scriptvariabeleNASA_API_KEY. - het script werkt ook met een specifieke datum (
--date 2024-01-01) en om de HD-versie te downloaden (--hd). - Onderaan het bestand staan installatie-instructies, inclusief een voorbeeld-cronjob om het script elke ochtend automatisch te laten draaien op je Pi.
Daar gaan we…
Zorg dat Python 3 up-to-date en pip geïnstalleerd zijn (meestal al het geval):
sudo apt update && sudo apt install python3-pip -y
Installeer de benodigde bibliotheek en systeemonderdelen:
pip3 install requests
sudo apt install feh
Het Python script (apod_wallpaper.py)
Het script werkt standaard met de desktop-omgeving van Raspberry Pi OS (PIXEL/LXDE, via pcmanfm). Voor andere desktop-omgevingen kun je met –method een andere methode kiezen (zie hieronder).
Start het script op door een van de onderstaande voorbeelden of een combinatie ervan in de terminal in te geven:
python3 apod_wallpaper.py
python3 apod_wallpaper.py --date 2024-01-01
python3 apod_wallpaper.py --api-key JOUW_API_KEY --dir /home/han/apod # vul hier je api-key in
python3 apod_wallpaper.py --method feh
python3 apod_wallpaper.py --no-wallpaper # alleen downloaden, niet instellen
Let op! In het derde commando geef je het download pad mee. Tegenwoordig gebruiken we geen pi als id meer, maar zal het je eigen id zijn. In dit geval is dit mijn naam (id = han).
Script test met GUI
Test het script handmatig (via de terminal op het bureaublad of op afstand via VNC. Alleen SSH werkt niet) met:
python3 apod_wallpaper.py --dir /home/han/apod
De code
Ik ga ervan uit dat je inmiddels weet hoe je het onderstaande script met een (SSH) editor naar de Raspberry Pi terminal kopieert, opslaat en vervolgens opstart. Zo niet laat het me weten door hieronder een reactie te geven.
#!/usr/bin/env python3
import argparse
import json
import os
import subprocess
import sys
from datetime import date
from urllib.parse import urlparse
import requests
APOD_API_URL = "https://api.nasa.gov/planetary/apod"
def parse_args():
parser = argparse.ArgumentParser(
description="Download de NASA APOD en stel 'm in als bureaubladachtergrond"
)
parser.add_argument(
"--api-key",
default=os.environ.get("NASA_API_KEY", "DEMO_KEY"),
help="NASA API key (of zet de omgevingsvariabele NASA_API_KEY). Standaard: DEMO_KEY",
)
parser.add_argument(
"--date",
default=None,
help="Datum in YYYY-MM-DD formaat. Standaard: vandaag",
)
parser.add_argument(
"--dir",
default=os.path.join(os.path.expanduser("~"), "apod"),
help="Map waarin afbeeldingen worden opgeslagen. Standaard: ~/apod",
)
parser.add_argument(
"--hd",
action="store_true",
help="Download de HD-versie van de afbeelding indien beschikbaar",
)
parser.add_argument(
"--method",
choices=["pcmanfm", "feh", "gsettings"],
default="pcmanfm",
help=(
"Methode om de achtergrond in te stellen: "
"'pcmanfm' (standaard Raspberry Pi OS/LXDE), "
"'feh' (lichte window managers), "
"'gsettings' (GNOME-achtige desktops). Standaard: pcmanfm"
),
)
parser.add_argument(
"--no-wallpaper",
action="store_true",
help="Alleen downloaden, achtergrond niet instellen",
)
return parser.parse_args()
def fetch_apod_metadata(api_key, target_date=None):
"""Haal de metadata van de APOD op via de NASA API."""
params = {"api_key": api_key}
if target_date:
params["date"] = target_date
response = requests.get(APOD_API_URL, params=params, timeout=30)
response.raise_for_status()
return response.json()
def download_file(url, destination_path):
"""Download een bestand in streaming-modus (geheugenvriendelijk op een Pi)."""
with requests.get(url, stream=True, timeout=60) as response:
response.raise_for_status()
with open(destination_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
def set_wallpaper(image_path, method):
"""Stel de bureaubladachtergrond in met de gekozen methode."""
image_path = os.path.abspath(image_path)
if method == "pcmanfm":
# Standaard voor Raspberry Pi OS (PIXEL desktop / LXDE)
# Probeer eerst met een expliciete desktop-omgevingsnaam, val anders terug.
cmd = ["pcmanfm", "--set-wallpaper", image_path, "--wallpaper-mode=fit"]
elif method == "feh":
cmd = ["feh", "--bg-fill", image_path]
elif method == "gsettings":
uri = f"file://{image_path}"
cmd = ["gsettings", "set", "org.gnome.desktop.background", "picture-uri", uri]
else:
raise ValueError(f"Onbekende methode: {method}")
try:
subprocess.run(cmd, check=True, env={**os.environ, "DISPLAY": os.environ.get("DISPLAY", ":0")})
return True
except FileNotFoundError:
print(
f"Commando '{cmd[0]}' niet gevonden. Installeer het bijvoorbeeld met:\n"
f" sudo apt install {cmd[0]}",
file=sys.stderr,
)
return False
except subprocess.CalledProcessError as e:
print(f"Instellen van achtergrond mislukt: {e}", file=sys.stderr)
return False
def main():
args = parse_args()
os.makedirs(args.dir, exist_ok=True)
try:
data = fetch_apod_metadata(args.api_key, args.date)
except requests.exceptions.HTTPError as e:
print(f"Fout bij ophalen van APOD-gegevens: {e}", file=sys.stderr)
sys.exit(1)
except requests.exceptions.RequestException as e:
print(f"Netwerkfout: {e}", file=sys.stderr)
sys.exit(1)
apod_date = data.get("date", str(date.today()))
media_type = data.get("media_type", "image")
meta_path = os.path.join(args.dir, f"{apod_date}.json")
with open(meta_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
if media_type != "image":
print(
f"APOD van {apod_date} is geen afbeelding maar '{media_type}', "
f"achtergrond wordt niet aangepast. URL: {data.get('url')}"
)
return
image_url = data.get("hdurl") if (args.hd and "hdurl" in data) else data.get("url")
parsed_url = urlparse(image_url)
ext = os.path.splitext(parsed_url.path)[1] or ".jpg"
filename = f"{apod_date}{ext}"
image_path = os.path.join(args.dir, filename)
print(f"Downloaden van: {image_url}")
try:
download_file(image_url, image_path)
except requests.exceptions.RequestException as e:
print(f"Fout bij downloaden van afbeelding: {e}", file=sys.stderr)
sys.exit(1)
print(f"Afbeelding opgeslagen als: {image_path}")
print(f"Titel: {data.get('title')}")
if not args.no_wallpaper:
if set_wallpaper(image_path, args.method):
print(f"Bureaubladachtergrond ingesteld ({args.method}).")
else:
print(
"Kon de achtergrond niet automatisch instellen. "
"De afbeelding staat wel klaar op de bovenstaande locatie.",
file=sys.stderr,
)
if __name__ == "__main__":
main()
Elke dag om 08:00 uur een nieuwe afbeelding via Cron
Als je dagelijks bij het opstarten van de Raspberry Pi automatisch een nieuwe bureaubladachtergrond wilt hebben, kun je cron(tab) als scheduler gebruiken.
Let op: een cronjob heeft normaal geen toegang tot je grafische sessie (DISPLAY), dus geef die expliciet mee.
Start Cron in de editmodus op:
crontab -e
Voeg de volgende regel onderaan het bestand toe om het script elke dag om 08:00 te draaien:0 8 * * * DISPLAY=:0 NASA_API_KEY=JOUW_KEY /usr/bin/python3 /home/han/nasa/apod_wallpaper.py --dir /home/han/apod >> /home/han/apod/apod.log 2>&1
Cronregel met voorbeeldkey (bijv. 1a2B3c4D5e6F7g8H9i0JklMnOpQrStUvWxYz1234):
0 8 * * * DISPLAY=:0 NASA_API_KEY=1a2B3c4D5e6F7g8H9i0JklMnOpQrStUvWxYz1234 /usr/bin/python3 /home/han/nasa/apod_wallpaper.py --dir /home/han/apod >> /home/han/apod/apod.log 2>&1Vervang 1a2B3c4D5e6F7g8H9i0JklMnOpQrStUvWxYz1234 door je eigen echte key uit een vorige stap (niet in dit voorbeeld plakken als je de regel ergens deelt of opslaat op een plek die anderen kunnen zien).
Als dit vanuit cron niet werkt, kan het zijn dat er ook een XAUTHORITY-omgevingsvariabele nodig is. Voeg dan vóór het NASA_API_KEY-gedeelte in de cronregel de volgende regel toe:
XAUTHORITY=/home/han/.Xauthority
Sla de wijzigingen op en sluit de editor af. De cronjob is actief na een (her)start van de Raspberry Pi.
Resultaat
Als alles goed gegaan is verschijnt na het starten van het script de volgende informatie in je terminal.

De HD afbeelding met de titel ‘Perseids and Magic’ (zie hieronder) is gedownload en met de standaard methode (pcmanfm) als bureaubladachtergrond ingesteld.

Conclusie
Met slechts een enkele inspanning, het NASA APOD archief en een gratis API bouw je met AI een leuke functie die dagelijks je desktop van een nieuwe astronomische afbeelding voorziet.
Doe er je voordeel mee!
Have A Nice Day!

Laat een reactie achter