Hey I wanted to share my ESPhome configuration for floodlight.
To begin with previously I was not able to find any floodlight that is sealable after playing around with its guts but now I have found one. It is the Brennenstuhl WF2050P, and it requires removing 4 rubbber cover and 4 screws from top and you are good to go (but You do not have to if you manage to “cloud cut” it) with ESPhome (since libreTiny branch was merged).
This one is not cheapest one but …
Anyway next problem was to template chip. I believe there is space for improvement, so feel free to adjust my code.
My aim was to provide same capabilities as regular app assuming it should be still functional without connection to HA … and I have added few switches to ease adjusting for You use-case.
So: Action mode: self explanatory Action mode fallback: time after which manual mode will switch to auto - You probably will forget abut that after party . Ambient light threshold: level of ADC input used by ambient sensor to determine light conditions - you can tweak voltage levels on code level Luminance: RAW value of ADC voltage corresponding to current light conditions - i do not know which sensor is used so i did not bother to convert it to lux since it would require me to guess. Duration after movement: how long led will be on after detecting movement - during being on if PIR sensor will be triggered duration time will reset to this value. Motion delayed PIR: this is variable responsible directly for switching light Motion sensor: this is sensor connected directly to Your PIR - You can use it to adjust PIR sensivity PIR sensitivity: this is PWM output that determines how sensitive PIR is - you can tweak voltage levels on code level Set Automatic manual mode: if this is on it will switch manual mode if you manually enable light without PIR being True Set PIR based fallback to auto mode: if this is True it light will switch it mode from manual to auto if PIR is triggered Set Time based fallback to auto mode: if this is True It will automatically switch to auto mode after being in manual mode for time stated in Action mode fallback, this option is set in code to default as it will be probably most commonly used.
WF2050P Floodlight - light itself WF2050P WiFi Signal Sensor - I left this because i may have to add external antenna at one point.
If you want to you can dig into code I have added ## adjust.. comment in potentially every place that regular users may be interested.
Probably you will want to turn off loggers.
It should be easy adapting this to any other tuya light only differences probably will be light type and PWM output for PIR adjustment.
Edit:
If You are all new to this my post is explaining how to handle #placeyours marked values. Also it contains guide on how to flash it by wire but instead of using ESPhome web flasher refer to next point.
Also as @amphibitus pointed out in his post to be able to flash esphome for the first time by wire, you will have to use Itchiptool.
esphome:
name: brennenstuhl-floodlight-wf2050p
friendly_name: Brennenstuhl Floodlight WF2050P
bk72xx:
board: wb3s
framework:
version: latest
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: #placeyours
ota:
password: #placeyours
web_server:
port: 80
version: 2
include_internal: true
ota: true
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot in case wifi connection fails
ap:
ssid: "Brennenstuhl-Floodlight-Wf2050P"
password: "6OcBkZ0R8NqH"
globals:
- id: ambientmapper
type: float
restore_value: yes
initial_value: "1.8" ## adjust default fallback time should be same as initial selector
- id: autofallbackglob
type: int
restore_value: yes
initial_value: "3600" ## adjust default fallback time to automode
- id: leddurationglob
type: int
restore_value: yes
initial_value: "60" ## adjust default led duration in automode
button:
- platform: restart
name: "WF2050P restart"
number:
- platform: template
name: Action mode fallback
id: autofallback
unit_of_measurement: s
min_value: 0
max_value: 86400
step: 1
icon: "mdi:timer-refresh-outline"
optimistic: true
restore_value: true
on_value:
then:
- globals.set:
id: autofallbackglob
value: !lambda 'return x;'
- platform: template
name: Duration after movement
id: ledduration
unit_of_measurement: s
icon: "mdi:timer-play-outline"
min_value: 0
max_value: 3600
step: 1
restore_value: true
optimistic: true
on_value:
then:
- globals.set:
id: leddurationglob
value: !lambda 'return x;'
output:
- platform: libretiny_pwm
id: lightbri
pin: P8
frequency: 1000 Hz
- platform: libretiny_pwm
id: lightct
pin: P9
frequency: 1000 Hz
inverted: true
- platform: libretiny_pwm
id: PIRsen
frequency: 1000 Hz
pin: P26
select:
- platform: template
name: PIR sensitivity
id: PIRsenMode
options:
- "Far"
- "Medium"
- "Close"
initial_option: "Medium"
optimistic: true
icon: "mdi:signal-distance-variant"
restore_value: True
## adjust below values of PIR sensitivity
on_value:
then:
- lambda: |-
if (id(PIRsenMode).state == "Far") {
id(PIRsen).set_level(0.00);
} else if (id(PIRsenMode).state == "Medium") {
id(PIRsen).set_level(0.50);
} else if (id(PIRsenMode).state == "Close") {
id(PIRsen).set_level(1.00);
}
- platform: template
name: Ambient light threshold
id: ambientLight
options:
- "Pitch Black"
- "Semi Dark"
- "Moderate"
- "Semi Bright"
- "Day"
initial_option: "Moderate"
optimistic: true
icon: "mdi:theme-light-dark"
restore_value: True
## adjust below values ambient light trheshold
on_value:
then:
- if:
condition:
lambda: 'return id(ambientLight).state == "Pitch Black";'
then:
- globals.set:
id: ambientmapper
value: '3.6'
- logger.log:
format: "Ambient value set to %.2f"
args: [ 'id(ambientmapper)']
- if:
condition:
lambda: 'return id(ambientLight).state == "Semi Dark";'
then:
- globals.set:
id: ambientmapper
value: '2.7'
- logger.log:
format: "Ambient value set to %.2f"
args: [ 'id(ambientmapper)']
- if:
condition:
lambda: 'return id(ambientLight).state == "Moderate";'
then:
- globals.set:
id: ambientmapper
value: '1.8'
- logger.log:
format: "Ambient value set to %.2f"
args: [ 'id(ambientmapper)']
- if:
condition:
lambda: 'return id(ambientLight).state == "Semi Bright";'
then:
- globals.set:
id: ambientmapper
value: '0.9'
- logger.log:
format: "Ambient value set to %.2f"
args: [ 'id(ambientmapper)']
- if:
condition:
lambda: 'return id(ambientLight).state == "Day";'
then:
- globals.set:
id: ambientmapper
value: '0.01'
- logger.log:
format: "Ambient value set to %.2f"
args: [ 'id(ambientmapper)']
- platform: template
name: Action mode
id: actionmode
options:
- "manual"
- "auto"
initial_option: "auto"
optimistic: true
restore_value: True
on_value:
then:
- if:
condition:
lambda: |-
if ( id(actionmode).state == "manual" & id(timeautofallback).state ) {
return true;
} else {
return false;
}
then:
- logger.log:
format: "Manual mode set, will get into auto mode after %i s"
args: [ 'id(autofallbackglob)']
- delay: !lambda 'return id(autofallbackglob) * 1000;' # how long it will take befoore falling back to auto mode works only from HA
- select.set:
id: actionmode
option: "auto"
- logger.log:
format: "Autmoaticaly got back to auto mode after time set"
sensor:
- platform: adc
id: luval
pin: ADC3
name: "Luminance"
update_interval: 10s
internal: true
accuracy_decimals: 2
- platform: wifi_signal
name: "WF2050P WiFi Signal Sensor"
update_interval: 60s
icon: "md:signal-variant"
binary_sensor:
- platform: gpio
name: Motion sensor
pin: P6
internal: True
id: motionsensor
on_press:
then:
- if:
condition:
lambda: |-
if ( id(pirautofallback).state & id(actionmode).state == "manual") {
return true;
} else {
return false;
}
then:
- logger.log:
format: "Automatically switched back to autom mode according to setting"
- select.set:
id: actionmode
option: "auto"
- platform: template
internal: true
name: Motion delayed PIR
id: motiondelayed
lambda: |-
return id(motionsensor).state;
filters:
- delayed_off: !lambda 'return id(leddurationglob)*1000;' # Sensor goes to OFF state when this time has passed after last true ON
on_press:
then:
- if:
condition:
lambda: |-
if (id(actionmode).state == "auto" & id(ambientmapper) <= id(luval).state) {
return true;
} else {
return false;
}
then:
- light.turn_on:
id: wf2050p
- logger.log:
format: "AmbientLightThreshold %.2f was lower than current ADC illumination %.2f"
args: [ 'id(ambientmapper)', 'id(luval).state']
else:
- logger.log:
format: "AmbientLightThreshold %.2f was higher than current ADC illumination %.2f "
args: [ 'id(ambientmapper)', 'id(luval).state']
on_release:
then:
- light.turn_off:
id: wf2050p
light:
- platform: color_temperature
name: "WF2050P"
icon: "mdi:light-flood-down"
id: wf2050p
color_temperature: lightct
brightness: lightbri
cold_white_color_temperature: 6500 K
warm_white_color_temperature: 3000 K
## Comment below section if You want to use Light with outside automations.
on_turn_on:
then:
- if:
condition:
lambda: |-
if (id(actionmode).state == "auto" & not id(motionsensor).state & id(automanual).state ) {
return true;
} else {
return false;
}
then:
- select.set:
id: actionmode
option: "manual"
- logger.log:
format: "Switched to manual mode since PIR was not active during enablling LED"
switch:
# Chooser time based fallback to auto mode
- platform: template
name: "Set Time based fallback to auto mode"
id: timeautofallback
optimistic: true
restore_mode: RESTORE_DEFAULT_ON # adjust default state
# Chooser PIR based fallback to auto mode
- platform: template
name: "Set PIR based fallback to auto mode"
optimistic: true
id: pirautofallback
# restore_mode: RESTORE_DEFAULT_ON # adjust default state
# Chooser Automatic manual mode
- platform: template
name: "Set Automatic manual mode"
optimistic: true
id: automanual
# restore_mode: RESTORE_DEFAULT_ON ## adjust default state
connect it to programmer (leave CEN wire loose for now);
I find it rare but for me to work I had to supply other power source (that provided by programmer was not enough) 3V3.
to enable programming you will have to short CEN wire to GND while you click connect in Your browser;
de-solder put it back together;
Note: if you are worried about losing warranty by soldering use BDM/pogo probes (be advised this is really failure prone solution), and swapping FW probably voids warranty anyway.
But the software part doesn’t work for me. After hours of experience I tried “ltchiptool”. And now it was easy! I converted four spotlights and the last one only took me five minutes to fully install.
Here the Way
→ Manual Download
→ UF2 package
Download the ltchiptool here:
Start the Program Select your Com and the “UF2” File and klick to start
I still had a suitable plug for 3V and GND lying around, so I only needed to operate TX and RX. I managed the bridge connection with a loose cable (or press the Resetbutton on back).
So I was right about me not mentioning something caused by taking different path.
I should have figured out it will require using the ltchiptool since I have used it to flash different BK chip on another project.
I am happy that you have managed to make it work and that my trial and error path was useful for someone else.
If You will find any need for code change feel free to point it out.
I will refer to your post in OP.
Thanks for posting about this conversion.
I ordered the same floodlight but I really want to try the cloud cut approach when it arrives since my soldiering skills are subpar.
I’d also like to say thanks for this setup. These floodlights aren’t sold here in Australia but I got one from Amazon UK, and flashed it serially with no dramas. It’s working just fine and I’m pleased with the PIR performance - seems adequately sensitive but less prone to false triggering than some I’ve tried before.
I am happy to hear that !
Lately I have discovered that after upgrading ESPhome Duration after movement falls back to 0. Did not have time to debug this.
Short update on my cloudcutter approach
I managed to use cloud cutter with the ume-motion-security-light profile.
It showed a kickstarter UI afterwards.
This only allowed me to set my WLAN and do an OTA upate. I needed multiple tries to upload an ota image to get to more or less blank esp home ui.
I flashed it again and now I have a UI that shows this:
Well it has been some time and there are new versions of Brennenstuhl Floodlights. Just done testing with WFD3051P and it seem like only this
`
bk72xx:
board: cb3s
I found these WS2811 Flood lights that come with no problematical controller that needs modified or flashed. It has no controller so that you can choose the controller you want. This one is an RBGW but, they make White only flood lights too.
I have just bought the WF2050p but unfortunately the UME cloudcutter profile does not work.
The device core FW version is 1.0.14. The CPU is 7231t.
Anyone any luck with such devices recently ?
[!] The binary supplied appears to be patched and no longer vulnerable to the tuya-cloudcutter exploit.
output from ltchiptool:
I: UPK: - color brightness: pin P7, inverted False
I: UPK: - color temperature: pin P8, inverted False
Seems that the pins have also changed.
WiFi Module model is cb3s