add curly braces support to mqtt integration, documentation
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
# where only the value is allowed to contain references to other variables.
|
||||
# A reference to a variable is escaped by a leading "%" character in front of the variable name consisting of only
|
||||
# alphabetic characters or the underscore. A double percent character "%%" is replaced by a single "%" in the value.
|
||||
# Curly braces may be used to separate a variable explicitly from the rest, e.g. as "%{version}" instead of "%version".
|
||||
# Every variable without an underscore in the name is automatically made available as well with an uppercase name and a
|
||||
# normalized value composed of only alphanumeric characters or underscore (i.e. suitable for being part of a topic).
|
||||
# When using "?=" instead of only the equal sign in a variable definition, the variable value is set to empty when one
|
||||
@@ -93,12 +94,10 @@ filter-direction = r|u
|
||||
#filter-field =
|
||||
|
||||
|
||||
|
||||
# the field type mapped from variables named "type_map-%direction-%type" or "type_map-%type" as fallback with the
|
||||
# field type and the optional direction in the suffix. The variable including the direction is evaluated first and
|
||||
# if it is missing or the result is empty, the variable excluding the direction is used instead.
|
||||
# This is also an implicit field type filter as missing or empty mappings are not published at all.
|
||||
|
||||
type_map-number = number
|
||||
type_map-list = string
|
||||
type_map-string = string
|
||||
@@ -107,6 +106,30 @@ type_map-time = string
|
||||
type_map-datetime = string
|
||||
|
||||
|
||||
# field type switch designator, see below.
|
||||
#type_switch-by = %name%field,%unit
|
||||
|
||||
# field type switch variables names to use in addition to %type_switch in case of multiple keys (separated by comma).
|
||||
#type_switch-names = type_topic,type_class,type_state
|
||||
|
||||
# field type switch for each field type and optionally direction (between dash before the field type) available as
|
||||
# %type_switch (as well as the variable names defined in "type_switch-names" if any).
|
||||
# The value needs to be a constant list of string pairs with one pair per line. Each pair is separated by "=" and the
|
||||
# left part is the value set to the type_switch variable (as well as the variable names defined in %type_switch-names)
|
||||
# when the wildcard string in the right part matched the "type_switch-by" value. The list is traversed from top to
|
||||
# bottom stopping at the first match. If direction specific definitions exist, these are traversed first. If no line
|
||||
# matches at all, the variable(s) are set to the empty string.
|
||||
#type_switch-w-number =
|
||||
|
||||
|
||||
# field type part suffix to use instead of the field type itself, see below.
|
||||
#type_part-by = %type_topic
|
||||
|
||||
# field type part mappings for each field type (or the "type_part-by" variable value) in the suffix (available as
|
||||
# %type_part).
|
||||
#type_part-number = ,
|
||||
|
||||
|
||||
# the message definition config topic, payload, and retain setting.
|
||||
definition-topic = %prefixn/config/%CIRCUIT/%NAME/%FIELD
|
||||
definition-payload = {
|
||||
|
||||
+36
-19
@@ -338,7 +338,7 @@ static const char* knownFieldNames[] = {
|
||||
/** the number of known field names. */
|
||||
static const size_t knownFieldCount = sizeof(knownFieldNames) / sizeof(char*);
|
||||
|
||||
std::pair<string, int> makeField(const string name, bool isField) {
|
||||
std::pair<string, int> makeField(const string& name, bool isField) {
|
||||
if (!isField) {
|
||||
return {name, -1};
|
||||
}
|
||||
@@ -350,38 +350,55 @@ std::pair<string, int> makeField(const string name, bool isField) {
|
||||
return {name, knownFieldCount};
|
||||
}
|
||||
|
||||
void addPart(ostringstream& stack, int inField, vector<std::pair<string, int>>& parts) {
|
||||
string str = stack.str();
|
||||
if (inField == 1 && str == "_") {
|
||||
inField = 0; // single "%_" pattern to reduce to "_"
|
||||
} else if (inField == 2) {
|
||||
str = "%{" + str;
|
||||
inField = 0;
|
||||
}
|
||||
if (inField == 0 && str.empty()) {
|
||||
return;
|
||||
}
|
||||
stack.str("");
|
||||
if (inField == 0 && !parts.empty() && parts[parts.size()-1].second < 0) {
|
||||
// append constant to previous constant
|
||||
parts[parts.size()-1].first += str;
|
||||
return;
|
||||
}
|
||||
parts.push_back(makeField(str, inField>0));
|
||||
}
|
||||
|
||||
bool MqttReplacer::parse(const string& templateStr, bool onlyKnown, bool noKnownDuplicates, bool emptyIfMissing) {
|
||||
m_parts.clear();
|
||||
size_t end = templateStr.length();
|
||||
bool inField = false;
|
||||
int inField = 0; // 1 after '%', 2 after '%{'
|
||||
ostringstream stack;
|
||||
for (size_t pos = 0; pos < end+1; pos++) {
|
||||
char ch = pos<end ? templateStr[pos] : '\0';
|
||||
for (auto ch : templateStr) {
|
||||
bool empty = stack.tellp()<=0;
|
||||
if (ch=='%' || ch=='\0') {
|
||||
if (inField && empty) { // %% for plain %
|
||||
inField = false;
|
||||
if (ch=='%') {
|
||||
if (inField==1 && empty) { // %% for plain %
|
||||
inField = 0;
|
||||
stack << ch;
|
||||
} else {
|
||||
if (!empty) {
|
||||
m_parts.push_back(makeField(stack.str(), inField));
|
||||
stack.str("");
|
||||
}
|
||||
inField = true;
|
||||
addPart(stack, inField, m_parts);
|
||||
inField = 1;
|
||||
}
|
||||
} else if (ch=='{' && inField==1 && empty) {
|
||||
inField = 2;
|
||||
} else if (ch=='}' && inField==2) {
|
||||
addPart(stack, 1, m_parts);
|
||||
inField = 0;
|
||||
} else {
|
||||
if (inField && !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')) {
|
||||
if (inField>0 && !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_')) {
|
||||
// invalid field character
|
||||
if (stack.tellp()>0) {
|
||||
m_parts.push_back(makeField(stack.str(), true));
|
||||
stack.str("");
|
||||
}
|
||||
inField = false;
|
||||
addPart(stack, inField, m_parts);
|
||||
inField = 0;
|
||||
}
|
||||
stack << ch;
|
||||
}
|
||||
}
|
||||
addPart(stack, inField, m_parts);
|
||||
if (onlyKnown || noKnownDuplicates) {
|
||||
int foundMask = 0;
|
||||
int knownCount = knownFieldCount;
|
||||
|
||||
Reference in New Issue
Block a user