Code cleanups
This commit is contained in:
Submodule components/Adafruit_TSL2561 updated: 8737563fa6...98cf7b89b9
Submodule components/DHT-sensor-library updated: 845a39f12b...5b9e8755b6
@@ -2,10 +2,30 @@ idf_build_get_property(project_dir PROJECT_DIR)
|
|||||||
message(STATUS "The project dir is: ${project_dir}")
|
message(STATUS "The project dir is: ${project_dir}")
|
||||||
|
|
||||||
set(headers
|
set(headers
|
||||||
|
feature_bmp.h
|
||||||
|
feature_dht.h
|
||||||
|
feature_lamp.h
|
||||||
|
feature_switch.h
|
||||||
|
feature_tsl.h
|
||||||
|
myconfig.h
|
||||||
|
mymdns.h
|
||||||
|
mymqtt.h
|
||||||
|
mywifi.h
|
||||||
|
webserver.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(sources
|
set(sources
|
||||||
|
feature_bmp.cpp
|
||||||
|
feature_dht.cpp
|
||||||
|
feature_lamp.cpp
|
||||||
|
feature_switch.cpp
|
||||||
|
feature_tsl.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
|
myconfig.cpp
|
||||||
|
mymdns.cpp
|
||||||
|
mymqtt.cpp
|
||||||
|
mywifi.cpp
|
||||||
|
webserver.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(dependencies
|
set(dependencies
|
||||||
|
118
main/feature_bmp.cpp
Normal file
118
main/feature_bmp.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#include "feature_bmp.h"
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <Adafruit_BMP085_U.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "myconfig.h"
|
||||||
|
#include "mymqtt.h"
|
||||||
|
#include "delayedconstruction.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
std::optional<BmpValue> lastBmpValue;
|
||||||
|
espchrono::millis_clock::time_point last_bmp085_pressure_pub;
|
||||||
|
espchrono::millis_clock::time_point last_bmp085_temperature_pub;
|
||||||
|
espchrono::millis_clock::time_point last_bmp085_altitude_pub;
|
||||||
|
bool bmpInitialized{};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "BMP";
|
||||||
|
|
||||||
|
cpputils::DelayedConstruction<Adafruit_BMP085_Unified> bmp;
|
||||||
|
espchrono::millis_clock::time_point last_bmp085_readout;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_bmp()
|
||||||
|
{
|
||||||
|
if (!config::enable_bmp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bmp.construct(10085);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "calling bmp.begin()...");
|
||||||
|
bmpInitialized = bmp->begin();
|
||||||
|
ESP_LOGI(TAG, "finished with %s", bmpInitialized ? "true" : "false");
|
||||||
|
|
||||||
|
if (bmpInitialized) {
|
||||||
|
sensor_t sensor = bmp->getSensor();
|
||||||
|
ESP_LOGI(TAG, "------------------------------------");
|
||||||
|
ESP_LOGI(TAG, "Sensor: %s", sensor.name);
|
||||||
|
ESP_LOGI(TAG, "Driver Ver: %i", sensor.version);
|
||||||
|
ESP_LOGI(TAG, "Unique ID: %i", sensor.sensor_id);
|
||||||
|
ESP_LOGI(TAG, "Max Value: %.1f hPa", sensor.max_value);
|
||||||
|
ESP_LOGI(TAG, "Min Value: %.1f hPa", sensor.min_value);
|
||||||
|
ESP_LOGI(TAG, "Resolution: %.1f hPa", sensor.resolution);
|
||||||
|
ESP_LOGI(TAG, "------------------------------------");
|
||||||
|
ESP_LOGI(TAG, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_bmp()
|
||||||
|
{
|
||||||
|
if (!config::enable_bmp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (bmpInitialized) {
|
||||||
|
if (espchrono::ago(last_bmp085_readout) < 5s)
|
||||||
|
return;
|
||||||
|
|
||||||
|
last_bmp085_readout = espchrono::millis_clock::now();
|
||||||
|
|
||||||
|
if (std::optional<Adafruit_BMP085_Unified::TemperatureAndPressure> values = bmp->getTemperatureAndPressure()) {
|
||||||
|
if (values->temperature && values->pressure) {
|
||||||
|
BmpValue bmpValue {
|
||||||
|
.timestamp = espchrono::millis_clock::now(),
|
||||||
|
.pressure = values->pressure,
|
||||||
|
.temperature = values->temperature};
|
||||||
|
ESP_LOGI(TAG, "read bmp Pressure: %.1f hPa", bmpValue.pressure);
|
||||||
|
ESP_LOGI(TAG, "read bmp Temperature: %.1f C", bmpValue.temperature);
|
||||||
|
|
||||||
|
/* Then convert the atmospheric pressure, and SLP to altitude */
|
||||||
|
/* Update this next line with the current SLP for better results */
|
||||||
|
constexpr const float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
|
||||||
|
bmpValue.altitude = bmp->pressureToAltitude(seaLevelPressure, bmpValue.pressure);
|
||||||
|
ESP_LOGI(TAG, "read bmp Altitude: %.1f m", bmpValue.altitude);
|
||||||
|
|
||||||
|
if (mqttClient && mqttConnected) {
|
||||||
|
if (!lastBmpValue)
|
||||||
|
mqttVerbosePub(config::topic_bmp085_availability, "online", 0, 1);
|
||||||
|
if (!lastBmpValue || espchrono::ago(last_bmp085_pressure_pub) >= config::valueUpdateInterval) {
|
||||||
|
if (mqttVerbosePub(config::topic_bmp085_pressure, fmt::format("{:.1f}", bmpValue.pressure), 0, 1) >= 0)
|
||||||
|
last_bmp085_pressure_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
if (!lastBmpValue || espchrono::ago(last_bmp085_temperature_pub) >= config::valueUpdateInterval) {
|
||||||
|
if (mqttVerbosePub(config::topic_bmp085_temperature, fmt::format("{:.1f}", bmpValue.temperature), 0, 1) >= 0)
|
||||||
|
last_bmp085_temperature_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
if (!lastBmpValue || espchrono::ago(last_bmp085_altitude_pub) >= config::valueUpdateInterval) {
|
||||||
|
if (mqttVerbosePub(config::topic_bmp085_altitude, fmt::format("{:.1f}", bmpValue.altitude), 0, 1) >= 0)
|
||||||
|
last_bmp085_altitude_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastBmpValue = bmpValue;
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "bmp sensor error");
|
||||||
|
goto bmpOffline;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "bmp failed");
|
||||||
|
goto bmpOffline;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bmpOffline:
|
||||||
|
if (lastBmpValue && espchrono::ago(lastBmpValue->timestamp) >= config::availableTimeoutTime) {
|
||||||
|
ESP_LOGW(TAG, "bmp timeouted");
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_bmp085_availability, "offline", 0, 1);
|
||||||
|
lastBmpValue = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace deckenlampe
|
25
main/feature_bmp.h
Normal file
25
main/feature_bmp.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "espchrono.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
struct BmpValue
|
||||||
|
{
|
||||||
|
espchrono::millis_clock::time_point timestamp;
|
||||||
|
float pressure;
|
||||||
|
float temperature;
|
||||||
|
float altitude;
|
||||||
|
};
|
||||||
|
extern std::optional<BmpValue> lastBmpValue;
|
||||||
|
extern espchrono::millis_clock::time_point last_bmp085_pressure_pub;
|
||||||
|
extern espchrono::millis_clock::time_point last_bmp085_temperature_pub;
|
||||||
|
extern espchrono::millis_clock::time_point last_bmp085_altitude_pub;
|
||||||
|
extern bool bmpInitialized;
|
||||||
|
|
||||||
|
void init_bmp();
|
||||||
|
void update_bmp();
|
||||||
|
} // namespace deckenlampe
|
91
main/feature_dht.cpp
Normal file
91
main/feature_dht.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include "feature_dht.h"
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <DHT.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "myconfig.h"
|
||||||
|
#include "mymqtt.h"
|
||||||
|
#include "delayedconstruction.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
std::optional<DhtValue> lastDhtValue;
|
||||||
|
espchrono::millis_clock::time_point last_dht11_temperature_pub;
|
||||||
|
espchrono::millis_clock::time_point last_dht11_humidity_pub;
|
||||||
|
bool dhtInitialized{};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "DHT";
|
||||||
|
|
||||||
|
cpputils::DelayedConstruction<DHT> dht;
|
||||||
|
espchrono::millis_clock::time_point last_dht11_readout;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_dht()
|
||||||
|
{
|
||||||
|
if (!config::enable_dht)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dht.construct(config::pins_dht, DHT11);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "calling dht.begin()...");
|
||||||
|
dhtInitialized = dht->begin();
|
||||||
|
ESP_LOGI(TAG, "finished with %s", dhtInitialized ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_dht()
|
||||||
|
{
|
||||||
|
if (!config::enable_dht)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dhtInitialized) {
|
||||||
|
if (espchrono::ago(last_dht11_readout) < 5s)
|
||||||
|
return;
|
||||||
|
|
||||||
|
last_dht11_readout = espchrono::millis_clock::now();
|
||||||
|
|
||||||
|
if (const auto data = dht->read()) {
|
||||||
|
DhtValue dhtValue {
|
||||||
|
.timestamp = espchrono::millis_clock::now(),
|
||||||
|
.temperature = dht->readTemperature(*data),
|
||||||
|
.humidity = dht->readHumidity(*data)
|
||||||
|
};
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "read dht temperature: %.1f C", dhtValue.temperature);
|
||||||
|
ESP_LOGI(TAG, "read dht humidity: %.1f %%", dhtValue.humidity);
|
||||||
|
|
||||||
|
if (mqttClient && mqttConnected) {
|
||||||
|
if (!lastDhtValue)
|
||||||
|
mqttVerbosePub(config::topic_dht11_availability, "online", 0, 1);
|
||||||
|
if (!lastDhtValue || espchrono::ago(last_dht11_temperature_pub) >= config::valueUpdateInterval) {
|
||||||
|
if (mqttVerbosePub(config::topic_dht11_temperature, fmt::format("{:.1f}", dhtValue.temperature), 0, 1) >= 0)
|
||||||
|
last_dht11_temperature_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
if (!lastDhtValue || espchrono::ago(last_dht11_humidity_pub) >= config::valueUpdateInterval) {
|
||||||
|
if (mqttVerbosePub(config::topic_dht11_humidity, fmt::format("{:.1f}", dhtValue.humidity), 0, 1) >= 0)
|
||||||
|
last_dht11_humidity_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastDhtValue = dhtValue;
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "dht failed");
|
||||||
|
goto dhtOffline;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dhtOffline:
|
||||||
|
if (lastDhtValue && espchrono::ago(lastDhtValue->timestamp) >= config::availableTimeoutTime) {
|
||||||
|
ESP_LOGW(TAG, "dht timeouted");
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_dht11_availability, "offline", 0, 1);
|
||||||
|
lastDhtValue = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace deckenlampe
|
23
main/feature_dht.h
Normal file
23
main/feature_dht.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "espchrono.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
struct DhtValue
|
||||||
|
{
|
||||||
|
espchrono::millis_clock::time_point timestamp;
|
||||||
|
float temperature;
|
||||||
|
float humidity;
|
||||||
|
};
|
||||||
|
extern std::optional<DhtValue> lastDhtValue;
|
||||||
|
extern espchrono::millis_clock::time_point last_dht11_temperature_pub;
|
||||||
|
extern espchrono::millis_clock::time_point last_dht11_humidity_pub;
|
||||||
|
extern bool dhtInitialized;
|
||||||
|
|
||||||
|
void init_dht();
|
||||||
|
void update_dht();
|
||||||
|
} // namespace deckenlampe
|
33
main/feature_lamp.cpp
Normal file
33
main/feature_lamp.cpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "feature_lamp.h"
|
||||||
|
|
||||||
|
// Arduino includes
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include <myconfig.h>
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
std::atomic<bool> lampState;
|
||||||
|
|
||||||
|
void init_lamp()
|
||||||
|
{
|
||||||
|
if (!config::enable_lamp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pinMode(config::pins_lamp, OUTPUT);
|
||||||
|
writeLamp(lampState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_lamp()
|
||||||
|
{
|
||||||
|
if (!config::enable_lamp)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeLamp(bool state)
|
||||||
|
{
|
||||||
|
if (config::invertLamp)
|
||||||
|
state = !state;
|
||||||
|
digitalWrite(config::pins_lamp, state ? HIGH : LOW);
|
||||||
|
}
|
||||||
|
} // namespace deckenlampe
|
13
main/feature_lamp.h
Normal file
13
main/feature_lamp.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
extern std::atomic<bool> lampState;
|
||||||
|
|
||||||
|
void init_lamp();
|
||||||
|
void update_lamp();
|
||||||
|
|
||||||
|
void writeLamp(bool state);
|
||||||
|
} // namespace deckenlampe
|
66
main/feature_switch.cpp
Normal file
66
main/feature_switch.cpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#include "feature_switch.h"
|
||||||
|
|
||||||
|
// Arduino includes
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "myconfig.h"
|
||||||
|
#include "mymqtt.h"
|
||||||
|
#include "feature_lamp.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
std::atomic<bool> switchState;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
uint8_t switchDebounce{};
|
||||||
|
|
||||||
|
bool readSwitch();
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_switch()
|
||||||
|
{
|
||||||
|
if (!config::enable_switch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pinMode(config::pins_switch, INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_switch()
|
||||||
|
{
|
||||||
|
if (!config::enable_switch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto newState = readSwitch();
|
||||||
|
if (newState == switchState.load())
|
||||||
|
switchDebounce = 0;
|
||||||
|
else {
|
||||||
|
switchDebounce++;
|
||||||
|
if (switchDebounce >= 10) {
|
||||||
|
switchDebounce = 0;
|
||||||
|
|
||||||
|
switchState = newState;
|
||||||
|
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_switch_status, switchState ? "ON" : "OFF", 0, 1);
|
||||||
|
|
||||||
|
if (config::enable_lamp) {
|
||||||
|
lampState = !lampState;
|
||||||
|
writeLamp(lampState);
|
||||||
|
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_lamp_status, lampState ? "ON" : "OFF", 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool readSwitch()
|
||||||
|
{
|
||||||
|
bool state = digitalRead(config::pins_switch) == HIGH;
|
||||||
|
if (config::invert_switch)
|
||||||
|
state = !state;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
} // namespace deckenlampe
|
11
main/feature_switch.h
Normal file
11
main/feature_switch.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
extern std::atomic<bool> switchState;
|
||||||
|
|
||||||
|
void init_switch();
|
||||||
|
void update_switch();
|
||||||
|
} // namespace deckenlampe
|
120
main/feature_tsl.cpp
Normal file
120
main/feature_tsl.cpp
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
#include "feature_tsl.h"
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <Adafruit_TSL2561_U.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "myconfig.h"
|
||||||
|
#include "mymqtt.h"
|
||||||
|
#include "delayedconstruction.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
std::optional<TslValue> lastTslValue;
|
||||||
|
espchrono::millis_clock::time_point last_tsl2561_lux_pub;
|
||||||
|
bool tslInitialized{};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "TSL";
|
||||||
|
|
||||||
|
cpputils::DelayedConstruction<Adafruit_TSL2561_Unified> tsl;
|
||||||
|
espchrono::millis_clock::time_point last_tsl2561_readout;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_tsl()
|
||||||
|
{
|
||||||
|
if (!config::enable_tsl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tsl.construct(TSL2561_ADDR_FLOAT, 12345);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "calling tsl.begin()...");
|
||||||
|
tslInitialized = tsl->begin(true);
|
||||||
|
ESP_LOGI(TAG, "finished with %s", tslInitialized ? "true" : "false");
|
||||||
|
|
||||||
|
if (tslInitialized) {
|
||||||
|
sensor_t sensor = tsl->getSensor();
|
||||||
|
ESP_LOGI(TAG, "------------------------------------");
|
||||||
|
ESP_LOGI(TAG, "Sensor: %s", sensor.name);
|
||||||
|
ESP_LOGI(TAG, "Driver Ver: %i", sensor.version);
|
||||||
|
ESP_LOGI(TAG, "Unique ID: %i", sensor.sensor_id);
|
||||||
|
ESP_LOGI(TAG, "Max Value: %.1f lux", sensor.max_value);
|
||||||
|
ESP_LOGI(TAG, "Min Value: %.1f lux", sensor.min_value);
|
||||||
|
ESP_LOGI(TAG, "Resolution: %.1f lux", sensor.resolution);
|
||||||
|
ESP_LOGI(TAG, "------------------------------------");
|
||||||
|
ESP_LOGI(TAG, "");
|
||||||
|
|
||||||
|
/* You can also manually set the gain or enable auto-gain support */
|
||||||
|
// tsl->setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */
|
||||||
|
// tsl->setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */
|
||||||
|
tsl->enableAutoRange(true); /* Auto-gain ... switches automatically between 1x and 16x */
|
||||||
|
|
||||||
|
/* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
|
||||||
|
tsl->setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */
|
||||||
|
// tsl->setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */
|
||||||
|
// tsl->setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */
|
||||||
|
|
||||||
|
/* Update these values depending on what you've set above! */
|
||||||
|
ESP_LOGI(TAG, "------------------------------------");
|
||||||
|
ESP_LOGI(TAG, "Gain: Auto");
|
||||||
|
ESP_LOGI(TAG, "Timing: 13 ms");
|
||||||
|
ESP_LOGI(TAG, "------------------------------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_tsl()
|
||||||
|
{
|
||||||
|
if (!config::enable_tsl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tslInitialized) {
|
||||||
|
if (espchrono::ago(last_tsl2561_readout) < 5s)
|
||||||
|
return;
|
||||||
|
|
||||||
|
last_tsl2561_readout = espchrono::millis_clock::now();
|
||||||
|
|
||||||
|
if (std::optional<sensors_event_t> event = tsl->getEvent()) {
|
||||||
|
/* Display the results (light is measured in lux) */
|
||||||
|
if (event->light) {
|
||||||
|
TslValue tslValue {
|
||||||
|
.timestamp = espchrono::millis_clock::now(),
|
||||||
|
.lux = event->light
|
||||||
|
};
|
||||||
|
ESP_LOGI(TAG, "read tsl: %.1f lux", tslValue.lux);
|
||||||
|
|
||||||
|
if (mqttClient && mqttConnected) {
|
||||||
|
if (!lastTslValue)
|
||||||
|
mqttVerbosePub(config::topic_tsl2561_availability, "online", 0, 1);
|
||||||
|
if (!lastTslValue || espchrono::ago(last_tsl2561_lux_pub) >= config::valueUpdateInterval) {
|
||||||
|
if (mqttVerbosePub(config::topic_tsl2561_lux, fmt::format("{:.1f}", tslValue.lux), 0, 1) >= 0)
|
||||||
|
last_tsl2561_lux_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTslValue = tslValue;
|
||||||
|
} else {
|
||||||
|
/* If event.light = 0 lux the sensor is probably saturated
|
||||||
|
* and no reliable data could be generated! */
|
||||||
|
ESP_LOGW(TAG, "tsl sensor overload %f", event->light);
|
||||||
|
goto tslOffline;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "tsl failed");
|
||||||
|
goto tslOffline;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tslOffline:
|
||||||
|
if (lastTslValue && espchrono::ago(lastTslValue->timestamp) >= config::availableTimeoutTime) {
|
||||||
|
ESP_LOGW(TAG, "tsl timeouted");
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_tsl2561_availability, "offline", 0, 1);
|
||||||
|
lastTslValue = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace deckenlampe
|
21
main/feature_tsl.h
Normal file
21
main/feature_tsl.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "espchrono.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
struct TslValue
|
||||||
|
{
|
||||||
|
espchrono::millis_clock::time_point timestamp;
|
||||||
|
float lux;
|
||||||
|
};
|
||||||
|
extern std::optional<TslValue> lastTslValue;
|
||||||
|
extern espchrono::millis_clock::time_point last_tsl2561_lux_pub;
|
||||||
|
extern bool tslInitialized;
|
||||||
|
|
||||||
|
void init_tsl();
|
||||||
|
void update_tsl();
|
||||||
|
} // namespace deckenlampe
|
855
main/main.cpp
855
main/main.cpp
@@ -14,133 +14,41 @@
|
|||||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||||
#include <esp_ota_ops.h>
|
#include <esp_ota_ops.h>
|
||||||
#endif
|
#endif
|
||||||
#include <nvs_flash.h>
|
|
||||||
#include <esp_http_server.h>
|
|
||||||
#include <mdns.h>
|
|
||||||
#include <esp_system.h>
|
#include <esp_system.h>
|
||||||
#include <hal/gpio_types.h>
|
|
||||||
|
|
||||||
// Arduino includes
|
// Arduino includes
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
|
|
||||||
// 3rdparty lib includes
|
// 3rdparty lib includes
|
||||||
#include <Adafruit_TSL2561_U.h>
|
|
||||||
#include <Adafruit_BMP085_U.h>
|
|
||||||
#include <DHT.h>
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "espwifistack.h"
|
|
||||||
#include "tickchrono.h"
|
#include "tickchrono.h"
|
||||||
#include "wrappers/mqtt_client.h"
|
#include "myconfig.h"
|
||||||
|
#include "mywifi.h"
|
||||||
|
#include "webserver.h"
|
||||||
|
#include "mymdns.h"
|
||||||
|
#include "mymqtt.h"
|
||||||
|
#include "feature_lamp.h"
|
||||||
|
#include "feature_switch.h"
|
||||||
|
#include "feature_dht.h"
|
||||||
|
#include "feature_tsl.h"
|
||||||
|
#include "feature_bmp.h"
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
namespace {
|
namespace {
|
||||||
constexpr const char * const TAG = "MAIN";
|
constexpr const char * const TAG = "MAIN";
|
||||||
|
|
||||||
constexpr const bool invertLamp = true;
|
|
||||||
constexpr const bool invertSwitch = true;
|
|
||||||
|
|
||||||
constexpr const gpio_num_t pins_lamp = GPIO_NUM_25;
|
|
||||||
constexpr const gpio_num_t pins_switch = GPIO_NUM_35;
|
|
||||||
constexpr const gpio_num_t pins_sda = GPIO_NUM_16;
|
|
||||||
constexpr const gpio_num_t pins_scl = GPIO_NUM_17;
|
|
||||||
constexpr const gpio_num_t pins_dht = GPIO_NUM_33;
|
|
||||||
|
|
||||||
constexpr const std::string_view broker_url = "mqtt://192.168.0.2/";
|
|
||||||
|
|
||||||
constexpr const std::string_view topic_lamp_availability = "dahoam/wohnzimmer/deckenlicht1/available";
|
|
||||||
constexpr const std::string_view topic_lamp_status = "dahoam/wohnzimmer/deckenlicht1/status";
|
|
||||||
constexpr const std::string_view topic_lamp_set = "dahoam/wohnzimmer/deckenlicht1/set";
|
|
||||||
|
|
||||||
constexpr const std::string_view topic_switch_availability = "dahoam/wohnzimmer/schalter1/available";
|
|
||||||
constexpr const std::string_view topic_switch_status = "dahoam/wohnzimmer/schalter1/status";
|
|
||||||
|
|
||||||
constexpr const std::string_view topic_tsl2561_availability = "dahoam/wohnzimmer/tsl2561_1/available";
|
|
||||||
constexpr const std::string_view topic_tsl2561_lux = "dahoam/wohnzimmer/tsl2561_1/lux";
|
|
||||||
|
|
||||||
constexpr const std::string_view topic_bmp085_availability = "dahoam/wohnzimmer/bmp085_1/available";
|
|
||||||
constexpr const std::string_view topic_bmp085_pressure = "dahoam/wohnzimmer/bmp085_1/pressure";
|
|
||||||
constexpr const std::string_view topic_bmp085_temperature = "dahoam/wohnzimmer/bmp085_1/temperature";
|
|
||||||
constexpr const std::string_view topic_bmp085_altitude = "dahoam/wohnzimmer/bmp085_1/altitude";
|
|
||||||
|
|
||||||
constexpr const std::string_view topic_dht11_availability = "dahoam/wohnzimmer/dht11_1/available";
|
|
||||||
constexpr const std::string_view topic_dht11_temperature = "dahoam/wohnzimmer/dht11_1/temperature";
|
|
||||||
constexpr const std::string_view topic_dht11_humidity = "dahoam/wohnzimmer/dht11_1/humidity";
|
|
||||||
|
|
||||||
constexpr const auto availableTimeoutTime = 1min;
|
|
||||||
constexpr const auto valueUpdateInterval = 15s;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::atomic<bool> mqttConnected;
|
|
||||||
espcpputils::mqtt_client mqttClient;
|
|
||||||
|
|
||||||
std::atomic<bool> lampState;
|
|
||||||
std::atomic<bool> switchState;
|
|
||||||
uint8_t switchDebounce{};
|
|
||||||
|
|
||||||
//espchrono::millis_clock::time_point lastLampToggle;
|
|
||||||
//espchrono::millis_clock::time_point lastSwitchToggle;
|
|
||||||
|
|
||||||
|
|
||||||
Adafruit_TSL2561_Unified tsl{TSL2561_ADDR_FLOAT, 12345};
|
|
||||||
struct TslValue
|
|
||||||
{
|
|
||||||
espchrono::millis_clock::time_point timestamp;
|
|
||||||
float lux;
|
|
||||||
};
|
|
||||||
std::optional<TslValue> lastTslValue;
|
|
||||||
espchrono::millis_clock::time_point last_tsl2561_lux_pub;
|
|
||||||
|
|
||||||
|
|
||||||
Adafruit_BMP085_Unified bmp{10085};
|
|
||||||
struct BmpValue
|
|
||||||
{
|
|
||||||
espchrono::millis_clock::time_point timestamp;
|
|
||||||
float pressure;
|
|
||||||
float temperature;
|
|
||||||
float altitude;
|
|
||||||
};
|
|
||||||
std::optional<BmpValue> lastBmpValue;
|
|
||||||
espchrono::millis_clock::time_point last_bmp085_pressure_pub;
|
|
||||||
espchrono::millis_clock::time_point last_bmp085_temperature_pub;
|
|
||||||
espchrono::millis_clock::time_point last_bmp085_altitude_pub;
|
|
||||||
|
|
||||||
|
|
||||||
DHT dht(pins_dht, DHT11);
|
|
||||||
struct DhtValue
|
|
||||||
{
|
|
||||||
espchrono::millis_clock::time_point timestamp;
|
|
||||||
float temperature;
|
|
||||||
float humidity;
|
|
||||||
};
|
|
||||||
std::optional<DhtValue> lastDhtValue;
|
|
||||||
espchrono::millis_clock::time_point last_dht11_temperature_pub;
|
|
||||||
espchrono::millis_clock::time_point last_dht11_humidity_pub;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
esp_err_t webserver_root_handler(httpd_req_t *req);
|
|
||||||
esp_err_t webserver_on_handler(httpd_req_t *req);
|
|
||||||
esp_err_t webserver_off_handler(httpd_req_t *req);
|
|
||||||
esp_err_t webserver_toggle_handler(httpd_req_t *req);
|
|
||||||
esp_err_t webserver_reboot_handler(httpd_req_t *req);
|
|
||||||
|
|
||||||
void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
|
||||||
|
|
||||||
int mqttVerbosePub(std::string_view topic, std::string_view value, int qos, int retain);
|
|
||||||
|
|
||||||
void verboseDigitalWrite(uint8_t pin, uint8_t val);
|
|
||||||
|
|
||||||
void writeLamp(bool state);
|
|
||||||
bool readSwitch();
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
} // namespace deckenlamp
|
||||||
|
|
||||||
extern "C" void app_main()
|
extern "C" void app_main()
|
||||||
{
|
{
|
||||||
|
using namespace deckenlampe;
|
||||||
|
|
||||||
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
|
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
|
||||||
{
|
{
|
||||||
const auto taskHandle = xTaskGetCurrentTaskHandle();
|
const auto taskHandle = xTaskGetCurrentTaskHandle();
|
||||||
@@ -174,489 +82,53 @@ extern "C" void app_main()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
init_config();
|
||||||
const auto result = nvs_flash_init();
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_flash_init(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
nvs_handle_t nvsHandle;
|
init_lamp();
|
||||||
|
|
||||||
{
|
init_switch();
|
||||||
const auto result = nvs_open("deckenlampe", NVS_READWRITE, &nvsHandle);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_open(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
wifi_stack::config wifiConfig {
|
|
||||||
.wifiEnabled = true,
|
|
||||||
.hostname = "deckenlampe1",
|
|
||||||
.wifis = std::array<wifi_stack::wifi_entry, 10> {
|
|
||||||
wifi_stack::wifi_entry { .ssid = "ScheissAP", .key = "Passwort_123" },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
|
||||||
wifi_stack::wifi_entry { .ssid = {}, .key = {} }
|
|
||||||
},
|
|
||||||
.sta_ip = {
|
|
||||||
.dhcpEnabled = true,
|
|
||||||
// .staticIp = {},
|
|
||||||
// .staticGateway = {},
|
|
||||||
// .staticSubnet = {},
|
|
||||||
// .staticDns1 = {},
|
|
||||||
// .staticDns2 = {}
|
|
||||||
},
|
|
||||||
.ap = {
|
|
||||||
{
|
|
||||||
.ssid = "deckenlampe1",
|
|
||||||
.key = "Passwort_123"
|
|
||||||
},
|
|
||||||
.channel = 1,
|
|
||||||
.authmode = WIFI_AUTH_WPA2_PSK,
|
|
||||||
.ssid_hidden = false,
|
|
||||||
.max_connection = 4,
|
|
||||||
.beacon_interval = 100,
|
|
||||||
.ip{192, 168, 4, 1},
|
|
||||||
.subnet{255, 255, 255, 0}
|
|
||||||
},
|
|
||||||
.min_rssi = -90
|
|
||||||
};
|
|
||||||
|
|
||||||
wifi_stack::init(wifiConfig);
|
|
||||||
|
|
||||||
pinMode(pins_lamp, OUTPUT);
|
|
||||||
writeLamp(lampState);
|
|
||||||
|
|
||||||
pinMode(pins_switch, INPUT);
|
|
||||||
|
|
||||||
httpd_handle_t httpdHandle{};
|
|
||||||
|
|
||||||
{
|
|
||||||
httpd_config_t httpConfig HTTPD_DEFAULT_CONFIG();
|
|
||||||
|
|
||||||
const auto result = httpd_start(&httpdHandle, &httpConfig);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_start(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
httpd_uri_t uri {
|
|
||||||
.uri = "/",
|
|
||||||
.method = HTTP_GET,
|
|
||||||
.handler = webserver_root_handler,
|
|
||||||
.user_ctx = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto result = httpd_register_uri_handler(httpdHandle, &uri);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
httpd_uri_t uri {
|
|
||||||
.uri = "/on",
|
|
||||||
.method = HTTP_GET,
|
|
||||||
.handler = webserver_on_handler,
|
|
||||||
.user_ctx = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto result = httpd_register_uri_handler(httpdHandle, &uri);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/on", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
httpd_uri_t uri {
|
|
||||||
.uri = "/off",
|
|
||||||
.method = HTTP_GET,
|
|
||||||
.handler = webserver_off_handler,
|
|
||||||
.user_ctx = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto result = httpd_register_uri_handler(httpdHandle, &uri);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/off", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
httpd_uri_t uri {
|
|
||||||
.uri = "/toggle",
|
|
||||||
.method = HTTP_GET,
|
|
||||||
.handler = webserver_toggle_handler,
|
|
||||||
.user_ctx = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto result = httpd_register_uri_handler(httpdHandle, &uri);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/toggle", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
httpd_uri_t uri {
|
|
||||||
.uri = "/reboot",
|
|
||||||
.method = HTTP_GET,
|
|
||||||
.handler = webserver_reboot_handler,
|
|
||||||
.user_ctx = NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto result = httpd_register_uri_handler(httpdHandle, &uri);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/reboot", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto result = mdns_init();
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_init(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto result = mdns_hostname_set(wifiConfig.hostname.c_str());
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_hostname_set(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto result = mdns_instance_name_set(wifiConfig.hostname.c_str());
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_instance_name_set(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto result = mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_service_add(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
esp_mqtt_client_config_t mqtt_cfg = {
|
|
||||||
.uri = broker_url.data(),
|
|
||||||
};
|
|
||||||
|
|
||||||
mqttClient = espcpputils::mqtt_client{&mqtt_cfg};
|
|
||||||
|
|
||||||
if (!mqttClient)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "error while initializing mqtt client!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
{
|
|
||||||
const auto result = mqttClient.register_event(MQTT_EVENT_ANY, mqttEventHandler, NULL);
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_mqtt_client_register_event(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto result = mqttClient.start();
|
|
||||||
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_mqtt_client_start(): %s", esp_err_to_name(result));
|
|
||||||
//if (result != ESP_OK)
|
|
||||||
// return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
espchrono::millis_clock::time_point lastValuesRead;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "calling Wire.begin()...");
|
ESP_LOGI(TAG, "calling Wire.begin()...");
|
||||||
const auto result = Wire.begin(pins_sda, pins_scl);
|
const auto result = Wire.begin(config::pins_sda, config::pins_scl);
|
||||||
ESP_LOGI(TAG, "finished with %s", result ? "true" : "false");
|
ESP_LOGI(TAG, "finished with %s", result ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tslInitialized{};
|
init_wifi();
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "calling tsl.begin()...");
|
|
||||||
tslInitialized = tsl.begin(true);
|
|
||||||
ESP_LOGI(TAG, "finished with %s", tslInitialized ? "true" : "false");
|
|
||||||
|
|
||||||
if (tslInitialized)
|
init_webserver();
|
||||||
{
|
|
||||||
sensor_t sensor = tsl.getSensor();
|
|
||||||
ESP_LOGI(TAG, "------------------------------------");
|
|
||||||
ESP_LOGI(TAG, "Sensor: %s", sensor.name);
|
|
||||||
ESP_LOGI(TAG, "Driver Ver: %i", sensor.version);
|
|
||||||
ESP_LOGI(TAG, "Unique ID: %i", sensor.sensor_id);
|
|
||||||
ESP_LOGI(TAG, "Max Value: %.1f lux", sensor.max_value);
|
|
||||||
ESP_LOGI(TAG, "Min Value: %.1f lux", sensor.min_value);
|
|
||||||
ESP_LOGI(TAG, "Resolution: %.1f lux", sensor.resolution);
|
|
||||||
ESP_LOGI(TAG, "------------------------------------");
|
|
||||||
ESP_LOGI(TAG, "");
|
|
||||||
|
|
||||||
/* You can also manually set the gain or enable auto-gain support */
|
init_mdns();
|
||||||
// tsl.setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */
|
|
||||||
// tsl.setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */
|
|
||||||
tsl.enableAutoRange(true); /* Auto-gain ... switches automatically between 1x and 16x */
|
|
||||||
|
|
||||||
/* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
|
init_mqtt();
|
||||||
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */
|
|
||||||
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */
|
|
||||||
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */
|
|
||||||
|
|
||||||
/* Update these values depending on what you've set above! */
|
init_dht();
|
||||||
ESP_LOGI(TAG, "------------------------------------");
|
|
||||||
ESP_LOGI(TAG, "Gain: Auto");
|
|
||||||
ESP_LOGI(TAG, "Timing: 13 ms");
|
|
||||||
ESP_LOGI(TAG, "------------------------------------");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bmpInitialized{};
|
init_tsl();
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "calling bmp.begin()...");
|
|
||||||
bmpInitialized = bmp.begin();
|
|
||||||
ESP_LOGI(TAG, "finished with %s", bmpInitialized ? "true" : "false");
|
|
||||||
|
|
||||||
if (bmpInitialized)
|
init_bmp();
|
||||||
{
|
|
||||||
sensor_t sensor = bmp.getSensor();
|
|
||||||
ESP_LOGI(TAG, "------------------------------------");
|
|
||||||
ESP_LOGI(TAG, "Sensor: %s", sensor.name);
|
|
||||||
ESP_LOGI(TAG, "Driver Ver: %i", sensor.version);
|
|
||||||
ESP_LOGI(TAG, "Unique ID: %i", sensor.sensor_id);
|
|
||||||
ESP_LOGI(TAG, "Max Value: %.1f hPa", sensor.max_value);
|
|
||||||
ESP_LOGI(TAG, "Min Value: %.1f hPa", sensor.min_value);
|
|
||||||
ESP_LOGI(TAG, "Resolution: %.1f hPa", sensor.resolution);
|
|
||||||
ESP_LOGI(TAG, "------------------------------------");
|
|
||||||
ESP_LOGI(TAG, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dhtInitialized{};
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "calling dht.begin()...");
|
|
||||||
dhtInitialized = dht.begin();
|
|
||||||
ESP_LOGI(TAG, "finished with %s", dhtInitialized ? "true" : "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
wifi_stack::update(wifiConfig);
|
update_config();
|
||||||
|
|
||||||
// if (espchrono::ago(lastLampToggle) >= 10s)
|
update_lamp();
|
||||||
// {
|
|
||||||
// lastLampToggle = espchrono::millis_clock::now();
|
|
||||||
// lampState = !lampState;
|
|
||||||
// writeLamp(lampState);
|
|
||||||
|
|
||||||
// if (mqttClient && mqttConnected)
|
update_wifi();
|
||||||
// mqttVerbosePub(topic_lamp_status, lampState ? "ON" : "OFF", 0, 1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (espchrono::ago(lastSwitchToggle) >= 30s)
|
update_webserver();
|
||||||
// {
|
|
||||||
// lastSwitchToggle = espchrono::millis_clock::now();
|
|
||||||
// switchState = !switchState;
|
|
||||||
|
|
||||||
// if (mqttClient && mqttConnected)
|
update_mdns();
|
||||||
// mqttVerbosePub(topic_switch_status, switchState ? "ON" : "OFF", 0, 1);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (espchrono::ago(lastValuesRead) >= 2s) {
|
update_mqtt();
|
||||||
lastValuesRead = espchrono::millis_clock::now();
|
|
||||||
|
|
||||||
if (tslInitialized)
|
update_dht();
|
||||||
{
|
|
||||||
if (std::optional<sensors_event_t> event = tsl.getEvent())
|
|
||||||
{
|
|
||||||
/* Display the results (light is measured in lux) */
|
|
||||||
if (event->light)
|
|
||||||
{
|
|
||||||
TslValue tslValue {
|
|
||||||
.timestamp = espchrono::millis_clock::now(),
|
|
||||||
.lux = event->light
|
|
||||||
};
|
|
||||||
ESP_LOGI(TAG, "read tsl: %.1f lux", tslValue.lux);
|
|
||||||
|
|
||||||
if (mqttClient && mqttConnected)
|
update_tsl();
|
||||||
{
|
|
||||||
if (!lastTslValue)
|
|
||||||
mqttVerbosePub(topic_tsl2561_availability, "online", 0, 1);
|
|
||||||
if (!lastTslValue || espchrono::ago(last_tsl2561_lux_pub) >= valueUpdateInterval)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_tsl2561_lux, fmt::format("{:.1f}", tslValue.lux), 0, 1) >= 0)
|
|
||||||
last_tsl2561_lux_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTslValue = tslValue;
|
update_bmp();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* If event.light = 0 lux the sensor is probably saturated
|
|
||||||
* and no reliable data could be generated! */
|
|
||||||
ESP_LOGW(TAG, "tsl sensor overload %f", event->light);
|
|
||||||
goto tslOffline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGW(TAG, "tsl failed");
|
|
||||||
goto tslOffline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tslOffline:
|
|
||||||
if (lastTslValue && espchrono::ago(lastTslValue->timestamp) >= availableTimeoutTime)
|
|
||||||
{
|
|
||||||
ESP_LOGW(TAG, "tsl timeouted");
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_tsl2561_availability, "offline", 0, 1);
|
|
||||||
lastTslValue = std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bmpInitialized)
|
update_switch();
|
||||||
{
|
|
||||||
if (std::optional<Adafruit_BMP085_Unified::TemperatureAndPressure> values = bmp.getTemperatureAndPressure())
|
|
||||||
{
|
|
||||||
if (values->temperature && values->pressure)
|
|
||||||
{
|
|
||||||
BmpValue bmpValue {
|
|
||||||
.timestamp = espchrono::millis_clock::now(),
|
|
||||||
.pressure = values->pressure,
|
|
||||||
.temperature = values->temperature
|
|
||||||
};
|
|
||||||
ESP_LOGI(TAG, "read bmp Pressure: %.1f hPa", bmpValue.pressure);
|
|
||||||
ESP_LOGI(TAG, "read bmp Temperature: %.1f C", bmpValue.temperature);
|
|
||||||
|
|
||||||
/* Then convert the atmospheric pressure, and SLP to altitude */
|
|
||||||
/* Update this next line with the current SLP for better results */
|
|
||||||
constexpr const float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;
|
|
||||||
bmpValue.altitude = bmp.pressureToAltitude(seaLevelPressure, bmpValue.pressure);
|
|
||||||
ESP_LOGI(TAG, "read bmp Altitude: %.1f m", bmpValue.altitude);
|
|
||||||
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
{
|
|
||||||
if (!lastBmpValue)
|
|
||||||
mqttVerbosePub(topic_bmp085_availability, "online", 0, 1);
|
|
||||||
if (!lastBmpValue || espchrono::ago(last_bmp085_pressure_pub) >= valueUpdateInterval)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_bmp085_pressure, fmt::format("{:.1f}", bmpValue.pressure), 0, 1) >= 0)
|
|
||||||
last_bmp085_pressure_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
if (!lastBmpValue || espchrono::ago(last_bmp085_temperature_pub) >= valueUpdateInterval)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_bmp085_temperature, fmt::format("{:.1f}", bmpValue.temperature), 0, 1) >= 0)
|
|
||||||
last_bmp085_temperature_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
if (!lastBmpValue || espchrono::ago(last_bmp085_altitude_pub) >= valueUpdateInterval)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_bmp085_altitude, fmt::format("{:.1f}", bmpValue.altitude), 0, 1) >= 0)
|
|
||||||
last_bmp085_altitude_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastBmpValue = bmpValue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGW(TAG, "bmp sensor error");
|
|
||||||
goto bmpOffline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ESP_LOGW(TAG, "bmp failed");
|
|
||||||
goto bmpOffline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bmpOffline:
|
|
||||||
if (lastBmpValue && espchrono::ago(lastBmpValue->timestamp) >= availableTimeoutTime)
|
|
||||||
{
|
|
||||||
ESP_LOGW(TAG, "bmp timeouted");
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_bmp085_availability, "offline", 0, 1);
|
|
||||||
lastBmpValue = std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dhtInitialized) {
|
|
||||||
if (const auto data = dht.read())
|
|
||||||
{
|
|
||||||
DhtValue dhtValue {
|
|
||||||
.timestamp = espchrono::millis_clock::now(),
|
|
||||||
.temperature = dht.readTemperature(*data),
|
|
||||||
.humidity = dht.readHumidity(*data)
|
|
||||||
};
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "read dht temperature: %.1f C", dhtValue.temperature);
|
|
||||||
ESP_LOGI(TAG, "read dht humidity: %.1f %%", dhtValue.humidity);
|
|
||||||
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
{
|
|
||||||
if (!lastDhtValue)
|
|
||||||
mqttVerbosePub(topic_dht11_availability, "online", 0, 1);
|
|
||||||
if (!lastDhtValue || espchrono::ago(last_dht11_temperature_pub) >= valueUpdateInterval)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_dht11_temperature, fmt::format("{:.1f}", dhtValue.temperature), 0, 1) >= 0)
|
|
||||||
last_dht11_temperature_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
if (!lastDhtValue || espchrono::ago(last_dht11_humidity_pub) >= valueUpdateInterval)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_dht11_humidity, fmt::format("{:.1f}", dhtValue.humidity), 0, 1) >= 0)
|
|
||||||
last_dht11_humidity_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastDhtValue = dhtValue;
|
|
||||||
} else {
|
|
||||||
ESP_LOGW(TAG, "dht failed");
|
|
||||||
goto dhtOffline;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dhtOffline:
|
|
||||||
if (lastDhtValue && espchrono::ago(lastDhtValue->timestamp) >= availableTimeoutTime) {
|
|
||||||
ESP_LOGW(TAG, "dht timeouted");
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_dht11_availability, "offline", 0, 1);
|
|
||||||
lastDhtValue = std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const auto newState = readSwitch();
|
|
||||||
if (newState == switchState.load())
|
|
||||||
switchDebounce = 0;
|
|
||||||
else {
|
|
||||||
switchDebounce++;
|
|
||||||
if (switchDebounce >= 10) {
|
|
||||||
switchDebounce = 0;
|
|
||||||
|
|
||||||
switchState = newState;
|
|
||||||
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_switch_status, switchState ? "ON" : "OFF", 0, 1);
|
|
||||||
|
|
||||||
lampState = !lampState;
|
|
||||||
writeLamp(lampState);
|
|
||||||
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_lamp_status, lampState ? "ON" : "OFF", 0, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
|
#if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT)
|
||||||
if (const auto result = esp_task_wdt_reset(); result != ESP_OK)
|
if (const auto result = esp_task_wdt_reset(); result != ESP_OK)
|
||||||
@@ -676,263 +148,6 @@ extern "C" void app_main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CALL_AND_EXIT_ON_ERROR(METHOD, ...) \
|
|
||||||
if (const auto result = METHOD(__VA_ARGS__); result != ESP_OK) \
|
|
||||||
{ \
|
|
||||||
ESP_LOGE(TAG, "%s() failed with %s", #METHOD, esp_err_to_name(result)); \
|
|
||||||
return result; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CALL_AND_EXIT(METHOD, ...) \
|
|
||||||
if (const auto result = METHOD(__VA_ARGS__); result != ESP_OK) \
|
|
||||||
{ \
|
|
||||||
ESP_LOGE(TAG, "%s() failed with %s", #METHOD, esp_err_to_name(result)); \
|
|
||||||
return result; \
|
|
||||||
} \
|
|
||||||
else \
|
|
||||||
return result;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
esp_err_t webserver_root_handler(httpd_req_t *req)
|
|
||||||
{
|
|
||||||
std::string body = "this is work in progress...<br/>\n"
|
|
||||||
"<a href=\"/on\">on</a><br/>\n"
|
|
||||||
"<a href=\"/off\">off</a><br/>\n"
|
|
||||||
"<a href=\"/toggle\">toggle</a><br/>\n"
|
|
||||||
"<a href=\"/reboot\">reboot</a><br/>\n"
|
|
||||||
"<br/>\n";
|
|
||||||
|
|
||||||
body += fmt::format("Lamp: {}<br/>\n", lampState ? "ON" : "OFF");
|
|
||||||
body += fmt::format("Switch: {}<br/>\n", switchState ? "ON" : "OFF");
|
|
||||||
|
|
||||||
if (lastTslValue)
|
|
||||||
{
|
|
||||||
body += fmt::format("TSL2561 Brightness: {:.1f} lux<br/>\n", lastTslValue->lux);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastBmpValue)
|
|
||||||
{
|
|
||||||
body += fmt::format("BMP085 Pressure: {:.1f} lux<br/>\n", lastBmpValue->pressure);
|
|
||||||
body += fmt::format("BMP085 Temperature: {:.1f} C<br/>\n", lastBmpValue->temperature);
|
|
||||||
body += fmt::format("BMP085 Altitude: {:.1f} m<br/>\n", lastBmpValue->altitude);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastDhtValue)
|
|
||||||
{
|
|
||||||
body += fmt::format("DHT11 Temperature: {:.1f} C<br/>\n", lastDhtValue->temperature);
|
|
||||||
body += fmt::format("DHT11 Humidity: {:.1f} %<br/>\n", lastDhtValue->humidity);
|
|
||||||
}
|
|
||||||
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t webserver_on_handler(httpd_req_t *req)
|
|
||||||
{
|
|
||||||
const bool state = (lampState = true);
|
|
||||||
writeLamp(state);
|
|
||||||
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_lamp_status, state ? "ON" : "OFF", 0, 1);
|
|
||||||
|
|
||||||
std::string_view body{"ON called..."};
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t webserver_off_handler(httpd_req_t *req)
|
|
||||||
{
|
|
||||||
const bool state = (lampState = false);
|
|
||||||
writeLamp(state);
|
|
||||||
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_lamp_status, state ? "ON" : "OFF", 0, 1);
|
|
||||||
|
|
||||||
std::string_view body{"OFF called..."};
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t webserver_toggle_handler(httpd_req_t *req)
|
|
||||||
{
|
|
||||||
const bool state = (lampState = !lampState);
|
|
||||||
writeLamp(state);
|
|
||||||
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_lamp_status, state ? "ON" : "OFF", 0, 1);
|
|
||||||
|
|
||||||
std::string_view body{"TOGGLE called..."};
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t webserver_reboot_handler(httpd_req_t *req)
|
|
||||||
{
|
|
||||||
std::string_view body{"REBOOT called..."};
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
|
||||||
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
|
||||||
|
|
||||||
esp_restart();
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
|
||||||
{
|
|
||||||
CPP_UNUSED(event_handler_arg)
|
|
||||||
|
|
||||||
const esp_mqtt_event_t *data = reinterpret_cast<const esp_mqtt_event_t *>(event_data);
|
|
||||||
|
|
||||||
switch (esp_mqtt_event_id_t(event_id))
|
|
||||||
{
|
|
||||||
case MQTT_EVENT_ERROR:
|
|
||||||
ESP_LOGE(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_ERROR");
|
|
||||||
|
|
||||||
// ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
|
||||||
// if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
|
|
||||||
// {
|
|
||||||
// log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
|
||||||
// log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
|
||||||
// log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
|
||||||
// ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
|
||||||
|
|
||||||
// }
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MQTT_EVENT_CONNECTED:
|
|
||||||
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_CONNECTED");
|
|
||||||
|
|
||||||
mqttConnected = true;
|
|
||||||
|
|
||||||
mqttVerbosePub(topic_lamp_availability, "online", 0, 1);
|
|
||||||
mqttVerbosePub(topic_lamp_status, lampState.load() ? "ON" : "OFF", 0, 1);
|
|
||||||
|
|
||||||
mqttVerbosePub(topic_switch_availability, "online", 0, 1);
|
|
||||||
mqttVerbosePub(topic_switch_status, switchState.load() ? "ON" : "OFF", 0, 1);
|
|
||||||
|
|
||||||
mqttVerbosePub(topic_tsl2561_availability, lastTslValue ? "online" : "offline", 0, 1);
|
|
||||||
if (lastTslValue)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_tsl2561_lux, fmt::format("{:.1f}", lastTslValue->lux), 0, 1) >= 0)
|
|
||||||
last_tsl2561_lux_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
mqttVerbosePub(topic_bmp085_availability, lastBmpValue ? "online" : "offline", 0, 1);
|
|
||||||
if (lastBmpValue)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_bmp085_pressure, fmt::format("{:.1f}", lastBmpValue->pressure), 0, 1) >= 0)
|
|
||||||
last_bmp085_pressure_pub = espchrono::millis_clock::now();
|
|
||||||
if (mqttVerbosePub(topic_bmp085_temperature, fmt::format("{:.1f}", lastBmpValue->temperature), 0, 1) >= 0)
|
|
||||||
last_bmp085_temperature_pub = espchrono::millis_clock::now();
|
|
||||||
if (mqttVerbosePub(topic_bmp085_altitude, fmt::format("{:.1f}", lastBmpValue->altitude), 0, 1) >= 0)
|
|
||||||
last_bmp085_altitude_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
mqttVerbosePub(topic_dht11_availability, lastDhtValue ? "online" : "offline", 0, 1);
|
|
||||||
if (lastDhtValue)
|
|
||||||
{
|
|
||||||
if (mqttVerbosePub(topic_dht11_temperature, fmt::format("{:.1f}", lastDhtValue->temperature), 0, 1) >= 0)
|
|
||||||
last_dht11_temperature_pub = espchrono::millis_clock::now();
|
|
||||||
if (mqttVerbosePub(topic_dht11_humidity, fmt::format("{:.1f}", lastDhtValue->humidity), 0, 1) >= 0)
|
|
||||||
last_dht11_humidity_pub = espchrono::millis_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
mqttClient.subscribe(topic_lamp_set, 0);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MQTT_EVENT_DISCONNECTED:
|
|
||||||
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_DISCONNECTED");
|
|
||||||
|
|
||||||
mqttConnected = false;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MQTT_EVENT_SUBSCRIBED:
|
|
||||||
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_SUBSCRIBED");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MQTT_EVENT_UNSUBSCRIBED:
|
|
||||||
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_UNSUBSCRIBED");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MQTT_EVENT_PUBLISHED:
|
|
||||||
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_PUBLISHED");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MQTT_EVENT_DATA:
|
|
||||||
{
|
|
||||||
std::string_view topic{data->topic, (size_t)data->topic_len};
|
|
||||||
std::string_view value{data->data, (size_t)data->data_len};
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "%s event_id=%s topic=%.*s data=%.*s", event_base, "MQTT_EVENT_DATA", topic.size(), topic.data(), value.size(), value.data());
|
|
||||||
|
|
||||||
if (topic == topic_lamp_set)
|
|
||||||
{
|
|
||||||
bool newState = (lampState = (value == "ON"));
|
|
||||||
writeLamp(newState);
|
|
||||||
if (mqttClient && mqttConnected)
|
|
||||||
mqttVerbosePub(topic_lamp_status, newState ? "ON" : "OFF", 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MQTT_EVENT_BEFORE_CONNECT:
|
|
||||||
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_BEFORE_CONNECT");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MQTT_EVENT_DELETED:
|
|
||||||
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_DELETED");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ESP_LOGW(TAG, "%s unknown event_id %i", event_base, event_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int mqttVerbosePub(std::string_view topic, std::string_view value, int qos, int retain)
|
|
||||||
{
|
|
||||||
ESP_LOGD(TAG, "topic=\"%.*s\" value=\"%.*s\"", topic.size(), topic.data(), value.size(), value.data());
|
|
||||||
const auto pending_msg_id = mqttClient.publish(topic, value, qos, retain);
|
|
||||||
if (pending_msg_id < 0)
|
|
||||||
ESP_LOGE(TAG, "topic=\"%.*s\" value=\"%.*s\" failed pending_msg_id=%i", topic.size(), topic.data(), value.size(), value.data(), pending_msg_id);
|
|
||||||
else
|
|
||||||
ESP_LOGI(TAG, "topic=\"%.*s\" value=\"%.*s\" succeeded pending_msg_id=%i", topic.size(), topic.data(), value.size(), value.data(), pending_msg_id);
|
|
||||||
return pending_msg_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void verboseDigitalWrite(uint8_t pin, uint8_t val)
|
|
||||||
{
|
|
||||||
ESP_LOGI(TAG, "pin=%hhu val=%hhu", pin, val);
|
|
||||||
|
|
||||||
digitalWrite(pin, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeLamp(bool state)
|
|
||||||
{
|
|
||||||
if (invertLamp)
|
|
||||||
state = !state;
|
|
||||||
verboseDigitalWrite(pins_lamp, state ? HIGH : LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool readSwitch()
|
|
||||||
{
|
|
||||||
bool state = digitalRead(pins_switch) == HIGH;
|
|
||||||
if (invertSwitch)
|
|
||||||
state = !state;
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
auto espchrono::local_clock::timezone() noexcept -> time_zone
|
auto espchrono::local_clock::timezone() noexcept -> time_zone
|
||||||
{
|
{
|
||||||
return time_zone{1h, DayLightSavingMode::EuropeanSummerTime};
|
return time_zone{1h, DayLightSavingMode::EuropeanSummerTime};
|
||||||
|
36
main/myconfig.cpp
Normal file
36
main/myconfig.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include "myconfig.h"
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <nvs_flash.h>
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
nvs_handle_t nvsHandle;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "CONFIG";
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_config()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const auto result = nvs_flash_init();
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_flash_init(): %s", esp_err_to_name(result));
|
||||||
|
//if (result != ESP_OK)
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto result = nvs_open("deckenlampe", NVS_READWRITE, &nvsHandle);
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_open(): %s", esp_err_to_name(result));
|
||||||
|
//if (result != ESP_OK)
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_config()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
} // namespace deckenlamp
|
64
main/myconfig.h
Normal file
64
main/myconfig.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <string_view>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <nvs.h>
|
||||||
|
#include <hal/gpio_types.h>
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
extern nvs_handle_t nvsHandle;
|
||||||
|
|
||||||
|
namespace config {
|
||||||
|
constexpr const std::string_view hostname = "deckenlampe1";
|
||||||
|
|
||||||
|
constexpr const std::string_view sta_ssid = "ScheissAP";
|
||||||
|
constexpr const std::string_view sta_key = "Passwort_123";
|
||||||
|
|
||||||
|
constexpr const std::string_view ap_ssid = "deckenlampe1";
|
||||||
|
constexpr const std::string_view ap_key = "Passwort_123";
|
||||||
|
|
||||||
|
constexpr const std::string_view broker_url = "mqtt://192.168.0.2/";
|
||||||
|
|
||||||
|
constexpr const bool enable_lamp = true;
|
||||||
|
constexpr const gpio_num_t pins_lamp = GPIO_NUM_25;
|
||||||
|
constexpr const bool invertLamp = true;
|
||||||
|
constexpr const std::string_view topic_lamp_availability = "dahoam/wohnzimmer/deckenlicht1/available";
|
||||||
|
constexpr const std::string_view topic_lamp_status = "dahoam/wohnzimmer/deckenlicht1/status";
|
||||||
|
constexpr const std::string_view topic_lamp_set = "dahoam/wohnzimmer/deckenlicht1/set";
|
||||||
|
|
||||||
|
|
||||||
|
constexpr const bool enable_switch = true;
|
||||||
|
constexpr const gpio_num_t pins_switch = GPIO_NUM_35;
|
||||||
|
constexpr const bool invert_switch = true;
|
||||||
|
constexpr const std::string_view topic_switch_availability = "dahoam/wohnzimmer/schalter1/available";
|
||||||
|
constexpr const std::string_view topic_switch_status = "dahoam/wohnzimmer/schalter1/status";
|
||||||
|
|
||||||
|
constexpr const bool enable_dht = true;
|
||||||
|
constexpr const gpio_num_t pins_dht = GPIO_NUM_33;
|
||||||
|
constexpr const std::string_view topic_dht11_availability = "dahoam/wohnzimmer/dht11_1/available";
|
||||||
|
constexpr const std::string_view topic_dht11_temperature = "dahoam/wohnzimmer/dht11_1/temperature";
|
||||||
|
constexpr const std::string_view topic_dht11_humidity = "dahoam/wohnzimmer/dht11_1/humidity";
|
||||||
|
|
||||||
|
constexpr const gpio_num_t pins_sda = GPIO_NUM_16;
|
||||||
|
constexpr const gpio_num_t pins_scl = GPIO_NUM_17;
|
||||||
|
|
||||||
|
constexpr const bool enable_tsl = true;
|
||||||
|
constexpr const std::string_view topic_tsl2561_availability = "dahoam/wohnzimmer/tsl2561_1/available";
|
||||||
|
constexpr const std::string_view topic_tsl2561_lux = "dahoam/wohnzimmer/tsl2561_1/lux";
|
||||||
|
|
||||||
|
constexpr const bool enable_bmp = true;
|
||||||
|
constexpr const std::string_view topic_bmp085_availability = "dahoam/wohnzimmer/bmp085_1/available";
|
||||||
|
constexpr const std::string_view topic_bmp085_pressure = "dahoam/wohnzimmer/bmp085_1/pressure";
|
||||||
|
constexpr const std::string_view topic_bmp085_temperature = "dahoam/wohnzimmer/bmp085_1/temperature";
|
||||||
|
constexpr const std::string_view topic_bmp085_altitude = "dahoam/wohnzimmer/bmp085_1/altitude";
|
||||||
|
|
||||||
|
constexpr const std::chrono::minutes availableTimeoutTime{1};
|
||||||
|
constexpr const std::chrono::seconds valueUpdateInterval{15};
|
||||||
|
} // namespace configs
|
||||||
|
|
||||||
|
void init_config();
|
||||||
|
void update_config();
|
||||||
|
} // namespace deckenlampe
|
50
main/mymdns.cpp
Normal file
50
main/mymdns.cpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#include "mymdns.h"
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <mdns.h>
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "myconfig.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "MDNS";
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_mdns()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const auto result = mdns_init();
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_init(): %s", esp_err_to_name(result));
|
||||||
|
if (result != ESP_OK)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto result = mdns_hostname_set(config::hostname.data());
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_hostname_set(): %s", esp_err_to_name(result));
|
||||||
|
//if (result != ESP_OK)
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto result = mdns_instance_name_set(config::hostname.data());
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_instance_name_set(): %s", esp_err_to_name(result));
|
||||||
|
//if (result != ESP_OK)
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto result = mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_service_add(): %s", esp_err_to_name(result));
|
||||||
|
//if (result != ESP_OK)
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_mdns()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace deckenlampe
|
6
main/mymdns.h
Normal file
6
main/mymdns.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
void init_mdns();
|
||||||
|
void update_mdns();
|
||||||
|
} // namespace deckenlampe
|
194
main/mymqtt.cpp
Normal file
194
main/mymqtt.cpp
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
#include "mymqtt.h"
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "myconfig.h"
|
||||||
|
#include "feature_lamp.h"
|
||||||
|
#include "feature_switch.h"
|
||||||
|
#include "feature_dht.h"
|
||||||
|
#include "feature_tsl.h"
|
||||||
|
#include "feature_bmp.h"
|
||||||
|
#include "cppmacros.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
std::atomic<bool> mqttConnected;
|
||||||
|
espcpputils::mqtt_client mqttClient;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "MQTT";
|
||||||
|
|
||||||
|
void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_mqtt()
|
||||||
|
{
|
||||||
|
esp_mqtt_client_config_t mqtt_cfg = {
|
||||||
|
.uri = config::broker_url.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
mqttClient = espcpputils::mqtt_client{&mqtt_cfg};
|
||||||
|
|
||||||
|
if (!mqttClient)
|
||||||
|
{
|
||||||
|
ESP_LOGE(TAG, "error while initializing mqtt client!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto result = mqttClient.register_event(MQTT_EVENT_ANY, mqttEventHandler, NULL);
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_mqtt_client_register_event(): %s", esp_err_to_name(result));
|
||||||
|
//if (result != ESP_OK)
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto result = mqttClient.start();
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_mqtt_client_start(): %s", esp_err_to_name(result));
|
||||||
|
//if (result != ESP_OK)
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_mqtt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int mqttVerbosePub(std::string_view topic, std::string_view value, int qos, int retain)
|
||||||
|
{
|
||||||
|
ESP_LOGD(TAG, "topic=\"%.*s\" value=\"%.*s\"", topic.size(), topic.data(), value.size(), value.data());
|
||||||
|
const auto pending_msg_id = mqttClient.publish(topic, value, qos, retain);
|
||||||
|
if (pending_msg_id < 0)
|
||||||
|
ESP_LOGE(TAG, "topic=\"%.*s\" value=\"%.*s\" failed pending_msg_id=%i", topic.size(), topic.data(), value.size(), value.data(), pending_msg_id);
|
||||||
|
else
|
||||||
|
ESP_LOGI(TAG, "topic=\"%.*s\" value=\"%.*s\" succeeded pending_msg_id=%i", topic.size(), topic.data(), value.size(), value.data(), pending_msg_id);
|
||||||
|
return pending_msg_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
|
||||||
|
{
|
||||||
|
CPP_UNUSED(event_handler_arg)
|
||||||
|
|
||||||
|
const esp_mqtt_event_t *data = reinterpret_cast<const esp_mqtt_event_t *>(event_data);
|
||||||
|
|
||||||
|
switch (esp_mqtt_event_id_t(event_id)) {
|
||||||
|
case MQTT_EVENT_ERROR:
|
||||||
|
ESP_LOGE(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_ERROR");
|
||||||
|
|
||||||
|
// ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||||
|
// if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
|
||||||
|
// {
|
||||||
|
// log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
|
||||||
|
// log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
|
||||||
|
// log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
|
||||||
|
// ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
|
||||||
|
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_CONNECTED:
|
||||||
|
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_CONNECTED");
|
||||||
|
|
||||||
|
mqttConnected = true;
|
||||||
|
|
||||||
|
if (config::enable_lamp) {
|
||||||
|
mqttVerbosePub(config::topic_lamp_availability, "online", 0, 1);
|
||||||
|
mqttVerbosePub(config::topic_lamp_status, lampState.load() ? "ON" : "OFF", 0, 1);
|
||||||
|
mqttClient.subscribe(config::topic_lamp_set, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config::enable_switch) {
|
||||||
|
mqttVerbosePub(config::topic_switch_availability, "online", 0, 1);
|
||||||
|
mqttVerbosePub(config::topic_switch_status, switchState.load() ? "ON" : "OFF", 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config::enable_dht) {
|
||||||
|
mqttVerbosePub(config::topic_dht11_availability, lastDhtValue ? "online" : "offline", 0, 1);
|
||||||
|
if (lastDhtValue) {
|
||||||
|
if (mqttVerbosePub(config::topic_dht11_temperature, fmt::format("{:.1f}", lastDhtValue->temperature), 0, 1) >= 0)
|
||||||
|
last_dht11_temperature_pub = espchrono::millis_clock::now();
|
||||||
|
if (mqttVerbosePub(config::topic_dht11_humidity, fmt::format("{:.1f}", lastDhtValue->humidity), 0, 1) >= 0)
|
||||||
|
last_dht11_humidity_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config::enable_tsl) {
|
||||||
|
mqttVerbosePub(config::topic_tsl2561_availability, lastTslValue ? "online" : "offline", 0, 1);
|
||||||
|
if (lastTslValue) {
|
||||||
|
if (mqttVerbosePub(config::topic_tsl2561_lux, fmt::format("{:.1f}", lastTslValue->lux), 0, 1) >= 0)
|
||||||
|
last_tsl2561_lux_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config::enable_bmp) {
|
||||||
|
mqttVerbosePub(config::topic_bmp085_availability, lastBmpValue ? "online" : "offline", 0, 1);
|
||||||
|
if (lastBmpValue) {
|
||||||
|
if (mqttVerbosePub(config::topic_bmp085_pressure, fmt::format("{:.1f}", lastBmpValue->pressure), 0, 1) >= 0)
|
||||||
|
last_bmp085_pressure_pub = espchrono::millis_clock::now();
|
||||||
|
if (mqttVerbosePub(config::topic_bmp085_temperature, fmt::format("{:.1f}", lastBmpValue->temperature), 0, 1) >= 0)
|
||||||
|
last_bmp085_temperature_pub = espchrono::millis_clock::now();
|
||||||
|
if (mqttVerbosePub(config::topic_bmp085_altitude, fmt::format("{:.1f}", lastBmpValue->altitude), 0, 1) >= 0)
|
||||||
|
last_bmp085_altitude_pub = espchrono::millis_clock::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_DISCONNECTED:
|
||||||
|
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_DISCONNECTED");
|
||||||
|
|
||||||
|
mqttConnected = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_SUBSCRIBED:
|
||||||
|
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_SUBSCRIBED");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_UNSUBSCRIBED:
|
||||||
|
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_UNSUBSCRIBED");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_PUBLISHED:
|
||||||
|
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_PUBLISHED");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_DATA: {
|
||||||
|
std::string_view topic{data->topic, (size_t)data->topic_len};
|
||||||
|
std::string_view value{data->data, (size_t)data->data_len};
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "%s event_id=%s topic=%.*s data=%.*s", event_base, "MQTT_EVENT_DATA", topic.size(), topic.data(), value.size(), value.data());
|
||||||
|
|
||||||
|
if (topic == config::topic_lamp_set) {
|
||||||
|
if (config::enable_lamp) {
|
||||||
|
bool newState = (lampState = (value == "ON"));
|
||||||
|
writeLamp(newState);
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_lamp_status, newState ? "ON" : "OFF", 0, 1);
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "received lamp set without lamp support enabled!");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "received unknown data topic=%.*s data=%.*s", topic.size(), topic.data(), value.size(), value.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MQTT_EVENT_BEFORE_CONNECT:
|
||||||
|
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_BEFORE_CONNECT");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MQTT_EVENT_DELETED:
|
||||||
|
ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_DELETED");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ESP_LOGW(TAG, "%s unknown event_id %i", event_base, event_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
} // namespace deckenlampe
|
18
main/mymqtt.h
Normal file
18
main/mymqtt.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <atomic>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "wrappers/mqtt_client.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
extern std::atomic<bool> mqttConnected;
|
||||||
|
extern espcpputils::mqtt_client mqttClient;
|
||||||
|
|
||||||
|
void init_mqtt();
|
||||||
|
void update_mqtt();
|
||||||
|
|
||||||
|
int mqttVerbosePub(std::string_view topic, std::string_view value, int qos, int retain);
|
||||||
|
} // namespace deckenlampe
|
65
main/mywifi.cpp
Normal file
65
main/mywifi.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "mywifi.h"
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "espwifistack.h"
|
||||||
|
#include "myconfig.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
namespace {
|
||||||
|
wifi_stack::config makeWifiConfig();
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_wifi()
|
||||||
|
{
|
||||||
|
wifi_stack::init(makeWifiConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_wifi()
|
||||||
|
{
|
||||||
|
wifi_stack::update(makeWifiConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
wifi_stack::config makeWifiConfig()
|
||||||
|
{
|
||||||
|
return wifi_stack::config {
|
||||||
|
.wifiEnabled = true,
|
||||||
|
.hostname = std::string{config::hostname},
|
||||||
|
.wifis = std::array<wifi_stack::wifi_entry, 10> {
|
||||||
|
wifi_stack::wifi_entry { .ssid = std::string{config::sta_ssid}, .key = std::string{config::sta_key} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} },
|
||||||
|
wifi_stack::wifi_entry { .ssid = {}, .key = {} }
|
||||||
|
},
|
||||||
|
.sta_ip = {
|
||||||
|
.dhcpEnabled = true,
|
||||||
|
// .staticIp = {},
|
||||||
|
// .staticGateway = {},
|
||||||
|
// .staticSubnet = {},
|
||||||
|
// .staticDns1 = {},
|
||||||
|
// .staticDns2 = {}
|
||||||
|
},
|
||||||
|
.ap = {
|
||||||
|
{
|
||||||
|
.ssid = std::string{config::ap_ssid},
|
||||||
|
.key = std::string{config::ap_key}
|
||||||
|
},
|
||||||
|
.channel = 1,
|
||||||
|
.authmode = WIFI_AUTH_WPA2_PSK,
|
||||||
|
.ssid_hidden = false,
|
||||||
|
.max_connection = 4,
|
||||||
|
.beacon_interval = 100,
|
||||||
|
.ip{192, 168, 4, 1},
|
||||||
|
.subnet{255, 255, 255, 0}
|
||||||
|
},
|
||||||
|
.min_rssi = -90
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
} // namespace deckenlampe
|
6
main/mywifi.h
Normal file
6
main/mywifi.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
void init_wifi();
|
||||||
|
void update_wifi();
|
||||||
|
} // namespace deckenlampe
|
202
main/webserver.cpp
Normal file
202
main/webserver.cpp
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
#include "webserver.h"
|
||||||
|
|
||||||
|
// system includes
|
||||||
|
#include <string_view>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
// 3rdparty lib includes
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "myconfig.h"
|
||||||
|
#include "feature_lamp.h"
|
||||||
|
#include "feature_switch.h"
|
||||||
|
#include "feature_dht.h"
|
||||||
|
#include "feature_tsl.h"
|
||||||
|
#include "feature_bmp.h"
|
||||||
|
#include "mymqtt.h"
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
httpd_handle_t httpdHandle;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr const char * const TAG = "WEBSERVER";
|
||||||
|
|
||||||
|
esp_err_t webserver_root_handler(httpd_req_t *req);
|
||||||
|
esp_err_t webserver_on_handler(httpd_req_t *req);
|
||||||
|
esp_err_t webserver_off_handler(httpd_req_t *req);
|
||||||
|
esp_err_t webserver_toggle_handler(httpd_req_t *req);
|
||||||
|
esp_err_t webserver_reboot_handler(httpd_req_t *req);
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void init_webserver()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
httpd_config_t httpConfig HTTPD_DEFAULT_CONFIG();
|
||||||
|
|
||||||
|
const auto result = httpd_start(&httpdHandle, &httpConfig);
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_start(): %s", esp_err_to_name(result));
|
||||||
|
if (result != ESP_OK)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const httpd_uri_t &uri : {
|
||||||
|
httpd_uri_t { .uri = "/", .method = HTTP_GET, .handler = webserver_root_handler, .user_ctx = NULL },
|
||||||
|
httpd_uri_t { .uri = "/on", .method = HTTP_GET, .handler = webserver_on_handler, .user_ctx = NULL },
|
||||||
|
httpd_uri_t { .uri = "/off", .method = HTTP_GET, .handler = webserver_off_handler, .user_ctx = NULL },
|
||||||
|
httpd_uri_t { .uri = "/toggle", .method = HTTP_GET, .handler = webserver_toggle_handler, .user_ctx = NULL },
|
||||||
|
httpd_uri_t { .uri = "/reboot", .method = HTTP_GET, .handler = webserver_reboot_handler, .user_ctx = NULL }
|
||||||
|
})
|
||||||
|
{
|
||||||
|
const auto result = httpd_register_uri_handler(httpdHandle, &uri);
|
||||||
|
ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", uri.uri, esp_err_to_name(result));
|
||||||
|
//if (result != ESP_OK)
|
||||||
|
// return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_webserver()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
#define CALL_AND_EXIT_ON_ERROR(METHOD, ...) \
|
||||||
|
if (const auto result = METHOD(__VA_ARGS__); result != ESP_OK) \
|
||||||
|
{ \
|
||||||
|
ESP_LOGE(TAG, "%s() failed with %s", #METHOD, esp_err_to_name(result)); \
|
||||||
|
return result; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CALL_AND_EXIT(METHOD, ...) \
|
||||||
|
if (const auto result = METHOD(__VA_ARGS__); result != ESP_OK) \
|
||||||
|
{ \
|
||||||
|
ESP_LOGE(TAG, "%s() failed with %s", #METHOD, esp_err_to_name(result)); \
|
||||||
|
return result; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
return result;
|
||||||
|
|
||||||
|
esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
std::string body = "this is work in progress...<br/>\n";
|
||||||
|
|
||||||
|
if (config::enable_lamp) {
|
||||||
|
body += "<a href=\"/on\">on</a><br/>\n"
|
||||||
|
"<a href=\"/off\">off</a><br/>\n"
|
||||||
|
"<a href=\"/toggle\">toggle</a><br/>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
body += "<a href=\"/reboot\">reboot</a><br/>\n"
|
||||||
|
"<br/>\n";
|
||||||
|
|
||||||
|
if (config::enable_lamp)
|
||||||
|
body += fmt::format("Lamp: {}<br/>\n", lampState ? "ON" : "OFF");
|
||||||
|
|
||||||
|
if (config::enable_switch)
|
||||||
|
body += fmt::format("Switch: {}<br/>\n", switchState ? "ON" : "OFF");
|
||||||
|
|
||||||
|
if (config::enable_dht) {
|
||||||
|
if (lastDhtValue) {
|
||||||
|
body += fmt::format("DHT11 Temperature: {:.1f} C<br/>\n", lastDhtValue->temperature);
|
||||||
|
body += fmt::format("DHT11 Humidity: {:.1f} %<br/>\n", lastDhtValue->humidity);
|
||||||
|
} else
|
||||||
|
body += "DHT11 not available at the moment<br/>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config::enable_tsl) {
|
||||||
|
if (lastTslValue) {
|
||||||
|
body += fmt::format("TSL2561 Brightness: {:.1f} lux<br/>\n", lastTslValue->lux);
|
||||||
|
} else
|
||||||
|
body += "TSL2561 not available at the moment<br/>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config::enable_bmp) {
|
||||||
|
if (lastBmpValue) {
|
||||||
|
body += fmt::format("BMP085 Pressure: {:.1f} lux<br/>\n", lastBmpValue->pressure);
|
||||||
|
body += fmt::format("BMP085 Temperature: {:.1f} C<br/>\n", lastBmpValue->temperature);
|
||||||
|
body += fmt::format("BMP085 Altitude: {:.1f} m<br/>\n", lastBmpValue->altitude);
|
||||||
|
} else
|
||||||
|
body += "BMP085 not available at the moment<br/>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t webserver_on_handler(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
if (!config::enable_lamp) {
|
||||||
|
ESP_LOGW(TAG, "lamp support not enabled!");
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_send_err, req, HTTPD_400_BAD_REQUEST, "lamp support not enabled!")
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool state = (lampState = true);
|
||||||
|
writeLamp(state);
|
||||||
|
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_lamp_status, state ? "ON" : "OFF", 0, 1);
|
||||||
|
|
||||||
|
std::string_view body{"ON called..."};
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t webserver_off_handler(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
if (!config::enable_lamp) {
|
||||||
|
ESP_LOGW(TAG, "lamp support not enabled!");
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_send_err, req, HTTPD_400_BAD_REQUEST, "lamp support not enabled!")
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool state = (lampState = false);
|
||||||
|
writeLamp(state);
|
||||||
|
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_lamp_status, state ? "ON" : "OFF", 0, 1);
|
||||||
|
|
||||||
|
std::string_view body{"OFF called..."};
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t webserver_toggle_handler(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
if (!config::enable_lamp) {
|
||||||
|
ESP_LOGW(TAG, "lamp support not enabled!");
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_send_err, req, HTTPD_400_BAD_REQUEST, "lamp support not enabled!")
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool state = (lampState = !lampState);
|
||||||
|
writeLamp(state);
|
||||||
|
|
||||||
|
if (mqttClient && mqttConnected)
|
||||||
|
mqttVerbosePub(config::topic_lamp_status, state ? "ON" : "OFF", 0, 1);
|
||||||
|
|
||||||
|
std::string_view body{"TOGGLE called..."};
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t webserver_reboot_handler(httpd_req_t *req)
|
||||||
|
{
|
||||||
|
std::string_view body{"REBOOT called..."};
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html")
|
||||||
|
CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size())
|
||||||
|
|
||||||
|
esp_restart();
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
} // namespace deckenlampe
|
11
main/webserver.h
Normal file
11
main/webserver.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// esp-idf includes
|
||||||
|
#include <esp_http_server.h>
|
||||||
|
|
||||||
|
namespace deckenlampe {
|
||||||
|
extern httpd_handle_t httpdHandle;
|
||||||
|
|
||||||
|
void init_webserver();
|
||||||
|
void update_webserver();
|
||||||
|
} // namespace deckenlampe
|
Reference in New Issue
Block a user