Add Ledvance Smart+ BT Bluetooth

Is it possible to add the Ledvance Smart+ BT?

SMART+ Classic filament lamps with Bluetooth technology | LEDVANCE

How can I help with this? ESPhome blutooth proxy is installed and a bulbe is also there.

6 Likes

I´d like to do the same as there are quite a few Smart+ manufacturers now, so somewhat a standard in bluetooth bulbs.

3 Likes

Also looking for a solution on this - any progress so far?

2 Likes

An integration for this would be really awesome. These bulbs aren’t the best on the planet, but they’re excellent value for money.

4 Likes

Hello
Bump here
I also bought one of this to test

I have a raspberry pi 4, extra bluetooth asus dongle and esp home to test, if it helps

Is it predicted to have an integration for this,

Local only please

1 Like

it works?
LDV BT dont work with smartthings app !?!

Update from my side:
Still have no breakthrough, but tried the following. Bought an old iPhone (:-D) to flash the Bluetooth lamp to the HomeKit compatible firmware. After that HA recognizes the lamp immediately and automatically. However, a PIN is needed for the connection setup, which is unfortunately not included with my lamp (if - unlike with me - “works with HomeKit” is written on the package, the pin should be enclosed).
→ I am now the owner of a useless old iPhone, but the lamp still does not work via HA - possibly the approach helps one or the other, however…

Still looking forward to smart ways/tips for integration.

2 Likes

Could you describe the steps how you came there, please? I tryed the same but I stucked already on the step “activate”. The ledvance App show “no Network found”

I think these “Ledvance Smart+” are the same as the “Osram Smart+” and “Sylvania Smart+” bulbs

My Sylvania Smart+ is recognized by my pixel phone as

[Destination BD_ADDR: Ledvance_22:c6:ac (f0:d1:b8:22:c6:ac)]
[Destination Device Name: SYLVANIA A19 T-C-MC6AC]

From my explorations using bluez gatttool:

Attempting to connect to F0:D1:B8:22:C6:AC
Connection successful
Indication   handle = 0x0029 value: 01 00 ff 00
[F0:D1:B8:22:C6:AC][LE]> primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x000c uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle: 0x000d, end grp handle: 0x0010 uuid: 00010203-0405-0607-0809-0a0b0c0d1912
attr handle: 0x0011, end grp handle: 0x0019 uuid: 00001827-0000-1000-8000-00805f9b34fb
attr handle: 0x001a, end grp handle: 0x0022 uuid: 00007fdd-0000-1000-8000-00805f9b34fb
attr handle: 0x0023, end grp handle: 0x0026 uuid: 00010203-0405-0607-0809-0a0b0c0d7fde
attr handle: 0x0027, end grp handle: 0x002b uuid: 00001801-0000-1000-8000-00805f9b34fb
[F0:D1:B8:22:C6:AC][LE]> char-desc
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x0008, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0009, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000a, uuid: 00002a50-0000-1000-8000-00805f9b34fb
handle: 0x000b, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000c, uuid: 00002a26-0000-1000-8000-00805f9b34fb
handle: 0x000d, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000e, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000f, uuid: 00010203-0405-0607-0809-0a0b0c0d2b12
handle: 0x0010, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0011, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0012, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0013, uuid: 00002adc-0000-1000-8000-00805f9b34fb
handle: 0x0014, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0015, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0016, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0017, uuid: 00002adb-0000-1000-8000-00805f9b34fb
handle: 0x0018, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0019, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x001a, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x001b, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x001c, uuid: 00002ade-0000-1000-8000-00805f9b34fb
handle: 0x001d, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x001e, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x001f, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0020, uuid: 00002add-0000-1000-8000-00805f9b34fb
handle: 0x0021, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0022, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0023, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0024, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0025, uuid: 00010203-0405-0607-0809-0a0b0c0d7fdf
handle: 0x0026, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0027, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0028, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0029, uuid: 00002a05-0000-1000-8000-00805f9b34fb
handle: 0x002a, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x002b, uuid: 00002902-0000-1000-8000-00805f9b34fb

I used this sylvania app to control it:
com.ledvance.smartplus

I enabled bluetooth debugging on my phone and them imported the log into wireshark
It uses bluetooth mesh which is not simple to reverse-engineer
Looks like all commands are sent over handle 0x0020
But the commands are variable length, I can’t spot any pattern, and replaying the commands using gatttool doesn’t work

Imgur

I don’t know enough about bluetooth mesh to take this much further

1 Like

From the nRF connect app, nothing too interesting, I can see the firmware version, and maybe some references to things like SigMesh and Telink, which seems to be an obscure proprietary BLE mesh protocol. There’s some information about it on Google but it seems to be mostly in Japanese

http://wiki.telink-semi.cn/wiki/protocols/Telink-Mesh/


1 Like

A bit more research on this bulb

It looks like it operates differently depending on whether it has the HomeBridge firmware (uses BLE) or the Google/Amazon firmware (uses Bluetooth Mesh)

From:

a) SMART+ Bluetooth lights in connection with the LEDVANCE SMART+ Bluetooth app, Amazon Alexa app or Google Assistant:

If SMART+ Bluetooth lights are operated with the LEDVANCE SMART+ Bluetooth app, the Amazon Alexa app or Google Assistant, they communicate with Bluetooth mesh. This means that any SMART+ Bluetooth product on the same network acts as a repeater and can therefore relay the signal to other SMART+ Bluetooth devices. This means that the range between the smartphone and the SMART+ light to be controlled can be significantly higher if there are other SMART+ Bluetooth products in between.

b) SMART+ Bluetooth lights in connection with Apple HomeKit:

If SMART+ Bluetooth lights are operated with the Apple Home App, they communicate with Bluetooth Low Energy. Here there is only direct communication between the smartphone and the SMART+ Bluetooth light. This means that only lights that are within direct range of the Bluetooth signal can be controlled.```
1 Like

I played a bit with one of these bulbs and here’s what I found so far:
On the Telink wiki page that @SomeGuyNamedBob mentioned, I found the TelinkBleMesh example app together with its source code in the Bluetooth SDK: http://wiki.telink-semi.cn/tools_and_sdk/BLE_Mesh/SIG_Mesh/sig_mesh_sdk.zip
With this app, I could successfully pair and control these bulbs. Apparently, the bulb follows the Bluetooth Mesh standard and can be provisioned with (almost) any Bluetooth Mesh stack.

From there I tried to provision it from the Linux Bluez stack. I used the latest 5.66 version and built it with --enable-mesh and --enable-deprecated.
Using meshctl, I could discover the device. Provisioning also worked when setting security 0 first. I could not control the light, however.

Using the (newer and non-deprecated) mesh-cfgclient, I had no luck provisioning. I believe the device supports only the PB-GATT bearer that meshctl is using for provisioning, but not PB-ADV, which seems to be the only one that mesh-cfgclient supports.
That’s all I found out so far. I tried to somehow copy the device information from meshctl to the mesh-cfgclient configuration, but so far without success. Maybe someone else has more luck or a better idea.

1 Like

Good news! I got the Ledvance Bluetooth bulbs integrated into Homeassistant on a Raspberry Pi with a modified version of GitHub - dominikberse/homeassistant-bluetooth-mesh: Allows to use bluetooth mesh devices directly from homeassistant.

Long story short, I had to switch back to the older BlueZ Version 5.55 from the Debian Bullseye package repository. I also had to make a few other small changes to make it work more reliably (e.g. lights did not work after restarting the Docker container). The working version with my changes is also on GitHub: GitHub - olipink/homeassistant-bluetooth-mesh: Allows to use bluetooth mesh devices directly from homeassistant

From there on, it was basically just following the steps in the setup instructions. I.e. clone repository, build and run the Docker container, docker compose exec <container_name> /bin/bash into the docker container, and then provision the devices:

  1. python3 gateway.py scan
  2. Create entry in the config.yaml.
  3. python3 gateway.py prov --uuid <uuid> add
  4. python3 gateway.py prov --uuid <uuid> config
  5. python3 gateway.py or restart the container

Further notes:

  • To make sure that the bulb runs the right firmware, I’d recommend to first pair it in the Ledvance Bluetooth app, then remove/reset it
  • Make sure you are using a recent Linux kernel version (check with uname -a). I am using the 6.10 kernel from the latest Raspberry Pi OS release. I did not get it to work with Kernel 5.10.
  • In some cases, provisioning failed with a bad-pdu message. This is returned for all sorts of different errors. In some cases, it helps to add --reload to the provision commands, e.g. python3 gateway.py --reload prov --uuid <uuid> add
  • Apart from BlueZ 5.55 from the package sources, I also tested versions 5.58 and 5.62 and got it to work. For 5.62, I had to add --reload to the provision commands.
  • If you are having trouble and want to rule out hardware or configuration issues, you might want to try provisioning with meshctl and/or mesh-cfgclient first. In case of the latter, you will have to build it from source. The version from the package repository will get you stuck with a “Failed to generate UUID array” error when trying to provision: BlueZ seems to be very picky about the device UUIDs, and the UUIDs of the Ledvance SMART+ bulbs are apparently not considered valid. Remove all occurrences of || !l_uuid_is_valid(uuid) from mesh-cfgclient.c and it will work.
2 Likes

you are a genius!!! I can confirm that your steps worked for me with the Sylvania Smart+ bulbs. Going to let it run for a few days to see how stable it is.

Only thing that’s not working is the color picker only allows to select the color temperature (cool to warm), not the full RGB spectrum

Hi @Homeowner
thank you for this solution. I bought two color light strips for my kids and would like to get them to work with home assistant and thus home kit too.

However, can you elaborate a little more on what to do? What uuid and password do I have to put in the docker config? How do I actually do this?

And one further question aside from installation how-to: Is the RGB going to work? I read that you are not intending to support this but it would be great if this is the key use case I am looking for (“hey Siri, turn my lights red”)

Thanks
Philip

You’ll get a list of UUIDs after running “python3 gateway.py scan

The lack of reliable RGB was also a dealbreaker for me. For now, I picked up a 3rd gen Amazon Echo for around $15 on marketplace, it has flawless support for these Ledvance/Sylvania Bluetooth Smart+ bulbs, including RGB, and it integrates with HomeAssistant:

  1. You’ll need an amazon account with 2FA (either use an existing one or create a new dummy one)
  2. Pair the bulbs to Echo (make sure the Echo is updated to the latest firmware otherwise the pairing process will keep failing)
  3. in HomeAssistant install HACS
  4. in HACS install “Alexa Media Player” and in the config ensure “Include devices connected via Echo” is checked

Could this also be done on HaOS and would this also work with (esphome) bluetooth proxy’s at all (without bluetooth on the HA server)? :thinking:

I have a load of these lights at home and they are terrible the app can only control one at a time. Maybe this is what I am looking for however I need some help with this please.

The config yaml is confusing because how do you create the data for the config file. I presume it comes from running python3 gateway.py scan but the guide runs that after the build.

If I try to run it I get this error…

opt/hass-ble-mesh/gateway# python3 gateway.py scan
DEBUG:asyncio:Using selector: EpollSelector
Traceback (most recent call last):
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 53, in _load
return StoredNodeSchema().loads(r)
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 756, in loads
return self.load(data, many=many, partial=partial, unknown=unknown)
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 722, in load
return self._do_load(
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 909, in _do_load
raise exc
marshmallow.exceptions.ValidationError: {‘token’: [‘Field may not be null.’]}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 271, in
main()
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 267, in main
loop.run_until_complete(app.run(args))
File “/usr/local/lib/python3.10/asyncio/base_events.py”, line 649, in run_until_complete
return future.result()
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 198, in run
self.token_ring.token = self._store.get(“token”)
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/application.py”, line 187, in token_ring
return self.TOKEN_RING(uuid=self.uuid)
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 44, in init
self.data = self._load()
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 55, in _load
return dict(token=int(r, 16), acl={}, network={})
ValueError: invalid literal for int() with base 16: ‘{“network”: {}, “acl”: {}, “token”: null}’
root@nas:/opt/hass-ble-mesh/gateway# python3 gateway.py --reload
DEBUG:asyncio:Using selector: EpollSelector
Traceback (most recent call last):
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 53, in _load
return StoredNodeSchema().loads(r)
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 756, in loads
return self.load(data, many=many, partial=partial, unknown=unknown)
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 722, in load
return self._do_load(
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 909, in _do_load
raise exc
marshmallow.exceptions.ValidationError: {‘token’: [‘Field may not be null.’]}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 271, in
main()
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 267, in main
loop.run_until_complete(app.run(args))
File “/usr/local/lib/python3.10/asyncio/base_events.py”, line 649, in run_until_complete
return future.result()
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 198, in run
self.token_ring.token = self._store.get(“token”)
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/application.py”, line 187, in token_ring
return self.TOKEN_RING(uuid=self.uuid)
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 44, in init
self.data = self._load()
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 55, in _load
return dict(token=int(r, 16), acl={}, network={})
ValueError: invalid literal for int() with base 16: ‘{“network”: {}, “acl”: {}, “token”: null}’
root@nas:/opt/hass-ble-mesh/gateway# python3 gateway.py scan
DEBUG:asyncio:Using selector: EpollSelector
Traceback (most recent call last):
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 53, in _load
return StoredNodeSchema().loads(r)
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 756, in loads
return self.load(data, many=many, partial=partial, unknown=unknown)
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 722, in load
return self._do_load(
File “/usr/local/lib/python3.10/site-packages/marshmallow/schema.py”, line 909, in _do_load
raise exc
marshmallow.exceptions.ValidationError: {‘token’: [‘Field may not be null.’]}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 271, in
main()
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 267, in main
loop.run_until_complete(app.run(args))
File “/usr/local/lib/python3.10/asyncio/base_events.py”, line 649, in run_until_complete
return future.result()
File “/opt/hass-ble-mesh/gateway/gateway.py”, line 198, in run
self.token_ring.token = self._store.get(“token”)
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/application.py”, line 187, in token_ring
return self.TOKEN_RING(uuid=self.uuid)
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 44, in init
self.data = self._load()
File “/usr/local/lib/python3.10/site-packages/bluetooth_mesh/tokenring.py”, line 55, in _load
return dict(token=int(r, 16), acl={}, network={})
ValueError: invalid literal for int() with base 16: ‘{“network”: {}, “acl”: {}, “token”: null}’

I set this up from scratch on a Raspi 4 with 64bit Bookworm (Homeassistant, Docker, Mosquitto already installed). Here’s a summary of the steps:

sudo systemctl stop bluetooth
sudo systemctl disable bluetooth
sudo systemctl mask bluetooth
cd ~
git clone https://github.com/olipink/homeassistant-bluetooth-mesh
cd homeassistant-bluetooth-mesh

→ create/modify docker/config.yaml with following content:

mqtt:
  broker: 192.168.1.123 # replace with your address
  # username: <username> 
  # password: <password>
  node_id: mqtt_mesh

Then

docker compose build
docker compose up -d
docker compose exec app /bin/bash
python3 gateway.py scan

Now you should get something like

INFO:root:Scanning for unprovisioned devices...
Found 1 node:
...

Now add one entry for each device to the config.yaml, e.g.:

mesh:
  living_room_light:
    uuid: <bluetooth_mesh_device_uuid>
    name: "Living Room Light"
    type: light
    relay: false  # or true, if you prefer 

@domrnet curiously, I got the same error message as you did at my first try. But after a reboot, it was gone and I could not reproduce it since. My guess is it had something to do with the bluetooth device still being locked.

@PhilSnider No, RGB is not supported, and since I do not own any Ledvance RGB device, I am not able to add support either. I also do not plan to put more effort into these lights: Link quality has been an issue for me all the time, and a couple days ago, the first out of 4 lights went out. So I give them a few more months until all of them have to be replaced.

Since I also own some of these bluetooth bulbs and the solution from Homeowner has not worked for me, I digged into the ESP BLE MESH framework and finally managed to get a working version running on my ESP32.
The ESP32 is acting.as a BLE MESH client and communicates to Home Assistant via MQTT.
It is by no means perfect but so far it works fine enough for me.
If anybody is interested, I put my code with some instructions on GitHub.

3 Likes