ESPHome  2024.6.1
wifi_component.h
Go to the documentation of this file.
1 #pragma once
2 
6 #include "esphome/core/defines.h"
7 #include "esphome/core/helpers.h"
8 
9 #include <string>
10 #include <vector>
11 
12 #ifdef USE_ESP32_FRAMEWORK_ARDUINO
13 #include <WiFi.h>
14 #include <WiFiType.h>
15 #include <esp_wifi.h>
16 #endif
17 
18 #ifdef USE_LIBRETINY
19 #include <WiFi.h>
20 #endif
21 
22 #if defined(USE_ESP_IDF) && defined(USE_WIFI_WPA2_EAP)
23 #include <esp_wpa2.h>
24 #endif
25 
26 #ifdef USE_ESP8266
27 #include <ESP8266WiFi.h>
28 #include <ESP8266WiFiType.h>
29 
30 #if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE < VERSION_CODE(2, 4, 0)
31 extern "C" {
32 #include <user_interface.h>
33 };
34 #endif
35 #endif
36 
37 #ifdef USE_RP2040
38 extern "C" {
39 #include "cyw43.h"
40 #include "cyw43_country.h"
41 #include "pico/cyw43_arch.h"
42 }
43 
44 #include <WiFi.h>
45 #endif
46 
47 namespace esphome {
48 namespace wifi {
49 
51  char ssid[33];
52  char password[65];
53 } PACKED; // NOLINT
54 
56  uint8_t bssid[6];
57  uint8_t channel;
58 } PACKED; // NOLINT
59 
81 };
82 
83 enum class WiFiSTAConnectStatus : int {
84  IDLE,
85  CONNECTING,
86  CONNECTED,
89 };
90 
92 struct ManualIP {
98 };
99 
100 #ifdef USE_WIFI_WPA2_EAP
101 struct EAPAuth {
102  std::string identity; // required for all auth types
103  std::string username;
104  std::string password;
105  const char *ca_cert; // optionally verify authentication server
106  // used for EAP-TLS
107  const char *client_cert;
108  const char *client_key;
109 // used for EAP-TTLS
110 #ifdef USE_ESP_IDF
111  esp_eap_ttls_phase2_types ttls_phase_2;
112 #endif
113 };
114 #endif // USE_WIFI_WPA2_EAP
115 
116 using bssid_t = std::array<uint8_t, 6>;
117 
118 class WiFiAP {
119  public:
120  void set_ssid(const std::string &ssid);
121  void set_bssid(bssid_t bssid);
122  void set_bssid(optional<bssid_t> bssid);
123  void set_password(const std::string &password);
124 #ifdef USE_WIFI_WPA2_EAP
125  void set_eap(optional<EAPAuth> eap_auth);
126 #endif // USE_WIFI_WPA2_EAP
127  void set_channel(optional<uint8_t> channel);
128  void set_priority(float priority) { priority_ = priority; }
129  void set_manual_ip(optional<ManualIP> manual_ip);
130  void set_hidden(bool hidden);
131  const std::string &get_ssid() const;
132  const optional<bssid_t> &get_bssid() const;
133  const std::string &get_password() const;
134 #ifdef USE_WIFI_WPA2_EAP
135  const optional<EAPAuth> &get_eap() const;
136 #endif // USE_WIFI_WPA2_EAP
137  const optional<uint8_t> &get_channel() const;
138  float get_priority() const { return priority_; }
139  const optional<ManualIP> &get_manual_ip() const;
140  bool get_hidden() const;
141 
142  protected:
143  std::string ssid_;
145  std::string password_;
146 #ifdef USE_WIFI_WPA2_EAP
148 #endif // USE_WIFI_WPA2_EAP
150  float priority_{0};
152  bool hidden_{false};
153 };
154 
156  public:
157  WiFiScanResult(const bssid_t &bssid, std::string ssid, uint8_t channel, int8_t rssi, bool with_auth, bool is_hidden);
158 
159  bool matches(const WiFiAP &config);
160 
161  bool get_matches() const;
162  void set_matches(bool matches);
163  const bssid_t &get_bssid() const;
164  const std::string &get_ssid() const;
165  uint8_t get_channel() const;
166  int8_t get_rssi() const;
167  bool get_with_auth() const;
168  bool get_is_hidden() const;
169  float get_priority() const { return priority_; }
170  void set_priority(float priority) { priority_ = priority; }
171 
172  bool operator==(const WiFiScanResult &rhs) const;
173 
174  protected:
175  bool matches_{false};
177  std::string ssid_;
178  uint8_t channel_;
179  int8_t rssi_;
182  float priority_{0.0f};
183 };
184 
187  float priority;
188 };
189 
194 };
195 
196 #ifdef USE_ESP_IDF
197 struct IDFWiFiEvent;
198 #endif
199 
201 class WiFiComponent : public Component {
202  public:
204  WiFiComponent();
205 
206  void set_sta(const WiFiAP &ap);
207  void add_sta(const WiFiAP &ap);
208  void clear_sta();
209 
210 #ifdef USE_WIFI_AP
211 
218  void set_ap(const WiFiAP &ap);
219  WiFiAP get_ap() { return this->ap_; }
220 #endif // USE_WIFI_AP
221 
222  void enable();
223  void disable();
224  bool is_disabled();
225  void start_scanning();
226  void check_scanning_finished();
227  void start_connecting(const WiFiAP &ap, bool two);
228  void set_fast_connect(bool fast_connect);
229  void set_ap_timeout(uint32_t ap_timeout) { ap_timeout_ = ap_timeout; }
230 
231  void check_connecting_finished();
232 
233  void retry_connect();
234 
235  bool can_proceed() override;
236 
237  void set_reboot_timeout(uint32_t reboot_timeout);
238 
239  bool is_connected();
240 
241  void set_power_save_mode(WiFiPowerSaveMode power_save);
242  void set_output_power(float output_power) { output_power_ = output_power; }
243 
244  void set_passive_scan(bool passive);
245 
246  void save_wifi_sta(const std::string &ssid, const std::string &password);
247  // ========== INTERNAL METHODS ==========
248  // (In most use cases you won't need these)
250  void setup() override;
251  void start();
252  void dump_config() override;
254  float get_setup_priority() const override;
255  float get_loop_priority() const override;
256 
258  void loop() override;
259 
260  bool has_sta() const;
261  bool has_ap() const;
262 
263 #ifdef USE_WIFI_11KV_SUPPORT
264  void set_btm(bool btm);
265  void set_rrm(bool rrm);
266 #endif
267 
268  network::IPAddress get_dns_address(int num);
270  std::string get_use_address() const;
271  void set_use_address(const std::string &use_address);
272 
273  const std::vector<WiFiScanResult> &get_scan_result() const { return scan_result_; }
274 
275  network::IPAddress wifi_soft_ap_ip();
276 
277  bool has_sta_priority(const bssid_t &bssid) {
278  for (auto &it : this->sta_priorities_) {
279  if (it.bssid == bssid)
280  return true;
281  }
282  return false;
283  }
284  float get_sta_priority(const bssid_t bssid) {
285  for (auto &it : this->sta_priorities_) {
286  if (it.bssid == bssid)
287  return it.priority;
288  }
289  return 0.0f;
290  }
291  void set_sta_priority(const bssid_t bssid, float priority) {
292  for (auto &it : this->sta_priorities_) {
293  if (it.bssid == bssid) {
294  it.priority = priority;
295  return;
296  }
297  }
298  this->sta_priorities_.push_back(WiFiSTAPriority{
299  .bssid = bssid,
300  .priority = priority,
301  });
302  }
303 
304  network::IPAddresses wifi_sta_ip_addresses();
305  std::string wifi_ssid();
306  bssid_t wifi_bssid();
307 
308  int8_t wifi_rssi();
309 
310  void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
311 
312  Trigger<> *get_connect_trigger() const { return this->connect_trigger_; };
313  Trigger<> *get_disconnect_trigger() const { return this->disconnect_trigger_; };
314 
315  protected:
316  static std::string format_mac_addr(const uint8_t mac[6]);
317 
318 #ifdef USE_WIFI_AP
319  void setup_ap_config_();
320 #endif // USE_WIFI_AP
321 
322  void print_connect_params_();
323 
324  void wifi_loop_();
325  bool wifi_mode_(optional<bool> sta, optional<bool> ap);
326  bool wifi_sta_pre_setup_();
327  bool wifi_apply_output_power_(float output_power);
328  bool wifi_apply_power_save_();
329  bool wifi_sta_ip_config_(optional<ManualIP> manual_ip);
330  bool wifi_apply_hostname_();
331  bool wifi_sta_connect_(const WiFiAP &ap);
332  void wifi_pre_setup_();
333  WiFiSTAConnectStatus wifi_sta_connect_status_();
334  bool wifi_scan_start_(bool passive);
335 
336 #ifdef USE_WIFI_AP
337  bool wifi_ap_ip_config_(optional<ManualIP> manual_ip);
338  bool wifi_start_ap_(const WiFiAP &ap);
339 #endif // USE_WIFI_AP
340 
341  bool wifi_disconnect_();
342  int32_t wifi_channel_();
343  network::IPAddress wifi_subnet_mask_();
344  network::IPAddress wifi_gateway_ip_();
345  network::IPAddress wifi_dns_ip_(int num);
346 
347  bool is_captive_portal_active_();
348  bool is_esp32_improv_active_();
349 
350  void load_fast_connect_settings_();
351  void save_fast_connect_settings_();
352 
353 #ifdef USE_ESP8266
354  static void wifi_event_callback(System_Event_t *event);
355  void wifi_scan_done_callback_(void *arg, STATUS status);
356  static void s_wifi_scan_done_callback(void *arg, STATUS status);
357 #endif
358 
359 #ifdef USE_ESP32_FRAMEWORK_ARDUINO
360  void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info);
361  void wifi_scan_done_callback_();
362 #endif
363 #ifdef USE_ESP_IDF
364  void wifi_process_event_(IDFWiFiEvent *data);
365 #endif
366 
367 #ifdef USE_RP2040
368  static int s_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result);
369  void wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result);
370 #endif
371 
372 #ifdef USE_LIBRETINY
373  void wifi_event_callback_(arduino_event_id_t event, arduino_event_info_t info);
374  void wifi_scan_done_callback_();
375 #endif
376 
377  std::string use_address_;
378  std::vector<WiFiAP> sta_;
379  std::vector<WiFiSTAPriority> sta_priorities_;
381  bool fast_connect_{false};
382  bool retry_hidden_{false};
383 
384  bool has_ap_{false};
387  bool handled_connected_state_{false};
388  uint32_t action_started_;
389  uint8_t num_retried_{0};
390  uint32_t last_connected_{0};
391  uint32_t reboot_timeout_{};
392  uint32_t ap_timeout_{};
394  bool error_from_callback_{false};
395  std::vector<WiFiScanResult> scan_result_;
396  bool scan_done_{false};
397  bool ap_setup_{false};
399  bool passive_scan_{false};
402  bool has_saved_wifi_settings_{false};
403 #ifdef USE_WIFI_11KV_SUPPORT
404  bool btm_{false};
405  bool rrm_{false};
406 #endif
408  bool got_ipv4_address_{false};
409 #if USE_NETWORK_IPV6
410  uint8_t num_ipv6_addresses_{0};
411 #endif /* USE_NETWORK_IPV6 */
412 
413  Trigger<> *connect_trigger_{new Trigger<>()};
414  Trigger<> *disconnect_trigger_{new Trigger<>()};
415 };
416 
417 extern WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
418 
419 template<typename... Ts> class WiFiConnectedCondition : public Condition<Ts...> {
420  public:
421  bool check(Ts... x) override { return global_wifi_component->is_connected(); }
422 };
423 
424 template<typename... Ts> class WiFiEnabledCondition : public Condition<Ts...> {
425  public:
426  bool check(Ts... x) override { return !global_wifi_component->is_disabled(); }
427 };
428 
429 template<typename... Ts> class WiFiEnableAction : public Action<Ts...> {
430  public:
431  void play(Ts... x) override { global_wifi_component->enable(); }
432 };
433 
434 template<typename... Ts> class WiFiDisableAction : public Action<Ts...> {
435  public:
436  void play(Ts... x) override { global_wifi_component->disable(); }
437 };
438 
439 } // namespace wifi
440 } // namespace esphome
void setup()
Nothing has been initialized yet.
void loop()
This component is responsible for managing the ESP WiFi interface.
void set_enable_on_boot(bool enable_on_boot)
void set_priority(float priority)
std::array< uint8_t, 6 > bssid_t
std::string get_use_address()
Get the active network hostname.
Definition: util.cpp:52
float get_priority() const
void set_output_power(float output_power)
Trigger * get_disconnect_trigger() const
const std::vector< WiFiScanResult > & get_scan_result() const
uint16_t x
Definition: tt21100.cpp:17
void set_sta_priority(const bssid_t bssid, float priority)
optional< ManualIP > manual_ip_
WiFi is in STA(+AP) mode and currently connecting to an AP a second time.
void play(Ts... x) override
WiFi is in STA(+AP) mode and successfully connected.
void set_priority(float priority)
network::IPAddress static_ip
bool is_connected()
Return whether the node is connected to the network (through wifi, eth, ...)
Definition: util.cpp:15
network::IPAddress gateway
void set_ap_timeout(uint32_t ap_timeout)
std::vector< WiFiScanResult > scan_result_
WiFi is in STA-only mode and currently scanning for APs.
network::IPAddresses get_ip_addresses()
Definition: util.cpp:40
Struct for setting static IPs in WiFiComponent.
network::IPAddress dns1
The first DNS server. 0.0.0.0 for default.
Base class for all automation conditions.
Definition: automation.h:74
WiFi is in STA(+AP) mode and currently connecting to an AP.
bool has_sta_priority(const bssid_t &bssid)
WiFi is in cooldown mode because something went wrong, scanning will begin after a short period of ti...
optional< bssid_t > bssid_
esp_eap_ttls_phase2_types ttls_phase_2
Trigger * get_connect_trigger() const
WiFiComponent * global_wifi_component
std::array< IPAddress, 5 > IPAddresses
Definition: ip_address.h:139
optional< uint8_t > channel_
uint8_t priority
uint8_t status
Definition: bl0942.h:23
ESPPreferenceObject pref_
bool is_disabled()
Return whether the network is disabled (only wifi for now)
Definition: util.cpp:32
network::IPAddress dns2
The second DNS server. 0.0.0.0 for default.
struct esphome::wifi::SavedWifiSettings PACKED
std::vector< WiFiSTAPriority > sta_priorities_
bool operator==(optional< T > const &x, optional< U > const &y)
Definition: optional.h:114
std::vector< WiFiAP > sta_
optional< float > output_power_
network::IPAddress subnet
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
ESPPreferenceObject fast_connect_pref_
void play(Ts... x) override
float get_sta_priority(const bssid_t bssid)
optional< EAPAuth > eap_
WiFi is in AP-only mode and internal AP is already enabled.