Chill-Division / M5Stack-ESPHome

Collection of information for getting M5Stack sensors / controllers working with ESPHome
Apache License 2.0
62 stars 9 forks source link

M5Stack ENV Pro Unit with Temperature, Humidity, Pressure and Gas Sensor (BME688) #9

Open DavidGeorge528 opened 1 month ago

DavidGeorge528 commented 1 month ago

Thought I would share a working configuration for the M5Stack ENV Pro. As I had some trouble finding all the information myself when adding it to a ESPHome. This is a stripped down version of this ESP yaml file, which I needed to update as the bme68x sections didn't work anymore and weren't compatible with the M5Stack Env Pro. Should run as is, except the i2c pins will need to be modified.

external_components:
  - source: github://neffs/esphome@bsec2_bme68x
    components:
      - bme68x_bsec2_i2c

i2c:
  sda: GPIO40
  scl: GPIO39
  frequency: 400kHz

bme68x_bsec2_i2c:
  model: bme688
  state_save_interval: 5min
  address: 0x77

sensor:
  - platform: bme68x_bsec2_i2c
    temperature:
      name: "Temperature"
      filters:
        - median
    pressure:
      name: "Pressure"
      filters:
        - median
    humidity:
      name: "Humidity"
      filters:
        - median
    iaq:
      name: "IAQ"
      id: iaq
      filters:
        - median
      on_value:
        - component.update: iaq_classification
    iaq_static:
      name: "Static IAQ"
      id: static_iaq
      filters:
        - median
      on_value:
        - component.update: static_iaq_classification
    co2_equivalent:
      name: "CO2 equivalent"
      filters:
        - median
    breath_voc_equivalent:
      name: "Breath VOC equivalent"
      filters:
        - median
    gas_resistance:
      # Gas resistance in Ω
      name: "Gas resistance"
      filters:
        - median

text_sensor:
  - platform: template
    name: "IAQ classification"
    id: iaq_classification
    icon: "mdi:checkbox-marked-circle-outline"
    lambda: |-
      auto iaq_ = int(id(iaq).state);
      if (iaq_ < 0) {
        // No IAQ sensor.
        return {"unknown"};
      }
      if (iaq_ <= 50) {
        return {"excellent"};
      }
      else if (iaq_ <= 100) {
        return {"good"};
      }
      else if (iaq_ <= 150) {
        return {"lightly polluted"};
      }
      else if (iaq_ <= 200) {
        return {"moderately polluted"};
      }
      else if (iaq_ <= 250) {
        return {"heavily polluted"};
      }
      else if (iaq_ <= 350) {
        return {"severely polluted"};
      }
      else if (iaq_ <= 500) {
        return {"extremely polluted"};
      }
      else {
        // ESP_LOGD("iaq-classification", "IAQ not yet established: %s", id(static_iaq).state);
        return {"unknown"};
      }
    update_interval: never

  - platform: template
    name: "Static IAQ classification"
    id: static_iaq_classification
    icon: "mdi:checkbox-marked-circle-outline"
    lambda: |-
      auto iaq_ = int(id(static_iaq).state);
      if (iaq_ < 0) {
        // No IAQ sensor.
        return {"unknown"};
      }
      if (iaq_ <= 50) {
        return {"excellent"};
      }
      else if (iaq_ <= 100) {
        return {"good"};
      }
      else if (iaq_ <= 150) {
        return {"lightly polluted"};
      }
      else if (iaq_ <= 200) {
        return {"moderately polluted"};
      }
      else if (iaq_ <= 250) {
        return {"heavily polluted"};
      }
      else if (iaq_ <= 350) {
        return {"severely polluted"};
      }
      else if (iaq_ <= 500) {
        return {"extremely polluted"};
      }
      else {
        // ESP_LOGD("iaq-classification", "IAQ not yet established: %s", id(static_iaq).state);
        return {"unknown"};
      }
    update_interval: never
  - platform: bme68x_bsec2_i2c
    iaq_accuracy: 
      name: "IAQ accuracy"
ChillingSilence commented 1 month ago

Hey that's perfect, thanks @DavidGeorge528 ! I've got one of those myself sitting here beside me and haven't found time to plug it in and try out, so thankyou very much for that. You're cool if this gets added verbatim then?

DavidGeorge528 commented 1 month ago

Hey, yeah I'm happy with that, think it would be a great help to anyone else who has it as it took me some digging.

If you do have one and a spare ESP32 and could quickly flash it with this + everything else needed to set it up, it would be great to verify that it all works before publishing it as I did cut it out of a much larger yaml file. I think its all there, but there could be some things wrong.

ChillingSilence commented 1 month ago

I won't be able to for a few days, but will leave this open until I have :) Thanks again!

ChillingSilence commented 4 weeks ago

So I finally found my ENV.Pro and went to give it a whirl... Only to find two issues:

  1. The custom component has been updated in the last week and doesn't seem to be working
  2. I have an M5NanoC6 for testing which won't work with the standard bme680_bsec because it uses esp-idf, and it only works with arduino 😢

Anyways I've found two sets of components that are already supported in esphome natively without relying on a 3rd party repo: https://esphome.io/components/sensor/bme680.html and https://esphome.io/components/sensor/bme680_bsec.html

So I can confirm that this is working for me:

i2c:
  sda: 2
  scl: 1

sensor:
  - platform: bme680
    temperature:
      name: "BME680 Temperature"
      oversampling: 16x
    pressure:
      name: "BME680 Pressure"
    humidity:
      id: "humidity"
      name: "BME680 Humidity"
    gas_resistance:
      id: "gas_resistance"
      name: "BME680 Gas Resistance"
    address: 0x77
    update_interval: 60s
  - platform: template
    name: "BME680 Indoor Air Quality"
    id: iaq
    icon: "mdi:gauge"
    # calculation: comp_gas = log(R_gas[ohm]) + 0.04 log(Ohm)/%rh * hum[%rh]
    lambda: |-
      return log(id(gas_resistance).state) + 0.04 *  id(humidity).state;
    state_class: "measurement"
text_sensor:
  - platform: template
    name: "BME680 IAQ Classification"
    icon: "mdi:checkbox-marked-circle-outline"
    lambda: |-
      if (int(id(iaq).state) <= 50) {
        return {"Excellent"};
      }
      else if (int(id(iaq).state) <= 100) {
        return {"Good"};
      }
      else if (int(id(iaq).state) <= 150) {
        return {"Lightly polluted"};
      }
      else if (int(id(iaq).state) <= 200) {
        return {"Moderately polluted"};
      }
      else if (int(id(iaq).state) <= 250) {
        return {"Heavily polluted"};
      }
      else if (int(id(iaq).state) <= 350) {
        return {"Severely polluted"};
      }
      else if (int(id(iaq).state) <= 500) {
        return {"Extremely polluted"};
      }
      else {
        return {"unknown"};
      }

But if you have a chance to test the BME688 with the bme680_bsec link, that'd be awesome 🙏

DavidGeorge528 commented 2 weeks ago

The latest update to ESPHome (2024.8.0) has the BME68x added natively, see the bme68x_bsec2_i2c section of the release notes. As result, my minimal example works with the following changes:

Below is the fixed example:

i2c:
  sda: GPIO40
  scl: GPIO39
  frequency: 400kHz

bme68x_bsec2_i2c:
  model: bme688
  state_save_interval: 5min
  address: 0x77

sensor:
  - platform: bme68x_bsec2
    temperature:
      name: "Temperature"
      filters:
        - median
    pressure:
      name: "Pressure"
      filters:
        - median
    humidity:
      name: "Humidity"
      filters:
        - median
    iaq:
      name: "IAQ"
      id: iaq
      filters:
        - median
      on_value:
        - component.update: iaq_classification
    iaq_static:
      name: "Static IAQ"
      id: static_iaq
      filters:
        - median
      on_value:
        - component.update: static_iaq_classification
    co2_equivalent:
      name: "CO2 equivalent"
      filters:
        - median
    breath_voc_equivalent:
      name: "Breath VOC equivalent"
      filters:
        - median
    gas_resistance:
      # Gas resistance in Ω
      name: "Gas resistance"
      filters:
        - median

text_sensor:
  - platform: template
    name: "IAQ classification"
    id: iaq_classification
    icon: "mdi:checkbox-marked-circle-outline"
    lambda: |-
      auto iaq_ = int(id(iaq).state);
      if (iaq_ < 0) {
        // No IAQ sensor.
        return {"unknown"};
      }
      if (iaq_ <= 50) {
        return {"excellent"};
      }
      else if (iaq_ <= 100) {
        return {"good"};
      }
      else if (iaq_ <= 150) {
        return {"lightly polluted"};
      }
      else if (iaq_ <= 200) {
        return {"moderately polluted"};
      }
      else if (iaq_ <= 250) {
        return {"heavily polluted"};
      }
      else if (iaq_ <= 350) {
        return {"severely polluted"};
      }
      else if (iaq_ <= 500) {
        return {"extremely polluted"};
      }
      else {
        // ESP_LOGD("iaq-classification", "IAQ not yet established: %s", id(static_iaq).state);
        return {"unknown"};
      }
    update_interval: never

  - platform: template
    name: "Static IAQ classification"
    id: static_iaq_classification
    icon: "mdi:checkbox-marked-circle-outline"
    lambda: |-
      auto iaq_ = int(id(static_iaq).state);
      if (iaq_ < 0) {
        // No IAQ sensor.
        return {"unknown"};
      }
      if (iaq_ <= 50) {
        return {"excellent"};
      }
      else if (iaq_ <= 100) {
        return {"good"};
      }
      else if (iaq_ <= 150) {
        return {"lightly polluted"};
      }
      else if (iaq_ <= 200) {
        return {"moderately polluted"};
      }
      else if (iaq_ <= 250) {
        return {"heavily polluted"};
      }
      else if (iaq_ <= 350) {
        return {"severely polluted"};
      }
      else if (iaq_ <= 500) {
        return {"extremely polluted"};
      }
      else {
        // ESP_LOGD("iaq-classification", "IAQ not yet established: %s", id(static_iaq).state);
        return {"unknown"};
      }
    update_interval: never
  - platform: bme68x_bsec2
    iaq_accuracy: 
      name: "IAQ accuracy"

This version allows for the 688 version of the BME sensor, which the M5 sensor is. Would be grateful if you could verify if yours works with this version, instead of the 680 version only.

Be mindful of the config variables as mine are likely different to yours