@@ -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 ;
0 commit comments