Halb eins nachts. Ich gehe durchs Haus in die Küche, weil ich Durst habe. Sekunden später vibriert das Galaxy auf dem Nachttisch — neben dem Bett, in dem ich gerade nicht liege, weil ich ja in der Küche stehe. Meine Frau liegt da aber schon. Vibration direkt neben dem Ohr, Display leuchtet auf, „Bewegung erkannt“ von Blink. Glückwunsch, Kamera. Du hast den Hausherrn beim Wassertrinken erwischt.
Die Mini steht im Wohnzimmer und soll dort rund um die Uhr aufzeichnen. An allen Zugängen rund ums Haus hängen separate Kameras, die pushen ganz normal — wenn nachts wirklich jemand am Haus rumschleicht, weckt mich schon eine davon, lange bevor er drinnen ist. Die Mini drinnen ist die zweite Ebene: dokumentieren, was im Wohnzimmer passiert, falls außen einer durchkommt. Pushes von genau dieser Kamera will ich dagegen nie. Tagsüber laufen wir selbst durchs Bild, da ist jede Meldung Lärm. Was ich also brauche: Aufzeichnung dauerhaft an, Pushes dauerhaft aus. Klingt nach einer trivialen Anforderung. Ist es nicht.
Was die Blink-App kann — und was nicht
Blink hat eine Snooze-Funktion. In der App tippt man auf das Kamerasymbol, wählt zwischen einer Minute und 24 Stunden, fertig. Die Aufnahmen laufen weiter, nur die Push-Mitteilungen sind aus. Das Feature gibt es seit Jahren und funktioniert auch. Es hat genau eine Schwäche: Man muss es jeden Tag manuell antippen. Zeitgesteuertes Snooze, „täglich um 22 Uhr bis morgen um 21 Uhr“? Fehlanzeige.
In Communitys wird das seit Jahren diskutiert. Feature-Requests im Blink-Forum häufen sich, die Antworten sind die üblichen „Wir geben das ans Produktteam weiter“. Passiert ist nichts. Das ist okay — Blink gehört zu Amazon, da ist die Roadmap mutmaßlich von größeren Themen bestimmt als von Komfortfunktionen für drei Hardcore-User. Trotzdem nervt’s.
Erste Idee, weil’s ja schließlich konzernintern ist: Alexa-Routinen. Alexa kann die Kamera arm/disarm, also bewaffnen oder entwaffnen. Das Problem: entwaffnet heißt komplett aus — keine Aufnahmen, keine Pushes, gar nichts. Genau nicht das, was ich will. HomeKit-Integration gibt es nicht, IFTTT spielt in der Blink-Welt seit Längerem keine Rolle mehr, und Home Assistant kann zwar einiges mit der Blink-API, aber das Snooze-Setting findet sich da nirgends. Sackgasse.
Reverse Engineering, weil die App es ja irgendwie macht
Wenn die App das auf dem Telefon hinkriegt, muss da irgendwo ein API-Call hingehen. Logisch. Also: mitmproxy auf dem Laptop, das Galaxy als Client konfiguriert, das CA-Zertifikat aufs Telefon, los geht’s. Bei einem Kunden hatte ich vor ein paar Jahren mal eine alte Branchen-App auseinandergenommen, weil der Hersteller pleite war und der Kunde wissen wollte, wie die Datenbankstruktur aussieht — der Workflow ist derselbe.
Die Blink-App spricht mit rest-prod.immedia-semi.com und mit tier-spezifischen Hosts wie rest-e003.immedia-semi.com. Authentication läuft über JWT-Bearer-Tokens, der Standard-OAuth2-Tanz. Was ich gesucht habe, war schnell gefunden:
POST /api/v1/accounts/{aid}/networks/{nid}/owls/{cid}/snooze
Authorization: Bearer <access_token>
Content-Type: application/json
{"snooze_time": 1380}owls ist Blink-Slang für die Mini-Kameras (die anderen Modelle heißen schlicht „cameras“). snooze_time ist die Dauer in Minuten, Maximum 1440 — also 24 Stunden. Würde ich 1440 setzen und die Routine läuft um 22:00, beginnt der nächste Lauf erst morgen um 22:00 — und in der Sekunde dazwischen wäre potentiell eine wache Minute, in der die Kamera wieder pushen darf. 1380 Minuten (23 Stunden) überlappt bewusst und schließt die Lücke. Manueller curl-Test: HTTP 200, in der App erscheint das Snooze-Symbol, Push-Mitteilungen schweigen. Aufnahmen laufen weiter wie gehabt. Genau das, was ich wollte.
Jetzt müsste das nur noch jeden Tag automatisch passieren.
Der erste, falsche Plan: PHP-Cron auf netcup
Naiver Ansatz Nummer eins: Ich habe einen netcup-Webspace, da kann ich PHP-Skripte ablegen, da gibt’s Cron. Skript schreiben, das den oben gezeigten POST absetzt, täglich um 22 Uhr triggern, fertig.
Funktionierte. Genau einmal. Am nächsten Tag um 22 Uhr: HTTP 401. Token abgelaufen.
Der Access-Token, den die Blink-App benutzt, lebt vier Stunden. Wenn das Cron-Skript nur einmal pro Tag läuft, ist der Token bei jedem zweiten Lauf tot. Naheliegende Lösung: vorher einen neuen Token holen. Das bringt uns zur eigentlich spannenden Frage — wie loggt man sich denn programmatisch bei Blink ein?
Die OAuth2-Architektur, die niemand dokumentiert hat
POST /api/v5/account/login mit Mailadresse und Passwort: HTTP 426. „App update required.“ Egal welchen User-Agent ich setze, egal welche App-Version ich vortäusche — die 426 bleibt. Programmatischer Login mit Mail/Passwort ist offenbar nicht vorgesehen; der dokumentierte (na ja, beobachtbare) Weg ist der OAuth2-Refresh-Flow, was bei genauerem Hinsehen ohnehin der OAuth-Standard wäre.
Hat mich anderthalb Stunden gekostet zu akzeptieren, dass die 426 endgültig ist — fünf User-Agents durchprobiert, fünfmal dieselbe Antwort. Irgendwann ist man fertig.
Zweiter Anlauf: Im JWT-Payload des bestehenden Tokens nachgesehen, was der iss-Claim sagt. Da steht BlinkOauthService-prod. Also gibt es einen separaten OAuth-Service. Eine kurze Suche im Proxy-Mitschnitt liefert den Host: api.oauth.blink.com. Dort gibt es einen /oauth/token-Endpoint, der den OAuth2-Standard-Flow spricht:
POST https://api.oauth.blink.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=<token>Der Body ist überraschend minimal: kein client_id, kein client_secret, nur Grant-Type und der aktuelle Refresh-Token. Antwort: ein frischer Access-Token, gültig vier Stunden. Soweit Standard.
Aber da ist ein Detail, das in Blinks (nicht existierender) Dokumentation niemand hingeschrieben hat: Der Refresh-Token wird bei jedem Aufruf rotiert. Der alte stirbt sofort, ein neuer kommt im Response. Wer ihn nicht persistiert, hat beim nächsten Lauf nichts mehr in der Hand und darf das ganze Spiel mit mitmproxy von vorn beginnen.
Das ist sicherheitstechnisch sauber gedacht — Refresh-Token-Rotation ist seit Jahren OAuth2-Empfehlung, weil ein einmal abgegriffener Token nur einmal nützt — in der Praxis aber ein Stolperstein, wenn man den Token-Lifecycle in einem Skript managen muss. Es gibt offenbar eine kleine Grace-Period von ein paar Stunden, in der der alte Token nochmal ziehen würde; verlassen würde ich mich darauf nicht. Damit war klar, was die Infrastruktur können musste: Sie muss den Refresh-Token speichern, in jedem Lauf benutzen, das Response auseinandernehmen, den neuen Refresh-Token persistieren, dann erst den Snooze-Call absetzen. Vier Schritte, von denen einer einen schreibbaren persistenten Speicher braucht.
Warum Claude Code Routines und nicht PHP-Cron 2.0
An dieser Stelle hätte ich das PHP-Skript um eine MySQL-Tabelle erweitern können. State-Handling in PHP ist nun wirklich keine Raketenwissenschaft. Habe ich aber nicht gemacht — und der Grund ist nicht „weil’s hipper ist“, sondern eher pragmatisch.
Claude Code Routines hat Anthropic Mitte April 2026 als Research Preview veröffentlicht. Das Konzept ist trocken erklärt: Eine Routine ist eine gespeicherte Claude-Code-Sitzung — Prompt, Repositories, Connectors, Tools — die nach Zeitplan, per GitHub-Event oder per HTTP-POST in Anthropics Cloud läuft. Mein Rechner darf aus sein, mein Internet darf weg sein, die Routine läuft trotzdem. Minimum-Intervall ist eine Stunde, was für „einmal am Tag um 22 Uhr“ reicht.
Für meinen Anwendungsfall heißt das: Kein eigener Server zu pflegen. Kein PHP-Update, das mich am Sonntagabend in den Webspace zwingt. Kein Cron-Debug-Marathon, wenn der Hoster mal wieder die PHP-Version umstellt. Routines verbrauchen Subscription-Quota — im Abo sind ausreichend Routine-Läufe pro Tag enthalten, für genau einen Snooze pro Tag ist es völlig egal, welchen Plan man hat.
Außerdem — und das ist das eigentliche Argument — kann ich die ganze Logik in Markdown beschreiben. Das ist kein Code-Golf, das ist eine Liste von Anweisungen: „Lies die Datei. Mach einen POST. Parse das JSON. Schreib die Datei zurück. Mach noch einen POST.“ Die Routine ist mein Skript, nur dass ich’s nicht in PHP schreibe, sondern in Sätzen. Wenn morgen Blink den Endpoint ändert, passe ich zwei Zeilen Klartext an. Im Pflege-Alltag macht das einen Unterschied — gerade bei einer privaten Bastel-Lösung, deren Code man nach zwei Jahren selbst nicht mehr lesen will.
Honest Trade-off: Routines sind Preview. Die API kann sich ändern. Wer die Funktion produktiv in einer Firma einsetzt, sollte das einplanen.
Der Persistence-Twist
Jeder Routine-Lauf startet in einem frischen Container. Was im letzten Lauf in /tmp lag, ist weg. Logisch — das ist im Grunde Serverless. Aber meinen rotierten Refresh-Token muss ich irgendwie von einem Lauf zum nächsten retten.
Lösung: Ein kleines privates GitHub-Repo. Die Routine clont das Repo zu Beginn, liest dort eine tokens.json, macht ihr Ding, schreibt die neue tokens.json zurück und committet sie. Ein Commit pro Tag, einzeiliger Diff (der neue Token-String), git-History wird zur unfreiwilligen Audit-Spur des Token-Lebenszyklus.
Sicherheitsbeurteilung dazu, ehrlich: Private Repos sind nicht das Hochsicherheitstresor-Äquivalent. Wer Zugriff auf mein GitHub-Konto bekommt, hat auch den Token. Andererseits — wer Zugriff auf mein GitHub-Konto hat, hat auch wesentlich peinlichere Dinge. Für die Snooze-Funktion meiner Wohnzimmerkamera ist das Threat Model okay. Für jemanden, der echte Sicherheitskameras eines Geschäftsstandorts auf diese Weise verwaltet, würde ich anders argumentieren.
Das fertige Setup in vier Schritten
Die Routine läuft täglich um 22:00, hat in den Allowed Domains nur die zwei Blink-Hosts (kein freies Internet), und macht der Reihe nach:
- Repo clonen,
tokens.jsonlesen. Darin steht aktuell ein Refresh-Token. - OAuth-Endpoint anfragen mit Grant-Type
refresh_token. Aus dem Response den neuen Access-Token und den neuen Refresh-Token rausholen. tokens.jsonmit dem rotierten Refresh-Token überschreiben, committen, pushen. Damit ist die State-Frage für den nächsten Lauf gelöst — egal, was im aktuellen Lauf danach noch passiert.- Snooze-Endpoint anfragen mit
snooze_time: 1380. Bei HTTP 200 ist Feierabend.
Beim ersten Lauf habe ich in der Blink-App auf dem Telefon zugeschaut. Pünktlich erscheint das kleine Mond-Symbol an der Mini-Kamera, „Snooze aktiv bis morgen 21 Uhr“. Seitdem ist Ruhe. Die Kamera zeichnet auf, das Telefon schweigt — genau die Trennung, die ich wollte.
Was das Beispiel größer macht
Snooze für eine Blink Mini ist als Einzelfall überschaubar. Interessanter ist das Muster: OAuth2-Reverse-Engineering der Hersteller-App, plus Routines, plus Repo-Persistence. Das funktioniert sinngemäß für eine ganze Reihe von Smart-Home-Geräten, deren App schmäler ist als die unterliegende API — Tuya, Hue, Ring, Nest, Tado, Bosch Smart Home. Voraussetzung: Die Hersteller-API spricht OAuth2, was 2026 quasi überall der Fall ist.
Im Vergleich zu Home Assistant heißt das: Kein lokaler Server, keine YAML, keine Custom-Integration aus dem Community-Forum, deren Maintainer nach dem nächsten Hue-Firmware-Update aufgehört hat zu pflegen. Auf der anderen Seite: Home Assistant ist offline-fähig und behält die Kontrolle lokal. Das ist nicht trivial weniger wert. Wer beides parallel pflegen will, kann das tun.
Eine Einschränkung, die ich nicht unter den Tisch fallen lasse: Die Nutzungsbedingungen der meisten Hersteller verbieten Reverse Engineering der mobilen Apps. Für den Privatgebrauch ist das in Deutschland nach §§69d, 69e UrhG (Dekompilierung zur Herstellung von Interoperabilität) in vielen Konstellationen abgedeckt — aber das ist eine juristische Schnittlinie, an der ich keine Garantie aussprechen will. Kommerzieller Nachbau auf dieser Basis ist ein anderes Thema. Und natürlich kann jedes größere Update der Blink-App theoretisch die ganze Mechanik kippen. Das Setup ist hier frisch aufgesetzt — ich werde im Blog nachtragen, wie es sich über die ersten Wochen bewährt.
Aufwand, Lebensdauer, Bauchgefühl
Vom ersten „Das nervt jetzt aber wirklich“ bis zum laufenden Setup: knapp vier Stunden. Davon gut die Hälfte für mitmproxy, JWT-Header lesen, OAuth-Endpoint finden und HTTP 426 verstehen. Die Routine selbst ist trivial — wer das Schema einmal hat, hat in einer Stunde die nächste Integration für ein anderes Gerät stehen.
Was ich aus dem Projekt mitnehme, ist weniger der konkrete Workflow als die Architektur dahinter. Vor zwei Jahren hätte ich für genau dasselbe Ergebnis einen Mini-Server bei Hetzner laufen lassen, ein systemd-Timer-Unit gebaut, ein virtualenv für Python gepflegt und mich alle paar Monate über kaputte SSL-Zertifikate geärgert. Heute committe ich eine Markdown-Datei in ein GitHub-Repo, hänge sie als Routine an einen Zeitplan, und Anthropic kümmert sich um den Rest. Ob das langfristig die richtige Abhängigkeit ist, weiß ich nicht. Für eine Aufgabe, die mich täglich genau einen Push erspart, ist es der angemessene Aufwand.
Die Kamera schweigt jetzt.
Hinweis zur Nachnutzung
Die hier beschriebene Vorgehensweise nutzt eine inoffizielle, nicht öffentlich dokumentierte API. Sie kann gegen die Nutzungsbedingungen von Blink/Amazon verstoßen. Bei Account-Sperrung oder anderen Maßnahmen des Anbieters trägt jeder Anwender das Risiko selbst. Dies ist die Beschreibung meines persönlichen Bastelprojekts, keine Empfehlung zur Nachahmung.
Quellen & weiterführend
- Anthropic: Introducing routines in Claude Code — claude.com/blog/introducing-routines-in-claude-code
- Claude Code Docs: Automate work with routines — code.claude.com/docs/en/routines
- Blink Subreddit, diverse Threads zum Feature-Request „scheduled snooze“ — reddit.com/r/blinkcameras
- §§69d, 69e UrhG (Dekompilierung zur Herstellung von Interoperabilität), Gesetzestext — gesetze-im-internet.de



