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