Custom firmware ESPHome-Xiaomi_bslamp2

I extended the documentation for the repository:

I just removed all the scary wires from my Frankenstein lamp, and I soldered / hot glued a permanent flashing setup to it instead. Placement of the button and header based on an idea of my colleague Erwin, who did the setup with a male header (his FTDI has a female connector on it).

So this probably concludes the low level reverse engineering phase :smiley:
There’s one thing left to investigate: the little black IC (visible in the photo above the two black and to the left of the yellow and orange wires). Probably an EEPROM, but I did not yet try to talk to it using I2C.

First, I’m checking out if some kind of disco-mode access is feasible, so it is possible to apply new light settings instantly, without saving or publishing them.
What I want to use this for, is to provide some visual feedback when flashing the lamp OTA. Within the OTA process, normally the light cannot be changed, because the OTA does not give control back to the main loop(). The light is normally only updated when its loop() method is called, but during OTA this is never done.

2 Likes

I’ve got some working code for disco-mode updates. The light state is applied immediately, is not published and not stored. I’ve used it for building a fun demo (which depends on an open pull request for ota triggers).

The demo shows some visual feedback during an OTA upgrade.

  • the light goes blue during the firmware transfer
  • the slider illumination represents the progres
  • after a successful upgrade, the light goes green, before the device reboots
  • after a failed upgrade, the light shortly flashes red
1 Like

Im following this thread now since it started and I have to say, you are developing faster than many companies. You made me wanna buy one if these lamps, just to use your awesome work!

2 Likes

Thanks for your friendly words, very much appreciated!

Developing for it, and learning a lot about ESPHome while I’m at it, is a huge pleasure.
I already was pleased with the lamp, but after hacking it, it has become on of my favorite devices that I have in my house. It doesn’t win from my heavily modified Nabaztag v1 rabbit though!
The moment at which I was able to move the rabbit’s ears by using the slider on the lamp really was epic :smiley:

I added a bit of extra hardware to one of my lamps: I attached a microwave presence sensor (RCWL-0516). It is built into the foot of the lamp and therefore completely invisible from the outside. Since it is based on microwave, it sees right through the lamp’s plastic housing (and it even detects my motion when I’m behind the wooden door of my room :wink: ).

Here’s an overview of the mod:

The black wire is connected to a GND point.

The red wire was a bit fiddly. I connected that on the bottom of the board to a point where I could tap into the 12V of the power supply. The presence sensor accepts 4V - 28V and has its own regulator to bring it down to 3.3V. The signal from the sensor is also using 3.3V, so no level shifting is required before feeding it to GPIO2.

I used the debug pad that is attached to GPIO2 for the sensor signal (yello wire). I wasn’t sure if that would be possible, but by the looks of it, that debug pad is only used for a test function in the original firmware. Using it does not disturb the lamp’s functionality. I could use GPIO2 without any issues and the presence sensor is doing a great job.

Here’s a demo of the sensor:

Update: Something not working

When I turn off the light, the presence sensor now continuously shows presence. It only goes to an OFF state, when the light is turned on.
I thought this was possibly related to the use of GPIO2, but this is not the issue. I get the same result on GPIO23.
In fact: when I disconnect the data wire completely and measure that on, it stays at 3.3V all the time when the lamp is off. Weirdness…

Update: nailed it

It looks like the power supply isn’t providing clean power when the LEDs are off. I added a filter to the input. While I was at it, I added a pull down resistor to the data line.Using these modifications, I now have a working presence sensor, regardless the state of the LEDs :smiley:

1 Like

Short note to thank you for producing and sharing this solution.
Yesterday my lamp woke up disconnected from HA; upon further inspection it seems yeelight pushed the upgrade overnight and ‘LAN’ was no longer available in the app.

Followed your very detailed steps and it’s now an ESP convert.

Small question and forgive me if it’s obvious. If mqtt is added to the config, could the lamp also be controlled via mqtt?

Thank you again.

Very good! Welcome to the club :grin:

I am not sure how mqtt works in relation to light control or state updates. I have only used it to publish some data from automations.
But it might just work!
The code that I wrote extends standard ESPHome components, so what works for those should work for this lamp.

Do you use it to connect to Hone Assistant, or are you connecting to mqtt for a different purpose? If it is only for Home Assistant, I would advise the API. It is a great way of connecting.

Thank you .
I am using homeassistant and indeed the API works great.

Just considering the mqtt option in case I need to migrate to another platform. Everything seems to talk mqtt.

I will take a look at it, to see if things would work out of the box. A nice opportunity to familiarize myself with the mqtt component.

Well @juan11perez, I tested MQTT with the Bedside Lamp 2, and it worked extremely simple. I configured the mqtt section to connect to my MQTT broker. After flashing this firmware, I went to the MQTT integration in Home Assistant and found that the lamp was already added there because of the autodiscovery messages that the lamp had sent.

I have full control over the lamp via MQTT.

So no worries there, MQTT will work just fine when you’re in need of a different integration approach.
Just remember to remove the api section when switching to MQTT-only, otherwise the lamp will reboot itself because it does not see any API clients connected.

Once again thank you very much for your help and prompt response.

This means people can easily use your solution with any other home automation platform.

Hadn’t thought of it that way yet (who would want another platform to begin with? :wink: ), but you are right.
It is genuinely awesome, but I gladly attribute all the awesomness to ESPHome in this case!

Well I agree, HA is very powerful and I have no intention of changing, however openhab and others have a large ussrbase and being mqtt compatible means those users can also implement your solution.

1 Like

Today, my (genuine, no-clone) Arduino Uno R3 arrived. I hooked it up to my lamp to see if I could get a serial console. I managed to do so, but… I had to connect the pin labeled RX to the RX on the lamp, and TX to TX. Only after doing that, I saw the serial console log messages come in. This probably has something to do with the way the USB to serial passes through to the TX/RX pins on the Arduino.

With the logging working, I tried flashing the device using esphome-flasher, ignoring 3.3V / 5V differences (YOLO!). I ran into the following error:

Detecting chip type... ESP32
Connecting........__

Chip Info:
 - Chip Family: ESP32
 - Chip Model: unknown ESP32 (revision 1)
 - Number of Cores: 1
 - Max CPU Frequency: 240MHz
 - Has Bluetooth: YES
 - Has Embedded Flash: NO
 - Has Factory-Calibrated ADC: YES
 - MAC Address: **:**:**:**:**:**
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Unexpected error: Reading chip details failed: Timed out waiting for packet header

Suspecting that the chosed baud rate was too high for this to work, I reverted to flashing the firmware and other parts using esptool on the command line:

PS C:\Users\mauri\Downloads> esptool.py.exe --chip esp32 -p COM5 --baud 115200 write_flash 0x10000 firmware_office.bin 0x1000 bootloader_dout_40m.bin 0x8000 partitions.bin 0xe000 boot_app0.bin
esptool.py v2.8
Serial port COM5
Connecting........_____....._____....._____....
Chip is unknown ESP32 (revision 1)
Features: WiFi, BT, Single Core, 240MHz, VRef calibration in efuse, Coding Scheme 3/4
Crystal is 40MHz
MAC: **:**:**:**:**:**
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 922832 bytes to 526222...
Wrote 922832 bytes (526222 compressed) at 0x00010000 in 45.8 seconds (effective 161.2 kbit/s)...
Hash of data verified.
Compressed 17184 bytes to 11210...
Wrote 17184 bytes (11210 compressed) at 0x00001000 in 1.0 seconds (effective 140.6 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 144...
Wrote 3072 bytes (144 compressed) at 0x00008000 in 0.0 seconds (effective 1170.2 kbit/s)...
Hash of data verified.
Compressed 8192 bytes to 47...
Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.0 seconds (effective 5461.0 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

After disconnecting and reconnecting the power supply, the lamp is now running the ESPHome firmware that was successfully uploaded via the Arduino R3. So I can confirm that this should be possible.

Maybe start out by switching TX and RX, @Kmq ?

Today my USB-UART converter arrived, but anyway i’ll try to flash the lamp with arduino :slight_smile: i’ll inform you about the results! And thanks for the help :slight_smile:

Can this FW be flashed to the Yeelight desk lamp? Got the same problem with LAN control

1 Like

I’m also curious about this (I have two of these desk lamps), and other Xiaomi lamps (I have three of the bslamp1 that would also be great to flash):

In case you’re not aware, looks like you can flash the desk lamp with Tasmota: Xiaomi Mi Desk Lamp - Tasmota

I haven’t tried flashing my desk lamps with Tasmota yet, but considering it. Also, waiting to see how mmakaay’s work unfolds, looks like great progress has been made already!

Thanks Lili for pointing to Tasmota. I will give it a try. BTW, I reckon that I have 3 such desk lamps. The first 2 I bought years ago whose model is yeelink.light.lamp1. I just bought one recently whose model is yeelink.light.lamp4. The out look is exactly the same. The lamp1 has FW version 1.3.9_0062 which still be able to use with HA (I enabled LAN long time ago). The lamp4 with FW ver 2.1.7_0012 cannot.

Do you think we can flash the lamp4 with lamp1 FW? Is it possible to backup/restore lamp4 FW in case it doesn’t work? I have never flash before.

The first thing to do with any lamp is to open it up and have a look at the electronics, take some pictures and share those. That may give us some clues. I suggest that you start a new topic for each type of lamp, though. This one is getting fairly long already, and different setups shouldn’t be mixed :wink:

Well, i finally connected it, but i have the following error:

esptool -p /dev/ttyUSB0 read_flash 0x0 0x400000 original-firmware.bin
esptool.py v2.8
Serial port /dev/ttyUSB0
Connecting........_
Detecting chip type... ESP32
Chip is unknown ESP32 (revision 1)
Features: WiFi, BT, Single Core, 240MHz, VRef calibration in efuse, Coding Scheme 3/4
Crystal is 40MHz
MAC: 64:90:c1:a6:d8:2b
Enabling default SPI flash mode...

A fatal error occurred: ESP32 ROM does not support function read_flash.

What is going on?

#EDIT
Okay, i found the solution - it isn’t working with esptool 2.8 which is by default on ubuntu 20.04. I tried with esptool 3.0 and it is working. We will see if it succeeds :slight_smile:

#EDIT2
I made a backup of the firmware and it worked, but when i try to compile a new firmware in ESPHome i have following errors:

INFO Reading configuration /config/esphome/esphome-xiaomi_bslamp2.yaml...
Failed config

light.xiaomi_bslamp2: [source /config/esphome/esphome-xiaomi_bslamp2.yaml:74]
  
  Platform not found: 'light.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp
  name: Bedside Lamp RGBW Light
  default_transition_length: 500ms
  on_brightness: 
    - if: 
        condition: 
          text_sensor.state: 
            id: bedside_lamp_light_mode
            state: night
        then: 
          - output.set_level: 
              id: bedside_lamp_front_panel_illumination
              level: 0
        else: 
          - output.set_level: 
              id: bedside_lamp_front_panel_illumination
              level: !lambda |-
                return x;
  effects: 
    - random: 
        name: Slow Random
        transition_length: 30s
        update_interval: 30s
    - random: 
        name: Fast Random
        transition_length: 3s
        update_interval: 3s
  presets: 
    rgb: 
      red: 
        red: 100%
        green: 0%
        blue: 0%
      green: 
        red: 0%
        green: 100%
        blue: 0%
      blue: 
        red: 0%
        green: 0%
        blue: 100%
      yellow: 
        red: 100%
        green: 100%
        blue: 0%
      purple: 
        red: 100%
        green: 0%
        blue: 100%
      randomize: 
        effect: Fast Random
    white: 
      cold: 
        color_temperature: 153 mireds
      chilly: 
        color_temperature: 275 mireds
      luke: 
        color_temperature: 400 mireds
      warm: 
        color_temperature: 588 mireds
text_sensor.xiaomi_bslamp2: [source /config/esphome/esphome-xiaomi_bslamp2.yaml:131]
  
  Platform not found: 'text_sensor.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  name: bedside_lamp Light Mode
  id: bedside_lamp_light_mode
output.xiaomi_bslamp2: [source /config/esphome/esphome-xiaomi_bslamp2.yaml:139]
  
  Platform not found: 'output.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp_front_panel_illumination
binary_sensor.xiaomi_bslamp2: [source /config/esphome/esphome-xiaomi_bslamp2.yaml:148]
  
  Platform not found: 'binary_sensor.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp_power_button
  for: POWER_BUTTON
  on_multi_click: 
    - timing: 
        - ON for at most 0.8s
      then: 
        - light.toggle: bedside_lamp
    - timing: 
        - ON for at least 0.8s
      then: 
        - light.turn_on: 
            id: bedside_lamp
            brightness: 1%
binary_sensor.xiaomi_bslamp2: [source /config/esphome/esphome-xiaomi_bslamp2.yaml:165]
  
  Platform not found: 'binary_sensor.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp_color_button
  for: COLOR_BUTTON
  on_multi_click: 
    - timing: 
        - ON for at most 0.6s
      then: 
        - preset.activate: 
            next: preset
    - timing: 
        - ON for at least 0.6s
      then: 
        - preset.activate: 
            next: group
sensor.xiaomi_bslamp2: [source /config/esphome/esphome-xiaomi_bslamp2.yaml:189]
  
  Platform not found: 'sensor.xiaomi_bslamp2'.
  platform: xiaomi_bslamp2
  id: bedside_lamp_slider_level
  range_from: 0.02
  on_value: 
    then: 
      - light.turn_on: 
          id: bedside_lamp
          brightness: !lambda |-
            return x;

#EDIT3
Okay, i think i fixed that also. Folder name was wrong…

#EDIT4
It works with HA, i’m so happy :slight_smile: But how to change its colors/modes from lovelace UI for example? I can only change it’s brightness.