Skip to content

Instantly share code, notes, and snippets.

@micw
Last active January 4, 2022 16:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save micw/098709efc83a9d9ebf16d14cea4ca38e to your computer and use it in GitHub Desktop.
Save micw/098709efc83a9d9ebf16d14cea4ca38e to your computer and use it in GitHub Desktop.
Ventus W132 decoder sketch
/**
* Ein ESP8622 NodeMCU Develompent Board, welches Sensorwerte via MQTT verschickt
* http://frightanic.com/iot/comparison-of-esp8266-nodemcu-development-boards/
*
* Umbau eines W132 Windsensors von ELV
*
* - Abtrennen des 433 MHZ-Senders, welcher mit 3 Leitungen (Schwarz, Rot, Blau) an der Logik-Platine angeschlossen ist
* - Anschließen des ESP-8266
* - Schwarz -> GND
* - Rot -> 3.3V
* - Blau -> D2
*
* Eine Beschreibung des Protokoll ist unter http://www.tfd.hu/tfdhu/files/wsprotocol/auriol_protocol_v20.pdf zu finden, hilfreich ist auch https://sourceforge.net/p/wmrx00/discussion/855158/thread/b3a47730/
* - Bits und Sync-Signale werden über die Abstände der fallenden Flanke codiert
* - diese Implementierung nutzt dazu einen Interrupt auf der fallenden Flanke
*/
#define MQTT_ALIVE_TOPIC "sensor/%s/alive"
#define MQTT_DATA_TOPIC "sensor/%s/%s"
#include <common_wifi.h>
#include <common_mqtt.h>
#include <esp_pins.h>
#define PIN_ANEMOMETER D2
volatile unsigned long lastTrigger;
byte mac[6];
char sensorId[7];
char topicBuffer[255];
char messageBuffer[255];
byte bitPos=-1;
byte messageNum=-1;
// there are always sent 6 messages. For temperature/humidity, the message is repeatet 6 times. For wind, 2 messages are repeatet 3 times each
int message1Bits[36];
int message2Bits[36];
bool verifyChecksum(int bits[]) {
int checksum=0xf;
for (int i=0;i<8;i++) {
checksum-=bits[i*4]|bits[i*4+1]<<1|bits[i*4+2]<<2|bits[i*4+3]<<3;
}
checksum&=0xf;
int expectedChecksum=bits[32]|bits[33]<<1|bits[34]<<2|bits[35]<<3;
return checksum==expectedChecksum;
}
void decodeMessages() {
if (!verifyChecksum(message1Bits)) {
Serial.println("Checksum mismatch in message #1");
return;
}
/*
Serial.println("---");
for (int i=0;i<36;i++) {
Serial.print(message1Bits[i]);
Serial.print(" ");
}
Serial.println();
for (int i=0;i<36;i++) {
Serial.print(message2Bits[i]);
Serial.print(" ");
}
Serial.println();
*/
if (message1Bits[9]==1 && message1Bits[10]==1) { // wind data (2 messages)
if (!verifyChecksum(message2Bits)) {
Serial.println("Checksum mismatch in message #1");
return;
}
float windSpeed=(message1Bits[24] | message1Bits[25]<<1 | message1Bits[26]<<2 | message1Bits[27]<<3 |
message1Bits[28]<<4 | message1Bits[29]<<5 | message1Bits[30]<<6 | message1Bits[31]<<7)*0.2f;
Serial.print("Average wind speed: ");
Serial.print(windSpeed);
Serial.println(" m/s");
sprintf(topicBuffer, MQTT_DATA_TOPIC, sensorId, "wind_speed");
String value = String(windSpeed,1);
value.toCharArray(messageBuffer,255);
mqttClient.publish(topicBuffer,(byte*)messageBuffer,strlen(messageBuffer));
float windGust=(message2Bits[24] | message2Bits[25]<<1 | message2Bits[26]<<2 | message2Bits[27]<<3 |
message2Bits[28]<<4 | message2Bits[29]<<5 | message2Bits[30]<<6 | message2Bits[31]<<7)*0.2f;
Serial.print("Max wind speed: ");
Serial.print(windGust);
Serial.println(" m/s");
sprintf(topicBuffer, MQTT_DATA_TOPIC, sensorId, "wind_gust");
value = String(windGust,1);
value.toCharArray(messageBuffer,255);
mqttClient.publish(topicBuffer,(byte*)messageBuffer,strlen(messageBuffer));
int windDirection=(message2Bits[15] | message2Bits[16]<<1 | message2Bits[17]<<2 | message2Bits[18]<<3 |
message2Bits[19]<<4 | message2Bits[20]<<5 | message2Bits[21]<<6 | message2Bits[22]<<7 |
message2Bits[23]<<8);
Serial.print("Wind direction: ");
Serial.print(windDirection);
Serial.println(" °");
sprintf(topicBuffer, MQTT_DATA_TOPIC, sensorId, "wind_direction");
value = String(windDirection);
value.toCharArray(messageBuffer,255);
mqttClient.publish(topicBuffer,(byte*)messageBuffer,strlen(messageBuffer));
} else { // temperature/humidity in both messages
int temperatureRaw=(message1Bits[12] | message1Bits[13]<<1 | message1Bits[14]<<2 | message1Bits[15]<<3 |
message1Bits[16]<<4 | message1Bits[17]<<5 | message1Bits[18]<<6 | message1Bits[19]<<7 |
message1Bits[20]<<8 | message1Bits[21]<<9 | message1Bits[22]<<10| message1Bits[23]<<11);
if (temperatureRaw& 0x800) temperatureRaw+=0xF000; // negative number, 12 to 16 bit
float temperature=temperatureRaw*0.1f;
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
sprintf(topicBuffer, MQTT_DATA_TOPIC, sensorId, "temp");
String value = String(temperature,1);
value.toCharArray(messageBuffer,255);
mqttClient.publish(topicBuffer,(byte*)messageBuffer,strlen(messageBuffer));
int humidity=(message1Bits[24] | message1Bits[25]<<1 | message1Bits[26]<<2 | message1Bits[27]<<3 )+
(message1Bits[28] | message1Bits[29]<<1 | message1Bits[30]<<2 | message1Bits[31]<<3 )*10;
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println(" %");
sprintf(topicBuffer, MQTT_DATA_TOPIC, sensorId, "humi");
value = String(humidity);
value.toCharArray(messageBuffer,255);
mqttClient.publish(topicBuffer,(byte*)messageBuffer,strlen(messageBuffer));
}
}
void dataTrigger() {
unsigned long now=micros();
unsigned long duration=now-lastTrigger;
lastTrigger=now;
if (duration>30000) { // a news block of messages begins
messageNum=0;
}
if (duration>7000) { // ~9 ms = sync signal
if (bitPos==36) { // we got a full message
if (messageNum==0) { // 1st message completed
messageNum=1;
} else if (messageNum==1) { // 2nd message completed
decodeMessages();
messageNum=-1;
}
}
bitPos=0; // Nachricht begonnen
return;
}
if (messageNum<0) return; // ignore repeated messages
if (bitPos<0) return; // invalid message, ignored
if (messageNum==0) {
message1Bits[bitPos]=(duration>3300); // 2.2ms=LOW, 4.4ms = HIGH bits
} else {
message2Bits[bitPos]=(duration>3300); // 2.2ms=LOW, 4.4ms = HIGH bits
}
bitPos++;
if (bitPos>36) bitPos=-1; // message too long -> invalid
}
void setup() {
wdt_enable(WDTO_8S); // Watchdog muss alle 8 Sekunden resettet werden
Serial.begin(115200);
Serial.println("Initializing");
WiFi.macAddress(mac);
sprintf(sensorId, "%02X%02X%02X", mac[3], mac[4], mac[5]);
setup_wifi();
wdt_reset(); // Watchdog resetten
setup_mqtt();
wdt_reset(); // Watchdog resetten
pinMode(PIN_ANEMOMETER,INPUT);
attachInterrupt(digitalPinToInterrupt(PIN_ANEMOMETER), dataTrigger, FALLING);
wdt_reset(); // Watchdog resetten
Serial.println("Starting");
}
void loop() {
wdt_reset(); // Watchdog resetten
connect_mqtt(0);
wdt_reset(); // Watchdog resetten
mqttClient.loop();
}
@micw
Copy link
Author

micw commented Oct 25, 2020

esp_pins.h (usually only required on "generic" esp boards).

#include "Arduino.h"

#define D0   16
#define D1   5
#define D2   4
#define D3   0
#define D4   2
#define D5   14
#define D6   12
#define D7   13
#define D8   15
#define D9   3
#define D10  1

extern const uint32 GPIO_MUX[] {
	PERIPHS_IO_MUX_GPIO0_U,
	PERIPHS_IO_MUX_U0TXD_U,
	PERIPHS_IO_MUX_GPIO2_U,
	PERIPHS_IO_MUX_U0RXD_U,
	PERIPHS_IO_MUX_GPIO4_U,
	PERIPHS_IO_MUX_GPIO5_U,
	PERIPHS_IO_MUX_SD_CLK_U,
	PERIPHS_IO_MUX_SD_DATA0_U,
	PERIPHS_IO_MUX_SD_DATA1_U,
	PERIPHS_IO_MUX_SD_DATA2_U,
	PERIPHS_IO_MUX_SD_DATA3_U,
	PERIPHS_IO_MUX_SD_CMD_U,
	PERIPHS_IO_MUX_MTDI_U,
	PERIPHS_IO_MUX_MTCK_U,
	PERIPHS_IO_MUX_MTMS_U,
	PERIPHS_IO_MUX_MTDO_U
};
extern const uint32 GPIO_FUNC[] {
	FUNC_GPIO0,
	FUNC_GPIO1,
	FUNC_GPIO2,
	FUNC_GPIO3,
	FUNC_GPIO4,
	FUNC_GPIO5,
	FUNC_GPIO6,
	FUNC_GPIO7,
	FUNC_GPIO8,
	FUNC_GPIO9,
	FUNC_GPIO10,
	FUNC_GPIO11,
	FUNC_GPIO12,
	FUNC_GPIO13,
	FUNC_GPIO14,
	FUNC_GPIO15
};

@micw
Copy link
Author

micw commented Oct 25, 2020

common_wifi.h

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WIFI_SSID);

  WiFi.mode(WIFI_STA); // disable hotspot
  WiFi.begin(WIFI_SSID,WIFI_PASSWORD);
  wdt_reset(); // Watchdock resetten

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

@micw
Copy link
Author

micw commented Oct 25, 2020

common_mqtt.h

#define MQTT_KEEPALIVE 10

#include <PubSubClient.h>

extern const char* MQTT_FALSE = "0";
extern const char* MQTT_TRUE = "1";

WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

char MQTT_CLIENT_ID[15];

void setup_mqtt() {
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  byte mac[6];
  WiFi.macAddress(mac);
  sprintf(MQTT_CLIENT_ID, "ESP8266_%02X%02X%02X", mac[3], mac[4], mac[5]);
}

void connect_mqtt(char* MQTT_TOPIC) {
  // Loop until we're reconnected
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
#if defined(MQTT_ALIVE_TOPIC)
    byte mac[6];
    WiFi.macAddress(mac);
    char aliveTopicId[7];
    sprintf(aliveTopicId, "%02X%02X%02X", mac[3], mac[4], mac[5]);
    char aliveTopic[255];
    sprintf(aliveTopic, MQTT_ALIVE_TOPIC, aliveTopicId);
    if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD, aliveTopic, 1, 1, MQTT_FALSE)) {
      Serial.println("connected with last will and testament enabled");
      mqttClient.publish(aliveTopic,MQTT_TRUE,1);
      Serial.print("Sent alive message to ");
      Serial.println(aliveTopic);
#else
    if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD)) {
      Serial.println("connected");
#endif
      if (MQTT_TOPIC && mqttClient.subscribe(MQTT_TOPIC,1)) {
        Serial.print("Subscribed to ");
        Serial.println(MQTT_TOPIC);
      }
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
      wdt_reset();
    }
  }
}

@di-ai-wai
Copy link

di-ai-wai commented Oct 26, 2020

thanx, I already found the relevant post in iobroker forum, where you linked the files from your github project :-)
that's why i deleted my post here.
br
Stefan

@t1me2die
Copy link

Hi, habe aktuell ein Problem mit der ermittelten Temperatur.
Ich vermute, dass eine negative Temperatur (ca. -5,0°C) falsch umgesetzt wird (Zeile 114-118).
Aktuell bekomme ich nämlich eine Temperatur von ~6550°C angezeigt.

Gruß
Mathias

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment