Afvalmelding op je Home Assistant-tablet (met Fully Kiosk)

In deze post laat ik stap voor stap zien hoe ik een fullscreen pop-up maak op mijn Home Assistant-tablet met Fully Kiosk Browser. De pop-up verschijnt ’s ochtends/’s avonds, houdt het scherm wakker met een watchdog en verdwijnt pas als ik op Sluiten tik. Inclusief alle YAML, REST-commands en het HTML-bestand — copy/paste klaar. Alle gevoelige gegevens zijn geanonimiseerd met !secret.


Waarom ik dit bouwde

Ik wil ’s ochtends direct zien welke container(s) aan de straat moeten. Mijn Android-tablet draait Fully Kiosk als dashboard. Met een fullscreen pop-up mis ik niets meer, en dankzij een helper + watchdog blijft het scherm actief zolang de melding open staat.


Wat je nodig hebt

  • Home Assistant (toegang tot configuration.yaml en Automations UI)

  • Android-tablet met Fully Kiosk Browser (Remote Admin aan, poort 2323)

  • Afval-sensoren (bijv. via HACS Afvalinfo)

  • Een helper (toggle) in Home Assistant


Stap 1 — Fully Kiosk snel instellen

  1. Remote Admin aan (poort 2323) + sterk wachtwoord.

  2. Start URL = jouw HA-dashboard (bijv. https://hass.example.com).

  3. Power: Keep Screen On = uit; Screen Off Timer = 120 sec (na sluiten mag scherm weer uit).

  4. Screensaver: bijvoorbeeld Black Screen; “Delete cache on reload” aan.


Stap 2 — REST-commands in configuration.yaml (met !secret)

Gebruik !secret om IP’s en wachtwoorden te verbergen. Voeg in secrets.yaml toe:

fully_tablet_ip: 172.16.xx.yy
fully_tablet_pass: SterkWachtwoordHier

De &v={{ now().timestamp() }} bust de cache zodat je popup-HTML altijd de nieuwste versie is.

rest_command:
  fully_fullscreen_http:
    url: >-
      http://!secret fully_tablet_ip:2323/?cmd=loadURL
      &url=https://hass.example.com/local/afval_popup.html?msg={{ message | urlencode }}&v={{ (now().timestamp() | int) }}
      &password=!secret fully_tablet_pass
    method: GET

  fully_stop_screensaver:
    url: "http://!secret fully_tablet_ip:2323/?cmd=stopScreensaver&password=!secret fully_tablet_pass"
    method: GET

  fully_trigger_motion:
    url: "http://!secret fully_tablet_ip:2323/?cmd=triggerMotion&password=!secret fully_tablet_pass"
    method: GET

  fully_set_brightness_120:
    url: "http://!secret fully_tablet_ip:2323/?cmd=setScreenBrightness&level=120&password=!secret fully_tablet_pass"
    method: GET

  fully_screen_on:
    url: "http://!secret fully_tablet_ip:2323/?cmd=screenOn&password=!secret fully_tablet_pass"
    method: GET

Na opslaan: Instellingen → Systeem → Serverbeheer → Controleer configuratieHerstart.


Stap 3 — Helper aanmaken

Instellingen → Apparaten & diensten → Helpers → + → Schakelaar. Noem hem: Afval popup actief. Entiteit: input_boolean.afval_popup_actief.


Stap 4 — HTML-bestand (/config/www/afval_popup.html)

Dit is het fullscreen venster. De knop Sluiten stuurt een webhook en navigeert terug naar het dashboard. Deze versie leest ook de tekst uit ?msg= correct in (spaties i.p.v. +, ondersteunt meerdere regels met \n, en Esc = sluiten).




  
  
  
  
  
  Afvalmelding
  
    html,body{height:100%;margin:0}
    body{
      background:#1E90FF; color:#fff; display:flex; flex-direction:column;
      align-items:center; justify-content:center; text-align:center;
      font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;
      -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
      user-select:none
    }
    .msg{
      font-size:clamp(28px, 6vw, 56px);
      line-height:1.2;
      max-width:92vw;
      margin:0 4vw 6vh;
      white-space:pre-wrap;         /* toont \n als nieuwe regels */
      word-wrap:break-word;
    }
    .btn{
      font-size:clamp(18px, 3.2vw, 28px);
      padding:18px 28px; background:#ffffff; color:#1E90FF;
      border:none; border-radius:16px; text-decoration:none; display:inline-block
    }
    .btn:active{transform:scale(0.98)}
  


  
Afvalmelding

  [Sluiten »](#)

  
    (function(){
      // Tekst uit ?msg= veilig ophalen
      const qs = new URLSearchParams(location.search);
      const raw = qs.get('msg');

      // Sommige encoders zetten spaties als '+'
      const decoded = raw
        ? decodeURIComponent(String(raw)).replace(/\+/g, ' ')
        : 'Vandaag is er geen inzameling';

      // Multi-line ondersteunen: \n → nieuwe regel (white-space: pre-wrap in CSS)
      const text = decoded.replace(/\\n/g, '\n');

      const msgEl = document.getElementById('msg');
      msgEl.textContent = text; // veilig (geen HTML-injectie)

      const DASHBOARD_URL = '/tablet-v2'; // pas aan naar jouw Lovelace route
      const WEBHOOK_URL   = `${location.origin}/api/webhook/afval_popup_close`;

      function closePopup(){
        fetch(WEBHOOK_URL, { method: 'POST', keepalive: true, mode: 'no-cors' })
          .catch(() => {})
          .finally(() => {
            setTimeout(() => { location.replace(DASHBOARD_URL); }, 300);
          });
      }

      document.getElementById('closeBtn').addEventListener('click', function(e){
        e.preventDefault();
        closePopup();
      });

      // Extra: Esc-toets sluit ook
      document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape') closePopup();
      });
    })();
  


Stap 5 — Webhook-automation (helper uit, met debounce)

Zet dit via Automatiseringen → Lege automatisering → Bewerken in YAML.

alias: Afval popup - helper UIT via webhook (debounced)
mode: single
trigger:
  - platform: webhook
    webhook_id: afval_popup_close
    allowed_methods:
      - POST
      - GET
    local_only: true
condition:
  - condition: state
    entity_id: input_boolean.afval_popup_actief
    state: "on"
  - condition: template
    value_template: >
      {{ (as_timestamp(now()) - as_timestamp(states.input_boolean.afval_popup_actief.last_changed | default(0))) >= 15 }}
action:
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.afval_popup_actief

Stap 6 — Watchdog (scherm wakker houden zolang helper aan staat)

alias: Tablet popup - wakker houden (helper)
id: tablet_popup_watchdog
mode: single
trigger:
  - platform: homeassistant
    event: start
  - platform: state
    entity_id: input_boolean.afval_popup_actief
    to: "on"
  - platform: time_pattern
    seconds: "/5"
condition:
  - condition: state
    entity_id: input_boolean.afval_popup_actief
    state: "on"
action:
  - service: rest_command.fully_screen_on
  - service: rest_command.fully_stop_screensaver
  - service: rest_command.fully_trigger_motion
  - service: switch.turn_on
    target:
      entity_id: switch.tab_woonkamer_scherm    # pas aan
  - service: rest_command.fully_set_brightness_120

Stap 7 — Popup-automation (07:00, 21:00 & test)

Pas de sensor-namen aan jouw setup aan (gft, restafval, pbd). De avondmelding (21:00) kijkt naar morgen; de ochtendmelding (07:00) kijkt naar vandaag. Hieronder staat ook de meerregelige boodschap (Optie A) direct in de actie.

alias: Afval popups 07:00 & 21:00 (met helper + delay)
id: afval_popup_0700_2100
mode: single
trigger:
  - platform: time
    at: "07:00:00"
    id: ochtend
  - platform: time
    at: "21:00:00"
    id: avond
  - platform: event
    event_type: afvalpopup_test
    id: test
variables:
  is_ochtend: "{{ trigger.id == 'ochtend' }}"
  is_avond: "{{ trigger.id == 'avond' }}"
  is_test: "{{ trigger.id == 'test' }}"
  datum_doel: >
    {{ (now().date() | string) if (is_ochtend or is_test)
       else ((now().date() + timedelta(days=1)) | string) }}
  gft: "{{ states('sensor.afvalinfo_home_gft') == datum_doel }}"
  rest: "{{ states('sensor.afvalinfo_home_restafval') == datum_doel }}"
  pbd: "{{ states('sensor.afvalinfo_home_pbd') == datum_doel }}"
  items_list: >
    {{  | select('string') | list }}
  heeft_afval: "{{ items_list | length > 0 }}"
  lijst_afval: "{{ items_list | join(' en ') }}"
condition:
  - condition: template
    value_template: "{{ is_test or heeft_afval }}"
action:
  - service: switch.turn_on
    target:
      entity_id: switch.tab_woonkamer_scherm     # pas aan
  - service: rest_command.fully_stop_screensaver
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.afval_popup_actief
  - delay: "00:00:05"
  - service: rest_command.fully_fullscreen_http
    data:
      message: |-
        {% if is_avond %}Morgen{% else %}Vandaag{% endif %} wordt {{ lijst_afval if lijst_afval else '—' }} opgehaald!
        Vergeet de bak(ken) niet buiten te zetten. 👍

Hoe werkt de ochtend/avond-logica precies?

  • 07:00 → controleert vandaag → “Vandaag wordt … opgehaald”.

  • 21:00 → controleert morgen → “Morgen wordt … opgehaald”.

  • De automation stuurt alleen een pop-up als er voor de gecontroleerde dag daadwerkelijk een inzameling is.


Testen

  1. Herstart Home Assistant (na wijzigingen in configuration.yaml).

  2. Ontwikkelaarstools → Gebeurtenissen → afvalpopup_test → Vuren.

  3. Helper gaat AAN, pop-up verschijnt, watchdog houdt scherm aan.

  4. Tik Sluiten → webhook zet helper UIT → watchdog stopt → scherm mag weer uit na je Screen Off Timer.


Veelvoorkomende issues (& oplossingen)

  • Popup gebruikt oude code: cache-buster zit al in het REST-commando; zet in Fully “Delete cache on reload” aan.

  • Webhook doet niks: maar één automation met webhook_id: afval_popup_close; methods GET/POST toegestaan; automation herladen.

  • Scherm gaat toch uit: controleer dat de helper ON is, de watchdog draait en Fully’s Screen Off Timer niet te kort staat.


Producten die ik gebruik

Android-tablet – Betrouwbaar als Home Assistant dashboard. Bekijk bij Amazon

Tablet wandhouder – Voor verschillende Samsung-types. Bekijk bij Amazon

Fully Kiosk Browser (Pro) – Remote Admin, motion/face-detectie, kiosk-modus. Bekijk bij Fully

Afvalinfo (HACS) – Sensoren voor inzameldagen. Meer info


Slot

Met deze setup mis ik geen enkele afvalinzameling meer. De pop-up is duidelijk, het scherm blijft wakker, en met één tik op Sluiten is alles weer netjes. Kopieer de code, pas je URL’s en sensoren aan en je bent in no-time klaar. Let op: bewaar altijd je IP’s en wachtwoorden in secrets.yaml en verwijs ernaar met !secret.

Bekijk ook mijn slimme airco automatisering.