Browse Source

inital wind.h

master
Norwin 4 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 @@
# wind_rain_sensor

Arduino library to read out a Weather Sensor Assembly p/n 80422
Arduino library to read out a Weather Sensor Assembly p/n 80422, as sold [here](https://www.watterott.com/de/Wetter-Messeinheit)

Will add documentation & make it a proper Arduino library once I find the time.
The lib is really small though, just skim over it.

# license
GPL-3.0

BIN
datasheet.pdf View File


+ 178
- 0
wind.h View File

@@ -0,0 +1,178 @@
/**
* provides functions to read out the sensors of a SEN 08942 "Wettermesseinheit":
* - Wind Direction: analog sensor with 16 cardinal direction steps
* - Wind Speed: Interrupt counter
* - Rain: Interrupt counter
*
* Check your controller's spec which pins have ADC or interrupt capabilities!
* On a senseBox MCU this should work well:
* WeatherUnit weather(4, 6, 5);
*/

#pragma once

#include <math.h>

class WeatherUnit {
public:
WeatherUnit (uint8_t pinDirection, uint8_t pinSpeed, uint8_t pinRain, uint16_t directionOffset);
void begin ();

float getWindDir (unsigned char numMeasures, unsigned int interval);
float getWindDir ();
float getWindSpeed ();
float getRain ();

// interrupt handlers
void countRain ();
void countSpeed ();

private:
const unsigned int pinDirection, pinSpeed, pinRain, directionOffset;
const unsigned int directionVolt[16] = {320, 410, 450, 620, 900, 1190, 1400, 1980, 2250, 2930, 3080, 3430, 3840, 4040, 4620, 4780};
const unsigned int directionDegree[16] = {113, 68, 90, 158, 135, 203, 180, 23, 45, 248, 225, 338, 0, 292, 315, 270 };

unsigned unsigned long lastResetRain = 0, lastResetSpeed = 0;
volatile unsigned long rainCounter = 0, speedCounter = 0;
volatile bool lastRainReading = 0, currentRainReading = 0, lastSpeedReading = 0, currentSpeedReading = 0;

bool debounceInput (unsigned int pin, bool last);
};







// keep a pointer to the last created instance, in order to attach global interrupt handlers
WeatherUnit* WEATHER_INSTANCE = NULL;

void WEATHER_speedInterruptHandler () {
WEATHER_INSTANCE->countSpeed();
}

void WEATHER_rainInterruptHandler () {
WEATHER_INSTANCE->countRain();
}








WeatherUnit::WeatherUnit (uint8_t pinDirection, uint8_t pinSpeed, uint8_t pinRain, uint16_t directionOffset = 0)
: pinDirection(pinDirection), pinSpeed(pinSpeed), pinRain(pinRain), directionOffset(directionOffset) {
WEATHER_INSTANCE = this;
}

void WeatherUnit::begin () {
lastResetRain = millis();
lastResetSpeed = millis();

pinMode(pinDirection, INPUT);
pinMode(pinSpeed, INPUT_PULLUP);
pinMode(pinRain, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(pinSpeed), WEATHER_speedInterruptHandler, RISING);
attachInterrupt(digitalPinToInterrupt(pinRain), WEATHER_rainInterruptHandler, LOW);
}

float WeatherUnit::getWindDir (unsigned char numMeasures, unsigned int interval) {
// angular average
float sumX = 0, sumY = 0, val;
for (unsigned char i = 0; i < numMeasures; i++) {
val = radians(getWindDir());
sumX += sin(val);
sumY += cos(val);
if (i != numMeasures - 1) delay(interval);
}
return 180 + atan(sumX / sumY) * 180 / 3.1415;
}

float WeatherUnit::getWindDir () {
unsigned int mvolt = analogRead(pinDirection);
mvolt = map(mvolt, 0, 1023, 0, 5000); // map to range 0-5000 to make use of voltage values as defined in data sheet

// search for correct index
unsigned char i;
for (i = 0; i < 16; i++) {
if (mvolt <= directionVolt[i]) break;
}
i--; // the correct reference is actually lower than the reference value found.

return (float) ((directionDegree[i] + directionOffset) % 360);
}

float WeatherUnit::getWindSpeed () {
unsigned long now = millis();
double secondsPassed = (now - lastResetSpeed) / 1000; // @FIXME: might yield bullshit when millis() overflows!
// one impulse per second equals 2.4 km/h -> 0.6666 m/s
float metersPerSec = (2 * speedCounter) / (3 * max(secondsPassed, 1.0));
speedCounter = 0;
lastResetSpeed = now;
return metersPerSec;
}

float WeatherUnit::getRain () {
float val = rainCounter * 0.2794; // mm aka L/m²
rainCounter = 0;
return val;
}

bool WeatherUnit::debounceInput (unsigned int pin, bool last) {
bool current = digitalRead(pin);
if (last != current) {
// adjust this value.
// shorter -> risk of detecting single switch multiple times,
// longer -> risk of missing switches.
delayMicroseconds(1e3);
current = digitalRead(pin);
}
return current;
}

void WeatherUnit::countRain () {
currentRainReading = debounceInput(pinRain, lastRainReading);
if (lastRainReading == LOW && currentRainReading == HIGH)
rainCounter++;
lastRainReading = currentRainReading;
}

void WeatherUnit::countSpeed () {
currentSpeedReading = debounceInput(pinSpeed, lastSpeedReading);
if (lastSpeedReading == LOW && currentSpeedReading == HIGH)
speedCounter++;
lastSpeedReading = currentSpeedReading;
}




float mpsToKmph (float val) { return val * 3.6; }
float mpsToKnots (float val) { return val * 1.943843307; }
float mpsToBeaufort (float val) {
if (val < 0.5) return 0;
else if (val < 1.5) return 1;
else if (val < 3.3) return 2;
else if (val < 5.5) return 3;
else if (val < 7.9) return 4;
else if (val < 10.7) return 5;
else if (val < 13.8) return 6;
else if (val < 17.1) return 7;
else if (val < 20.7) return 8;
else if (val < 24.4) return 9;
else if (val < 28.4) return 10;
else if (val < 32.6) return 11;
else return 12;
}

const String CARDINAL_DIRS_EN[16] = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
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"};
String degreeToCardinal (float val, const String cardinalNames[] = CARDINAL_DIRS_EN) {
int i = (int)((val + 11.25) / 22.5);
return cardinalNames[i % 16];
}


Loading…
Cancel
Save