Uniot Core
0.8.1
Loading...
Searching...
No Matches
ConfigCaptivePortal.h
Go to the documentation of this file.
1/*
2 * This is a part of the Uniot project.
3 * Copyright (C) 2016-2025 Uniot <contact@uniot.io>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#pragma once
20
21#include <Common.h>
22#include <DNSServer.h>
23#include <ESPAsyncWebServer.h>
24#include <IExecutor.h>
25#ifdef ESP8266
26#include <ESP8266mDNS.h>
27#else
28#include <ESPmDNS.h>
29#endif
30
31#define DNS_PORT 53
32#define HTTP_PORT 80
33#define WS_URL "/ws"
34#define DOMAIN_NAME "*"
35#define MDNS_HOSTNAME "uniot"
36
78
79namespace uniot {
80
88class DetailedAsyncWebServer : public AsyncWebServer {
89 public:
94 DetailedAsyncWebServer(uint16_t port) : AsyncWebServer(port) {}
95
100 uint8_t status() {
101 return _server.status();
102 }
103};
104
124 public:
134 ConfigCaptivePortal(const IPAddress& apIp, AwsEventHandler wsHandler = nullptr)
135 : mIsStarted(false),
136 mMdnsStarted(false),
137 mApIp(apIp),
138 mpDnsServer(new DNSServer()),
139 mpWebServer(new DetailedAsyncWebServer(HTTP_PORT)),
140 mpWebSocket(new AsyncWebSocket(WS_URL)),
141 mWebSocketHandler(wsHandler),
142 mWsClientLastSeen(0) {
143 mpWebServer->addHandler(mpWebSocket.get());
144 }
145
159 bool start() {
160 if (!mIsStarted) {
161 mpDnsServer->setTTL(30);
162 mpDnsServer->setErrorReplyCode(DNSReplyCode::ServerFailure);
163 if (mpDnsServer->start(DNS_PORT, DOMAIN_NAME, mApIp)) {
164 if (mWebSocketHandler) {
165 mpWebSocket->enable(true);
166 mpWebSocket->onEvent([this](AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) {
167 mWebSocketHandler(server, client, type, arg, data, len);
168 mWsClientLastSeen = millis();
169 });
170 }
171 mpWebServer->begin();
172 auto status = mpWebServer->status();
173 if (status == 0) {
174 mpWebServer->end();
175 return false;
176 }
177
178 if (MDNS.begin(MDNS_HOSTNAME)) {
179 MDNS.addService("http", "tcp", HTTP_PORT);
180 mMdnsStarted = true;
181 }
182
183 return mIsStarted = true;
184 }
185 return false;
186 }
187 return true;
188 }
189
201 void stop() {
202 if (mIsStarted) {
203 if (mMdnsStarted) {
204 MDNS.end();
205 mMdnsStarted = false;
206 }
207 // DNSServer has problem with memory deallocation when stop() called
208 // TODO: fix, pull request
209 mpDnsServer->stop();
210 mpDnsServer.reset(new DNSServer());
211 mpWebServer->end();
212 // mpWebServer->removeHandler(mpWebSocket.get());
213 mpWebSocket->closeAll();
214 mpWebSocket->cleanupClients();
215 mIsStarted = false;
216 }
217 }
218
226 AsyncWebServer* get() {
227 return mpWebServer.get();
228 }
229
237 void wsTextAll(const String& message) {
238 if (mpWebSocket) {
239 mpWebSocket->textAll(message);
240 }
241 }
242
251 void wsText(uint32_t clientId, const String& message) {
252 if (mpWebSocket) {
253 mpWebSocket->text(clientId, message);
254 }
255 }
256
263 void wsCloseAll() {
264 if (mpWebSocket) {
265 mpWebSocket->enable(false);
266 mpWebSocket->closeAll();
267 mpWebSocket->cleanupClients();
268 }
269 }
270
279 void wsEnable(bool enable) {
280 if (mpWebSocket) {
281 mpWebSocket->enable(enable);
282 }
283 }
284
294 bool wsClientsActive(unsigned long window = 30000) const {
295 auto timeSinceLastSeen = millis() - mWsClientLastSeen;
296 return (mpWebSocket && mpWebSocket->count() > 0 && timeSinceLastSeen < window);
297 }
298
303 inline const IPAddress& ip() const {
304 return mApIp;
305 }
306
318 virtual void execute(short _) override {
319 if (mIsStarted) {
320 if (mpDnsServer) {
321 mpDnsServer->processNextRequest();
322 }
323 if (mpWebSocket) {
324 mpWebSocket->cleanupClients();
325 }
326#ifdef ESP8266
327 if (mMdnsStarted) {
328 MDNS.update();
329 }
330#endif
331 }
332 }
333
334 private:
335 bool mIsStarted;
336 bool mMdnsStarted;
337
338 IPAddress mApIp;
339 UniquePointer<DNSServer> mpDnsServer;
342 AwsEventHandler mWebSocketHandler;
343 unsigned long mWsClientLastSeen;
344};
345
346} // namespace uniot
347
#define HTTP_PORT
Standard HTTP port for web server.
Definition ConfigCaptivePortal.h:32
#define WS_URL
WebSocket endpoint URL path.
Definition ConfigCaptivePortal.h:33
#define MDNS_HOSTNAME
mDNS hostname for local discovery
Definition ConfigCaptivePortal.h:35
#define DOMAIN_NAME
Wildcard domain name for DNS capture.
Definition ConfigCaptivePortal.h:34
#define DNS_PORT
Standard DNS port for captive portal functionality.
Definition ConfigCaptivePortal.h:31
void wsCloseAll()
Close all WebSocket connections.
Definition ConfigCaptivePortal.h:263
virtual void execute(short _) override
Execute periodic captive portal maintenance tasks.
Definition ConfigCaptivePortal.h:318
bool wsClientsActive(unsigned long window=30000) const
Check if WebSocket clients are actively connected.
Definition ConfigCaptivePortal.h:294
void wsText(uint32_t clientId, const String &message)
Send text message to a specific WebSocket client.
Definition ConfigCaptivePortal.h:251
void wsEnable(bool enable)
Enable or disable WebSocket functionality.
Definition ConfigCaptivePortal.h:279
bool start()
Start the captive portal services.
Definition ConfigCaptivePortal.h:159
ConfigCaptivePortal(const IPAddress &apIp, AwsEventHandler wsHandler=nullptr)
Construct a new ConfigCaptivePortal.
Definition ConfigCaptivePortal.h:134
void stop()
Stop all captive portal services.
Definition ConfigCaptivePortal.h:201
const IPAddress & ip() const
Get the IP address of the captive portal.
Definition ConfigCaptivePortal.h:303
void wsTextAll(const String &message)
Send text message to all connected WebSocket clients.
Definition ConfigCaptivePortal.h:237
AsyncWebServer * get()
Get the underlying AsyncWebServer instance.
Definition ConfigCaptivePortal.h:226
Extended AsyncWebServer with status monitoring capabilities.
Definition ConfigCaptivePortal.h:88
uint8_t status()
Get the current server status.
Definition ConfigCaptivePortal.h:100
DetailedAsyncWebServer(uint16_t port)
Construct a new DetailedAsyncWebServer.
Definition ConfigCaptivePortal.h:94
Interface for executing tasks in the scheduler system.
Definition IExecutor.h:31
std::unique_ptr< T > UniquePointer
Type alias for std::unique_ptr with cleaner syntax.
Definition Common.h:152
Contains all classes and functions related to the Uniot Core.