Last active
January 18, 2020 17:26
-
-
Save Alacika/2d06d2c96b5caecf99f7ec2eaad32748 to your computer and use it in GitHub Desktop.
Wemos D1 Mini weather station (BH1750 + BME280)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ESP8266WiFi.h> | |
#include <PubSubClient.h> | |
#include <BH1750.h> | |
#include "Seeed_BME280.h" | |
#include <time.h> | |
#include "own_system.h" // Wifi, MQTT, etc definíciók | |
/* | |
// own_system.h | |
#define wifi_ssid "" | |
#define wifi_password "" | |
#define mqtt_server "" | |
#define mqtt_port 1883 | |
#define mqtt_user "" | |
#define mqtt_password "" | |
char mqtt_msg[MQTT_MAX_PACKET_SIZE + 1]; | |
const char *topicin = "domoticz/in"; | |
const char *topicout = "domoticz/out"; | |
*/ | |
#define mqtt_client_id "Weather-Station" | |
#define domoticz_lux_idx "194" | |
#define domoticz_temp_idx "195" | |
#define domoticz_humidity_idx "196" | |
#define domoticz_pressure_idx "197" | |
// #define TEST | |
BH1750 bh1750; | |
BME280 bme280; | |
WiFiClient espClient; | |
PubSubClient mqttClient(espClient); | |
uint16_t lux = 666; | |
float_t temp = 666; | |
float_t humidity = 666; | |
uint8_t hum_stat = 666; | |
float_t pressure = 666; | |
struct | |
{ | |
uint32_t crc32; // 4 bytes | |
uint8_t rf_wake_disabled; // 1 byte, 5 | |
uint8_t ap_channel; // 1 byte, 6 | |
uint8_t ap_mac[6]; // 6 bytes, 12 | |
uint16_t lux; // 2 bytes, 14 | |
float_t temp; // 4 bytes, 18 | |
float_t humidity; // 4 bytes, 22 | |
float_t pressure; // 4 bytes, 26 | |
uint8_t maradek[2]; // 3 bytes, 28 | |
} rtcData; | |
unsigned long startTime; | |
bool rtcValid = false; | |
bool rtcClean = false; | |
#ifdef TEST | |
const int sleepSeconds = 10; | |
#else | |
const int sleepSeconds = 60; | |
#endif | |
// ------------------------------------------------------------------------------------------------ | |
void setup_wifi() | |
{ | |
unsigned long wifiConnectStart = millis(); | |
// Set WiFi to station mode and disconnect from an AP if it was previously connected | |
WiFi.mode(WIFI_STA); | |
WiFi.disconnect(); | |
delay(1); | |
#ifdef TEST | |
Serial.println(); | |
Serial.print("Connecting to "); | |
Serial.print(wifi_ssid); | |
#endif | |
WiFi.forceSleepWake(); | |
delay(1); | |
// Disable the WiFi persistence. The ESP8266 will not load and save WiFi settings in the flash memory. | |
WiFi.persistent( false ); | |
#ifdef TEST | |
IPAddress ip(10, 0, 0, 36); // wemos-d1-4 | |
IPAddress gateway(10, 0, 0, 1); | |
IPAddress subnet(255, 255, 255, 0); | |
IPAddress dns(10, 0, 0, 1); | |
WiFi.config(ip, dns, gateway, subnet); | |
#endif | |
if ( !rtcValid || rtcClean ) | |
{ | |
WiFi.begin( wifi_ssid, wifi_password ); | |
} | |
else | |
{ | |
#ifdef TEST | |
Serial.print("\r\n"); | |
Serial.println(String(rtcData.ap_channel).c_str()); | |
#endif | |
WiFi.begin( wifi_ssid, wifi_password, rtcData.ap_channel, rtcData.ap_mac, true ); | |
} | |
while (WiFi.status() != WL_CONNECTED) | |
{ | |
delay(500); | |
#ifdef TEST | |
Serial.print("."); | |
#endif | |
// Only try for 15 seconds. | |
if (millis() - wifiConnectStart > 15000) | |
{ | |
#ifdef TEST | |
Serial.println(" Failed to connect to WiFi"); | |
#endif | |
delay(5000); // 5mp | |
WiFi.mode(WIFI_OFF); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin( wifi_ssid, wifi_password ); | |
delay(1); | |
ESP.restart(); | |
} | |
} | |
#ifdef TEST | |
Serial.println(" WiFi connected"); | |
Serial.println("IP address: "); | |
Serial.println(WiFi.localIP()); | |
wifiConnectStart = millis() - wifiConnectStart; | |
Serial.print("ConnectTime: "); | |
Serial.print(wifiConnectStart); | |
Serial.println(" milliseconds"); | |
#endif | |
} | |
// ------------------------------------------------------------------------------------------------ | |
void mqtt_reconnect() | |
{ | |
while (!mqttClient.connected()) | |
{ | |
#ifdef TEST | |
Serial.print("Attempting MQTT connection..."); | |
#endif | |
if (mqttClient.connect(mqtt_client_id, mqtt_user, mqtt_password)) | |
{ | |
#ifdef TEST | |
Serial.println(" connected"); | |
#endif | |
mqttClient.subscribe("topicin"); | |
} | |
else | |
{ | |
#ifdef TEST | |
Serial.print(" failed, rc="); | |
Serial.print(mqttClient.state()); | |
Serial.println(" try again in 5 seconds..."); | |
#endif | |
delay(5000); // 5mp | |
} | |
} | |
} | |
// ------------------------------------------------------------------------------------------------ | |
uint32_t calculateCRC32( const uint8_t *data, size_t length ) | |
{ | |
uint32_t crc = 0xffffffff; | |
while ( length-- ) | |
{ | |
uint8_t c = *data++; | |
for ( uint32_t i = 0x80; i > 0; i >>= 1 ) | |
{ | |
bool bit = crc & 0x80000000; | |
if ( c & i ) | |
{ | |
bit = !bit; | |
} | |
crc <<= 1; | |
if ( bit ) | |
{ | |
crc ^= 0x04c11db7; | |
} | |
} | |
} | |
return crc; | |
} | |
// ------------------------------------------------------------------------------------------------ | |
void setup() | |
{ | |
startTime = micros(); | |
Serial.begin(115200); | |
while (!Serial) { } | |
} | |
// ------------------------------------------------------------------------------------------------ | |
void loop() | |
{ | |
#ifdef TEST | |
Serial.print("\r\n\nReset reason: "); | |
Serial.println(ESP.getResetReason()); | |
#endif | |
if (ESP.getResetReason() != "Deep-Sleep Wake") | |
{ | |
#ifdef TEST | |
Serial.println("Non deep-sleep wake. Clearing RTC data storage."); | |
#endif | |
rtcData.rf_wake_disabled = 0; | |
rtcData.ap_channel = 0; | |
rtcData.lux = 0; | |
rtcData.temp = 0; | |
rtcData.humidity = 0; | |
rtcData.pressure = 0; | |
rtcClean = true; | |
rtcData.crc32 = calculateCRC32( ((uint8_t*)&rtcData) + 4, sizeof( rtcData ) - 4 ); | |
ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData)); | |
} | |
if ( ESP.rtcUserMemoryRead( 0, (uint32_t*)&rtcData, sizeof( rtcData ) ) ) | |
{ | |
// Calculate the CRC of what we just read from RTC memory, but skip the first 4 bytes as that's the checksum itself. | |
if ( rtcClean != true ) | |
{ | |
uint32_t crc = calculateCRC32( ((uint8_t*)&rtcData) + 4, sizeof( rtcData ) - 4 ); | |
if ( crc == rtcData.crc32 ) | |
{ | |
rtcValid = true; | |
} | |
} | |
else | |
{ | |
rtcValid = true; | |
} | |
// Initialize WEMOS D1 mini | |
// D1, SCL GPIO5 | |
// D2, SDA GPIO4 | |
Wire.begin(4, 5); // SDA GPIO4, SCL GPIO5 | |
/* | |
I2C scanner. Scanning ... | |
Found address: 35 (0x23) // BH1750 | |
Found address: 118 (0x76) // BME280 | |
*/ | |
/* | |
Serial monitor: | |
[BH1750] ERROR: received NACK on transmit of address | |
[BH1750] ERROR: received NACK on transmit of data | |
[BH1750] ERROR: other error | |
[BH1750] ERROR: undefined error | |
BH1750 device error! | |
*/ | |
/* | |
BH1750_CONTINUOUS_LOW_RES_MODE | |
BH1750_CONTINUOUS_HIGH_RES_MODE (default) | |
BH1750_CONTINUOUS_HIGH_RES_MODE_2 | |
BH1750_ONE_TIME_LOW_RES_MODE | |
BH1750_ONE_TIME_HIGH_RES_MODE | |
BH1750_ONE_TIME_HIGH_RES_MODE_2 | |
*/ | |
// if (!bh1750.begin(BH1750::ONE_TIME_LOW_RES_MODE)) | |
if (!bh1750.begin()) | |
{ | |
#ifdef TEST | |
Serial.println("BH1750 device error!"); | |
#endif | |
} | |
else | |
{ | |
#ifdef TEST | |
Serial.println("BH1750 OK!"); | |
#endif | |
// lux = bh1750.readLightLevel(true); | |
lux = bh1750.readLightLevel(); | |
if (lux > 5) | |
{ | |
lux = round(lux / 10) * 10; // Keretítve 0 vagy 5 pontosságra | |
} | |
} | |
if (!bme280.init()) | |
{ | |
#ifdef TEST | |
Serial.println("BME280 device error!"); | |
#endif | |
} | |
else | |
{ | |
temp = bme280.getTemperature(); | |
temp = round(temp * 10) / 10.0; | |
humidity = bme280.getHumidity(); | |
pressure = ( bme280.getPressure() / 100 ); // pressure in Pa / 100 = pressure in hPa or mbar | |
// BH1750 | |
// ------------------------------------- | |
#ifdef TEST | |
Serial.print("Lux: "); | |
Serial.print(lux); | |
Serial.print(" / "); | |
Serial.println(rtcData.lux); | |
// BME280 | |
// ------------------------------------- | |
Serial.print("Temp: "); | |
Serial.print(temp); | |
Serial.print("C"); | |
Serial.print(" / "); | |
Serial.print(rtcData.temp); | |
Serial.println("C"); | |
// ------------------------------------- | |
Serial.print("Humidity: "); | |
Serial.print(humidity); | |
Serial.print("%"); | |
Serial.print(" / "); | |
Serial.print(rtcData.humidity); | |
Serial.println("%"); | |
// ------------------------------------- | |
Serial.print("Pressure: "); | |
Serial.print(pressure); | |
Serial.print("mbar"); | |
Serial.print(" / "); | |
Serial.print(rtcData.pressure); | |
Serial.println("mbar"); | |
#endif | |
// if ( rtcData.lux != lux || rtcData.temp != temp || rtcData.humidity != humidity || rtcData.pressure != pressure ) | |
if ( rtcData.lux != lux || rtcData.temp != temp || rtcData.humidity != humidity ) | |
{ | |
if ( rtcData.rf_wake_disabled == 0 ) | |
{ | |
setup_wifi(); | |
mqttClient.setServer(mqtt_server, mqtt_port); | |
if (!mqttClient.connected()) | |
{ | |
mqtt_reconnect(); | |
} | |
mqttClient.loop(); | |
// On the ESP8266 it has been reported that an additional delay(10); after mqttClient.loop(); | |
// fixes many stability issues with WiFi connections. | |
delay(10); | |
// BH1750 | |
// ------------------------------------- | |
String dataMsg = "{\"idx\":"; | |
dataMsg.concat(domoticz_lux_idx); | |
dataMsg.concat(",\"svalue\":\""); | |
dataMsg.concat(String(lux).c_str()); | |
dataMsg.concat("\"}"); | |
dataMsg.toCharArray(mqtt_msg, dataMsg.length() + 1); | |
#ifndef TEST | |
mqttClient.publish(topicin, mqtt_msg, true); | |
#endif | |
// BME280 | |
// get temperatures | |
// ------------------------------------- | |
dataMsg = "{\"idx\":"; | |
dataMsg.concat(domoticz_temp_idx); | |
dataMsg.concat(",\"svalue\":\""); | |
dataMsg.concat(String(temp).c_str()); | |
dataMsg.concat("\"}"); | |
dataMsg.toCharArray(mqtt_msg, dataMsg.length() + 1); | |
#ifndef TEST | |
mqttClient.publish(topicin, mqtt_msg, true); | |
#endif | |
// get humidity data | |
// ------------------------------------- | |
// hum_stat: | |
// 0=Normal | |
// 1=Comfortable | |
// 2=Dry | |
// 3=Wet | |
hum_stat = 0; // Normal | |
if ( humidity > 60 ) | |
{ | |
hum_stat = 3; // Wet | |
} | |
else if ( humidity < 30 ) | |
{ | |
hum_stat = 2; // Dry | |
} | |
else if ( humidity > 45 & humidity <= 60 ) | |
{ | |
hum_stat = 1; // Comfortable | |
} | |
dataMsg = "{\"idx\":"; | |
dataMsg.concat(domoticz_humidity_idx); | |
dataMsg.concat(",\"nvalue\":"); | |
dataMsg.concat(String(round(humidity)).c_str()); | |
dataMsg.concat(",\"svalue\":\""); | |
dataMsg.concat(String(hum_stat).c_str()); | |
dataMsg.concat("\"}"); | |
dataMsg.toCharArray(mqtt_msg, dataMsg.length() + 1); | |
#ifndef TEST | |
mqttClient.publish(topicin, mqtt_msg, true); | |
#endif | |
// get atmospheric pressure data | |
// ------------------------------------- | |
dataMsg = "{\"idx\":"; | |
dataMsg.concat(domoticz_pressure_idx); | |
dataMsg.concat(",\"svalue\":\""); | |
dataMsg.concat(String(pressure).c_str()); | |
dataMsg.concat("\"}"); | |
dataMsg.toCharArray(mqtt_msg, dataMsg.length() + 1); | |
#ifndef TEST | |
mqttClient.publish(topicin, mqtt_msg, true); | |
#endif | |
/* | |
// get and print altitude data | |
// ------------------------------------- | |
float altitude = bme280.calcAltitude(pressure); | |
Serial.print("Altitude: "); | |
Serial.print(altitude); | |
Serial.println("m"); | |
*/ | |
#ifdef TEST | |
long rssi = WiFi.RSSI(); | |
Serial.print("WiFi RSSI:"); | |
Serial.println(rssi); | |
#endif | |
rtcData.ap_channel = WiFi.channel(); | |
memcpy( rtcData.ap_mac, WiFi.BSSID(), 6 ); // Copy 6 bytes of BSSID (AP's MAC address) | |
rtcData.lux = lux; | |
rtcData.temp = temp; | |
rtcData.humidity = humidity; | |
rtcData.pressure = pressure; | |
rtcData.rf_wake_disabled++; | |
} | |
else | |
{ | |
rtcData.rf_wake_disabled = 0; | |
} | |
} | |
else | |
{ | |
#ifdef TEST | |
Serial.println("\r\nNINCS VÁLTOZÁS!!!\n"); | |
#endif | |
if ( rtcData.rf_wake_disabled >= 60 ) // Legalább 60 perc telt el az utolsó jelentés óta | |
rtcData.rf_wake_disabled = 0; | |
else | |
rtcData.rf_wake_disabled++; | |
} | |
rtcData.crc32 = calculateCRC32( ((uint8_t*)&rtcData) + 4, sizeof( rtcData ) - 4 ); | |
ESP.rtcUserMemoryWrite( 0, (uint32_t*)&rtcData, sizeof( rtcData ) ); | |
delay(50); // 0.05mp Ez fontos! | |
} | |
} | |
else | |
{ | |
#ifdef TEST | |
Serial.println("RTC Memory read failed"); | |
#endif | |
rtcData.rf_wake_disabled = 0; | |
} | |
WiFi.disconnect( true ); | |
delay( 1 ); | |
WiFi.forceSleepBegin(); | |
delay( 1 ); | |
startTime = micros() - startTime; | |
#ifdef TEST | |
Serial.print("RunningTime: "); | |
Serial.print(startTime / 1000); | |
Serial.println(" milliseconds"); | |
Serial.print("Entering to deep sleep for "); | |
Serial.print(sleepSeconds); | |
Serial.print(" seconds and waking up with "); | |
if ( rtcData.rf_wake_disabled == 0 ) | |
Serial.println("wifi enabled"); | |
else | |
Serial.println("wifi disabled"); | |
#endif | |
if ( rtcData.rf_wake_disabled == 0 ) | |
ESP.deepSleep(sleepSeconds * 1000000, WAKE_RF_DEFAULT); | |
else | |
ESP.deepSleep(sleepSeconds * 1000000, WAKE_RF_DISABLED); | |
} |
So i have set ' Wire.begin(D3, D4)'
If you set the right board under tools, you do not need to supply pin info to 'Wire.begin()' unless you us different pins.
On theWemos D1 it is // D1, SCL GPIO5
// D2, SDA GPIO4
So, Wire.begin(4,5);
I have connected the BME280 to the same SCL,SDA lines as the BH1750, i get 'BME280 device error!' in console.
Try the BME280 stand alone with one of the example programs in order to see if it actually works. Mind you that many BME280's old turn out to be BMP280
also what board did you use? anything special you needed to do for the deepsleep function?
From the code it appears the Wemos D1 mini was used. Only thing needed is to connect RST to GPIO16/D0
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how did you setup your wiring ? i am trying to get this to work with a Wemos D1 mini.
So i have set ' Wire.begin(D3, D4)'
When defining test i get 'BH1750 OK!' on console, but i cant get the BME280 to work.
I have connected the BME280 to the same SCL,SDA lines as the BH1750, i get 'BME280 device error!' in console.
I have also tried connecting CSB and SD0 of the BME280 to 3v, then i do not get the 'BME280 device error!' error but the code does not continue running. when i add a println() above 'temp = bme280.getTemperature();' it does not get printed :(
also what board did you use? anything special you needed to do for the deepsleep function?