Skip to content

Instantly share code, notes, and snippets.

@Alacika
Last active January 18, 2020 17:26
Show Gist options
  • Save Alacika/2d06d2c96b5caecf99f7ec2eaad32748 to your computer and use it in GitHub Desktop.
Save Alacika/2d06d2c96b5caecf99f7ec2eaad32748 to your computer and use it in GitHub Desktop.
Wemos D1 Mini weather station (BH1750 + BME280)
#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);
}
@Warsenius
Copy link

Warsenius commented Dec 30, 2018

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?

@consolacion
Copy link

consolacion commented Jan 18, 2020

@Warsenius

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