forked from Aircoookie/WLED
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Usermod: Add support for Si7021 temperature and humidity sensors (Air…
…coookie#2617) * added first version (work in progress) * added some sensors to publish * typo * added dependency * mqtt si7021_* names + don't retain * timer to 60 s * some changes to HA auto discovery * added config entries (no function yet) * renaming * made configs work * added getId() * refactoring + wrong mqtt topics fixed * retain HA auto discovery * do not spam serial console on each sensor update * added readme * add update interval info Co-authored-by: Christian Schwinne <[email protected]>
- Loading branch information
1 parent
8b79a97
commit 9cd8aca
Showing
4 changed files
with
314 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Si7021 to MQTT (with Home Assistant Auto Discovery) usermod | ||
|
||
This usermod implements support for [Si7021 I²C temperature and humidity sensors](https://www.silabs.com/documents/public/data-sheets/Si7021-A20.pdf). | ||
|
||
The sensor data will *not* be shown on the WLED UI (so far) but published via MQTT to WLED's "build in" MQTT device topic. | ||
|
||
``` | ||
temperature: $mqttDeviceTopic/si7021_temperature | ||
humidity: $mqttDeviceTopic/si7021_humidity | ||
``` | ||
|
||
Additionally the following sensors can be published: | ||
|
||
``` | ||
heat_index: $mqttDeviceTopic/si7021_heat_index | ||
dew_point: $mqttDeviceTopic/si7021_dew_point | ||
absolute_humidity: $mqttDeviceTopic/si7021_absolute_humidity | ||
``` | ||
|
||
Sensor data will be updated/send every 60 seconds. | ||
|
||
This usermod also supports Home Assistant Auto Discovery. | ||
|
||
## Settings via Usermod Setup | ||
|
||
- `enabled`: Enables this usermod | ||
- `Send Dew Point, Abs. Humidity and Heat Index`: Enables additional sensors | ||
- `Home Assistant MQTT Auto-Discovery`: Enables Home Assistant Auto Discovery | ||
|
||
# Installation | ||
|
||
## Hardware | ||
|
||
Attach the Si7021 sensor to the I²C interface. | ||
|
||
Default PINs ESP32: | ||
|
||
``` | ||
SCL_PIN = 22; | ||
SDA_PIN = 21; | ||
``` | ||
|
||
Default PINs ESP8266: | ||
|
||
``` | ||
SCL_PIN = 5; | ||
SDA_PIN = 4; | ||
``` | ||
|
||
## Software | ||
|
||
Add to `build_flags` in platformio.ini: | ||
|
||
``` | ||
-D USERMOD_SI7021_MQTT_HA | ||
``` | ||
|
||
Add to `lib_deps` in platformio.ini: | ||
|
||
``` | ||
adafruit/Adafruit Si7021 Library @ 1.4.0 | ||
BME280@~3.0.0 | ||
``` | ||
|
||
# Credits | ||
|
||
- Aircoookie for making WLED | ||
- Other usermod creators for example code (`sensors_to_mqtt` and `multi_relay` especially) | ||
- You, for reading this |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
#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; | ||
|
||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards | ||
uint8_t SCL_PIN = 22; | ||
uint8_t SDA_PIN = 21; | ||
#else //ESP8266 boards | ||
uint8_t SCL_PIN = 5; | ||
uint8_t SDA_PIN = 4; | ||
#endif | ||
|
||
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!"); | ||
Wire.begin(SDA_PIN, SCL_PIN); | ||
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"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters