Measuring wind speed

Here is code I use for wind speed/gust measurement (on ESP32), works OK.
It calculates min/max gust over predefined periods + avg for wind speed.

in globals section:

globals:
# global variables for wind/rain sensors
  - 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'
  - id: g_WindGust_10min
    type: float
    restore_value: no
    initial_value: '0.0'

wind sensor:

sensor:
  - platform: pulse_meter
  # # 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 switch. A wind speed of 1.492 MPH (2.4 km/h)
  # # causes the switch to close once per second.
  # # 1rps = 60rpm = 2.4kmh
  # # 1pulse/min = 2.4kmh/60 = 0.04kmh

  # It measures the time between rising edges on a pin, for each pulse it outputs the frequency in pulses/min.
    id: id_wind_speed
    pin: GPIO26
    internal: true
    # internal_filter_mode: EDGE
    internal_filter: 10 ms
    unit_of_measurement: 'km/h'
    name: "Roof Wind speed"
    icon: 'mdi:weather-windy'
    accuracy_decimals: 7
    timeout: '5s'
    filters:
    - multiply: 0.04 #kmh
    on_value:
      - lambda: |-
          //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(x > id(g_WindGust_10min)) {
            id(g_WindGust_10min) = x;
            id(id_wind_gust_10min).publish_state(id(g_WindGust_10min));
          };
          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

Different wind speeds/gusts calculations inside template sensors:

  - 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

with help of interval:

interval:
  - interval: 10s
    then:
      - lambda: |-
          //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;
1 Like

Thanks for this, but I get a compile error:

Couldnt find ID "g_WindSpeedMin_Reset"

Hi Jimmy, the reason I used pulse_meter is that it reports the pulse frequency in pulses/min on every pulse recieved. pulse_counter reports pulses within a specified period of time in pulses/min. So they are not that different; I chose to use pulse_meter as it offers better data resolution (the sensor receives more pulses the faster the wind blows, so it catches more data of wind gusts).

I have never had any trouble with inconsistent or errant wind data from this sensor using pulse_meter. If you are seeing a gust, know that one way or the other your ESP is recording many pulses. So whether there is interference, or if your wiring is not correct, I am not aware of any issues with pulse_meter on the ESP32 using my setup and pin config. Is it possible you were handling the sensor and turning the anemometer during this time period? I have provided myself with bogus data in this way and caused confusion before.

Per your error Couldnt find ID "g_WindSpeedMin_Reset", it appears that this variable is not defined in any of the code provided by kluszczyn. I suspect it may be a template switch that allows the user to reset the WindSpeedMin in home assistant. Perhaps he forgot to attach as switches are in a different area of the yaml. So you may want to add some code like such:

switch:
  - platform: template
    id: g_WindSpeedMin_Reset

@kluszczyn, thank you for sharing your config and very detailed solutions! For the time being I use statistics sensors in home assistant to handle gust calculation, but your code looks very nice for a native solution in ESPhome.

Edit: Mean to attach this info on pulse_counter vs. pulse_meter: Pulse_counter vs pulse_meter - ESPHome - Home Assistant Community (home-assistant.io)

1 Like

Thanks for the additional info @devjklein - would you be able to post your complete code for this please?
Iā€™m still having issues with it reporting gusts of 76mph, on a still day! I suspect I have the math messed up somewhere!

The full code for my weather station and my home assistant sensor and template yaml files is located here at my github repository: devjklein/esphome-weatherstation: A repository for my configuration of an ESPHome-based weather station (github.com)

1 Like

Awesome, thank you sir :slight_smile:

Hey @jimmyeao, hey all,

did you got your wrong windspeed-data fixed? I have exactly the same problem with getting extremely high speed-data for short periods of time. Iā€™ve tried to search for others with this problem but canā€™t find any, expected you in this thread.

This is my wind-speed-graph. More or less the same picture as you described in your post.

sensor:
  - platform: pulse_meter
    pin:
      # PULUP-Widerstand 10kOhm
      number: GPIO25
      mode: INPUT_PULLUP
    id: wind_speed
    unit_of_measurement: 'm/s'
    name: "Aktuelle Windgeschwindigkeit (m/s)"
    icon: 'mdi:weather-windy'
    #internal_filter: 13us
    timeout: 5s
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 15
      #espHome pulse_meter gibt den Wert in pulses/min aus / Laut Datasheet bedeutet  1 pulse/sec = 2,4km/h
      # Wir rechnen also: 2,4km/h / 60 / 3,6 / 2 (60 weil pulses/min -> pulses/sec; 3,6 weil km/h -> m/s; 2 weil 2 Ticks pro Umdrehung)
      - multiply: 0.005555556

This is my ESPHome Code-Snippet for calculating the wind speed in m/s (I also have a sensor for km/h - It multiplys the value of the m/s sensor with 3.6 for getting the speed in km/h).
I tried to play around with the internal_filter and the sliding_window_moving_average - but nothing helps.

Any tips what could be wrong?

My setup is an ESP32-DevKit-V1 + SparkFun Weather-MeterKit (windspeed, wind direction, rain gauge) + BME280 + ESPHome 2022.9.2

Thanks everyone!

Hi chm3r,

This is a very strange behaviour. Up until a week ago I did not notice any anomalies in my own data, until I had these odd spikes in my statistics sensor of all places:

Even more confusing is the fact that the raw data from my wind meter does not exhibit these spikes. So I am not sure if this could be related to your issue or not.

First, can you confirm the picture you shared is the chart from your wind meter, without any averages applied? Second, can you provide a zoomed in view of the moment the spike occurs? And finally, are you able to capture a log of the esphome device while these are occuring? These are not things I have access to as I have not been having consistent spikes, save the three spikes on my mean statistics sensor.

Today I notice the issue may not be HA related - with the sensor not turning (no wind) I get this:

I do have a long run (approx. 5m) of cable between the sensor and the ESP, I wonder if it needs a pull up resistor or the ESP being mounted closer to the sensor?

Edit: Changing from pulse_meter to pulse_counter seems to deal with this, now getting consistant 0mph readings - now just need some wind to test it properly!

I can imagine that a long run of cable could introduce noise, that makes sense. But I do not understand why pulse_counter would eliminate this issue, as the ā€œnoisyā€ pulses should still be coming in.

Perhaps there is a difference in the way the two platforms count pulses? I know they added internal_filter_mode to pulse_meter, but I didnā€™t find that necessary for my use case. pulse_counter uses rising and falling edge, but without examining the signal coming to your esp on an oscilloscope, it could be tricky to determine the kind of noise that is occuring.

My recommendation is to get the esp as close to the sensor as possible, in my setup I use a long power run up an unused chimney, and the esp is mounted in a waterproof PVC box on the roof, close to the sensors. There is a cable run up the mast to the sensors, but iirc itā€™s as short as possible, maybe 3m?

I wouldnā€™t think that 5m would be an issue; are there any sources of electrical interference in your area? One diagnosis I would be interested in is attempting to connect the sensor to the esp with the shortest run possible and determining if this improves the signal quality.

To solve this issue we should remove as many variables and then gradually reintroduce those conditions until we observe the issue.

image
Can you see where I changed from one to the other? It much more stable now, and looks fairly accurate

Hi @devjklein, hey all,

yes I can confirm, that the chart displays the ā€œrawā€ km/h-values I get from my esp.

The zommed-in-view seems very interesting:

There is a constant value of 240km/h for 10sec until the next value was send. Although the esp is configured to send a value every 5sec. (I played around a bit in the config, so it has changed since my last post). I tried to remove the sliding_moving_avarage and switched it to a calibration with a heartbeatā€¦:

sensor:
  - platform: pulse_meter
    pin:
      # PULUP-Widerstand 10kOhm
      number: GPIO25
      inverted: true
      mode: INPUT_PULLUP
    id: wind_speed
    unit_of_measurement: 'm/s'
    name: "Aktuelle Windgeschwindigkeit (m/s)"
    icon: 'mdi:weather-windy'
    internal_filter: 10ms
    timeout: 60s #nur bei pulse_meter
    filters:
      - calibrate_linear:
        - 0 -> 0.0
        - 60 -> 0.6666666667 #kmh/3.6 = m/s
      - heartbeat: 5s

Unfortunately I canā€™t provide a log from the moments these spikes had happened. Is there a way to save the log-messages from the esp to a file or do I have just the live-logs inside the home assistant-esphome-addon? Because I donā€™t have a clue how to predict such events it seems very hard to get the log from just that minutesā€¦

My setup is near exactly the same as @devjkleinā€™s. So I donā€™t think that the cables are the issue.

I could try to change the pulse_meter to a pulse_counter like @jimmyeao but as mentioned in this thread before theyā€™re a good arguments for taking the pulse_meter for that purpose.
I searched a bit if there ore other known problems with pulse_meter. Somehow I landed on https://github.com/esphome/esphome/pull/3321 and tried the customized pulse_meter out (I really donā€™t know if this PR is affecting this issue at all):

external_components:
  - source: github://pr#3321
    components: [pulse_meter]

Today the graph seems much calmer:


(it was I bit windy today)
Nevertheless the 240km/h spikes occurred with the changes applied, so I donā€™t think that it helpedā€¦

Hi again,

The only difference from my config is the heartbeat filter. I do not have time at the moment to investigate in detail, but I am wondering if that is causing the esp to send bad data? Can you check the logs from your esp?

Thought I would add something to this thread regarding spikes in readings off an ESP32. I run a number of ESP projects and the latest one happened to be the weather station using the Misol equipment many here also use and I subsequently saw additional pulses being received when not expected.

It was while researching the Espressif documentation of these devices I learnt that a decoupling capacitor should be placed on the pin being used for sampling data. By adding a 0.1uF capacitor between the pin in question and ground (at the ESP32 itself), all issues with random pulses being detected were eliminated.

I have some 5+ metres of wire linking the anemometer and wind vane to the ESP32 and I use the pulse counter in ESPHome. Hope this information helps someone.

2 Likes

Hey @IanC
thanks for coming back here and share your knowledge.
Indeed Iā€™m still having problems with random data-spikes, although I optimized my configuration to get at least a little ā€œcleanerā€ data know.

Just one question: You wrote, that the decoupling capacitor has to be placed between the pin being used for data and ground.
I searched a bit for decoupling capacitors and learned that such a capacitor has to placed between the power-source and ground. So, in my case (ESP32-DevKit-V1) between the 3.3V pin and ground.
Did you meant that in your post or did I misunderstood something?

Hi chm3r,

Sorry for the late reply as Iā€™ve been away on holiday for the xmas period.

The capacitor needs to be directly connected between the GPIO pin you are using and ground. Iā€™ll attach a photo which shows the capacitor attached to a D1 Mini. Hope that helps you.

1 Like

Hello,
please can you tell me if I am doing the correct conversion for the sensor to kmh ?

  • Pulses Per Rotation: 20 pulses per rotation
  • Wind speed: 1.75m/s = 20 pulses per second

1.75 m/s = 6.2995 km/h.

So my multiply to get km/h should be :

  • multiply: 0.005245 # 6.2995 km/h per rotation/s = ((1 / 60) / 20) * 6.2995

0.005245 is number I get

However, 20 pulses per rotation is very odd ā€¦ most anemometers have a reed switch / relay which is triggered by one rotation

1 Like

Hey IanC,

indeed, that was the trick. Thank you very very much for the tip.
Since I soldered the Capacitor in, the random spikes are gone and now I have clean and plausible data. Nice!

Now Iā€˜m in the details: although you all (or most of you) use the calibration divided by two (because of two ticks per rotation), iā€˜m using the original calibration from the datasheet (2.4km/h per 1 Rotation per second) and it seems to be quite accurate in comparision to my local weather data provider. Iā€˜m wondering if there are different versions of the Spakfun like anemometers on the market. Some using the 2.4-calibration, others the 1.2. Maybe the datasheet we all use is just for one specific version of the sensor.

And last but not least for everyone whos interested: to avoid the situation, that the Wind sensor gets stuck at a value > 0 km/h when using the sliding window moving average in esphome and no new wind data comes in from the sensor: I just configured a little automation inside HA, which tests every few seconds if the value of the windspeed-meter has not changed for more than 10 seconds. If that condition turns true, i simply set the value of the sensor to zero via a little script inside of HA.
Its not perfect but better than nothing :slight_smile:

Happy Weekend everyone!

Hereā€™s how I dealt with the wind calculations. I do not rely on counting pulses per rotation, I measure the duration between pulses instead. It also shows how I dealt with calculating gusts according to the standards by the world meteorogical organization.

It works perfectly to this day.

1 Like