UM SHT: Added SHT usermod
This commit is contained in:
parent
917cd96a3d
commit
e8edb99bb0
45
usermods/sht/readme.md
Normal file
45
usermods/sht/readme.md
Normal 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
312
usermods/sht/usermod_sht.h
Normal 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";
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
@ -292,7 +296,7 @@ void registerUsermods()
|
||||
#ifdef QUINLED_AN_PENTA
|
||||
usermods.add(new QuinLEDAnPentaUsermod());
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USERMOD_WIZLIGHTS
|
||||
usermods.add(new WizLightsUsermod());
|
||||
#endif
|
||||
@ -340,4 +344,8 @@ void registerUsermods()
|
||||
#ifdef USERMOD_PWM_OUTPUTS
|
||||
usermods.add(new PwmOutputsUsermod());
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_SHT
|
||||
usermods.add(new ShtUsermod());
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user