Browse Source

Updated documentation for 1.18.0 release with external components support.

pull/26/head
Maurice Makaay 3 years ago
parent
commit
dc72f012c6
38 changed files with 384 additions and 565 deletions
  1. +35
    -44
      README.md
  2. +0
    -0
      components/xiaomi_bslamp2/.clang-format
  3. +0
    -0
      components/xiaomi_bslamp2/.clang-tidy
  4. +0
    -0
      components/xiaomi_bslamp2/__init__.py
  5. +0
    -0
      components/xiaomi_bslamp2/binary_sensor/__init__.py
  6. +0
    -0
      components/xiaomi_bslamp2/binary_sensor/touch_binary_sensor.h
  7. +0
    -0
      components/xiaomi_bslamp2/common.h
  8. +0
    -0
      components/xiaomi_bslamp2/front_panel_hal.h
  9. +0
    -0
      components/xiaomi_bslamp2/light/__init__.py
  10. +0
    -0
      components/xiaomi_bslamp2/light/automation.h
  11. +0
    -0
      components/xiaomi_bslamp2/light/color_instant_handler.h
  12. +0
    -0
      components/xiaomi_bslamp2/light/color_night_light.h
  13. +0
    -0
      components/xiaomi_bslamp2/light/color_off.h
  14. +0
    -0
      components/xiaomi_bslamp2/light/color_rgb_light.h
  15. +0
    -0
      components/xiaomi_bslamp2/light/color_transition_handler.h
  16. +0
    -0
      components/xiaomi_bslamp2/light/color_white_light.h
  17. +0
    -0
      components/xiaomi_bslamp2/light/gpio_outputs.h
  18. +0
    -0
      components/xiaomi_bslamp2/light/interfaces.h
  19. +0
    -0
      components/xiaomi_bslamp2/light/light_modes.h
  20. +0
    -0
      components/xiaomi_bslamp2/light/light_output.h
  21. +0
    -0
      components/xiaomi_bslamp2/light/light_state.h
  22. +0
    -0
      components/xiaomi_bslamp2/light/presets.h
  23. +0
    -0
      components/xiaomi_bslamp2/light_hal.h
  24. +0
    -0
      components/xiaomi_bslamp2/output/__init__.py
  25. +0
    -0
      components/xiaomi_bslamp2/output/output.h
  26. +0
    -0
      components/xiaomi_bslamp2/sensor/__init__.py
  27. +0
    -0
      components/xiaomi_bslamp2/sensor/slider_sensor.h
  28. +0
    -0
      components/xiaomi_bslamp2/text_sensor/__init__.py
  29. +0
    -0
      components/xiaomi_bslamp2/text_sensor/light_mode_text_sensor.h
  30. +109
    -134
      doc/configuration.md
  31. +8
    -1
      doc/example.yaml
  32. +99
    -109
      doc/flashing.md
  33. +23
    -57
      doc/installation.md
  34. +0
    -86
      doc/known_issues.md
  35. +8
    -11
      doc/sponsoring.md
  36. +58
    -69
      doc/technical_details.md
  37. +27
    -32
      doc/testplan.md
  38. +17
    -22
      doc/why_custom_firmware.md

+ 35
- 44
README.md View File

@ -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 `<CONFIG_DIR>/<NODE_NAME>.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)

.clang-format → components/xiaomi_bslamp2/.clang-format View File


.clang-tidy → components/xiaomi_bslamp2/.clang-tidy View File


__init__.py → components/xiaomi_bslamp2/__init__.py View File


binary_sensor/__init__.py → components/xiaomi_bslamp2/binary_sensor/__init__.py View File


binary_sensor/touch_binary_sensor.h → components/xiaomi_bslamp2/binary_sensor/touch_binary_sensor.h View File


common.h → components/xiaomi_bslamp2/common.h View File


front_panel_hal.h → components/xiaomi_bslamp2/front_panel_hal.h View File


light/__init__.py → components/xiaomi_bslamp2/light/__init__.py View File


light/automation.h → components/xiaomi_bslamp2/light/automation.h View File


light/color_instant_handler.h → components/xiaomi_bslamp2/light/color_instant_handler.h View File


light/color_night_light.h → components/xiaomi_bslamp2/light/color_night_light.h View File


light/color_off.h → components/xiaomi_bslamp2/light/color_off.h View File


light/color_rgb_light.h → components/xiaomi_bslamp2/light/color_rgb_light.h View File


light/color_transition_handler.h → components/xiaomi_bslamp2/light/color_transition_handler.h View File


light/color_white_light.h → components/xiaomi_bslamp2/light/color_white_light.h View File


light/gpio_outputs.h → components/xiaomi_bslamp2/light/gpio_outputs.h View File


light/interfaces.h → components/xiaomi_bslamp2/light/interfaces.h View File


light/light_modes.h → components/xiaomi_bslamp2/light/light_modes.h View File


light/light_output.h → components/xiaomi_bslamp2/light/light_output.h View File


light/light_state.h → components/xiaomi_bslamp2/light/light_state.h View File


light/presets.h → components/xiaomi_bslamp2/light/presets.h View File


light_hal.h → components/xiaomi_bslamp2/light_hal.h View File


output/__init__.py → components/xiaomi_bslamp2/output/__init__.py View File


output/output.h → components/xiaomi_bslamp2/output/output.h View File


sensor/__init__.py → components/xiaomi_bslamp2/sensor/__init__.py View File


sensor/slider_sensor.h → components/xiaomi_bslamp2/sensor/slider_sensor.h View File


text_sensor/__init__.py → components/xiaomi_bslamp2/text_sensor/__init__.py View File


text_sensor/light_mode_text_sensor.h → components/xiaomi_bslamp2/text_sensor/light_mode_text_sensor.h View File


+ 109
- 134
doc/configuration.md View File

@ -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)


+ 8
- 1
doc/example.yaml View File

@ -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:


+ 99
- 109
doc/flashing.md View File

@ -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.
<img src="images/01_unboxed.jpg" width="200"><img src="images/02_remove_rubber_pads.jpg" width="200">
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.
<img src="images/03_bolts_overview.jpg" width="200">
@ -47,8 +47,8 @@ Unbolt the 4 screws which were hidden under the rubber pads.
<img src="images/04_remove_bolts.jpg" width="200"><img src="images/05_bolts.jpg" width="200">
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.
<img src="images/06_pull_off_the_bottom.jpg" width="200"><img src="images/07_bottom_removed.jpg" width="200">
@ -61,43 +61,40 @@ The wires will be connected to the debug pads that are shown in the following im
<img src="images/09_debug_pads_for_soldering.jpg" width="400">
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.*
<img src="images/10_stripped_dupont_wires.jpg" width="200">
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.
<img src="images/11_soldered_wires.jpg" width="200"><img src="images/12_optional_hot_glue.jpg" width="200">
## 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:
<img src="images/14_connect_to_serial_to_usb_adapter_close_up.jpg" width="400">
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.
<img src="images/15_power_up_for_flashing.jpg" width="400">
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:
<img src="images/16_serial_showing_download_mode.png" width="400">
## 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 `<config dir>/<device name>/.pioenvs/<device name>/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.
<img src="images/18_disconnect_GPIO0.jpg" width="200">
@ -269,12 +259,12 @@ The lamp should now be operational using the new firmware.
<img src="images/19_test_run.jpg" width="200">
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.
<img src="images/20_tuck_away_wires.jpg" width="200">
@ -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) >

+ 23
- 57
doc/installation.md View File

@ -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) >

+ 0
- 86
doc/known_issues.md View File

@ -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) >

+ 8
- 11
doc/sponsoring.md View File

@ -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).


+ 58
- 69
doc/technical_details.md View File

@ -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:
<img src="images/hardware/ESP32_pinout.jpg" width="600">
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-
<img src="images/hardware/front_panel.jpg" width="150">
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:
<img src="images/hardware/front_panel_flat_cable_connection.jpg" width="400">
@ -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) >

+ 27
- 32
doc/testplan.md View File

@ -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.

+ 17
- 22
doc/why_custom_firmware.md View File

@ -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


Loading…
Cancel
Save