supla-device
Loading...
Searching...
No Matches
esp_wifi.h
1/*
2 Copyright (C) AC SOFTWARE SP. Z O.O.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17*/
18
19#ifndef SRC_SUPLA_NETWORK_ESP_WIFI_H_
20#define SRC_SUPLA_NETWORK_ESP_WIFI_H_
21
22#include <Arduino.h>
23
24#include <supla/input_noise_guard.h>
25#include <supla/log_wrapper.h>
26#include <supla/network/arduino_netif_config.h>
27#include <supla/network/wifi_scan_result.h>
28#include <supla/time.h>
29#include <supla/tools.h>
30
31#ifdef ARDUINO_ARCH_ESP8266
32#include <ESP8266WiFi.h>
33
34// workaround for incompatible names in ESP8266 and ESP32 boards
35#define WIFI_MODE_AP WIFI_AP
36#define WIFI_MODE_STA WIFI_STA
37
38#else
39#include <WiFi.h>
40#endif
41
42#include "../supla_lib_config.h"
43#include "netif_wifi.h"
44
45namespace Supla {
46class ESPWifi : public Supla::Wifi {
47 public:
48 ESPWifi(const char *wifiSsid = nullptr,
49 const char *wifiPassword = nullptr,
50 unsigned char *ip = nullptr)
51 : Wifi(wifiSsid, wifiPassword, ip) {
52 }
53
54
55 bool isReady() override {
56 return WiFi.status() == WL_CONNECTED;
57 }
58
59 static void printConnectionDetails() {
60 SUPLA_LOG_INFO("Connected BSSID: %s", WiFi.BSSIDstr().c_str());
61 SUPLA_LOG_INFO("local IP: %s", WiFi.localIP().toString().c_str());
62 SUPLA_LOG_INFO("subnetMask: %s", WiFi.subnetMask().toString().c_str());
63 SUPLA_LOG_INFO("gatewayIP: %s", WiFi.gatewayIP().toString().c_str());
64 int rssi = WiFi.RSSI();
65 SUPLA_LOG_INFO("Signal strength (RSSI): %d dBm", rssi);
66 }
67
68 void setup() override {
69 // ESP8266: for some reason when hostname is longer than 30 bytes, Wi-Fi
70 // connection can't be esablished. So as a workaround, we truncate hostname
71 // to 30 bytes
72 hostname[30] = '\0';
73 if (!wifiConfigured) {
74 // ESP32 requires setHostname to be called before begin...
75 WiFi.setHostname(hostname);
76 wifiConfigured = true;
77#ifdef ARDUINO_ARCH_ESP8266
78 gotIpEventHandler =
79 WiFi.onStationModeGotIP([](const WiFiEventStationModeGotIP &event) {
80 (void)(event);
81 ESPWifi::printConnectionDetails();
82 });
83 disconnectedEventHandler = WiFi.onStationModeDisconnected(
84 [](const WiFiEventStationModeDisconnected &event) {
85 (void)(event);
86 SUPLA_LOG_INFO("WiFi station disconnected");
87 });
88#else
89 WiFiEventId_t event_gotIP = WiFi.onEvent(
90 [](WiFiEvent_t event, WiFiEventInfo_t info) {
91 Supla::InputNoiseGuard::NotifyWifiStaConnected();
92 ESPWifi::printConnectionDetails();
93 },
94 WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
95
96 (void)(event_gotIP);
97
98 WiFiEventId_t event_disconnected = WiFi.onEvent(
99 [](WiFiEvent_t event, WiFiEventInfo_t info) {
100 SUPLA_LOG_INFO("WiFi Station disconnected");
101 // ESP32 doesn't reconnect automatically after lost connection
102 Supla::InputNoiseGuard::NotifyWifiStaDisconnected();
103 if (mode != Supla::DEVICE_MODE_CONFIG) {
104 WiFi.reconnect();
105 }
106 },
107 WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
108
109 (void)(event_disconnected);
110#endif
111 } else {
112 if (mode == Supla::DEVICE_MODE_CONFIG) {
113 Supla::InputNoiseGuard::NotifyWifiTransition();
114 WiFi.mode(WIFI_MODE_AP);
115 } else {
116 Supla::InputNoiseGuard::NotifyWifiTransition();
117 WiFi.mode(WIFI_MODE_STA);
118 }
119 SUPLA_LOG_INFO("WiFi: resetting WiFi connection");
120 DisconnectProtocols();
121 Supla::InputNoiseGuard::NotifyWifiTransition();
122 WiFi.disconnect();
123 }
124
125 if (mode == Supla::DEVICE_MODE_CONFIG) {
126 SUPLA_LOG_INFO("WiFi: enter config mode with SSID: \"%s\"", hostname);
127 Supla::InputNoiseGuard::NotifyWifiTransition();
128 WiFi.mode(WIFI_AP_STA);
129 Supla::InputNoiseGuard::NotifyWifiTransition();
130 WiFi.softAP(hostname, nullptr, 6);
131 startConfigModeScan();
132
133 } else {
134 SUPLA_LOG_INFO("WiFi: establishing connection with SSID: \"%s\"", ssid);
135 Supla::InputNoiseGuard::NotifyWifiTransition();
136 WiFi.mode(WIFI_MODE_STA);
137 if (hasStaticIpConfig()) {
138 const auto &cfg = getNetifConfig();
139 IPAddress localIp = toArduinoIpAddress(cfg.ip);
140 IPAddress gateway = toArduinoIpAddress(cfg.gateway);
141 IPAddress subnet = toArduinoIpAddress(cfg.netmask);
142 IPAddress dns1 = toArduinoIpAddress(cfg.dns1);
143 IPAddress dns2 = toArduinoIpAddress(cfg.dns2);
144 if (!WiFi.config(localIp, gateway, subnet, dns1, dns2)) {
145 SUPLA_LOG_WARNING("WiFi static IP config failed, continuing");
146 }
147 }
148 Supla::InputNoiseGuard::NotifyWifiTransition();
149 WiFi.begin(ssid, password);
150 // ESP8266 requires setHostname to be called after begin...
151 WiFi.setHostname(hostname);
152 }
153
154 yield();
155 allowDisable = true;
156 }
157
158 bool iterate() override {
159 if (!configModeScanInProgress) {
160 return Supla::Wifi::iterate();
161 }
162
163 int scanResult = WiFi.scanComplete();
164 if (scanResult == WIFI_SCAN_RUNNING) {
165 return false;
166 }
167
168 configModeScanInProgress = false;
169 auto cache = Supla::WifiScanResultCache::Instance();
170 cache->beginUpdate();
171
172 if (scanResult >= 0) {
173 for (int i = 0; i < scanResult; i++) {
174 cache->addOrUpdate(WiFi.SSID(i).c_str(), WiFi.RSSI(i), WiFi.channel(i));
175 }
176 cache->finishUpdate(millis());
177 SUPLA_LOG_INFO("WiFi: config mode scan completed (%d networks)",
178 scanResult);
179 } else {
180 cache->clear();
181 SUPLA_LOG_WARNING("WiFi: config mode scan failed (%d)", scanResult);
182 }
183
184 WiFi.scanDelete();
185 return Supla::Wifi::iterate();
186 }
187
188 void startConfigModeScan() override {
189 if (mode != Supla::DEVICE_MODE_CONFIG || configModeScanInProgress) {
190 return;
191 }
192
193 WiFi.scanDelete();
194 int scanResult = WiFi.scanNetworks(true, true);
195 configModeScanInProgress = (scanResult == WIFI_SCAN_RUNNING);
196 if (!configModeScanInProgress && scanResult >= 0) {
197 auto cache = Supla::WifiScanResultCache::Instance();
198 cache->beginUpdate();
199 for (int i = 0; i < scanResult; i++) {
200 cache->addOrUpdate(WiFi.SSID(i).c_str(), WiFi.RSSI(i), WiFi.channel(i));
201 }
202 cache->finishUpdate(millis());
203 WiFi.scanDelete();
204 SUPLA_LOG_INFO("WiFi: config mode scan completed (%d networks)",
205 scanResult);
206 } else if (!configModeScanInProgress) {
207 SUPLA_LOG_WARNING("WiFi: config mode scan start failed (%d)",
208 scanResult);
209 } else {
210 SUPLA_LOG_INFO("WiFi: config mode scan started");
211 }
212 }
213
214 void disable() override {
215 if (!allowDisable) {
216 return;
217 }
218
219 allowDisable = false;
220 configModeScanInProgress = false;
221 SUPLA_LOG_DEBUG("[%s] disabling WiFi connection", getIntfName());
222 DisconnectProtocols();
223 WiFi.scanDelete();
224 Supla::InputNoiseGuard::NotifyWifiTransition();
225 WiFi.softAPdisconnect(true);
226 Supla::InputNoiseGuard::NotifyWifiTransition();
227 WiFi.disconnect(true);
228 Supla::InputNoiseGuard::NotifyWifiTransition();
229 WiFi.mode(WIFI_OFF);
230 }
231
232 // DEPRECATED, use setSSLEnabled instead
233 void enableSSL(bool value) {
234 setSSLEnabled(value);
235 }
236
237 void fillStateData(TDSC_ChannelState *channelState) override {
238 channelState->Fields |= SUPLA_CHANNELSTATE_FIELD_IPV4 |
239 SUPLA_CHANNELSTATE_FIELD_MAC |
240 SUPLA_CHANNELSTATE_FIELD_WIFIRSSI |
241 SUPLA_CHANNELSTATE_FIELD_WIFISIGNALSTRENGTH;
242 channelState->IPv4 = WiFi.localIP();
243 getMacAddr(channelState->MAC);
244 int rssi = WiFi.RSSI();
245 channelState->WiFiRSSI = rssi;
246 channelState->WiFiSignalStrength = Supla::rssiToSignalStrength(rssi);
247 }
248
249 bool getMacAddr(uint8_t *out) override {
250#ifdef ARDUINO_ARCH_ESP8266
251 WiFi.macAddress(out);
252#else
253#ifdef ESP_ARDUINO_VERSION_MAJOR
254#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
255 // Code for version 3.x
256 ::Network.macAddress(out);
257#else
258 // Code for version 2.x
259 WiFi.macAddress(out);
260#endif
261#endif
262#endif
263 return true;
264 }
265
266 void uninit() override {
267 disable();
268 }
269
270 uint32_t getIP() override {
271 return WiFi.localIP();
272 }
273
274 const char *getIntfName() const override {
275 return "Wi-Fi";
276 }
277
278 protected:
279 bool wifiConfigured = false;
280 bool configModeScanInProgress = false;
281 bool allowDisable = false;
282
283#ifdef ARDUINO_ARCH_ESP8266
284 WiFiEventHandler gotIpEventHandler, disconnectedEventHandler;
285#endif
286
287 bool isConfigModeScanInProgress() const override {
288 return configModeScanInProgress;
289 }
290};
291
292}; // namespace Supla
293
294#endif // SRC_SUPLA_NETWORK_ESP_WIFI_H_
Definition ip_address.h:30
Definition network.h:36
Definition netif_wifi.h:31
Definition proto.h:2981