A beelogger on ESP32 basis, part 5: Test setup: The wind direction sensor

I bought a wind direction sensor from china, it’s a spare part for the “misol” weather stations, just search for “wind direction sensor misol aliexpress” for the product, it was less than 15€.

I unscrewed it to understand how it works. The picture of the PCB verifies that the hardware matches the datasheets I found in this wiki:
datasheet_1
datasheet_2

So it’s a few hall sensors that switch resistors connected in parallel. The magnet switches one or two of them at once:

The resistor values are given in the datasheet:

Direction (degrees)Resistance (ohms)
033K
22.56.57K
458.2K
67.5891
901K
112.5688
1352.2K
157.51.41K
1803.9K
202.53.14K
22516K
247.514.12K
270120K
292.542.12K
31564.9K
337.521.88K


Every second entry in this table is a combination of the entries below and above when both switches are triggered and is defined by the formular for two resistors connected in parallel:

$$R = \frac{R_1 \cdot R_2}{R_1 + R_2}$$

So we have to measure the resistance of the sensor via the ADC. Therefore a voltage divider is needed. A voltage divider looks like this:

R2 is the variable resistor that is the sensor. R1 has to be chosen correctly so that it matches the range of R2, the value of Vin and the desired measuring range on Vout.

According to the datasheets we have to measure resistances for R2 that can be between 688 Ω and 120 kΩ. The ADC of the ESP32S3 accepts up to 3100 mV with ADC_ATTEN_DB_11 (that’s Vout), Vin is 3.3V from the ESP32.

Now the value for R1 has to be calculated for the biggest possible resistor, so we have R2=120 kΩ, Vin=3.3V and Vout3.1V:

The formular for the voltage divider is:

$$V_{\text{out}} = V_{\text{in}} \cdot \frac{R_2}{R_1 + R_2}$$

So, for our values of Vin, Vout and R2 we get:

$$R_1 = R_2 \cdot (\frac{V_{\text{in}}}{V_{\text{out}}} – 1) = 120kΩ \cdot (\frac{3.3V}{3.1V} – 1) ≈ 7.74kΩ$$

The next fitting standard resistor is 8.2kΩ, let’s calculate Vout for it:

$$V_{\text{out}} = V_{\text{in}} \cdot \frac{R_2}{R_1 + R_2} = 3.3V \cdot \frac{120kΩ}{8.2kΩ + 120kΩ} ≈ 3089mV$$

That’s a good value: with it we get 3.089V on Vout for 120kΩ which is about 99.6% of the maximal voltage of 3.1V the ADC of the ESP323 can handle.
The ADC has 12 bits, that means we have a measuring range of 212=4096 values, 99.6% of it are ≈4080, so we have a resolution of round about 120kΩ/4080 ≈ 29Ω.
That’s sufficient, the minimal difference between the resistors we want to measure is more than 100Ω.

So we can wire the sensor up now via a properly chosen voltage divider:

Integrating it in esphome is comfortable:

substitutions:
  update_interval: 5s

text_sensor:
  - platform: template
    name: "Wind direction"
    icon: 'mdi:windsock'
    id: wind_dir

sensor:
  - platform: adc
    id: source_sensor
    pin: GPIO32
    name: ADC
    attenuation: 11db
    internal: true
    update_interval: ${update_interval}
    accuracy_decimals: 1

  - platform: resistance
    sensor: source_sensor
    id: resistance_sensor
    configuration: DOWNSTREAM
    resistor: 8.2kOhm
    internal: true
    name: Resistance Sensor
    reference_voltage: 3.3V
    accuracy_decimals: 1
    update_interval: ${update_interval}

    on_value:
      then:
        - lambda: |-
            struct WindEntry {
              int lower;
              int upper;
              const char* direction;
              float heading;
            };

            static const WindEntry wind_table[] = {
              {  400,    789, "East-South-East",  112.5},  // 688 Ω
              {  789,    945, "East-North-East",   67.5},  // 891 Ω
              {  945,   1205, "East",              90.0},  // 1 kΩ
              { 1205,   1805, "South-South-East", 157.5},  // 1.41 kΩ
              { 1805,   2670, "South-East",       135.0},  // 2.2 kΩ
              { 2670,   3520, "South-South-West", 202.5},  // 3.14 kΩ
              { 3520,   5235, "South",            180.0},  // 3.9 kΩ
              { 5235,   7385, "North-North-East",  22.5},  // 6.57 kΩ
              { 7385,  11160, "North-East",        45.0},  // 8.2 kΩ
              {11160,  15060, "West-South-West",  247.5},  // 14.12 kΩ
              {15060,  18940, "South-West",       225.0},  // 16 kΩ
              {18940,  27440, "North-North-West", 337.5},  // 21.88 kΩ
              {27440,  37560, "North",              0.0},  // 33 kΩ
              {37560,  53510, "West-North-West",  292.5},  // 42.12 kΩ
              {53510,  92450, "North-West",       315.0},  // 64.9 kΩ
              {92450, 150000, "West",             270.0},  // 120 kΩ
            };

            const int resistance = id(resistance_sensor).state;

            for (const auto& entry : wind_table) {
              if (resistance >= entry.lower && resistance < entry.upper) {
                id(wind_dir).publish_state(entry.direction);
                id(wind_heading).publish_state(entry.heading);
                break;
              }
            }

  - platform: template
    name: "Wind Heading"
    id: wind_heading
    unit_of_measurement: "°"

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *