diff --git a/README.md b/README.md index 401ab25..588f2ba 100644 --- a/README.md +++ b/README.md @@ -2,67 +2,59 @@ [ [Changelog](CHANGELOG.md) | [License](LICENSE.md) | [Code of conduct](CODE_OF_CONDUCT.md) ] -The Bedside Lamp 2 is a smart RGBWW LED lamp, produced by Yeelight. It can -be controlled via the WiFi network and using a touch panel on the front of -the device. The touch panel contains a power button, a button that changes -the color of the light and a slider that can be used to change the -brightness of the light. +The Bedside Lamp 2 is a smart RGBWW LED lamp, produced by Yeelight for the Xiaomi Mijia brand. It +can be controlled via the WiFi network and from a touch panel on the front of the device. The touch +panel contains a power button, a button that changes the color of the light and a slider that can be +used to change the brightness of the light. -This project provides custom components for ESPHome, which make it -possible to fully control every aspect of the lamp and to integrate the -lamp in your Home Assistant setup. +This project provides custom components for ESPHome, which make it possible to fully control every +aspect of the lamp and to integrate the lamp in your Home Assistant setup. ## Features * The lamp **integrates easily with Home Assistant** using the ESPHome integration. -* **The lamp no longer phones home to the Mijia Cloud.** Using this firmware, - you can rest assured that the network traffic is limited to your own network. - This matches the ideas behind Home Assistant, of providing a local home - automation platform, that puts privacy first. +* **The lamp no longer phones home to the Mijia Cloud.** Using this firmware, you can rest assured + that the network traffic is limited to your own network. This matches the ideas behind Home + Assistant, of providing a local home automation platform, that puts privacy first. -* **No more need for the LAN control option** to integrate the lamp with - Home Assistant. Especially important, because Xiaomi decided in all their - wisdom to remove LAN control from the device, breaking existing integrations. +* **No more need for the LAN control option** to integrate the lamp with Home Assistant. Especially + important, because Xiaomi decided in all their wisdom to remove LAN control from the device, + breaking existing integrations. -* **The night light supports multiple colors**. The original firmware only supports - a single warm white night light color. +* **The night light supports multiple colors**. The original firmware only supports a single warm + white night light color. -* **Smooth light color transitions**, unlike the current version of the Yeelight - integration. The Homekit integration does provide good transitions, but on my - system, the color temperature white light mode is missing in the Home Assistant GUI. +* **Smooth light color transitions**, unlike the current version of the Yeelight integration. The + Homekit integration does provide good transitions, but on my system, the color temperature white + light mode is missing in the Home Assistant GUI. -* **Since the components of the lamp are exposed as ESPHome components, you - don't have to stick with the lamp's original behavior**. You can hook up the - lamp in your home automation as you see fit. Use the slider to control the - volume of your audio set? Long press the power button to put your house in - night mode? Use the illumination behind the slider bar to represent the - progress of your sour dough bread bulk fermentation? - Go ahead, make it so! :-) +* **Since the components of the lamp are exposed as ESPHome components, you don't have to stick with + the lamp's original behavior**. You can hook up the lamp in your home automation as you see fit. + Use the slider to control the volume of your audio set? Long press the power button to put your + house in night mode? Use the illumination behind the slider bar to represent the progress of your + sour dough bread bulk fermentation? Go ahead, make it so! :-) -* **Possibilities to extend the device's functionality through hardware mods.** - There are [GPIO pins that are not in use](doc/technical_details.md#esp32-pinout). - If "tinkerer" is your middle name, you can use those pins to come up with - your own hardware hacks to extend the device's functionality. +* **Possibilities to extend the device's functionality through hardware mods.** There are [GPIO pins + that are not in use](doc/technical_details.md#esp32-pinout). If "tinkerer" is your middle name, + you can use those pins to come up with your own hardware hacks to extend the device's + functionality. ## Quick start guide For those who have experience with flashing ESPHome onto devices: -* Clone the [GitHub repo](https://github.com/mmakaay/esphome-xiaomi_bslamp2) - into your ESPHome `config/custom_components` directory. -* Copy `[doc/example.yaml](doc/example.yaml)` to `config/your_device_name.yaml`. +* Make sure you are using ESPHome 1.18.0 or newer. +* Copy `[doc/example.yaml](doc/example.yaml)` to `/.yaml`. * Modify the configuration to your needs (see the [configuration guide](doc/configuration.md)). -* Compile the `firmware.bin` file and download it to the device to which you - have connected your serial to USB adapter (FTDI). -* [Open up the lamp](doc/flashing.md#opening-the-lamp-to-expose-the-pcb) and connect - its `TX`, `RX`, `GND` and `GPIO0` debug pads to the serial adapter. Check this - [image for the debug pad locations](doc/images/09_debug_pads_for_soldering.jpg). +* Compile the `firmware.bin` file and download it to the device to which you have connected your + serial to USB adapter. +* [Open up the lamp](doc/flashing.md#opening-the-lamp-to-expose-the-pcb) and connect its `TX`, `RX`, + `GND` and `GPIO0` debug pads to the serial adapter. Check this [image for the debug pad + locations](doc/images/09_debug_pads_for_soldering.jpg). * Power up the lamp with `GPIO0` connected to GND to enable flashing mode. -* Flash `firmware.bin` onto the device. - -If you experience regular disconnects between Home Assistant and the lamp, -then take a look at the [known issues document](doc/known_issues.md). +* Flash `firmware.bin` onto the device, for example using + [esphome-flasher](https://github.com/esphome/esphome-flasher).. ## Table of contents @@ -70,6 +62,5 @@ then take a look at the [known issues document](doc/known_issues.md). * [Installation guide](doc/installation.md) * [Configuration_guide](doc/configuration.md) * [Flashing guide](doc/flashing.md) -* [Known issues](doc/known_issues.md) * [Technical details](doc/technical_details.md) * [Sponsoring](doc/sponsoring.md) diff --git a/.clang-format b/components/xiaomi_bslamp2/.clang-format similarity index 100% rename from .clang-format rename to components/xiaomi_bslamp2/.clang-format diff --git a/.clang-tidy b/components/xiaomi_bslamp2/.clang-tidy similarity index 100% rename from .clang-tidy rename to components/xiaomi_bslamp2/.clang-tidy diff --git a/__init__.py b/components/xiaomi_bslamp2/__init__.py similarity index 100% rename from __init__.py rename to components/xiaomi_bslamp2/__init__.py diff --git a/binary_sensor/__init__.py b/components/xiaomi_bslamp2/binary_sensor/__init__.py similarity index 100% rename from binary_sensor/__init__.py rename to components/xiaomi_bslamp2/binary_sensor/__init__.py diff --git a/binary_sensor/touch_binary_sensor.h b/components/xiaomi_bslamp2/binary_sensor/touch_binary_sensor.h similarity index 100% rename from binary_sensor/touch_binary_sensor.h rename to components/xiaomi_bslamp2/binary_sensor/touch_binary_sensor.h diff --git a/common.h b/components/xiaomi_bslamp2/common.h similarity index 100% rename from common.h rename to components/xiaomi_bslamp2/common.h diff --git a/front_panel_hal.h b/components/xiaomi_bslamp2/front_panel_hal.h similarity index 100% rename from front_panel_hal.h rename to components/xiaomi_bslamp2/front_panel_hal.h diff --git a/light/__init__.py b/components/xiaomi_bslamp2/light/__init__.py similarity index 100% rename from light/__init__.py rename to components/xiaomi_bslamp2/light/__init__.py diff --git a/light/automation.h b/components/xiaomi_bslamp2/light/automation.h similarity index 100% rename from light/automation.h rename to components/xiaomi_bslamp2/light/automation.h diff --git a/light/color_instant_handler.h b/components/xiaomi_bslamp2/light/color_instant_handler.h similarity index 100% rename from light/color_instant_handler.h rename to components/xiaomi_bslamp2/light/color_instant_handler.h diff --git a/light/color_night_light.h b/components/xiaomi_bslamp2/light/color_night_light.h similarity index 100% rename from light/color_night_light.h rename to components/xiaomi_bslamp2/light/color_night_light.h diff --git a/light/color_off.h b/components/xiaomi_bslamp2/light/color_off.h similarity index 100% rename from light/color_off.h rename to components/xiaomi_bslamp2/light/color_off.h diff --git a/light/color_rgb_light.h b/components/xiaomi_bslamp2/light/color_rgb_light.h similarity index 100% rename from light/color_rgb_light.h rename to components/xiaomi_bslamp2/light/color_rgb_light.h diff --git a/light/color_transition_handler.h b/components/xiaomi_bslamp2/light/color_transition_handler.h similarity index 100% rename from light/color_transition_handler.h rename to components/xiaomi_bslamp2/light/color_transition_handler.h diff --git a/light/color_white_light.h b/components/xiaomi_bslamp2/light/color_white_light.h similarity index 100% rename from light/color_white_light.h rename to components/xiaomi_bslamp2/light/color_white_light.h diff --git a/light/gpio_outputs.h b/components/xiaomi_bslamp2/light/gpio_outputs.h similarity index 100% rename from light/gpio_outputs.h rename to components/xiaomi_bslamp2/light/gpio_outputs.h diff --git a/light/interfaces.h b/components/xiaomi_bslamp2/light/interfaces.h similarity index 100% rename from light/interfaces.h rename to components/xiaomi_bslamp2/light/interfaces.h diff --git a/light/light_modes.h b/components/xiaomi_bslamp2/light/light_modes.h similarity index 100% rename from light/light_modes.h rename to components/xiaomi_bslamp2/light/light_modes.h diff --git a/light/light_output.h b/components/xiaomi_bslamp2/light/light_output.h similarity index 100% rename from light/light_output.h rename to components/xiaomi_bslamp2/light/light_output.h diff --git a/light/light_state.h b/components/xiaomi_bslamp2/light/light_state.h similarity index 100% rename from light/light_state.h rename to components/xiaomi_bslamp2/light/light_state.h diff --git a/light/presets.h b/components/xiaomi_bslamp2/light/presets.h similarity index 100% rename from light/presets.h rename to components/xiaomi_bslamp2/light/presets.h diff --git a/light_hal.h b/components/xiaomi_bslamp2/light_hal.h similarity index 100% rename from light_hal.h rename to components/xiaomi_bslamp2/light_hal.h diff --git a/output/__init__.py b/components/xiaomi_bslamp2/output/__init__.py similarity index 100% rename from output/__init__.py rename to components/xiaomi_bslamp2/output/__init__.py diff --git a/output/output.h b/components/xiaomi_bslamp2/output/output.h similarity index 100% rename from output/output.h rename to components/xiaomi_bslamp2/output/output.h diff --git a/sensor/__init__.py b/components/xiaomi_bslamp2/sensor/__init__.py similarity index 100% rename from sensor/__init__.py rename to components/xiaomi_bslamp2/sensor/__init__.py diff --git a/sensor/slider_sensor.h b/components/xiaomi_bslamp2/sensor/slider_sensor.h similarity index 100% rename from sensor/slider_sensor.h rename to components/xiaomi_bslamp2/sensor/slider_sensor.h diff --git a/text_sensor/__init__.py b/components/xiaomi_bslamp2/text_sensor/__init__.py similarity index 100% rename from text_sensor/__init__.py rename to components/xiaomi_bslamp2/text_sensor/__init__.py diff --git a/text_sensor/light_mode_text_sensor.h b/components/xiaomi_bslamp2/text_sensor/light_mode_text_sensor.h similarity index 100% rename from text_sensor/light_mode_text_sensor.h rename to components/xiaomi_bslamp2/text_sensor/light_mode_text_sensor.h diff --git a/doc/configuration.md b/doc/configuration.md index 678c2b3..d0497c0 100644 --- a/doc/configuration.md +++ b/doc/configuration.md @@ -2,15 +2,14 @@ # Configuration guide -I think, the best starting point for creating your own yaml configuration, -is to look at the [example.yaml](example.yaml) file from the project -documentation. This configuration was written with the functionality of the -original firmware in mind and it makes use of all available options. This -configuration guide can be used to fill in the blanks. +I think, the best starting point for creating your own yaml configuration, is to look at the +[example.yaml](example.yaml) file from the project documentation. This configuration was written +with the functionality of the original firmware in mind and it makes use of all available options. +This configuration guide can be used to fill in the blanks. -The `xiaomi_bslamp2` platform provides various components that expose the -core functionalities of the lamp. In the following table, you can find what -components are used for exposing what physical components of the lamp. +The `xiaomi_bslamp2` platform provides various components that expose the core functionalities of +the lamp. In the following table, you can find what components are used for exposing what physical +components of the lamp. | Part | Component(s) | | -------------------------- |------------------------------------------------------------------| @@ -25,17 +24,16 @@ components are used for exposing what physical components of the lamp. ## Platform: xiaomi_bslamp2 -At the core of the hardware support is the `xiaomi_bslamp2` platform, which -provides two hub-style hardware abstraction layer (HAL) components that are -used by the other components: one for driving the GPIO's for the RGBWW leds -and one for the I2C communication between the ESP32 and the front panel. +At the core of the hardware support is the `xiaomi_bslamp2` platform, which provides two hub-style +hardware abstraction layer (HAL) components that are used by the other components: one for driving +the GPIO's for the RGBWW leds and one for the I2C communication between the ESP32 and the front +panel. -I do mention the platform configuration here for completeness sake, but -generally you will not have to add the following configuration option to -your yaml file. It is loaded automatically by the components that need it, -and the GPIO + I2C configurations are fully prepared to work for the Bedside -Lamp 2 wiring out of the box. Therefore, you will not find this piece of -configuration in the [example.yaml](example.yaml). +I do mention the platform configuration here for completeness sake, but **generally you will not have +to add the following configuration option to your yaml file**. It is loaded automatically by the +components that need it, and the GPIO + I2C configurations are fully prepared to work for the +Bedside Lamp 2 wiring out of the box. Therefore, you will not find this piece of configuration in +the [example.yaml](example.yaml). Having said that, here are the configuration options: @@ -56,14 +54,14 @@ xiaomi_bslamp2: trigger_pin: "GPIO16" ``` -The only reason that I can think of for adding this platform configuration -to your yaml file, would be if you blew one or more or the ESP32 pins, and -need to rewire functionality. In other casis, simply omit the section. +The only reason that I can think of for adding this platform configuration to your yaml file, would +be if you blew one or more or the ESP32 pins, and need to rewire functionality. In other casis, +simply omit the section. ## Component: light -The light component creates an RGBWW light. This means that it can do -colored light and cold/warm white light based on a color temperature. +The light component creates an RGBWW light. This means that it can do colored light and cold/warm +white light based on a color temperature. ```yaml light: @@ -97,24 +95,22 @@ light: ### Configuration variables: * **name** (**Required**, string): The name of the light. -* **id** (*Optional*, ID): Manually specify the ID used for code generation. - By providing an id, you can reference the light from automation rules - (e.g. to turn on the light when the power button is tapped) -* **default_transition_length** (*Optional*, Time): The transition length to - use when no transition length is set in a light call. Defaults to 1s. +* **id** (*Optional*, ID): Manually specify the ID used for code generation. By providing an id, + you can reference the light from automation rules (e.g. to turn on the light when the power button + is tapped) +* **default_transition_length** (*Optional*, Time): The transition length to use when no transition + length is set in a light call. Defaults to 1s. * **effects** (*Optional*, list): A list of - [light effects](https://esphome.io/components/light/index.html#light-effects) - to use for this light. -* **presets** (*Optional*, dict): Used to define presets, that can be used - from automations. See [below](#light-presets) for detailed information. -* **on_brightness** (*Optional*, Action): An automation to perform when the - brightness of the light is modified. -* All other options from [the base Light - implementation](https://esphome.io/components/light/index.html#config-light), - except for options that handle color correction options like - `gamma_correct` and `color_correct`. These options are superceded by the - fact that the light component has a fully customized light model, that - closely follows the light model of the original lamp's firmware. + [light effects](https://esphome.io/components/light/index.html#light-effects) to use for this light. +* **presets** (*Optional*, dict): Used to define presets, that can be used from automations. See + [below](#light-presets) for detailed information. +* **on_brightness** (*Optional*, Action): An automation to perform when the brightness of the light + is modified. +* All other options from + [the base Light implementation](https://esphome.io/components/light/index.html#config-light), + except for options that handle color correction options like `gamma_correct` and `color_correct`. + These options are superceded by the fact that the light component has a fully customized light + model, that closely follows the light model of the original lamp's firmware. ### Light modes @@ -124,22 +120,19 @@ The lamp supports multiple light modes. These are: * **White light** (input: Color Temperature + brightness > 1%) * **Night light** (input: RGB or White light + brightness at 1%) -In the original firmware + Yeelight Home Assistant integration, the night -light feature is implemented through a switch component. The switch can be -turned on to activate the night light mode. In this ESPHome firmware, -setting the brightness to its lowest value triggers the night light mode. -This makes things a lot easier to control. +In the original firmware + Yeelight Home Assistant integration, the night light feature is +implemented through a switch component. The switch can be turned on to activate the night light +mode. In this ESPHome firmware, setting the brightness to its lowest value triggers the night light +mode. This makes things a lot easier to control. -It is possible to control the night light mode separately. An example of -this can be found in the [example.yaml](example.yaml), in which holding the -power button is bound to activating the night light. +It is possible to control the night light mode separately. An example of this can be found in the +[example.yaml](example.yaml), in which holding the power button is bound to activating the night +light. ### light.disco_on Action -This action sets the state of the light immediately -(i.e. without waiting for the next main loop iteration), -without saving the state to memory and without publishing -the state change. +This action sets the state of the light immediately (i.e. without waiting for the next main loop +iteration), without saving the state to memory and without publishing the state change. ```yaml on_...: @@ -152,13 +145,13 @@ on_...: blue: 100% ``` -The possible configuration options for this Action are the same -as those for the standard `light.turn_on` Action. +The possible configuration options for this Action are the same as those for the standard +`light.turn_on` Action. ### light.disco_off Action -This action turns off the disco mode by restoring the state -of the lamp to the last known state that was saved to memory. +This action turns off the disco mode by restoring the state of the lamp to the last known state from +before using the disco mode. ```yaml on_...: @@ -169,29 +162,25 @@ on_...: ### Light presets -The presets functionality was written with the original lamp firemware -functionality in mind: the user has two groups of presets available: one for -RGB light presets and one for white light presets (based on color -temperature). The color button (the top one on the front panel) can be -tapped to switch to the next preset within the active preset group. The same -button can be held for a little while, to switch to the other preset group. +The presets functionality was written with the original lamp firemware functionality in mind: the +user has two groups of presets available: one for RGB light presets and one for white light presets +(based on color temperature). The color button (the top one on the front panel) can be tapped to +switch to the next preset within the active preset group. The same button can be held for a little +while, to switch to the other preset group. -In your light configuration, you can mimic this behavior (in fact: it is -done so in the [example.yaml](example.yaml)) by means of the presets system. -This system consists of two parts: +In your light configuration, you can mimic this behavior (in fact: it is done so in the +[example.yaml](example.yaml)) by means of the presets system. This system consists of two parts: * Defining presets * Activating presets from automations **Defining presets** -Presets can be configured in the `presets` option of the `light` -configuration. +Presets can be configured in the `presets` option of the `light` configuration. -Presets are arranged in groups. You can define as little or as many groups -as you like. The example configuration uses two groups, but that is only to -mimic the original behavior. If you only need one group, then create one -group. If you need ten, go ahead and knock yourself out. +Presets are arranged in groups. You can define as little or as many groups as you like. The example +configuration uses two groups, but that is only to mimic the original behavior. If you only need one +group, then create one group. If you need ten, go ahead and knock yourself out. The general structure of the presets configuration is: @@ -209,9 +198,9 @@ light: .. ``` -*Note: duplicate template names are ok, as long as they are within their own -group. If you use duplicate preset names within a single group, then the -last preset will override the earlier one(s).* +*Note: duplicate template names are ok, as long as they are within their own group. If you use +duplicate preset names within a single group, then the last preset will override the earlier +one(s).* A preset can define one of the following: @@ -232,9 +221,8 @@ A preset can define one of the following: **Activating presets from automations** -Once presets have been configured, they can be activated using the -`preset.activate` action. The following options are available for this -action: +Once presets have been configured, they can be activated using the `preset.activate` action. The +following options are available for this action: * Switch to next preset group (and after the last, switch to the first): ```yaml @@ -273,25 +261,22 @@ preset.activate: white.warm **Handling of invalid input** -When a group or template is specified that does not exist, or if next -group/preset is used while no presets have been defined at all, then the -action will be ignored and an error will be logged. +When a group or template is specified that does not exist, or if next group/preset is used while no +presets have been defined at all, then the action will be ignored and an error will be logged. -*Note: This is validation at run time. It would be a lot better to -validate the names at compile time more strictly, so the firmware will not -even compile when invalid names are in use. -[Issue #15](https://github.com/mmakaay/esphome-xiaomi_bslamp2/issues/15) -was created for implementing this. However, a new feature in ESPHome is -required to be able to do this implementation. Good news is that this -is already well on its way.* +*Note: This is validation at run time. It would be a lot better to validate the names at compile +time more strictly, so the firmware will not even compile when invalid names are in use. +[Issue #15](https://github.com/mmakaay/esphome-xiaomi_bslamp2/issues/15) was created for +implementing this. However, a new feature in ESPHome is required to be able to do this +implementation. Good news is that this is already well on its way.* ## Component: binary_sensor -Binary sensors can be added to the configuration for handling touch/release -events for the front panel. On touch, a binary_sensor will publish `True`, -on release it will publish `False`. The configuration of a binary_sensor -determines what part of the front panel is involved in the touch events. +Binary sensors can be added to the configuration for handling touch/release events for the front +panel. On touch, a binary_sensor will publish `True`, on release it will publish `False`. The +configuration of a binary_sensor determines what part of the front panel is involved in the touch +events. ```yaml binary_sensor: @@ -303,38 +288,35 @@ binary_sensor: - light.toggle: my_bedside_lamp ``` -For referencing the parts of the front panel, the following part identifiers -are available: +For referencing the parts of the front panel, the following part identifiers are available: * POWER_BUTTON (or its alias: POWER) * COLOR_BUTTON (or its alias: COLOR) * SLIDER -If personal taste dictates so, you can use lower case characters and spaces -instead of underscores. This means that for example "Power Button" and -"power" would be valid identifiers for the power button. +If personal taste dictates so, you can use lower case characters and spaces instead of underscores. +This means that for example "Power Button" and "power" would be valid identifiers for the power +button. ### Configuration variables: -* **name** (*Optional*, string): The name of the binary sensor. Setting a - name will expose the binary sensor as an entity in Home Assistant. If you - do not need this, you can omit the name. -* **id** (*Optional*, ID): Manually specify the ID used for code generation. - By providing an id, you can reference the binary_sensor from automation - rules (to retrieve the current state of the binary_sensor). -* **for** (*Mandatory*, part identifier): This specifies to for part of the - front panel the binary sensor must report touch events. +* **name** (*Optional*, string): The name of the binary sensor. Setting a name will expose the + binary sensor as an entity in Home Assistant. If you do not need this, you can omit the name. +* **id** (*Optional*, ID): Manually specify the ID used for code generation. By providing an id, + you can reference the binary_sensor from automation rules (to retrieve the current state of the + binary_sensor). +* **for** (*Mandatory*, part identifier): This specifies to for part of the front panel the binary + sensor must report touch events. * All other options from [Binary Sensor](https://esphome.io/components/binary_sensor/index.html#config-binary-sensor). ## Component: sensor -The sensor component publishes touch events for the front panel slider. The -published value represents the level at which the slider was touched. +The sensor component publishes touch events for the front panel slider. The published value +represents the level at which the slider was touched. -*Note: This sensor only reports the touched slider level. It cannot be used -for detecting release events. If you want to handle touch/release events for -the slider, then you can make use of the +*Note: This sensor only reports the touched slider level. It cannot be used for detecting release +events. If you want to handle touch/release events for the slider, then you can make use of the [binary_sensor](#component-binary_sensor) instead.* ```yaml @@ -352,27 +334,22 @@ sensor: ### Configuration variables: -* **name** (*Optional*, string): The name of the sensor. Setting a name will - expose the sensor as an entity in Home Assistant. If you do not need this, - you can omit the name. -* **id** (*Optional*, ID): Manually specify the ID used for code generation. - By providing an id, you can reference the sensor from automation rules - (e.g. to retrieve the current state of the binary_sensor). -* **range_from** (*Optional*, float): By default, published values vary from - the range 0.01 to 1.00, in 20 steps. This option modifies the lower bound - of the range. -* **range_to** (*Optional*, float): This option modifies the upper bound of - the range. +* **name** (*Optional*, string): The name of the sensor. Setting a name will expose the sensor as an + entity in Home Assistant. If you do not need this, you can omit the name. +* **id** (*Optional*, ID): Manually specify the ID used for code generation. By providing an id, + you can reference the sensor from automation rules (e.g. to retrieve the current state of the + binary_sensor). +* **range_from** (*Optional*, float): By default, published values vary from the range 0.01 to 1.00, + in 20 steps. This option modifies the lower bound of the range. +* **range_to** (*Optional*, float): This option modifies the upper bound of the range. * All other options from [Sensor](https://esphome.io/components/sensor/index.html#config-sensor). ## Component: output -The (float) output component is linked to the front panel illumination + -level indicator. Setting this output to value 0.0 will turn off the -frontpanel illumination. Other values, up to 1.0, will turn on the -illumination and will set the level indicator to the requested level (in 10 -steps). +The (float) output component is linked to the front panel illumination + level indicator. Setting +this output to value 0.0 will turn off the frontpanel illumination. Other values, up to 1.0, will +turn on the illumination and will set the level indicator to the requested level (in 10 steps). ```yaml output: @@ -387,18 +364,16 @@ output: ## Component: text_sensor -The text sensor component publishes changes in the active -[light mode](#light-modes). Possible output values for this sensor are: "off", -"rgb", "white" and "night". +The text sensor component publishes changes in the active [light mode](#light-modes). Possible +output values for this sensor are: "off", "rgb", "white" and "night". ### Configuration variables: -* **name** (*Optional*, string): The name of the text sensor. Setting a name - will expose the text sensor as an entity in Home Assistant. If you do not - need this, you can omit the name. -* **id** (*Optional*, ID): Manually specify the ID used for code generation. - By providing an id, you can reference the text sensor from automation - rules (to retrieve the current state of the text_sensor). +* **name** (*Optional*, string): The name of the text sensor. Setting a name will expose the text + sensor as an entity in Home Assistant. If you do not need this, you can omit the name. +* **id** (*Optional*, ID): Manually specify the ID used for code generation. By providing an id, + you can reference the text sensor from automation rules (to retrieve the current state of the + text_sensor). * All other options from [Text Sensor](https://esphome.io/components/text_sensor/index.html) diff --git a/doc/example.yaml b/doc/example.yaml index e221564..dc5167f 100644 --- a/doc/example.yaml +++ b/doc/example.yaml @@ -55,7 +55,14 @@ logger: # This is just an example. You can of course modify it for your own needs. # -------------------------------------------------------------------------- -# Special platform + package are used for enabling unicore and disabling the +# Retrieve the code for the xiaomi_bslamp2 platform from GitHub. +external_components: + - source: + type: git + url: https://github.com/mmakaay/xiaomi_bslamp2 + ref: main + +# 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: diff --git a/doc/flashing.md b/doc/flashing.md index 004ca49..0d40b49 100644 --- a/doc/flashing.md +++ b/doc/flashing.md @@ -1,4 +1,4 @@ -< [Configuration guide](configuration.md) | [Index](../README.md) | [Known issues](known_issues.md) > +< [Configuration guide](configuration.md) | [Index](../README.md) | [Technical details](doc/technical_details.md) > # Flashing guide @@ -16,8 +16,8 @@ Table of contents: ## Warning -We have writen these instructions with care, but we will give absolutely no -warranty. Perhaps you will destroy your lamp and your computer. +We have writen these instructions with care, but we will give absolutely no warranty. Perhaps you +will destroy your lamp and your computer. ## Tools needed @@ -33,13 +33,13 @@ warranty. Perhaps you will destroy your lamp and your computer. *Tip: you can click on all images from below to view them in full size.* -Remove the rubber pads from the bottom of the lamp, to get access to 4 -screws that attach the bottom to the rest of the lamp. +Remove the rubber pads from the bottom of the lamp, to get access to 4 screws that attach the bottom +to the rest of the lamp. -Note that you don't have to remove these pads fully. Once you can access -the screws, you've gone far enough. +Note that you don't have to remove these pads fully. Once you can access the screws, you've gone far +enough. @@ -47,8 +47,8 @@ Unbolt the 4 screws which were hidden under the rubber pads. -Detach the bottom from the rest of the lamp, exposing the PCB. This might -take a bit of force. Just pull it off bit by bit, until it pops loose. +Detach the bottom from the rest of the lamp, exposing the PCB. This might take a bit of force. Just +pull it off bit by bit, until it pops loose. @@ -61,43 +61,40 @@ The wires will be connected to the debug pads that are shown in the following im -Many of the serial to USB adapter have some header pins to which you can -connect the wires of a device (no soldering required). Therefore, it might be -useful to use dupont wire. Cut off one end, strip the wire, tin the wire and -solder it to the board. +Many of the serial to USB adapter have some header pins to which you can connect the wires of a +device (no soldering required). Therefore, it might be useful to use dupont wire. Cut off one end, +strip the wire, tin the wire and solder it to the board. -*Note: Whether to use male or female dupont wires depends on how you want to connect -the serial adapter. In this example, I have used male wires, so I could plug them -into a breadbord.* +*Note: Whether to use male or female dupont wires depends on how you want to connect the serial +adapter. In this example, I have used male wires, so I could plug them into a breadbord.* Solder the wires to the `RX`, `TX`, `GND` and `GPIO0` debug pads. -*Note: The board has a debug pad that exposes 3.3V. Do not use this pad to power -the board from your serial adapter. Always power the lamp using its own power supply.* +*Note: The board has a debug pad that exposes 3.3V. Do not use this pad to power the board from your +serial adapter. Always power the lamp using its own power supply.* A few tips: -- Depending on the quality of your eyes, you might want to use a magnifying glass for the - soldering work. Use one that is mounted on a stand, or you will quickly be left wishing - that you could grow a third arm. +- Depending on the quality of your eyes, you might want to use a magnifying glass for the soldering + work. Use one that is mounted on a stand, or you will quickly be left wishing that you could grow + a third arm. - You could use some sticky tape to fixate the cables before soldering. -- When you want to keep the wires attached after flashing the new firmware (e.g. for - serial logging or for future firmware flashing), then you might want to apply some - hot glue to fixate the wires. This prevents the wires from breaking off, due to - excessive movement. +- When you want to keep the wires attached after flashing the new firmware (e.g. for serial logging + or for future firmware flashing), then you might want to apply some hot glue to fixate the wires. + This prevents the wires from breaking off, due to excessive movement. ## Connect the wires to your serial to USB adapter -Make sure that your adapter uses 3.3V for the pns that you will connect to the lamp. -Some of these adapters allow you to switch between 3.3V and 5V using a switch or a jumper. -Do not use an adapter that only provides 5V output. Reason for this, is that the ESP32 chip -works at 3.3V. I have seen the chips accept 5V serial input, but I am not sure if they are -actually 5V tolerant. Better safe than sorry in such case! +Make sure that your adapter uses 3.3V for the RX/TX pins that you will connect to the lamp. Some of +these adapters allow you to switch between 3.3V and 5V using a switch or a jumper. Do not use an +adapter that only provides 5V output. Reason for this, is that the ESP32 chip works at 3.3V. I have +seen the chips accept 5V serial input (I did flash the lamp successfully like that), but I am not +sure if they are actually 5V tolerant. Better safe than sorry in such case! The wires must be connected as follows: @@ -109,42 +106,39 @@ The wires must be connected as follows: | GPIO0 | GND | To be able to flash the lamp, `GPIO0` must be connected to ground while the lamp boots up. -Therefore, connect these wires *before* plugging in the lamp's power supply. -Flashing will *not* work if you connect these wires *after* the lamp has already been booted up. +Therefore, connect these wires *before* plugging in the lamp's power supply. Flashing will *not* +work if you connect these wires *after* the lamp has already been booted up. ## When you only have one GND pin on your USB Adapter -If your USB Adapter does not have multiple `GND` pins, then you'll have to -find another way to attach `GPIO0` to ground. Some options: +If your USB Adapter does not have multiple `GND` pins, then you'll have to find another way to +attach `GPIO0` to ground. Some options: -- **Use a breadbord**, so you can connect the USB Adapter `GND` pin to a row on - the bread bord, and connect the `GND` and `GPIO0` wires of the lamp's - board to that same row. The rest of this guide will show this method. +- **Use a breadbord**, so you can connect the USB Adapter `GND` pin to a row on the bread bord, and + connect the `GND` and `GPIO0` wires of the lamp's board to that same row. The rest of this guide + will show this method. [View example by @mmakaay](images/13_connect_to_serial_to_usb_adapter.jpg). -- **Solder a button on the board** that connects `GPIO0` to `GND` when pressed. - Then you can hold down this button while plugging in the lamp's power - supply. After booting up, you can release the button (the serial console - will also mention that flash mode is now enabled). This is not the most - practical solution for most people (since only one such flash operation is - needed, from then on OTA - Over The Air - updates are possible), but it - was a great help to me during the initial reverse engineering and firmware - development. Some example implementations: [a crude one by @mmakaay](images/13_connect_to_serial_with_button.jpg), - [one by @edwinschoonhoven](images/13_connect_to_serial_with_button_alternative.jpg), - and [one by @mmakaay, inspired by Erwin's](images/13_connect_to_serial_with_button_alternative2.jpg). - -- **Manually hold a wire connected** to both a GND surface (e.g. the silver pad - on the left of the board) and the `GPIO0` debug pad, while plugging in the - power supply. After booting, the wire can be removed. This is very fiddly - way of doing it (a third hand would be very welcome with this), but it can - be done. - -- **Temporarily solder a lead between `GND` and `GPIO0` on the board**, - making `GPIO0` pulled to ground permanently. It is a bit less flexible than - some other options, but if you only need to do the initial backup and firmware - flash of the lamp, then this can be all that you need. Remove the lead after - flashing is done, otherwise the lamp won't boot in normal mode. +- **Solder a button on the board** that connects `GPIO0` to `GND` when pressed. Then you can hold + down this button while plugging in the lamp's power supply. After booting up, you can release the + button (the serial console will also mention that flash mode is now enabled). This is not the most + practical solution for most people (since only one such flash operation is needed, from then on + OTA - Over The Air - updates are possible), but it was a great help to me during the initial + reverse engineering and firmware development. Some example implementations: + [a crude one by @mmakaay](images/13_connect_to_serial_with_button.jpg), + [one by @edwinschoonhoven](images/13_connect_to_serial_with_button_alternative.jpg) and + [one by @mmakaay, inspired by Erwin's](images/13_connect_to_serial_with_button_alternative2.jpg). + +- **Manually hold a wire connected** to both a GND surface (e.g. the silver pad on the left of the + board) and the `GPIO0` debug pad, while plugging in the power supply. After booting, the wire can + be removed. This is very fiddly way of doing it (a third hand would be very welcome with this), + but it can be done. + +- **Temporarily solder a lead between `GND` and `GPIO0` on the board**, making `GPIO0` pulled to + ground permanently. It is a bit less flexible than some other options, but if you only need to do + the initial backup and firmware flash of the lamp, then this can be all that you need. Remove the + lead after flashing is done, otherwise the lamp won't boot in normal mode. [View example by @erwinschoonhoven](images/13_connect_to_serial_with_soldered_gnd.jpg). In the following images, you will see the first solution, using a breadboard. @@ -155,52 +149,51 @@ In close up: -You can now connect the serial to USB adapter to you computer. Pay special attention -to the cross-over of the TX/RX pair (TX connects to RX and vice versa). -Start the [esphome-flasher tool](https://github.com/esphome/esphome-flasher) and -select the COM port to use. Then click on "View logs". +You can now connect the serial to USB adapter to you computer. Pay special attention to the +cross-over of the TX/RX pair (TX connects to RX and vice versa). Start the +[esphome-flasher tool](https://github.com/esphome/esphome-flasher) and select the COM port to use. +Then click on "View logs". Now, plug in the lamp's power supply to boot up the lamp. -Because GPIO0 is connected to GND, the device should start up in flashing mode. -If all went well, the log output in esphome-flasher looks somewhat like this: +Because GPIO0 is connected to GND, the device should start up in flashing mode. If all went well, +the log output in esphome-flasher looks somewhat like this: ## Make a backup of the current firmware -Backing up the firmware makes it possible to revert to the original firmware, -in case you have problems with the ESPHome firmware. The backup can be -created using "esptool". Installation instructures can be found here: +Backing up the firmware makes it possible to revert to the original firmware, in case you have +problems with the ESPHome firmware. The backup can be created using "esptool". Installation +instructures can be found here: https://github.com/espressif/esptool/blob/master/README.md#installation--dependencies -Here's an example on how to backup the original firmware from Linux. -First, unplug your lamp's power supply, then start the esptool read_flash command: +Here's an example on how to backup the original firmware from Linux. First, unplug your lamp's +power supply, then start the esptool read_flash command: ``` python esptool.py -p /dev/ttyUSB0 read_flash 0x0 0x400000 original-firmware.bin ``` -`/dev/ttyUSB0` is the port of the USB adaper on Linux. You can find what -port is used by the adapter by running `dmesg` after plugging in the USB -device. On Windows this is often `COM1`, `COM2` or `COM3`. +`/dev/ttyUSB0` is the port of the USB adaper on Linux. You can find what port is used by the adapter +by running `dmesg` after plugging in the USB device. On Windows this is often `COM1`, `COM2` or +`COM3`. -Now plug back in the power supply. The output of esptool should now show that it -connects to the lamp and downloads the firmware from it. +Now plug back in the power supply. The output of esptool should now show that it connects to the +lamp and downloads the firmware from it. -**Caution**: You will find the WLAN SSID and Password of the last used -WiFi network in this file. Therefore, keep this backup in a safe place. +**Caution**: You will find the WLAN SSID and Password of the last used WiFi network in this file. +Therefore, keep this backup in a safe place. ## How to restore the backed up firmware -In case you need to rollback to the lamp's original firmware at some -point, here's an example of how to restore the original firmware from -Windows, by fully flashing it back onto the lamp. +In case you need to rollback to the lamp's original firmware at some point, here's an example of how +to restore the original firmware from Windows, by fully flashing it back onto the lamp. First, unplug your lamp's power supply, then start the esptool write_flash command: @@ -208,27 +201,24 @@ First, unplug your lamp's power supply, then start the esptool write_flash comma python.exe .\esptool.py --chip esp32 --port COM3 --baud 115200 write_flash 0x00 original-firmware.bin ``` -Make sure that `GPIO0` is connected to GND and plug in the power supply. -The output of esptool should now show that it connects to the lamp and -uploads the firmware to it. +Make sure that `GPIO0` is connected to GND and plug in the power supply. The output of esptool +should now show that it connects to the lamp and uploads the firmware to it. -Be patient after the upload reaches 100%. The output is silent while -esptool tool is verifying that the firmware was uploaded correctly. +Be patient after the upload reaches 100%. The output is silent while esptool tool is verifying that +the firmware was uploaded correctly. -After the firmware upload completes, unplug the power, disconnect `GPIO0` -from GND and reconnect the power supply to boot into the restored firmware. +After the firmware upload completes, unplug the power, disconnect `GPIO0` from GND and reconnect the +power supply to boot into the restored firmware. ## Flash new ESPHome firmware -Setup an ESPHome Project (see [README.md](../README.md)), compile the firmware -for the lamp and download the `firmware.bin` file to the device to which -the serial adapter is connected. +Setup an ESPHome Project (see [README.md](../README.md)), compile the firmware for the lamp and +download the `firmware.bin` file to the device to which the serial adapter is connected. -You can flash the lamp using esphome or esptool. I would strongly recommend using -the [esphome-flasher](https://github.com/esphome/esphome-flasher) tool. This is -a very easy to use GUI utility app for flashing ESPHome devices and for viewing -serial console logging. +You can flash the lamp using esphome or esptool. I would strongly recommend using the +[esphome-flasher](https://github.com/esphome/esphome-flasher) tool. This is a very easy to use GUI +utility app for flashing ESPHome devices and for viewing serial console logging. - In the app, select the COM port of your serial adapter. - Then select the firmware.bin file to flash onto the lamp. @@ -241,8 +231,8 @@ If all went well, the final log output in esphome-flasher looks somewhat like th If you want to flash with esptool, you can use the following command. -*Note: unless you know exactly what you're doing with esptool here, -I recommend to use the esphome-flasher instead.* +*Note: unless you know exactly what you're doing with esptool here, I recommend to use the +esphome-flasher instead.* ``` python esptool.py --chip esp32 -p /dev/ttyUSB0 --baud 115200 \ @@ -260,8 +250,8 @@ The required .bin files can be found in the following locations: - **boot_app0.bin**: [from arduino-esp32 package](https://github.com/mmakaay/arduino-esp32-unicore-no-mac-crc/blob/v1.0.6/tools/partitions/boot_app0.bin) in `tools/partitions/` - **firmware.bin**: from `//.pioenvs//firmware.bin` -After flashing, power down the lamp, disconnect `GPIO0` from GND and -reconnect the power to boot into the new ESPHome firmware. +After flashing, power down the lamp, disconnect `GPIO0` from GND and reconnect the power to boot +into the new ESPHome firmware. @@ -269,12 +259,12 @@ The lamp should now be operational using the new firmware. -From here on, it is possible to flash the lamp OTA (over the air, which -means that the firmware is uploaded over WiFi) from ESPHome. Therefore, it -is now time to tuck away or remove those soldered wires. +From here on, it is possible to flash the lamp OTA (over the air, which means that the firmware is +uploaded over WiFi) from ESPHome. Therefore, it is now time to tuck away or remove those soldered +wires. -Because I want to keep them around for future use, I tuck them away, making -sure that the connectors don't touch each other or the board. +Because I want to keep them around for future use, I tuck them away, making sure that the connectors +don't touch each other or the board. @@ -285,11 +275,11 @@ The bottom cover can now be put back on. The lamp is ready for use. ## Troubleshooting flash -If you have **A fatal error occurred: MD5 of file does not match data in flash!**, -then make sure you are powering the board using the lamp's own power adapter. -We've seen these errors when trying to power the board using the 3.3V debug pad. +If you have **A fatal error occurred: MD5 of file does not match data in flash!**, then make sure +you are powering the board using the lamp's own power adapter. We've seen these errors when trying +to power the board using the 3.3V debug pad. -After seeing this error, user @tabacha was able to successfully flash his -lamp using the regular power adapter. +After seeing this error, user @tabacha was able to successfully flash his lamp using the regular +power adapter. -< [Configuration guide](configuration.md) | [Index](../README.md) | [Known issues](known_issues.md) > +< [Configuration guide](configuration.md) | [Index](../README.md) | [Technical details](doc/technical_details.md) > diff --git a/doc/installation.md b/doc/installation.md index db871bb..9541376 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -2,62 +2,28 @@ # Installation guide -The code must be compiled using ESPHome. Therefore, a prerequisite is that -you have ESPHome up and running in some form (command line, docker container, -web dashboard, possibly from within Home Assistant). -For information on this, please refer to the documentation on the -[ESPHome website](https://esphome.io). - -Create a folder named `custom_components` in the folder where your device's -yaml configuration file is stored. Then clone the the Github repo into a -subfolder `xiaomi_bslamp2`. For example on the command line: - -``` -# cd /your/path/to/config -# mkdir custom_components -# cd custom_components -# git clone https://github.com/mmakaay/esphome-xiaomi_bslamp2 xiaomi_bslamp2 -``` - -Your folder structure should now look like: -``` -config -├── yourdevice.yaml -├── custom_components/ -│ ├── xiaomi_bslamp2/ -│ . ├── README.md -. . ├── LICENSE.md -. . . -``` - -On a Rapsbery Pi with HomeAssistant and ESPHome as a plugin, the directory -should be: `/config/esphome/custom_components/xiaomi_bslamp2/` - -``` -config -├── esphome -│ ├── yourdevice.yaml -│ ├── custom_components/ -| . ├── xiaomi_bslamp2/ -│ . . ├── README.md -. . . ├── LICENSE.md -. . . . -``` - -Then create the required configuration in your device's yaml configuration -file. For an example file, take a look at the example file -[example.yaml](example.yaml) in this repository. -Detailed configuration instructions can be found in the -[Configuration guide](configuration.md). - -After these steps you can compile your firmware `firmware.bin` file. -This firmware can then be flashed onto the device. - -Like normal with ESPHome, the first time you will have to flash the -device using a serial interface. After this initial flashing operation, you -can flash new versions of the firmware using the OTA (Over The Air) method. - -See [the flashing guide](flashing.md) for hints on opening up the -device and flashing its firmware using its serial interface. +The code must be compiled into a firmware using ESPHome. Therefore, a prerequisite is that you have +ESPHome up and running in some form (command line, docker container, web dashboard, possibly from +within Home Assistant as an add-on). For information on this, please refer to the documentation on +the [ESPHome website](https://esphome.io). + +The component code is distributed directly from GitHub. You will not have to download and install +the code manually. This leverages the external components feature that was introduced in ESPHome +version 1.18.0. Therefore, you must use ESPHome version 1.18.0 or later. + +Before you can compile the firmware, you will have to create the YAML configuration file for your +device. You can take the [example.yaml](example.yaml) from this repository as a starting point, and +modify that one to your needs. Detailed information about the YAML configuration options can be +found in the [Configuration guide](configuration.md). + +After these steps you can let ESPHome compile your firmware (`firmware.bin`) file. This firmware +can then be flashed onto the device. + +Like normal with ESPHome, the first time you will have to flash the device using a serial interface. +After this initial flashing operation, you can flash new versions of the firmware using the OTA +(Over The Air) method. + +See [the flashing guide](flashing.md) for hints on opening up the device and flashing its firmware +using the serial interface. < [Why custom firmware?](why_custom_firmware.md) | [Index](../README.md) | [Configuration guide](configuration.md) > diff --git a/doc/known_issues.md b/doc/known_issues.md deleted file mode 100644 index 98bd753..0000000 --- a/doc/known_issues.md +++ /dev/null @@ -1,86 +0,0 @@ -< [Flashing guide](flashing.md) | [Index](../README.md) | [Technical details](technical_details.md) > - -# Known issues - -## The device keeps losing its connection to Home Assistant - -Disconnects are annoying, but even more annoying is that sometimes the -lamp will reboot (during which the light will be turned off) as a result of -these disconnects. The reasons for these reboots are very likely in the -underlying libraries, and I'm working on tracking these down. - -In the meanwhile, there are a few factors that you can look at to bring down -the number of disconnects: - -* A bug in the AsyncTCP library -* The number of connected API clients -* The logging output level - -**A bug in the AsyncTCP library** - -You might be running into a problem in the upstream library "AsyncTCP". -If you connect a serial console to your lamp and see "ack timeout 4" -messages in the logging output before the lamp disconnects the API client, -then you can be pretty sure that this is the culprit. - -I did identify the underlying issue and a pull request for a fix was -accepted and merged into the ESPHome fork of the library: - - https://github.com/OttoWinter/AsyncTCP/pull/4 - -This fix will likely be available in the next release of ESPHome -(the current version at the time of writing is 1.16.2). - -If you want to try out this fix on beforehand, then create a `libs` folder -in the folder where your device's yaml configuration file is stored (e.g. -when using the Home Assistant plugin: `/config/esphome/libs/`). -Then clone the following repository into that folder: - - https://github.com/mmakaay/AsyncTCP - -For example on the command line: - -``` -# cd /config/esphome -# mkdir libs -# cd libs -# git clone https://github.com/mmakaay/AsyncTCP -``` - -Then add a pointer to this folder from within your device's yaml -configuration file, using the `lib_extra_dirs` option. Provide it with the -absolute path to your `libs` folder. The relevant part of the config change -looks like this (matching the example from above): - -```yaml -esphome: - platformio_options: - lib_extra_dirs: /config/esphome/libs -``` - -This way, the repository version of the library will override the version of -the library that is bundled with ESPHome. Build the device firmware and -flash the device like you would normally do. - -**The number of connected API clients** - -Another factor on the connection stability, seems to be the number of -clients that are connected to the API. When connecting a log client via the -API (e.g. when looking at the logging from within the web dashboard), while -Home Assistant is also connected, disconnects might occur. - -When the lamp is in production, this is not an issue. Then only Home -Assistant is connected. - -**The logging output level** - -I have seen an increase in disconnects while the log level was set to -`VERY_VERBOSE`. The logging code might take up so much time, that it -interferes with the operation of the networking code. Especially since the -ESP32-WROOM-32D chip that is used in the lamp is a single core version of -the ESP32. - -For this reason, I advise to completely omit logging or use a very low log -level for production purposes. - -< [Flashing guide](flashing.md) | [Index](../README.md) | [Technical details](technical_details.md) > diff --git a/doc/sponsoring.md b/doc/sponsoring.md index a8782d8..9c3dfbb 100644 --- a/doc/sponsoring.md +++ b/doc/sponsoring.md @@ -2,20 +2,17 @@ # Sponsoring the project -All development on this firmware is done for the greater good of mankind. -You can use it for free. However, if you do feel the uncontrollable urge -to contribute financially to the project, you can do so through -[this PayPal link](https://www.paypal.com/paypalme/bedsidelamp2). +All development on this firmware is done for the greater good of mankind. You can use it for free. +However, if you do feel the uncontrollable urge to contribute financially to the project, you can do +so through [this PayPal link](https://www.paypal.com/paypalme/bedsidelamp2). -This account is used for acquiring hardware and software licenses that -I use for my open source development. Specific hardware that I bought for -this project were: +This account is used for acquiring hardware and software licenses that I use for my open source +development. Specific hardware that I bought for this project were: -* An extra lamp for development and testing, so I don't annoy my wife - with buggy deployements ;-) +* An extra lamp for development and testing, so I don't annoy my wife with buggy deployements ;-) * A dedicated serial to USB adapter, connected to the development lamp. -* a simple 8 port logic analyzer that helped me with reverse engineering - the I2C protocol of the front panel. +* a simple 8 port logic analyzer that helped me with reverse engineering the I2C protocol of the + front panel. * Various wires and buttons. * An Arduino Uno R3, to [help out somebody in the community forums with flashing the lamp using the Arduino](https://community.home-assistant.io/t/hacking-yeelight-fw-enabling-lan-control/284406/214?u=mmakaay). diff --git a/doc/technical_details.md b/doc/technical_details.md index 2909e57..a90ffcb 100644 --- a/doc/technical_details.md +++ b/doc/technical_details.md @@ -1,9 +1,9 @@ -< [Known issues](known_issues.md) | [Index](../README.md) | [Sponsoring](sponsoring.md) > +< [Flashing guide](flashing.md) | [Index](../README.md) | [Sponsoring](sponsoring.md) > # Technical details -In this section, you can find some of the information that was gathered -during the reverse engineering of the Bedside Lamp 2 hardware. +In this section, you can find some of the information that was gathered during the reverse +engineering of the Bedside Lamp 2 hardware. Table of contents: @@ -41,10 +41,9 @@ The LED circuitry provides two light modes: * Colored RGB light; * Warm to cool white light. -The front panel of the device contains a two touch buttons (power on/off and -color selection) and a touch slider (for setting the brightness level). This -panel is lit when the device is turned on. The light behind the slider will -represent the actual brightness setting of the device. +The front panel of the device contains a two touch buttons (power on/off and color selection) and a +touch slider (for setting the brightness level). This panel is lit when the device is turned on. The +light behind the slider will represent the actual brightness setting of the device. ## ESP32 pinout @@ -53,10 +52,9 @@ In the following image, you can find the pinout as used for the ESP32: -Here's an overview of all exposed pins of the chip, starting at the GND + -3.3V pins, and going anti-clockwise. The table shows not only the functions -of the pins that are actually in use by the lamp's circuitry, but also the -pins that are not in use and their possible use. +Here's an overview of all exposed pins of the chip, starting at the GND + 3.3V pins, and going +anti-clockwise. The table shows not only the functions of the pins that are actually in use by the +lamp's circuitry, but also the pins that are not in use and their possible use. | PIN | GPIO# | Function | Description | Possible use | |------|--------|-----------|--------------------------------|--------------| @@ -99,19 +97,16 @@ pins that are not in use and their possible use. | 36 | GPIO23 | - | | IN/OUT | | GND | | Ground | Connected to ground | - | -1. GPIO25 is connected to a 10k pull up resistor. This suggests that it - might have some function in the lamp, but I have not found that function - yet. If you find the actual use for this pin, or find that you can indeed - repurpose it, then please let me know. -1. Beware that GPIO15 outputs a PWM signal at boot. This might make the pin - less useful for your use case. -1. Often, GPIO2 is used for an on-board LED. Here, it is only connected - to the debug pad. The pin is usable for I/O (I tested it), which is great - because of the easy access of the debug pad. GPIO2 might only be used for - testing purposes in the original firmware. -1. The connected IC, using I2C address 0x10, looks a lot like an EEPROM, - but this has yet to be confirmed. It uses a decicated I2C bus, separate - from the I2C bus of the front panel. +1. GPIO25 is connected to a 10k pull up resistor. This suggests that it might have some function in + the lamp, but I have not found that function yet. If you find the actual use for this pin, or + find that you can indeed repurpose it, then please let me know. +1. Beware that GPIO15 outputs a PWM signal at boot. This might make the pin less useful for your use + case. +1. Often, GPIO2 is used for an on-board LED. Here, it is only connected to the debug pad. The pin is + usable for I/O (I tested it), which is great because of the easy access of the debug pad. GPIO2 + might only be used for testing purposes in the original firmware. +1. The connected IC, using I2C address 0x10, looks a lot like an EEPROM, but this has yet to be + confirmed. It uses a decicated I2C bus, separate from the I2C bus of the front panel. [This picture](images/hardware/IC_on_I2C_GPIO1718.jpg) shows the IC. For more information on the use of pins on the ESP32 chip, please check out @@ -122,9 +117,8 @@ this [ESP32 pinout reference information](https://randomnerdtutorials.com/esp32- -The front panel is a stand-alone component, with its own control chip -(KungFu KF8TS2716). Communication between the ESP32 and the front panel -is done using: +The front panel is a stand-alone component, with its own control chip (KungFu KF8TS2716). +Communication between the ESP32 and the front panel is done using: - **An I2C bus** - the front panel is the I2C slave, the ESP32 is the I2C master @@ -137,20 +131,17 @@ is done using: - the default state is HIGH - line is pulled LOW for at least 6 ms when a new event is available -Commands can be written to and data can be read from the front panel -component using I2C. The I2C protocol is fairly simple. All read and write -operations uses 6 bytes of data. No register selection is done before -reading or writing. +Commands can be written to and data can be read from the front panel component using I2C. The I2C +protocol is fairly simple. All read and write operations uses 6 bytes of data. No register selection +is done before reading or writing. -The interrupt data line is used by the front panel, to signal the ESP32 that -a new button or slider event is available. Further details on this can be -found below. +The interrupt data line is used by the front panel, to signal the ESP32 that a new button or slider +event is available. Further details on this can be found below. **Connection to the main board** -The front panel is connected to the main board using a flat cable. -The picture below shows the connector on the main board, including the -functions of the cable pins: +The front panel is connected to the main board using a flat cable. The picture below shows the +connector on the main board, including the functions of the cable pins: @@ -176,9 +167,8 @@ The available commands are: | SET LEVEL 10 | 02 03 5F FF 64 00 00 | | READY FOR EVENT | 01 00 00 00 00 00 01 | -*Note: The `READY FOR EVENT` command is only used when a new event is provided -by the front panel. Information about this command can be found in the next -section.* +*Note: The `READY FOR EVENT` command is only used when a new event is provided by the front panel. +Information about this command can be found in the next section.* **Reading events from the front panel** @@ -188,21 +178,21 @@ The types of events that can occur can be summarized as: - Touch or release the color button - Touch or release the slider at a certain level -Because the front panel is an I2C slave device, it cannot contact the ESP32 via -I2C. Only an I2C master device can initiate communication. Therefore, when the -front panel has a new event available, it will pull down the interrupt line for -a short period of time, to signal the ESP32 about this new event. +Because the front panel is an I2C slave device, it cannot contact the ESP32 via I2C. Only an I2C +master device can initiate communication. Therefore, when the front panel has a new event available, +it will pull down the interrupt line for a short period of time, to signal the ESP32 about this new +event. -*Note that the ESP32 needs to poll the interrupt line at least at 667 Hz to be -able to trustworthy detect the 6 ms signal. Unfortunately, the interrupt line -does not wait for the ESP32 to respond to its signalling. The best way to -handle signals from this line, is to use an actual interrupt handler.* +*Note that the ESP32 needs to poll the interrupt line at least at 667 Hz to be able to trustworthy +detect the 6 ms signal. Unfortunately, the interrupt line does not wait for the ESP32 to respond to +its signalling. The best way to handle signals from this line, is to use an actual interrupt +handler.* -After detecting this signal, the ESP32 must first write the "READY FOR EVENT" -command (`01 00 00 00 00 00 01`) via I2C to the front panel. +After detecting this signal, the ESP32 must first write the "READY FOR EVENT" command (`01 00 00 00 +00 00 01`) via I2C to the front panel. -After the front panel has ACK'ed this command, the ESP32 can read 6 bytes, -which will represent the event that occurred. +After the front panel has ACK'ed this command, the ESP32 can read 6 bytes, which will represent the +event that occurred. Here's the mapping for the events and their corresponding byte sequences: @@ -235,29 +225,28 @@ Here's the mapping for the events and their corresponding byte sequences: **Behavior when more events come in than can be handled** -The front panel does not queue events. When a new event occurs, before the -previous event has be read by the ESP32, the new event will replace the old -event and a new signal is sent over the interrupt line. +The front panel does not queue events. When a new event occurs, before the previous event has be +read by the ESP32, the new event will replace the old event and a new signal is sent over the +interrupt line. -The ESP32 can read the last event multiple times. It will not be cleared -by the front panel after reading it. +The ESP32 can read the last event multiple times. It will not be cleared by the front panel after +reading it. ## Build requirements -The ESP-WROOM-32D that is used for this lamp (and for various other Xiaomi devices), -contains a single core CPU, even though the data sheet for ESP-WROOM-32D specifies -a dual core CPU. Therefore, when flashing the device with a generic ESP32 build, -you will end up with the following boot error: +The ESP-WROOM-32D that is used for this lamp (and for various other Xiaomi devices), contains a +single core CPU, even though the data sheet for ESP-WROOM-32D specifies a dual core CPU. Therefore, +when flashing the device with a generic ESP32 build, you will end up with the following boot error: ``` E (459) cpu_start: Running on single core chip, but application is built with dual core support. E (459) cpu_start: Please enable CONFIG_FREERTOS_UNICORE option in menuconfig. ``` -Another issue with a lot of these devices, is that the MAC address that is burnt into -EFUSE does not match the CRC checksum that is also burnt into EFUSE. Using a generic -ESP32 build, you will end up with the boot error: +Another issue with a lot of these devices, is that the MAC address that is burnt into EFUSE does not +match the CRC checksum that is also burnt into EFUSE. Using a generic ESP32 build, you will end up +with the boot error: ``` Base MAC address from BLK0 of EFUSE CRC error @@ -268,8 +257,8 @@ You can make use of the version [created by @pauln](https://github.com/pauln/ard or the version [created by @mmakaay](https://github.com/mmakaay/arduino-esp32-unicore-no-mac-crc). To make use of one of these in an ESPHome build, you'll have to provide a platform package -definition for the PlatformIO build. Here's an example configuration that will work for -these Xiaomi devices: +definition for the PlatformIO build. Here's an example configuration that will work for these Xiaomi +devices: ```yaml esphome: @@ -288,8 +277,8 @@ the build scripts [by @mmakaay here](https://github.com/mmakaay/arduino-esp32-un ## Original firmware -Below, I have gathered some of the interesting boot messages from the -original firmware. These messages are logged via the serial interface. +Below, I have gathered some of the interesting boot messages from the original firmware. These +messages are logged via the serial interface. **SPI Flash memory:** ``` @@ -363,4 +352,4 @@ ots: Connected. ``` -< [Known issues](known_issues.md) | [Index](../README.md) | [Sponsoring](sponsoring.md) > +< [Flashing guide](flashing.md) | [Index](../README.md) | [Sponsoring](sponsoring.md) > diff --git a/doc/testplan.md b/doc/testplan.md index 5e6ad4a..b50d4ac 100644 --- a/doc/testplan.md +++ b/doc/testplan.md @@ -1,20 +1,20 @@ # Testplan -This is the test plan that I follow for every release. -I use it to ensure that no regression has been introduced. +This is the test plan that I follow for every release. I use it to ensure that no regression has +been introduced. ## Step 1: Preparation - build and flash the firmware -* Use the latest stable release for ESPHome (to make sure that my code - builds and works with that release). In my clone I make sure that I - checked out the master branch and that it's up-to-date with the origin. +* Use the latest stable release for ESPHome (to make sure that my code builds and works with that + release). In my clone I make sure that I checked out the master branch and that it's up-to-date + with the origin. * Remove the cached framework package: `/bin/rm -fR ~/.platformio/packages/framework-arduinoespressif32` -* Copy `doc/example.yaml` to a clean build directory, and update the - first two sections for the local setup (substitutions, wifi, api, ota). +* Copy `doc/example.yaml` to a clean build directory, and update the first two sections for the + local setup (substitutions, wifi, api, ota). * Use `esphome example.yaml compile` to build the code. @@ -27,35 +27,31 @@ I use it to ensure that no regression has been introduced. * Touch the power button again --> the light must turn off. -* Touch the slider at any level --> the light must turn on, using the - level at which the slider was touched as the brightness. The front panel - illumination is turned on and shows the brightness level. +* Touch the slider at any level --> the light must turn on, using the level at which the slider was + touched as the brightness. The front panel illumination is turned on and shows the brightness + level. -* Touch the slider at various points and touch the slider while moving your - finger up and down --> the brightness of the light and the brightness - level on the front panel must follow the touches. +* Touch the slider at various points and touch the slider while moving your finger up and down --> + the brightness of the light and the brightness level on the front panel must follow the touches. -* Touch and hold the power button --> the light must go into "night light" - mode. This means that it will become very dim. The front panel - illumination must be turned off. +* Touch and hold the power button --> the light must go into "night light" mode. This means that it + will become very dim. The front panel illumination must be turned off. -* Touch the slider at a random level --> the light must go back to its - normal brightness levels and the front panel illumination must be turned - on again. +* Touch the slider at a random level --> the light must go back to its normal brightness levels and + the front panel illumination must be turned on again. -* Touch the color button a few times in a row --> the light must loop through - the various preset light colors. +* Touch the color button a few times in a row --> the light must loop through the various preset + light colors. -* Touch and hold the color button --> the light must switch to a different - preset group. There are two groups: one with rgb colors and one with white - light colors, and holding the color button will switch between these two. +* Touch and hold the color button --> the light must switch to a different preset group. There are + two groups: one with rgb colors and one with white light colors, and holding the color button will + switch between these two. -* Touch the color button to select a light color, long touch it to switch to - the other preset group, then long touch again to switch the preset group - again -> the lamp must remember what light colors were active within the - preset groups. If the red preset was selected, you switch to the white - light group, select a different white preset and then go back to the rgb - presets, then the light must become red again. +* Touch the color button to select a light color, long touch it to switch to the other preset group, + then long touch again to switch the preset group again -> the lamp must remember what light colors + were active within the preset groups. If the red preset was selected, you switch to the white + light group, select a different white preset and then go back to the rgb presets, then the light + must become red again. * Go to Home Assistant and check: * if you can turn on/off the lamp @@ -68,5 +64,4 @@ I use it to ensure that no regression has been introduced. ## Step 3: Release the new version -Only after performing these tests successfully, the new version can be -released. +Only after performing these tests successfully, the new version can be released. diff --git a/doc/why_custom_firmware.md b/doc/why_custom_firmware.md index c2b4249..f707e40 100644 --- a/doc/why_custom_firmware.md +++ b/doc/why_custom_firmware.md @@ -2,38 +2,33 @@ # Why custom ESPHome firmware? -This lamp could always be added to Home Assistant using the Yeelight -integration. For this to work, the lamp had to be configured to enable a -special "LAN control" option, which provides the interface that the Yeelight -integration could talk to. +This lamp could always be added to Home Assistant using the Yeelight integration. For this to work, +the lamp had to be configured to enable a special "LAN control" option, which provides the interface +that the Yeelight integration could talk to. -January 2021, Xiaomi decided to remove the LAN control option from the -firmware. Information about this can be found on the Yeelight forums: +January 2021, Xiaomi decided to remove the LAN control option from the firmware. Information about +this can be found on the Yeelight forums: https://forum.yeelight.com/t/topic/22664 -In the forums, a work-around is offered: by providing your Mi ID, you can be -added to some mythical white list, through which you'll get a special -firmware upgrade that does have LAN control enabled. After that, no further -ugprades should be done. +In the forums, a work-around is offered: by providing your Mi ID, you can be added to some mythical +white list, through which you'll get a special firmware upgrade that does have LAN control enabled. +After that, no further ugprades should be done. -This just didn't feel right, so I started looking into alternative solutions -to regain control over the lamp. After opening it up, I was pleased to -find an ESP32-WROOM-32D chip inside, meaning that it might be possible to -build my own firmware for it using ESPHome. +This just didn't feel right, so I started looking into alternative solutions to regain control over +the lamp. After opening it up, I was pleased to find an ESP32-WROOM-32D chip inside, meaning that it +might be possible to build my own firmware for it using ESPHome. -On the Home Assistant community forums, I found an existing thread where -people already started poking at the lamp. +On the Home Assistant community forums, I found an existing thread where people already started +poking at the lamp. https://community.home-assistant.io/t/hacking-yeelight-fw-enabling-lan-control/284406 -I joined the discussion and started poking as well. Some things turned out -to be more complicated than anticipated and quite a bit of reverse -engineering was required to make things work, but eventually this all -resulted in working firmware. +I joined the discussion and started poking as well. Some things turned out to be more complicated +than anticipated and quite a bit of reverse engineering was required to make things work, but +eventually this all resulted in working firmware. -Documents related to the reverse engineering process can be found in a -separate GitHub repository: +Documents related to the reverse engineering process can be found in a separate GitHub repository: https://github.com/mmakaay/esphome-yeelight_bs2-revengineering