DIY Windsensor mit MQTT mit Esp8266 für IObroker

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.

“Durchdachtes” Kabelmanagement im Prototyp

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


}




2 Kommentare zu „DIY Windsensor mit MQTT mit Esp8266 für IObroker

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.