@ -32,6 +32,8 @@
# include "network/XD0OTA.h"
# include "network/XD0MQTT.h"
# include <ArduinoJson.h>
# include "SensorHistory.h"
# include "icons.h"
@ -42,6 +44,10 @@ uint8_t temprature_sens_read();
static const char * TAG = " MAIN " ;
# define TIME_TO_SLEEP 60 // seconds
constexpr unsigned int dhcp_interval = 60 * 60 ;
WiFiMulti wifiMulti ;
GxEPD2_BW < GxEPD2_213_B72 , GxEPD2_213_B72 : : HEIGHT > display ( GxEPD2_213_B72 ( /*CS=SS*/ TFT_CS , /*DC=*/ TFT_DC , /*RST=*/ TFT_RST , /*BUSY=*/ - 1 ) ) ; // GDEH0213B72
static constexpr uint8_t y_offset = 6 ;
@ -53,8 +59,22 @@ SdsDustSensor sds(Serial2);
Adafruit_VEML6075 uv = Adafruit_VEML6075 ( ) ;
BH1750 lightMeter ;
XD0OTA ota ( " esp32-weatherstation " ) ;
constexpr unsigned int JSON_BUF_LEN = 512 ;
constexpr unsigned int JSON_CAPACITY = JSON_OBJECT_SIZE ( 16 ) + 0 * JSON_ARRAY_SIZE ( 2 ) + 120 ;
XD0MQTT mqtt ;
XD0OTA ota ( " esp32-weatherstation " ) ;
struct __attribute__ ( ( packed ) ) network_t {
uint32_t ip ;
uint32_t dns ;
uint32_t gateway ;
uint32_t subnet ;
char ssid [ 64 ] ;
char password [ 64 ] ;
int32_t channel ;
time_t last_dhcp ;
} ;
RTC_DATA_ATTR network_t network ;
struct __attribute__ ( ( packed ) ) sensor_readings_t {
float temperature = NAN ; // °C
@ -72,22 +92,143 @@ struct __attribute__((packed)) sensor_readings_t {
float temperature_min = NAN ; // °C
int battery = 0 ;
int8_t rssi = 0 ;
uint32 _t lastUpdate = 0 ;
time _t lastUpdate = 0 ;
} sensor_readings ;
sensor_readings_t sensors_a4cf1211c3e4 , sensors_246f28d1fa5c , sensors_246f28d1a080 , sensors_246f28d1eff4 ;
SensorHistory history_pressure ( 30 ) ;
uint32_t lastDisplayUpdate = 0 ;
uint32_t lastDisplayRefresh = 0 ;
bool bme280_active = false ;
bool bme680_active = false ;
bool uv_active = false ;
bool light_active = false ;
bool sds_active = false ;
RTC_DATA_ATTR time_t lastDisplayRefresh = 0 ;
struct __attribute__ ( ( packed ) ) sensors_active_t {
bool bme280 = false ;
bool bme680 = false ;
bool uv = false ;
bool light = false ;
bool sds = false ;
} ;
RTC_DATA_ATTR sensors_active_t sensors_active ;
float station_height = 0 ;
RTC_DATA_ATTR int bootCount = 0 ;
time_t getTimestamp ( ) {
struct timeval tv ;
gettimeofday ( & tv , NULL ) ;
return tv . tv_sec ;
}
void poweroffDevices ( ) {
display . powerOff ( ) ;
if ( sensors_active . bme680 ) {
bme680 . setGasHeater ( 0 , 0 ) ;
}
if ( sensors_active . bme280 ) {
bme280 . setSampling ( Adafruit_BME280 : : MODE_SLEEP ,
Adafruit_BME280 : : SAMPLING_X1 , // temperature
Adafruit_BME280 : : SAMPLING_X1 , // pressure
Adafruit_BME280 : : SAMPLING_X1 , // humidity
Adafruit_BME280 : : FILTER_OFF ) ;
}
if ( sensors_active . light ) {
static constexpr byte BH1750_I2CADDR = 0x23 ;
Wire . beginTransmission ( BH1750_I2CADDR ) ;
Wire . write ( BH1750_POWER_DOWN ) ;
byte ack = Wire . endTransmission ( ) ;
}
if ( sensors_active . uv ) {
uv . shutdown ( true ) ;
}
}
void gotoSleep ( unsigned int sleep_time = TIME_TO_SLEEP ) {
mqtt . end ( ) ;
WiFi . disconnect ( ) ;
WiFi . mode ( WIFI_OFF ) ;
poweroffDevices ( ) ;
//rtc_gpio_isolate(GPIO_NUM_12);
esp_sleep_enable_timer_wakeup ( sleep_time * 1000000LL ) ;
esp_sleep_pd_config ( ESP_PD_DOMAIN_RTC_PERIPH , ESP_PD_OPTION_OFF ) ;
ESP_LOGI ( TAG , " going to to sleep for %d seconds " , sleep_time ) ;
Serial . flush ( ) ;
esp_deep_sleep_start ( ) ;
delay ( 1 ) ;
}
void wifiConnect ( ) {
WiFi . persistent ( false ) ;
WiFi . setHostname ( " esp32-weatherstation " ) ;
wifiMulti . addAP ( WIFI_SSID , WIFI_PASSWD ) ;
wifiMulti . addAP ( WIFI_SSID2 , WIFI_PASSWD2 ) ;
wifiMulti . addAP ( WIFI_SSID3 , WIFI_PASSWD3 ) ;
IPAddress ip = IPAddress ( network . ip ) ;
IPAddress dns = IPAddress ( network . dns ) ;
IPAddress subnet = IPAddress ( network . subnet ) ;
IPAddress gateway = IPAddress ( network . gateway ) ;
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
ESP_LOGD ( TAG , " previous dhcp: %lu s ago " , getTimestamp ( ) - network . last_dhcp ) ;
if ( ip ! = INADDR_NONE & & dns ! = INADDR_NONE & & gateway ! = INADDR_NONE & & subnet ! = INADDR_NONE
& & ( ( ip [ 0 ] = = 192 & & ip [ 1 ] = = 168 ) | | ( ip [ 0 ] = = 172 & & ip [ 1 ] = = 16 ) )
& & strlen ( network . ssid ) > 0 & & strlen ( network . password ) > 0
& & ( getTimestamp ( ) - network . last_dhcp < dhcp_interval )
) {
ESP_LOGD ( " WiFi " , " STATIC IP " ) ;
WiFi . config ( ip , gateway , subnet , dns ) ;
WiFi . begin ( network . ssid , network . password , network . channel ) ;
for ( int tries = 0 ; WiFi . status ( ) ! = WL_CONNECTED & & tries < 10 ; tries + + ) {
ESP_LOGD ( " WiFi " , " . " ) ;
delay ( 500 ) ;
}
} else {
ESP_LOGD ( " WiFi " , " DHCP " ) ;
for ( int tries = 0 ; wifiMulti . run ( ) ! = WL_CONNECTED & & tries < 20 ; tries + + ) {
ESP_LOGD ( " WiFi " , " . " ) ;
delay ( 500 ) ;
}
network . ip = ( uint32_t ) WiFi . localIP ( ) ;
network . dns = ( uint32_t ) WiFi . dnsIP ( ) ;
network . gateway = ( uint32_t ) WiFi . gatewayIP ( ) ;
network . subnet = ( uint32_t ) WiFi . subnetMask ( ) ;
strncpy ( network . ssid , WiFi . SSID ( ) . c_str ( ) , 64 ) ;
strncpy ( network . password , WiFi . psk ( ) . c_str ( ) , 64 ) ;
network . channel = WiFi . channel ( ) ;
network . last_dhcp = getTimestamp ( ) ;
}
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
if ( WiFi . status ( ) = = WL_CONNECTED ) {
ESP_LOGD ( " WiFi " , " connected " ) ;
//ESP_LOGD("WiFi", (WiFi.localIP().toString().c_str()));
} else {
ESP_LOGE ( " WiFi " , " could not connect to WiFi " ) ;
ESP_LOGE ( TAG , " restarting " ) ;
ESP . restart ( ) ;
}
}
bool obtain_time ( ) {
ESP_LOGI ( TAG , " syncing time " ) ;
configTzTime ( " CET-1CEST,M3.5.0/2,M10.5.0/3 " , " de.pool.ntp.org " ) ;
struct tm timeinfo ;
return getLocalTime ( & timeinfo , 5000 ) ;
}
void helloWorld ( )
{
@ -101,7 +242,11 @@ void helloWorld()
// center bounding box by transposition of origin:
uint16_t x = ( ( display . width ( ) - tbw ) / 2 ) - tbx ;
uint16_t y = ( ( display . height ( ) - tbh ) / 2 ) - tby ;
display . setFullWindow ( ) ;
if ( display . epd2 . hasFastPartialUpdate ) {
display . setPartialWindow ( 0 , 0 , display . width ( ) , display . height ( ) ) ;
} else {
display . setFullWindow ( ) ;
}
display . firstPage ( ) ;
do
{
@ -139,20 +284,28 @@ void getTime(char* ptr, size_t maxsize, const char* format) {
void getSensorMeasurements ( ) {
if ( bme280_active ) {
if ( sensors_active . bme280 ) {
bme280 . takeForcedMeasurement ( ) ;
sensor_readings . temperature = bme280 . readTemperature ( ) ;
sensor_readings . humidity = bme280 . readHumidity ( ) ;
sensor_readings . pressure_raw = bme280 . readPressure ( ) ;
ESP_LOGI ( TAG , " Temperature : %8.2f °C " , sensor_readings . temperature ) ;
ESP_LOGI ( TAG , " Pressure (Raw): %8.2f Pa " , sensor_readings . pressure_raw ) ;
ESP_LOGI ( TAG , " Humidity : %8.2f % " , sensor_readings . humidity ) ;
}
if ( bme680_active ) {
if ( sensors_active . bme680 ) {
bme680 . endReading ( ) ; // ToDo
if ( bme680 . performReading ( ) ) {
sensor_readings . temperature = bme680 . temperature ;
sensor_readings . humidity = bme680 . humidity ;
sensor_readings . pressure_raw = bme680 . pressure ;
sensor_readings . voc = bme680 . gas_resistance ;
ESP_LOGI ( TAG , " Temperature : %8.2f °C " , sensor_readings . temperature ) ;
ESP_LOGI ( TAG , " Pressure (Raw): %8.2f Pa " , sensor_readings . pressure_raw ) ;
ESP_LOGI ( TAG , " Humidity : %8.2f % " , sensor_readings . humidity ) ;
ESP_LOGI ( TAG , " VOC : %5lu kOhm " , sensor_readings . voc ) ;
} else {
Serial . println ( " Failed to perform reading :( " ) ;
ESP_LOGE ( TAG , " Failed to perform BME680 reading :( " ) ;
}
}
@ -174,50 +327,62 @@ void getSensorMeasurements() {
history_pressure . addValue ( sensor_readings . pressure ) ;
if ( uv_active ) {
if ( sensors_active . uv ) {
sensor_readings . uvi = uv . readUVI ( ) ;
sensor_readings . uva = uv . readUVA ( ) ;
sensor_readings . uvb = uv . readUVB ( ) ;
ESP_LOGI ( TAG , " UVI : %8.2f " , sensor_readings . uvi ) ;
ESP_LOGI ( TAG , " UVA : %8.2f " , sensor_readings . uva ) ;
ESP_LOGI ( TAG , " UVB : %8.2f " , sensor_readings . uvb ) ;
}
if ( light_active ) {
if ( sensors_active . light ) {
sensor_readings . lux = lightMeter . readLightLevel ( ) ;
// auto-adjust sensitivity
if ( sensor_readings . lux < 0 ) {
Serial . println ( " Error reading light level " ) ;
ESP_LOGE ( TAG , " Error reading light level " ) ;
} else if ( sensor_readings . lux > 40000.0 ) {
if ( lightMeter . setMTreg ( 32 ) ) {
Serial . println ( F ( " Setting MTReg to low value for high light environment " ) ) ;
ESP_LOGD ( TAG , " Setting MTReg to low value for high light environment " ) ;
}
} else if ( sensor_readings . lux < = 10.0 ) {
if ( lightMeter . setMTreg ( 138 ) ) {
Serial . println ( F ( " Setting MTReg to high value for low light environment " ) ) ;
ESP_LOGD ( TAG , " Setting MTReg to high value for low light environment " ) ;
}
} else { // if (sensor_readings.lux > 10.0)
if ( lightMeter . setMTreg ( 69 ) ) {
Serial . println ( F ( " Setting MTReg to default value for normal light environment " ) ) ;
ESP_LOGD ( TAG , " Setting MTReg to default value for normal light environment " ) ;
}
}
ESP_LOGI ( TAG , " Lux : %8.2f lx " , sensor_readings . lux ) ;
}
if ( sds_active ) {
if ( sensors_active . sds ) {
PmResult pm = sds . readPm ( ) ;
if ( pm . isOk ( ) ) {
sensor_readings . pm10 = pm . pm10 ;
sensor_readings . pm25 = pm . pm25 ;
ESP_LOGI ( TAG , " PM10 : %8.2f µg/m³ " , sensor_readings . pm10 ) ;
ESP_LOGI ( TAG , " PM2.5 : %8.2f µg/m³ " , sensor_readings . pm25 ) ;
}
}
sensor_readings . battery = analogRead ( _VBAT ) ;
sensor_readings . rssi = WiFi . RSSI ( ) ;
sensor_readings . lastUpdate = millis ( ) ;
ESP_LOGI ( TAG , " RSSI : %5d dBm " , sensor_readings . rssi ) ;
ESP_LOGI ( TAG , " Battery : %5d " , sensor_readings . battery ) ;
ESP_LOGI ( TAG , " Heap : %5lu " , ESP . getFreeHeap ( ) ) ;
sensor_readings . lastUpdate = getTimestamp ( ) ;
}
void receiveMqtt ( const char * topic , const char * data ) {
void receiveMqtt ( const char * topic , const char * data , int data_len ) {
sensor_readings_t * sensor = NULL ;
ESP_LOGI ( TAG , " received MQTT message on subscribed topic %s " , topic ) ;
if ( strstr ( topic , " thomas/sensor/a4cf1211c3e4 " ) = = topic ) {
sensor = & sensors_a4cf1211c3e4 ;
} else if ( strstr ( topic , " thomas/sensor/246f28d1fa5c " ) = = topic ) {
@ -231,8 +396,32 @@ void receiveMqtt(const char* topic, const char* data) {
char * topic_last = strrchr ( topic , ' / ' ) ;
if ( topic_last & & sensor ) {
if ( strcmp ( " /temperature " , topic_last ) = = 0 ) {
if ( strcmp ( " /json " , topic_last ) = = 0 ) {
StaticJsonDocument < JSON_CAPACITY + 120 > jsonDoc ;
DeserializationError err = deserializeJson ( jsonDoc , data , data_len ) ;
if ( err ) {
ESP_LOGW ( TAG , " Error parsing JSON, code: %s " , err . c_str ( ) ) ;
} else {
// got json
if ( jsonDoc . containsKey ( " temperature " ) ) sensor - > temperature = jsonDoc [ " temperature " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " humidity " ) ) sensor - > humidity = jsonDoc [ " humidity " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " pressure " ) ) sensor - > pressure = jsonDoc [ " pressure " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " voc " ) ) sensor - > voc = jsonDoc [ " voc " ] . as < uint32_t > ( ) ;
if ( jsonDoc . containsKey ( " lux " ) ) sensor - > lux = jsonDoc [ " lux " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " uvi " ) ) sensor - > uvi = jsonDoc [ " uvi " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " uva " ) ) sensor - > uva = jsonDoc [ " uva " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " uvb " ) ) sensor - > uvb = jsonDoc [ " uvb " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " pm10 " ) ) sensor - > pm10 = jsonDoc [ " pm10 " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " pm2.5 " ) ) sensor - > pm25 = jsonDoc [ " pm2.5 " ] . as < float > ( ) ;
if ( jsonDoc . containsKey ( " voltage " ) ) sensor - > battery = jsonDoc [ " voltage " ] . as < int > ( ) ;
if ( jsonDoc . containsKey ( " rssi " ) ) sensor - > rssi = jsonDoc [ " rssi " ] . as < int8_t > ( ) ;
if ( jsonDoc . containsKey ( " timestamp " ) ) sensor - > lastUpdate = jsonDoc [ " timestamp " ] . as < time_t > ( ) ;
ESP_LOGI ( TAG , " got new values from %s, timestamp: %lu " , topic , sensor - > lastUpdate ) ;
ESP_LOGI ( TAG , " %lu seconds ago " , topic , getTimestamp ( ) - sensor - > lastUpdate ) ;
}
} else if ( strcmp ( " /temperature " , topic_last ) = = 0 ) {
sensor - > temperature = atof ( data ) ;
sensor - > lastUpdate = getTimestamp ( ) ;
} else if ( strcmp ( " /humidity " , topic_last ) = = 0 ) {
sensor - > humidity = atof ( data ) ;
} else if ( strcmp ( " /pressure " , topic_last ) = = 0 ) {
@ -252,7 +441,6 @@ void receiveMqtt(const char* topic, const char* data) {
} else if ( strcmp ( " /voc " , topic_last ) = = 0 ) {
sensor - > voc = atof ( data ) ;
}
sensor - > lastUpdate = millis ( ) ;
}
}
@ -267,6 +455,7 @@ void displayValues() {
char timeStr [ 40 ] ;
getTime ( timeStr , sizeof ( timeStr ) , " %d. %b %Y %H:%M:%S " ) ;
ESP_LOGD ( TAG , " displayValues() " ) ;
if ( display . epd2 . hasFastPartialUpdate ) {
display . setPartialWindow ( 0 , 0 , display . width ( ) , display . height ( ) ) ;
@ -354,7 +543,7 @@ void displayValues() {
display . printf ( " %.1f k \xe9 " , sensor_readings . voc / 1000.0F ) ;
// PM
float pm10 , pm25 ;
if ( sds_active ) {
if ( sensors_active . sds ) {
pm10 = sensor_readings . pm10 ;
pm25 = sensor_readings . pm25 ;
} else if ( ! isnan ( sensors_a4cf1211c3e4 . pm10 ) | | ! isnan ( sensors_a4cf1211c3e4 . pm25 ) ) {
@ -378,7 +567,7 @@ void displayValues() {
display . printf ( " %.1f " , pm25 ) ;
// Lux
float lux ;
if ( light_active ) {
if ( sensors_active . light ) {
lux = sensor_readings . lux ;
} else if ( ! isnan ( sensors_a4cf1211c3e4 . lux ) ) {
lux = sensors_a4cf1211c3e4 . lux ;
@ -395,7 +584,7 @@ void displayValues() {
display . printf ( " %.1f lx " , lux ) ;
// UV
float uvi , uva , uvb ;
if ( uv_active ) {
if ( sensors_active . uv ) {
uvi = sensor_readings . uvi ;
uva = sensor_readings . uva ;
uvb = sensor_readings . uvb ;
@ -428,16 +617,16 @@ void displayValues() {
// other nodes
display . setFont ( NULL ) ;
display . setCursor ( 0 , y_offset + 70 ) ;
if ( ! ota . getMAC ( ) . equals ( " 246f28d1fa5c " ) & & millis ( ) - sensors_246f28d1fa5c . lastUpdate < 15 * 60 * 100 0 ) {
if ( ! ota . getMAC ( ) . equals ( " 246f28d1fa5c " ) & & getTimestamp ( ) - sensors_246f28d1fa5c . lastUpdate < 15 * 60 ) {
display . printf ( " 246f28d1fa5c: %4.1f %4.1f %6.1f \n " , sensors_246f28d1fa5c . temperature , sensors_246f28d1fa5c . humidity , sensors_246f28d1fa5c . pressure ) ;
}
if ( ! ota . getMAC ( ) . equals ( " a4cf1211c3e4 " ) & & millis ( ) - sensors_a4cf1211c3e4 . lastUpdate < 15 * 60 * 100 0 ) {
if ( ! ota . getMAC ( ) . equals ( " a4cf1211c3e4 " ) & & getTimestamp ( ) - sensors_a4cf1211c3e4 . lastUpdate < 15 * 60 ) {
display . printf ( " a4cf1211c3e4: %4.1f %4.1f %6.1f \n " , sensors_a4cf1211c3e4 . temperature , sensors_a4cf1211c3e4 . humidity , sensors_a4cf1211c3e4 . pressure ) ;
}
if ( ! ota . getMAC ( ) . equals ( " 246f28d1a080 " ) & & millis ( ) - sensors_246f28d1a080 . lastUpdate < 15 * 60 * 100 0 ) {
if ( ! ota . getMAC ( ) . equals ( " 246f28d1a080 " ) & & getTimestamp ( ) - sensors_246f28d1a080 . lastUpdate < 15 * 60 ) {
display . printf ( " 246f28d1a080: %4.1f %4.1f %6.1f \n " , sensors_246f28d1a080 . temperature , sensors_246f28d1a080 . humidity , sensors_246f28d1a080 . pressure ) ;
}
if ( ! ota . getMAC ( ) . equals ( " 246f28d1eff4 " ) & & millis ( ) - sensors_246f28d1eff4 . lastUpdate < 15 * 60 * 100 0 ) {
if ( ! ota . getMAC ( ) . equals ( " 246f28d1eff4 " ) & & getTimestamp ( ) - sensors_246f28d1eff4 . lastUpdate < 15 * 60 ) {
display . printf ( " 246f28d1eff4: %4.1f %4.1f %6.1f \n " , sensors_246f28d1eff4 . temperature , sensors_246f28d1eff4 . humidity , sensors_246f28d1eff4 . pressure ) ;
}
@ -448,58 +637,45 @@ void displayValues() {
}
void printValues ( ) {
if ( bme280_active | | bme680_active ) {
# define SEALEVELPRESSURE_HPA (1013.25)
Serial . print ( " Temperature = " ) ;
Serial . print ( sensor_readings . temperature ) ;
Serial . println ( " *C " ) ;
Serial . print ( " Pressure = " ) ;
Serial . print ( sensor_readings . pressure ) ;
Serial . println ( " hPa " ) ;
Serial . print ( " Pressure [RAW] = " ) ;
Serial . print ( sensor_readings . pressure_raw / 100.0F ) ;
Serial . println ( " hPa " ) ;
Serial . print ( " Humidity = " ) ;
Serial . print ( sensor_readings . humidity ) ;
Serial . println ( " % " ) ;
}
if ( bme680_active ) {
Serial . print ( " VOC = " ) ;
Serial . print ( sensor_readings . voc / 1000.0F ) ;
Serial . println ( " kOhm " ) ;
}
Serial . println ( ) ;
if ( uv_active ) {
Serial . print ( " UV Index reading: " ) ; Serial . println ( sensor_readings . uvi ) ;
Serial . print ( " Raw UVA reading: " ) ; Serial . println ( sensor_readings . uva ) ;
Serial . print ( " Raw UVB reading: " ) ; Serial . println ( sensor_readings . uvb ) ;
Serial . println ( ) ;
}
if ( sds_active ) {
Serial . print ( " PM2.5 = " ) ;
Serial . print ( sensor_readings . pm25 ) ;
Serial . print ( " , PM10 = " ) ;
Serial . println ( sensor_readings . pm10 ) ;
}
Serial . print ( " RSSI: " ) ; Serial . println ( sensor_readings . rssi ) ;
Serial . print ( " Battery: " ) ; Serial . println ( sensor_readings . battery ) ;
Serial . print ( " Free HEAP: " ) ; Serial . println ( ESP . getFreeHeap ( ) ) ;
}
void sendValues ( ) {
for ( int tries = 0 ; mqtt . isConnected ( ) = = false & & tries < 10 ; tries + + ) {
ESP_LOGD ( TAG , " waiting for mqtt connection " ) ;
delay ( 300 ) ;
}
/* send values MQTT JSON */
char buf [ JSON_BUF_LEN ] ;
StaticJsonDocument < JSON_CAPACITY > jsonDoc ;
if ( sensors_active . bme280 | | sensors_active . bme680 ) {
jsonDoc [ " temperature " ] = sensor_readings . temperature ;
jsonDoc [ " humidity " ] = sensor_readings . humidity ;
jsonDoc [ " pressure " ] = sensor_readings . pressure ;
}
if ( sensors_active . bme680 ) {
jsonDoc [ " voc " ] = sensor_readings . voc ;
}
if ( sensors_active . light ) {
jsonDoc [ " lux " ] = sensor_readings . lux ;
}
if ( sensors_active . uv ) {
jsonDoc [ " uvi " ] = sensor_readings . uvi ;
jsonDoc [ " uva " ] = sensor_readings . uva ;
jsonDoc [ " uvb " ] = sensor_readings . uvb ;
}
if ( sensors_active . sds ) {
jsonDoc [ " pm10 " ] = sensor_readings . pm10 ;
jsonDoc [ " pm2.5 " ] = sensor_readings . pm25 ;
}
jsonDoc [ " voltage " ] = sensor_readings . battery ;
jsonDoc [ " rssi " ] = sensor_readings . rssi ;
jsonDoc [ " timestamp " ] = sensor_readings . lastUpdate ;
serializeJson ( jsonDoc , buf , JSON_BUF_LEN ) ;
String topic_json = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /json " ) ;
mqtt . publish ( topic_json . c_str ( ) , buf , strlen ( buf ) , 1 , 1 ) ;
delay ( 10 ) ;
/* send values MQTT */
if ( bme280_active | | bme680_active ) {
if ( sensors_active . bme280 | | sensors_active . bme680 ) {
String topic_temperature = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /temperature " ) ;
String topic_humidity = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /humidity " ) ;
String topic_pressure = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /pressure " ) ;
@ -510,20 +686,13 @@ void sendValues() {
mqtt . publishf ( topic_pressure . c_str ( ) , " %.2f " , sensor_readings . pressure ) ;
delay ( 10 ) ;
}
if ( bme680_active ) {
if ( sensors_active . bme680 ) {
String topic_voc = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /voc " ) ;
mqtt . publishf ( topic_voc . c_str ( ) , " %.2f " , sensor_readings . voc / 1000.0F ) ;
delay ( 10 ) ;
}
if ( ! bme280_active & & ! bme680_active ) {
String topic_temperature = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /temperature " ) ;
float esp32_temperature = ( temprature_sens_read ( ) - 32 ) / 1.8 ;
char temperature [ 8 ] ; sprintf ( temperature , " %.2f " , esp32_temperature - 29.40 ) ;
mqtt . publish ( topic_temperature . c_str ( ) , temperature , strlen ( temperature ) ) ;
delay ( 10 ) ;
}
if ( uv_active ) {
if ( sensors_active . uv ) {
String topic_uvi = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /uvi " ) ;
String topic_uva = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /uva " ) ;
String topic_uvb = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /uvb " ) ;
@ -533,13 +702,13 @@ void sendValues() {
delay ( 10 ) ;
}
if ( light_active ) {
if ( sensors_active . light ) {
String topic_lux = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /lux " ) ;
mqtt . publishf ( topic_lux . c_str ( ) , " %.2f " , sensor_readings . lux ) ;
delay ( 10 ) ;
}
if ( sds_active ) {
if ( sensors_active . sds ) {
String topic_pm10 = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /pm10 " ) ;
String topic_pm25 = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /pm25 " ) ;
mqtt . publishf ( topic_pm10 . c_str ( ) , " %.2f " , sensor_readings . pm10 ) ;
@ -569,7 +738,12 @@ void sendValues() {
void setup ( )
{
Serial . begin ( 115200 ) ;
delay ( 10 ) ;
Serial2 . begin ( 9600 , SERIAL_8N1 , /*rx*/ 15 , /*tx*/ 2 ) ; // IMPORTANT: don't run with default pins 16, 17 as they are connected to PSRAM on boards that ship with it
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause ( ) ;
+ + bootCount ;
ESP_LOGI ( TAG , " Boot number: %d " , bootCount ) ;
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
ESP_LOGD ( TAG , " setup hardware and sensors " ) ;
@ -583,20 +757,21 @@ void setup()
adcAttachPin ( _VBAT ) ;
adcStart ( _VBAT ) ;
// initialize e-paper display
SPI . begin ( 18 , 19 , 23 , TFT_CS ) ; // MISO is not connected to TFT_MISO!
display . init ( ) ;
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
# define BME_SDA 21
# define BME_SCL 22
Wire . begin ( BME_SDA , BME_SCL ) ;
if ( bme280 . begin ( ) ) {
bme280_active = true ;
sensors_active . bme280 = true ;
} else {
ESP_LOGE ( TAG , " Could not find a valid BME280 sensor, check wiring! " ) ;
}
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
if ( bme680 . begin ( ) ) {
bme680_active = true ;
sensors_active . bme680 = true ;
// Set up oversampling and filter initialization
bme680 . setTemperatureOversampling ( BME680_OS_8X ) ;
@ -604,12 +779,15 @@ void setup()
bme680 . setPressureOversampling ( BME680_OS_4X ) ;
bme680 . setIIRFilterSize ( BME680_FILTER_SIZE_3 ) ;
bme680 . setGasHeater ( 320 , 150 ) ; // 320*C for 150 ms
bme680 . beginReading ( ) ;
} else {
ESP_LOGE ( TAG , " Could not find a valid BME680 sensor, check wiring! " ) ;
}
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
if ( uv . begin ( ) ) {
uv_active = true ;
sensors_active . uv = true ;
uv . setIntegrationTime ( VEML6075_100MS ) ; // Set the integration constant
uv . setHighDynamic ( true ) ; // Set the high dynamic mode
@ -619,58 +797,72 @@ void setup()
2.95 , 1.74 , // UVB_C and UVB_D coefficients
0.001461 , 0.002591 ) ; // UVA and UVB responses
} else {
Serial . println ( " Failed to communicate with VEML6075 sensor, check wiring? " ) ;
ESP_LOGW ( TAG , " Failed to communicate with VEML6075 sensor, check wiring? " ) ;
}
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
if ( lightMeter . begin ( ) ) {
light_active = true ;
sensors_active . light = true ;
lightMeter . setMTreg ( ( byte ) BH1750_DEFAULT_MTREG ) ;
} else {
Serial . println ( " Failed to communicate with BH1750 sensor, check wiring? " ) ;
ESP_LOGW ( TAG , " Failed to communicate with BH1750 sensor, check wiring? " ) ;
}
sds . begin ( ) ;
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
FirmwareVersionResult sds_fw = sds . queryFirmwareVersion ( ) ;
if ( sds_fw . isOk ( ) ) {
sds_active = true ;
//sds.begin(); // don't call begin, only messes with Serial
sds . setActiveReportingMode ( ) ; // ensures sensor is in 'active' reporting mode
sds . setCustomWorkingPeriod ( 5 ) ; // sensor sends data every 3 minutes
} else {
Serial . println ( " Failed to communicate with SDS011 sensor, check wiring? " ) ;
}
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
//display.clearScreen();
//display.refresh();
if ( wakeup_reason = = ESP_SLEEP_WAKEUP_UNDEFINED | | bootCount = = 1 ) {
FirmwareVersionResult sds_fw = sds . queryFirmwareVersion ( ) ;
if ( sds_fw . isOk ( ) ) {
sensors_active . sds = true ;
ESP_LOGD ( TAG , " displaying welcome screen " ) ;
helloWorld ( ) ;
display . powerOff ( ) ;
sds . setActiveReportingMode ( ) ; // ensures sensor is in 'active' reporting mode
sds . setCustomWorkingPeriod ( 5 ) ; // sensor sends data every 3 minutes
} else {
ESP_LOGW ( TAG , " Failed to communicate with SDS011 sensor, check wiring? " ) ;
}
}
ESP_LOGD ( TAG , " connecting to WiFi " ) ;
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
WiFi . setHostname ( " esp32-weatherstation " ) ;
// initialize e-paper display
SPI . begin ( 18 , 19 , 23 , TFT_CS ) ; // MISO is not connected to TFT_MISO!
display . init ( 0 , false , false ) ;
display . setRotation ( 1 ) ;
wifiMulti . addAP ( WIFI_SSID , WIFI_PASSWD ) ;
wifiMulti . addAP ( WIFI_SSID2 , WIFI_PASSWD2 ) ;
wifiMulti . addAP ( WIFI_SSID3 , WIFI_PASSWD3 ) ;
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
for ( int tries = 0 ; wifiMulti . run ( ) ! = WL_CONNECTED & & tries < 10 ; tries + + ) {
Serial . print ( " . " ) ;
delay ( 500 ) ;
if ( wakeup_reason = = ESP_SLEEP_WAKEUP_UNDEFINED | | bootCount = = 1 ) {
// wakeup not caused by deep sleep
display . clearScreen ( ) ;
display . refresh ( ) ;
lastDisplayRefresh = getTimestamp ( ) ;
helloWorld ( ) ;
display . powerOff ( ) ;
} else {
// wakeup by deep sleep
// displayValues();
}
if ( wifiMulti . run ( ) = = WL_CONNECTED ) {
Serial . println ( " " ) ;
Serial . println ( " WiFi connected " ) ;
Serial . println ( " IP address: " ) ;
Serial . println ( WiFi . localIP ( ) ) ;
displayIcoPartial ( ico_wifi16 , display . width ( ) - 20 , y_offset + 0 , ico_wifi16_width , ico_wifi16_height ) ;
}
ESP_LOGD ( TAG , " connecting to WiFi " ) ;
Serial . println ( " millis(): " + String ( millis ( ) ) ) ;
wifiConnect ( ) ;
ESP_LOGD ( TAG , " trying to fetch over-the-air update " ) ;
if ( WiFi . status ( ) = = WL_CONNECTED ) {
ota . update ( ) ;
WiFi . waitForConnectResult ( ) ;
displayIcoPartial ( ico_wifi16 , display . width ( ) - 20 , y_offset + 0 , ico_wifi16_width , ico_wifi16_height ) ;
if ( wakeup_reason = = ESP_SLEEP_WAKEUP_UNDEFINED | | bootCount = = 1 ) {
// wakeup not caused by deep sleep
obtain_time ( ) ;
ESP_LOGD ( TAG , " trying to fetch over-the-air update " ) ;
if ( WiFi . status ( ) = = WL_CONNECTED ) {
ota . update ( ) ;
}
}
WiFi . setSleep ( true ) ;
@ -678,13 +870,12 @@ void setup()
ESP_LOGD ( TAG , " connecting to MQTT " ) ;
mqtt . begin ( ) ;
if ( ! ota . getMAC ( ) . equals ( " a4cf1211c3e4 " ) ) mqtt . subscribe ( " thomas/sensor/a4cf1211c3e4/# " , receiveMqtt ) ;
if ( ! ota . getMAC ( ) . equals ( " 246f28d1fa5c " ) ) mqtt . subscribe ( " thomas/sensor/246f28d1fa5c/# " , receiveMqtt ) ;
if ( ! ota . getMAC ( ) . equals ( " 246f28d1a080 " ) ) mqtt . subscribe ( " thomas/sensor/246f28d1a080/# " , receiveMqtt ) ;
if ( ! ota . getMAC ( ) . equals ( " 246f28d1eff4 " ) ) mqtt . subscribe ( " thomas/sensor/246f28d1eff4/# " , receiveMqtt ) ;
if ( ! ota . getMAC ( ) . equals ( " a4cf1211c3e4 " ) ) mqtt . subscribe ( " thomas/sensor/a4cf1211c3e4/json " , receiveMqtt ) ;
if ( ! ota . getMAC ( ) . equals ( " 246f28d1fa5c " ) ) mqtt . subscribe ( " thomas/sensor/246f28d1fa5c/json " , receiveMqtt ) ;
if ( ! ota . getMAC ( ) . equals ( " 246f28d1a080 " ) ) mqtt . subscribe ( " thomas/sensor/246f28d1a080/json " , receiveMqtt ) ;
if ( ! ota . getMAC ( ) . equals ( " 246f28d1eff4 " ) ) mqtt . subscribe ( " thomas/sensor/246f28d1eff4/json " , receiveMqtt ) ;
/* temp: publish version */
delay ( 5000 ) ;
String topic_version = String ( " thomas/sensor/ " ) + ota . getMAC ( ) + String ( " /version " ) ;
const char * fw_version_str = String ( FW_VERSION ) . c_str ( ) ;
mqtt . publish ( topic_version . c_str ( ) , fw_version_str , strlen ( fw_version_str ) ) ;
@ -705,27 +896,26 @@ void setup()
*/
void loop ( )
{
/* Do an e-paper display refresh every 1 minutes */
if ( millis ( ) - lastDisplayUpdate > = 1 * 60 * 1000 ) {
lastDisplayUpdate = millis ( ) ;
/* if(wifiMulti.run() != WL_CONNECTED) {
Serial . println ( " WiFi not connected! " ) ;
delay ( 1000 ) ;
} */
/* Do a full refresh every hour */
if ( millis ( ) - lastDisplayRefresh > = 60 * 60 * 1000 ) {
lastDisplayRefresh = millis ( ) ;
display . clearScreen ( ) ;
display . refresh ( ) ;
}
getSensorMeasurements ( ) ;
displayValues ( ) ;
printValues ( ) ;
sendValues ( ) ;
if ( getTimestamp ( ) - lastDisplayRefresh > = 60 * 60 ) {
lastDisplayRefresh = getTimestamp ( ) ;
display . clearScreen ( ) ;
display . refresh ( ) ;
}
if ( wifiMulti . run ( ) ! = WL_CONNECTED ) {
Serial . println ( " WiFi not connected! " ) ;
delay ( 1000 ) ;
}
getSensorMeasurements ( ) ;
sendValues ( ) ;
delay ( 1 ) ;
displayValues ( ) ;
int runtime = millis ( ) / 1000 ;
if ( runtime < 0 | | runtime > = TIME_TO_SLEEP ) runtime = 0 ;
gotoSleep ( TIME_TO_SLEEP - runtime ) ;
delay ( 2000 ) ;
}