Files
ESPEasy/src/_C005.cpp
T

207 lines
6.0 KiB
C++

#include "src/Helpers/_CPlugin_Helper.h"
#ifdef USES_C005
# include "src/Commands/InternalCommands.h"
# include "src/Globals/EventQueue.h"
# include "src/Helpers/_CPlugin_Helper_mqtt.h"
# include "src/Helpers/PeriodicalActions.h"
# include "src/Helpers/StringParser.h"
# include "_Plugin_Helper.h"
// #######################################################################################################
// ################### Controller Plugin 005: Home Assistant (openHAB) MQTT ##############################
// #######################################################################################################
/** Changelog:
* 2023-08-18 tonhuisman: Clean up source for pull request
* 2023-03-15 tonhuisman: Add processing of topic endpoint /set to issue a TaskValueSet,taskname,taskvalue,payload command for
* topic %sysname%/#/taskname/valuename/set
* Move /cmd and /set handling to helper file for generic MQTT use
* Reformatted source using Uncrustify
* 2023-03 Changelog started
*/
# define CPLUGIN_005
# define CPLUGIN_ID_005 5
# define CPLUGIN_NAME_005 "Home Assistant (openHAB) MQTT"
String CPlugin_005_pubname;
bool CPlugin_005_mqtt_retainFlag = false;
bool C005_parse_command(struct EventStruct *event);
bool CPlugin_005(CPlugin::Function function, struct EventStruct *event, String& string)
{
bool success = false;
switch (function)
{
case CPlugin::Function::CPLUGIN_PROTOCOL_ADD:
{
ProtocolStruct& proto = getProtocolStruct(event->idx); // = CPLUGIN_ID_005;
proto.usesMQTT = true;
proto.usesTemplate = true;
proto.usesAccount = true;
proto.usesPassword = true;
proto.usesExtCreds = true;
proto.defaultPort = 1883;
proto.usesID = false;
break;
}
case CPlugin::Function::CPLUGIN_GET_DEVICENAME:
{
string = F(CPLUGIN_NAME_005);
break;
}
case CPlugin::Function::CPLUGIN_INIT:
{
success = init_mqtt_delay_queue(event->ControllerIndex, CPlugin_005_pubname, CPlugin_005_mqtt_retainFlag);
break;
}
case CPlugin::Function::CPLUGIN_EXIT:
{
exit_mqtt_delay_queue();
break;
}
case CPlugin::Function::CPLUGIN_PROTOCOL_TEMPLATE:
{
event->String1 = F("%sysname%/#");
event->String2 = F("%sysname%/%tskname%/%valname%");
break;
}
case CPlugin::Function::CPLUGIN_PROTOCOL_RECV:
{
controllerIndex_t ControllerID = findFirstEnabledControllerWithId(CPLUGIN_ID_005);
if (validControllerIndex(ControllerID)) {
C005_parse_command(event);
}
break;
}
case CPlugin::Function::CPLUGIN_PROTOCOL_SEND:
{
if (MQTT_queueFull(event->ControllerIndex)) {
break;
}
// String pubname = CPlugin_005_pubname;
success = MQTT_protocol_send(event, CPlugin_005_pubname, CPlugin_005_mqtt_retainFlag);
break;
}
case CPlugin::Function::CPLUGIN_FLUSH:
{
processMQTTdelayQueue();
delay(0);
break;
}
default:
break;
}
return success;
}
bool C005_parse_command(struct EventStruct *event) {
// FIXME TD-er: Command is not parsed for template arguments.
// Topic : event->String1
// Message: event->String2
bool validTopic = MQTT_handle_topic_commands(event); // default handling of /cmd and /set topics
if (!validTopic) {
String cmd;
const int lastindex = event->String1.lastIndexOf('/');
const String lastPartTopic = event->String1.substring(lastindex + 1);
const bool has_cmd_arg_index = event->String1.lastIndexOf(F("cmd_arg")) != -1;
if (has_cmd_arg_index) {
// Example:
// Topic: ESP_Easy/Bathroom_pir_env/cmd_arg1/GPIO/0
// Message: 14
// Full command: gpio,14,0
uint8_t topic_index = 1;
String topic_folder = parseStringKeepCase(event->String1, topic_index, '/');
while (!topic_folder.startsWith(F("cmd_arg")) && !topic_folder.isEmpty()) {
++topic_index;
topic_folder = parseStringKeepCase(event->String1, topic_index, '/');
}
if (!topic_folder.isEmpty()) {
int cmd_arg_nr = -1;
if (validIntFromString(topic_folder.substring(7), cmd_arg_nr)) {
int constructed_cmd_arg_nr = 0;
++topic_index;
topic_folder = parseStringKeepCase(event->String1, topic_index, '/');
bool msg_added = false;
while (!topic_folder.isEmpty()) {
if (constructed_cmd_arg_nr != 0) {
cmd += ',';
}
if (constructed_cmd_arg_nr == cmd_arg_nr) {
cmd += event->String2;
msg_added = true;
} else {
cmd += topic_folder;
++topic_index;
topic_folder = parseStringKeepCase(event->String1, topic_index, '/');
}
++constructed_cmd_arg_nr;
}
if (!msg_added) {
cmd += ',';
cmd += event->String2;
}
// addLog(LOG_LEVEL_INFO, String(F("MQTT cmd: ")) + cmd);
validTopic = true;
}
}
} else {
// Example:
// Topic: ESP_Easy/Bathroom_pir_env/GPIO/14
// Message: 0 or 1
// Full command: gpio,14,0
if (lastindex > 0) {
// Topic has at least one separator
int lastPartTopic_int;
float value_f;
if (validFloatFromString(event->String2, value_f) &&
validIntFromString(lastPartTopic, lastPartTopic_int)) {
const int prevLastindex = event->String1.lastIndexOf('/', lastindex - 1);
cmd = event->String1.substring(prevLastindex + 1, lastindex);
cmd += ',';
cmd += lastPartTopic_int;
cmd += ',';
cmd += event->String2; // Just use the original format
validTopic = true;
}
}
}
if (validTopic) {
MQTT_execute_command(cmd);
}
}
return validTopic;
}
#endif // ifdef USES_C005