mirror of https://github.com/lumapu/ahoy.git
Browse Source
* combined common network functions into class * seperated wifi station from AP modepull/1549/head
lumapu
10 months ago
12 changed files with 540 additions and 25 deletions
@ -0,0 +1,82 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2024 Ahoy, https://ahoydtu.de
|
|||
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
#ifndef __AHOY_ETHERNET_H__ |
|||
#define __AHOY_ETHERNET_H__ |
|||
|
|||
#include <functional> |
|||
#include <AsyncUDP.h> |
|||
#include <ETH.h> |
|||
#include "AhoyEthernetSpi.h" |
|||
#include "AhoyEthernet.h" |
|||
|
|||
class AhoyEthernet : public AhoyNetwork { |
|||
public: |
|||
void begin() override { |
|||
setupIp([this](IPAddress ip, IPAddress gateway, IPAddress mask, IPAddress dns1, IPAddress dns2) -> bool { |
|||
return ETH.config(ip, gateway, mask, dns1, dns2); |
|||
}); |
|||
} |
|||
|
|||
void tickNetworkLoop() override { |
|||
switch(mState) { |
|||
case NetworkState::DISCONNECTED: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
private: |
|||
|
|||
/*switch (event) {
|
|||
case ARDUINO_EVENT_ETH_START: |
|||
DPRINTLN(DBG_VERBOSE, F("ETH Started")); |
|||
|
|||
if(String(mConfig->sys.deviceName) != "") |
|||
ETH.setHostname(mConfig->sys.deviceName); |
|||
else |
|||
ETH.setHostname(F("ESP32_W5500")); |
|||
break; |
|||
|
|||
case ARDUINO_EVENT_ETH_CONNECTED: |
|||
DPRINTLN(DBG_VERBOSE, F("ETH Connected")); |
|||
break; |
|||
|
|||
case ARDUINO_EVENT_ETH_GOT_IP: |
|||
if (!mEthConnected) { |
|||
welcome(ETH.localIP().toString(), F(" (Station)")); |
|||
|
|||
mEthConnected = true; |
|||
mOnNetworkCB(true); |
|||
} |
|||
|
|||
if (!MDNS.begin(mConfig->sys.deviceName)) { |
|||
DPRINTLN(DBG_ERROR, F("Error setting up MDNS responder!")); |
|||
} else { |
|||
DBGPRINT(F("mDNS established: ")); |
|||
DBGPRINT(mConfig->sys.deviceName); |
|||
DBGPRINTLN(F(".local")); |
|||
} |
|||
break; |
|||
|
|||
case ARDUINO_EVENT_ETH_DISCONNECTED: |
|||
DPRINTLN(DBG_INFO, F("ETH Disconnected")); |
|||
mEthConnected = false; |
|||
mUdp.close(); |
|||
mOnNetworkCB(false); |
|||
break; |
|||
|
|||
case ARDUINO_EVENT_ETH_STOP: |
|||
DPRINTLN(DBG_INFO, F("ETH Stopped")); |
|||
mEthConnected = false; |
|||
mUdp.close(); |
|||
mOnNetworkCB(false); |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
}*/ |
|||
}; |
|||
|
|||
#endif /*__AHOY_ETHERNET_H__*/ |
@ -0,0 +1,194 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2024 Ahoy, https://ahoydtu.de
|
|||
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
#ifndef __AHOY_NETWORK_H__ |
|||
#define __AHOY_NETWORK_H__ |
|||
|
|||
#include "AhoyNetworkHelper.h" |
|||
#include <WiFiUdp.h> |
|||
#include "../config/settings.h" |
|||
#include "../utils/helper.h" |
|||
|
|||
#if defined(ESP32) |
|||
#include <ESPmDNS.h> |
|||
#else |
|||
#include <ESP8266mDNS.h> |
|||
#endif |
|||
|
|||
#define NTP_PACKET_SIZE 48 |
|||
|
|||
class AhoyNetwork { |
|||
public: |
|||
typedef std::function<void(bool)> OnNetworkCB; |
|||
typedef std::function<void(bool)> OnTimeCB; |
|||
|
|||
public: |
|||
void setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB) { |
|||
mConfig = config; |
|||
mUtcTimestamp = utcTimestamp; |
|||
mOnNetworkCB = onNetworkCB; |
|||
mOnTimeCB = onTimeCB; |
|||
|
|||
#if defined(ESP32) |
|||
WiFi.onEvent([this](WiFiEvent_t event) -> void { |
|||
this->OnEvent(event); |
|||
}); |
|||
#else |
|||
wifiConnectHandler = WiFi.onStationModeConnected( |
|||
[this](const WiFiEventStationModeConnected& event) -> void { |
|||
OnEvent(SYSTEM_EVENT_STA_CONNECTED); |
|||
}); |
|||
wifiGotIPHandler = WiFi.onStationModeGotIP( |
|||
[this](const WiFiEventStationModeGotIP& event) -> void { |
|||
OnEvent(SYSTEM_EVENT_STA_GOT_IP); |
|||
}); |
|||
wifiDisconnectHandler = WiFi.onStationModeDisconnected( |
|||
[this](const WiFiEventStationModeDisconnected& event) -> void { |
|||
OnEvent(SYSTEM_EVENT_STA_DISCONNECTED); |
|||
}); |
|||
#endif |
|||
} |
|||
|
|||
bool isConnected() const { |
|||
return (mStatus == NetworkState.CONNECTED); |
|||
} |
|||
|
|||
bool updateNtpTime(void) { |
|||
if(CONNECTED != mStatus) |
|||
return; |
|||
|
|||
if (!mUdp.connected()) { |
|||
IPAddress timeServer; |
|||
if (!WiFi.hostByName(mConfig->ntp.addr, timeServer)) |
|||
return false; |
|||
if (!mUdp.connect(timeServer, mConfig->ntp.port)) |
|||
return false; |
|||
} |
|||
|
|||
mUdp.onPacket([this](AsyncUDPPacket packet) { |
|||
this->handleNTPPacket(packet); |
|||
}); |
|||
sendNTPpacket(timeServer); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
public: |
|||
virtual void begin() = 0; |
|||
virtual void tickNetworkLoop() = 0; |
|||
virtual void connectionEvent(WiFiStatus_t status) = 0; |
|||
|
|||
protected: |
|||
void setupIp(void) { |
|||
if(mConfig->sys.ip.ip[0] != 0) { |
|||
IPAddress ip(mConfig->sys.ip.ip); |
|||
IPAddress mask(mConfig->sys.ip.mask); |
|||
IPAddress dns1(mConfig->sys.ip.dns1); |
|||
IPAddress dns2(mConfig->sys.ip.dns2); |
|||
IPAddress gateway(mConfig->sys.ip.gateway); |
|||
if(!ETH.config(ip, gateway, mask, dns1, dns2)) |
|||
DPRINTLN(DBG_ERROR, F("failed to set static IP!")); |
|||
} |
|||
} |
|||
|
|||
void OnEvent(WiFiEvent_t event) { |
|||
switch(event) { |
|||
case SYSTEM_EVENT_STA_CONNECTED: |
|||
[[fallthrough]]; |
|||
case ARDUINO_EVENT_ETH_CONNECTED: |
|||
if(NetworkState::CONNECTED != mStatus) { |
|||
mStatus = NetworkState::CONNECTED; |
|||
DPRINTLN(DBG_INFO, F("Network connected")); |
|||
} |
|||
break; |
|||
|
|||
case SYSTEM_EVENT_STA_GOT_IP: |
|||
[[fallthrough]]; |
|||
case ARDUINO_EVENT_ETH_GOT_IP: |
|||
mStatus = NetworkState::GOT_IP; |
|||
break; |
|||
|
|||
case ARDUINO_EVENT_WIFI_STA_LOST_IP: |
|||
[[fallthrough]]; |
|||
case ARDUINO_EVENT_WIFI_STA_STOP: |
|||
[[fallthrough]]; |
|||
case SYSTEM_EVENT_STA_DISCONNECTED: |
|||
[[fallthrough]]; |
|||
case ARDUINO_EVENT_ETH_STOP: |
|||
[[fallthrough]]; |
|||
case ARDUINO_EVENT_ETH_DISCONNECTED: |
|||
mStatus = NetworkState::DISCONNECTED; |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
private: |
|||
void sendNTPpacket(IPAddress& address) { |
|||
//DPRINTLN(DBG_VERBOSE, F("wifi::sendNTPpacket"));
|
|||
uint8_t buf[NTP_PACKET_SIZE]; |
|||
memset(buf, 0, NTP_PACKET_SIZE); |
|||
|
|||
buf[0] = 0b11100011; // LI, Version, Mode
|
|||
buf[1] = 0; // Stratum
|
|||
buf[2] = 6; // Max Interval between messages in seconds
|
|||
buf[3] = 0xEC; // Clock Precision
|
|||
// bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset
|
|||
buf[12] = 49; // four-byte reference ID identifying
|
|||
buf[13] = 0x4E; |
|||
buf[14] = 49; |
|||
buf[15] = 52; |
|||
|
|||
//mUdp.beginPacket(address, 123); // NTP request, port 123
|
|||
mUdp.write(buf, NTP_PACKET_SIZE); |
|||
//mUdp.endPacket();
|
|||
} |
|||
|
|||
void handleNTPPacket(AsyncUDPPacket packet) { |
|||
char buf[80]; |
|||
|
|||
memcpy(buf, packet.data(), sizeof(buf)); |
|||
|
|||
unsigned long highWord = word(buf[40], buf[41]); |
|||
unsigned long lowWord = word(buf[42], buf[43]); |
|||
|
|||
// combine the four bytes (two words) into a long integer
|
|||
// this is NTP time (seconds since Jan 1 1900):
|
|||
unsigned long secsSince1900 = highWord << 16 | lowWord; |
|||
|
|||
*mUtcTimestamp = secsSince1900 - 2208988800UL; // UTC time
|
|||
DPRINTLN(DBG_INFO, "[NTP]: " + ah::getDateTimeStr(*mUtcTimestamp) + " UTC"); |
|||
mOnTimeCB(true); |
|||
mUdp.close(); |
|||
} |
|||
|
|||
protected: |
|||
enum class NetworkState : uint8_t { |
|||
DISCONNECTED, |
|||
CONNECTING, |
|||
CONNECTED, |
|||
IN_AP_MODE, |
|||
GOT_IP, |
|||
IN_STA_MODE, |
|||
RESET, |
|||
SCAN_READY |
|||
}; |
|||
|
|||
protected: |
|||
settings_t *mConfig = nullptr; |
|||
uint32_t *mUtcTimestamp = nullptr; |
|||
|
|||
OnNetworkCB mOnNetworkCB; |
|||
OnTimeCB mOnTimeCB; |
|||
|
|||
NetworkState mStatus = NetworkState.DISCONNECTED; |
|||
|
|||
WiFiUDP mUdp; // for time server
|
|||
DNSServer mDns; |
|||
}; |
|||
|
|||
#endif /*__AHOY_NETWORK_H__*/ |
@ -0,0 +1,29 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2024 Ahoy, https://ahoydtu.de
|
|||
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
#ifndef __AHOY_NETWORK_HELPER_H__ |
|||
#define __AHOY_NETWORK_HELPER_H__ |
|||
|
|||
#include "../utils/dbg.h" |
|||
#include <Arduino.h> |
|||
#include <WiFiType.h> |
|||
#include <WiFi.h> |
|||
#include <DNSServer.h> |
|||
|
|||
namespace ah { |
|||
void welcome(String ip, String info) { |
|||
DBGPRINTLN(F("\n\n-------------------")); |
|||
DBGPRINTLN(F("Welcome to AHOY!")); |
|||
DBGPRINT(F("\npoint your browser to http://")); |
|||
DBGPRINT(ip); |
|||
DBGPRINT(" ("); |
|||
DBGPRINT(info); |
|||
DBGPRINTLN(")"); |
|||
DBGPRINTLN(F("to configure your device")); |
|||
DBGPRINTLN(F("-------------------\n")); |
|||
} |
|||
} |
|||
|
|||
#endif /*__AHOY_NETWORK_HELPER_H__*/ |
@ -0,0 +1,70 @@ |
|||
//-----------------------------------------------------------------------------
|
|||
// 2024 Ahoy, https://ahoydtu.de
|
|||
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|||
//-----------------------------------------------------------------------------
|
|||
|
|||
#ifndef __AHOY_WIFI_AP_H__ |
|||
#define __AHOY_WIFI_AP_H__ |
|||
|
|||
#include "../utils/dbg.h" |
|||
#include <Arduino.h> |
|||
#include "../config/settings.h" |
|||
#include "AhoyNetworkHelper.h" |
|||
|
|||
class AhoyWifiAp { |
|||
public: |
|||
AhoyWifiAp() : mIp(192, 168, 4, 1) {} |
|||
|
|||
void setup(cfgSys_t *cfg) { |
|||
mCfg = cfg; |
|||
} |
|||
|
|||
void tickLoop() { |
|||
if(mEnabled) |
|||
mDns.processNextRequest(); |
|||
} |
|||
|
|||
void enable() { |
|||
ah::welcome(mIp.toString(), String(F("Password: ") + String(mCfg->apPwd))); |
|||
if('\0' == mCfg->deviceName[0]) |
|||
snprintf(mCfg->deviceName, DEVNAME_LEN, "%s", DEF_DEVICE_NAME); |
|||
WiFi.hostname(mCfg->deviceName); |
|||
|
|||
#if defined(ETHERNET) |
|||
WiFi.mode(WIFI_AP); |
|||
#else |
|||
WiFi.mode(WIFI_AP_STA); |
|||
#endif |
|||
WiFi.softAPConfig(mIp, mIp, IPAddress(255, 255, 255, 0)); |
|||
WiFi.softAP(WIFI_AP_SSID, mCfg->apPwd); |
|||
|
|||
mDns.start(53, "*", mIp); |
|||
|
|||
mEnabled = true; |
|||
tickLoop(); |
|||
} |
|||
|
|||
void disable() { |
|||
mDns.stop(); |
|||
WiFi.softAPdisconnect(); |
|||
#if defined(ETHERNET) |
|||
WiFi.mode(WIFI_OFF); |
|||
#else |
|||
WiFi.mode(WIFI_STA); |
|||
#endif |
|||
|
|||
mEnabled = false; |
|||
} |
|||
|
|||
bool getEnable() const { |
|||
return mEnabled; |
|||
} |
|||
|
|||
private: |
|||
cfgSys_t *mCfg = nullptr; |
|||
DNSServer mDns; |
|||
IPAddress mIp; |
|||
bool mEnabled = false; |
|||
}; |
|||
|
|||
#endif /*__AHOY_WIFI_AP_H__*/ |
Loading…
Reference in new issue