
Ein Windsensor für meine Haussteuerung steht schon lange auf meiner ToDo Liste. Diesen brauche ich vor allem als Sicherheitsfunktion für die automatische Steuerung der Raffstores – und aus Datensammelwut.
Als Basis habe ich mir einen Ventus Ersatzsensor entkernt und dort einen ESP8266 + Arduino Mini Pro 3,3V untergebracht.
Die Komponenten
Folgende Komponenten habe ich verbaut:
- Ventus Ersatzwindmesser (link) ca. 23 € bei Reichelt .de
- Arduino Pro 3,3V 8Mhz (link) ca. 4 € bei Amazon.de
- Wemos D1 Mini (link) ca. 5 € bei Amazon.de
- 3 Volt Solarzelle (link) für 8 € bei Amazon.de
- 100k Widerstand zur Spannungsmessung
Macht insgesamt ca. 40 € für einen smarten Windsensor mit Batteriebetrieb. Deutlich Billiger als alle Modelle die auf dem Markt sind und auch etwas besser zu befestigen als die Stab-Bauweise von Homematic.
Warum 2 Boards?
Für die Akkulaufzeit – den ESP8266 kann ich nicht mit einem externen Interrupt wecken ohne einen vollen Reboot zur durchlaufen. Der Arduino kann jedoch an 2 Interrupt Pins geweckt werden und anschließend wieder schlafen, ohne einen Reboot zu durchlaufen.
Der Ablauf ist eigentlich recht einfach, der Arduino zählt an PIN 2 alle Umdrehung des Windsensors und lauscht auf PIN3 ob ein Low vom Wemos gesetzt wird. Kommt das Signal auf PIN3 erfolgt eine Serielle Ausgabe des Aktuellen Windcounters.
Der Wemos Rebootet alle 30 Sekunden neu, liest den Serial Input und sendet ggf. Daten via MQTT an IObroker. Ansonsten sind beide Geräte im Deep Sleep und verbrauchen nur Minimal Strom.
Der Ablauf nochmal grafisch dargestellt:

Aktuell läuft das ganze noch im Testbetrieb, um zu sehen, wie sich die Batterielaufzeit verhält. Um möglichst lange Betriebszeiten zu erreichen werden 2 NiMH Akkus durch eine 3V Solarzelle geladen – ohne Laderegler. Den Laderegler halte ich für überflüssig, da NiMH Zellen ein überladen mit geringer Stärke gut verkraften. Ich habe die Akkus vorher einem Kapazitätstest unterzogen und werde im Frühjahr einen weiteren Test mache.
Code Arduino Pro mini
#include <LowPower.h>
#define WIND_INTERRUPT 0
#define ESP_INTERRUPT 1
#define WIND_INTERRUPT_PIN 3
#define ESP_INTERRUPT_PIN 2
volatile int pulses = 0;
volatile long last_interrupt_time = 0;
volatile int sendcheck = false;
void pulse() {
unsigned long interrupt_time = millis();
// If interrupts come faster than 200ms, assume it's a bounce and ignore
if (interrupt_time - last_interrupt_time > 10)
{
++pulses;
}
last_interrupt_time = interrupt_time;
}
void ESP_awake() {
sendcheck = true;
}
void sendWind() {
int temppulse = pulses;
delay(200);
Serial.println("-");
Serial.print("pulses:");
Serial.println(temppulse);
// gesendete vom Global Counter abziehen
pulses -= temppulse;
}
void setup() {
pinMode(WIND_INTERRUPT_PIN, INPUT_PULLUP);
pinMode(ESP_INTERRUPT_PIN, INPUT);
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(WIND_INTERRUPT_PIN), pulse, RISING);
attachInterrupt(digitalPinToInterrupt(ESP_INTERRUPT_PIN), ESP_awake, FALLING);
}
void loop() {
delay(100);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
// Wake up ab hier
if (sendcheck) {
sendcheck = false;
sendWind();
}
}
Code Wemos / Esp8266
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <PubSubClient.h>
#include <RTCVars.h>
RTCVars state; // create the state object
int reset_counter;
int program_step;
int sumwindcount;
unsigned int raw = 0;
float volt = 0.0;
WiFiClient espClient;
PubSubClient client(espClient);
const char* ssid = "****";
const char* password = "****";
const char* mqttServer = "192.168.****";
const int mqttPort = 1886;
const char* mqttUser = "*****";
const char* mqttPassword = "*****";
int sleepTimeS = 30;
volatile unsigned long ContactBounceTime; // Timer to avoid contact bounce in interrupt routine
void setup() {
Serial.begin(9600);
state.registerVar( &reset_counter );
state.registerVar( &sumwindcount );
if (state.loadFromRTC()) {
reset_counter++;
} else {
reset_counter = 0;
sumwindcount = 0;
program_step = 0;
}
// Pin 4 Aktivieren / Deaktiveren >> Signal für Arudino Interrupt
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(4, LOW);
}
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void senddata(int windspeed, int boe, float battery) {
WiFi.begin(ssid, password);
byte wifiCNT = 0;
byte mqttCNT = 0;
while (WiFi.status() != WL_CONNECTED && wifiCNT < 10) {
delay(500);
wifiCNT++;
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
client.setServer(mqttServer, mqttPort);
while (!client.connected() && mqttCNT < 10) {
mqttCNT++;
Serial.println("Connecting to MQTT...");
if (client.connect("windsensor", mqttUser, mqttPassword )) {
Serial.println("connected");
} else {
Serial.print("failed with state ");
Serial.print(client.state());
delay(200);
}
}
if (windspeed != -1) {
boolean rc = client.publish("windsensor/windspeed", String(windspeed).c_str());
}
if (battery != -1) {
client.publish("windsensor/battery", String(battery).c_str());
}
if (boe != -1) {
client.publish("windsensor/boe", String(boe).c_str());
}
delay(100);
}
void loop() {
Serial.begin(9600);
delay(100);
String a;
int aktwindcount = -1;
while (Serial.available()) {
Serial.println("wait for data");
a = Serial.readString(); // read the incoming data as
Serial.println(a);
if (a.indexOf("pulses") > 0) {
a.replace("\n", "");
a.replace("⸮-", "");
a = getValue(a, ':', 1);
Serial.println(a);
aktwindcount = a.toInt();
break;
}
delay(100);
}
if (aktwindcount > 150) {
senddata(-1, aktwindcount, -1);
}
// summe windcount erhöhen
sumwindcount = aktwindcount + sumwindcount;
// aller 12 durchgänge senden oder wenn starker wind
if (reset_counter >= 12) {
int raw = analogRead(A0);
int windavg = sumwindcount / reset_counter;
volt = raw / 1023.0;
volt = volt * 4.2;
senddata(windavg, -1, volt);
reset_counter = 0;
sumwindcount = 0;
}
state.saveToRTC();
delay(100);
ESP.deepSleep(29e6); // 20e6 is 20 microseconds
}
Coole Sache,
hat sich das Teil mittlerweile bewährt?
Hi, mir ist noch nicht so ganz klar wo du den Widerstand rein klemmst. Hast du evtl ein „Schalt“ oder „Verdrahtungs“ Bild?
Hallo David,
auch ich wär an dem Verdrahtungsplan interessiert. Scheinbar war der auch schon mal im Beitrag ist nur nicht mehr zu sehen..??
Danke für Deine Unterstützung