Brennenstuhl Floodlight WF2050P PIR and ambient light sensor - others?

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:

  1. 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.

  2. 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 
2 Likes

Hi, Great project, but can you explain to us how you flashed the WBs3 or share a suitable link

Ok. Hope You don`t mind if I will write something obvious for You.

  1. I have not checked if it can be done in any wireless way.
  2. It is not that hard if you have basic soldering skills and You have flashed anything by wire. You can follow these steps:
    Preparing firmware:
    • create new project in ESPHome dashboard;
    • copy yaml content to notepad;
    • paste my code;
    • mind swapping values marked #placeyours whit these generated by ESP home dashboard that You have just placed in notepad;
  • click install and choose by wire;
  • at this point ESP will recognize that it will not be compiling FW for regular ESP board so it will have slightly different menu than usually.
  • use https://web.esphome.io/ ltchiptool to install generated file.

I may have not mention something since my path was different - I have initially installed OpenBeken and then migrated wireless to ESPhome.

Mechanical part:

  • remove back mount plate;
  • release white connector with L and N terminals;
  • remove rubber screw covers;
  • unscrew all of them (total of 4);
  • open case (pay attention to rubber sealing);
  • pulling of white connector enables you to put apart top and bottom part a little further;
  • pull two white JST connectors visible on next photo;
  • solder pins as shown in photo (remember to cross TX and RX wires) i have used numbering from datasheet (“Pin No.”).
  • 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.

Feel free to ask questions, but here are few helpful links:
WB3S Module Datasheet
ESPhome LibreTiny Platform

The hardware part works perfectly!

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

grafik

→ Manual Download

grafik

→ UF2 package

Download the ltchiptool here:

grafik

Start the Program Select your Com and the “UF2” File and klick to start

Don’t forget the bridge CEN to GND after start

And here is my Hardware.

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).

Thanks, for your work!

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.

1 Like

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.

1 Like

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:


There are still some problems:

  • I can only activate the light via the ON switch
  • It still does not show up on my esp home page in home assistant

I’ll keep on investigating.

1 Like

It works :smiley:

I renamed the name to floodlight and flashed it again. It now shows up and after fiddeling with the settings it works.

Many thanks to @Kosy for the initial posting

1 Like

I have a WFD3050P Brennenstuhl Connect WiFi LED Duo floodlight and can confirm that the it works with the cloudcutter approach (I followed this tutorial: UPDATED How To Guide - Tuya CloudCutter with ESPHome LibreTiny - No soldering | digiblurDIY ) and used the ESPHome config at the top.

I can also confirm that it works with Cloudflatter. I followed the guide provided by @Mikael and the ESPHome code from @Kosy!

Many thanks to @Kosy!

One more question:
Is there a way to display sensor status in Home Assistant for other automations?

Sensor → Movement - no movement
You can see this in the web interface.

Just set this

binary_sensor:
  - platform: gpio
    name: Motion sensor
    pin: P6
    internal: True

To False

It works! Thank you!

Thanks guys for the great guide, worked for my 3 lights.
Any idea how to implement or configure the warm / cold light setting?

Used my lights before with original software where the warm/cold setting was working.

Best,
Arek

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


output:

  • platform: libretiny_pwm
    id: lightbri
    pin: P7
    frequency: 1000 Hz

  • platform: libretiny_pwm
    id: lightct
    pin: P8
    frequency: 1000 Hz
    inverted: true`

should be adjusted. Will report if I am not right, after fixing it to wall and do some testing at night.

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 ?

I have opened the device, downloaded FW and analyzed it. It seems that the FW is patched and cloudcutter cannot be used anymore:

[+] Searching for known exploit patterns

[!] The binary supplied appears to be patched and no longer vulnerable to the tuya-cloudcutter exploit.

[+] uuid: 1b5a830298f34ed6
[+] auth_key: M6tvmVupDXvKI9cFc2g5Sc8A0zyotNiM
[+] ap_ssid: SmartLife
[+] factory pin: htztgarmoax7cn4l
[+] storage swv: 1.0.14
[+] storage dev_swv: 1.0.12
[+] storage bv: 40.00
[+] firmware key: keyvkfcucn7xnenx
[+] product key: keyvkfcucn7xnenx
[+] SDK Version: 2.3.3
[+] SDK String: < TUYA IOT SDK V:2.3.3 BS:40.00_PT:2.3_LAN:3.5_CAD:1.0.5_CD:1.0.0 >
[+] SDK Build At: BUILD AT:2025_01_06_16_54_08 BY ci_manage FOR ty_iot_sdk AT bk7231n >
[+] Device class: oem_bk7231n_light_pir_ty
[+] Schema already present

[!] 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

I have downloaded the ESPHome FW via programmer, and it works great. Thank you @Kosy for initial work and sharing your ideas

My ESPHome config is below, updated to latest ESPHome state, cleaned up, removed warnings, etc.

Functional changes:

  1. Added LED blink at boot to show if the device is alive
  2. Removed Set Time to auto mode - the same functionality is kept when the Auto Timer is set to 0
  3. Made Motion delayed PIR to turn on only when the lighting condition is met. This is IMHO more logical
esphome:
  name: place-yours
  friendly_name: place-yours
  comment: Brennenstuhl Floodlight WF2050P 
  on_boot:
    priority: 600
    then:
      - logger.log: 
            level: INFO
            format: "Device booted"
      - script.execute: script_light_blink

bk72xx:
  board: cb3s 
  framework:
    version: latest
# Enable logging
logger:
  baud_rate: 0 # BK72xx devices often don’t have usable UART. Disable serial output to avoid issues
  level: INFO # Change to DEBUG to view full log


# Enable Home Assistant API
api:
  encryption:
    key: !secret place-yours

ota:  
  - platform: esphome
  - platform: web_server
    on_begin:
      then:
        - logger.log: 
            level: INFO
            format: "=================== OTA has started =================== "
    on_end:
      then:
        - logger.log: 
            level: INFO
            format: "=================== OTA has finished =================== "
    on_error:
      then:
        - logger.log:
            level: ERROR
            format: "!!!!!!!!!!!!!!!!!!!! OTA update error %d !!!!!!!!!!!!!!!!!!!!"
            args: ["x"]

web_server:
  port: 80
  version: 2
  include_internal: true
  auth:
    username: !secret place-yours
    password: !secret place-yours


wifi:
  power_save_mode: high
  # Change to your networks and prioritize channels if you have more than one AP, otherwise remove channel statement
  networks:
  - ssid: !secret wifi_ssid
    password: !secret wifi_password
    channel: place-yours

  - ssid: !secret wifi_ssid
    password: !secret wifi_password
    channel: place-yours

  # Enable fallback hotspot in case wifi connection fails
  ap:
    ssid: "place-yours"
    password: !secret AP_Password
    channel: place-yours

  # Set static IP or remove this section
  manual_ip:
    static_ip: place-yours
    gateway: place-yours
    subnet: place-yours


script:
  - id: script_light_blink
    mode: restart   # restarts if triggered again
    then:
      - light.turn_on:
          id: wf2050p
      - delay: 2s
      - light.turn_off:
          id: wf2050p

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

  - id: luminancelowglob
    type: bool
    restore_value: no  # Do not store value
    initial_value: "false"

button:
  - platform: restart
    name: "Device restart"

number:
  - platform: template
    name: Auto mode timer
    id: autofallback
    unit_of_measurement: s
    min_value: 0
    max_value: 7200
    step: 30
    icon: "mdi:timer-refresh-outline"
    optimistic: true
    restore_value: true
    initial_value: "3600" 
    on_value:
      then:
        - globals.set:
            id: autofallbackglob
            value: !lambda 'return x;'

  - platform: template
    name: PIR Illumination
    id: ledduration
    unit_of_measurement: s
    icon: "mdi:timer-play-outline"
    min_value: 0
    max_value: 3600
    step: 10
    restore_value: true
    optimistic: true
    initial_value: "60" 
    on_value:
      then:
        - globals.set:
            id: leddurationglob
            value: !lambda 'return x;'
    
output:  # Free pins: P24 - PWM 4, P9 - PWM 3, 
  - platform: libretiny_pwm
    id: lightbri
    pin: P7 # PWM 1
    frequency: 1000 Hz
    # Adjusted power to prevent LED blinking
    min_power: 0.05
    max_power: 0.9
    zero_means_zero: true
    
  - platform: libretiny_pwm
    id: lightct
    pin: P8 # PWM 2
    frequency: 1000 Hz
    inverted: true

  - platform: libretiny_pwm
    # Wire color: white, Module pin: 5
    id: PIRsen
    frequency: 1000 Hz
    pin: P26 # PWM 5

select:
  - platform: template
    name: PIR Sensitivity
    icon: "mdi:signal-distance-variant"
    id: PIRsenMode
    options:
      - "Far"
      - "Medium"
      - "Close"
    initial_option: "Medium"
    optimistic: true    
    restore_value: True
    ## adjust below values of PIR sensitivity
    on_value:
      then:
        - lambda: |-
            if (id(PIRsenMode).current_option() == "Far") {
              id(PIRsen).set_level(0.00); 
            } else if (id(PIRsenMode).current_option() == "Medium") {
              id(PIRsen).set_level(0.50);
            } else if (id(PIRsenMode).current_option() == "Close") {
              id(PIRsen).set_level(1.00);
            }

  - platform: template
    name: Luminance 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).current_option() == "Pitch Black";'
            then:
              - globals.set:
                  id: ambientmapper
                  value: '3.6'
              - logger.log:
                  level: INFO
                  format: "Ambient value set to %.2f - Pitch Black"
                  args: [ 'id(ambientmapper)']
        - if:
            condition:
                lambda: 'return id(ambientLight).current_option() == "Semi Dark";'
            then:
              - globals.set:
                  id: ambientmapper
                  value: '2.7'
              - logger.log:
                  level: INFO
                  format: "Ambient value set to %.2f - Semi Dark"
                  args: [ 'id(ambientmapper)']
        - if:
            condition:
                lambda: 'return id(ambientLight).current_option() == "Moderate";'
            then:
              - globals.set:
                  id: ambientmapper
                  value: '1.8'
              - logger.log:
                  level: INFO
                  format: "Ambient value set to %.2f - Moderate"
                  args: [ 'id(ambientmapper)']
        - if:
            condition:
                lambda: 'return id(ambientLight).current_option() == "Semi Bright";'
            then:
              - globals.set:
                  id: ambientmapper
                  value: '0.9'
              - logger.log:
                  level: INFO
                  format: "Ambient value set to %.2f - Semi Bright"
                  args: [ 'id(ambientmapper)']
        - if:
            condition:
                lambda: 'return id(ambientLight).current_option() == "Day";'
            then:
              - globals.set:
                  id: ambientmapper
                  value: '0.01'
              - logger.log:
                  level: INFO
                  format: "Ambient value set to %.2f - Day"
                  args: [ 'id(ambientmapper)']

  - platform: template
    name: Action mode
    icon: "mdi:refresh-auto"
    id: actionmode
    options:
      - "Manual"
      - "Auto"
    initial_option: "Auto"
    optimistic: true
    restore_value: True
    on_value:
      then:
        - if:
            condition:
              #lambda: |-
              #  if ( id(actionmode).current_option() == "Manual" & id(timeautofallback).state ) {
              #    return true;
              #  } else {
              #    return false;
              #  }           
              lambda: |-
                if ( id(actionmode).current_option() == "Manual" & ( id(autofallbackglob) > 0 ) ) {
                  return true;
                } else {
                  return false;
                }                
            then:
              - logger.log:
                  level: INFO
                  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 before falling back to auto mode works only from HA
              - select.set:
                  id: actionmode
                  option: "Auto"
              - logger.log:
                  level: INFO
                  format: "Autmoaticaly got back to auto mode after time set"

sensor:
  - platform: adc
    # Wire color: magenta,  Module pin: 2
    id: luval
    pin: ADC3
    name: "Luminance"
    update_interval: 10s
    internal: true
    accuracy_decimals: 2

  - platform: wifi_signal
    name: "WiFi Signal dB"
    id: wifi_signal_db
    update_interval: 60s    
    icon: "mdi:signal-variant"
    entity_category: "diagnostic"
    device_class: "signal_strength"
    accuracy_decimals: 0

  - platform: copy # Reports the WiFi signal strength in %
    source_id: wifi_signal_db
    name: "WiFi Signal Percent"
    icon: "mdi:percent-outline"
    accuracy_decimals: 0
    filters:
      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
    unit_of_measurement: "%"
    entity_category: "diagnostic"
    device_class: "signal_strength"

binary_sensor:
  - platform: gpio
    name: PIR Motion sensor
    icon: "mdi:motion-sensor"
    # Wire color: blue, Module pin: 7 
    pin: P6 # PWM 0
    internal: False # True
    id: motionsensor
    on_press:
      then:
        - if:
            condition:
              lambda: |-
                if ( id(pirautofallback).state & id(actionmode).current_option() == "Manual") {
                  return true;
                } else {
                  return false;
                }
            then:
              - logger.log:
                  level: INFO
                  tag: BINARY_SENSOR
                  format: "PIR: Automatically switched back to auto mode - Movement detected"
              - select.set:
                  id: actionmode
                  option: "Auto"



  - platform: template
    internal: true
    name: PIR Motion delayed
    id: motiondelayed
    # Do not turn on if the luminance is too high
    # ESP_LOGD("Motion", "AmbientLightThreshold %.2f, ADC illumination %.2f, Motion Delayer PIR %s", id(ambientmapper), id(luval).state, id(luminancelowglob) ? "TRUE" : "FALSE");
    lambda: |-
      id(luminancelowglob) = ( id(ambientmapper) <= id(luval).state ) ? true: false;
      return id(motionsensor).state & id(luminancelowglob);
    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).current_option() == "Auto" & id(luminancelowglob)) {
                  return true;
                } else {
                  return false;
                }
            then:
              - light.turn_on:
                  id: wf2050p
              - logger.log:
                  level: INFO
                  tag: BINARY_SENSOR
                  format: "AmbientLightThreshold %.2f was lower than current ADC illumination %.2f"
                  args: [ 'id(ambientmapper)', 'id(luval).state']
            else:
              - logger.log:
                  level: INFO
                  tag: BINARY_SENSOR
                  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 # cwww
    name: "Light switch"
    icon: "mdi:light-flood-down"
    id: wf2050p
    color_temperature: lightct
    brightness: lightbri
    #cold_white: lightct
    #warm_white: lightbri
    cold_white_color_temperature: 6500 K
    warm_white_color_temperature: 3000 K
    restore_mode: RESTORE_AND_OFF
    initial_state:
      state: OFF    

## Comment below section if You want to use Light with outside automations. 

    on_turn_on:
      then: 
        - if:
            condition:
              lambda: |-
                if (id(actionmode).current_option() == "Auto" & not id(motionsensor).state & id(automanual).state ) {
                  return true;
                } else {
                  return false;
                }
            then:
              - select.set:
                  id: actionmode
                  option: "Manual"
              - logger.log:
                  level: INFO
                  tag: LIGHT
                  format: "Switched to manual mode since PIR was not active during enablling LED"


switch: 
# Choose time based fallback to auto mode
#  - platform: template
#    name: "Set Time to Auto"
#    icon: "mdi:timer-remove-outline"
#    id: timeautofallback
#    optimistic: true
#    restore_mode: RESTORE_DEFAULT_ON # adjust default state 


# Choose PIR based fallback to auto mode
  - platform: template
    name: "Set PIR to Auto"
    icon: "mdi:motion-sensor-off"
    optimistic: true
    id: pirautofallback
    restore_mode: RESTORE_DEFAULT_ON # adjust default state 
  

# Choose Automatic manual mode
  - platform: template
    name: "Set Default manual mode"
    icon: "mdi:car-shift-pattern"
    optimistic: true
    id: automanual
    #restore_mode: RESTORE_DEFAULT_ON ## adjust default state