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