Schluss mit dicker Luft: Die LinkGear CO2-Ampel

Originally published at: Schluss mit dicker Luft: Die LinkGear CO2-Ampel

Fühlst du dich oft müde oder ist die Luft zu Hause schnell „verbraucht“? Die smarte CO2-Ampel von LinkGear zeigt dir dank intuitivem LED-Ring sofort, wann es Zeit zum Lüften ist. Anders als günstige Alternativen, die Werte oft nur schätzen, setzt dieses Multi-Sensor-Board auf den hochpräzisen SCD41-Sensor für echte und verlässliche Messdaten. Erfahre im Video, warum diese CO2-Ampel ihr Geld absolut wert ist, wie einfach sie sich dank ESPHome lokal und ohne Cloud-Zwang in Home Assistant integrieren lässt und wie du dein Raumklima damit smart automatisierst.

Hallo Olli, hier ist die Weiterführung der Diskussion von u-tube. Ich möchte die CO2 Ampel im Wohnmobil nutzen. Hierzu möchte ich die LED Anzeige z.B. von 22 bis 7 Uhr ausschalten. Zurzeit wird die ausgeschaltete LED scheinbar bei der Aktualisierung des nächstes Messwertes wieder eingeschaltet. Gruß Thomas

Hi Thomas!

Ich habe das mal wie folgt umgesetzt:

substitutions:
  device_name: linkgear-co2-ampel-967258
  friendly_name: LinkGear CO2 Ampel
  project_name: LinkGear.co2ampel
  project_version: '1.0'

esphome:
  name: ${device_name}
  name_add_mac_suffix: false
  project:
    name: ${project_name}
    version: ${project_version}

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Zuverlässiger Zeitserver für Deutschland (inklusive Sommer-/Winterzeit)
time:
  - platform: sntp
    id: sntp_time
    servers:
      - 0.de.pool.ntp.org
      - 1.de.pool.ntp.org
    timezone: "CET-1CEST,M3.5.0,M10.5.0/3"

datetime:
  - platform: template
    name: "Nachtmodus Start"
    id: night_mode_start
    type: time
    optimistic: true
    initial_value: "22:00:00"
    restore_value: true

  - platform: template
    name: "Nachtmodus Ende"
    id: night_mode_end
    type: time
    optimistic: true
    initial_value: "07:00:00"
    restore_value: true


# Enable Home Assistant API
api:
  actions:
  - action: eca_action_rtttl
    variables:
      song_str: string
    then:
    - rtttl.play:
        rtttl: !lambda 'return song_str;'

# Enable Over The Air updates
ota:
  platform: esphome

#Public location of this yaml file
dashboard_import:
  package_import_url: 
    github://performeon/LinkGearMisc/products/lg-eca/eca_esphome_config_hwv1_cv1.yaml@main
  import_full_config: true

# Enable fallback hotspot (captive portal) in case wifi connection fails
captive_portal:

improv_serial:

esp32_improv:
  authorizer: none

wifi:
  ap:
    ssid: ${friendly_name}

i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true
  id: bus_a

sensor:
- platform: scd4x
  ambient_pressure_compensation_source: eca_bme_pressure
  # temperature_offset: 4  # 4 is default, adjust to your needs
  update_interval: 60s
  co2:
    name: SCD41 CO2
    id: eca_scd41_co2
    on_value:
      then:
        - logger.log:
            format: ">>> Aktuelle ESP-Zeit: %02d:%02d Uhr | Zeit gueltig: %s"
            args: [ 'id(sntp_time).now().hour', 'id(sntp_time).now().minute', 'id(sntp_time).now().is_valid() ? "JA" : "NEIN"' ]
            
        - if:
            condition:
              lambda: |-
                auto time = id(sntp_time).now();
                // Prüft: Ist es 22 Uhr (oder später) ODER ist es vor 9 Uhr morgens?                
                return time.is_valid() && (time.hour >= id(night_mode_start).hour || time.hour < id(night_mode_end).hour);
            then:
              - light.turn_off:
                  id: eca_leds
            else:
              - if:
                  condition:
                    lambda: return id(eca_scd41_co2).state < 800;
                  then:
                  - light.turn_on:
                      id: eca_leds
                      brightness: 30%
                      red: 0%
                      green: 100%
                      blue: 0%
              - if:
                  condition:
                    lambda: return id(eca_scd41_co2).state >= 800 && id(eca_scd41_co2).state < 1200;
                  then:
                  - light.turn_on:
                      id: eca_leds
                      brightness: 30%
                      red: 100%
                      green: 100%
                      blue: 0%
              - if:
                  condition:
                    lambda: return id(eca_scd41_co2).state >= 1200 && id(eca_scd41_co2).state < 1500;
                  then:
                  - light.turn_on:
                      id: eca_leds
                      brightness: 30%
                      red: 100%
                      green: 50%
                      blue: 0%
              - if:
                  condition:
                    lambda: return id(eca_scd41_co2).state >= 1500;
                  then:
                  - light.turn_on:
                      id: eca_leds
                      brightness: 50%
                      red: 100%
                      green: 0%
                      blue: 0%

  temperature:
    name: SCD41 Temperature
    id: eca_scd41_temp
    filters:
    - offset: -4   # -4 is a good value when used in an enclosure
  humidity:
    name: SCD41 Humidity
    id: eca_scd41_hum

- platform: bme280_i2c
  address: 0x76
  temperature:
    name: BME280 Temperature
    id: eca_bme_temp
    filters:
    - offset: -7   # -7 is a good value when used in an enclosure
  pressure:
    name: BME280 Pressure
    id: eca_bme_pressure
  humidity:
    name: BME280 Humidity
    id: eca_bme_hum

- platform: bh1750
  name: BH1750 Illuminance
  id: eca_bh1750_illuminance
  #address: 0x23
  address: 0x5c
  update_interval: 60s

- platform: template
  name: SCD41 CO2 Moving Average 60m
  id: eca_co2_moving_avg
  unit_of_measurement: ppm
  lambda: |-
    return id(eca_scd41_co2).state;
  filters:
  - sliding_window_moving_average:
      window_size: 60
      send_every: 1

light:
- platform: esp32_rmt_led_strip
  name: SK6812 LEDs
  rgb_order: GRB
  pin: GPIO18
  num_leds: 8
  #rmt_channel: 0
  chipset: SK6812
  id: eca_leds
  restore_mode: ALWAYS_OFF    # Ensures the light is initially off

output:
- platform: ledc
  pin: GPIO19
  channel: 0
  id: eca_buzzer_gpio19

rtttl:
  output: eca_buzzer_gpio19
  gain: 90%
  on_finished_playback:
  - logger.log: Song ended!
  id: eca_buzzer

Das ist der vollständige Code meiner CO2-Ampel aktuell der im Wesentlichen um

datetime:
  - platform: template
    name: "Nachtmodus Start"
    id: night_mode_start
    type: time
    optimistic: true
    initial_value: "22:00:00"
    restore_value: true

  - platform: template
    name: "Nachtmodus Ende"
    id: night_mode_end
    type: time
    optimistic: true
    initial_value: "07:00:00"
    restore_value: true

erweitert wurde, wodurch man die Start- und Endzeit des Nachtmodus direkt über die Geräteseite bspw. steuern kann:

Und zusätzlich gibt es dann noch die Prüfung auf die Uhrzeit, die folgende Änderungen mit sich bringen:

co2:
    name: SCD41 CO2
    id: eca_scd41_co2
    on_value:
      then:
        - logger.log:
            format: ">>> Aktuelle ESP-Zeit: %02d:%02d Uhr | Zeit gueltig: %s"
            args: [ 'id(sntp_time).now().hour', 'id(sntp_time).now().minute', 'id(sntp_time).now().is_valid() ? "JA" : "NEIN"' ]
            
        - if:
            condition:
              lambda: |-
                auto time = id(sntp_time).now();
                // Prüft: Ist es 22 Uhr (oder später) ODER ist es vor 9 Uhr morgens?                
                return time.is_valid() && (time.hour >= id(night_mode_start).hour || time.hour < id(night_mode_end).hour);
            then:
              - light.turn_off:
                  id: eca_leds
            else:
              - if:
                  condition:
                    lambda: return id(eca_scd41_co2).state < 800;
                  then:
                  - light.turn_on:
                      id: eca_leds
                      brightness: 30%
                      red: 0%
                      green: 100%
                      blue: 0%
              - if:
                  condition:
                    lambda: return id(eca_scd41_co2).state >= 800 && id(eca_scd41_co2).state < 1200;
                  then:
                  - light.turn_on:
                      id: eca_leds
                      brightness: 30%
                      red: 100%
                      green: 100%
                      blue: 0%
              - if:
                  condition:
                    lambda: return id(eca_scd41_co2).state >= 1200 && id(eca_scd41_co2).state < 1500;
                  then:
                  - light.turn_on:
                      id: eca_leds
                      brightness: 30%
                      red: 100%
                      green: 50%
                      blue: 0%
              - if:
                  condition:
                    lambda: return id(eca_scd41_co2).state >= 1500;
                  then:
                  - light.turn_on:
                      id: eca_leds
                      brightness: 50%
                      red: 100%
                      green: 0%
                      blue: 0%

Beide hier noch einmal explizit erwähnten Änderungen sind im eingangs eingefügten YAML-Code enthalten und sollten so übernommen werden können.

Was noch nicht klappt, ist dass die CO2-Ampel dynamisch auf das Ändern der Start- oder Endzeit reagiert. Aber wenn man dann die Ampel manuell ausschaltet, sollte sie ausgeschaltet bleiben, solange man sich im Nachtmodus-Zeitfenster befindet.

VG Olli

Hallo Olli,

vielen Dank !!!

In der Zeile 217 musst du vor den Kommentar noch bitte “#” setzten.

Für die Fehler habe ich keine Lösung:

ERROR Error while reading config: Invalid YAML syntax:

Duplicate key „datetime“
in „/config/esphome/linkgear-co2-ampel-966f78.yaml“, line 219, column 1
NOTE: Previous declaration here:
in „/config/esphome/linkgear-co2-ampel-966f78.yaml“, line 31, column 1

Gruß Thomas

Hi Thomas,

der Code ganz oben in meiner letzten Antwort ist der vollständige, funktionale Code. Die Code-Schnipsel darunter sind die Erklärungen, wozu ich was ergänzt habe (was aber oben im Code so schon enthalten ist).

Mein funktionaler Code ist 215 Zeilen lang, weshalb ich annehme, dass du den obigen Code um die Codeschnipsel ergänzt hast?

VG Olli