Help with calibrating wind speed on weather station

Hi,

I have had my weather station running for a while now, but the Wind Speed seems to be the only thing that is not quite right.

I am curious as to how people are actually able to calibrate the wind speed? Do you use a known wind speed source? I have tried with a hand help anemometer but the wind fluxgate’s so much its hard to actually calibrate.

Right now, my wind speed is measure between 3000 and 5000km/s which I really hope is not right.

How can I get this right? I have calibrated the rain sensor and everything but the wind I have had so much trouble with. I have a 5 inch anemometer prop.

My code is as follows.

I would appreciate any help with this. Thanks

esphome:
  name: "weather-station"
  friendly_name: "weather-station"
  platform: ESP32
  board: esp-wrover-kit
  comment: 'Ethernet'

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: ""
  on_client_connected:
    - light.turn_on:
         id: led
         brightness: 100%
         red: 0%
         green: 100%
         blue: 0%
         effect: none
  on_client_disconnected:
     - light.control:
         id: led
         state: on
         effect: ERROR

ota:
  - platform: esphome
    password: ""
    
i2c:
  sda: 2
  scl: 4
#  scan: True
  id: bus_a

web_server:
  port: 80
  log: true
  local: True
  include_internal: true
  version: 3
  auth:
    username: !secret web_server_username
    password: !secret web_server_password

ethernet:
  type: LAN8720
  mdc_pin: GPIO23
  mdio_pin: GPIO18
  clk_mode: GPIO0_IN
  phy_addr: 1
  power_pin: GPIO16


  # Optional manual IP
  manual_ip:
    static_ip: 172.16.102.17
    gateway: 172.16.102.1
    subnet: 255.255.255.224

sensor:
####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: GPIO15
      mode: INPUT
    unit_of_measurement: 'mm'
    name: "${friendly_name} rain gauge"
    icon: 'mdi:weather-rainy'
    id: rain_gauge
    count_mode:
      rising_edge: DISABLE
      falling_edge: INCREMENT
    internal_filter: 13us
    update_interval: 1s
    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: GPIO12
      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: 1.2
#      - sliding_window_moving_average:
#          window_size: 5
#          send_every: 5

  - 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 Speed END####

####Wind Direction Start####
  - platform: mlx90393
    address: 0x0c
    id: mlx
#    gain: 1X
    x_axis:
      name: "mlx_x"
      id: "mlx_x"
      resolution: 16BIT
    y_axis:
      name: "mlx_y"
      id: "mlx_y"
      resolution: 16BIT
    z_axis:
      name: "mlx_z"
      resolution: 16BIT
    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 += 50.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: 14
    chipset: WS2812
    num_leds: 1
    rgb_order: GRB
    restore_mode: ALWAYS_OFF
    effects:
      - lambda:
          name: "ERROR"
          update_interval: 1s
          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: 1s
          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

button:
  - platform: restart
    name: "Weather Station Reboot"

Manufacturer didn’t supply any information for pulse/speed conversion??

You need to calibrate the pulse_meter sensor to some known wind speed.
Remove the multiply 1.2
Output is pulses/minute.
Observe what it outputs while also measuring with your hand held anemometer.
Post what you get.

No, these devices certainly we not designed to be modified.

I have reached out to the manufacturer for the pulse count, they gave me the anemometer size, I replied asking for pulse count.

Will do and will let you know

So im not sure if this helps at all, but just a basic RAW pulse counter, obv the wind is blowing.

image

It’s very hard to me to imagine that wind speed pulse sensor is giving 3000 pulses/minute. While possible, not probable.
Does it react to different speeds?

I should provide the code in case I messed something up. This is using GPIO12 on a WT32-ETH01

  - platform: pulse_meter
    pin:
      number: GPIO12
      mode: INPUT
    id: wind_speed
    name: Wind Speed Raw Pulse

My questions to support,

Q: Could you please provide me the details of the dimensions for the propeller on the Kestrelmet 6000 Anemometer?
A. It is a 5 inch diameter anemometer.

Q. Also would you happen to know how many pulses per rotation the pulse counter is?
A. This is proprietary, sorry.

They dont want to share.

Shit, do I need a pullup or pull down resistor over the pulse_counter?

Elon is talking about going to Mars and you’re already living in the middle of Jupiter’s giant red eye storm. Noice.

Making the multiply value very small, brings my pulse counts down significantly, this is obviously guessing.

    filters:
      - multiply: 0.003086

image

I think your best bet is to calibrate with a known measurement like your handheld. Instead of wind, use a more consistent source like an oscillating fan.

How do I know the fans wind speed haha

in your orignal post you mentioned a hand held anemometer?

Yea I’ll have to find it,

The the plan is, measure the wind speed of the fan, then adjust the multiplier value until the weather station matches the speed of the fan?

Is this a sufficient method to calibrate? Can I assume that different wind speeds will be correct?

If there’s not built in resistor, you need to implement one with mode: INPUT_PULLUP (or pulldown).

Initially yes.
Later you can fine tune it with some calibrate_linear for example.

What value resistor? Where can I find that information?

Thanks

mode: INPUT_PULLUP
uses Esp internal pullup, you don’t need to worry about it.
But you have to try if you need pullup or pulldown (or neither).

If I was you I would add total option on your pulse_counter and observe the behavior while turning the sensor 360deg by hand

Hello @deanfourie. Since you already know the distance the cups move in one rotation (2 x 3.14 x r), all you now need to know is the number of times the relay is activated in one rotation. As @Karosm mentioned you can use multimeter and turn the cup by hand OR use the total function in ESPHome pulse sensor and watch as you turn by hand. Most anemometers are 1 pulse

With that and some maths you know exactly the wind speed and therefore can calculate in km/h knots etc.

Next stage is pull up to avoid bouncing (and capacitor if you experience erratic spikes which I do). You can also add debounce through

  • internal_filter

And I use a median or quantile filters to smooth out. And many templates to capture lulls and gusts

I am by open coastline and can constantly compare my readings with marine commercial shipping lane stations. Cup positioning is more important than anything; so 3 -4 m above highest roof line and a good distance away from other objects. I ended up with a calibration of 1.08 i.e.8%

Ok thanks, its bit of a mission to pull this thing off the roof, so I want to have a whole bunch of stuff to test when its down,

So if you think of anything else I can do to test to get this sorted, then I will pull it down and try.

I will trying with the TOTAL value and rotation the prop
I will try measuring the pulses with continuity with my multimeter.
I will check and test with a PULLUP and PULLDOWN resistor.
I will test with INPUT_PULLUP

Just to confirm, you want me to setup the pulse counter as basic as possible, with the total option, and count the total amount of pulses per rotation.

Thanks

You can use INPUT_PULLDOWN as well,
no need to physically change the circuit. Which one it is depends how the wind sensor is wired to the Esp.
It’s important to get pulses that match the rotations, not some random noise or debounces. Calibration itself is quite straightforward.