Adafruit Library
ws_networking_pico.h
Go to the documentation of this file.
1 
17 #ifndef WS_NETWORKING_PICO_H
18 #define WS_NETWORKING_PICO_H
19 
20 #ifdef ARDUINO_ARCH_RP2040
21 
22 #define PICO_CONNECT_TIMEOUT_MS 20000
23 #define PICO_CONNECT_RETRY_DELAY_MS 200
25 #include "Wippersnapper.h"
26 
27 #include "Adafruit_MQTT.h"
28 #include "Adafruit_MQTT_Client.h"
29 #include "Arduino.h"
30 #include <WiFiClient.h>
31 #include <WiFiClientSecure.h>
32 
33 class ws_networking_pico;
34 extern ws_networking_pico WS;
35 /****************************************************************************/
39 /****************************************************************************/
40 class ws_networking_pico : public Wippersnapper {
41 
42 public:
43  /**************************************************************************/
47  /**************************************************************************/
48  ws_networking_pico() : Wippersnapper() {
49  _ssid = 0;
50  _pass = 0;
51  }
52 
53  /**************************************************************************/
57  /**************************************************************************/
58  ~ws_networking_pico() {
59  if (_mqtt_client_secure)
60  delete _mqtt_client_secure;
61  if (_mqtt_client_secure)
62  delete _mqtt_client_secure;
63  }
64 
65  /********************************************************/
73  /********************************************************/
74  void set_ssid_pass(const char *ssid, const char *ssidPassword) {
75  _ssid = ssid;
76 
77  // set the AP password
78  // check if ssidPassword was "" in secrets.json
79  if ((ssidPassword != NULL) && (strlen(ssidPassword) == 0)) {
80  _pass = NULL; // Set as NULL for open networks
81  } else {
82  _pass = ssidPassword;
83  }
84  }
85 
86  /**********************************************************/
90  /**********************************************************/
91  void set_ssid_pass() {
92  _ssid = WS._config.network.ssid;
93  _pass = WS._config.network.pass;
94  }
95 
96  /***********************************************************/
101  /***********************************************************/
102  bool check_valid_ssid() {
103  // Set WiFi to station mode and disconnect from an AP if it was previously
104  // connected
105  WiFi.mode(WIFI_STA);
106  WiFi.disconnect();
107  delay(100);
108 
109  // Perform a network scan
110  int n = WiFi.scanNetworks();
111  if (n == 0) {
112  WS_DEBUG_PRINTLN("ERROR: No WiFi networks found!");
113  return false;
114  }
115 
116  bool foundNetwork = false;
117 
118  WS_DEBUG_PRINTLN("WipperSnapper found these WiFi networks:");
119  for (uint8_t i = 0; i < n; i++) {
120  if (!foundNetwork && strcmp(WiFi.SSID(i), _ssid) == 0) {
121  foundNetwork = true;
122  } else if (!foundNetwork && WS._isWiFiMulti) {
123  // multi network mode
124  for (int j = 0; j < WS_MAX_ALT_WIFI_NETWORKS; j++) {
125  if (strcmp(WS._multiNetworks[j].ssid, WiFi.SSID(i)) == 0) {
126  foundNetwork = true;
127  }
128  }
129  }
130  WS_DEBUG_PRINT(WiFi.SSID(i));
131  WS_DEBUG_PRINT(" (");
132  uint8_t BSSID[WL_MAC_ADDR_LENGTH];
133  WiFi.BSSID(i, BSSID);
134  for (int m = 0; m < WL_MAC_ADDR_LENGTH; m++) {
135  if (m != 0)
136  WS_DEBUG_PRINT(":");
137  WS_DEBUG_PRINTHEX(BSSID[m]);
138  }
139  WS_DEBUG_PRINT(") ");
140  WS_DEBUG_PRINT(WiFi.RSSI(i));
141  WS_DEBUG_PRINT("dB (ch");
142  WS_DEBUG_PRINT(WiFi.channel(i))
143  WS_DEBUG_PRINTLN(")");
144  }
145 
146  if (!foundNetwork) {
147  WS_DEBUG_PRINTLN("ERROR: Your requested WiFi network was not found!");
148  }
149  return foundNetwork;
150  }
151 
152  /********************************************************/
157  /********************************************************/
158  void getMacAddr() {
159  uint8_t mac[6] = {0};
160  WiFi.macAddress(mac);
161  memcpy(WS._macAddr, mac, sizeof(mac));
162  }
163 
164  /********************************************************/
169  /********************************************************/
170  int32_t getRSSI() { return WiFi.RSSI(); }
171 
172  /********************************************************/
178  /********************************************************/
179  void setupMQTTClient(const char *clientID) {
180  if (strcmp(WS._config.aio_url, "io.adafruit.com") == 0 ||
181  strcmp(WS._config.aio_url, "io.adafruit.us") == 0) {
182  _mqtt_client_secure = new WiFiClientSecure();
183  _mqtt_client_secure->setCACert(
184  strcmp(WS._config.aio_url, "io.adafruit.com") == 0
185  ? _aio_root_ca_prod
186  : _aio_root_ca_staging);
187  WS._mqtt = new Adafruit_MQTT_Client(
188  _mqtt_client_secure, WS._config.aio_url, WS._config.io_port, clientID,
189  WS._config.aio_user, WS._config.aio_key);
190  } else {
191  _mqtt_client_insecure = new WiFiClient();
192  WS._mqtt = new Adafruit_MQTT_Client(
193  _mqtt_client_insecure, WS._config.aio_url, WS._config.io_port,
194  clientID, WS._config.aio_user, WS._config.aio_key);
195  }
196  }
197 
198  /********************************************************/
203  /********************************************************/
205  switch (WiFi.status()) {
206  case WL_CONNECTED:
207  return WS_NET_CONNECTED;
208  case WL_CONNECT_FAILED:
209  return WS_NET_CONNECT_FAILED;
210  case WL_IDLE_STATUS:
211  return WS_IDLE;
212  default:
213  return WS_NET_DISCONNECTED;
214  }
215  }
216 
217  /*******************************************************************/
222  /*******************************************************************/
223  const char *connectionType() { return "Pico"; }
224 
225 protected:
226  const char *_ssid;
227  const char *_pass;
228  WiFiClient
229  *_mqtt_client_insecure;
230  WiFiClientSecure
231  *_mqtt_client_secure;
232  WiFiMulti _wifiMulti;
233 
234  const char *_aio_root_ca_staging =
235  "-----BEGIN CERTIFICATE-----\n"
236  "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
237  "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n"
238  "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n"
239  "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n"
240  "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n"
241  "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n"
242  "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n"
243  "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n"
244  "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n"
245  "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n"
246  "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n"
247  "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n"
248  "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n"
249  "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n"
250  "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n"
251  "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n"
252  "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n"
253  "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n"
254  "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n"
255  "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n"
256  "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n"
257  "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n"
258  "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n"
259  "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n"
260  "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n"
261  "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n"
262  "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n"
263  "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n"
264  "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n"
265  "-----END CERTIFICATE-----\n";
266 
267  const char *_aio_root_ca_prod =
268  "-----BEGIN CERTIFICATE-----\n"
269  "MIIEjTCCA3WgAwIBAgIQDQd4KhM/xvmlcpbhMf/ReTANBgkqhkiG9w0BAQsFADBh\n"
270  "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
271  "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n"
272  "MjAeFw0xNzExMDIxMjIzMzdaFw0yNzExMDIxMjIzMzdaMGAxCzAJBgNVBAYTAlVT\n"
273  "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
274  "b20xHzAdBgNVBAMTFkdlb1RydXN0IFRMUyBSU0EgQ0EgRzEwggEiMA0GCSqGSIb3\n"
275  "DQEBAQUAA4IBDwAwggEKAoIBAQC+F+jsvikKy/65LWEx/TMkCDIuWegh1Ngwvm4Q\n"
276  "yISgP7oU5d79eoySG3vOhC3w/3jEMuipoH1fBtp7m0tTpsYbAhch4XA7rfuD6whU\n"
277  "gajeErLVxoiWMPkC/DnUvbgi74BJmdBiuGHQSd7LwsuXpTEGG9fYXcbTVN5SATYq\n"
278  "DfbexbYxTMwVJWoVb6lrBEgM3gBBqiiAiy800xu1Nq07JdCIQkBsNpFtZbIZhsDS\n"
279  "fzlGWP4wEmBQ3O67c+ZXkFr2DcrXBEtHam80Gp2SNhou2U5U7UesDL/xgLK6/0d7\n"
280  "6TnEVMSUVJkZ8VeZr+IUIlvoLrtjLbqugb0T3OYXW+CQU0kBAgMBAAGjggFAMIIB\n"
281  "PDAdBgNVHQ4EFgQUlE/UXYvkpOKmgP792PkA76O+AlcwHwYDVR0jBBgwFoAUTiJU\n"
282  "IBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG\n"
283  "AQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEB\n"
284  "BCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGA1Ud\n"
285  "HwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEds\n"
286  "b2JhbFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEW\n"
287  "HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEB\n"
288  "AIIcBDqC6cWpyGUSXAjjAcYwsK4iiGF7KweG97i1RJz1kwZhRoo6orU1JtBYnjzB\n"
289  "c4+/sXmnHJk3mlPyL1xuIAt9sMeC7+vreRIF5wFBC0MCN5sbHwhNN1JzKbifNeP5\n"
290  "ozpZdQFmkCo+neBiKR6HqIA+LMTMCMMuv2khGGuPHmtDze4GmEGZtYLyF8EQpa5Y\n"
291  "jPuV6k2Cr/N3XxFpT3hRpt/3usU/Zb9wfKPtWpoznZ4/44c1p9rzFcZYrWkj3A+7\n"
292  "TNBJE0GmP2fhXhP1D/XVfIW/h0yCJGEiV9Glm/uGOa3DXHlmbAcxSyCRraG+ZBkA\n"
293  "7h4SeM6Y8l/7MBRpPCz6l8Y=\n"
294  "-----END CERTIFICATE-----\n";
295 
296  /**************************************************************************/
300  /**************************************************************************/
301  void _connect() {
302 
303  if (WiFi.status() == WL_CONNECTED)
304  return;
305 
306  WiFi.mode(WIFI_STA);
307  WS.feedWDT();
308  WiFi.setTimeout(20000);
309  WS.feedWDT();
310 
311  if (strlen(_ssid) == 0) {
312  _status = WS_SSID_INVALID;
313  } else {
314  _disconnect();
315  delay(5000);
316  WS.feedWDT();
317  if (WS._isWiFiMulti) {
318  // multi network mode
319  _wifiMulti.clearAPList();
320  // add default network
321  _wifiMulti.addAP(_ssid, _pass);
322  // add array of alternative networks
323  for (int i = 0; i < WS_MAX_ALT_WIFI_NETWORKS; i++) {
324  _wifiMulti.addAP(WS._multiNetworks[i].ssid,
325  WS._multiNetworks[i].pass);
326  }
327  WS.feedWDT();
328  if (_wifiMulti.run(20000) == WL_CONNECTED) {
329  WS.feedWDT();
330  _status = WS_NET_CONNECTED;
331  return;
332  }
333  WS.feedWDT();
334  } else {
335  WiFi.begin(_ssid, _pass);
336 
337  // Use the macro to retry the status check until connected / timed out
338  int lastResult;
340  []() -> int { return WiFi.status(); }, // Function call each cycle
341  int, // return type
342  lastResult, // return variable (unused here)
343  [](int status) { return status == WL_CONNECTED; }, // check
344  PICO_CONNECT_TIMEOUT_MS, // timeout interval (ms)
345  PICO_CONNECT_RETRY_DELAY_MS); // interval between retries
346 
347  if (lastResult == WL_CONNECTED) {
348  _status = WS_NET_CONNECTED;
349  // wait 2seconds for connection to stabilize
350  WS_DELAY_WITH_WDT(2000);
351  return;
352  }
353  }
354  _status = WS_NET_DISCONNECTED;
355  }
356  }
357 
358  /**************************************************************************/
362  /**************************************************************************/
363  void _disconnect() {
364  WS.feedWDT();
365  WiFi.disconnect();
366  delay(5000);
367  WS.feedWDT();
368  }
369 };
370 
371 #endif // ARDUINO_ARCH_RP2040
372 #endif // WS_NETWORKING_PICO_H
virtual void setupMQTTClient(const char *clientID)
Sets up the MQTT client session.
Definition: Wippersnapper.cpp:187
#define RETRY_FUNCTION_UNTIL_TIMEOUT(func, result_type, result_var, condition, timeout, interval,...)
Retry a function until a condition is met or a timeout is reached.
Definition: Wippersnapper.h:140
#define WS_DEBUG_PRINT(...)
Prints debug output.
Definition: Wippersnapper.h:63
#define WS_DEBUG_PRINTHEX(...)
Prints in hexadecimal.
Definition: Wippersnapper.h:78
secretsConfig _config
Definition: Wippersnapper.h:432
#define WL_MAC_ADDR_LENGTH
MAC address length - from RP2040 BSP.
Definition: Wippersnapper_Networking.h:20
ws_status_t
Definition: Wippersnapper.h:219
virtual bool check_valid_ssid()
Performs a scan of local WiFi networks.
Definition: Wippersnapper.cpp:232
Class that provides storage and functions for the Adafruit IO Wippersnapper interface.
Definition: Wippersnapper.h:311
virtual void _connect()
Connects to wireless network.
Definition: Wippersnapper.cpp:146
#define WS_MAX_ALT_WIFI_NETWORKS
Maximum number of alternative networks.
Definition: Wippersnapper.h:280
virtual void getMacAddr()
Sets the network interface&#39;s unique identifier, typically the MAC address.
Definition: Wippersnapper.cpp:165
virtual void set_ssid_pass()
Sets the device&#39;s wireless network credentials from the secrets.json configuration file...
Definition: Wippersnapper.cpp:222
void feedWDT()
Feeds the WDT to prevent hardware reset.
Definition: Wippersnapper.cpp:2645
bool _isWiFiMulti
Definition: Wippersnapper.h:434
networkConfig _multiNetworks[3]
Definition: Wippersnapper.h:433
#define WS_DEBUG_PRINTLN(...)
Prints line from debug output.
Definition: Wippersnapper.h:66
#define WS_DELAY_WITH_WDT(timeout)
Delay function.
Definition: Wippersnapper.h:97
Wippersnapper_AIRLIFT WS
Global instance of Wippersnapper_WiFi.
Definition: Wippersnapper.cpp:38
uint8_t _macAddr[6]
Definition: Wippersnapper.h:426
Adafruit_MQTT * _mqtt
Definition: Wippersnapper.h:430
virtual ws_status_t networkStatus()
Returns the network&#39;s connection status.
Definition: Wippersnapper.cpp:197
virtual int32_t getRSSI()
Gets the network&#39;s RSSI.
Definition: Wippersnapper.cpp:175
virtual void _disconnect()
Disconnect Wippersnapper MQTT session and network.
Definition: Wippersnapper.cpp:155