Home Assistant custom integration for Beurer daylight therapy lamps via Bluetooth Low Energy (BLE).
I noticed that most integrations were fragile. After fiddling for some time I found out that one of the main issues is that the integrations were not reviewed for new developments in Home assistant itself. In addition to that, it bugged me, that no integration had the timer feature like the Beurer LightUp App so it was not possible to integrate it into automations with the already built-in device functions. I managed to sniff BLE traffic between the Beurer LightUp app and the TL100 and let AI sift through it (I was way too lazy to use wireshark). So now I got it working. As far as I can say, it's way more stable than the successors I have forked.
I heavily used claude as I did in other projects but focused on keeping it tight and close to Home Assitant standards and guidelines and general coding guidelines. It may still contain bad code, so feel free to review and submit issues or PRs.
| Model | Status | Notes |
|---|---|---|
| TL100 | ✅ Tested | Full support |
| TL50 | Should work | |
| TL70 | Should work | |
| TL80 | Should work | |
| TL90 | Should work | |
| WL75 | Wake-up Light (same protocol family as WL90) | |
| WL90 | Wake-up Light with Radio, Speaker, Alarms |
- 💡 On/off and brightness control
- 🎨 RGB color mode with color picker
- 🌡️ Color temperature (2700K - 6500K)
- ✨ Light effects (Rainbow, Pulse, Forest, Wave, etc.)
- 🔆 Separate white/color brightness sliders
- 📡 Bluetooth auto-discovery
- 🔄 ESPHome/Shelly Bluetooth Proxy support
- 📶 Automatic adapter switching to best signal
- 🔗 Connection status monitoring
Important: These features are for personal lifestyle tracking and wellness purposes only. This integration is NOT a medical device and should not be used for medical purposes.
- Sunrise/Sunset Simulation: Native integration layer simulation with gradual brightness and color temperature changes
- Light Exposure Tracking: Track daily and weekly bright light exposure minutes
- Daily Goal Progress: Configurable daily light exposure goal with progress sensor
- Goal Reached Notification: Binary sensor for automation triggers when daily goal is met
| Entity Type | Name | Description |
|---|---|---|
| Light | Beurer Lamp | Main light entity with all controls |
| Button | Identify | Blinks lamp 3x to find it |
| Button | Reconnect | Forces BLE reconnection |
| Button | Sync time | Syncs HA clock to device |
| Select | Effect | Dropdown for light effects |
| Number | White brightness | Slider 0-100% |
| Number | Color brightness | Slider 0-100% |
| Number | Timer | Auto-off timer 0-120 min (0 = off, works in both modes) |
| Number | Daily light goal | Configurable daily exposure goal (5-120 min) |
| Sensor | Signal strength | RSSI in dBm (disabled by default) |
| Sensor | Light exposure today | Minutes of bright light today |
| Sensor | Light exposure this week | Minutes of bright light this week |
| Sensor | Daily goal progress | Percentage of daily goal completed |
| Binary Sensor | Connected | BLE connection status |
| Binary Sensor | Bluetooth reachable | Device seen by any adapter |
| Binary Sensor | Daily goal reached | True when daily exposure goal is met |
| Switch | Feedback sound | Enable/disable device beep on button press |
| Switch | Fade | Enable/disable smooth brightness transitions |
| Switch | Adaptive Lighting | Allow/block Adaptive Lighting (HACS) control |
| Sensor | Reconnect count | Total BLE reconnections since startup (diagnostic, disabled) |
| Sensor | Command success rate | Percentage of successful BLE commands (diagnostic, disabled) |
| Sensor | Connection uptime | Seconds since current connection established (diagnostic, disabled) |
| Entity Type | Name | Description |
|---|---|---|
| Media Player | FM Radio | Radio with on/off, volume, seek, presets |
| Media Player | Bluetooth Speaker | BT speaker with on/off, volume |
| Number | Radio volume | Radio volume slider 0-10 |
| Number | Speaker volume | Speaker volume slider 0-10 |
- Timer: Works in both White and RGB mode. Set to 0 to disable. Note: Timer is automatically cancelled when switching modes.
- Signal Strength: Disabled by default. RSSI values: -30 to -50 dBm = excellent, -50 to -70 = good, < -80 = poor
Apply predefined lighting presets:
| Preset | Description |
|---|---|
daylight_therapy |
Full brightness 5300K for therapy |
relax |
Warm dim light (2700K, 40%) |
focus |
Cool bright light (5000K, 90%) |
reading |
Neutral white (4000K, 80%) |
warm_cozy |
Very warm (2700K, 60%) |
cool_bright |
Cool white full brightness |
sunset |
Orange sunset simulation |
night_light |
Very dim warm light |
energize |
Bright cool light to wake up |
Example usage:
service: beurer_daylight_lamps.apply_preset
target:
entity_id: light.beurer_tl100
data:
preset: daylight_therapySet an auto-off timer (1-120 minutes). The lamp will turn off automatically after the specified time. Works in both White and RGB mode.
service: beurer_daylight_lamps.set_timer
target:
entity_id: light.beurer_tl100
data:
minutes: 30Start a sunrise simulation with gradual brightness and color temperature increase.
Lifestyle Feature: This is a personal wellness feature, not a medical device.
service: beurer_daylight_lamps.start_sunrise
target:
entity_id: light.beurer_tl100
data:
duration: 15 # minutes (1-60)
profile: natural # gentle, natural, energize, or therapyProfiles:
| Profile | Description |
|---|---|
gentle |
Slow, soft transition for sensitive users |
natural |
Mimics natural sunrise timing |
energize |
Faster transition with brighter end point |
therapy |
Optimized for bright light exposure |
Start a sunset simulation with gradual brightness decrease and warm color shift.
service: beurer_daylight_lamps.start_sunset
target:
entity_id: light.beurer_tl100
data:
duration: 30 # minutes (1-60)
end_brightness: 0 # 0-100%, 0 = turn off at endStop any running sunrise or sunset simulation.
service: beurer_daylight_lamps.stop_simulation
target:
entity_id: light.beurer_tl100Configure one of 3 alarm slots with sunrise simulation.
service: beurer_daylight_lamps.set_alarm
target:
entity_id: light.beurer_wl90
data:
slot: 0 # Alarm slot 0, 1, or 2
enabled: true
hour: 7
minute: 30
days: "Mon,Tue,Wed,Thu,Fri"
tone: 2 # 0=Buzzer, 1=Radio, 2-11=Melody 1-10
volume: 5
snooze: 10 # 1, 2, 5, 10, 20, or 30 minutes
sunrise_enabled: true
sunrise_time: 20 # Start 20 min before alarm
sunrise_brightness: 50| Component | Minimum version | Notes |
|---|---|---|
| Home Assistant Core | 2025.12.0 | Required for modern Bluetooth + coordinator APIs and Python 3.13.2. Users on older HA should stay on v1.33.0. |
| Python | 3.13 | HA Core 2025.2+ requires Python 3.13. |
| Bluetooth | HA Bluetooth integration | Built-in BLE adapter, ESPHome BT proxy, or Shelly BT proxy. |
Upgrading from < 1.34.0? Make sure your Home Assistant Core is on 2025.12.0 or newer before installing this version. HACS will hide the update on older HA installs. Users still on HA ≤ 2025.11 can continue to use v1.33.0.
Note: Restart Home Assistant after installation.
- Open HACS in Home Assistant
- Go to "Integrations"
- Search for "Beurer Daylight Lamps"
- Click "Download" and install
git clone https://github.com/moag1000/beurer_daylight_lamps
cd beurer_daylight_lamps
cp -r custom_components/beurer_daylight_lamps ~/.homeassistant/custom_components/- Go to Settings → Devices & Services
- Find the Beurer Daylight Lamps integration
- Click the three dots menu → Delete
- Restart Home Assistant
- (Optional) Remove the integration folder from
custom_components/
- Turn on your Beurer lamp
- Home Assistant will automatically detect the lamp via Bluetooth
- A notification will appear - click "Configure"
- The lamp will blink to confirm connection
- Click "Submit" to complete setup
- Go to Settings → Devices & Services → Add Integration
- Search for "Beurer Daylight Lamps"
- Select your lamp from the list or enter MAC address manually
- The lamp will blink to confirm - click "Yes" if it blinked
This integration fully supports ESPHome and Shelly Bluetooth Proxies:
- Automatically uses the proxy with the best signal
- Seamlessly switches between adapters as signal changes
- No configuration needed - just set up your proxies in Home Assistant
⚠️ Critical: The Beurer TL100 does not support BLE 5.0 PHY negotiation. Standard ESP32 Bluetooth Proxy configurations will fail with error0x3e(BLE_HCI_CONN_FAIL_ESTABLISH).
| ESP32 Variant | Works? | Notes |
|---|---|---|
| ESP32-S3 | ✅ Yes | Recommended - Dual-core Xtensa, best WiFi/BLE coexistence |
| ESP32-WROOM-32 | ✅ Yes | Dual-core Xtensa, works with BLE 5.0 fix |
| ESP32-C3 | ❌ No | Single-core RISC-V, WiFi/BLE conflicts |
| ESP32-C6 | ❌ No | Single-core RISC-V, same issues as C3 |
Why C3/C6 don't work: Single-core RISC-V chips cannot handle WiFi and BLE simultaneously when the BLE connection requires frequent packet exchanges (like the TL100 does).
You must disable BLE 5.0 features in your ESPHome configuration:
esp32:
board: esp32-s3-devkitc-1
variant: esp32s3
framework:
type: esp-idf
version: recommended
sdkconfig_options:
# CRITICAL: Disable BLE 5.0 - TL100 doesn't support PHY negotiation
CONFIG_BT_BLE_50_FEATURES_SUPPORTED: n
CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y
# WiFi/BLE Coexistence
CONFIG_SW_COEXIST_ENABLE: y
CONFIG_SW_COEXIST_PREFERENCE_BT: y# ESP32-S3 Bluetooth Proxy for Beurer Daylight Lamps
# BLE 5.0 disabled - TL100 requires BLE 4.2 only
esphome:
name: btproxy-beurer
friendly_name: BT Proxy Beurer
esp32:
board: esp32-s3-devkitc-1
variant: esp32s3
framework:
type: esp-idf
version: recommended
sdkconfig_options:
# CRITICAL: Disable BLE 5.0 for Beurer TL100 compatibility
CONFIG_BT_BLE_50_FEATURES_SUPPORTED: n
CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y
# WiFi/BLE Coexistence (Dual-Core)
CONFIG_SW_COEXIST_ENABLE: y
CONFIG_SW_COEXIST_PREFERENCE_BT: y
# BLE Connection Parameters
CONFIG_BT_ACL_CONNECTIONS: "3"
CONFIG_BT_GATT_MAX_SR_PROFILES: "8"
# Dual-Core: Pin BT to Core 0
CONFIG_BT_BLUEDROID_PINNED_TO_CORE: "0"
logger:
level: DEBUG
api:
encryption:
key: !secret api_encryption_key
ota:
- platform: esphome
password: !secret ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
power_save_mode: none
ap:
ssid: "BT-Proxy-Fallback"
password: !secret fallback_password
captive_portal:
esp32_ble:
esp32_ble_tracker:
scan_parameters:
interval: 60ms
window: 30ms
active: true
continuous: true
bluetooth_proxy:
active: true
cache_services: falseNote: Create a secrets.yaml file with your credentials:
wifi_ssid: "YourWiFiNetwork"
wifi_password: "YourWiFiPassword"
api_encryption_key: "your-32-byte-base64-key"
ota_password: "your-ota-password"
fallback_password: "fallback-ap-password"| Problem | Solution |
|---|---|
Error 0x3e on connect |
Missing CONFIG_BT_BLE_50_FEATURES_SUPPORTED: n |
| Connection drops with C3/C6 | Switch to ESP32-S3 or WROOM-32 |
| Slow response | Enable CONFIG_SW_COEXIST_PREFERENCE_BT: y |
| Device not found | Increase scan_parameters.window to 50ms |
The following effects are available (matching the Beurer LightUp app):
| Effect | Description |
|---|---|
| Off | No effect |
| Random | Random color changes |
| Rainbow | Smooth rainbow cycle |
| Rainbow Slow | Slower rainbow cycle |
| Fusion | Color fusion effect |
| Pulse | Pulsing brightness |
| Wave | Wave-like transitions |
| Chill | Relaxing color changes |
| Action | Dynamic color changes |
| Forest | Green/nature tones |
| Summer | Warm summer colors |
Three ready-to-use blueprints for common lighting scenarios. Click the badge to import directly into Home Assistant!
Wake up naturally with a sunrise simulation followed by bright light therapy.
- Gradual warm-to-cool transition (2700K -> 5300K)
- Configurable sunrise duration (0-30 min)
- Therapy session at full brightness (10-60 min)
- Schedule: Workdays, weekends, or every day
- End behavior: Off, stay on, or switch to reading light
Prepare for sleep by gradually dimming to warm light.
- Triggers at sunset or fixed time
- Gradual dimming over 15-120 minutes
- Warm light only (2700K) to avoid blue light
- Configurable start and end brightness
Optimize your work environment with alerting cool light.
- Cool, alerting light (4000K-6500K configurable)
- Optional Pomodoro-style break reminders
- Work sessions from 15-120 minutes
- End with relaxing light or turn off
Alternatively, copy the blueprint files manually:
- Download the YAML files from
blueprints/automation/beurer_daylight_lamps/ - Copy to
config/blueprints/automation/beurer_daylight_lamps/in your Home Assistant - Restart Home Assistant or reload automations
automation:
- alias: "Wake-up light"
trigger:
- platform: time
at: "06:30:00"
condition:
- condition: workday
country: DE
action:
- service: beurer_daylight_lamps.apply_preset
target:
entity_id: light.beurer_tl100
data:
preset: energizeautomation:
- alias: "Gradual wake-up light"
trigger:
- platform: time
at: "06:30:00"
action:
- service: light.turn_on
target:
entity_id: light.beurer_tl100
data:
color_temp_kelvin: 2700
brightness: 25
- delay: "00:05:00"
- service: light.turn_on
target:
entity_id: light.beurer_tl100
data:
color_temp_kelvin: 4000
brightness: 128
- delay: "00:05:00"
- service: light.turn_on
target:
entity_id: light.beurer_tl100
data:
color_temp_kelvin: 5300
brightness: 255automation:
- alias: "Evening mood light"
trigger:
- platform: sun
event: sunset
action:
- service: beurer_daylight_lamps.apply_preset
target:
entity_id: light.beurer_tl100
data:
preset: sunsetautomation:
- alias: "Morning light therapy"
trigger:
- platform: time
at: "07:00:00"
action:
- service: beurer_daylight_lamps.apply_preset
target:
entity_id: light.beurer_tl100
data:
preset: daylight_therapy
- delay: "00:30:00"
- service: light.turn_off
target:
entity_id: light.beurer_tl100This integration uses Bluetooth Low Energy (BLE) for communication:
- State Updates: The lamp sends BLE notifications when its state changes. These are processed in real-time.
- RSSI Updates: Signal strength is updated whenever the lamp sends a Bluetooth advertisement (typically every few seconds).
- Adaptive Polling: Periodic refresh ensures state consistency with intervals that adapt to device state:
- 30 seconds when light is on (responsive updates)
- 5 minutes when light is off (save resources)
- 15 minutes when device unavailable (minimal polling)
- Command Timing: Commands are rate-limited to 100ms minimum between sends to prevent overwhelming the device.
- Mode Changes: Mode switches (white <-> RGB) include a 500ms delay to allow the hardware to stabilize.
| Operation | Typical Latency |
|---|---|
| On/Off | 100-300ms |
| Brightness change | 100-200ms |
| Color change | 150-300ms |
| Effect change | 200-500ms |
| Status update | Real-time (push) |
Note: These are design constraints, not bugs.
-
Timer cancels on mode switch: The auto-off timer works in both White and RGB mode, but is automatically cancelled when switching between modes. This is hardware behavior.
-
Bluetooth LED always on: The small Bluetooth indicator LED on the lamp stays illuminated while connected to Home Assistant. This cannot be disabled.
-
Single connection: The lamp can only maintain one BLE connection at a time. You cannot use the Beurer LightUp app while connected to Home Assistant.
-
Connection after reboot: Connection may fail a few times after Home Assistant reboots while the Bluetooth stack initializes. The integration will auto-reconnect.
-
Light exposure tracking resets daily: The therapy/exposure tracking resets at midnight. Historical data beyond the current week is not retained.
-
Simulation requires connection: Sunrise/sunset simulations require an active BLE connection. If the connection drops, the simulation will pause and resume when reconnected.
-
Color temperature approximation: Color temperatures are approximated using RGB values since the lamp doesn't have a native CT mode. Results may vary slightly from true Kelvin values.
-
White brightness capped at 99%: Some device firmware versions switch to red/RGB mode when white brightness is set to exactly 100%. The integration caps white brightness at 99% to work around this firmware bug. The visual difference is imperceptible.
To download diagnostic information for troubleshooting:
- Go to Settings → Devices & Services
- Click on the Beurer Daylight Lamps integration
- Click the three dots menu → Download diagnostics
The diagnostic file contains device state, connection info, and configuration (MAC address is redacted).
- Ensure the lamp is powered on and not connected to another device (e.g., Beurer LightUp app)
- Check that your Home Assistant host has Bluetooth enabled
- Move the lamp closer to your Home Assistant host (within 10 meters)
- Try restarting the lamp by unplugging and plugging it back in
- Check Settings → System → Repairs for any connection issues
- Check the signal strength sensor (enable it under the device's disabled entities)
- If RSSI is below -80 dBm, move the lamp closer or use a Bluetooth adapter with better range
- Ensure no other devices are interfering with Bluetooth (e.g., USB 3.0 devices near the adapter)
- Recommended: Use an ESPHome Bluetooth Proxy for better range and reliability
- The integration limits commands to prevent overwhelming the BLE device
- Multiple rapid commands may be queued (100ms minimum between commands)
- This is normal behavior to ensure reliable communication
- The lamp may have lost Bluetooth connection
- Check Settings → System → Repairs for repair issues
- Try using the "Reconnect" button entity
- Try turning the lamp off and on again
- The integration will automatically try to reconnect
- Some effects only work at specific brightness levels
- Try setting brightness to 100% first, then apply the effect
- The "Off" effect disables all effects and returns to static color
Enable debug logging in configuration.yaml:
logger:
default: warn
logs:
custom_components.beurer_daylight_lamps: debugFor detailed debugging and reverse engineering information, see CONTRIBUTING.md.
For developers interested in the BLE protocol or contributing new features, see:
- docs/PROTOCOL.md - BLE protocol documentation
- CONTRIBUTING.md - Development and reverse engineering guide
Based on work by:
This project is licensed under the MIT License.