##########################################################################################
##########################################################################################
# XCRhom.tech E27 9W RGBWW Smart Bulb
#
# # V1.0 2025-09-09 Initial Version
#
# Device https://www.aliexpress.com/item/1005007226730234.html
# Tasmota name AiYaTo-RGBCW
#
# GPIO Config
# -----
# - Pin map mirrors original Tasmota config:
#   PWM1=GPIO12 (R), PWM2=GPIO14 (G), PWM3=GPIO5 (B),
#   PWM4=GPIO4 (CW), PWM5=GPIO13 (WW, inverted).
# 
# NOTES
#
##########################################################################################
##########################################################################################


##########################################################################################
# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS
# If NOT using a secrets file, just replace these with the passwords etc (in quotes)
##########################################################################################
substitutions:
  # Device Naming
  device_name: esp-rgblampbulb1
  friendly_name: "RGBWW 9W E27 Smart Bulb"
  description_comment: "RGBWW light bulb in bedroom 3 lamp"
  device_area: "Bedroom 3" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant.  

  # Passwords   If NOT using a secrets file, just replace these with the passwords etc (in quotes)
  api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names
  ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names
  static_ip_address: !secret esp-rgblampbulb1_ip

  # Adjust the color temperature here (200 mired is approx 5000k)
  white_temp: "3000K"

  # Device Settings
  log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE
  update_interval: "60s" # update time for for general sensors etc

  # Adjust the ON/OFF times for flashing.
  # 600ms on, 400ms off => 60% ON, 40% OFF duty cycle
  on_time_ms: "500ms"
  off_time_ms: "500ms"

##########################################################################################
# PACKAGES: Included Common Packages
# https://esphome.io/components/packages.html
##########################################################################################
# Comment some of these out where not needed, eg MQTT, Web portal, SNTP, General Sensors
##########################################################################################
packages:
  common_wifi: !include
    file: common/network_common.yaml
    vars:
      local_device_name: "${device_name}"
      local_static_ip_address: "${static_ip_address}"
      local_ota_pass: "${ota_pass}"
  common_api: !include
    file: common/api_common.yaml
    vars:
      local_api_key: "${api_key}"
  #common_webportal: !include
  #  file: common/webportal_common.yaml
  common_mqtt: !include
    file: common/mqtt_common.yaml
    vars:
      local_device_name: "${device_name}"
  common_sntp: !include
    file: common/sntp_common.yaml
  common_general_sensors: !include
    file: common/sensors_common.yaml
    vars:
      local_friendly_name: "${friendly_name}"
      local_update_interval: "${update_interval}"

#########################################################################################
# ESPHome
# https://esphome.io/components/esphome.html
#########################################################################################
esphome:
  name: ${device_name}
  friendly_name: ${friendly_name}
  comment: ${description_comment} # appears on the esphome page in HA
  on_boot:
    priority: 800
    then:
      - light.turn_on:
          id: my_light
          brightness: 80%
          color_temperature: ${white_temp}  # e.g. "3000K" or "370 mireds"
          transition_length: 3s

#########################################################################################
# ESP Platform and Framework
# https://esphome.io/components/esp32.html
#########################################################################################
esp8266:
  board: esp01_1m
  #early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True.
  board_flash_mode: dout # Default is dout
  #restore_from_flash: true # restore some values on reboot

mdns:
  disabled: false # Disabling will make the build file smaller (and it is still available via static IP)

preferences:
  flash_write_interval: 20s

#########################################################################################    
# ESPHome Logging Enable
# https://esphome.io/components/logger.html
#########################################################################################  
logger:
  level: INFO  # INFO Level suggested, or DEBUG for testing
  #baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM)
  #esp8266_store_log_strings_in_flash: false
  #tx_buffer_size: 64

##########################################################################################
# OUTPUT COMPONENT
# https://esphome.io/components/output/esp8266_pwm.html
##########################################################################################
output:
  - platform: esp8266_pwm
    id: output_red          # PWM1 → GPIO12
    pin: GPIO12
    frequency: 1500 Hz

  - platform: esp8266_pwm
    id: output_green        # PWM2 → GPIO14
    pin: GPIO14
    frequency: 1500 Hz

  - platform: esp8266_pwm
    id: output_blue         # PWM3 → GPIO05
    pin: GPIO05
    frequency: 1500 Hz

  # Typically one channel is cold white...
  - platform: esp8266_pwm
    id: output_cold_white   # PWM4 → GPIO04
    pin: GPIO04
    frequency: 1500 Hz

  # ...and one channel is warm white (inverted on GPIO13).
  - platform: esp8266_pwm
    id: output_warm_white   # PWM5 → GPIO13
    pin: GPIO13
    frequency: 1500 Hz
    inverted: true

##########################################################################################
# LIGHT COMPONENT
# https://esphome.io/components/light/
##########################################################################################
light:
  - platform: rgbww
    name: ${friendly_name}
    id: my_light
    red: output_red
    green: output_green
    blue: output_blue
    cold_white: output_cold_white
    warm_white: output_warm_white

    # Keep total output reasonable on 9W bulbs and avoid mixing RGB with WW simultaneously.
    constant_brightness: true
    color_interlock: true
    
    # Typical white temperature mapping for RGBWW
    cold_white_color_temperature: 6500 K
    warm_white_color_temperature: 2700 K

    # Ensure it always powers on (and with our desired effect).
    restore_mode: ALWAYS_ON

    # Optional: small gamma tweak for nicer dimming curves
    gamma_correct: 2.4

    # You can omit this or set it to zero for no fade on effect changes.
    default_transition_length: 0s

    ######################################################################################
    # CALM EFFECTS
    # - Night Light: steady warm, ~3% brightness
    # - Breathe (Soft): slow, gentle brightness wave on current color
    # - Amber Glow: very gentle warm amber wave
    # - Blue Calm: subtle cool blue drift
    # - Warm Dim: static warm preset around 15%
    ######################################################################################
    effects:
      # Night Light (steady warm ~3%)
      - lambda:
          name: "Night Light"
          update_interval: 2s
          lambda: |-
            auto call = id(my_light).turn_on();
            call.set_brightness(0.03f);
            // 2700K ≈ 370 mireds
            call.set_color_temperature(370.0f);
            call.set_transition_length(1000);
            call.perform();

      # Breathe (Soft) — gentle pulse on the *current* color
      - pulse:
          name: "Breathe (Soft)"
          transition_length: 3s
          update_interval: 3s
          min_brightness: 5%
          max_brightness: 35%

      # Amber Glow — very gentle warm wave (8–20%)
      - lambda:
          name: "Amber Glow"
          update_interval: 500ms
          lambda: |-
            static float t = 0.0f;
            t += 0.5f;  // seconds step (approx)
            float phase = (sinf(t * 2.0f * (3.14159f/16.0f)) + 1.0f) / 2.0f; // 16s cycle
            float b = 0.08f + phase * 0.12f; // 8%..20%
            auto call = id(my_light).turn_on();
            call.set_brightness(b);
            // Warm amber tone via WW channel (keep RGB off)
            call.set_color_temperature(400.0f); // ≈ 2500K-2800K feel
            call.set_transition_length(800);
            call.perform();

      # Blue Calm — soft cool tint, tiny drift (6–14%)
      - lambda:
          name: "Blue Calm"
          update_interval: 1000ms
          lambda: |-
            static float t = 0.0f;
            t += 1.0f;
            float phase = (sinf(t * 2.0f * (3.14159f/20.0f)) + 1.0f) / 2.0f; // 20s cycle
            float b = 0.06f + phase * 0.08f; // 6%..14%
            auto call = id(my_light).turn_on();
            call.set_brightness(b);
            // Gentle cool tint using RGB to keep it soft
            call.set_rgb(0.45f, 0.55f, 1.00f);
            call.set_transition_length(1200);
            call.perform();

      # Warm Dim — static warm preset (~15%)
      - lambda:
          name: "Warm Dim"
          update_interval: 5s
          lambda: |-
            auto call = id(my_light).turn_on();
            call.set_brightness(0.15f);
            call.set_color_temperature(360.0f); // ~2777K
            call.set_transition_length(800);
            call.perform();
