@@ -28,19 +28,98 @@ class PJONMIMqttTransfer : public MIMqttTransfer {
28
28
// Whether to read master settings from MQTT or not
29
29
void set_read_master_settings (bool read) { read_master_settings = read; }
30
30
31
+ virtual void start () {
32
+ // When starting based on master settings from MQTT, we are doing it in 3 phases:
33
+ // 1. Get master settings, create ModuleInterface objects based on module list.
34
+ // 2. Get contracts from all modules.
35
+ // 3. Reconnect to MQTT now subscribing to all settings and inputs, so that
36
+ // these will be registered in objects and synced to modules.
37
+
38
+ // If we have all master settings then start normally (phase 3)
39
+ if (!read_master_settings || (got_settings () && got_contracts ())) {
40
+ phase = PHASE_RUNNING;
41
+ MIMqttTransfer::start ();
42
+ }
43
+ else {
44
+ // Subscribe to master settings only (phase 1)
45
+ phase = PHASE_WAIT_MQTT;
46
+ #if defined(DEBUG_PRINT) || defined(DEBUG_PRINT_SETTINGUPDATE_MQTT)
47
+ printf (" %%%%%%%%%%%% PHASE_WAIT_MQTT starting at %dms.\n " , millis ());
48
+ #endif
49
+ String master_topic = " moduleinterface/master_" ; master_topic += interfaces.get_prefix ();
50
+ #ifdef MIMQTT_USE_JSON
51
+ master_topic += " /setting" ;
52
+ #else
53
+ master_topic += " /setting/+" ;
54
+ #endif
55
+ #if defined(DEBUG_PRINT) || defined(DEBUG_PRINT_SETTINGUPDATE_MQTT)
56
+ printf (" Subscribing to topic '%s'\n " , master_topic.c_str ());
57
+ #endif
58
+ client.subscribe (master_topic.c_str (), 1 );
59
+ client.start ();
60
+ }
61
+ }
62
+
31
63
private:
64
+ // Flags used in got_master_settings member
65
+ const uint8_t SETTING_MODULE_LIST = 1 , SETTING_DEVID = 2 , SETTING_INTERVAL = 4 , SETTING_ALL = 7 ;
66
+
67
+ // Startup phases
68
+ enum Phase { PHASE_STOPPED, PHASE_WAIT_MQTT, PHASE_WAIT_CONTRACTS, PHASE_RUNNING };
69
+
32
70
bool read_master_settings = false ;
71
+ uint8_t got_master_settings = 0 ; // Bitmasked,
72
+ enum Phase phase = PHASE_STOPPED;
73
+ long contract_retrieval_start = 0 ;
74
+
75
+ bool got_settings () const { return (got_master_settings & SETTING_ALL) == SETTING_ALL; }
76
+ bool got_contracts () const {
77
+ return interfaces.got_all_contracts ()
78
+ && ((interfaces.get_inactive_module_count () == 0 )
79
+ || (uint32_t (millis () - contract_retrieval_start) > MI_INACTIVE_TIME_THRESHOLD*1000l ));
80
+ }
33
81
34
- virtual void read_nonmodule_topic (const char *modulename,
35
- const char *category,
36
- const char *topic,
37
- const char *data,
38
- uint16_t len,
39
- uint8_t transfer_ix)
82
+ virtual void update () {
83
+ MIMqttTransfer::update ();
84
+ check_phase ();
85
+ if (read_master_settings) debug_print_missing_settings ();
86
+ }
87
+
88
+ void check_phase () {
89
+ // Check if we are ready to transition to a new connection phase
90
+ switch (phase) {
91
+ case PHASE_STOPPED: break ;
92
+ case PHASE_WAIT_MQTT:
93
+ if (got_settings ()) {
94
+ phase = PHASE_WAIT_CONTRACTS;
95
+ contract_retrieval_start = millis ();
96
+ #if defined(DEBUG_PRINT) || defined(DEBUG_PRINT_SETTINGUPDATE_MQTT)
97
+ printf (" %%%%%%%%%%%% PHASE_WAIT_CONTRACTS starting at %dms. Got all master settings.\n " , millis ());
98
+ #endif
99
+ }
100
+ break ;
101
+ case PHASE_WAIT_CONTRACTS:
102
+ if (got_contracts ()) {
103
+ // Reconnect to MQTT broker wil full subscription, not only master settings
104
+ #if defined(DEBUG_PRINT) || defined(DEBUG_PRINT_SETTINGUPDATE_MQTT)
105
+ printf (" %%%%%%%%%%%% PHASE_RUNNING starting at %dms. Got %d (%d inactive) modules.\n " , millis (), interfaces.get_module_count (), interfaces.get_inactive_module_count ());
106
+ #endif
107
+ phase = PHASE_RUNNING;
108
+ stop ();
109
+ start ();
110
+ }
111
+ break ;
112
+ case PHASE_RUNNING: break ;
113
+ }
114
+ }
115
+
116
+ virtual void read_master_topic (const char *modulename,
117
+ const char *category,
118
+ const char *topic,
119
+ const char *data,
120
+ uint16_t len,
121
+ uint8_t transfer_ix)
40
122
{
41
- printf (" Starting on read_nonmodule_topic '%s'\n " , topic);
42
- if (strncmp (topic, " moduleinterface/master_m1/setting/modules" , 33 ) == 0 ) printf (" ------> Modules: '%s'\n " , data);
43
- printf (" %d Category: %s\n " , read_master_settings, category);
44
123
if (!read_master_settings) return ;
45
124
bool for_me = false ;
46
125
{
@@ -50,32 +129,42 @@ printf("%d Category: %s\n", read_master_settings, category);
50
129
if (for_me && strcmp (category, " setting" )==0 ) {
51
130
// A setting for this master
52
131
#ifdef MIMQTT_USE_JSON
53
- read_master_json_settings_from_buffer (interfaces, data, len);
132
+ bool ok = read_master_json_settings_from_buffer ((PJONModuleInterfaceSet&) interfaces, data, len);
133
+ got_master_settings = ok ? SETTING_ALL : 0 ;
134
+ // Check if module list was changed and objects recreated
135
+ bool all_empty = true ;
136
+ for (uint8_t m = 0 ; m < interfaces.get_module_count (); m++) {
137
+ if (interfaces[m]->settings .get_num_variables () > 0 || interfaces[m]->outputs .get_num_variables () > 0 ) {
138
+ all_empty = false ; break ;
139
+ }
140
+ }
141
+ if (all_empty) phase = PHASE_WAIT_MQTT; // Trigger exchange of contracts followed by reconnect to get all settings
54
142
#else
55
143
if (strstr (topic, " /modules" )>0 ) {
56
- if (((PJONModuleInterfaceSet&)interfaces).set_interface_list (data)) {
57
- // The module list changed. Reconnect to get all settings from MQTT to new module objects.
58
- printf (" --> GOT NEW MODULE LIST. Reconnecting to get settings.\n " );
59
- #ifdef DEBUG_PRINT
60
- DPRINTLN (" --> GOT NEW MODULE LIST. Reconnecting to get settings." );
144
+ if (((PJONModuleInterfaceSet&)interfaces).set_interface_list (data)) {
145
+ // The module list changed. Reconnect to get all settings from MQTT to new module objects.
146
+ got_master_settings |= SETTING_MODULE_LIST;
147
+ phase = PHASE_WAIT_MQTT;
148
+ #if defined(DEBUG_PRINT) || defined(DEBUG_PRINT_SETTINGUPDATE_MQTT)
149
+ if (phase != PHASE_WAIT_MQTT) DPRINTLN (" --> GOT NEW MODULE LIST. Changing to PHASE_WAIT_MQTT." );
61
150
#endif
62
- stop ();
63
- start ();
64
- }
65
- #ifdef DEBUG_PRINT
151
+ }
152
+ #if defined(DEBUG_PRINT) || defined(DEBUG_PRINT_SETTINGUPDATE_MQTT)
66
153
DPRINT (" Modules: '" ); DPRINT (data); DPRINTLN (" '" );
67
154
#endif
68
155
} else if (strstr (topic, " /devid" )>0 ) {
69
156
// Set PJON id for master
157
+ got_master_settings |= SETTING_DEVID;
70
158
uint8_t device_id = (uint8_t ) atoi (data);
71
159
if (device_id != 0 ) ((PJONModuleInterfaceSet&)interfaces).get_link ()->set_id (device_id);
72
160
} else if (strstr (topic, " /intsettings" )>0 ) {
73
161
// Set time interval between exchanges
162
+ got_master_settings |= SETTING_INTERVAL;
74
163
uint32_t interval = atoi (data);
75
164
if (interval > 100 ) ((PJONModuleInterfaceSet&)interfaces).set_transfer_interval (interval);
76
165
}
77
166
#endif
167
+ check_phase ();
78
168
}
79
- printf (" Finished with read_nonmodule_topic" );
80
169
}
81
170
};
0 commit comments