2023-01-12 19:35:34 +00:00
|
|
|
#ifndef WLED_ENABLE_MQTT
|
|
|
|
#error "This user mod requires MQTT to be enabled."
|
|
|
|
#endif
|
|
|
|
|
2022-04-03 20:30:37 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
// this is remixed from usermod_v2_SensorsToMqtt.h (sensors_to_mqtt usermod)
|
|
|
|
// and usermod_multi_relay.h (multi_relay usermod)
|
|
|
|
|
|
|
|
#include "wled.h"
|
|
|
|
#include <Adafruit_Si7021.h>
|
|
|
|
#include <EnvironmentCalculations.h> // EnvironmentCalculations::HeatIndex(), ::DewPoint(), ::AbsoluteHumidity()
|
|
|
|
|
|
|
|
Adafruit_Si7021 si7021;
|
|
|
|
|
|
|
|
class Si7021_MQTT_HA : public Usermod
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
bool sensorInitialized = false;
|
|
|
|
bool mqttInitialized = false;
|
|
|
|
float sensorTemperature = 0;
|
|
|
|
float sensorHumidity = 0;
|
|
|
|
float sensorHeatIndex = 0;
|
|
|
|
float sensorDewPoint = 0;
|
|
|
|
float sensorAbsoluteHumidity= 0;
|
|
|
|
String mqttTemperatureTopic = "";
|
|
|
|
String mqttHumidityTopic = "";
|
|
|
|
String mqttHeatIndexTopic = "";
|
|
|
|
String mqttDewPointTopic = "";
|
|
|
|
String mqttAbsoluteHumidityTopic = "";
|
|
|
|
unsigned long nextMeasure = 0;
|
|
|
|
bool enabled = false;
|
|
|
|
bool haAutoDiscovery = true;
|
|
|
|
bool sendAdditionalSensors = true;
|
|
|
|
|
|
|
|
// strings to reduce flash memory usage (used more than twice)
|
|
|
|
static const char _name[];
|
|
|
|
static const char _enabled[];
|
|
|
|
static const char _sendAdditionalSensors[];
|
|
|
|
static const char _haAutoDiscovery[];
|
|
|
|
|
|
|
|
void _initializeSensor()
|
|
|
|
{
|
|
|
|
sensorInitialized = si7021.begin();
|
|
|
|
Serial.printf("Si7021_MQTT_HA: sensorInitialized = %d\n", sensorInitialized);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _initializeMqtt()
|
|
|
|
{
|
|
|
|
mqttTemperatureTopic = String(mqttDeviceTopic) + "/si7021_temperature";
|
|
|
|
mqttHumidityTopic = String(mqttDeviceTopic) + "/si7021_humidity";
|
|
|
|
mqttHeatIndexTopic = String(mqttDeviceTopic) + "/si7021_heat_index";
|
|
|
|
mqttDewPointTopic = String(mqttDeviceTopic) + "/si7021_dew_point";
|
|
|
|
mqttAbsoluteHumidityTopic = String(mqttDeviceTopic) + "/si7021_absolute_humidity";
|
|
|
|
|
|
|
|
// Update and publish sensor data
|
|
|
|
_updateSensorData();
|
|
|
|
_publishSensorData();
|
|
|
|
|
|
|
|
if (haAutoDiscovery) {
|
|
|
|
_publishHAMqttSensor("temperature", "Temperature", mqttTemperatureTopic, "temperature", "°C");
|
|
|
|
_publishHAMqttSensor("humidity", "Humidity", mqttHumidityTopic, "humidity", "%");
|
|
|
|
if (sendAdditionalSensors) {
|
|
|
|
_publishHAMqttSensor("heat_index", "Heat Index", mqttHeatIndexTopic, "temperature", "°C");
|
|
|
|
_publishHAMqttSensor("dew_point", "Dew Point", mqttDewPointTopic, "", "°C");
|
|
|
|
_publishHAMqttSensor("absolute_humidity", "Absolute Humidity", mqttAbsoluteHumidityTopic, "", "g/m³");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mqttInitialized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _publishHAMqttSensor(
|
|
|
|
const String &name,
|
|
|
|
const String &friendly_name,
|
|
|
|
const String &state_topic,
|
|
|
|
const String &deviceClass,
|
|
|
|
const String &unitOfMeasurement)
|
|
|
|
{
|
|
|
|
if (WLED_MQTT_CONNECTED) {
|
|
|
|
String topic = String("homeassistant/sensor/") + mqttClientID + "/" + name + "/config";
|
|
|
|
|
|
|
|
StaticJsonDocument<300> doc;
|
|
|
|
|
|
|
|
doc["name"] = String(serverDescription) + " " + friendly_name;
|
|
|
|
doc["state_topic"] = state_topic;
|
|
|
|
doc["unique_id"] = String(mqttClientID) + name;
|
|
|
|
if (unitOfMeasurement != "")
|
|
|
|
doc["unit_of_measurement"] = unitOfMeasurement;
|
|
|
|
if (deviceClass != "")
|
|
|
|
doc["device_class"] = deviceClass;
|
|
|
|
doc["expire_after"] = 1800;
|
|
|
|
|
|
|
|
JsonObject device = doc.createNestedObject("device"); // attach the sensor to the same device
|
|
|
|
device["name"] = String(serverDescription);
|
|
|
|
device["model"] = "WLED";
|
|
|
|
device["manufacturer"] = "Aircoookie";
|
|
|
|
device["identifiers"] = String("wled-") + String(serverDescription);
|
|
|
|
device["sw_version"] = VERSION;
|
|
|
|
|
|
|
|
String payload;
|
|
|
|
serializeJson(doc, payload);
|
|
|
|
|
|
|
|
mqtt->publish(topic.c_str(), 0, true, payload.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _updateSensorData()
|
|
|
|
{
|
|
|
|
sensorTemperature = si7021.readTemperature();
|
|
|
|
sensorHumidity = si7021.readHumidity();
|
|
|
|
|
|
|
|
// Serial.print("Si7021_MQTT_HA: Temperature: ");
|
|
|
|
// Serial.print(sensorTemperature, 2);
|
|
|
|
// Serial.print("\tHumidity: ");
|
|
|
|
// Serial.print(sensorHumidity, 2);
|
|
|
|
|
|
|
|
if (sendAdditionalSensors) {
|
|
|
|
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
|
|
|
|
sensorHeatIndex = EnvironmentCalculations::HeatIndex(sensorTemperature, sensorHumidity, envTempUnit);
|
|
|
|
sensorDewPoint = EnvironmentCalculations::DewPoint(sensorTemperature, sensorHumidity, envTempUnit);
|
|
|
|
sensorAbsoluteHumidity = EnvironmentCalculations::AbsoluteHumidity(sensorTemperature, sensorHumidity, envTempUnit);
|
|
|
|
|
|
|
|
// Serial.print("\tHeat Index: ");
|
|
|
|
// Serial.print(sensorHeatIndex, 2);
|
|
|
|
// Serial.print("\tDew Point: ");
|
|
|
|
// Serial.print(sensorDewPoint, 2);
|
|
|
|
// Serial.print("\tAbsolute Humidity: ");
|
|
|
|
// Serial.println(sensorAbsoluteHumidity, 2);
|
|
|
|
}
|
|
|
|
// else
|
|
|
|
// Serial.println("");
|
|
|
|
}
|
|
|
|
|
|
|
|
void _publishSensorData()
|
|
|
|
{
|
|
|
|
if (WLED_MQTT_CONNECTED) {
|
|
|
|
mqtt->publish(mqttTemperatureTopic.c_str(), 0, false, String(sensorTemperature).c_str());
|
|
|
|
mqtt->publish(mqttHumidityTopic.c_str(), 0, false, String(sensorHumidity).c_str());
|
|
|
|
if (sendAdditionalSensors) {
|
|
|
|
mqtt->publish(mqttHeatIndexTopic.c_str(), 0, false, String(sensorHeatIndex).c_str());
|
|
|
|
mqtt->publish(mqttDewPointTopic.c_str(), 0, false, String(sensorDewPoint).c_str());
|
|
|
|
mqtt->publish(mqttAbsoluteHumidityTopic.c_str(), 0, false, String(sensorAbsoluteHumidity).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
void addToConfig(JsonObject& root)
|
|
|
|
{
|
|
|
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
|
|
|
|
|
|
|
top[FPSTR(_enabled)] = enabled;
|
|
|
|
top[FPSTR(_sendAdditionalSensors)] = sendAdditionalSensors;
|
|
|
|
top[FPSTR(_haAutoDiscovery)] = haAutoDiscovery;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool readFromConfig(JsonObject& root)
|
|
|
|
{
|
|
|
|
JsonObject top = root[FPSTR(_name)];
|
|
|
|
|
|
|
|
bool configComplete = !top.isNull();
|
|
|
|
configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled);
|
|
|
|
configComplete &= getJsonValue(top[FPSTR(_sendAdditionalSensors)], sendAdditionalSensors);
|
|
|
|
configComplete &= getJsonValue(top[FPSTR(_haAutoDiscovery)], haAutoDiscovery);
|
|
|
|
|
|
|
|
return configComplete;
|
|
|
|
}
|
|
|
|
|
|
|
|
void onMqttConnect(bool sessionPresent) {
|
|
|
|
if (mqttDeviceTopic[0] != 0)
|
|
|
|
_initializeMqtt();
|
|
|
|
}
|
|
|
|
|
|
|
|
void setup()
|
|
|
|
{
|
|
|
|
if (enabled) {
|
|
|
|
Serial.println("Si7021_MQTT_HA: Starting!");
|
|
|
|
Serial.println("Si7021_MQTT_HA: Initializing sensors.. ");
|
|
|
|
_initializeSensor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// gets called every time WiFi is (re-)connected.
|
|
|
|
void connected()
|
|
|
|
{
|
|
|
|
nextMeasure = millis() + 5000; // Schedule next measure in 5 seconds
|
|
|
|
}
|
|
|
|
|
|
|
|
void loop()
|
|
|
|
{
|
|
|
|
yield();
|
|
|
|
if (!enabled || strip.isUpdating()) return; // !sensorFound ||
|
|
|
|
|
|
|
|
unsigned long tempTimer = millis();
|
|
|
|
|
|
|
|
if (tempTimer > nextMeasure) {
|
|
|
|
nextMeasure = tempTimer + 60000; // Schedule next measure in 60 seconds
|
|
|
|
|
|
|
|
if (!sensorInitialized) {
|
|
|
|
Serial.println("Si7021_MQTT_HA: Error! Sensors not initialized in loop()!");
|
|
|
|
_initializeSensor();
|
|
|
|
return; // lets try again next loop
|
|
|
|
}
|
|
|
|
|
|
|
|
if (WLED_MQTT_CONNECTED) {
|
|
|
|
if (!mqttInitialized)
|
|
|
|
_initializeMqtt();
|
|
|
|
|
|
|
|
// Update and publish sensor data
|
|
|
|
_updateSensorData();
|
|
|
|
_publishSensorData();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Serial.println("Si7021_MQTT_HA: Missing MQTT connection. Not publishing data");
|
|
|
|
mqttInitialized = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t getId()
|
|
|
|
{
|
|
|
|
return USERMOD_ID_SI7021_MQTT_HA;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// strings to reduce flash memory usage (used more than twice)
|
|
|
|
const char Si7021_MQTT_HA::_name[] PROGMEM = "Si7021 MQTT (Home Assistant)";
|
|
|
|
const char Si7021_MQTT_HA::_enabled[] PROGMEM = "enabled";
|
|
|
|
const char Si7021_MQTT_HA::_sendAdditionalSensors[] PROGMEM = "Send Dew Point, Abs. Humidity and Heat Index";
|
|
|
|
const char Si7021_MQTT_HA::_haAutoDiscovery[] PROGMEM = "Home Assistant MQTT Auto-Discovery";
|