Browse Source

inital wind.h

master
Norwin Roosen 2 months ago
parent
commit
f51f1f32d2
3 changed files with 185 additions and 1 deletions
  1. 7
    1
      README.md
  2. BIN
      datasheet.pdf
  3. 178
    0
      wind.h

+ 7
- 1
README.md View File

@@ -1,3 +1,9 @@
1 1
 # wind_rain_sensor
2 2
 
3
-Arduino library to read out a Weather Sensor Assembly p/n 80422  
3
+Arduino library to read out a Weather Sensor Assembly p/n 80422, as sold [here](https://www.watterott.com/de/Wetter-Messeinheit)
4
+
5
+Will add documentation & make it a proper Arduino library once I find the time.
6
+The lib is really small though, just skim over it.
7
+
8
+# license
9
+GPL-3.0

BIN
datasheet.pdf View File


+ 178
- 0
wind.h View File

@@ -0,0 +1,178 @@
1
+/**
2
+ * provides functions to read out the sensors of a SEN 08942 "Wettermesseinheit":
3
+ * - Wind Direction: analog sensor with 16 cardinal direction steps
4
+ * - Wind Speed:     Interrupt counter
5
+ * - Rain:           Interrupt counter
6
+ *
7
+ * Check your controller's spec which pins have ADC or interrupt capabilities!
8
+ * On a senseBox MCU this should work well:
9
+ *   WeatherUnit weather(4, 6, 5);
10
+ */
11
+
12
+#pragma once
13
+
14
+#include <math.h>
15
+
16
+class WeatherUnit {
17
+   public:
18
+    WeatherUnit (uint8_t pinDirection, uint8_t pinSpeed, uint8_t pinRain, uint16_t directionOffset);
19
+    void begin ();
20
+
21
+    float getWindDir (unsigned char numMeasures, unsigned int interval);
22
+    float getWindDir ();
23
+    float getWindSpeed ();
24
+    float getRain ();
25
+
26
+    // interrupt handlers
27
+    void countRain ();
28
+    void countSpeed ();
29
+
30
+    private:
31
+    const unsigned int pinDirection, pinSpeed, pinRain, directionOffset;
32
+    const unsigned int directionVolt[16]   = {320, 410, 450, 620, 900, 1190, 1400, 1980, 2250, 2930, 3080, 3430, 3840, 4040, 4620, 4780};
33
+    const unsigned int directionDegree[16] = {113, 68,  90,  158, 135, 203,  180,  23,   45,   248,  225,  338,  0,    292,  315,  270 };
34
+
35
+    unsigned unsigned long lastResetRain = 0, lastResetSpeed = 0;
36
+    volatile unsigned long rainCounter = 0, speedCounter = 0;
37
+    volatile bool lastRainReading = 0, currentRainReading = 0, lastSpeedReading = 0, currentSpeedReading = 0;
38
+
39
+    bool debounceInput (unsigned int pin, bool last);
40
+};
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+// keep a pointer to the last created instance, in order to attach global interrupt handlers
49
+WeatherUnit* WEATHER_INSTANCE = NULL;
50
+
51
+void WEATHER_speedInterruptHandler () {
52
+    WEATHER_INSTANCE->countSpeed();
53
+}
54
+
55
+void WEATHER_rainInterruptHandler () {
56
+    WEATHER_INSTANCE->countRain();
57
+}
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+WeatherUnit::WeatherUnit (uint8_t pinDirection, uint8_t pinSpeed, uint8_t pinRain, uint16_t directionOffset = 0)
67
+  : pinDirection(pinDirection), pinSpeed(pinSpeed), pinRain(pinRain), directionOffset(directionOffset) {
68
+    WEATHER_INSTANCE = this;
69
+}
70
+
71
+void WeatherUnit::begin () {
72
+    lastResetRain  = millis();
73
+    lastResetSpeed = millis();
74
+
75
+    pinMode(pinDirection, INPUT);
76
+    pinMode(pinSpeed, INPUT_PULLUP);
77
+    pinMode(pinRain, INPUT_PULLUP);
78
+    
79
+    attachInterrupt(digitalPinToInterrupt(pinSpeed), WEATHER_speedInterruptHandler, RISING);
80
+    attachInterrupt(digitalPinToInterrupt(pinRain), WEATHER_rainInterruptHandler, LOW);
81
+}
82
+
83
+float WeatherUnit::getWindDir (unsigned char numMeasures, unsigned int interval) {
84
+    // angular average
85
+    float sumX = 0, sumY = 0, val;
86
+    for (unsigned char i = 0; i < numMeasures; i++) {
87
+        val = radians(getWindDir());
88
+        sumX += sin(val);
89
+        sumY += cos(val);
90
+        if (i != numMeasures - 1) delay(interval);
91
+    }
92
+    return 180 + atan(sumX / sumY) * 180 / 3.1415;
93
+}
94
+
95
+float WeatherUnit::getWindDir () {
96
+    unsigned int mvolt = analogRead(pinDirection);
97
+    mvolt = map(mvolt, 0, 1023, 0, 5000); // map to range 0-5000 to make use of voltage values as defined in data sheet
98
+
99
+    // search for correct index
100
+    unsigned char i;
101
+    for (i = 0; i < 16; i++) {
102
+        if (mvolt <= directionVolt[i]) break;
103
+    }
104
+    i--; // the correct reference is actually lower than the reference value found.
105
+
106
+    return (float) ((directionDegree[i] + directionOffset) % 360);
107
+}
108
+
109
+float WeatherUnit::getWindSpeed () {
110
+    unsigned long now = millis();
111
+    double secondsPassed = (now - lastResetSpeed) / 1000; // @FIXME: might yield bullshit when millis() overflows!
112
+    // one impulse per second equals 2.4 km/h -> 0.6666 m/s
113
+    float metersPerSec = (2 * speedCounter) / (3 * max(secondsPassed, 1.0));
114
+    speedCounter = 0;
115
+    lastResetSpeed = now;
116
+    return metersPerSec;
117
+}
118
+
119
+float WeatherUnit::getRain () {
120
+    float val = rainCounter * 0.2794; // mm aka L/m²
121
+    rainCounter = 0;
122
+    return val;
123
+}
124
+
125
+bool WeatherUnit::debounceInput (unsigned int pin, bool last) {
126
+  bool current = digitalRead(pin);
127
+  if (last != current) {
128
+    // adjust this value.
129
+    //  shorter -> risk of detecting single switch multiple times, 
130
+    //  longer  -> risk of missing switches. 
131
+    delayMicroseconds(1e3);
132
+    current = digitalRead(pin);
133
+  }
134
+  return current;
135
+}
136
+
137
+void WeatherUnit::countRain () {
138
+    currentRainReading = debounceInput(pinRain, lastRainReading);
139
+    if (lastRainReading == LOW && currentRainReading == HIGH)
140
+        rainCounter++;
141
+    lastRainReading = currentRainReading;
142
+}
143
+
144
+void WeatherUnit::countSpeed () {
145
+    currentSpeedReading = debounceInput(pinSpeed, lastSpeedReading);
146
+    if (lastSpeedReading == LOW && currentSpeedReading == HIGH)
147
+        speedCounter++;
148
+    lastSpeedReading = currentSpeedReading;
149
+}
150
+
151
+
152
+
153
+
154
+float mpsToKmph  (float val) { return val * 3.6; }
155
+float mpsToKnots (float val) { return val * 1.943843307; }
156
+float mpsToBeaufort (float val) {
157
+  if (val < 0.5)       return 0;
158
+  else if (val < 1.5)  return 1;
159
+  else if (val < 3.3)  return 2;
160
+  else if (val < 5.5)  return 3;
161
+  else if (val < 7.9)  return 4;
162
+  else if (val < 10.7) return 5;
163
+  else if (val < 13.8) return 6;
164
+  else if (val < 17.1) return 7;
165
+  else if (val < 20.7) return 8;
166
+  else if (val < 24.4) return 9;
167
+  else if (val < 28.4) return 10;
168
+  else if (val < 32.6) return 11;
169
+  else return 12;
170
+}
171
+
172
+const String CARDINAL_DIRS_EN[16] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
173
+const String CARDINAL_DIRS_DE[16] = {"N", "N-NO", "N-O", "O-NO", "O", "O-SO", "S-O", "S-SO", "S", "S-SW", "S-W", "W-SW", "W", "W-NW", "N-W", "N-NW"};
174
+String degreeToCardinal (float val, const String cardinalNames[] = CARDINAL_DIRS_EN) {
175
+    int i = (int)((val + 11.25) / 22.5);
176
+    return cardinalNames[i % 16];
177
+}
178
+

Loading…
Cancel
Save