mmakaay / esphome-xiaomi_bslamp2

ESPHome integration for the Xiaomi Mijia Bedside Lamp v2.
Other
218 stars 51 forks source link

[BUG] Problems with compiling the firmware #124

Closed lazariv closed 1 month ago

lazariv commented 9 months ago

Describe the bug Compiling fails because custom components cannot be imported.

To Reproduce Steps to reproduce the behavior:

  1. Use default configuration file
  2. esphome compile bedside-lamp.yaml
  3. ImportError: cannot import name 'I2CComponent' from 'esphome.components.i2c' (/home/service/.local/lib/python3.10/site-packages/esphome/components/i2c/__init__.py)

Expected behavior Expect successful compilation

Additional context Configuration file:

# --------------------------------------------------------------------------
# A few practical configuration substitutions.
# --------------------------------------------------------------------------

substitutions:
  name: bedside-lamp
  friendly_name: Bedside Lamp
  transition_length: 500ms

  # Component identifiers.
  prefix: bedside_lamp
  id_light: ${prefix}
  id_light_mode: ${prefix}_light_mode
  id_power_button: ${prefix}_power_button
  id_color_button: ${prefix}_color_button
  id_slider_level: ${prefix}_slider_level
  id_front_panel_illumination: ${prefix}_front_panel_illumination

# --------------------------------------------------------------------------
# Use your own preferences for these components.
# --------------------------------------------------------------------------

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

  # Enable fallback hotspot (for captive portal) in case wifi connection fails
  ap:
    ssid: "ESPHome $friendly_name"
    password: !secret wifi_password

captive_portal:

api:
  password: !secret api_encryption_key
  # Disable the reboot timeout. By default, the lamp reboots after 15
  # minutes without any client connections (e.g. when home assistant is off
  # line, or when the WiFi is broken). Reboots are annoying though, because
  # the RGBWW LEDs will turn off during the reboot, causing the light to
  # flicker.
  reboot_timeout: 0s

  # If you want to use light presets (see below) from Home Assistant,
  # then you can expose the required functionality as a service here.
  # This is an example of how you could expose the activation of a preset.
  services:
    - service: activate_preset
      variables:
        my_group: string
        my_preset: string
      then:
        - preset.activate:
            group: !lambda 'return my_group;'
            preset: !lambda 'return my_preset;'

ota:
  # These OTA triggers are used to provide some visual feedback during the OTA
  # flashing process. The light is turned blue when the upgrade starts, the
  # brightness indicator will represent the update progress (fills up from 0%
  # to 100%), the light will flash red when the upgrade fails or green when the
  # upgrade succeeds.
  # You can safely remove these if you don't want the visual feedback.
  on_begin:
    then:
      - light.disco_on:
          id: ${id_light}
          red: 0%
          green: 0%
          blue: 100%
          brightness: 2%
          transition_length: 0s
  on_progress:
    then:
      - front_panel.set_level: !lambda return (x / 100.0f);
      - front_panel.update_leds:
  on_end:
    then:
      - light.disco_on:
          id: ${id_light}
          red: 0%
          green: 100%
          blue: 0%
          brightness: 2%
          transition_length: 0s
  on_error:
    then:
      - light.disco_on:
          id: ${id_light}
          red: 100%
          green: 0%
          blue: 0%
          brightness: 2%
      - delay: 1s
      - light.disco_off:
          id: ${id_light}

# The log level can be raised when needed for debugging the firmware. For
# production, a low log level is recommended. Mainly because high volume log
# output might interfere with the API/WiFi connection stability. So when
# raising the log level, beware that you might see dropped connections from
# Home Assistant and the network log viewer.
logger:
    level: WARN

# --------------------------------------------------------------------------
# Configuration specific for the Xiaomi Mijia Bedside Lamp 2.
# This is just an example. You can of course modify it for your own needs.
# --------------------------------------------------------------------------

# Retrieve the code for the xiaomi_bslamp2 platform from GitHub.
external_components:
  - source:
      type: git
      url: https://github.com/mmakaay/esphome-xiaomi_bslamp2
      ref: main
    refresh: 60s

# A special platform package is used for enabling unicore and disabling the
# efuse mac crc check. These two changes are required for the ESP32-WROOM-32D
# chip that is used in the lamp.
esphome:
  name: ${name}
  platform: ESP32
  board: esp32doit-devkit-v1
  platformio_options:
    platform: espressif32@3.2.0
    platform_packages: |-
      framework-arduinoespressif32 @ https://github.com/mmakaay/arduino-esp32-unicore-no-mac-crc#v1.0.6

# This component controls the LED lights of the lamp.
light:
  - platform: xiaomi_bslamp2
    id: ${id_light}
    name: ${friendly_name} RGBWW Light
    default_transition_length: ${transition_length}
    # When the brightness is changed, then update the level indicator
    # on the front panel accordingly. In night light mode, turn off
    # the front panel illumination.
    on_brightness:
      - if:
          condition:
            text_sensor.state:
                id: ${id_light_mode}
                state: night
          then:
            - output.set_level:
                id: ${id_front_panel_illumination}
                level: 0
          else:
            - output.set_level:
                id: ${id_front_panel_illumination}
                level: !lambda return x;
    # You can use any effects that you like. These are just examples.
    effects:
      - random:
          name: "Slow Random"
          transition_length: 30s
          update_interval: 30s
      - random:
          name: "Fast Random"
          transition_length: 3s
          update_interval: 3s
    # You can define one or more groups of presets. These presets can
    # be activated using various "preset.activate" action options.
    # The presets can for example be used to mimic the behavior of the
    # original firmware (tapping the color button = go to next preset,
    # holding the color button = switch between RGB and white light mode).
    # These bindings have been setup below, using the binary_sensor for
    # the color button.
    presets:
      rgb:
        red:         { red: 100%, green: 0%,   blue: 0%   }
        green:       { red: 0%,   green: 100%, blue: 0%   }
        blue:        { red: 0%,   green: 0%,   blue: 100% }
        yellow:      { red: 100%, green: 100%, blue: 0%   }
        purple:      { red: 100%, green: 0%,   blue: 100% }
        randomize:   { effect: Fast Random                }
      white:
        cold:        { color_temperature: 153 mireds      }
        chilly:      { color_temperature: 275 mireds      }
        luke:        { color_temperature: 400 mireds      }
        warm:        { color_temperature: 588 mireds      }

# This text sensor propagates the currently active light mode.
# The possible light modes are: "off", "rgb", "white" and "night".
# By setting the name, the text_sensor will show up as an entity
# for the lamp in Home Assistant.
text_sensor:
  - platform: xiaomi_bslamp2
    name: ${friendly_name} Light Mode
    id: ${id_light_mode}

# This float output controls the front panel illumination + level indicator.
# Value 0.0 turns off the illumination. Other values (up to 1.0) turn on
# the illumination and set the level indicator to the requested level.
output:
  - platform: xiaomi_bslamp2
    id: ${id_front_panel_illumination}

# Binary sensors can be created for handling front panel touch / release
# events. To specify what part of the front panel to look at, the "for"
# parameter can be set to: "POWER_BUTTON", "COLOR_BUTTON" or "SLIDER".
binary_sensor:
  # When tapping the power button, toggle the light.
  # When holding the power button, turn on night light mode.
  - platform: xiaomi_bslamp2
    id: ${id_power_button}
    for: POWER_BUTTON
    on_multi_click:
    - timing:
        - ON for at most 0.8s
      then:
        - light.toggle: ${id_light}
    - timing:
        - ON for at least 0.8s
      then:
        - light.turn_on:
            id: ${id_light}
            brightness: 1%

  # When tapping the color button, acivate the next preset.
  # When holding the color button, activate the next preset group.
  - platform: xiaomi_bslamp2
    id: ${id_color_button}
    for: COLOR_BUTTON
    on_multi_click:
      - timing:
          - ON for at most 0.6s
        then:
          - preset.activate:
              next: preset
      - timing:
          - ON for at least 0.6s
        then:
          - preset.activate:
              next: group

# This sensor component publishes touch events for the front panel slider.
# The published value represents the level at which the slider was touched.
# By default, values range from 0.01 to 1.00 (in 20 steps). This range can
# be modified using the "range_from" and "range_to" parameters.
sensor:
  # When the slider is touched, update the brightness.
  # Brightness 0.01 initiates the light night mode, which has already
  # been handled above (by holding the power button). Therefore, brightness
  # starts from 0.02 here, to not trigger night mode using the slider.
  - platform: xiaomi_bslamp2
    id: ${id_slider_level}
    range_from: 0.02
    on_value:
      then:
        - light.turn_on:
            id: ${id_light}
            brightness: !lambda return x;

Error output:

$ esphome compile bedside-lamp.yaml
INFO ESPHome 2023.12.9
INFO Reading configuration bedside-lamp.yaml...
INFO Cloning https://github.com/mmakaay/esphome-xiaomi_bslamp2@main
ERROR Unable to import component xiaomi_bslamp2.light:
Traceback (most recent call last):
  File "/home/service/.local/lib/python3.10/site-packages/esphome/loader.py", line 169, in _lookup_module
    module = importlib.import_module(f"esphome.components.{domain}")
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/service/esphome/.esphome/external_components/d1d49d2c/components/xiaomi_bslamp2/__init__.py", line 6, in <module>
    from esphome.components.i2c import I2CComponent, I2CDevice
ImportError: cannot import name 'I2CComponent' from 'esphome.components.i2c' (/home/service/.local/lib/python3.10/site-packages/esphome/components/i2c/__init__.py)
ERROR Unable to import component xiaomi_bslamp2.text_sensor:
Traceback (most recent call last):
  File "/home/service/.local/lib/python3.10/site-packages/esphome/loader.py", line 169, in _lookup_module
    module = importlib.import_module(f"esphome.components.{domain}")
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/service/esphome/.esphome/external_components/d1d49d2c/components/xiaomi_bslamp2/__init__.py", line 6, in <module>
    from esphome.components.i2c import I2CComponent, I2CDevice
ImportError: cannot import name 'I2CComponent' from 'esphome.components.i2c' (/home/service/.local/lib/python3.10/site-packages/esphome/components/i2c/__init__.py)
ERROR Unable to import component xiaomi_bslamp2.output:
Traceback (most recent call last):
  File "/home/service/.local/lib/python3.10/site-packages/esphome/loader.py", line 169, in _lookup_module
    module = importlib.import_module(f"esphome.components.{domain}")
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/service/esphome/.esphome/external_components/d1d49d2c/components/xiaomi_bslamp2/__init__.py", line 6, in <module>
    from esphome.components.i2c import I2CComponent, I2CDevice
ImportError: cannot import name 'I2CComponent' from 'esphome.components.i2c' (/home/service/.local/lib/python3.10/site-packages/esphome/components/i2c/__init__.py)
ERROR Unable to import component xiaomi_bslamp2.binary_sensor:
Traceback (most recent call last):
  File "/home/service/.local/lib/python3.10/site-packages/esphome/loader.py", line 169, in _lookup_module
    module = importlib.import_module(f"esphome.components.{domain}")
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/service/esphome/.esphome/external_components/d1d49d2c/components/xiaomi_bslamp2/__init__.py", line 6, in <module>
    from esphome.components.i2c import I2CComponent, I2CDevice
ImportError: cannot import name 'I2CComponent' from 'esphome.components.i2c' (/home/service/.local/lib/python3.10/site-packages/esphome/components/i2c/__init__.py)
ERROR Unable to import component xiaomi_bslamp2.binary_sensor:
Traceback (most recent call last):
  File "/home/service/.local/lib/python3.10/site-packages/esphome/loader.py", line 169, in _lookup_module
    module = importlib.import_module(f"esphome.components.{domain}")
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/service/esphome/.esphome/external_components/d1d49d2c/components/xiaomi_bslamp2/__init__.py", line 6, in <module>
    from esphome.components.i2c import I2CComponent, I2CDevice
ImportError: cannot import name 'I2CComponent' from 'esphome.components.i2c' (/home/service/.local/lib/python3.10/site-packages/esphome/components/i2c/__init__.py)
ERROR Unable to import component xiaomi_bslamp2.sensor:
Traceback (most recent call last):
  File "/home/service/.local/lib/python3.10/site-packages/esphome/loader.py", line 169, in _lookup_module
    module = importlib.import_module(f"esphome.components.{domain}")
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/service/esphome/.esphome/external_components/d1d49d2c/components/xiaomi_bslamp2/__init__.py", line 6, in <module>
    from esphome.components.i2c import I2CComponent, I2CDevice
ImportError: cannot import name 'I2CComponent' from 'esphome.components.i2c' (/home/service/.local/lib/python3.10/site-packages/esphome/components/i2c/__init__.py)
Failed config

api: [source <unicode string>:35]
  password: !secret api_encryption_key
  reboot_timeout: 0s
  services:
    - service: activate_preset
      variables:
        my_group: string
        my_preset: string
      then:
        -
          Unable to find action with the name 'preset.activate'.
          preset.activate:
            group: !lambda |-
              return my_group;
            preset: !lambda |-
              return my_preset;
ota: [source <unicode string>:63]
  on_begin:
    then:
      -
        Unable to find action with the name 'light.disco_on'.
        light.disco_on:
          id: bedside_lamp
          red: 0%
          green: 0%
          blue: 100%
          brightness: 2%
          transition_length: 0s
  on_progress:
    then:
      -
        Unable to find action with the name 'front_panel.set_level'.
        front_panel.set_level: !lambda |-
          return (x / 100.0f);
      - front_panel.update_leds:
  on_end:
    then:
      -
        Unable to find action with the name 'light.disco_on'.
        light.disco_on:
          id: bedside_lamp
          red: 0%
          green: 100%
          blue: 0%
          brightness: 2%
          transition_length: 0s
  on_error:
    then:
      -
        Unable to find action with the name 'light.disco_on'.
        light.disco_on:
          id: bedside_lamp
          red: 100%
          green: 0%
          blue: 0%
          brightness: 2%
      - delay: 1s
      - light.disco_off:
          id: bedside_lamp
light.xiaomi_bslamp2: [source <unicode string>:132]

  Platform not found: 'light.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp
  name: Bedside Lamp RGBWW Light
  default_transition_length: 500ms
  on_brightness:
    - if:
        condition:
          text_sensor.state:
            id: bedside_lamp_light_mode
            state: night
        then:
          - output.set_level:
              id: bedside_lamp_front_panel_illumination
              level: 0
        else:
          - output.set_level:
              id: bedside_lamp_front_panel_illumination
              level: !lambda |-
                return x;
  effects:
    - random:
        name: Slow Random
        transition_length: 30s
        update_interval: 30s
    - random:
        name: Fast Random
        transition_length: 3s
        update_interval: 3s
  presets:
    rgb:
      red:
        red: 100%
        green: 0%
        blue: 0%
      green:
        red: 0%
        green: 100%
        blue: 0%
      blue:
        red: 0%
        green: 0%
        blue: 100%
      yellow:
        red: 100%
        green: 100%
        blue: 0%
      purple:
        red: 100%
        green: 0%
        blue: 100%
      randomize:
        effect: Fast Random
    white:
      cold:
        color_temperature: 153 mireds
      chilly:
        color_temperature: 275 mireds
      luke:
        color_temperature: 400 mireds
      warm:
        color_temperature: 588 mireds
text_sensor.xiaomi_bslamp2: [source <unicode string>:189]

  Platform not found: 'text_sensor.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  name: Bedside Lamp Light Mode
  id: bedside_lamp_light_mode
output.xiaomi_bslamp2: [source <unicode string>:197]

  Platform not found: 'output.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp_front_panel_illumination
binary_sensor.xiaomi_bslamp2: [source <unicode string>:206]

  Platform not found: 'binary_sensor.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp_power_button
  for: POWER_BUTTON
  on_multi_click:
    - timing:
        - ON for at most 0.8s
      then:
        - light.toggle: bedside_lamp
    - timing:
        - ON for at least 0.8s
      then:
        - light.turn_on:
            id: bedside_lamp
            brightness: 1%
binary_sensor.xiaomi_bslamp2: [source <unicode string>:223]

  Platform not found: 'binary_sensor.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp_color_button
  for: COLOR_BUTTON
  on_multi_click:
    - timing:
        - ON for at most 0.6s
      then:
        - preset.activate:
            next: preset
    - timing:
        - ON for at least 0.6s
      then:
        - preset.activate:
            next: group
sensor.xiaomi_bslamp2: [source <unicode string>:247]

  Platform not found: 'sensor.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp_slider_level
  range_from: 0.02
  on_value:
    then:
      - light.turn_on:
          id: bedside_lamp
          brightness: !lambda |-
            return x;
lazariv commented 9 months ago

The configuration file from dev-branch compiles correctly. Is the functionality the same as on main?

mmakaay commented 9 months ago

Sorry for the late answer. Somehow notifications end up in my spam box :-/

The main branch can best be ignored. It is an old branch and dev is the default branch, which I adopted from the esphome repository.

I dropped the use of main, because backward compatibility issues made it a bit hard to keep a clean main branch. To me, main communicates "stable!". Therefore, I switched to dev to make it clear that this is the development branch, that might sometimes be broken (I try not to break it though, all my home lamps are running this ;-) ) For releases, I branch dev to a specific release/<version> branch and publish that one as the release version.

As for what repository to use: use dev if you are feeling lucky and trust in my competence, otherwise stick with the latest release version, which is currently 2023.4.0.

This might sound like a really old version, but fact is that it works well and it is still compatible with the current ESPHome version. I am working on a new version, with mainly changes in the build flags that make for a cleaner more standard build (the Espressif framework now has new features that can be used to clean things up). This means there will be a 2024 release in the upcoming future. But still, nothing too big feature-wise.

I hope this clears up your question. Enjoy your lamp!

mmakaay commented 9 months ago

BTW: keeping this issue open, as a reminder to remove the main branch to prevent others from running into it.

mmakaay commented 1 month ago

The main branch has been removed after releasing 2024.10.0, so closing the issue.