2026-10-13

Alten Roomba smart machen

Die neuen Saug-Wisch-Roboter sind schon genial. Wir haben uns einen Mova Z70 zugelegt. Hammerteil.

Aber was machen wir mit unserem alten Roomba?

  • Er ist über 10 (!) Jahre alt.
  • Läuft immer noch.
  • Saugt halt nur.
  • Sensorik eingeschränkt.
  • Kann über eine Fernbedienung gesteuert werden.

Meine Lösung:

Die Fernsteuerung wird zerlegt. In ein separates Gehäuse kommen Ultraschall-Entfernungs-Sensoren, ein Relais, ein Touch-Taster und eine RGB-LED (WS2812B). Zur Steuerung genügt ein ESP8266.

Fix mal alles verdrahten. Die Roomba-Fernsteuerung wird über 3,3V vom ESP versorgt.

Alles in ein Gehäuse.

Die Docking wird über eine Halterung an der Wand oberhalb der Sockelleiste fest montiert, dann wandert da nichts.

 

Konfiguration des ESP:

esphome:
  name: esp21roomba

esp8266:
  board: nodemcuv2
  framework:
    version: recommended


################################################################################
# RoombaBot Küche
################################################################################

wifi:
  networks:
    - ssid: !secret wifi_ssid
      password: !secret wifi_password

  manual_ip:
    static_ip: 192.168.x.y
    gateway: 192.168.x.1
    subnet: 255.255.255.0

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  - platform: esphome

switch:
# Roomba starten
  - platform: gpio
    pin: D1
    id: relay
  - platform: template
    name: "esp21_roomba"
    icon: "mdi:robot-vacuum"
    turn_on_action:
    - switch.turn_on: relay
    - delay: 500ms
    - switch.turn_off: relay

  - platform: restart
    name: "restart_esp21"

sensor:
  - platform: ultrasonic
    trigger_pin: D5
    echo_pin: D6
    name: "roomba_present"
    id: roomba_present

binary_sensor:
  - platform: template
    name: roomba_at_home
    lambda: !lambda |-
      if (id(roomba_present).state < 0.07) {
          return true;
      } else {
        return false;
      }
 # Taster: Staubbehälter wurde geleert
  - platform: gpio
    pin:
      number: D2
      mode: INPUT_PULLUP
    #  inverted: true
    name: "Roomba Behälter geleert"
    id: roomba_geleert
    filters:
      - delayed_on: 50ms
      - delayed_off: 50ms
light:
  - platform: neopixelbus
    type: GRB
    variant: WS2812
    pin: D7
    num_leds: 1
    name: "Roomba Status LED"
    id: roomba_led
    restore_mode: ALWAYS_OFF

Verdrahtungsplan:

Helfer zur Steuerung:

Typ 

Name 

Entity-ID 

Zähler 

Roomba Wartungszähler 

counter.roomba_wartung 

Dropdown 

Roomba Wartungsintervall 

input_select.roomba_wartungsintervall 

Datum und Uhrzeit 

Roomba letzte Leerung 

input_datetime.roomba_letzte_leerung 

Datum und Uhrzeit 

Roomba letzte Wartung 

input_datetime.roomba_letzte_wartung 

Zeitplan 

Roomba Reinigung 

schedule.roomba_reinigung 

Boolean 

Roomba unterwegs 

input_boolean.roomba_unterwegs 

Zähler 

Roomba Reinigungen 

counter.roomba_reinigungen 

Zähler 

Roomba Gesamt Reinigungen 

counter.roomba_gesamt_reinigungen 

 

 


Scripte:

alias: Roomba Behälter geleert
description: Setzt den Leerungszähler zurück und speichert den Zeitpunkt
sequence:
  - action: counter.reset
    target:
      entity_id: counter.roomba_reinigungen
  - action: input_datetime.set_datetime
    target:
      entity_id: input_datetime.roomba_letzte_leerung
    data:
      timestamp: '{{ now().timestamp() }}'
mode: single

 

alias: Roomba Gesamtwartung durchgeführt
description: Setzt den Wartungszähler zurück und speichert den Zeitpunkt
sequence:
  - action: counter.reset
    target:
      entity_id: counter.roomba_wartung
  - action: input_datetime.set_datetime
    target:
      entity_id: input_datetime.roomba_letzte_wartung
    data:
      timestamp: '{{ now().timestamp() }}'
mode: single
 

Automatisierungen:

 alias: Roomba - Status LED
description: Grün unter 4, Rot ab 4 Reinigungen
triggers:
  - trigger: state
    entity_id: counter.roomba_reinigungen
  - trigger: homeassistant
    event: start
actions:
  - choose:
      - conditions:
          - condition: numeric_state
            entity_id: counter.roomba_reinigungen
            above: 3
        sequence:
          - action: light.turn_on
            target:
              entity_id:
                - light.kuche_esp21roomba_roomba_status_led
            data:
              rgb_color:
                - 255
                - 0
                - 0
              brightness_pct: 10
    default:
      - action: light.turn_on
        target:
          entity_id:
            - light.kuche_esp21roomba_roomba_status_led
        data:
          rgb_color:
            - 0
            - 255
            - 0
          brightness_pct: 10
mode: restart

 

alias: Roomba - Reinigungsläufe zählen
description: Zählt Reinigungsläufe seit Leerung und insgesamt
triggers:
  - trigger: state
    entity_id: binary_sensor.roomba_at_home
    from: 'on'
    to: 'off'
    for:
      seconds: 15
    id: verlassen
  - trigger: state
    entity_id: binary_sensor.roomba_at_home
    from: 'off'
    to: 'on'
    for:
      seconds: 15
    id: angekommen
actions:
  - choose:
      - conditions:
          - condition: trigger
            id: verlassen
        sequence:
          - action: input_boolean.turn_on
            target:
              entity_id: input_boolean.roomba_unterwegs
      - conditions:
          - condition: trigger
            id: angekommen
          - condition: state
            entity_id: input_boolean.roomba_unterwegs
            state: 'on'
        sequence:
          - action: counter.increment
            target:
              entity_id:
                - counter.roomba_reinigungen
                - counter.roomba_gesamt_reinigungen
                - counter.roomba_wartung
            data: {}
          - action: input_boolean.turn_off
            target:
              entity_id: input_boolean.roomba_unterwegs
mode: queued

 

alias: Roomba - Start nach Zeitplan
description: Startet den Roomba bei aktiviertem Zeitplan
triggers:
  - trigger: state
    entity_id: schedule.roomba_reinigung
    from: 'off'
    to: 'on'
conditions:
  - condition: state
    entity_id: binary_sensor.roomba_at_home
    state: 'on'
actions:
  - action: switch.turn_on
    target:
      entity_id: switch.esp21_roomba
mode: single

 

alias: Roomba - Behälter gereinigt
description: Setzt den Reinigungszähler zurück
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.kuche_esp21roomba_roomba_behalter_geleert
    from:
      - 'off'
    to:
      - 'on'
actions:
  - action: counter.reset
    target:
      entity_id: counter.roomba_reinigungen
mode: single

 

alias: Roomba Gesamtwartung fällig
description: Meldung bei erreichtem Wartungsintervall
triggers:
  - trigger: state
    entity_id:
      - counter.roomba_wartung
      - input_select.roomba_wartungsintervall
conditions:
  - condition: template
    value_template: >
      {% set count = states('counter.roomba_wartung') | int(0) %} {% set limit =
      states('input_select.roomba_wartungsintervall') | int(25) %} {{ count >=
      limit }}
actions:
  - action: persistent_notification.create
    data:
      notification_id: roomba_gesamtwartung
      title: Roomba – Gesamtwartung erforderlich
      message: >
        Der Roomba hat {{ states('counter.roomba_wartung') }} Reinigungen seit
        der letzten Wartung durchgeführt. Bitte Wartung durchführen.
mode: single
 

Dashbord-Kacheln:

Hier als RAW-Definition:

      - type: grid
        cards:
          - type: vertical-stack
            cards:
              - type: heading
                heading: Roomba – Reinigung
                heading_style: title
                icon: mdi:robot-vacuum
              - type: horizontal-stack
                cards:
                  - type: tile
                    entity: binary_sensor.roomba_at_home
                    name: Dockingstation
                    icon: mdi:home
                    color: green
                    vertical: true
                    features_position: bottom
                  - type: tile
                    entity: counter.roomba_reinigungen
                    name: Seit Leerung
                    icon: mdi:counter
                    color: green
                    vertical: true
                    features_position: bottom
              - type: conditional
                conditions:
                  - condition: numeric_state
                    entity: counter.roomba_reinigungen
                    above: 3
                card:
                  type: markdown
                  content: |
                    ## 🔴 Behälter leeren
                    Der Roomba hat mindestens vier
                    Reinigungen durchgeführt.
                    Bitte Staubbehälter leeren.
              - type: conditional
                conditions:
                  - condition: numeric_state
                    entity: counter.roomba_reinigungen
                    below: 4
                card:
                  type: markdown
                  content: |
                    ## 🟢 Behälter OK
                    **{{ states('counter.roomba_reinigungen') }} / 4**
                    Reinigungen seit letzter Leerung.
              - type: horizontal-stack
                cards:
                  - type: button
                    name: Roomba starten
                    icon: mdi:play-circle
                    show_state: false
                    tap_action:
                      action: call-service
                      service: switch.turn_on
                      target:
                        entity_id: switch.esp21_roomba
              - type: entities
                title: Reinigungsstatistik
                show_header_toggle: false
                entities:
                  - entity: counter.roomba_gesamt_reinigungen
                    name: Reinigungen insgesamt
                    icon: mdi:chart-line
          - type: vertical-stack
            cards:
              - type: heading
                heading: Roomba – Wartung
                heading_style: title
                icon: mdi:tools
              - type: markdown
                content: >-
                  {% set n = states('counter.roomba_reinigungen') | int(0) %} {%
                  set last = states('input_datetime.roomba_letzte_leerung') %}
                  ### {{ '🔴 Behälter leeren' if n >= 4 else '🟢 Behälter OK' }}

                  **{{ n }} / 4 Reinigungen**

                  {% if last not in ['unknown','unavailable','none'] %} Letzte
                  Leerung vor: {{ relative_time(as_datetime(last)) }} {% else %}
                  Letzte Leerung: Noch nicht erfasst {% endif %}
              - show_name: true
                show_icon: true
                type: button
                name: Behälter geleert – Reset
                icon: mdi:delete-empty
                tap_action:
                  action: perform-action
                  perform_action: script.roomba_behalter_geleert
                  confirmation:
                    text: Wurde der Staubbehälter geleert?
                  target: {}
              - type: markdown
                content: >-
                  {% set n = states('counter.roomba_wartung') | int(0) %} {% set
                  limit = states('input_select.roomba_wartungsintervall') |
                  int(25) %} {% set rest = [limit - n, 0] | max %} {% set last =
                  states('input_datetime.roomba_letzte_wartung') %}

                  ### {{ '🔴 Wartung erforderlich' if n >= limit else '🟢
                  Wartung OK' }}

                  **{{ n }} / {{ limit }} Reinigungen**

                  {% if n >= limit %} Wartungsintervall erreicht! {% else %}
                  Noch {{ rest }} Reinigungen bis zur Wartung. {% endif %}

                  {% if last not in ['unknown','unavailable','none'] %} Letzte
                  Wartung vor: {{ relative_time(as_datetime(last)) }} {% else %}
                  Letzte Wartung: Noch nicht erfasst {% endif %}
              - show_name: true
                show_icon: true
                type: button
                name: Gesamtwartung durchgeführt
                icon: mdi:tools
                tap_action:
                  action: perform-action
                  perform_action: script.roomba_gesamtwartung_durchgefuhrt
                  confirmation:
                    text: Wurde die Gesamtwartung durchgeführt?
                  target: {}
              - type: entities
                title: Gesamtwartung
                show_header_toggle: false
                entities:
                  - entity: counter.roomba_wartung
                    name: Reinigungen seit Wartung
                    icon: mdi:counter
                  - entity: input_select.roomba_wartungsintervall
                    name: Wartung alle
                    icon: mdi:cog-clock


 Schaut dann so aus:

 

 

Das Gehäuse für den ESP mitsamt der Elektronik gibt es auf printables.com. 

Strommix Deutschland als ApexChart in HomeAssistant

The Energy Charts: Online Data Platform Relaunched Today with New Features -  Fraunhofer ISE 

Installation: 

1. HACS öffnen und unter den benutzerdefinierten Repositories https://github.com/Philra94/homeassistant-energy-charts hinzufügen. 

2. Typ „Integration“ auswählen und Energy-Charts installieren. 

3. Home Assistant neu starten. 

4. Unter Einstellungen → Geräte & Dienste Energy-Charts hinzufügen. 

5. Land „Germany“, Aktualisierung 15 Minuten und historische Daten „Week“ auswählen. 

Datenaggregation:

Kleine Helfer-Sensoren erstellen, um die einzelnen Kategorien zusammenzufassen 

Strommix auf acht Erzeugungskategorien reduzieren.
Damit bleibt das Diagramm übersichtlich, ohne die wesentlichen Unterschiede zwischen den Energieträgern zu verlieren. 


 Füge folgende Definition in deine configuration.yaml ein. Falls du bereits einen template:-Abschnitt hast, ergänze nur den darunterliegenden - sensor:-Block.

 
template:
  - sensor:
      - name: "Strommix Solar"
        unique_id: strommix_solar
        unit_of_measurement: "MW"
        state_class: measurement
        state: >
          {{ states('sensor.energy_charts_germany_solar') | float(0) }}

      - name: "Strommix Wind"
        unique_id: strommix_wind
        unit_of_measurement: "MW"
        state_class: measurement
        state: >
          {{ states('sensor.energy_charts_germany_wind_total') | float(0) }}

      - name: "Strommix Wasser"
        unique_id: strommix_wasser
        unit_of_measurement: "MW"
        state_class: measurement
        state: >
          {{
            states('sensor.energy_charts_germany_hydro_run_of_river') | float(0)
            + states('sensor.energy_charts_germany_hydro_water_reservoir') | float(0)
          }}

      - name: "Strommix Sonstige EE"
        unique_id: strommix_sonstige_ee
        unit_of_measurement: "MW"
        state_class: measurement
        state: >
          {{
            states('sensor.energy_charts_germany_biomass') | float(0)
            + states('sensor.energy_charts_germany_geothermal') | float(0)
          }}

      - name: "Strommix Kohle"
        unique_id: strommix_kohle
        unit_of_measurement: "MW"
        state_class: measurement
        state: >
          {{
            states('sensor.energy_charts_germany_fossil_brown_coal_lignite') | float(0)
            + states('sensor.energy_charts_germany_fossil_hard_coal') | float(0)
            + states('sensor.energy_charts_germany_fossil_coal_derived_gas') | float(0)
          }}

      - name: "Strommix Gas und Oel"
        unique_id: strommix_gas_und_ol
        unit_of_measurement: "MW"
        state_class: measurement
        state: >
          {{
            states('sensor.energy_charts_germany_fossil_gas') | float(0)
            + states('sensor.energy_charts_germany_fossil_oil') | float(0)
          }}

      - name: "Strommix Atom"
        unique_id: strommix_atom
        unit_of_measurement: "MW"
        state_class: measurement
        state: >
          {{ states('sensor.energy_charts_germany_nuclear_production') | float(0) }}

      - name: "Strommix Sonstige"
        unique_id: strommix_sonstige
        unit_of_measurement: "MW"
        state_class: measurement
        state: >
          {{
            states('sensor.energy_charts_germany_hydro_pumped_storage') | float(0)
            + states('sensor.energy_charts_germany_waste') | float(0)
            + states('sensor.energy_charts_germany_others') | float(0)
          }}

ApexCart-Definition:


type: custom:apexcharts-card
graph_span: 7d
update_interval: 15min
stacked: true

header:
  show: true
  title: Strommix Deutschland – 7 Tage
  show_states: false

apex_config:
  chart:
    height: 400
    stacked: true
    stackType: 100%
    toolbar:
      show: false
  plotOptions:
    bar:
      columnWidth: 95%
      borderRadius: 0
  dataLabels:
    enabled: false
  stroke:
    width: 0
  legend:
    show: true
    position: bottom
  tooltip:
    shared: true
    intersect: false
    y:
      formatter: |
        EVAL:function(value) {
          return value.toFixed(0) + " MW";
        }

yaxis:
  - min: 0
    max: 100
    decimals: 0
    apex_config:
      title:
        text: "Anteil (%)"
      labels:
        formatter: |
          EVAL:function(value) {
            return value.toFixed(0) + " %";
          }

all_series_config:
  type: column
  group_by:
    func: avg
    duration: 1h
    fill: "null"
  show:
    legend_value: false

series:
  - entity: sensor.strommix_solar
    name: Solar
    color: "#FFD54F"

  - entity: sensor.strommix_wind
    name: Wind
    color: "#66BB6A"

  - entity: sensor.strommix_wasser
    name: Wasser
    color: "#2196F3"

  - entity: sensor.strommix_sonstige_ee
    name: Sonstige EE
    color: "#388E3C"

  - entity: sensor.strommix_kohle
    name: Kohle
    color: "#795548"

  - entity: sensor.strommix_gas_und_oel
    name: Gas und Öl
    color: "#FF9800"

  - entity: sensor.strommix_atom
    name: Atom
    color: "#9C27B0"

  - entity: sensor.strommix_sonstige
    name: Sonstige
    color: "#90A4AE"
 

Und wenn Daten drin sind, dann schaut die Grafik auch besser aus: