Community. Driven. Weather. Data. | Always Ad-Free | Developer FriendlyChecking statusDiscord
WxAlerts.org, Community Driven Weather Data
Support us
Sign in
Weather stations

Building one from scratch

Sensor selection, the firmware details that decide whether your data is any good, pressure reduction, parts lists by budget, and the siting standards to document honestly.


Building a station is entirely feasible with an ESP32 and a weekend. Whether it produces good data comes down to a handful of details (gust windowing, vector-averaging wind direction, pressure reduction and radiation shielding) that are easy to get wrong and invisible when you do.

Anemometer

Cup anemometers with a reed or hall pulse output are the usual choice. Propeller-on-a-vane designs work. Ultrasonic sensors have no moving parts and no cut-in speed, which makes them the best option for a low-maintenance safety installation if the budget allows. Hot-wire is research equipment.

Pulses to speed

A reed switch closes some number of times per revolution. Convert with a linear calibration, v = k·f + v0, where f is pulses per second. The slope and offset come from a wind tunnel or a reference instrument, not from theory.

Two constants worth knowing, because so much hardware descends from them:

  • Fine Offset, SparkFun and Argent cup assemblies: one switch closure per second equals 2.4 km/h (1.492 mph). The Fine Offset sensor gives two pulses per revolution, and its console counts over 2-second windows, giving 0.75 mph resolution steps. The empirical anemometer factor, wind speed divided by cup speed, is about 3.
  • Davis 6410 and Vantage: one closure per 2.25 s equals 1 mph, so v_mph = 2.25 · N counted over 2.25 s.

To derive your own, mount alongside a trusted station and regress, or do a calm-day car test at steady GPS speed on a genuinely windless day. Expect the best accuracy, around ±1%, between 5 and 15 m/s. Below 3 m/s the offset dominates, and above about 30 m/s cups flex and under-read.

Sustained and gust, done correctly

This is where most home-built firmware quietly diverges from every official station it will be compared against.

Definition
Sustained (NWS/METAR) A 2-minute average
WMO synoptic mean A 10-minute average
Gust The peak 3-second average in the period

A gust is not the single fastest pulse interval. It is the maximum of a 3-second sliding average. Implement it with a ring buffer of samples at 1 Hz or better, and debounce reed switches by roughly 1 to 5 ms, or use a hall sensor and skip the problem.

Wind vane

The classic Fine Offset and Argent vane is a resistor ladder: eight reed switches, each with a distinct resistor, and a magnet that closes one, or two adjacent ones, whose parallel resistance gives the value in between, for 16 discrete positions. Read it through a voltage divider into an ADC and map ranges to azimuth with a lookup table. There is a dead-band of about 10°.

A better choice for a new build is the AS5600: 12-bit, contactless, 0.1° resolution, no dead-band, nothing to wear out, I²C, and cheap.

Two details that ruin wind direction

Align to true north, not magnetic north. Look up your magnetic declination by latitude and longitude with NOAA NCEI’s calculator and correct for it. A declination of −4° means magnetic north sits 4° east of true.

Vector-average with sine and cosine components. Never average degrees. Averaging 350° and 10° numerically gives 180°, exactly backwards. The correct form is:

mean_dir = atan2(Σ sin θ, Σ cos θ)

This is not a refinement. A station that averages degrees reports garbage whenever the wind sits near north, which is most of the winter in much of the country.

Temperature and humidity

Sensor Accuracy Verdict
Sensirion SHT31/35, SHT41/45 ±0.2–0.3 °C, ±2% RH The DIY gold standard, low drift
BME280 ±1 °C Adequate, and gives you pressure too
BME680 as BME280 Adds gas sensing you probably do not need
HDC302x, Si7021 good Fine alternatives
AM2302 / DHT22 poor Avoid: slow, drifty, high failure rate

Watch for self-heating: mount the sensor away from the microcontroller, and never inside a sealed box in the sun.

Radiation shields

This is where citizen temperature data lives or dies.

A Stevenson screen is the classic wooden double-louvred reference, and it is bulky. A multi-plate Gill-style shield is the standard naturally ventilated AWS design, with radiation error typically around 0.5 K and occasionally 2–3 K in light wind and strong sun. An aspirated shield with a forced-draught fan is the accurate answer, around 0.1 °C, at the cost of power and a fan that can fail.

A stack of downturned plastic plant saucers with spacers makes a serviceable multi-plate shield for very little money, and adding a small 5 V fan gets you close to research quality. Mount over grass rather than pavement, 1.25 to 2 m up, well clear of walls.

Pressure

BMP390 and BMP581 have low drift; MS5611 is high resolution; DPS310 is cheap and good; BME280 is fine. Stability matters far more than absolute accuracy, because you are going to calibrate out an offset anyway.

Three pressures, and only one of them goes in the packet

Station pressure (QFE) The raw reading at your elevation
Altimeter setting Reduced to sea level using the ISA standard atmosphere, ignoring actual temperature. What aviation uses
Sea-level pressure (MSLP) Reduced using the actual mean column temperature. This is what CWOP’s b field wants

The hypsometric reduction:

Psl = Pstn · exp( g·H / (Rd · Tv) )

g  = 9.80665 m/s²      H  = elevation, metres
Rd = 287.05 J/kg·K     Tv = mean virtual column temperature, kelvin

Worked, from the NWS reference implementation: at H = 600 m, surface temperature 11 °C and station pressure 942.1 hPa, you get 1013.25 hPa. Change the assumed column temperature to 2 °C and it becomes 1015.6; to 20 °C and it becomes 1011.0.

Rain

The tipping bucket is the standard: each tip is a fixed volume, sensed by a reed switch. Common calibrations are 0.01 inch in the US or 0.2 mm metric; Davis uses 0.2794 mm per tip. Debounce by around 10 ms. Calibrate by pouring a known volume slowly and counting tips.

Understand what it will miss. Undercatch at high wind is significant, and an Alter shield reduces it. Unheated gauges miss snow entirely; a heated gauge melts frozen precipitation so it can be counted. Weighing gauges and optical or acoustic disdrometers are the higher-end answers.

Solar radiation and UV

Apogee SP-series, the Davis pyranometer, or a cheap silicon photodiode.

Be careful converting lux to W/m². Lux is weighted to the human eye, and the common approximation of about 0.0079 W/m² per lux for daylight is rough. A real pyranometer measures broadband irradiance, which is what CWOP’s luminosity field expects. For UV, a VEML6075 or LTR390 calibrated against the EPA UV index.

Soil, optionally

Capacitive soil moisture probes (avoid resistive ones, they corrode) and buried DS18B20 temperature sensors are cheap agricultural extras. They have no place in the APRS weather format, but they make useful telemetry.

Parts by budget

Tier Cost Wind T/RH Pressure Rain Compute Shield
Minimal under $100 Fine Offset / SparkFun cup and vane kit BME280 in the BME280 FO tipping bucket ESP32 dev board DIY saucer stack
Solid ~$300 Davis 6410, or FO cups with an AS5600 vane SHT31 BMP390 Davis or Ecowitt bucket ESP32-S3 or Pi Zero 2 W Multi-plate Gill type
Near-research ~$800 Ultrasonic, or Davis Pro2 SHT45, aspirated MS5611 / BMP581 Heated bucket with Alter shield Pi with industrial encoder Fan-aspirated

Choosing the compute

Board Strengths Weaknesses Best for
ESP32 / S3 / C6 WiFi and BLE, deep sleep, cheap, hardware pulse counters; C6 adds Thread and Zigbee Noisy ADC, analog needs care Battery WiFi stations, ESPHome
Pi Pico W Cheap, PIO for precise pulse timing, MicroPython WiFi only, no Linux Tidy MicroPython builds
Pi Zero 2 W Full Linux, so it runs WeeWX and Direwolf directly 1–2 W, no deep sleep Mains or solar bridge, and RF
Arduino (AVR) Dead-simple interrupts No WiFi, 8-bit Sensor front end only

Count wind pulses with hardware, the ESP32’s PCNT or the Pico’s PIO, and hardware interrupts. Never poll in a slow main loop; you will silently under-read in exactly the high-wind conditions that matter most.

Firmware

ESPHome is YAML rather than C, and integrates natively with Home Assistant:

esphome:
  name: wxstation
esp32:
  board: esp32dev
i2c:
  sda: GPIO21
  scl: GPIO22

sensor:
  - platform: pulse_counter          # anemometer (Fine Offset)
    pin:
      number: GPIO14
      mode: INPUT_PULLUP
    name: "Wind Speed"
    id: wind_mph
    unit_of_measurement: "mph"
    update_interval: 3s              # 3 s aligns with the gust definition
    count_mode:
      rising_edge: INCREMENT
      falling_edge: DISABLE
    internal_filter: 13us            # debounce
    filters:
      - multiply: 0.746              # counts/3s -> mph. CALIBRATE THIS

  - platform: adc                    # resistor-ladder vane
    pin: GPIO34
    name: "Wind Dir Raw"
    id: vane_v
    update_interval: 3s
    attenuation: 12db

  - platform: bme280_i2c
    address: 0x76
    temperature: {name: "Temp"}
    humidity: {name: "Humidity"}
    pressure: {name: "Station Pressure", id: p_stn}

Map the vane’s ADC ranges to degrees in a lambda lookup, and do the MSLP reduction and the sine/cosine direction averaging either on-device in a lambda or downstream. ESPHome also has as3935_i2c and as3935_spi components for lightning detection.

Tasmota works but is less flexible for custom sensors. PlatformIO or Arduino C++ gives full control and is the right choice for hard real-time pulse timing and power management. MicroPython and CircuitPython develop fast, but watch timing jitter on pulse counting; use the Pico’s PIO.

Meshtastic deserves a mention here: it is not an APRS transport, but it will carry sensor telemetry over a LoRa mesh where there is no WiFi or cell service, and you can bridge to CWOP at whichever node does have internet. If you already run a mesh, see MeshMonitor for the other direction: WxAlerts warnings onto that same mesh.

Enclosures and survival

Use an IP65 or better enclosure with cable glands on the bottom face, never open holes. Put desiccant inside and replace it periodically. Use UV-stabilised plastics; cheap ABS chalks and cracks within a season or two.

The failure nobody plans for is insects. Wasps nest in rain funnels and anemometer bodies, and spiders web across moving parts. Fine stainless mesh over openings solves most of it.

On the Gulf Coast or anywhere coastal, plan for salt corrosion: marine or stainless hardware, conformal-coated PCBs, and no dissimilar metals in contact.

Siting, and documenting it honestly

WMO No. 8, the CIMO Guide, defines siting classes 1 through 5 per variable, where 1 is ideal and 5 is severely compromised.

  • Wind: anemometer at 10 m over open terrain, with obstacles more than 10 times their own height away, though some references relax that to 4 times.
  • Temperature and humidity: 1.25 to 2 m over natural ground, away from pavement and buildings.
  • Rain: level, and clear of obstacles by at least twice, ideally four times, their height.

Where to go next