Skip to content

Commit 994ae28

Browse files
committed
Finished and tested MQTT JSON support
1 parent 948aa26 commit 994ae28

File tree

2 files changed

+50
-27
lines changed

2 files changed

+50
-27
lines changed

src/MI/ModuleInterfaceMqttTransfer.h

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -130,31 +130,46 @@ class MIMqttTransfer : public MITransferBase {
130130

131131
static void publish_to_mqtt(ModuleInterface &mi, ReconnectingMqttClient &client, bool settings,
132132
BinaryBuffer &buf, BinaryBuffer &namebuf, uint8_t transfer_ix, bool events_only) {
133-
#ifdef MIMQTT_USE_JSON
134-
DynamicJsonDocument root(MI_MAX_JSON_SIZE * 2);
135-
#endif
133+
// Scan for changes and events
136134
ModuleVariableSet &mvs = settings ? mi.settings : mi.outputs;
135+
bool some_events = false, some_changes = false;
136+
for (uint8_t i = 0; i < mvs.get_num_variables(); i++) {
137+
const ModuleVariable &v = mvs.get_module_variable(i);
138+
if (v.is_event()) some_events = true;
139+
if (v.is_changed()) some_changes = true;
140+
}
141+
if (events_only && !some_events) return;
142+
if (!some_changes) return;
143+
137144
#ifdef MIMQTT_USE_JSON
138145
// Build JSON text
139-
root["ContentType"] = "ModuleInterface";
140-
root["ModuleName"] = mi.module_name;
141-
root["ModulePrefix"] = mi.module_prefix;
142-
JsonObject o = root["Values"];
146+
DynamicJsonDocument root(MI_MAX_JSON_SIZE * 2);
147+
root["Name"] = mi.module_name;
148+
root["Prefix"] = mi.module_prefix;
149+
//if (some_events) root["Event"] = true; // Avoid this, it causes a temporary fast feedback loop
150+
JsonObject o = root.createNestedObject("Values");
143151
for (uint8_t i = 0; i < mvs.get_num_variables(); i++) {
144152
const ModuleVariable &v = mvs.get_module_variable(i);
153+
#ifdef MASTER_MULTI_TRANSFER
154+
if (v.is_initialized())
155+
#endif
145156
mv_to_json(v, o, v.name);
146157
}
147158
serializeJson(root, (char *)buf.get(), buf.length());
148159
#endif
149-
// Publish JSON packet to broker
160+
161+
// Build topic
150162
String topic = "moduleinterface/";
151163
strncpy(namebuf.chars(), mi.module_name, namebuf.length());
152164
mi_lowercase(namebuf.chars());
153165
topic += namebuf.chars();
154166
topic += (settings ? "/setting" : "/output");
167+
155168
#ifdef MIMQTT_USE_JSON
156-
client.publish(topic.c_str(), buf.chars(), true, 0);
157-
#else // Publish each variable by itself
169+
// Publish JSON packet to broker
170+
client.publish(topic.c_str(), buf.chars(), true, 1);
171+
#else
172+
// Publish each variable by itself
158173
String t, name;
159174
for (uint8_t i = 0; i < mvs.get_num_variables(); i++) {
160175
ModuleVariable &v = mvs.get_module_variable(i);
@@ -191,7 +206,7 @@ class MIMqttTransfer : public MITransferBase {
191206
uint8_t module_ix = interfaces.find_interface_by_name_ignorecase(modulename.c_str());
192207
ModuleInterface *mi = (module_ix == NO_MODULE ? NULL : interfaces[module_ix]);
193208

194-
/*
209+
/* TODO: Investigate this idea
195210
// Support a dummy ModuleInterface named "external" to receive values from
196211
if (!mi && modulename == "external") {
197212
module_ix = interfaces.find_interface_by_name_ignorecase(modulename.c_str());
@@ -214,30 +229,38 @@ class MIMqttTransfer : public MITransferBase {
214229
// Locate the correct ModuleVariableSet
215230
ModuleVariableSet *mvs = NULL;
216231
bool settings = false;
232+
#ifdef MIMQTT_USE_JSON
233+
// For topic moduleinterface/evttest/setting_event, change "setting_event" to "setting"
234+
#endif
217235
if (strcmp(category.c_str(), "setting") == 0) { mvs = &mi->settings; settings = true; }
218236
else if (strcmp(category.c_str(), "input")==0) mvs = &mi->inputs;
219237
if (!mvs) return;
220238

221239
#ifdef MIMQTT_USE_JSON
222240
// Parse JSON
223-
DynamicJsonDocument root(MI_MAX_JSON_SIZE * 2);
241+
int capacity = JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(255);
242+
DynamicJsonDocument root(capacity);
224243
DeserializationError result = deserializeJson(root, data);
225-
String contenttype = root["ContentType"];
226-
if (contenttype == "ModuleInterface") {
227-
String name = root["ModuleName"];
228-
if (name != modulename) return; // Payload meant for another module
229-
JsonObject values = root["Values"];
230-
for (auto kv : values) {
231-
String key = kv.key;
232-
bool is_event = find_and_remove_suffix(key, "_event");
233-
uint8_t varpos = mvs->get_variable_ix_ignorecase(key().c_str());
234-
if (varpos != NO_VARIABLE) {
235-
json_to_mv(mvs->get_module_variable(varpos), kv.value(), key().c_str());
236-
if (mv.changed() && is_event) mv.set_event(true);
237-
// interfaces.interfaces[mod]->inputs.get_module_variable(varpos).set_value(atoi(kv.value().as<char*>()));
238-
}
244+
String name = root["Name"]; if (!mi_compare_ignorecase(name.c_str(), modulename.c_str(), modulename.length())) return; // Payload meant for another module
245+
bool is_event = root["Event"];
246+
JsonObject values = root["Values"];
247+
for (JsonPair kv : values) {
248+
String key = kv.key().c_str();
249+
uint8_t varpos = mvs->get_variable_ix_ignorecase(key.c_str());
250+
if (varpos != NO_VARIABLE) {
251+
ModuleVariable &mv = mvs->get_module_variable(varpos), mv_new(mv);
252+
json_to_mv(mv_new, values, key.c_str());
253+
if (!settings) mv.set_changed(false); // Input only travel to modules
254+
set_mv_and_changed_flags(mv, mv_new.get_value_pointer(), mv_new.get_size(), transfer_ix);
255+
if (mv.is_changed() && is_event) mv.set_event(true); // Trigger immediate transfer to modules
256+
#ifdef MASTER_MULTI_TRANSFER
257+
mv.set_initialized();
258+
#endif
239259
}
240260
}
261+
#if defined(MASTER_MULTI_TRANSFER)
262+
if (mvs->is_initialized()) mvs->set_updated(); // All variables have been set, and one was just updated
263+
#endif
241264
#else // Read a single variable by itself
242265
// Extract variable name from topic
243266
if (!p3) return;

src/MI/ModuleVariable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ struct ModuleVariable {
6666
// (If set from a source like MQTT that transports one value at a time, this flag can be checked
6767
// to determine if a whole ModuleVariableSet has been set or if only some variables have been set.)
6868
void set_initialized() { change_bits |= (1 << 7); }
69-
bool is_initialized() { return (change_bits & (1 << 7)) != 0; }
69+
bool is_initialized() const { return (change_bits & (1 << 7)) != 0; }
7070
#endif
7171
#endif
7272

0 commit comments

Comments
 (0)