From 412a9e64fb8fda47b170ce84c826f47b671b685b Mon Sep 17 00:00:00 2001 From: TD-er Date: Sun, 18 Oct 2026 02:43:36 +0200 Subject: [PATCH] [Build] Use static func. MQTT helper, NWPlugin Helper, NW import/export --- .../net/Helpers/NWPlugin_import_export.cpp | 4 +- .../net/Helpers/_NWPlugin_Helper_webform.cpp | 78 +-- .../net/Helpers/_NWPlugin_Helper_webform.h | 8 +- src/src/Helpers/_CPlugin_Helper_mqtt.cpp | 473 ++++++++++-------- src/src/Helpers/_CPlugin_Helper_mqtt.h | 46 -- src/src/Static/WebStaticData.cpp | 337 +++++++------ src/src/Static/WebStaticData.h | 2 - 7 files changed, 480 insertions(+), 468 deletions(-) diff --git a/src/ESPEasy/net/Helpers/NWPlugin_import_export.cpp b/src/ESPEasy/net/Helpers/NWPlugin_import_export.cpp index cfe549a3b..68c4f9686 100644 --- a/src/ESPEasy/net/Helpers/NWPlugin_import_export.cpp +++ b/src/ESPEasy/net/Helpers/NWPlugin_import_export.cpp @@ -33,7 +33,7 @@ namespace ESPEasy { namespace net { -ESPEasy_key_value_store_import_export::LabelStringFunction getLabelFnc(ESPEasy::net::nwpluginID_t nwpluginID) +static ESPEasy_key_value_store_import_export::LabelStringFunction getLabelFnc(ESPEasy::net::nwpluginID_t nwpluginID) { switch (nwpluginID.value) @@ -67,7 +67,7 @@ ESPEasy_key_value_store_import_export::LabelStringFunction getLabelFnc(ESPEasy:: return nullptr; } -ESPEasy_key_value_store_import_export::NextKeyFunction getNextKeyFnc(ESPEasy::net::nwpluginID_t nwpluginID, bool includeCredentials) +static ESPEasy_key_value_store_import_export::NextKeyFunction getNextKeyFnc(ESPEasy::net::nwpluginID_t nwpluginID, bool includeCredentials) { switch (nwpluginID.value) diff --git a/src/ESPEasy/net/Helpers/_NWPlugin_Helper_webform.cpp b/src/ESPEasy/net/Helpers/_NWPlugin_Helper_webform.cpp index 03a8dc90e..0cfe3f2fe 100644 --- a/src/ESPEasy/net/Helpers/_NWPlugin_Helper_webform.cpp +++ b/src/ESPEasy/net/Helpers/_NWPlugin_Helper_webform.cpp @@ -13,7 +13,7 @@ namespace net { /*********************************************************************************************\ * Functions to load and store network settings on the web page. \*********************************************************************************************/ -const __FlashStringHelper* toString(NetworkSettingsStruct::VarType parameterIdx, bool displayName) +static const __FlashStringHelper* toString(NetworkSettingsStruct::VarType parameterIdx, bool displayName) { switch (parameterIdx) { @@ -61,16 +61,16 @@ String getNetworkParameterName(networkDriverIndex_t NetworkDriverIndex return name; } -String getNetworkParameterInternalName(networkDriverIndex_t NetworkDriverIndex, NetworkSettingsStruct::VarType parameterIdx) { +static String getNetworkParameterInternalName(networkDriverIndex_t NetworkDriverIndex, NetworkSettingsStruct::VarType parameterIdx) { bool isAlternative; // Dummy, not needed for internal name bool displayName = false; return getNetworkParameterName(NetworkDriverIndex, parameterIdx, displayName, isAlternative); } -String getNetworkParameterDisplayName(networkDriverIndex_t NetworkDriverIndex, - NetworkSettingsStruct::VarType parameterIdx, - bool & isAlternative) { +static String getNetworkParameterDisplayName(networkDriverIndex_t NetworkDriverIndex, + NetworkSettingsStruct::VarType parameterIdx, + bool & isAlternative) { bool displayName = true; return getNetworkParameterName(NetworkDriverIndex, parameterIdx, displayName, isAlternative); @@ -91,21 +91,22 @@ void addNetworkEnabledForm(networkIndex_t networkindex) { addFormCheckBox(displayName, internalName, Settings.getNetworkEnabled(networkindex)); } -void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings, +/* + void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings, networkIndex_t networkindex, NetworkSettingsStruct::VarType varType) { - networkDriverIndex_t NetworkDriverIndex = getNetworkDriverIndex_from_NetworkIndex(networkindex); + networkDriverIndex_t NetworkDriverIndex = getNetworkDriverIndex_from_NetworkIndex(networkindex); - if (!validNetworkDriverIndex(NetworkDriverIndex)) { + if (!validNetworkDriverIndex(NetworkDriverIndex)) { return; - } + } - bool isAlternativeDisplayName = false; - const String displayName = getNetworkParameterDisplayName(NetworkDriverIndex, varType, isAlternativeDisplayName); - const String internalName = getNetworkParameterInternalName(NetworkDriverIndex, varType); + bool isAlternativeDisplayName = false; + const String displayName = getNetworkParameterDisplayName(NetworkDriverIndex, varType, isAlternativeDisplayName); + const String internalName = getNetworkParameterInternalName(NetworkDriverIndex, varType); - switch (varType) - { + switch (varType) + { case NetworkSettingsStruct::NETWORK_IP: { addFormIPBox(displayName, internalName, NetworkSettings.IP); @@ -119,33 +120,32 @@ void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings, case NetworkSettingsStruct::NETWORK_USER: { - /* - const size_t fieldMaxLength = - NetworkSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_USER_LENGTH : sizeof(SecuritySettings.NetworkUser[0]) - 1; - addFormTextBox(displayName, - internalName, - getNetworkUser(networkindex, NetworkSettings, false), - fieldMaxLength); - */ - break; + + // const size_t fieldMaxLength = + // NetworkSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_USER_LENGTH : sizeof(SecuritySettings.NetworkUser[0]) - 1; + // addFormTextBox(displayName, + // internalName, + // getNetworkUser(networkindex, NetworkSettings, false), + // fieldMaxLength); + break; } case NetworkSettingsStruct::NETWORK_PASS: { - /* - const size_t fieldMaxLength = - NetworkSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_PASS_LENGTH : sizeof(SecuritySettings.NetworkPassword[0]) - 1; - if (isAlternativeDisplayName) { + // const size_t fieldMaxLength = + // NetworkSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_PASS_LENGTH : sizeof(SecuritySettings.NetworkPassword[0]) - 1; + + // if (isAlternativeDisplayName) { // It is not a regular password, thus use normal text field. - addFormTextBox(displayName, internalName, - getNetworkPass(networkindex, NetworkSettings), - fieldMaxLength); - } else { - addFormPasswordBox(displayName, internalName, - getNetworkPass(networkindex, NetworkSettings), - fieldMaxLength); - } - */ + // addFormTextBox(displayName, internalName, + // getNetworkPass(networkindex, NetworkSettings), + // fieldMaxLength); + // } else { + // addFormPasswordBox(displayName, internalName, + // getNetworkPass(networkindex, NetworkSettings), + // fieldMaxLength); + // } + break; } @@ -157,9 +157,9 @@ void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings, case NetworkSettingsStruct::NETWORK_ENABLED: addFormCheckBox(displayName, internalName, Settings.getNetworkEnabled(networkindex)); break; - } -} - + } + } + */ void saveNetworkParameterForm(NetworkSettingsStruct & NetworkSettings, networkIndex_t networkindex, NetworkSettingsStruct::VarType varType) { diff --git a/src/ESPEasy/net/Helpers/_NWPlugin_Helper_webform.h b/src/ESPEasy/net/Helpers/_NWPlugin_Helper_webform.h index 1be0a6b96..4b34ec927 100644 --- a/src/ESPEasy/net/Helpers/_NWPlugin_Helper_webform.h +++ b/src/ESPEasy/net/Helpers/_NWPlugin_Helper_webform.h @@ -19,19 +19,15 @@ String getNetworkParameterName(networkDriverIndex_t NetworkDriverIndex bool displayName, bool & isAlternative); -String getNetworkParameterInternalName(networkDriverIndex_t NetworkDriverIndex, - NetworkSettingsStruct::VarType parameterIdx); -String getNetworkParameterDisplayName(networkDriverIndex_t NetworkDriverIndex, - NetworkSettingsStruct::VarType parameterIdx, - bool & isAlternative); void addNetworkEnabledForm(networkIndex_t networkindex); +/* void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings, networkIndex_t networkindex, NetworkSettingsStruct::VarType varType); - +*/ void saveNetworkParameterForm(NetworkSettingsStruct & NetworkSettings, networkIndex_t networkindex, NetworkSettingsStruct::VarType varType); diff --git a/src/src/Helpers/_CPlugin_Helper_mqtt.cpp b/src/src/Helpers/_CPlugin_Helper_mqtt.cpp index 4fbf6b992..e74e726e5 100644 --- a/src/src/Helpers/_CPlugin_Helper_mqtt.cpp +++ b/src/src/Helpers/_CPlugin_Helper_mqtt.cpp @@ -378,21 +378,21 @@ int Plugin_QueryVType_BinarySensorInv(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_SWITCH_INVERTED) | Sensor_VType_CAN_SET; } -int Plugin_QueryVType_Analog(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_ANALOG_ONLY); } +int Plugin_QueryVType_Analog(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_ANALOG_ONLY); } -int Plugin_QueryVType_CO2(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_CO2_ONLY); } +int Plugin_QueryVType_CO2(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_CO2_ONLY); } -int Plugin_QueryVType_Distance(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_DISTANCE_ONLY); } +int Plugin_QueryVType_Distance(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_DISTANCE_ONLY); } -int Plugin_QueryVType_DustPM2_5(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY); } +int Plugin_QueryVType_DustPM2_5(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY); } -int Plugin_QueryVType_Lux(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_LUX_ONLY); } +int Plugin_QueryVType_Lux(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_LUX_ONLY); } -int Plugin_QueryVType_Temperature(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_TEMP_ONLY); } +int Plugin_QueryVType_Temperature(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_TEMP_ONLY); } -int Plugin_QueryVType_Weight(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY); } +int Plugin_QueryVType_Weight(uint8_t value_nr) { return static_cast(Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY); } -String makeHomeAssistantCompliantName(const String& name) { return ESPEasy::net::makeRFCCompliantName(name, '_', '_', 0); } +static String makeHomeAssistantCompliantName(const String& name) { return ESPEasy::net::makeRFCCompliantName(name, '_', '_', 0); } # if FEATURE_MQTT_DEVICECLASS const char mqtt_binary_deviceclass_names[] PROGMEM = @@ -412,7 +412,7 @@ String MQTT_binary_deviceClassName(int devClassIndex) { return result; } -int MQTT_binary_deviceClassIndex(const String& deviceClassName) { +static int MQTT_binary_deviceClassIndex(const String& deviceClassName) { return GetCommandCode(deviceClassName.c_str(), mqtt_binary_deviceclass_names); } @@ -468,49 +468,234 @@ const __FlashStringHelper* MQTT_sensor_StateClass(uint8_t index, # endif // if FEATURE_MQTT_STATE_CLASS -bool MQTT_SendAutoDiscovery(controllerIndex_t ControllerIndex, cpluginID_t CPluginID) { - bool success = true; +static String MQTT_DiscoveryBuildValueTopic(const String & topic, + struct EventStruct *event, + uint8_t taskValueIndex, + const __FlashStringHelper*deviceClass, + const String & uniqueId, + const String & elementId, + const String & valueName) { + String tmpTopic(topic); - MakeControllerSettings(ControllerSettings); // -V522 + # if FEATURE_STRING_VARIABLES - if (!AllocatedControllerSettings()) { - return false; + if (taskValueIndex >= VARS_PER_TASK) { + parseValNameVariable(tmpTopic, valueName, false); + } else + # endif // if FEATURE_STRING_VARIABLES + { + parseSingleControllerVariable(tmpTopic, event, taskValueIndex, false); } - LoadControllerSettings(ControllerIndex, *ControllerSettings); + parseDeviceClassVariable(tmpTopic, deviceClass, false); + parseUniqueIdVariable(tmpTopic, uniqueId, false); + parseElementIdVariable(tmpTopic, elementId, false); + parseControllerVariables(tmpTopic, event, false); // Replace this last - if (ControllerSettings->mqtt_autoDiscovery() + while (tmpTopic.endsWith(F("/"))) { + tmpTopic = tmpTopic.substring(0, tmpTopic.length() - 1); + } - // && (ControllerSettings->MqttAutoDiscoveryTrigger[0] != 0) - && (ControllerSettings->MqttAutoDiscoveryTopic[0] != 0)) { - # ifndef BUILD_NO_DEBUG + return tmpTopic; +} - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, concat(strformat(F("MQTT : AutoDiscovery for Controller %d CPlugin %d"), - ControllerIndex + 1, CPluginID), - validTaskIndex(mqttDiscoverOnlyTask) ? - strformat(F(", Task %d"), mqttDiscoverOnlyTask + 1) : - EMPTY_STRING)); - } - # endif // ifndef BUILD_NO_DEBUG +static String MQTT_TaskValueUniqueName(const String& taskName, + const String& valueName) { + String uniqueId = strformat(F("%s_%s_%s"), + makeHomeAssistantCompliantName(Settings.getHostname()).c_str(), + taskName.c_str(), + valueName.c_str()); + uniqueId.toLowerCase(); + return uniqueId; +} - // Dispatch autoDiscovery per supported CPlugin - switch (CPluginID) +static bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex, + const String & topic, + const String & discoveryMessage, + taskIndex_t x, + uint8_t v, + bool retainDsc) { + bool result = false; + + // Send each discovery message separate + result = MQTTpublish(ControllerIndex, INVALID_TASK_INDEX, topic.c_str(), discoveryMessage.c_str(), retainDsc); + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery %d Task %d '%s': disc.topic: %s"), + result, x + 1, getTaskDeviceName(x).c_str(), topic.c_str())); + addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery payload: %s"), + discoveryMessage.c_str())); + } + # endif // ifndef BUILD_NO_DEBUG + return result; +} + +static bool MQTT_DiscoveryPublishWithStatusAndSet( + uint8_t taskValue, + const String & valueName, + controllerIndex_t ControllerIndex, + ControllerSettingsStruct& ControllerSettings, + const __FlashStringHelper*componentClass, + const String & deviceClass, + const String & unitOfMeasure, + struct EventStruct *event, + const String & deviceElement, + const String & stateClass, + bool success, + bool hasSet, + bool hasIcon, + const String & elementName, + const String & elementId, + bool sendTrigger) +{ + if (!valueName.isEmpty()) { + const String taskName = makeHomeAssistantCompliantName(getTaskDeviceName(event->TaskIndex)); + const String valName = makeHomeAssistantCompliantName(valueName); + + const String uniqueId = elementName.isEmpty() ? MQTT_TaskValueUniqueName(taskName, valName) + : Settings.MQTTDiscoverGroupInclTaskname() + ? strformat(F("%s_%s_%s"), elementId.c_str(), taskName.c_str(), valName.c_str()) + : strformat(F("%s_%s"), elementId.c_str(), valName.c_str()); + String message; { - case 5: // CPLUGIN_ID_005 : Home assistant/openHAB - success = MQTT_HomeAssistant_SendAutoDiscovery(ControllerIndex, *ControllerSettings); - break; - } - } + const String publish = MQTT_DiscoveryBuildValueTopic(ControllerSettings.Publish, + event, + taskValue, + componentClass, + uniqueId, + elementId, + valName); + if (sendTrigger) { + // triggerMessage + message = strformat(F("{\"atype\":\"trigger\",\"t\":\"%s\"," + "\"p\":\"device_automation\"," + "\"type\":\"button_short_press\"," // FIXME ? + "\"stype\":\"switch_1\"" // FIXME ? + "%s}"), // deviceElement is used to pass in the TriggerState + publish.c_str(), deviceElement.c_str()); + } else { + // discoveryMessage + const String withSet = hasSet ? F(",\"cmd_t\":\"~/set\"") : EMPTY_STRING; + const String schema = hasSet ? EMPTY_STRING : "\"schema\":\"basic\","; + const String devOrIcon = hasIcon ? F("ic") : F("dev_cla"); + const String withUoM = unitOfMeasure.isEmpty() ? EMPTY_STRING : + strformat(F(",\"unit_of_meas\":\"%s\""), unitOfMeasure.c_str()); + const String stateJson = stateClass.isEmpty() ? EMPTY_STRING : + strformat(F(",\"stat_cla\":\"%s\""), stateClass.c_str()); + + message = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\",%s" + "\"%s\":\"%s\"%s%s%s,\"stat_t\":\"~\"" + "%s}"), // deviceElement last + publish.c_str(), taskName.c_str(), valName.c_str(), uniqueId.c_str(), schema.c_str(), + devOrIcon.c_str(), deviceClass.c_str(), withUoM.c_str(), stateJson.c_str(), withSet.c_str(), + deviceElement.c_str()); + } + } + + const bool retainDsc = ControllerSettings.mqtt_retainDiscovery(); + String topic; + { + const String discoveryUrl = MQTT_DiscoveryBuildValueTopic(ControllerSettings.MqttAutoDiscoveryTopic, + event, + taskValue, + componentClass, + uniqueId, + elementId, + valName); + const String discoveryConfig(parseStringKeepCase(ControllerSettings.MqttAutoDiscoveryConfig, 1, '|')); + topic = discoveryConfig.isEmpty() + ? concat(discoveryUrl, F("/config")) + : concat(discoveryUrl, discoveryConfig); + } + + return MQTT_DiscoveryPublish(ControllerIndex, + topic, + message, + event->TaskIndex, + taskValue, + retainDsc); + } return success; } +static bool MQTT_DiscoveryPublishWithStatusAndSet( + uint8_t taskValue, + const String & valueName, + controllerIndex_t ControllerIndex, + ControllerSettingsStruct& ControllerSettings, + const __FlashStringHelper*componentClass, + const String & deviceClass, + const String & unitOfMeasure, + struct EventStruct *event, + const String & deviceElement, + const String & stateClass, + bool success, + bool hasSet, + bool hasIcon, + const String & elementName, + const String & elementId) +{ + return MQTT_DiscoveryPublishWithStatusAndSet( + taskValue, + valueName, + ControllerIndex, + ControllerSettings, + componentClass, + deviceClass, + unitOfMeasure, + event, + deviceElement, + stateClass, + success, + hasSet, + hasIcon, + elementName, + elementId, + false); +} + +static String MQTT_DiscoveryHelperGetValueName(taskIndex_t taskIndex, + uint8_t taskVarIndex, + DiscoveryItem discoveryItem) { + return + # if FEATURE_STRING_VARIABLES + discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.varName : + # endif // if FEATURE_STRING_VARIABLES + getTaskValueName(taskIndex, taskVarIndex); +} + +static String MQTT_DiscoveryHelperGetValueUoM(taskIndex_t taskIndex, + uint8_t taskVarIndex, + DiscoveryItem discoveryItem, + const String& defaultUoM) { + return + # if FEATURE_TASKVALUE_UNIT_OF_MEASURE + # if FEATURE_STRING_VARIABLES + discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.uom : + # endif // if FEATURE_STRING_VARIABLES + toUnitOfMeasureName(Cache.getTaskVarUnitOfMeasure(taskIndex, taskVarIndex), defaultUoM); + # else // FEATURE_TASKVALUE_UNIT_OF_MEASURE + # if FEATURE_STRING_VARIABLES + discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.uom : + # endif // if FEATURE_STRING_VARIABLES + defaultUoM; + # endif // FEATURE_TASKVALUE_UNIT_OF_MEASURE +} + +static String MQTT_DiscoveryHelperGetValueUoM(taskIndex_t taskIndex, + uint8_t taskVarIndex, + DiscoveryItem discoveryItem) +{ + return MQTT_DiscoveryHelperGetValueUoM(taskIndex, taskVarIndex, discoveryItem, EMPTY_STRING); +} + /******************************************************** * Send MQTT AutoDiscovery in Home Assistant format *******************************************************/ -bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIndex, - ControllerSettingsStruct& ControllerSettings) { +static bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIndex, + ControllerSettingsStruct& ControllerSettings) { bool success = false; // Send plugin info @@ -934,6 +1119,44 @@ bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIn return success; } +bool MQTT_SendAutoDiscovery(controllerIndex_t ControllerIndex, cpluginID_t CPluginID) { + bool success = true; + + MakeControllerSettings(ControllerSettings); // -V522 + + if (!AllocatedControllerSettings()) { + return false; + } + LoadControllerSettings(ControllerIndex, *ControllerSettings); + + if (ControllerSettings->mqtt_autoDiscovery() + + // && (ControllerSettings->MqttAutoDiscoveryTrigger[0] != 0) + && (ControllerSettings->MqttAutoDiscoveryTopic[0] != 0)) { + # ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLog(LOG_LEVEL_INFO, concat(strformat(F("MQTT : AutoDiscovery for Controller %d CPlugin %d"), + ControllerIndex + 1, CPluginID), + validTaskIndex(mqttDiscoverOnlyTask) ? + strformat(F(", Task %d"), mqttDiscoverOnlyTask + 1) : + EMPTY_STRING)); + } + # endif // ifndef BUILD_NO_DEBUG + + + // Dispatch autoDiscovery per supported CPlugin + switch (CPluginID) + { + case 5: // CPLUGIN_ID_005 : Home assistant/openHAB + success = MQTT_HomeAssistant_SendAutoDiscovery(ControllerIndex, *ControllerSettings); + break; + } + } + + return success; +} + bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex, std::vector& discoveryItems, int valueCount, @@ -1017,184 +1240,6 @@ bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex, return discoveryItems.size() != orgLen; // Something added? } -String MQTT_TaskValueUniqueName(const String& taskName, - const String& valueName) { - String uniqueId = strformat(F("%s_%s_%s"), - makeHomeAssistantCompliantName(Settings.getHostname()).c_str(), - taskName.c_str(), - valueName.c_str()); - - uniqueId.toLowerCase(); - return uniqueId; -} - -String MQTT_DiscoveryBuildValueTopic(const String & topic, - struct EventStruct *event, - uint8_t taskValueIndex, - const __FlashStringHelper*deviceClass, - const String & uniqueId, - const String & elementId, - const String & valueName) { - String tmpTopic(topic); - - # if FEATURE_STRING_VARIABLES - - if (taskValueIndex >= VARS_PER_TASK) { - parseValNameVariable(tmpTopic, valueName, false); - } else - # endif // if FEATURE_STRING_VARIABLES - { - parseSingleControllerVariable(tmpTopic, event, taskValueIndex, false); - } - parseDeviceClassVariable(tmpTopic, deviceClass, false); - parseUniqueIdVariable(tmpTopic, uniqueId, false); - parseElementIdVariable(tmpTopic, elementId, false); - parseControllerVariables(tmpTopic, event, false); // Replace this last - - while (tmpTopic.endsWith(F("/"))) { - tmpTopic = tmpTopic.substring(0, tmpTopic.length() - 1); - } - - return tmpTopic; -} - -bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex, - const String & topic, - const String & discoveryMessage, - taskIndex_t x, - uint8_t v, - bool retainDsc) { - bool result = false; - - // Send each discovery message separate - result = MQTTpublish(ControllerIndex, INVALID_TASK_INDEX, topic.c_str(), discoveryMessage.c_str(), retainDsc); - # ifndef BUILD_NO_DEBUG - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery %d Task %d '%s': disc.topic: %s"), - result, x + 1, getTaskDeviceName(x).c_str(), topic.c_str())); - addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery payload: %s"), - discoveryMessage.c_str())); - } - # endif // ifndef BUILD_NO_DEBUG - return result; -} - -bool MQTT_DiscoveryPublishWithStatusAndSet(uint8_t taskValue, - const String & valueName, - controllerIndex_t ControllerIndex, - ControllerSettingsStruct& ControllerSettings, - const __FlashStringHelper*componentClass, - const String & deviceClass, - const String & unitOfMeasure, - struct EventStruct *event, - const String & deviceElement, - const String & stateClass, - bool success, - bool hasSet, - bool hasIcon, - const String & elementName, - const String & elementId, - bool sendTrigger) { - if (!valueName.isEmpty()) { - const String taskName = makeHomeAssistantCompliantName(getTaskDeviceName(event->TaskIndex)); - const String valName = makeHomeAssistantCompliantName(valueName); - - const String uniqueId = elementName.isEmpty() ? MQTT_TaskValueUniqueName(taskName, valName) - : Settings.MQTTDiscoverGroupInclTaskname() - ? strformat(F("%s_%s_%s"), elementId.c_str(), taskName.c_str(), valName.c_str()) - : strformat(F("%s_%s"), elementId.c_str(), valName.c_str()); - String message; - { - const String publish = MQTT_DiscoveryBuildValueTopic(ControllerSettings.Publish, - event, - taskValue, - componentClass, - uniqueId, - elementId, - valName); - - if (sendTrigger) { - // triggerMessage - message = strformat(F("{\"atype\":\"trigger\",\"t\":\"%s\"," - "\"p\":\"device_automation\"," - "\"type\":\"button_short_press\"," // FIXME ? - "\"stype\":\"switch_1\"" // FIXME ? - "%s}"), // deviceElement is used to pass in the TriggerState - publish.c_str(), deviceElement.c_str()); - } else { - // discoveryMessage - const String withSet = hasSet ? F(",\"cmd_t\":\"~/set\"") : EMPTY_STRING; - const String schema = hasSet ? EMPTY_STRING : "\"schema\":\"basic\","; - const String devOrIcon = hasIcon ? F("ic") : F("dev_cla"); - const String withUoM = unitOfMeasure.isEmpty() ? EMPTY_STRING : - strformat(F(",\"unit_of_meas\":\"%s\""), unitOfMeasure.c_str()); - const String stateJson = stateClass.isEmpty() ? EMPTY_STRING : - strformat(F(",\"stat_cla\":\"%s\""), stateClass.c_str()); - - message = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\",%s" - "\"%s\":\"%s\"%s%s%s,\"stat_t\":\"~\"" - "%s}"), // deviceElement last - publish.c_str(), taskName.c_str(), valName.c_str(), uniqueId.c_str(), schema.c_str(), - devOrIcon.c_str(), deviceClass.c_str(), withUoM.c_str(), stateJson.c_str(), withSet.c_str(), - deviceElement.c_str()); - } - } - - const bool retainDsc = ControllerSettings.mqtt_retainDiscovery(); - String topic; - { - const String discoveryUrl = MQTT_DiscoveryBuildValueTopic(ControllerSettings.MqttAutoDiscoveryTopic, - event, - taskValue, - componentClass, - uniqueId, - elementId, - valName); - const String discoveryConfig(parseStringKeepCase(ControllerSettings.MqttAutoDiscoveryConfig, 1, '|')); - topic = discoveryConfig.isEmpty() - ? concat(discoveryUrl, F("/config")) - : concat(discoveryUrl, discoveryConfig); - } - - return MQTT_DiscoveryPublish(ControllerIndex, - topic, - message, - event->TaskIndex, - taskValue, - retainDsc); - } - return success; -} - -String MQTT_DiscoveryHelperGetValueName(taskIndex_t taskIndex, - uint8_t taskVarIndex, - DiscoveryItem discoveryItem) { - return - # if FEATURE_STRING_VARIABLES - discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.varName : - # endif // if FEATURE_STRING_VARIABLES - getTaskValueName(taskIndex, taskVarIndex); -} - -String MQTT_DiscoveryHelperGetValueUoM(taskIndex_t taskIndex, - uint8_t taskVarIndex, - DiscoveryItem discoveryItem, - const String& defaultUoM) { - return - # if FEATURE_TASKVALUE_UNIT_OF_MEASURE - # if FEATURE_STRING_VARIABLES - discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.uom : - # endif // if FEATURE_STRING_VARIABLES - toUnitOfMeasureName(Cache.getTaskVarUnitOfMeasure(taskIndex, taskVarIndex), defaultUoM); - # else // FEATURE_TASKVALUE_UNIT_OF_MEASURE - # if FEATURE_STRING_VARIABLES - discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.uom : - # endif // if FEATURE_STRING_VARIABLES - defaultUoM; - # endif // FEATURE_TASKVALUE_UNIT_OF_MEASURE -} - # endif // if FEATURE_MQTT_DISCOVER #endif // if FEATURE_MQTT diff --git a/src/src/Helpers/_CPlugin_Helper_mqtt.h b/src/src/Helpers/_CPlugin_Helper_mqtt.h index 28ae33fc1..eaaa8804c 100644 --- a/src/src/Helpers/_CPlugin_Helper_mqtt.h +++ b/src/src/Helpers/_CPlugin_Helper_mqtt.h @@ -33,13 +33,10 @@ int Plugin_QueryVType_Lux(uint8_t value_nr); int Plugin_QueryVType_Temperature(uint8_t value_nr); int Plugin_QueryVType_Weight(uint8_t value_nr); -String makeHomeAssistantCompliantName(const String& name); - # if FEATURE_MQTT_DEVICECLASS String MQTT_binary_deviceClassName(int devClassIndex); bool MQTT_binary_deviceClassTwoWay(int devClassIndex); bool MQTT_binary_deviceClassSwitch(int devClassIndex); -int MQTT_binary_deviceClassIndex(const String& deviceClassName); # endif // if FEATURE_MQTT_DEVICECLASS # if FEATURE_MQTT_STATE_CLASS const __FlashStringHelper* MQTT_sensor_StateClass(uint8_t index, @@ -68,54 +65,11 @@ struct DiscoveryItem { bool MQTT_SendAutoDiscovery(controllerIndex_t ControllerIndex, cpluginID_t CPluginID); -bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIndex, - ControllerSettingsStruct& ControllerSettings); bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex, std::vector& discoveryItems, int valueCount, String & deviceClass); -String MQTT_TaskValueUniqueName(const String& taskName, - const String& valueName); -String MQTT_DiscoveryBuildValueTopic(const String & topic, - struct EventStruct *event, - uint8_t taskValueIndex, - const __FlashStringHelper*deviceClass, - const String & uniqueId, - const String & elementId, - const String & valueName); -bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex, - const String & topic, - const String & discoveryMessage, - taskIndex_t x, - uint8_t v, - bool retained = false); - -bool MQTT_DiscoveryPublishWithStatusAndSet(uint8_t taskValue, - const String & valueName, - controllerIndex_t ControllerIndex, - ControllerSettingsStruct& ControllerSettings, - const __FlashStringHelper*componentClass, - const String & deviceClass, - const String & unitOfMeasure, - struct EventStruct *event, - const String & deviceElement, - const String & stateClass, - bool success, - bool hasSet, - bool hasIcon, - const String & elementName, - const String & elementId, - bool sendTrigger = false); - -String MQTT_DiscoveryHelperGetValueName(taskIndex_t taskIndex, - uint8_t taskVarIndex, - DiscoveryItem discoveryItem); - -String MQTT_DiscoveryHelperGetValueUoM(taskIndex_t taskIndex, - uint8_t taskVarIndex, - DiscoveryItem discoveryItem, - const String& defaultUoM = EMPTY_STRING); # endif // if FEATURE_MQTT_DISCOVER #endif // if FEATURE_MQTT diff --git a/src/src/Static/WebStaticData.cpp b/src/src/Static/WebStaticData.cpp index 12b0a93a9..c6ad81632 100644 --- a/src/src/Static/WebStaticData.cpp +++ b/src/src/Static/WebStaticData.cpp @@ -8,7 +8,7 @@ #include "../WebServer/HTML_wrappers.h" #include "../WebServer/LoadFromFS.h" -String generate_external_URL(const String& fname, bool isEmbedded) { +static String generate_external_URL(const String& fname, bool isEmbedded) { if (isEmbedded || fileExists(fname)) { // Generate some URL indicating static files which will need to be served with some cache-control header return concat(F("static_"), Cache.fileCacheClearMoment) + '_' + fname; @@ -16,52 +16,54 @@ String generate_external_URL(const String& fname, bool isEmbedded) { #if FEATURE_ALTERNATIVE_CDN_URL String cdn = get_CDN_url_custom(); + if (!cdn.isEmpty()) { cdn = parseTemplate(cdn); // Replace system variables. return concat(cdn, fname); // cdn.endsWith('/') check done at save - } + } #endif // if FEATURE_ALTERNATIVE_CDN_URL return concat(get_CDN_url_prefix(), fname); } -void serve_CDN_CSS(const __FlashStringHelper * fname, const __FlashStringHelper * fname_alt, bool isEmbedded) { +static void serve_CDN_CSS(const __FlashStringHelper *fname, const __FlashStringHelper *fname_alt, bool isEmbedded) { const String url = generate_external_URL(fname, isEmbedded); // FIXME TD-er: For now just retry loading the same as failed loading the embedded one // may slow down next page loads until the browser finally was able to fetch the embedded one. const String url2 = generate_external_URL(fname, isEmbedded); -// const String url2 = generate_external_URL(fname_alt, !isEmbedded); + + // const String url2 = generate_external_URL(fname_alt, !isEmbedded); // Use 'onerror' to try to reload the CSS when first attempt loading failed // See: https://developer.mozilla.org/en-US/docs/Web/API/Window/error_event#element.onerror addHtml(strformat( - F(""), - url.c_str(), - url2.c_str() - )); + F(""), + url.c_str(), + url2.c_str() + )); // /* - // Delay loading CSS till after page has loaded. - // Disabled as it adds 'flickering' to the page loading - addHtml(strformat( - F(""), - url.c_str(), url.c_str() - )); - */ + // Delay loading CSS till after page has loaded. + // Disabled as it adds 'flickering' to the page loading + addHtml(strformat( + F(""), + url.c_str(), url.c_str() + )); + */ } -void serve_CDN_CSS(const __FlashStringHelper * fname, bool isEmbedded) { - serve_CDN_CSS(fname, fname, isEmbedded); -} +static void serve_CDN_CSS(const __FlashStringHelper *fname, bool isEmbedded) { serve_CDN_CSS(fname, fname, isEmbedded); } -void serve_CDN_JS(const __FlashStringHelper * fname, - const __FlashStringHelper * script_arg, - bool useDefer) { +static void serve_CDN_JS(const __FlashStringHelper *fname, + const __FlashStringHelper *script_arg, + bool useDefer) { addHtml(F("")); /* - addHtml(F("'); -*/ - #endif + addHtml(F("'); + */ + #endif // ifdef WEBSERVER_FAVICON_CDN #ifndef LIMIT_BUILD_SIZE addHtml(F("'); -/* - -*/ -#endif + /* + + */ +#endif // ifndef LIMIT_BUILD_SIZE } void serve_JS(JSfiles_e JSfile) { - const __FlashStringHelper * url = F(""); - const __FlashStringHelper * id = F(""); - bool useDefer = true; + const __FlashStringHelper *url = F(""); + const __FlashStringHelper *id = F(""); + bool useDefer = true; + #if defined(WEBSERVER_INCLUDE_JS) - bool useCDN = false; + bool useCDN = false; #endif - switch (JSfile) { + switch (JSfile) + { + case JSfiles_e::UpdateSensorValuesDevicePage: + url = F("update_sensor_values_device_page.js"); + break; + case JSfiles_e::FetchAndParseLog: + url = F("fetch_and_parse_log.js"); + break; + case JSfiles_e::SaveRulesFile: + url = F("rules_save.js"); + break; + case JSfiles_e::GitHubClipboard: + url = F("github_clipboard.js"); + break; + case JSfiles_e::Reboot: + url = F("reboot.js"); + break; + case JSfiles_e::Toasting: + url = F("toasting.js"); + break; + case JSfiles_e::SplitPasteInput: + url = F("split_paste.js"); + break; +#if FEATURE_RULES_EASY_COLOR_CODE + case JSfiles_e::EasyColorCode_codemirror: + url = F("codemirror.min.js"); + useDefer = false; + # if defined(WEBSERVER_INCLUDE_JS) + useCDN = true; + # endif + break; + case JSfiles_e::EasyColorCode_espeasy: + url = F("espeasy.min.js"); + useDefer = false; + # if defined(WEBSERVER_INCLUDE_JS) + useCDN = true; + # endif + break; + case JSfiles_e::EasyColorCode_cm_plugins: + url = F("cm-plugins.min.js"); + id = F("id='anyword'"); + useDefer = false; + # if defined(WEBSERVER_INCLUDE_JS) + useCDN = true; + # endif + break; +#endif // if FEATURE_RULES_EASY_COLOR_CODE +#ifdef USES_P113 + case JSfiles_e::P113_script: + url = F("p113_script.js"); + break; +#endif // ifdef USES_P113 +#ifdef USES_P165 + case JSfiles_e::P165_digit: + url = F("p165_digit.js"); + break; +#endif // ifdef USES_P165 + + } + + // Work-around for shortening the filename when stored on SPIFFS file system + // Files cannot be longer than 31 characters + const __FlashStringHelper *fname = + (JSfile == JSfiles_e::UpdateSensorValuesDevicePage) ? + F("upd_values_device_page.js") : url; + + if (!fileExists(fname)) + { + #if defined(WEBSERVER_INCLUDE_JS) + + if (!useCDN) { + html_add_script_arg(id, useDefer); + + switch (JSfile) + { case JSfiles_e::UpdateSensorValuesDevicePage: - url = F("update_sensor_values_device_page.js"); + # ifdef WEBSERVER_DEVICES + TXBuffer.addFlashString((PGM_P)FPSTR(DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS)); + # endif break; case JSfiles_e::FetchAndParseLog: - url = F("fetch_and_parse_log.js"); + # ifdef WEBSERVER_LOG + TXBuffer.addFlashString((PGM_P)FPSTR(DATA_FETCH_AND_PARSE_LOG_JS)); + # endif break; case JSfiles_e::SaveRulesFile: - url = F("rules_save.js"); + # ifdef WEBSERVER_RULES + TXBuffer.addFlashString((PGM_P)FPSTR(jsSaveRules)); + # endif break; case JSfiles_e::GitHubClipboard: - url = F("github_clipboard.js"); + # ifdef WEBSERVER_GITHUB_COPY + TXBuffer.addFlashString((PGM_P)FPSTR(DATA_GITHUB_CLIPBOARD_JS)); + # endif break; case JSfiles_e::Reboot: - url = F("reboot.js"); + TXBuffer.addFlashString((PGM_P)FPSTR(DATA_REBOOT_JS)); break; case JSfiles_e::Toasting: - url = F("toasting.js"); + TXBuffer.addFlashString((PGM_P)FPSTR(jsToastMessageBegin)); + + // we can push custom messages here in future releases... + addHtml(F("Submitted")); + TXBuffer.addFlashString((PGM_P)FPSTR(jsToastMessageEnd)); break; case JSfiles_e::SplitPasteInput: - url = F("split_paste.js"); + TXBuffer.addFlashString((PGM_P)FPSTR(jsSplitMultipleFields)); + + // After this, make sure to call it, like this: + // split('$', ".query-input") break; -#if FEATURE_RULES_EASY_COLOR_CODE +# if FEATURE_RULES_EASY_COLOR_CODE case JSfiles_e::EasyColorCode_codemirror: - url = F("codemirror.min.js"); - useDefer = false; - #if defined(WEBSERVER_INCLUDE_JS) - useCDN = true; - #endif - break; case JSfiles_e::EasyColorCode_espeasy: - url = F("espeasy.min.js"); - useDefer = false; - #if defined(WEBSERVER_INCLUDE_JS) - useCDN = true; - #endif - break; case JSfiles_e::EasyColorCode_cm_plugins: - url = F("cm-plugins.min.js"); - id = F("id='anyword'"); - useDefer = false; - #if defined(WEBSERVER_INCLUDE_JS) - useCDN = true; - #endif break; -#endif -#ifdef USES_P113 +# endif // if FEATURE_RULES_EASY_COLOR_CODE +# ifdef USES_P113 case JSfiles_e::P113_script: - url = F("p113_script.js"); + TXBuffer.addFlashString((PGM_P)FPSTR(p113_script)); break; -#endif // ifdef USES_P113 -#ifdef USES_P165 +# endif // ifdef USES_P113 +# ifdef USES_P165 case JSfiles_e::P165_digit: - url = F("p165_digit.js"); + TXBuffer.addFlashString((PGM_P)FPSTR(DATA_P165_DIGIT_JS)); break; -#endif // ifdef USES_P165 - - } - - // Work-around for shortening the filename when stored on SPIFFS file system - // Files cannot be longer than 31 characters - const __FlashStringHelper * fname = - (JSfile == JSfiles_e::UpdateSensorValuesDevicePage) ? - F("upd_values_device_page.js") : url; - - if (!fileExists(fname)) - { - #if defined(WEBSERVER_INCLUDE_JS) - if (!useCDN) { - html_add_script_arg(id, useDefer); - switch (JSfile) { - case JSfiles_e::UpdateSensorValuesDevicePage: - #ifdef WEBSERVER_DEVICES - TXBuffer.addFlashString((PGM_P)FPSTR(DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS)); - #endif - break; - case JSfiles_e::FetchAndParseLog: - #ifdef WEBSERVER_LOG - TXBuffer.addFlashString((PGM_P)FPSTR(DATA_FETCH_AND_PARSE_LOG_JS)); - #endif - break; - case JSfiles_e::SaveRulesFile: - #ifdef WEBSERVER_RULES - TXBuffer.addFlashString((PGM_P)FPSTR(jsSaveRules)); - #endif - break; - case JSfiles_e::GitHubClipboard: - #ifdef WEBSERVER_GITHUB_COPY - TXBuffer.addFlashString((PGM_P)FPSTR(DATA_GITHUB_CLIPBOARD_JS)); - #endif - break; - case JSfiles_e::Reboot: - TXBuffer.addFlashString((PGM_P)FPSTR(DATA_REBOOT_JS)); - break; - case JSfiles_e::Toasting: - TXBuffer.addFlashString((PGM_P)FPSTR(jsToastMessageBegin)); - // we can push custom messages here in future releases... - addHtml(F("Submitted")); - TXBuffer.addFlashString((PGM_P)FPSTR(jsToastMessageEnd)); - break; - case JSfiles_e::SplitPasteInput: - TXBuffer.addFlashString((PGM_P)FPSTR(jsSplitMultipleFields)); - // After this, make sure to call it, like this: - // split('$', ".query-input") - break; -#if FEATURE_RULES_EASY_COLOR_CODE - case JSfiles_e::EasyColorCode_codemirror: - case JSfiles_e::EasyColorCode_espeasy: - case JSfiles_e::EasyColorCode_cm_plugins: - break; -#endif -#ifdef USES_P113 - case JSfiles_e::P113_script: - TXBuffer.addFlashString((PGM_P)FPSTR(p113_script)); - break; -#endif // ifdef USES_P113 -#ifdef USES_P165 - case JSfiles_e::P165_digit: - TXBuffer.addFlashString((PGM_P)FPSTR(DATA_P165_DIGIT_JS)); - break; -#endif // ifdef USES_P165 - } - html_add_script_end(); - return; - } - #endif - serve_CDN_JS(url, id, useDefer); - } else { - serve_CDN_JS(fname, id, useDefer); +# endif // ifdef USES_P165 + } + html_add_script_end(); + return; } + #endif // if defined(WEBSERVER_INCLUDE_JS) + serve_CDN_JS(url, id, useDefer); + } else { + serve_CDN_JS(fname, id, useDefer); + } } diff --git a/src/src/Static/WebStaticData.h b/src/src/Static/WebStaticData.h index aa52e7720..c3038cdba 100644 --- a/src/src/Static/WebStaticData.h +++ b/src/src/Static/WebStaticData.h @@ -7,8 +7,6 @@ //-V::569 -String generate_external_URL(const String& fname); - void serve_favicon(); enum class JSfiles_e {