Une intégration Home Assistant officielle (HACS), une API de lecture gratuite, une spec OpenAPI pour construire le reste. Okilou fournit les faits ; ce que votre maison en fait vous appartient.
Gratuite · lecture seule · révocable
Okilou expose des faits : les minutes débloquées, la session en cours, la récompense qui vient d'être utilisée. Nous ne pilotons aucun appareil et nous ne savons rien de votre installation.
Le jeton ne peut rien valider. Même perdu, il ne permet pas de tricher : l'app reste le seul endroit où l'on valide un effort.
endsAt est fourni dès le lancement : votre automatisation
programme la fin à la minute près, sans minuteur fragile.
C'est votre Home Assistant qui vient lire Okilou (sortant, HTTPS). Aucun port à ouvrir, aucune adresse à exposer.
Dans l'app : Réglages → Ton foyer → API & domotique → Créer un jeton.
Il s'affiche une seule fois (copiez-le), et se révoque au même endroit à tout moment.
Un jeton couvre votre foyer : tous vos enfants, avec le même jeton. En
garde alternée indépendante, le jeton de votre maison ne voit que vos journées :
les jours chez l'autre parent, /today répond calmement
{ "isMyDay": false } (pas d'erreur), et l'autre maison crée
son propre jeton.
# Base
https://api.okilou.com/functions/v1/api
# Toutes les requêtes portent le jeton
curl -H "Authorization: Bearer rf_api_…" $BASE/children
| Route | Ce qu'elle renvoie |
|---|---|
GET /children | les enfants du foyer couverts par le jeton (id, prénom) |
GET /children/:id/today | minutes débloquées / consommées / restantes, points, comportements du jour, session { running, endsAt, minutes }, série de jours réussis, isMyDay |
GET /children/:id/events?since=… | les faits pour vos déclencheurs : behavior_validated, session_started, menu_item_consumed (avec le libellé, ex. « Soirée film »), cheer_sent |
Limite : 30 requêtes/minute par jeton. Les jetons créés avant l'ouverture de
api.okilou.com fonctionnent tels quels : l'ancienne adresse
…supabase.co/functions/v1/api reste valable.
Le chemin recommandé : tout est fait pour vous. Capteurs par enfant, événements sur le bus, curseur persistant (aucun rejeu au redémarrage), garde alternée gérée, re-connexion guidée si vous révoquez le jeton. Code ouvert (MIT) : github.com/okilou/okilou-homeassistant.
https://github.com/okilou/okilou-homeassistant (type Integration) ;Vous obtenez un appareil par enfant :
| Entité | Contenu |
|---|---|
sensor.…_minutes_de_recompense_restantes | la jauge de l'app (min) : gagné, utilisé, joker/gelé, prochain palier en attributs |
sensor.…_points_du_jour | points + détail des comportements en attributs |
sensor.…_fin_de_la_session | horodatage de fin : HA affiche « dans 23 min » tout seul |
sensor.…_serie_de_jours_reussis | la série du Parcours |
binary_sensor.…_session_de_recompense | session en cours (ends_at, minutes en attributs) |
binary_sensor.…_a_la_maison_aujourd_hui | garde alternée : l'enfant est-il chez vous aujourd'hui ? |
Et chaque fait nouveau arrive en événement
okilou_event sur le bus, avec childName
(le prénom) en plus des champs de l'API : parfait pour les annonces.
Distinction utile pour vos automatisations : une récompense en temps lancée
dans l'app émet session_started (avec minutes) ;
une récompense à la carte du menu (« Soirée film ») émet
menu_item_consumed (avec label).
automation:
- alias: "Okilou · annonce du bravo"
triggers:
- trigger: event
event_type: okilou_event
event_data: { type: behavior_validated }
actions:
- action: tts.speak
target: { entity_id: tts.home }
data:
media_player_entity_id: media_player.salon
message: "Bravo {{ trigger.event.data.childName }} — {{ trigger.event.data.label }} !"
# La console s'ouvre au lancement d'une session, et s'éteint à l'heure dite
automation:
- alias: "Okilou · session"
triggers:
- trigger: event
event_type: okilou_event
event_data: { type: session_started }
actions:
- action: switch.turn_on
target: { entity_id: switch.prise_console }
- alias: "Okilou · fin de session"
triggers:
- trigger: template
value_template: "{{ states('sensor.nino_fin_de_la_session') != 'unknown' and as_timestamp(states('sensor.nino_fin_de_la_session')) <= as_timestamp(now()) }}"
actions:
- # à vous de choisir : notification, scène, extinction…
- action: notify.mobile_app_parent
data: { message: "La session de Nino est terminée." }
Latence : l'app synchronise en 4 à 60 s, l'intégration interroge toutes les 60 s ; comptez 30 s à 2 min entre un geste dans l'app et sa trace dans Home Assistant. Le README du dépôt contient d'autres recettes et un exemple de tableau de bord.
Vous préférez tout câbler vous-même (ou vous n'utilisez pas HACS) ?
Un capteur rest et un « pont d'événements » suffisent ; ces recettes
restent entièrement fonctionnelles. ⚠️ Les noms d'entités de cette section
(sensor.okilou_nino…) sont ceux que vous créez ci-dessous :
ne les mélangez pas avec ceux de l'intégration de la section 2
(sensor.nino_…), qui n'existent pas en YAML pur.
Le jeton vit dans secrets.yaml, préfixe compris
(la syntaxe !secret ne s'interpole pas à l'intérieur d'une chaîne) :
# secrets.yaml
okilou_token: "Bearer rf_api_…"
# configuration.yaml — forme moderne (rest: de haut niveau)
rest:
- resource: "https://api.okilou.com/functions/v1/api/children/<ID>/today"
headers:
Authorization: !secret okilou_token
scan_interval: 60
sensor:
- name: "Okilou Nino"
# default(0) : en garde alternée, les jours « autre maison » (isMyDay: false)
# n'envoient pas minutesRemaining — sans lui, la jauge passerait à 'unknown'.
value_template: "{{ value_json.minutesRemaining | default(0) }}"
unit_of_measurement: "min"
json_attributes:
- minutesUnlocked
- session
- streakDays
- behaviors
Il relève /events pour chaque enfant, ré-émet chaque fait
dans Home Assistant (avec child pour router), et mémorise un curseur
par enfant. Un seul enfant ? Gardez une seule entrée dans la liste.
Au premier lancement, donnez à chaque curseur la date du jour (ex.
2026-07-22T00:00:00Z), sinon il rejouera l'historique récent.
⚠️ Posez cette valeur une fois à la main (via l'UI ou le service
input_text.set_value), jamais avec initial: :
ce paramètre désactive la restauration d'état, et chaque redémarrage de Home Assistant
rejouerait la journée.
# configuration.yaml
input_text:
okilou_cursor_lola:
name: "Curseur Okilou · Lola"
okilou_cursor_angelo:
name: "Curseur Okilou · Angelo"
rest_command:
okilou_events:
# urlencode : le curseur composite contient une virgule
url: "https://api.okilou.com/functions/v1/api/children/{{ child }}/events?since={{ states(cursor) | urlencode }}"
headers:
Authorization: !secret okilou_token
automation:
- alias: "Okilou · Pont événements"
mode: single
# silencieux si un cycle chevauche le précédent (pic réseau) — pas de log d'erreur
max_exceeded: silent
trigger:
- platform: time_pattern
seconds: "/30"
action:
- repeat:
for_each:
- { child: "<ID_LOLA>", cursor: input_text.okilou_cursor_lola }
- { child: "<ID_ANGELO>", cursor: input_text.okilou_cursor_angelo }
sequence:
# capturé AVANT la boucle interne : dedans, repeat.item désigne l'événement
- variables:
cursor_entity: "{{ repeat.item.cursor }}"
- service: rest_command.okilou_events
data:
child: "{{ repeat.item.child }}"
cursor: "{{ repeat.item.cursor }}"
response_variable: resp
- choose:
- conditions: "{{ resp.status == 200 and (resp.content.events | count) > 0 }}"
sequence:
- repeat:
for_each: "{{ resp.content.events }}"
sequence:
- event: okilou_event
event_data:
type: "{{ repeat.item.type }}"
child: "{{ repeat.item.childId }}"
label: "{{ repeat.item.label | default('') }}"
minutes: "{{ repeat.item.minutes | default(0) }}"
- service: input_text.set_value
target: { entity_id: "{{ cursor_entity }}" }
data:
value: "{{ resp.content.cursor }}"
La récompense à la carte que l'enfant vient d'utiliser déclenche la maison. C'est votre menu de récompenses qui pilote vos appareils.
automation:
- alias: "Okilou · Soirée film"
trigger:
- platform: event
event_type: okilou_event
event_data:
type: menu_item_consumed
label: "Soirée film 🍿"
action:
- service: media_player.turn_on
target: { entity_id: media_player.videoprojecteur }
- service: light.turn_on
target: { entity_id: light.salon }
data: { brightness_pct: 15 }
La durée arrive avec l'événement (minutes) : un
timer programme la suite ; contrairement à un delay, il
survit à un redémarrage de Home Assistant. À la fin, votre maison fait ce que
vous avez décidé : notification, scène, extinction de la prise.
# configuration.yaml
timer:
okilou_session:
name: "Session Okilou"
restore: true
automation:
- alias: "Okilou · Session"
trigger:
- platform: event
event_type: okilou_event
event_data: { type: session_started }
condition:
- condition: template
value_template: "{{ (trigger.event.data.minutes | int(0)) > 0 }}"
action:
- service: switch.turn_on
target: { entity_id: switch.prise_console }
- service: timer.start
target: { entity_id: timer.okilou_session }
data:
duration: "{{ trigger.event.data.minutes | int(0) * 60 }}"
- alias: "Okilou · Fin de session"
trigger:
- platform: event
event_type: timer.finished
event_data: { entity_id: timer.okilou_session }
action:
- service: switch.turn_off
target: { entity_id: switch.prise_console }
# Carte Lovelace — la jauge du frigo connecté
type: gauge
entity: sensor.okilou_nino
name: "Minutes de Nino"
min: 0
max: 60
severity: { green: 20, yellow: 10, red: 0 }
L'API est décrite en OpenAPI 3.1 : okilou.fr/api/openapi.yaml (aussi sur GitHub). Trois routes, un schéma précis pour chaque réponse, de quoi outiller n'importe quel projet :
Importez le fichier dans Insomnia, Postman ou l'éditeur editor.swagger.io : les routes, paramètres et réponses types apparaissent prêts à tester avec votre jeton.
Un client typé en une commande : par exemple
npx openapi-typescript openapi.yaml (TypeScript) ou
openapi-generator-cli (Python, C#, Go, Rust…).
Un widget Windows (barre des tâches), un module Linux (Waybar, GNOME), un plugin Jeedom, une carte Lovelace dédiée… Ouvrez une issue : on référence votre projet ici.
Idées de départ : un widget de bureau qui affiche la
jauge du jour (poll /today toutes les 60 s) ; une icône systray qui
passe au vert quand session.running ; un mode « ne pas déranger »
d'ordinateur familial piloté par /events. Lecture seule, 30 req/min,
curseur composite pour ne jamais rejouer un événement : tout est dans la spec.
Okilou est l'arbitre : il tient le compte des règles convenues, en lecture seule. L'app reste le seul endroit où l'on valide. Ce que votre maison fait de ces faits (célébrer, programmer, éteindre à l'heure dite), c'est chez vous, c'est vous qui décidez.