Files
zorruno-homeassistant/esphome/esp-weatherstation.temp
T
2025-09-20 15:18:46 +12:00

961 lines
37 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#######################################################################################################
#######################################################################################################
# Opengreen energy weather station board, with ESP8266 D1 Mini
# https://www.opengreenenergy.com/solar-powered-wifi-weather-station-v2-0/
# zorruno 2025-09-12 V6 fixes: AP SSID sub; ADC calibrate indent; NaN-safe temp avg; empty-string publishes; improved 10min gust (3s avg -> 10m max); comment tidy-ups
# zorruno 2024-06-14 V5 added wind heading, and sorted breaking a change for OTA
# zorruno 2024-06-03 V4 tweaks to battery and wind
# zorruno 2024-05-25 V3 Shuffled some sensors, rain count added
# zorruno 2024-05-25 V2 A bunch more sensors added (wind direction not yet sorted)
# zorruno 2024-05-24 V1.1 Tested ok and added some V calibration for mine
# zorruno 2024-05-23 V1.0 Tidied up sensor info and added BMP280
# zorruno 2024-05-04 V0.0 Untested
#######################################################################################################
#######################################################################################################
#######################################################################################################
# SENSORS INCLUDED
#
# TESTED WORKING
# status_led:
# uptime:
# wifi_signal:
# battery voltage (adc A0)
#
# ads1115: 4 Channel A->D (0x48 i2c)
# dht: DHT22 Temp/Humidity, Remote (GPIO13)
# bmp280: Temp/pressure on the board (0x76 i2c)
# pulse_meter: Wind Speed (GPIO14)
# pulse_meter: Rainfall (GPIO12)
# ads1115 A0_GND: Wind Direction
#
# text_sensor: Beaufort Wind Scale Labelling
# text_sensor: Temp (av) Average of all temps
# text_sensor: Wind Direction Heading
#
# Battery Calcs:
# template: Last 30mins battery MAX
# template: battery now - max (discharge/charge)
# template binary: discharging, charging, stable
#
# TO TEST (HAVE SENSOR or doesn't need one)
# tsl2561: Ambient Light sensor (0x39 i2c)
# ads1115 A1_GND: UV Index
# ltr390: Ambient Light and UV sensor (0x53 i2c)
# pmsx003: PM Particulate Filter (UART)
# AS3935: lightning sensor (i2c, but needs design)
# ds1307: RTC (i2c)
#
# NOT USED (but code commented)
# bme280_i2c: Temp/humid/press (not used)
#
# POSSIBLY ADD
# Analogue for Solar V?
# ground movement/earthquake?
# water sensor (rain now)
# soil temp
# soil moisture
#
#######################################################################################################
#######################################################################################################
# WEMOS D1 Mini GPIO, and Weather station Use
#######################################################################################################
# PIN HEADERS on Weatherstation board:
# D1, GPIO5 Used as SCL (I2C)
# D2, GPIO4 Used as SDA (I2C)
# D3, GPIO0 connected to FLASH button, boot fails if pulled LOW
# D4, GPIO2 connected to on-board LED, boot fails if pulled LOW
# D5, GPIO14 Used as Wind Speed Count
# D6, GPIO12 Used as Rainfall count
# D7, GPIO13 Used for DHT
# D8, GPIO15 (Boot fails if pulled HIGH)
#
# NO HEADERS on Weatherstation board:
# D0, GPIO16 (used to wake up from deep sleep)
# RX, GPIO3 (HIGH at boot)
# TX, GPIO1 (HIGH at boot, boot fails if pulled LOW)
# A0, ADC0 Used here to measure battery V
#
#######################################################################################################
#######################################################################################################
# Pulse Meter Issues 202405
# https://github.com/esphome/issues/issues/4807
# https://github.com/esphome/issues/issues/3143
#######################################################################################################
external_components:
- source: github://TrentHouliston/esphome@loop_pulse_isr
components: [ pulse_meter ]
#######################################################################################################
# Variable Substitutions
# Give this a useful name & description here
# and change values accordingly
#######################################################################################################
substitutions:
devicename: "esp-weatherstation"
friendly_name: "Weather Station"
description_comment: "Opengreen energy board, with BME280 Temp/Hum/Pres Sensor on an ESP8266 D1 Mini"
#if NOT using a secrets file, just replace these with the passwords etc in speech marks
api_key: !secret esp-weatherstation_api_key #unfortunately you can't use substitutions in secrets names
ota_pass: !secret esp-weatherstation_ota_pass #unfortunately you can't use substitutions in secrets names
wifi_ssid: !secret wifi_ssid
wifi_pass: !secret wifi_password
mqtt_server: !secret mqtt_server
mqtt_username: !secret mqtt_username
mqtt_password: !secret mqtt_password
mqtt_topic: "esphome" #main topic for the mqtt server, call it what you like
update_time: 30s #update time for for various temp sensors etc
#######################################################################################################
# ESPHome
# https://esphome.io/components/esphome.html
#######################################################################################################
esphome:
name: ${devicename}
comment: ${description_comment} #appears on the esphome page in HA
#on_boot: #Initial Setting stuff
# priority: -200
# then:
#######################################################################################################
# ESP Platform and Framework
# https://esphome.io/components/esp32.html OR
# https://esphome.io/components/esp8266.html
#######################################################################################################
#esp32:
# board:
# framework:
# type: arduino
# #type: esp-idf #Suggested Use ESP-IDF Framework for ESP32, or unplugging the UART Cable Might Cause ESP32 Hang.
# version: recommended #recommended, latest or dev
esp8266:
board: d1_mini
#######################################################################################################
# i2c bus
# https://esphome.io/components/i2c.html
# Put the relevant pins here, 4/5 are default for ESP8266
# and 21/22 for esp32 (although esp32 can have two buses)
#######################################################################################################
i2c:
sda: GPIO4
scl: GPIO5
scan: True #scan the bus on startup. Useful if looking for the address of something
#frequency: 100kHz #10, 50, 100, 200, 800 are possible settings, 100kHz was reliable for me for ESP32, default is 50kHz
#############################################
# 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
#############################################
# Enable the Home Assistant API
# https://esphome.io/components/api.html
#############################################
api:
encryption:
key: ${api_key}
#############################################
# Enable Over the Air Update Capability
# https://esphome.io/components/ota.html?highlight=ota
#############################################
ota:
- platform: esphome
password: ${ota_pass}
#############################################
# Safe Mode
# Safe mode will detect boot loops
# https://esphome.io/components/safe_mode
#############################################
safe_mode:
#############################################
# Wifi Settings
# https://esphome.io/components/wifi.html
#
# Power Save mode (can reduce wifi reliability)
# NONE (least power saving, Default for ESP8266)
# LIGHT (Default for ESP32)
# HIGH (most power saving)
#############################################
wifi:
ssid: ${wifi_ssid}
password: ${wifi_pass}
#power_save_mode: LIGHT #https://esphome.io/components/wifi.html#wifi-power-save-mode
#manual_ip: #optional static IP address
# static_ip: 192.168.x.x
# gateway: 192.168.X.x
# subnet: 255.255.255.0
ap: #Details for fallback hotspot in case wifi connection fails https://esphome.io/components/wifi.html#access-point-mode
ssid: "${devicename} fallback AP"
password: !secret fallback_ap_password
ap_timeout: 30min #default is 1min
#############################################
# Web Portal for display and monitoring
# Turning this off if you don't really need it
# is probably a good idea to save resources.
# Also, don't use it with other big ESP32 components
# such as Bluetooth proxy (it will run out of flash
# and not compile, or it will crash occasionally)
# https://esphome.io/components/web_server.html
#############################################
#web_server:
# port: 80
# version: 1 #V1 occasionally works better, V2 The nicer page
# username: !secret web_server_username #probably a good idea to secure it
# password: !secret web_server_password
#######################################################################################################
# MQTT Monitoring
# https://esphome.io/components/mqtt.html?highlight=mqtt
# MUST also have api enabled if you enable MQTT
#######################################################################################################
mqtt:
broker: ${mqtt_server}
topic_prefix: ${mqtt_topic}/${devicename}
username: ${mqtt_username}
password: ${mqtt_password}
#Method to prevent deep sleep using MQTT command
#on_message:
# - topic: ${mqtt_topic}/${devicename}/deepsleep
# payload: 'ON'
# then:
# - deep_sleep.prevent: deep_sleep_1
# - topic: ${mqtt_topic}/${devicename}/deepsleep
# payload: 'ON'
# then:
# - deep_sleep.enter: deep_sleep_1
########################################
# Deep Sleep
# https://esphome.io/components/deep_sleep.html
########################################
#deep_sleep:
# run_duration: 20s
# sleep_duration: 10min
# id: deep_sleep_1
#######################################################################################################
# General espHome status LED
# Not needed, but can be useful to see issues
# https://esphome.io/components/status_led.html
# If the LED appears inverted (on when it should be off), set 'inverted: true'.
#######################################################################################################
status_led:
pin:
number: GPIO2 #Wemos ESP32 and ESP8266 Onboard LEDs use GPIO2
inverted: false
#ignore_strapping_warning: True #https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
##########################################################################################
# 4 Input A->D sensor
# Analog sensor for voltage reading
# https://esphome.io/components/sensor/ads1115.html
##########################################################################################
ads1115:
- address: 0x48 #On the ADS1115 pull address pin to VCC for 0x49. Default is 0x48
#######################################################################################################
# Text Sensors
# https://esphome.io/components/text_sensor/index.html
#######################################################################################################
text_sensor:
- platform: template
name: ${friendly_name} Beaufort Wind Scale
icon: "mdi:tailwind"
id: wind_scale
update_interval: never
- platform: template
name: ${friendly_name} Wind Direction Heading
icon: "mdi:tailwind"
id: wind_dir_heading
update_interval: never
#######################################################################################################
#######################################################################################################
# General Sensors
# https://esphome.io/components/sensor/index.html
#######################################################################################################
#######################################################################################################
sensor:
################################
# UPTIME
# Device uptime info
# https://esphome.io/components/sensor/uptime.html
################################
- platform: uptime
name: ${friendly_name} Uptime
################################
# WIFI SIGNAL
# Quality of Wifi in dBm
# https://esphome.io/components/sensor/wifi_signal.html
################################
- platform: wifi_signal
name: ${friendly_name} WiFi Signal
update_interval: ${update_time}
#retain: true #retain useful if sleeping
################################
# BMP280 TEMPERATURE AND PRESSURE
# The BMP does not have humidity, use the BME for that
# https://esphome.io/components/sensor/bmp280.html
################################
- platform: bmp280
address: 0x76
iir_filter: 16x
update_interval: ${update_time}
temperature:
name: ${friendly_name} BMP280 Temperature
id: bmp280_temp
unit_of_measurement: "°C"
oversampling: 16x
#retain: true #MQTT retain useful if sleeping
pressure:
name: ${friendly_name} BMP280 Pressure
unit_of_measurement: "hPa"
oversampling: 16x
#retain: true #MQTT retain useful if sleeping
################################
# DHT TEMPERATURE, PRESSURE & HUMIDITY
# https://esphome.io/components/sensor/dht.html
# These DHTs are not very accurate...
################################
- platform: dht
pin: GPIO13 #D7 on the D1 Mini ESP8266
temperature:
name: ${friendly_name} DHT22 Temperature
id: dht_temp
unit_of_measurement: "°C"
#retain: true #retain useful if sleeping
humidity:
name: ${friendly_name} DHT22 Humidity
unit_of_measurement: "%"
#retain: true #retain useful if sleeping
################################
# TEMP SENSORS AVERAGE
# Averaging for the various temp sensors on board
################################
- platform: template
name: ${friendly_name} Temp (av)
icon: "mdi:thermometer"
unit_of_measurement: "°C"
lambda: |-
const float a = id(bmp280_temp).state;
const float b = id(dht_temp).state;
const bool va = !isnan(a);
const bool vb = !isnan(b);
if (va && vb) return (a + b) / 2.0f;
if (va) return a;
if (vb) return b;
return NAN;
################################
# BATTERY VOLTAGE
# Analog sensor for voltage reading
# (A0 on esp8266)
# https://esphome.io/components/sensor/adc.html
################################
- platform: adc
name: ${friendly_name} Battery Voltage
id: battery_voltage
pin: A0
unit_of_measurement: "V"
accuracy_decimals: 6
update_interval: 30s
#retain: true #retain useful if sleeping
filters:
- heartbeat: 30s
- multiply: 5.223 # tested with multimeter
- sliding_window_moving_average:
window_size: 2 #2x 30s = 60s average period
send_every: 1
send_first_at: 1
- calibrate_linear:
- 3.321 -> 3.125
- 3.89 -> 3.90
- 4.09 -> 4.14
################################
# A Calculation of recent Av V
# So we can see if battery is charging/discharging
################################
- platform: template
name: ${friendly_name} Av Battery Voltage over recent period
id: battery_voltage_recentav
unit_of_measurement: "V"
accuracy_decimals: 6
update_interval: 30s #updates every 30s
lambda: |-
return id(battery_voltage).state; //grabs values from the battery_voltage
filters:
- sliding_window_moving_average:
window_size: 60 #60x 30s = 30 min average period
send_every: 1
send_first_at: 1
##########################################################################################
# A Calculation of 10 min Max V
# So we can see if battery is charging/discharging
##########################################################################################
- platform: template
name: ${friendly_name} Max Battery Voltage over recent period
id: battery_voltage_recentmax
unit_of_measurement: "V"
accuracy_decimals: 6
update_interval: 30s #updates every 30s
lambda: |-
return id(battery_voltage).state; //grabs values from the battery_voltage
filters:
- heartbeat: 30s
- max:
window_size: 20 # 20 x 30s = 10 min max value (was 60 = 30 min)
send_every: 1
send_first_at: 1
- platform: template
name: ${friendly_name} Battery Voltage loss over 10 mins
id: battery_voltage_recentloss
unit_of_measurement: "V"
accuracy_decimals: 5
update_interval: 30s #updates every 30s
lambda: |-
return id(battery_voltage_recentmax).state - id(battery_voltage).state; //recent max voltage - now
- platform: duty_time
id: battery_discharge_time
name: ${friendly_name} Time battery is discharging
unit_of_measurement: "Mins"
retain: true #retain this as when device dies, we still want the value
# Support logical sources (optional): 'binary_sensor'
accuracy_decimals: 0
filters:
- multiply: 0.01666666
- round: 0
lambda: |-
return id(battery_voltage).state <= id(battery_voltage_recentav).state;
##########################################################################################
# RAIN SENSOR
# Pulse Meter for measuring rainfall
# https://esphome.io/components/sensor/pulse_meter.html
##########################################################################################
# CALIBRATION HINTS
# https://forum.mysensors.org/topic/9594/misol-rain-gauge-tipping-bucket-rain-amount/2
##########################################################################################
- platform: pulse_meter
id: rainfall_meter
pin:
number: GPIO12 #D6 on D1 Mini
mode:
input: true
pullup: true
internal_filter_mode: EDGE
internal_filter: 10ms
name: ${friendly_name} Rainfall
#icon: mdi:
unit_of_measurement: "mm"
accuracy_decimals: 1
timeout: 5s
filters:
- heartbeat: 2s
#- timeout:
# timeout: "5s" #after 5 seconds, if no pulses received....
# value: 0 #make the value = 0
- multiply: 0.2794 #mm of rain from tip bucket, 0.28 mm per pulse, or 3.57 pulse per mm (NEEDS CALIBRATION)
- sliding_window_moving_average: # Moving average to prevent too many data points
window_size: 4
send_every: 1
#- clamp:
# min_value: 0
# max_value: 250 #if anything over that, we have debounce issues or are going to die
# ignore_out_of_range: true
##########################################################################################
# Pulse Meter for measuring wind speed
# Analog sensor for voltage reading
# https://esphome.io/components/sensor/pulse_meter.html
#
# This Anemometer https://www.sparkfun.com/datasheets/Sensors/Weather/Weather%20Sensor%20Assembly..pdf
# The cup-type anemometer measures wind speed by closing a contact
# as a magnet moves past a reed switch. A wind speed of 1.492mph (2.4km/h) (0.667m/s)
# causes the switch to close once per second. The reed switch closes twice per revolution.
# 1rps = 60rpm = 2.4kmh
# 1pulse/min = 2.4kmh/60 = 0.04kmh
# Pulse meter component measures the time between rising edges on a pin,
# for each pulse it outputs the frequency in pulses/min.
##########################################################################################
# USEFUL LINKS
# https://community.home-assistant.io/t/measuring-wind-speed/395693/20
# https://community.home-assistant.io/t/measuring-wind-speed/395693/21
#############################################
- platform: pulse_meter # https://community.home-assistant.io/t/measuring-wind-speed/395693
id: wind_meter
pin:
number: GPIO14 #D5 on D1 Mini
mode:
input: true
pullup: true
#internal: true # If true, don't send to HA/MQTT etc
internal_filter_mode: EDGE
internal_filter: 10ms
name: ${friendly_name} Wind speed
icon: "mdi:weather-windy"
unit_of_measurement: "km/h"
accuracy_decimals: 1
timeout: 5s
filters:
- heartbeat: 2s
#- timeout:
# timeout: "5s" #after 5 seconds, if no pulses received....
# value: 0 #make the value = 0
- multiply: 0.04 #kmh
- sliding_window_moving_average: # Moving average to prevent too many data points
window_size: 4
send_every: 1
- clamp:
min_value: 0
max_value: 250 #if anything over that, we have debounce issues or are going to die
ignore_out_of_range: true
##########################################################################################
# WIND GUSTS WMO-style 10-minute gust
# Per WMO guidance, "gust" ≈ maximum of 3-second mean wind over the last 10 minutes.
# Implementation:
# 1) Compute a 3 s sliding average (updated every 1 s) from wind_meter.
# 2) Take the rolling maximum of that 3 s average over the last 10 minutes.
##########################################################################################
- platform: template
id: wind_speed_3s_avg
name: ${friendly_name} Wind speed (3s avg)
unit_of_measurement: "km/h"
icon: "mdi:weather-windy"
update_interval: 1s
lambda: |-
return id(wind_meter).state; // sample latest wind speed
filters:
- filter_out: nan
- sliding_window_moving_average:
window_size: 3 # 3 samples x 1s = 3 s average
send_every: 1
send_first_at: 1
- platform: template
name: ${friendly_name} Windspeed Gust (Max last 10m)
unit_of_measurement: "km/h"
icon: "mdi:weather-windy"
update_interval: 1s
lambda: |-
return id(wind_speed_3s_avg).state; # use the 3 s average stream
filters:
- filter_out: nan
- max:
window_size: 600 # 600 x 1s = 10 minutes rolling window
send_every: 1
send_first_at: 3 # after first 3 s average becomes meaningful
##########################################################################################
# BEAUFORT SCALE
# Template for Beaufort for measuring wind speed
# The output updates the Text Sensor ID wind_scale
# https://windy.app/blog/wind-speed-beaufort-scale.html
##########################################################################################
- platform: template
#name: ${friendly_name} Windspeed Scale
internal: true # no need to show this externally as it is just for calculating Beaufort
#icon: "mdi:weather-windy"
id: wind_meter_scale
lambda: |-
return id(wind_meter).state;
#unit_of_measurement: "m/s"
update_interval: 5s
filters:
- throttle_average: 5s
- multiply: 0.278 #to get m/s from km/h
on_value:
lambda: |-
if (id(wind_meter_scale).state < 0.1) {
id(wind_scale).publish_state("Calm");
} else if (id(wind_meter_scale).state > 0 && id(wind_meter_scale).state < 2) {
id(wind_scale).publish_state("Light Air");
} else if (id(wind_meter_scale).state >= 2 && id(wind_meter_scale).state < 3) {
id(wind_scale).publish_state("Light Breeze");
} else if (id(wind_meter_scale).state >= 3 && id(wind_meter_scale).state < 5) {
id(wind_scale).publish_state("Gentle Breeze");
} else if (id(wind_meter_scale).state >= 5 && id(wind_meter_scale).state < 8) {
id(wind_scale).publish_state("Moderate Breeze");
} else if (id(wind_meter_scale).state >= 8 && id(wind_meter_scale).state < 11) {
id(wind_scale).publish_state("Fresh Breeze");
} else if (id(wind_meter_scale).state >= 11 && id(wind_meter_scale).state < 14) {
id(wind_scale).publish_state("Strong Breeze");
} else if (id(wind_meter_scale).state >= 14 && id(wind_meter_scale).state < 17) {
id(wind_scale).publish_state("Near Gale");
} else if (id(wind_meter_scale).state >= 17 && id(wind_meter_scale).state < 21) {
id(wind_scale).publish_state("Gale");
} else if (id(wind_meter_scale).state >= 21 && id(wind_meter_scale).state < 24) {
id(wind_scale).publish_state("Severe Gale");
} else if (id(wind_meter_scale).state >= 24 && id(wind_meter_scale).state < 28) {
id(wind_scale).publish_state("Storm");
} else if (id(wind_meter_scale).state >= 28 && id(wind_meter_scale).state < 33) {
id(wind_scale).publish_state("Violent Storm");
} else if (id(wind_meter_scale).state >= 33) {
id(wind_scale).publish_state("Hurricane Force");
} else {
id(wind_scale).publish_state("");
}
#############################################
# WIND DIRECTION SENSOR
# looks like this one
# https://www.sparkfun.com/datasheets/Sensors/Weather/Weather%20Sensor%20Assembly..pdf
# uses black and green cables for R value
#############################################
# Wind Direction, Analogue on ADS115
# Analog sensor for voltage reading
# https://esphome.io/components/sensor/ads1115.html
##########################################################################################
# Using a analog wind direction sensor that has an output
# of 0 - 5 V for 360° representing the position of the arrow
# from the north pole. This is 5V divided by 8 resistor
# values giving the output voltage value for each azimuth.
# We could also report a compass direction.
##########################################################################################
# Useful Links
# https://community.home-assistant.io/t/davis-wind-direction-equipment-and-esp-home/508764
##########################################################################################
- platform: ads1115
multiplexer: 'A0_GND'
gain: 4.096
name: ${friendly_name} Wind Direction Voltage
id: wind_direction_voltage
update_interval: 2s
on_value:
lambda: |-
const float v = x; // use current reading from on_value
if (v >= 0.57816 && v <= 0.58984) {
id(wind_dir_heading).publish_state("E");
} else if (v >= 1.05039 && v <= 1.07161) {
id(wind_dir_heading).publish_state("SE");
} else if (v >= 1.49094 && v <= 1.52106) {
id(wind_dir_heading).publish_state("S");
} else if (v >= 2.08692 && v <= 2.12908) {
id(wind_dir_heading).publish_state("NE");
} else if (v >= 2.53440 && v <= 2.58560) {
id(wind_dir_heading).publish_state("SW");
} else if (v >= 2.87100 && v <= 2.92900) {
id(wind_dir_heading).publish_state("N");
} else if (v >= 3.05712 && v <= 3.11888) {
id(wind_dir_heading).publish_state("NW");
} else if (v >= 3.15414 && v <= 3.21786) {
id(wind_dir_heading).publish_state("W");
} else {
id(wind_dir_heading).publish_state("");
}
##########################################################################################
# BME280 temp/humidity/pressure (Note, BME and BMP Are different...)
# https://esphome.io/cookbook/bme280_environment.html
##########################################################################################
#- platform: bme280_i2c
# address: 0x76
# update_interval: ${update_time}
# temperature:
# name: ${friendly_name} BME280 Temp
# accuracy_decimals: 1
# oversampling: 2x
# unit_of_measurement: "°C"
# #retain: true #MQTT retain useful if sleeping
# pressure:
# name: ${friendly_name} BME280 Pressure
# oversampling: 2x
# unit_of_measurement: "hPa"
# #retain: true #MQTT retain useful if sleeping
# humidity:
# name: ${friendly_name} BME280 Humidity
# accuracy_decimals: 1
# oversampling: 2x
# unit_of_measurement: "%"
# #retain: true #MQTT retain useful if sleeping
##########################################################################################
# TSL2561 ambient light sensor
# https://esphome.io/components/sensor/tsl2561.html
##########################################################################################
#- platform: tsl2561
# name: ${friendly_name} Ambient Light
# address: 0x39
# update_interval: 60s
##########################################################################################
# LTR390 Ambient Light and UV Sensor
# https://esphome.io/components/sensor/ltr390.html
##########################################################################################
#- platform: ltr390
# address: 0x35
# uv_index:
# name: ${friendly_name} 390 UV Index
# uv:
# name: ${friendly_name} 390 UV Sensor Counts
# light:
# name: ${friendly_name} 390 Light
# ambient_light:
# name: ${friendly_name} 390 UV Sensor Counts
# update_interval: 60s
##########################################################################################
# PMSX003 Particulate sensor
# NEEDS UART SET FIRST
# https://esphome.io/components/sensor/pmsx003.html
##########################################################################################
#- platform: pmsx003
# type: PMSX003
# pm_1_0:
# name: ${friendly_name} Particulate Matter <1.0µm
# pm_2_5:
# name: ${friendly_name} <2.5µm
# pm_10_0:
# name: ${friendly_name} <10.0µm Concentration
# filters:
# lambda: |-
# if( (x * (360.0/5.0)) >= 10.0 && (x * (360.0/5.0)) <= 70.0 ) { return x = 45 };
# else if( (x * (360.0/5.0)) > 70.0 && (x * (360.0/5.0)) <= 120.0 ) { return x = 90 };
# else if( (x * (360.0/5.0)) > 120.0 && (x * (360.0/5.0)) <= 170.0 ) { return x = 135 };
# else if( (x * (360.0/5.0)) > 170.0 && (x * (360.0/5.0)) <= 215.0 ) { return x = 180 };
# else if( (x * (360.0/5.0)) > 215.0 && (x * (360.0/5.0)) <= 262.0 ) { return x = 225 };
# else if( (x * (360.0/5.0)) > 262.0 && (x * (360.0/5.0)) <= 330.0 ) { return x = 270 };
# else if( (x * (360.0/5.0)) > 330.0 && (x * (360.0/5.0)) <= 355.0 ) { return x = 315 };
# else if(((x * (360.0/5.0)) > 355.0 && (x * (360.0/5.0)) <= 360.0) || ((x * (360.0/5.0)) >= 0.0 && (x * (360.0/5.0)) <= 10.0)) { return x = 0 };
# - platform: template
# name: ${friendly_name} Winddirection Degrees
# id: wind_direction_voltage
# lambda: return id(wind_direction_voltage).state;
# unit_of_measurement: "degrees"
# update_interval: 5s
# filters:
# - throttle_average: 5s
# on_value:
# lambda: |-
# if (id(wind_direction_voltage).state * (360.0/5.0) >= 10.0 && id(wind_direction_voltage).state * (360.0/5.0) <= 70.0) {
# id(wind_dir_heading).publish_state("45");
# } else if (id(wind_direction_voltage).state * (360.0/5.0) = 70.0 && id(wind_direction_voltage).state * (360.0/5.0) <= 120.0) {
# id(wind_dir_heading).publish_state("90");
# } else if (id(wind_direction_voltage).state * (360.0/5.0) = 120.0 && id(wind_direction_voltage).state * (360.0/5.0) <= 170.0) {
# id(wind_dir_heading).publish_state("135");
# } else if (id(wind_direction_voltage).state * (360.0/5.0) = 170.0 && id(wind_direction_voltage).state * (360.0/5.0) <= 215.0) {
# id(wind_dir_heading).publish_state("180");
# } else if (id(wind_direction_voltage).state * (360.0/5.0) = 215.0 && id(wind_direction_voltage).state * (360.0/5.0) <= 262.0) {
# id(wind_dir_heading).publish_state("225");
# } else if (id(wind_direction_voltage).state * (360.0/5.0) = 262.0 && id(wind_direction_voltage).state * (360.0/5.0) <= 330.0) {
# id(wind_dir_heading).publish_state("270");
# } else if (id(wind_direction_voltage).state * (360.0/5.0) = 330.0 && id(wind_direction_voltage).state * (360.0/5.0) <= 355.0) {
# id(wind_dir_heading).publish_state("315");
# } else if (id(wind_direction_voltage).state * (360.0/5.0) = 355.0 && id(wind_direction_voltage).state * (360.0/5.0) <= 360.0) {
# id(wind_dir_heading).publish_state("0");
# } else {
# id(wind_dir_heading).publish_state("0");
# }
# - platform: ads1115
# multiplexer: "A1_GND"
# gain: 6.144
# name: ${friendly_name} UV Index
# update_interval: 10s
# unit_of_measurement: "mW/cm2"
# accuracy_decimals: 1
# on_value:
# lambda: |-
# if(x > id(g_WindGust_10min)) {
# id(g_WindGust_10min) = x;
# id(id_wind_gust_10min).publish_state(id(g_WindGust_10min));
# };
# //id(g_wind_run) += (x>0) ? 0.000666982 : 0;
# if(x > id(g_WindGust_10s)) {
# id(g_WindGust_10s) = x;
# id(id_wind_gust_10s).publish_state(id(g_WindGust_10s));
# };
# if(x > id(g_WindGust_60s)) {
# id(g_WindGust_60s) = x;
# id(id_wind_gust_60s).publish_state(id(g_WindGust_60s));
# };
# if(id(g_WindSpeedMin_Reset)){
# id(g_WindSpeedMin_10s) = x;
# id(g_WindSpeedMin_Reset) = false;
# } else {
# if(x < id(g_WindSpeedMin_10s)) {id(g_WindSpeedMin_10s) = x;};
# }
# total:
# name: "Roof Wind Run daily"
# id: id_wind_run_daily
# internal: false
# unit_of_measurement: "km"
# accuracy_decimals: 3
# filters:
# - multiply: 0.000666982
# - throttle: 30s
# https://www.reddit.com/r/Esphome/comments/kndues/take_max_value_over_time/
# - platform: template
# name: ${friendly_name} Windspeed last 10min max
# #id: ${node_name}_pm_1_0_rolling_30_minute_average
# unit_of_measurement: "km/h"
# update_interval: 60s
# lambda: |-
# const size_t window_size_ = 10;
# const size_t send_every_ = 10;
# static size_t send_at_ = 0;
# static std::deque<float> queue_;
# if (!isnan(x)) {
# if (queue_.size() >= window_size_) {
# queue_.pop_front();
# }
# queue_.push_back(x);
# }
# if (++send_at_ >= send_every_) {
# send_at_ = 0;
# if (!queue_.empty()) {
# std::deque<float>::iterator it = std::max_element(queue_.begin(), queue_.end());
# return *it;
# }
# return 0.0f;
# }
# return {};
# - platform: pulse_meter
# pin:
# number: GPIO13 #This is Pin D7 on the D1 Mini ESP8266
# mode:
# input: true
# pullup: true
# name: ${friendly_name} Wind speed
# id: wind_meter
# unit_of_measurement: m/s
# accuracy_decimals: 1
# timeout: 5s
# internal_filter_mode: EDGE
# internal_filter: 10ms
# A wind speed of 2.4km/h (1.492mph) causes the switch to close once per second.
# that is 0.667m/s.
# Switch closes twice per revolution
# rotations_per_sec = pulses / 2 / 60
# circ_m = 0.09 * 2 * 3.14 = 0.5652
# mps = 1.18 * circ_m * rotations_per_sec
# mps = 1.18 * (0.5652 / 2 / 60) = 0.0055578
#
# filters:
# # - multiply: 0.0055578 #use for m/s
# # - multiply: 2.237 #m/s to mph
# # - multiply: 0.0124327986 #m/s * mph conversion
# # - multiply: ? #m/s to kph
# - multiply: 0.0055578
# - sliding_window_moving_average: # Helps prevent too many datapoints
# window_size: 10
# send_every: 10
#switch:
# - platform: template
# optimistic: true
# name: switch
# #internal: True
# id: g_WindSpeedMin_Reset
#interval:
# - interval: 10s
# then:
# - lambda: |-
# id(g_WindSpeedMin_Reset).state == true;
# //id(id_wind_gust_10s).publish_state(id(g_WindGust_10s));
# id(id_wind_speed_min_10s).publish_state(id(g_WindSpeedMin_10s));
# //id(id_wind_gust_60s).publish_state(id(g_WindGust_60s));
# //id(id_wind_gust_10min).publish_state(id(g_WindGust_10min));
# id(g_WindGust_10s) = 0;
# // id(g_WindSpeedMin_10s) = 9999.9;
# id(g_WindSpeedMin_Reset) = true;
# - interval: 60s
# then:
# - lambda: |-
# id(g_WindGust_60s) = 0;
# //maintain rain
# //if (++id(g_minute) > 59) id(g_minute) = 0;
# //id(gt_rain_hour)[id(g_minute)] = 0;
# - interval: 10min
# then:
# - lambda: |-
# id(g_WindGust_10min) = 0;
#globals:
# global variables for wind/rain sensors
# - id: g_WindGust_10min
# type: float
# restore_value: no
# initial_value: '0.0'
# - id: g_wind_run_count
# type: int
# restore_value: no
# initial_value: '0'
# - id: g_rain_count
# type: int
# restore_value: no
# initial_value: '0'
# - id: gt_rain_hour
# type: byte[60]
# restore_value: no
# - id: g_minute
# type: byte
# restore_value: no
# initial_value: '0'
# - id: g_WindGust_10s
# type: float
# restore_value: no
# initial_value: '0.0'
# - id: g_WindSpeedMin_10s
# type: float
# restore_value: no
# initial_value: '9999.9'
# - id: g_WindGust_60s
# type: float
# restore_value: no
# initial_value: '0.0'