Here is my weather station project. This is a cheap wireless weather station I modified with an ESP32 & programmed with the wonderful ESPHome.
I choose to completely remove the original electronics because I wanted to receive data from the sensors at a shorter interval and I can’t be bothered decoding the wireless signal sent.
This is the cheap weather station I purchased. I will not be using the battery powered LCD display.
Weaknesses of this weather station is construction quality.
The metal stand is not stainless steel, nor galvanised or aluminium.
The plastic sensors are likely to breakdown in sunlight UV (as I have seen on another unit).
I painted the sensor units with outdoor rated white spray paint.
The sensors;
Anemometer (Wind speed)
This is a wind cup anemometer and the number of rotations per time period can be used to calculate wind speed.
I found this unit has a magnetic reed switch and a magnet. Two pulses are given per full rotation of the wind cups.
Bearing direction (Wind vane)
This uses 4 magnetic reed switches, for North, East, South & West.
When pointed North, the North reed switch closes and connects a resistor in parallel to the sensor’s wires.
Each direction has a different resistance per direction.
Directions between, e.g. North East, are the resistance value of two resistors in parallel.
I can’t remember off the top of my head what the resistor values were. I connected the sensor across a voltage divider and used an ADC sensor. Value ranges of the ADC correlated to a direction.
Rain gauge
This is a tipping bucket rain gauge. Rain water falls into a funnel and feels a small bucket. When the bucket fills with water it tips over under gravity and activates a magnetic reed switch. The count of bucket tips is the measured rain.
This rain gauge is 0.3mm per bucket tip.
Temperature + Humidity
I removed the original temperature sensor and utilised a DHT22 sensor.
esphome:
name: weather-station-esp32
friendly_name: weather_station_esp32
esp32:
board: esp32dev
framework:
type: arduino
#Buch of stuff here.
#Pinouts:
#DHT22 - 18/D18
#Anemometer - 32/D32
#Wind direction - 34/D34
#Rain gauge - 33/D33
button:
- platform: template
name: "Reset total rain"
id: stationraintotal_reset
icon: "mdi:rotate-left"
on_press:
- pulse_counter.set_total_pulses:
id: stationrain
value: !lambda 'return 0;'
sensor:
# DHT temp + humidity sensor
- platform: dht
pin: GPIO18
model: DHT22
temperature:
name: "Station Temperature"
id: stationtemperature
filters:
filter_out: nan
humidity:
name: "Station Humidity"
id: stationhumidity
filters:
filter_out: nan
update_interval: 120s
- platform: absolute_humidity
name: Station Absolute Humidity
temperature: stationtemperature
humidity: stationhumidity
filters:
filter_out: nan
# Wind anemometer
# 2 Pules per rotation
- platform: pulse_counter
name: Station Wind Speed
id: stationwindspeed
pin:
number: GPIO32
inverted: true
mode:
input: true
pullup: true
update_interval: 10s
filters:
- lambda: if (x < 0.001) return x; else return 1.761 / (1 + (x / 2 * 0.02010619298) ) + 3.013 * (x / 2 * 0.02010619298);
- sliding_window_moving_average:
window_size: 12
send_every: 6
unit_of_measurement: 'Km/h'
device_class: wind_speed
on_value:
then:
- component.update: stationknots
#Km/h to knots
- platform: template
name: Station wind speed knots
id: stationknots
lambda: |-
return id(stationwindspeed).state * 0.53996;
unit_of_measurement: 'knt'
# Feels like temperature
- platform: template
name: "Feels Like Temperature"
id: stationfeelslike
update_interval: 120s
unit_of_measurement: '°C'
filters:
filter_out: nan
lambda: |-
float T = id(stationtemperature).state; // Replace with your temperature sensor
float RH = id(stationhumidity).state; // Replace with your humidity sensor
float WS = id(stationwindspeed).state; // Replace with your wind speed sensor
float HI;
T = T * 9/5 + 32; // Convert temperature from Celsius to Fahrenheit for the formula
if (T < 80.0) {
HI = 0.5 * (T + 61.0 + ((T-68.0)*1.2) + (RH*0.094));
} else {
HI = -42.379 + 2.04901523*T + 10.14333127*RH - 0.22475541*T*RH - 6.83783*pow(10,-3)*pow(T,2) - 5.481717*pow(10,-2)*pow(RH,2) + 1.22874*pow(10,-3)*pow(T,2)*RH + 8.5282*pow(10,-4)*T*pow(RH,2) - 1.99*pow(10,-6)*pow(T,2)*pow(RH,2);
if (RH < 13 && T >= 80 && T <= 112) {
float adjust = ((13-RH)/4) * sqrt((17-abs(T-95))/17);
HI -= adjust;
} else if (RH > 85 && T >= 80 && T <= 87) {
float adjust = ((RH-85)/10) * ((87-T)/5);
HI += adjust;
}
}
return (HI - 32) * 5/9; // Convert back to Celsius
#Rain gauge
- platform: pulse_counter
pin:
number: GPIO33
inverted: true
mode:
pullup: true
input: true
unit_of_measurement: 'mm/min'
name: 'Station Rain'
id: stationrain
update_interval: 60s
accuracy_decimals: 1
filters:
- debounce: 0.05s
- multiply: 0.3 # pulses x 0.3mm
total:
unit_of_measurement: 'mm'
name: 'Station Total Rain'
accuracy_decimals: 1
filters:
- multiply: 0.3
#Wind direction
- platform: adc
name: "Station Wind Dir"
id: station_winddirection
internal: true
pin: 34
accuracy_decimals: 0
unit_of_measurement: 'ADC'
raw: true
filters:
- multiply: 1.0
- median:
window_size: 6
send_every: 6
send_first_at: 1
- platform: template
name: "Station Wind Direction bearing"
id: stationwinddirection_int
unit_of_measurement: '°'
lambda: |-
if (id(station_winddirection).state > 1500 && id(station_winddirection).state <= 1700) {
return 90.0; //North - offset to west
}
else if (id(station_winddirection).state > 650 && id(station_winddirection).state <= 800) {
return 135.0; //North East
}
else if (id(station_winddirection).state > 900 && id(station_winddirection).state <= 1100) {
return 180.0; //East
}
if (id(station_winddirection).state > 800 && id(station_winddirection).state <= 900) {
return 225.0; //South East
}
if (id(station_winddirection).state > 1900 && id(station_winddirection).state <= 2300) {
return 270.0; //South
}
if (id(station_winddirection).state > 1700 && id(station_winddirection).state <= 1900) {
return 315.0; //South West
}
if (id(station_winddirection).state > 2300 && id(station_winddirection).state <= 2500) {
return 0.0; //West
}
if (id(station_winddirection).state > 1100 && id(station_winddirection).state <= 1500) {
return 45.0; //North West
}
else {
return 345.0; //Fault
}
update_interval: 60s
This is an ESP32 module from AliExpress.
On the circuit board is terminal connectors, a power switch, 12v to 5v buck step down module and an LDR’s pcb. I have an LDR for light levels but never calibrated it (still does alright to schedule garden lights).
The station itself is mounted to my TV antenna on the back of my house. Power cables runs under a roof tile and is connected in a cupboard to a 12v PSU.