UM SHT: Added SHT usermod

This commit is contained in:
ezcGman 2022-12-11 01:16:14 +01:00
parent 917cd96a3d
commit e8edb99bb0
4 changed files with 367 additions and 1 deletions

45
usermods/sht/readme.md Normal file
View File

@ -0,0 +1,45 @@
# SHT
Usermod to support various SHT i2c sensors like the SHT30, SHT31, SHT35 and SHT85
## Requirements
* "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85
## Usermod installation
1. Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the buildflag `-D USERMOD_SHT` and the below library dependencies.
2. If you're not using thr SHT30 sensor, change the `-D USERMOD_SHT_TYPE_SHT30` build flag to one of these: `USERMOD_SHT_TYPE_SHT31`, `USERMOD_SHT_TYPE_SHT35` or `USERMOD_SHT_TYPE_SHT85`.
ESP32:
```
[env:custom_esp32dev_usermod_sht]
extends = env:esp32dev
build_flags = ${common.build_flags_esp32}
-D USERMOD_SHT
-D USERMOD_SHT_TYPE_SHT30
lib_deps = ${esp32.lib_deps}
robtillaart/SHT85@~0.3.3
```
ESP8266:
```
[env:custom_d1_mini_usermod_quinled_an_penta]
extends = env:d1_mini
build_flags = ${common.build_flags_esp8266}
-D USERMOD_SHT
-D USERMOD_SHT_TYPE_SHT30
lib_deps = ${esp8266.lib_deps}
olikraus/U8g2@~2.28.8
robtillaart/SHT85@~0.2.0
```
## MQTT Discovery for Home Assistant
If you're using Home Assistant and want to have the temperature and humidity available as entities in HA, you can tick the "Add-To-Home-Assistant-MQTT-Discovery" option in the usermod settings. If you have an MQTT broker configured under "Sync Settings" and it is connected, the mod will publish the auto discovery message to your broker and HA will instantly find it and create an entity each for the temperature and humidity.
### Publishing readings via MQTT
Regardless of having MQTT discovery ticked or not, the mod will always report temperature and humidity to the WLED MQTT topic of that instance, if you have a broker configured and it's connected.
## Change log
2022-12
* First implementation.
## Credits
ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: https://discord.gg/WdbAauG

312
usermods/sht/usermod_sht.h Normal file
View File

@ -0,0 +1,312 @@
#pragma once
#include "SHT85.h"
class ShtUsermod : public Usermod
{
private:
bool enabled = false;
bool firstRunDone = false;
bool initDone = false;
bool haMqttDiscovery = false;
SHT *shtTempHumidSensor;
// SHT vars
bool shtInitDone = false;
bool shtReadDataSuccess = false;
byte shtI2cAddress = 0x44;
unsigned long shtLastTimeUpdated = 0;
bool shtDataRequested = false;
float shtCurrentTemp = 0;
float shtLastKnownTemp = 0;
float shtCurrentHumidity = 0;
float shtLastKnownHumidity = 0;
void initShtTempHumiditySensor()
{
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } };
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) {
DEBUG_PRINTF("[%s] SHT pin allocation failed!\n", _name);
shtInitDone = false;
cleanupShtTempHumiditySensor();
cleanup();
return;
}
#ifdef USERMOD_SHT_TYPE_SHT31
shtTempHumidSensor = (SHT *) new SHT31();
#else
#ifdef USERMOD_SHT_TYPE_SHT35
shtTempHumidSensor = (SHT *) new SHT35();
#else
#ifdef USERMOD_SHT_TYPE_SHT85
shtTempHumidSensor = (SHT *) new SHT85();
#else
shtTempHumidSensor = (SHT *) new SHT30();
#endif
#endif
#endif
shtTempHumidSensor->begin(shtI2cAddress, i2c_sda, i2c_scl);
if (shtTempHumidSensor->readStatus() == 0xFFFF) {
DEBUG_PRINTF("[%s] SHT init failed!\n", _name);
shtInitDone = false;
cleanupShtTempHumiditySensor();
cleanup();
return;
}
shtInitDone = true;
}
void cleanupShtTempHumiditySensor()
{
if (shtInitDone) {
shtTempHumidSensor->reset();
}
pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C);
pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C);
delete shtTempHumidSensor;
shtInitDone = false;
}
void cleanup()
{
if (isShtReady()) {
cleanupShtTempHumiditySensor();
}
enabled = false;
}
bool isShtReady()
{
return shtInitDone;
}
public:
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _haMqttDiscovery[];
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup()
{
if (enabled) {
initShtTempHumiditySensor();
initDone = true;
}
firstRunDone = true;
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*
* Tips:
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
*
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here.
*/
void loop()
{
if (!enabled || !initDone || strip.isUpdating()) return;
if (isShtReady()) {
if (millis() - shtLastTimeUpdated > 30000 && !shtDataRequested) {
shtTempHumidSensor->requestData();
shtDataRequested = true;
shtLastTimeUpdated = millis();
}
if (shtDataRequested) {
if (shtTempHumidSensor->dataReady()) {
if (shtTempHumidSensor->readData(false)) {
shtCurrentTemp = shtTempHumidSensor->getTemperature();
shtCurrentHumidity = shtTempHumidSensor->getHumidity();
publishTemperatureAndHumidityViaMqtt();
shtReadDataSuccess = true;
}
else {
shtReadDataSuccess = false;
}
shtDataRequested = false;
}
}
}
}
void onMqttConnect(bool sessionPresent) {
if (haMqttDiscovery) publishHomeAssistantAutodiscovery();
}
void addToConfig(JsonObject &root)
{
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = enabled;
top[FPSTR(_haMqttDiscovery)] = haMqttDiscovery;
}
/**
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
*
* The function should return true if configuration was successfully loaded or false if there was no configuration.
*/
bool readFromConfig(JsonObject &root)
{
JsonObject top = root[FPSTR(_name)];
if (top.isNull()) {
DEBUG_PRINTF("[%s] No config found. (Using defaults.)\n", _name);
return false;
}
bool oldEnabled = enabled;
bool oldHaMqttDiscovery = haMqttDiscovery;
getJsonValue(top[FPSTR(_enabled)], enabled);
getJsonValue(top[FPSTR(_haMqttDiscovery)], haMqttDiscovery);
// First run: reading from cfg.json, nothing to do here, will be all done in setup()
if (!firstRunDone) {
DEBUG_PRINTF("[%s] First run, nothing to do\n", _name);
}
// Check if mod has been en-/disabled
else if (enabled != oldEnabled) {
enabled ? setup() : cleanup();
DEBUG_PRINTF("[%s] Usermod has been en-/disabled\n", _name);
}
// Config has been changed, so adopt to changes
else if (enabled) {
if (oldHaMqttDiscovery != haMqttDiscovery && haMqttDiscovery) {
publishHomeAssistantAutodiscovery();
}
DEBUG_PRINTF("[%s] Config (re)loaded\n", _name);
}
return true;
}
void addToJsonInfo(JsonObject& root)
{
if (!enabled && !isShtReady()) {
return;
}
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray jsonTemp = user.createNestedArray("Temperature");
JsonArray jsonHumidity = user.createNestedArray("Humidity");
if (shtLastTimeUpdated == 0 || !shtReadDataSuccess) {
jsonTemp.add(0);
jsonHumidity.add(0);
if (shtLastTimeUpdated == 0) {
jsonTemp.add(" Not read yet");
jsonHumidity.add(" Not read yet");
}
else {
jsonTemp.add(" Error");
jsonHumidity.add(" Error");
}
return;
}
jsonHumidity.add(shtCurrentHumidity);
jsonHumidity.add(" RH");
jsonTemp.add(shtCurrentTemp);
jsonTemp.add(" °C");
}
void publishTemperatureAndHumidityViaMqtt() {
if (!WLED_MQTT_CONNECTED) return;
char buf[128];
sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic);
mqtt->publish(buf, 0, false, String(shtCurrentTemp).c_str());
sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic);
mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str());
}
void publishHomeAssistantAutodiscovery() {
if (!WLED_MQTT_CONNECTED) return;
char json_str[1024], buf[128];
size_t payload_size;
StaticJsonDocument<1024> json;
sprintf_P(buf, PSTR("%s Temperature"), serverDescription);
json[F("name")] = buf;
sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic);
json[F("stat_t")] = buf;
json[F("dev_cla")] = F("temperature");
json[F("stat_cla")] = F("measurement");
sprintf_P(buf, PSTR("%s-temperature"), escapedMac.c_str());
json[F("uniq_id")] = buf;
json[F("unit_of_meas")] = F("°C");
appendDeviceToMqttDiscoveryMessage(json);
payload_size = serializeJson(json, json_str);
sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-temperature/config"), escapedMac.c_str(), escapedMac.c_str());
mqtt->publish(buf, 0, true, json_str, payload_size);
json.clear();
sprintf_P(buf, PSTR("%s Humidity"), serverDescription);
json[F("name")] = buf;
sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic);
json[F("stat_t")] = buf;
json[F("dev_cla")] = F("humidity");
json[F("stat_cla")] = F("measurement");
sprintf_P(buf, PSTR("%s-humidity"), escapedMac.c_str());
json[F("uniq_id")] = buf;
json[F("unit_of_meas")] = F("%");
appendDeviceToMqttDiscoveryMessage(json);
payload_size = serializeJson(json, json_str);
sprintf_P(buf, PSTR("homeassistant/sensor/%s/%s-humidity/config"), escapedMac.c_str(), escapedMac.c_str());
mqtt->publish(buf, 0, true, json_str, payload_size);
}
void appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
JsonObject device = root.createNestedObject("dev");
device["ids"] = escapedMac.c_str();
device["name"] = serverDescription;
device["sw"] = versionString;
device["mdl"] = ESP.getChipModel();
device["mf"] = "espressif";
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId()
{
return USERMOD_ID_SHT;
}
};
// strings to reduce flash memory usage (used more than twice)
// Config settings
const char ShtUsermod::_name[] PROGMEM = "SHT Temperature & Humidity Sensor";
const char ShtUsermod::_enabled[] PROGMEM = "Enabled";
const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-Home-Assistant-MQTT-Discovery";

View File

@ -100,6 +100,7 @@
#define USERMOD_ID_BOBLIGHT 36 //Usermod "boblight.h"
#define USERMOD_ID_SD_CARD 37 //Usermod "usermod_sd_card.h"
#define USERMOD_ID_PWM_OUTPUTS 38 //Usermod "usermod_pwm_outputs.h
#define USERMOD_ID_SHT 39 //Usermod "usermod_sht.h
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

View File

@ -180,6 +180,10 @@
#include "../usermods/pwm_outputs/usermod_pwm_outputs.h"
#endif
#ifdef USERMOD_SHT
#include "../usermods/sht/usermod_sht.h"
#endif
void registerUsermods()
{
@ -340,4 +344,8 @@ void registerUsermods()
#ifdef USERMOD_PWM_OUTPUTS
usermods.add(new PwmOutputsUsermod());
#endif
#ifdef USERMOD_SHT
usermods.add(new ShtUsermod());
#endif
}