UM SHT: Avoid inline methods

This commit is contained in:
ezcGman 2022-12-15 00:42:27 +01:00
parent 9587480e29
commit a3f6717c59

View File

@ -30,87 +30,28 @@ class ShtUsermod : public Usermod
float shtLastKnownHumidity = 0; float shtLastKnownHumidity = 0;
void initShtTempHumiditySensor() void initShtTempHumiditySensor();
{ void cleanupShtTempHumiditySensor();
switch (shtType) { void cleanup();
case USERMOD_SHT_TYPE_SHT30: shtTempHumidSensor = (SHT *) new SHT30(); break; bool isShtReady();
case USERMOD_SHT_TYPE_SHT31: shtTempHumidSensor = (SHT *) new SHT31(); break;
case USERMOD_SHT_TYPE_SHT35: shtTempHumidSensor = (SHT *) new SHT35(); break;
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
}
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();
}
delete shtTempHumidSensor;
shtInitDone = false;
}
void cleanup()
{
if (isShtReady()) {
cleanupShtTempHumiditySensor();
}
pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C);
pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C);
enabled = false;
}
bool isShtReady()
{
return shtInitDone;
}
void publishTemperatureAndHumidityViaMqtt();
void publishHomeAssistantAutodiscovery();
void appendDeviceToMqttDiscoveryMessage(JsonDocument& root);
public: public:
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
static const char _name[]; static const char _name[];
static const char _enabled[]; static const char _enabled[];
static const char _haMqttDiscovery[];
static const char _shtType[]; static const char _shtType[];
static const char _unitOfTemp[]; static const char _unitOfTemp[];
static const char _haMqttDiscovery[];
/* /*
* setup() is called once at boot. WiFi is not yet connected at this point. * setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar. * You can use it to initialize variables, sensors or similar.
*/ */
void setup() void setup();
{
if (enabled) {
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;
}
initShtTempHumiditySensor();
initDone = true;
}
firstRunDone = true;
}
/* /*
* loop() is called continuously. Here you can check for events, read sensors, etc. * loop() is called continuously. Here you can check for events, read sensors, etc.
@ -122,232 +63,328 @@ class ShtUsermod : public Usermod
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here. * Instead, use a timer check as shown here.
*/ */
void loop() void loop();
{ void onMqttConnect(bool sessionPresent);
if (!enabled || !initDone || strip.isUpdating()) return; void appendConfigData();
void addToConfig(JsonObject &root);
bool readFromConfig(JsonObject &root);
void addToJsonInfo(JsonObject& root);
if (isShtReady()) { float getTemperatureC();
if (millis() - shtLastTimeUpdated > 30000 && !shtDataRequested) { float getTemperatureF();
shtTempHumidSensor->requestData(); float getHumidity();
shtDataRequested = true;
shtLastTimeUpdated = millis();
}
if (shtDataRequested) {
if (shtTempHumidSensor->dataReady()) {
if (shtTempHumidSensor->readData(false)) {
shtCurrentTempC = shtTempHumidSensor->getTemperature();
shtCurrentTempF = shtTempHumidSensor->getFahrenheit();
shtCurrentHumidity = shtTempHumidSensor->getHumidity();
publishTemperatureAndHumidityViaMqtt();
shtReadDataSuccess = true;
}
else {
shtReadDataSuccess = false;
}
shtDataRequested = false;
}
}
}
}
void onMqttConnect(bool sessionPresent) {
if (haMqttDiscovery) publishHomeAssistantAutodiscovery();
}
void appendConfigData() {
oappend(SET_F("dd=addDropdown('"));
oappend(_name);
oappend(SET_F("','"));
oappend(_shtType);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'SHT30',0);"));
oappend(SET_F("addOption(dd,'SHT31',1);"));
oappend(SET_F("addOption(dd,'SHT35',2);"));
oappend(SET_F("addOption(dd,'SHT85',3);"));
oappend(SET_F("dd=addDropdown('"));
oappend(_name);
oappend(SET_F("','"));
oappend(_unitOfTemp);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'Celsius',0);"));
oappend(SET_F("addOption(dd,'Fahrenheit',1);"));
}
void addToConfig(JsonObject &root)
{
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = enabled;
top[FPSTR(_haMqttDiscovery)] = haMqttDiscovery;
top[FPSTR(_shtType)] = shtType;
top[FPSTR(_unitOfTemp)] = unitOfTemp;
}
/**
* 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;
byte oldShtType = shtType;
getJsonValue(top[FPSTR(_enabled)], enabled);
getJsonValue(top[FPSTR(_haMqttDiscovery)], haMqttDiscovery);
getJsonValue(top[FPSTR(_shtType)], shtType);
getJsonValue(top[FPSTR(_unitOfTemp)], unitOfTemp);
// 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();
}
if (oldShtType != shtType) {
cleanupShtTempHumiditySensor();
initShtTempHumiditySensor();
}
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(F("Temperature"));
JsonArray jsonHumidity = user.createNestedArray(F("Humidity"));
if (shtLastTimeUpdated == 0 || !shtReadDataSuccess) {
jsonTemp.add(0);
jsonHumidity.add(0);
if (shtLastTimeUpdated == 0) {
jsonTemp.add(F(" Not read yet"));
jsonHumidity.add(F(" Not read yet"));
}
else {
jsonTemp.add(F(" Error"));
jsonHumidity.add(F(" Error"));
}
return;
}
jsonHumidity.add(shtCurrentHumidity);
jsonHumidity.add(F(" RH"));
unitOfTemp ? jsonTemp.add(getTemperatureF()) : jsonTemp.add(getTemperatureC());
unitOfTemp ? jsonTemp.add(F(" °F")) : jsonTemp.add(F(" °C"));
}
void publishTemperatureAndHumidityViaMqtt() {
if (!WLED_MQTT_CONNECTED) return;
char buf[128];
sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic);
mqtt->publish(buf, 0, false, String((unitOfTemp ? getTemperatureF() : getTemperatureC())).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[F("ids")] = escapedMac.c_str();
device[F("name")] = serverDescription;
device[F("sw")] = versionString;
device[F("mdl")] = ESP.getChipModel();
device[F("mf")] = F("espressif");
}
float getTemperatureC() {
return shtCurrentTempC;
}
float getTemperatureF() {
return shtCurrentTempF;
}
/* /*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * 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. * This could be used in the future for the system to determine whether your usermod is installed.
*/ */
uint16_t getId() uint16_t getId() { return USERMOD_ID_SHT; }
{
return USERMOD_ID_SHT;
}
}; };
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
// Config settings // Config settings
const char ShtUsermod::_name[] PROGMEM = "SHT-Sensor"; const char ShtUsermod::_name[] PROGMEM = "SHT-Sensor";
const char ShtUsermod::_enabled[] PROGMEM = "Enabled"; const char ShtUsermod::_enabled[] PROGMEM = "Enabled";
const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-Home-Assistant-MQTT-Discovery";
const char ShtUsermod::_shtType[] PROGMEM = "SHT-Type"; const char ShtUsermod::_shtType[] PROGMEM = "SHT-Type";
const char ShtUsermod::_unitOfTemp[] PROGMEM = "Unit"; const char ShtUsermod::_unitOfTemp[] PROGMEM = "Unit";
const char ShtUsermod::_haMqttDiscovery[] PROGMEM = "Add-To-HA-MQTT-Discovery";
void ShtUsermod::initShtTempHumiditySensor()
{
switch (shtType) {
case USERMOD_SHT_TYPE_SHT30: shtTempHumidSensor = (SHT *) new SHT30(); break;
case USERMOD_SHT_TYPE_SHT31: shtTempHumidSensor = (SHT *) new SHT31(); break;
case USERMOD_SHT_TYPE_SHT35: shtTempHumidSensor = (SHT *) new SHT35(); break;
case USERMOD_SHT_TYPE_SHT85: shtTempHumidSensor = (SHT *) new SHT85(); break;
}
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 ShtUsermod::cleanupShtTempHumiditySensor()
{
if (shtInitDone) {
shtTempHumidSensor->reset();
}
delete shtTempHumidSensor;
shtInitDone = false;
}
void ShtUsermod::cleanup()
{
if (isShtReady()) {
cleanupShtTempHumiditySensor();
}
pinManager.deallocatePin(i2c_sda, PinOwner::HW_I2C);
pinManager.deallocatePin(i2c_scl, PinOwner::HW_I2C);
enabled = false;
}
bool ShtUsermod::isShtReady()
{
return shtInitDone;
}
void ShtUsermod::publishTemperatureAndHumidityViaMqtt() {
if (!WLED_MQTT_CONNECTED) return;
char buf[128];
sprintf_P(buf, PSTR("%s/temperature"), mqttDeviceTopic);
mqtt->publish(buf, 0, false, String((unitOfTemp ? getTemperatureF() : getTemperatureC())).c_str());
sprintf_P(buf, PSTR("%s/humidity"), mqttDeviceTopic);
mqtt->publish(buf, 0, false, String(shtCurrentHumidity).c_str());
}
void ShtUsermod::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 ShtUsermod::appendDeviceToMqttDiscoveryMessage(JsonDocument& root) {
JsonObject device = root.createNestedObject("dev");
device[F("ids")] = escapedMac.c_str();
device[F("name")] = serverDescription;
device[F("sw")] = versionString;
device[F("mdl")] = ESP.getChipModel();
device[F("mf")] = F("espressif");
}
/*
* 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 ShtUsermod::setup()
{
if (enabled) {
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;
}
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 ShtUsermod::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)) {
shtCurrentTempC = shtTempHumidSensor->getTemperature();
shtCurrentTempF = shtTempHumidSensor->getFahrenheit();
shtCurrentHumidity = shtTempHumidSensor->getHumidity();
publishTemperatureAndHumidityViaMqtt();
shtReadDataSuccess = true;
}
else {
shtReadDataSuccess = false;
}
shtDataRequested = false;
}
}
}
}
void ShtUsermod::onMqttConnect(bool sessionPresent) {
if (haMqttDiscovery) publishHomeAssistantAutodiscovery();
}
void ShtUsermod::appendConfigData() {
oappend(SET_F("dd=addDropdown('"));
oappend(_name);
oappend(SET_F("','"));
oappend(_shtType);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'SHT30',0);"));
oappend(SET_F("addOption(dd,'SHT31',1);"));
oappend(SET_F("addOption(dd,'SHT35',2);"));
oappend(SET_F("addOption(dd,'SHT85',3);"));
oappend(SET_F("dd=addDropdown('"));
oappend(_name);
oappend(SET_F("','"));
oappend(_unitOfTemp);
oappend(SET_F("');"));
oappend(SET_F("addOption(dd,'Celsius',0);"));
oappend(SET_F("addOption(dd,'Fahrenheit',1);"));
}
void ShtUsermod::addToConfig(JsonObject &root)
{
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = enabled;
top[FPSTR(_shtType)] = shtType;
top[FPSTR(_unitOfTemp)] = unitOfTemp;
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 ShtUsermod::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;
byte oldShtType = shtType;
bool oldHaMqttDiscovery = haMqttDiscovery;
getJsonValue(top[FPSTR(_enabled)], enabled);
getJsonValue(top[FPSTR(_shtType)], shtType);
getJsonValue(top[FPSTR(_unitOfTemp)], unitOfTemp);
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();
}
if (oldShtType != shtType) {
cleanupShtTempHumiditySensor();
initShtTempHumiditySensor();
}
DEBUG_PRINTF("[%s] Config (re)loaded\n", _name);
}
return true;
}
void ShtUsermod::addToJsonInfo(JsonObject& root)
{
if (!enabled && !isShtReady()) {
return;
}
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray jsonTemp = user.createNestedArray(F("Temperature"));
JsonArray jsonHumidity = user.createNestedArray(F("Humidity"));
if (shtLastTimeUpdated == 0 || !shtReadDataSuccess) {
jsonTemp.add(0);
jsonHumidity.add(0);
if (shtLastTimeUpdated == 0) {
jsonTemp.add(F(" Not read yet"));
jsonHumidity.add(F(" Not read yet"));
}
else {
jsonTemp.add(F(" Error"));
jsonHumidity.add(F(" Error"));
}
return;
}
jsonHumidity.add(shtCurrentHumidity);
jsonHumidity.add(F(" RH"));
unitOfTemp ? jsonTemp.add(getTemperatureF()) : jsonTemp.add(getTemperatureC());
unitOfTemp ? jsonTemp.add(F(" °F")) : jsonTemp.add(F(" °C"));
}
float ShtUsermod::getTemperatureC() {
return shtCurrentTempC;
}
float ShtUsermod::getTemperatureF() {
return shtCurrentTempF;
}
float ShtUsermod::getHumidity() {
return shtCurrentHumidity;
}