KestrelMet 6000 ESPHome Complete Conversion

August 28, 2023
3970
Views

Status LED

For the status LED, I used an addressable WS2811 LED. A single LED cut from the line of LEDs. When installing the LED, make sure you place it in the right place. You will see where the LED glass is on the solar panel, just line them up so when the solar panel is reinstalled, the light transfers through.

We can configure the addressable WS2811 for any color, and also assign flash patters. Here we will configure the status LED to indicate the status of the Wi-Fi connection.

To connect the LED, we supply it with 5V and GND, then connect the data line to GPIO23, and use the fastled_clockless integration in esphome. One trick with the addressable LEDs is that they are directional when wiring in the data line. You will see on the last photo above, there is a small arrow indicating the flow of the data. You must wire the incoming data to the arrow pointing forward, and if you were to wire in additional LEDs, you would connect them to the arrow pointing out, simulating the flow of data.

light:
  - platform: fastled_clockless
    id: led
    name: "LED"
    pin: 23
    chipset: WS2812
    num_leds: 1
    rgb_order: GRB
    restore_mode: ALWAYS_OFF
    effects:
      - lambda:
          name: "ERROR"
          update_interval: 0.2s
          lambda: |-
            static bool state = false;
            auto call = id(led).turn_on();
            call.set_transition_length(500);
            call.set_rgb(1, 0, 0);
            if (!state) {
              call.set_brightness(1);
            } else {
              // If using 0, it freaks Home Assistant UI.
              call.set_brightness(0.01);
            }
            call.perform();
            state = !state;
      - lambda:
          name: "BOOT"
          update_interval: 0.2s
          lambda: |-
            static bool state = false;
            auto call = id(led).turn_on();
            call.set_transition_length(500);
            call.set_rgb(0, 1, 0);
            if (!state) {
              call.set_brightness(1);
            } else {
              // If using 0, it freaks Home Assistant UI.
              call.set_brightness(0.01);
            }
            call.perform();
            state = !state;

Again, you will now have another entity as a light called “LED” where you can turn it on and off and select the color, brightness and effects.

We will now add the code to the Wi-Fi component to indicate the status of the Wi-Fi and display the LED accordingly. This is done using on_connect and on_disconnect to trigger the LED and the required events. In you esphome Wi-Fi component

wifi:
  networks:
  - ssid: !secret wifi_ssid
    password: !secret wifi_password
  on_connect:
    - light.turn_on:
        id: led
        brightness: 100%
        red: 0%
        green: 100%
        blue: 0%
        effect: none
  on_disconnect:
      - light.control:
          id: led
          state: on
          effect: ERROR

With the above code, when the ESP boots and connects to Wi-Fi, it will display the green LED at 100% brightness. If for any reason Wi-Fi fails to connect, or disconnects, it will then display the LED effect called “ERROR”

Final ESPHome YAML

This is my final, well rounded and complete code for full functionality and with all sensors and integrations including templates for daily and weekly rain totals, average wind speeds etc.

esphome:
  name: weather-station
  friendly_name: weather-station

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key:

ota:
  password:

i2c:
  sda: 21
  scl: 22
  scan: True
  id: bus_a

max6956:
  - id: max6956_1
    address: 0x40
    i2c_id: bus_a

sun:
  latitude:
  longitude:

wifi:
  networks:
  - ssid: !secret wifi_ssid
    password: !secret wifi_password
    bssid:
  fast_connect: true
  on_connect:
    - light.turn_on:
        id: led
        brightness: 100%
        red: 0%
        green: 100%
        blue: 0% 
  on_disconnect:
      - light.control:
          id: led
          state: on
          effect: ERROR

  # Optional manual IP
  manual_ip:
    static_ip:
    gateway:
    subnet:

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid:
    password:

sensor:
####Wifi Signal Start####
  - platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB
    name: "WiFi Signal dB"
    id: wifi_signal_db
    update_interval: 60s
    entity_category: "diagnostic"

  - platform: copy # Reports the WiFi signal strength in %
    source_id: wifi_signal_db
    name: "WiFi Signal Percent"
    filters:
      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
    unit_of_measurement: "Signal %"
    entity_category: "diagnostic"
####Wifi Signal END###

####Tempreature & Humidity Start####
  - platform: sht3xd
    temperature:
      name: "Temperature"
    humidity:
      name: "Humidity"
    address: 0x44
    update_interval: 60s
####Tempreature & Humidity END####

####Rainfall Start####
  - platform: pulse_counter
    pin:
      # Don't forget to add a pulling resistor, see README
      number: GPIO32
      mode: INPUT
    unit_of_measurement: 'mm'
    name: "${friendly_name} rain gauge"
    icon: 'mdi:weather-rainy'
    id: rain_gauge
    internal: true
    count_mode:
      rising_edge: DISABLE
      falling_edge: INCREMENT
    internal_filter: 13us
    update_interval: 10s
    filters:
      # Each 0.011" (0.2794mm) of rain causes one momentary contact closure
      - multiply: 0.2
    accuracy_decimals: 4

  - platform: integration
    name: "${friendly_name} rainfall per min"
    id: rain_per_min
    time_unit: min
    unit_of_measurement: 'mm'
    icon: 'mdi:weather-rainy'
    sensor: rain_gauge

  - platform: integration
    name: "${friendly_name} rainfall per hour"
    id: rain_per_hour
    time_unit: h
    unit_of_measurement: 'mm'
    icon: 'mdi:weather-rainy'
    sensor: rain_gauge

  - platform: integration
    name: "${friendly_name} rainfall per day"
    id: rain_per_daily
    time_unit: d
    unit_of_measurement: 'mm'
    icon: 'mdi:weather-rainy'
    sensor: rain_gauge

  - platform: total_daily_energy
    name: "${friendly_name} 24 Hour Rain"
    power_id: rain_gauge
    unit_of_measurement: 'mm'
    icon: 'mdi:weather-rainy'
    filters:
      - multiply: 60
      # x60 To convert to aggregated rain amount
####Rainfall End####

####Sun Start####
  - platform: sun
    name: "Sun elevation"
    type: elevation
    update_interval: 120s

  - platform: sun
    name: "Sun azimuth"
    type: azimuth
    update_interval: 120s
####Sun End####

####Wind Speed Start####
  - platform: pulse_meter
    pin:
      number: GPIO33
      mode: INPUT
    id: wind_speed
    unit_of_measurement: 'm/s'
    name: "${friendly_name} wind speed"
    icon: 'mdi:weather-windy'
    internal_filter: 13us
    timeout: 5s
    filters:
      - multiply: 0.005560619
      - sliding_window_moving_average:
          window_size: 5
          send_every: 5
####Wind Speed END####

  - platform: copy
    name: '${friendly_name} wind speed average'
    icon: 'mdi:weather-windy'
    id: wind_speed_avg
    source_id: wind_speed
    unit_of_measurement: 'm/s'
    filters:
      - throttle_average: 5s

  - platform: copy
    name: '${friendly_name} wind speed (km/h)'
    id: wind_speed_kmh
    source_id: wind_speed
    unit_of_measurement: 'km/h'
    icon: 'mdi:weather-windy'
    filters:
      - multiply: 3.6

  - platform: copy
    name: '${friendly_name} wind speed average (km/h)'
    icon: 'mdi:weather-windy'
    id: wind_speed_kmh_avg
    source_id: wind_speed_avg
    unit_of_measurement: 'km/h'
    filters:
      - multiply: 3.6
    on_value:
      lambda: |-
        if (x < 1) {
          id(wind_scale_code).publish_state("0");
          id(wind_scale).publish_state("Calm");
        } else if (x >= 1 && x < 6) {
          id(wind_scale_code).publish_state("1");
          id(wind_scale).publish_state("Light Air");
        } else if (x >= 6 && x < 12) {
          id(wind_scale_code).publish_state("2");
          id(wind_scale).publish_state("Light Breeze");
        } else if (x >= 12 && x < 20) {
          id(wind_scale_code).publish_state("3");
          id(wind_scale).publish_state("Gentle Breeze");
        } else if (x >= 20 && x < 29) {
          id(wind_scale_code).publish_state("4");
          id(wind_scale).publish_state("Moderate Breeze");
        } else if (x >= 29 && x < 39) {
          id(wind_scale_code).publish_state("5");
          id(wind_scale).publish_state("Fresh Breeze");
        } else if (x >= 39 && x < 50) {
          id(wind_scale_code).publish_state("6");
          id(wind_scale).publish_state("Strong Breeze");
        } else if (x >= 50 && x < 62) {
          id(wind_scale_code).publish_state("7");
          id(wind_scale).publish_state("Near Gale");
        } else if (x >= 62 && x < 75) {
          id(wind_scale_code).publish_state("8");
          id(wind_scale).publish_state("Gale");
        } else if (x >= 75 && x < 89) {
          id(wind_scale_code).publish_state("9");
          id(wind_scale).publish_state("Severe Gale");
        } else if (x >= 89 && x < 103) {
          id(wind_scale_code).publish_state("10");
          id(wind_scale).publish_state("Storm");
        } else if (x >= 103 && x < 118) {
          id(wind_scale_code).publish_state("11");
          id(wind_scale).publish_state("Violent Storm");
        } else if (x >= 118) {
          id(wind_scale_code).publish_state("12");
          id(wind_scale).publish_state("Hurricane Force");
        } else {
          ESP_LOGD("main", "It shouldn't happen (wind_speed_kmh_avg: %f)", x);
        }

####Wind Direction Start####
  - platform: mlx90393
    address: 0x0c
    id: mlx
    x_axis:
      name: "mlx_x"
      id: "mlx_x"
    y_axis:
      name: "mlx_y"
      id: "mlx_y"
    z_axis:
      name: "mlx_z"
    update_interval: 2s


  - platform: template
    id: 'wind_direction'
    name: 'Wind Direction'
    update_interval: 2s
    lambda: |-
      float w1 = id(mlx_x).state;  // magnetometer X
      float w0 = id(mlx_y).state;  // magnetometer Y
      float w = atan2(w0, w1);     // arctangent2 = radians
      w = (w * 180) / M_PI;    // radians to degrees
      w += 19.50;              // magnetic declination
      w += 68.00;              // seems to be off by 90
      if ( w < 0 ) w += 360.0; // adjust for negatives
      return w;
####END Wind Direction####


####FAN Switch Start####
switch:
  - platform: gpio
    pin: 25
    name: "Fan"
    inverted: True
####Fan Switch END####

####Status LED Start####
light:
  - platform: fastled_clockless
    id: led
    name: "LED"
    pin: 23
    chipset: WS2812
    num_leds: 1
    rgb_order: GRB
    restore_mode: ALWAYS_OFF
    effects:
      - lambda:
          name: "ERROR"
          update_interval: 0.2s
          lambda: |-
            static bool state = false;
            auto call = id(led).turn_on();
            call.set_transition_length(500);
            call.set_rgb(1, 0, 0);
            if (!state) {
              call.set_brightness(1);
            } else {
              // If using 0, it freaks Home Assistant UI.
              call.set_brightness(0.01);
            }
            call.perform();
            state = !state;
      - lambda:
          name: "BOOT"
          update_interval: 0.2s
          lambda: |-
            static bool state = false;
            auto call = id(led).turn_on();
            call.set_transition_length(500);
            call.set_rgb(0, 1, 0);
            if (!state) {
              call.set_brightness(1);
            } else {
              // If using 0, it freaks Home Assistant UI.
              call.set_brightness(0.01);
            }
            call.perform();
            state = !state;
####Status LED END####

####Rain Reset Timer Start####
interval:
  - interval: 60s
    then:
      - sensor.integration.reset: rain_per_min
####Rain Reset Timer END####

####Time Start####
time:
  - platform: homeassistant
####Time End####

text_sensor:
  - platform: sun
    name: Sun Next Sunrise
    type: sunrise
  - platform: sun
    name: Sun Next Sunset
    type: sunset

  - platform: template
    name: '${friendly_name} Beaufort wind scale code'
    icon: 'mdi:tailwind'
    id: wind_scale_code

  - platform: template
    name: '${friendly_name} Beaufort wind scale'
    icon: 'mdi:tailwind'
    id: wind_scale
    update_interval: never

1 2 3 4 5

Leave a Reply