esphome / issues

Issue Tracker for ESPHome
https://esphome.io/
291 stars 34 forks source link

Si1145 detected but reads 0 when i2c enabled #960

Closed zomfg closed 3 years ago

zomfg commented 4 years ago

Operating environment/Installation (Hass.io/Docker/pip/etc.):

1.14.3 in Docker

ESP (ESP32/ESP8266, Board/Sonoff):

ESP8266 Wemos D1 mini

Affected component:

i2c and custom https://esphome.io/components/sensor/custom.html

Description of problem:

See 3rd comment for the update Si1145 is detected (0x60) and initialized (.begin() returns true), yet it returns 0 for all three values

Problem-relevant YAML-configuration entries:

esphome:
  name: kitchen_weather_display
  platform: ESP8266
  board: d1_mini
  includes:
    - light_sensor.h
  libraries:
    - "Adafruit SI1145 Library"

wifi:
  ssid: ssid
  password: passwd
  fast_connect: true
  use_address: xx.xx.xx.xx
  domain: ".topkek"

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:

i2c:
  scan: False

sensor:
  - platform: custom
    lambda: |-
      auto light_sensor = new LightSensor();
      App.register_component(light_sensor);
      return {light_sensor};

    sensors:
      name: "Visible Light"
      unit_of_measurement: lux
      accuracy_decimals: 0

Logs (if applicable):

[19:46:28][D][sensor:092]: 'Visible Light': Sending state 0.00000 lux with 0 decimals of accuracy
[19:46:28][D][custom:044]: The value of sensor is: 0

Additional information and things you've tried: This is basically a duplicate of #342 that doesn't work, and my tests make me believe it's related to ESPHome.

Here's my light_sensor.h

#include "esphome.h"
#include "Adafruit_SI1145.h"

using namespace esphome;

class LightSensor : public PollingComponent, public Sensor {
 public:

  Adafruit_SI1145 si;

  LightSensor() : PollingComponent(5000) { }

  void setup() override {
    si.begin();
  }

  void update() override {
    uint16_t visible = si.readVisible();
    publish_state((float)visible);
    ESP_LOGD("custom", "The value of sensor is: %d", visible);
  }
};

I tried different things: casting value in different places, delaying .begin, .reset()ing (like in #342), setting the address manually (0x60), declaring Sensors as properties.

If I publish_state() a hardcoded value, I get that value on the other side as expected.

I tried i2c with and without scan: it detects a device at 0x60 as expected. .begin() returns true in both cases.

I made a VM with an updated Ubuntu Desktop 18.04.3 LTS (same-ish as Docker container), Arduino IDE 1.8.10 (from the website), ESP 2.6.3, and Adafruit Si1145 1.1.0 (same as Docker container), and this sketch works as expected on the same board without touching the wiring (also works on Windows)

#include <Adafruit_SI1145.h>

// i2c 0x60 Si1145
Adafruit_SI1145 uv = Adafruit_SI1145();

void setup() {
  Serial.begin(115200);
  Serial.println("init display");

  if (! uv.begin()) {
    Serial.println("Didn't find Si1145");
    while (1);
  }

  Serial.println("OK!");
  delay(1000);
}

char buffer[24];
void loop() {
  Serial.println("===================");
  Serial.print("Vis: "); Serial.println(uv.readVisible());
  Serial.print("IR: "); Serial.println(uv.readIR());
  // Uncomment if you have an IR LED attached to LED pin!
  //Serial.print("Prox: "); Serial.println(uv.readProx());
  float UVindex = uv.readUV();
  // the index is multiplied by 100 so to get the
  // integer index, divide by 100!
  UVindex /= 100.0;  
  Serial.print("UV: ");  Serial.println(UVindex);
  sprintf(buffer, "Vis : %d", uv.readVisible());
  Serial.println(buffer);
  sprintf(buffer, "IR   :  %d", uv.readIR());
  sprintf(buffer, "UV   :  %d", + uv.readUV());
  delay(1000);  
}

so maybe a version of some bit of the toolchain bundled with current ESPHome has some issue?

zomfg commented 4 years ago

Just tried swapping SI1145 for BME280 in light_sensor.h (which works fine with the native esphome component) and same result, 0 all around. It's as if the external i2c/wire library (Adafruit_* in this case) was in conflict with the native i2c or something? Or something is missing from the BMP085 sample here I also saw the I2CDevice bit, but I guess this is for implementing the whole i2c thing by yourself, and does not apply for when it's offloaded to an Adafruit library for ex.

zomfg commented 4 years ago

So with these base files

esphome:
  name: kitchen_weather_display
  platform: ESP8266
  board: d1_mini
  includes:
    - light_sensor.h
  libraries:
    - "Adafruit Unified Sensor"
    - "Adafruit BME280 Library"
    - "Adafruit SI1145 Library"

# Enable logging
logger:
api:
ota:

sensor:
  - platform: custom
    lambda: |-
      auto light_sensor = new LightSensor();
      App.register_component(light_sensor);
      return {light_sensor};

    sensors:
      name: "Visible Light"
      unit_of_measurement: lux
      accuracy_decimals: 1

light_sensor.h

#include "esphome.h"
#include "Adafruit_SI1145.h"
#include "Adafruit_BME280.h"

using namespace esphome;

class LightSensor : public PollingComponent, public Sensor {
 public:

  Adafruit_SI1145 si;
  Adafruit_BME280 bm;

  bool bmi = false;
  bool sii = false;

  LightSensor() : PollingComponent(5000) { }

  void setup() override {
    bmi = bm.begin(0x76);
    sii = si.begin(0x60);
  }

  void update() override {
    ESP_LOGD("custom", "BME.begin() == %s | pressure : %.2f", bmi ? "OK" : "FAIL", bm.readPressure() / 100.0);
    ESP_LOGD("custom", "SI.begin() == %s | visible : %d", sii ? "OK" : "FAIL", si.readVisible());
  }
};

both sensors work fine at the same time

[17:33:24][D][custom:025]: BME.begin() == OK | pressure : 1023.05
[17:33:24][D][custom:026]: SI.begin() == OK | visible : 259

but as soon as I enable i2c in the YAML, SI1145 stops reading right values

[18:27:09][I][i2c:033]: Scanning i2c bus for active devices...
[18:27:09][I][i2c:040]: Found i2c device at address 0x60
[18:27:09][I][i2c:040]: Found i2c device at address 0x76
...
[18:27:13][D][custom:025]: BME.begin() == OK | pressure : 1023.12
[18:27:13][D][custom:026]: SI.begin() == OK | visible : 0

Now, I don't know if this is normal or which of the two i2c implementations is at fault here

DreadPirateMiko commented 4 years ago

I'm having the same issue... have you found a workaround for that?

zomfg commented 4 years ago

the workaround is in my last message

this is what I ended up with

#include "esphome.h"
#include "Adafruit_SI1145.h"
#include "Adafruit_BME280.h"
using namespace esphome;
class LightSensor : public PollingComponent {
 public:
  Adafruit_SI1145 si;
  Adafruit_BME280 bm;
  bool bmi = false;
  bool sii = false;
  sensor::Sensor *visible_sensor = new sensor::Sensor();
  sensor::Sensor *ir_sensor = new sensor::Sensor();
  sensor::Sensor *uvindex_sensor = new sensor::Sensor();
  sensor::Sensor *temperature_sensor = new sensor::Sensor();
  sensor::Sensor *pressure_sensor = new sensor::Sensor();
  sensor::Sensor *humidity_sensor = new sensor::Sensor();

  LightSensor() : PollingComponent(5000) { }
  void setup() override {
    bmi = bm.begin(0x76);
    sii = si.begin(0x60);
  }
  void update() override {
    int visible = si.readVisible();
    visible_sensor->publish_state(visible);
    int irlight = si.readIR();
    ir_sensor->publish_state(irlight);
    int uvindex = si.readUV();
    uvindex_sensor->publish_state(uvindex / 100.0);
    float temperature = bm.readTemperature();
    temperature_sensor->publish_state(temperature);
    int pressure = bm.readPressure();
    pressure_sensor->publish_state(pressure / 100.0);
    float humidity = bm.readHumidity();
    humidity_sensor->publish_state(humidity);
    //ESP_LOGD("custom", "BME.begin() == %s | pressure : %.2f", bmi ? "OK" : "FAIL", bm.readPressure() / 100.0);
    //ESP_LOGD("custom", "SI.begin() == %s | visible : %d", sii ? "OK" : "FAIL", si.readVisible());
  }
};
esphome:
  name: kitchen_weather_display
  platform: ESP8266
  board: d1_mini
  includes:
    - light_sensor.h
  libraries:
    - "Adafruit Unified Sensor"
    - "Adafruit BME280 Library"
    - "Adafruit SI1145 Library"

# Enable logging
logger:
api:
ota:
#i2c:
uart:
  rx_pin: GPIO3
  tx_pin: GPIO1
  baud_rate: 9600

sensor:
  - platform: mhz19
    co2:
      name: "MH-Z19 CO2 Value"
    temperature:
      name: "MH-Z19 Temperature"
    update_interval: 10s
    automatic_baseline_calibration: false

  - platform: custom
    lambda: |-
      auto light_sensor = new LightSensor();
      App.register_component(light_sensor);
      return {light_sensor->visible_sensor,light_sensor->ir_sensor,light_sensor->uvindex_sensor,light_sensor->temperature_sensor,light_sensor->pressure_sensor,light_sensor->humidity_sensor};

    sensors:
    - name: "Visible Light"
      accuracy_decimals: 0
    - name: "IR Light"
      accuracy_decimals: 0
    - name: "UV Index"
      accuracy_decimals: 0
    - name: "Kitchen Temperature"
      unit_of_measurement: "°C"
      accuracy_decimals: 1
    - name: "Kitchen Pressure"
      unit_of_measurement: "hPa"
      accuracy_decimals: 0
    - name: "Kitchen Humidity"
      unit_of_measurement: "%"
      accuracy_decimals: 1
bigwoof commented 4 years ago

the workaround is in my last message

this is what I ended up with

#include "esphome.h"
#include "Adafruit_SI1145.h"
#include "Adafruit_BME280.h"
using namespace esphome;
class LightSensor : public PollingComponent {
 public:
  Adafruit_SI1145 si;
  Adafruit_BME280 bm;
  bool bmi = false;
  bool sii = false;
  sensor::Sensor *visible_sensor = new sensor::Sensor();
  sensor::Sensor *ir_sensor = new sensor::Sensor();
  sensor::Sensor *uvindex_sensor = new sensor::Sensor();
  sensor::Sensor *temperature_sensor = new sensor::Sensor();
  sensor::Sensor *pressure_sensor = new sensor::Sensor();
  sensor::Sensor *humidity_sensor = new sensor::Sensor();

  LightSensor() : PollingComponent(5000) { }
  void setup() override {
    bmi = bm.begin(0x76);
    sii = si.begin(0x60);
  }
  void update() override {
    int visible = si.readVisible();
    visible_sensor->publish_state(visible);
    int irlight = si.readIR();
    ir_sensor->publish_state(irlight);
    int uvindex = si.readUV();
    uvindex_sensor->publish_state(uvindex / 100.0);
    float temperature = bm.readTemperature();
    temperature_sensor->publish_state(temperature);
    int pressure = bm.readPressure();
    pressure_sensor->publish_state(pressure / 100.0);
    float humidity = bm.readHumidity();
    humidity_sensor->publish_state(humidity);
    //ESP_LOGD("custom", "BME.begin() == %s | pressure : %.2f", bmi ? "OK" : "FAIL", bm.readPressure() / 100.0);
    //ESP_LOGD("custom", "SI.begin() == %s | visible : %d", sii ? "OK" : "FAIL", si.readVisible());
  }
};
esphome:
  name: kitchen_weather_display
  platform: ESP8266
  board: d1_mini
  includes:
    - light_sensor.h
  libraries:
    - "Adafruit Unified Sensor"
    - "Adafruit BME280 Library"
    - "Adafruit SI1145 Library"

# Enable logging
logger:
api:
ota:
#i2c:
uart:
  rx_pin: GPIO3
  tx_pin: GPIO1
  baud_rate: 9600

sensor:
  - platform: mhz19
    co2:
      name: "MH-Z19 CO2 Value"
    temperature:
      name: "MH-Z19 Temperature"
    update_interval: 10s
    automatic_baseline_calibration: false

  - platform: custom
    lambda: |-
      auto light_sensor = new LightSensor();
      App.register_component(light_sensor);
      return {light_sensor->visible_sensor,light_sensor->ir_sensor,light_sensor->uvindex_sensor,light_sensor->temperature_sensor,light_sensor->pressure_sensor,light_sensor->humidity_sensor};

    sensors:
    - name: "Visible Light"
      accuracy_decimals: 0
    - name: "IR Light"
      accuracy_decimals: 0
    - name: "UV Index"
      accuracy_decimals: 0
    - name: "Kitchen Temperature"
      unit_of_measurement: "°C"
      accuracy_decimals: 1
    - name: "Kitchen Pressure"
      unit_of_measurement: "hPa"
      accuracy_decimals: 0
    - name: "Kitchen Humidity"
      unit_of_measurement: "%"
      accuracy_decimals: 1

Hi @zomfg,

Can you please share the wiring of your board? I am looking to do something very similar to your setup (BME208 and SI1145) on a nodemcu through esphome and I am not sure how the sensors are communicating to the ESP8266 without using the i2c pins. I am probably missing something obvious here. Can these sensors communicate over UART? Please can you assist.

zomfg commented 4 years ago

Hi, but I DO use i2c pins, so the wiring is just as you'd imagine (like here minus the purple wire, and 5V or 3.3V red wire depends on what sensor version you have), I use them internally in my custom sensor class from above (via corresponding Adafruit libraries that are included), not in the esphome yaml, the UART part is for MHZ19. Run i2c_scanner first to make sure you have the right addresses. mine were:

    bmi = bm.begin(0x76);
    sii = si.begin(0x60);

and test each sensor with simple sketches first (like Adafruit examples) before adding the whole esphome layer

bigwoof commented 4 years ago

Thanks, @zomfg I was worried i cooked my sensors as they were not showing up in the i2c scan but on a simple example sketch I can see them - I will keep tinkering...

bigwoof commented 4 years ago

OK, Thanks @zomfg I managed to get it to work, my BME280 was on 0x77 and I needed to disable i2c The BME280 on the wrong port was what was throwing me off.

thanks again.

Martinvdm commented 3 years ago

@zomfg I do have the save issue i think. But how do i manage to get the other sensor data when disabling the I2C? I have the following code now:

substitutions:
  display_name: SolarWeatherStation

esphome:
  name: solar_weather
  platform: ESP8266
#  board: d1_mini_pro
  board: d1_mini

  includes:
    - SI1145.h
  libraries:
    - "Adafruit SI1145 Library"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_pass

#api:

# Enable logging
logger:
 level: DEBUG

mqtt:
  broker: !secret mqtt_broker
  birth_message:
    topic: solarsensor/birthdisable
    payload: disable
  will_message:
    topic: solarsensor/willdisable
    payload: disable

ota:

i2c:
 - id: ic_1
   sda: 4
   scl: 5
   scan: true

sensor:
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    update_interval: 20s

  - platform: bme280
    temperature:
      name: ${display_name} Temp
      oversampling: 4x
    pressure:
      name: ${display_name} Pres
      oversampling: 4x
    humidity:
      name: ${display_name} Humi
      oversampling: 4x
    address: 0x76
    update_interval: 30s

  - platform: bh1750
    name: ${display_name} Lux
    address: 0x23
    update_interval: 25s

  - platform: custom
    lambda: |-
      auto UV_sensor = new SI1145_sensor();
      App.register_component(UV_sensor);
      return {UV_sensor->visible_sensor, UV_sensor->ir_sensor, UV_sensor->uvindex_sensor};

    sensors:
    - name: "Visible Light"
    - name: "IR Light"
    - name: "UV Index"

  - platform: adc
    pin: A0
    name: ${display_name} Battery
    update_interval: 35s
    filters:
      - multiply: 5.1923

deep_sleep:
  run_duration: 40s
  sleep_duration: 4min

Do i need to include the libraries for the BME280 and the bh1750 manually?

OttoWinter commented 3 years ago

Yes the issue here is that the internal i2c component by ESPHome is somehow interfering with Adafruit's SI1145 Library (I don't know where exactly). Probably the frequency setting has something to do with it, but that's just a guess.

That's also a reason why ESPHome uses self-made versions of these libraries on our own hardware abstraction layer.

As the issue here is linked to an external library, and not ESPHome itself, I will close the issue (but you can still discuss here further)

Martinvdm commented 3 years ago

Any time range when the SI1145 is supported bij esphome; then we don’t have this issue in the first place

asi71 commented 3 years ago

SI1145 need a 100kHz I2C frequency, while esphome default is 50kHz. Change is simple to make in the I2C configuration. Managed to have a SI1145 and a HTU21D both working at the same time. Thanks OttoWinter !

Martinvdm commented 3 years ago

SI1145 need a 100kHz I2C frequency, while esphome default is 50kHz. Change is simple to make in the I2C configuration. Managed to have a SI1145 and a HTU21D both working at the same time. Thanks OttoWinter !

Great catch! What was your working I2C code?

asi71 commented 3 years ago

I made the exact same light_sensor.h as Zomfg, in the config/esphome directory. Then the YAML configuration, include .h file and Adafruit library reference :

esphome:
  name: esp12
  platform: ESP8266
  board: esp12e

  includes:
    - light_sensor.h
  libraries:
    - "Adafruit SI1145 Library"

And a I2C component with optional frequency :

i2c:
   - id: bus_a
     sda: GPIO2
     scl: GPIO0
     scan: True
     frequency: 100kHz
Btje1977 commented 3 years ago

@Asi71 the Zomfg was already working he stated what is the advantage of the 100Khz? Could you share the complete yaml file? I'm trying to connect the SI and a BMP280. Doesn't give a value back.

When adding the 100Khz the value changed from 0 to a measured one thanx. This indeed in combination with the BMP280

asi71 commented 3 years ago

@Btje1977 : With I2C bus at 50kHz (by default in ESPHome), the SI1145 is detected successfully, but returns no value. With the I2C bus at 100kHz, SI1145 returns value. And the BME280 works with both frequencies. Here is my YAML code. Don't forget to include the .h file in the ESPHome directory.

#Station Meteo V2
esphome:
  name: esp28
  platform: ESP8266
  board: esp01_1m
  includes:
    - SI1145.h
  libraries:
    - "Adafruit SI1145 Library"

wifi:
  ssid: SSID
  password: PASSWORD

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:

i2c:
    sda: GPIO5
    scl: GPIO4
    frequency: 100kHz

sensor:
  - platform: bme280
    temperature:
      name: "Esp28_BME280_Temperature"
      id: bme280_temperature
      oversampling: 2x
    pressure:
      name: "Esp28_BME280_Pressure"
      id: bme280_pressure
      oversampling: 2x
    humidity:
      name: "Esp28_BME280_Relative_Humidity"
      id: bme280_humidity
      oversampling: 2x
    address: 0x76
    update_interval: 600s
  - platform: custom
    lambda: |-
      auto UV_sensor = new SI1145_sensor();
      App.register_component(UV_sensor);
      return {UV_sensor->visible_sensor, UV_sensor->ir_sensor, UV_sensor->uvindex_sensor};
    sensors:
    - name: "Esp28_SI1145_Visible_Light"
      unit_of_measurement: lux
      accuracy_decimals: 1
    - name: "Esp28_SI1145_IR_Light"
      unit_of_measurement: m2/w
      accuracy_decimals: 1
    - name: "Esp28_SI1145_UV_Index"
      unit_of_measurement: Index
      accuracy_decimals: 1
jtitley commented 2 years ago

I have the Node MCU8266. The 100khz fixed my issue. However, I cannot have this co-exist with my LCD screen. I haven't wired them together, but have defined two different I2C buses. I'll eventually try wiring my LCD and this on the same bus instead of having them separated. But is there any reason why this won't work? If the LCD works, the sensors return 0. If the sensor work, the LCD doesn't. I can't figure out how this works in the first place, because there is no reference to any ESPHome I2C object. So how does it know which I2C definition to use? I'm fine to code in C++ to make this work if someone can point me in the right direction.

Also, the init in this sample doesn't work for Node MCU. But when the init is replaced with just a plain si->reset() followed by si->begin(), it works. I found this in a different GitHub issue specifically relating to SI1145 and the Node MCU8266. Again, how can it work if I never defined what I2C pins to use? Something internal to ESPHome I guess. I'm assuming the proper way would be to rewrite this based on the I2CDevice class? I notice this is how my LCD screen has been coded. Or is there a quicker hack?

FWIW, I'm a programmer, but only just starting my electrical journey.

rcruikshank commented 2 years ago

Does the BMP280 (as opposed to BME280) also work at 100 kHz with SI1145? Not for me at present with D1 mini?