############################################# ############################################# # Opengreen energy weather station board, with ESP8266 D1 Mini # https://www.opengreenenergy.com/solar-powered-wifi-weather-station-v2-0/ # zorruno 2024-05-04 V0.0 Untested # zorruno 2024-05-23 V1.0 Tidied up sensor info and added BMP280 # zorruno 2024-05-24 V1.1 Tested ok and added some V calibration for mine # zorruno 2024-05-25 V2 A bunch more sensors added (wind direction not yet sorted) # zorruno 2024-05-25 V3 Shuffled some sensors, rain count added # zorruno 2024-06-03 V4 tweaks to battery and wind # zorruno 2024-06-14 V5 added wind heading, and sorted breaking a change for OTA ############################################# ############################################# ############################################# # 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 ############################################# 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: |- return ( id(bmp280_temp).state + id(dht_temp).state ) / 2; ################################ # 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 #40x 30s = 20 min average period send_every: 1 send_first_at: 1 ################################ # A Calculation of recent 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 10s lambda: > return id(battery_voltage).state; //grabs values from the battery_voltage filters: - heartbeat: 30s - max: window_size: 60 #60x 30s = 30 min max value 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 av 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 Anenometer 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 10 MINUTE MAX # Template for wind gust measurements # To measure GUST properly, the World Meteorological Organization # recommends gust measurement should be wind speed averages over # 3 second periods and report the maximum of these averages # within a sliding window of the last 10 minutes. # This needs a wind speed history buffer of 200 samples # (200 x 3 second average = 10 minutes) ################################ # Useful links # https://community.home-assistant.io/t/adding-an-old-marine-anemometer-to-ha/337842 ################################ - platform: template name: ${friendly_name} Windspeed Gust (Max last 10m) unit_of_measurement: "km/h" update_interval: 3s #updates every 2s lambda: > return id(wind_meter).state; //grabs values from the wind_sensor filters: - filter_out: nan #in case there is no value - max: window_size: 200 #10 Min window as 3s update x 200 = 10min send_every: 1 #updates on the 1st 2s check send_first_at: 1 #on restart, send after first 10s ################################ # 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 ################################################################ # CONVERT VOLTAGE TO HEADING # Version used here only has 8 heading points, some have 16. # # Bear R Head Meas'd Max Min # (deg) (Ohms) Volts V+1% V-1% # --------------------------------------------- # 0 33000 N 2.900 2.9290 2.8710 # 22.5 6570 NNE # 45 8200 NE 2.108 2.1290 2.0869 # 67.5 891 ENE # 90 1000 E 0.584 0.5898 0.5782 # 112.5 688 ESE # 135 2200 SE 1.061 1.0716 1.0504 # 157.5 1410 SSE # 180 3900 S 1.506 1.5211 1.4910 # 202.5 3140 SSW # 225 16000 SW 2.560 2.5856 2.5344 # 247.5 14120 WSW # 270 120000 W 3.186 3.2178 3.1541 # 292.5 42120 WNW # 315 64900 NW 3.088 3.1188 3.0571 # 337.5 21880 NNW ################################################################ on_value: lambda: |- if (id(wind_direction_voltage).state >= 0.57816 && id(wind_direction_voltage).state <= 0.58984) { id(wind_dir_heading).publish_state("E"); } else if (id(wind_direction_voltage).state >= 1.05039 && id(wind_direction_voltage).state <= 1.07161) { id(wind_dir_heading).publish_state("SE"); } else if (id(wind_direction_voltage).state >= 1.49094 && id(wind_direction_voltage).state <= 1.52106) { id(wind_dir_heading).publish_state("S"); } else if (id(wind_direction_voltage).state >= 2.08692 && id(wind_direction_voltage).state <= 2.12908) { id(wind_dir_heading).publish_state("NE"); } else if (id(wind_direction_voltage).state >= 2.5344 && id(wind_direction_voltage).state <= 2.5856) { id(wind_dir_heading).publish_state("SW"); } else if (id(wind_direction_voltage).state >= 2.871 && id(wind_direction_voltage).state <= 2.929) { id(wind_dir_heading).publish_state("N"); } else if (id(wind_direction_voltage).state >= 3.05712 && id(wind_direction_voltage).state <= 3.11888) { id(wind_dir_heading).publish_state("NW"); } else if (id(wind_direction_voltage).state >= 3.15414 && id(wind_direction_voltage).state <= 3.21786) { id(wind_dir_heading).publish_state("W"); } else { id(wind_dir_heading).publish_state({}); } # 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 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::iterator it = std::max_element(queue_.begin(), queue_.end()); # return *it; # } # return 0.0f; # } # return {}; # - platform: template # name: "Roof Wind Run daily" # icon: "mdi:weather-windy" # unit_of_measurement: "km" # accuracy_decimals: 3 # update_interval: 30s # internal: true # lambda: |- # return id(g_wind_run_count)*0.000666982; # id: id_wind_run_daily_g # - platform: template # name: "Roof Wind gust 10s" # unit_of_measurement: 'km/h' # update_interval: 10s # id: id_wind_gust_10s # lambda: return id(g_WindGust_10s); # # - platform: template # name: "Roof Wind gust 60s" # unit_of_measurement: 'km/h' # state_class: "measurement" # update_interval: 60s # id: id_wind_gust_60s # lambda: return id(g_WindGust_60s); # - platform: template # name: "Roof Wind gust 10min" # unit_of_measurement: 'km/h' # state_class: "measurement" # update_interval: 10min # id: id_wind_gust_10min # lambda: return id(g_WindGust_10min); # - platform: template # name: "Roof Wind speed avg 1s" # unit_of_measurement: 'km/h' # update_interval: 333ms # lambda: |- # return id(id_wind_speed).state; # filters: # throttle_average: 1s # id: id_wind_speed_avg_1s # # - platform: template # name: "Roof Wind speed avg 10s" # unit_of_measurement: 'km/h' # update_interval: 333ms # lambda: |- # return id(id_wind_speed).state; # filters: # throttle_average: 10s # id: id_wind_speed_avg_10s # # - platform: template # name: "Roof Wind Speed Min 10s" # unit_of_measurement: 'km/h' # id: id_wind_speed_min_10s # # - platform: template # name: "Roof Wind speed avg 1min" # unit_of_measurement: 'km/h' # state_class: "measurement" # update_interval: '1s' # lambda: |- # return id(id_wind_speed).state; # filters: # - throttle_average: 1min # id: id_wind_speed_avg_1min # # - platform: template # name: "Roof Wind speed avg 10min" # unit_of_measurement: 'km/h' # state_class: "measurement" # update_interval: 1s # lambda: |- # return id(id_wind_speed).state; # filters: # - throttle_average: 10min # id: id_wind_speed_avg_10min # - 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' ################################ # 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