mirror of https://github.com/lumapu/ahoy.git
lumapu
11 months ago
16 changed files with 238 additions and 983 deletions
@ -1,179 +0,0 @@ |
|||||
//-----------------------------------------------------------------------------
|
|
||||
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
|
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
|
|
||||
#if defined(ETHERNET) |
|
||||
|
|
||||
#if defined(ESP32) && defined(F) |
|
||||
#undef F |
|
||||
#define F(sl) (sl) |
|
||||
#endif |
|
||||
#include "ahoyeth.h" |
|
||||
#include <ESPmDNS.h> |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
ahoyeth::ahoyeth() |
|
||||
{ |
|
||||
// WiFi.onEvent(ESP32_W5500_event);
|
|
||||
} |
|
||||
|
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoyeth::setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB) { |
|
||||
mConfig = config; |
|
||||
mUtcTimestamp = utcTimestamp; |
|
||||
mOnNetworkCB = onNetworkCB; |
|
||||
mOnTimeCB = onTimeCB; |
|
||||
mEthConnected = false; |
|
||||
|
|
||||
Serial.flush(); |
|
||||
WiFi.onEvent([this](WiFiEvent_t event, arduino_event_info_t info) -> void { this->onEthernetEvent(event, info); }); |
|
||||
|
|
||||
Serial.flush(); |
|
||||
mEthSpi.begin(config->sys.eth.pinMiso, config->sys.eth.pinMosi, config->sys.eth.pinSclk, config->sys.eth.pinCs, config->sys.eth.pinIrq, config->sys.eth.pinRst); |
|
||||
|
|
||||
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!")); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
bool ahoyeth::updateNtpTime(void) { |
|
||||
if (!ETH.localIP()) |
|
||||
return false; |
|
||||
|
|
||||
DPRINTLN(DBG_DEBUG, F("updateNtpTime: checking udp \"connection\"...")); Serial.flush(); |
|
||||
if (!mUdp.connected()) { |
|
||||
DPRINTLN(DBG_DEBUG, F("updateNtpTime: About to (re)connect...")); Serial.flush(); |
|
||||
IPAddress timeServer; |
|
||||
if (!WiFi.hostByName(mConfig->ntp.addr, timeServer)) |
|
||||
return false; |
|
||||
|
|
||||
if (!mUdp.connect(timeServer, mConfig->ntp.port)) |
|
||||
return false; |
|
||||
|
|
||||
DPRINTLN(DBG_DEBUG, F("updateNtpTime: Connected...")); Serial.flush(); |
|
||||
mUdp.onPacket([this](AsyncUDPPacket packet) { |
|
||||
DPRINTLN(DBG_DEBUG, F("updateNtpTime: about to handle ntp packet...")); Serial.flush(); |
|
||||
this->handleNTPPacket(packet); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
DPRINTLN(DBG_DEBUG, F("updateNtpTime: prepare packet...")); Serial.flush(); |
|
||||
|
|
||||
// set all bytes in the buffer to 0
|
|
||||
memset(mUdpPacketBuffer, 0, NTP_PACKET_SIZE); |
|
||||
// Initialize values needed to form NTP request
|
|
||||
// (see URL above for details on the packets)
|
|
||||
|
|
||||
mUdpPacketBuffer[0] = 0b11100011; // LI, Version, Mode
|
|
||||
mUdpPacketBuffer[1] = 0; // Stratum, or type of clock
|
|
||||
mUdpPacketBuffer[2] = 6; // Polling Interval
|
|
||||
mUdpPacketBuffer[3] = 0xEC; // Peer Clock Precision
|
|
||||
|
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
|
||||
mUdpPacketBuffer[12] = 49; |
|
||||
mUdpPacketBuffer[13] = 0x4E; |
|
||||
mUdpPacketBuffer[14] = 49; |
|
||||
mUdpPacketBuffer[15] = 52; |
|
||||
|
|
||||
//Send unicast
|
|
||||
DPRINTLN(DBG_DEBUG, F("updateNtpTime: send packet...")); Serial.flush(); |
|
||||
mUdp.write(mUdpPacketBuffer, sizeof(mUdpPacketBuffer)); |
|
||||
|
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoyeth::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); |
|
||||
} |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoyeth::welcome(String ip, String mode) { |
|
||||
DBGPRINTLN(F("\n\n--------------------------------")); |
|
||||
DBGPRINTLN(F("Welcome to AHOY!")); |
|
||||
DBGPRINT(F("\npoint your browser to http://")); |
|
||||
DBGPRINT(ip); |
|
||||
DBGPRINTLN(mode); |
|
||||
DBGPRINTLN(F("to configure your device")); |
|
||||
DBGPRINTLN(F("--------------------------------\n")); |
|
||||
} |
|
||||
|
|
||||
void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) { |
|
||||
DPRINTLN(DBG_VERBOSE, F("[ETH]: Got event...")); |
|
||||
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) { |
|
||||
/*DPRINT(DBG_INFO, F("ETH MAC: "));
|
|
||||
DBGPRINT(mEthSpi.macAddress());*/ |
|
||||
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 /* defined(ETHERNET) */ |
|
@ -1,65 +0,0 @@ |
|||||
//-----------------------------------------------------------------------------
|
|
||||
// 2024 Ahoy, https://github.com/lumpapu/ahoy
|
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
|
|
||||
#if defined(ETHERNET) |
|
||||
#ifndef __AHOYETH_H__ |
|
||||
#define __AHOYETH_H__ |
|
||||
|
|
||||
#include <functional> |
|
||||
|
|
||||
#include "../utils/dbg.h" |
|
||||
#include <Arduino.h> |
|
||||
#include <AsyncUDP.h> |
|
||||
#include <DNSServer.h> |
|
||||
|
|
||||
#include "ethSpi.h" |
|
||||
#include <ETH.h> |
|
||||
#include "../utils/dbg.h" |
|
||||
#include "../config/config.h" |
|
||||
#include "../config/settings.h" |
|
||||
|
|
||||
|
|
||||
class app; |
|
||||
|
|
||||
#define NTP_PACKET_SIZE 48 |
|
||||
|
|
||||
class ahoyeth { |
|
||||
public: /* types */ |
|
||||
typedef std::function<void(bool)> OnNetworkCB; |
|
||||
typedef std::function<void(bool)> OnTimeCB; |
|
||||
|
|
||||
public: |
|
||||
ahoyeth(); |
|
||||
|
|
||||
void setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNetworkCB, OnTimeCB onTimeCB); |
|
||||
bool updateNtpTime(void); |
|
||||
|
|
||||
private: |
|
||||
void setupEthernet(); |
|
||||
|
|
||||
void handleNTPPacket(AsyncUDPPacket packet); |
|
||||
|
|
||||
void welcome(String ip, String mode); |
|
||||
|
|
||||
void onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info); |
|
||||
|
|
||||
private: |
|
||||
//#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
|
||||
EthSpi mEthSpi; |
|
||||
//#endif
|
|
||||
settings_t *mConfig = nullptr; |
|
||||
|
|
||||
uint32_t *mUtcTimestamp; |
|
||||
AsyncUDP mUdp; // for time server
|
|
||||
byte mUdpPacketBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
|
|
||||
|
|
||||
OnNetworkCB mOnNetworkCB; |
|
||||
OnTimeCB mOnTimeCB; |
|
||||
bool mEthConnected; |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
#endif /*__AHOYETH_H__*/ |
|
||||
#endif /* defined(ETHERNET) */ |
|
@ -0,0 +1,20 @@ |
|||||
|
//-----------------------------------------------------------------------------
|
||||
|
// 2024 Ahoy, https://ahoydtu.de
|
||||
|
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
||||
|
//-----------------------------------------------------------------------------
|
||||
|
|
||||
|
#include "AhoyNetworkHelper.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")); |
||||
|
} |
||||
|
} |
@ -0,0 +1,112 @@ |
|||||
|
//-----------------------------------------------------------------------------
|
||||
|
// 2024 Ahoy, https://ahoydtu.de
|
||||
|
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
||||
|
//-----------------------------------------------------------------------------
|
||||
|
|
||||
|
#ifndef __AHOY_Wifi_ESP32_H__ |
||||
|
#define __AHOY_Wifi_ESP32_H__ |
||||
|
|
||||
|
#if defined(ESP32) && !defined(ETHERNET) |
||||
|
#include <functional> |
||||
|
#include <AsyncUDP.h> |
||||
|
#include <Wifi.h> |
||||
|
#include "AhoyNetwork.h" |
||||
|
|
||||
|
class AhoyWifi : public AhoyNetwork { |
||||
|
public: |
||||
|
void begin() override { |
||||
|
mAp.enable(); |
||||
|
|
||||
|
// static IP
|
||||
|
setupIp([this](IPAddress ip, IPAddress gateway, IPAddress mask, IPAddress dns1, IPAddress dns2) -> bool { |
||||
|
return WiFi.config(ip, gateway, mask, dns1, dns2); |
||||
|
}); |
||||
|
|
||||
|
WiFi.setHostname(mConfig->sys.deviceName); |
||||
|
WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); |
||||
|
WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); |
||||
|
WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, WIFI_ALL_CHANNEL_SCAN); |
||||
|
|
||||
|
DBGPRINT(F("connect to network '")); Serial.flush(); |
||||
|
DBGPRINT(mConfig->sys.stationSsid); |
||||
|
} |
||||
|
|
||||
|
void tickNetworkLoop() override { |
||||
|
if(mAp.isEnabled()) |
||||
|
mAp.tickLoop(); |
||||
|
|
||||
|
switch(mStatus) { |
||||
|
case NetworkState::DISCONNECTED: |
||||
|
if(mConnected) { |
||||
|
mConnected = false; |
||||
|
mOnNetworkCB(false); |
||||
|
mAp.enable(); |
||||
|
} |
||||
|
|
||||
|
if (WiFi.softAPgetStationNum() > 0) { |
||||
|
DBGPRINTLN(F("AP client connected")); |
||||
|
} |
||||
|
break; |
||||
|
|
||||
|
case NetworkState::CONNECTED: |
||||
|
break; |
||||
|
|
||||
|
case NetworkState::GOT_IP: |
||||
|
if(!mConnected) { |
||||
|
mAp.disable(); |
||||
|
mConnected = true; |
||||
|
ah::welcome(WiFi.localIP().toString(), F("Station")); |
||||
|
MDNS.begin(mConfig->sys.deviceName); |
||||
|
mOnNetworkCB(true); |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
String getIp(void) override { |
||||
|
return WiFi.localIP().toString(); |
||||
|
} |
||||
|
|
||||
|
void scanAvailNetworks(void) override { |
||||
|
if(!mScanActive) { |
||||
|
mScanActive = true; |
||||
|
WiFi.scanNetworks(true); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool getAvailNetworks(JsonObject obj) override { |
||||
|
JsonArray nets = obj.createNestedArray(F("networks")); |
||||
|
|
||||
|
int n = WiFi.scanComplete(); |
||||
|
if (n < 0) |
||||
|
return false; |
||||
|
if(n > 0) { |
||||
|
int sort[n]; |
||||
|
sortRSSI(&sort[0], n); |
||||
|
for (int i = 0; i < n; ++i) { |
||||
|
nets[i][F("ssid")] = WiFi.SSID(sort[i]); |
||||
|
nets[i][F("rssi")] = WiFi.RSSI(sort[i]); |
||||
|
} |
||||
|
} |
||||
|
mScanActive = false; |
||||
|
WiFi.scanDelete(); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
void sortRSSI(int *sort, int n) { |
||||
|
for (int i = 0; i < n; i++) |
||||
|
sort[i] = i; |
||||
|
for (int i = 0; i < n; i++) |
||||
|
for (int j = i + 1; j < n; j++) |
||||
|
if (WiFi.RSSI(sort[j]) > WiFi.RSSI(sort[i])) |
||||
|
std::swap(sort[i], sort[j]); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
bool mScanActive = false; |
||||
|
}; |
||||
|
|
||||
|
#endif /*ESP32 & !ETHERNET*/ |
||||
|
#endif /*__AHOY_Wifi_ESP32_H__*/ |
@ -1,490 +0,0 @@ |
|||||
//-----------------------------------------------------------------------------
|
|
||||
// 2024 Ahoy, https://ahoydtu.de
|
|
||||
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
|
|
||||
#if !defined(ETHERNET) |
|
||||
#if defined(ESP32) && defined(F) |
|
||||
#undef F |
|
||||
#define F(sl) (sl) |
|
||||
#endif |
|
||||
#include "ahoywifi.h" |
|
||||
|
|
||||
#if defined(ESP32) |
|
||||
#include <ESPmDNS.h> |
|
||||
#else |
|
||||
#include <ESP8266mDNS.h> |
|
||||
#endif |
|
||||
|
|
||||
// NTP CONFIG
|
|
||||
#define NTP_PACKET_SIZE 48 |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
ahoywifi::ahoywifi() : mApIp(192, 168, 4, 1) {} |
|
||||
|
|
||||
|
|
||||
/**
|
|
||||
* TODO: ESP32 has native strongest AP support! |
|
||||
* WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); |
|
||||
WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); |
|
||||
*/ |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb, OnTimeCB onTimeCb) { |
|
||||
mConfig = config; |
|
||||
mUtcTimestamp = utcTimestamp; |
|
||||
mAppWifiCb = cb; |
|
||||
mOnTimeCb = onTimeCb; |
|
||||
|
|
||||
mGotDisconnect = false; |
|
||||
mStaConn = DISCONNECTED; |
|
||||
mCnt = 0; |
|
||||
mScanActive = false; |
|
||||
mScanCnt = 0; |
|
||||
mStopApAllowed = true; |
|
||||
|
|
||||
#if defined(ESP8266) |
|
||||
wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1)); |
|
||||
wifiGotIPHandler = WiFi.onStationModeGotIP(std::bind(&ahoywifi::onGotIP, this, std::placeholders::_1)); |
|
||||
wifiDisconnectHandler = WiFi.onStationModeDisconnected(std::bind(&ahoywifi::onDisconnect, this, std::placeholders::_1)); |
|
||||
#else |
|
||||
WiFi.onEvent(std::bind(&ahoywifi::onWiFiEvent, this, std::placeholders::_1)); |
|
||||
#endif |
|
||||
|
|
||||
setupWifi(true); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoywifi::setupWifi(bool startAP = false) { |
|
||||
#if !defined(FB_WIFI_OVERRIDDEN) |
|
||||
if(startAP) { |
|
||||
setupAp(); |
|
||||
delay(1000); |
|
||||
} |
|
||||
#endif |
|
||||
#if !defined(AP_ONLY) |
|
||||
#if defined(FB_WIFI_OVERRIDDEN) |
|
||||
snprintf(mConfig->sys.stationSsid, SSID_LEN, "%s", FB_WIFI_SSID); |
|
||||
snprintf(mConfig->sys.stationPwd, PWD_LEN, "%s", FB_WIFI_PWD); |
|
||||
setupStation(); |
|
||||
#else |
|
||||
if(mConfig->valid) { |
|
||||
if(strncmp(mConfig->sys.stationSsid, FB_WIFI_SSID, 14) != 0) |
|
||||
setupStation(); |
|
||||
} |
|
||||
#endif |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
|
|
||||
void ahoywifi::tickWifiLoop() { |
|
||||
static const uint8_t TIMEOUT = 20; |
|
||||
static const uint8_t SCAN_TIMEOUT = 10; |
|
||||
#if !defined(AP_ONLY) |
|
||||
|
|
||||
mCnt++; |
|
||||
|
|
||||
switch (mStaConn) { |
|
||||
case IN_STA_MODE: |
|
||||
// Nothing to do
|
|
||||
if (mGotDisconnect) { |
|
||||
mStaConn = RESET; |
|
||||
} |
|
||||
#if !defined(ESP32) |
|
||||
MDNS.update(); |
|
||||
if(WiFi.channel() > 11) |
|
||||
mWasInCh12to14 = true; |
|
||||
#endif |
|
||||
return; |
|
||||
case IN_AP_MODE: |
|
||||
if ((WiFi.softAPgetStationNum() == 0) || (!mStopApAllowed)) { |
|
||||
mCnt = 0; |
|
||||
mDns.stop(); |
|
||||
WiFi.mode(WIFI_AP_STA); |
|
||||
mStaConn = DISCONNECTED; |
|
||||
} else { |
|
||||
mDns.processNextRequest(); |
|
||||
return; |
|
||||
} |
|
||||
break; |
|
||||
case DISCONNECTED: |
|
||||
if ((WiFi.softAPgetStationNum() > 0) && (mStopApAllowed)) { |
|
||||
mStaConn = IN_AP_MODE; |
|
||||
// first time switch to AP Mode
|
|
||||
if (mScanActive) { |
|
||||
WiFi.scanDelete(); |
|
||||
mScanActive = false; |
|
||||
} |
|
||||
DBGPRINTLN(F("AP client connected")); |
|
||||
welcome(mApIp.toString(), ""); |
|
||||
WiFi.mode(WIFI_AP); |
|
||||
mDns.start(53, "*", mApIp); |
|
||||
mAppWifiCb(true); |
|
||||
mDns.processNextRequest(); |
|
||||
return; |
|
||||
} else if (!mScanActive) { |
|
||||
DBGPRINT(F("scanning APs with SSID ")); |
|
||||
DBGPRINTLN(String(mConfig->sys.stationSsid)); |
|
||||
mScanCnt = 0; |
|
||||
mCnt = 0; |
|
||||
mScanActive = true; |
|
||||
#if defined(ESP8266) |
|
||||
WiFi.scanNetworks(true, true, 0U, ([this]() { |
|
||||
if (mConfig->sys.isHidden) |
|
||||
return (uint8_t*)NULL; |
|
||||
return (uint8_t*)(mConfig->sys.stationSsid); |
|
||||
})()); |
|
||||
#else |
|
||||
WiFi.scanNetworks(true, true, false, 300U, 0U, ([this]() { |
|
||||
if (mConfig->sys.isHidden) |
|
||||
return (char*)NULL; |
|
||||
return (mConfig->sys.stationSsid); |
|
||||
})()); |
|
||||
#endif |
|
||||
return; |
|
||||
} else if(getBSSIDs()) { |
|
||||
// Scan ready
|
|
||||
mStaConn = SCAN_READY; |
|
||||
} else { |
|
||||
// In case of a timeout, what do we do?
|
|
||||
// For now we start scanning again as the original code did.
|
|
||||
// Would be better to into PA mode
|
|
||||
|
|
||||
if (isTimeout(SCAN_TIMEOUT)) { |
|
||||
WiFi.scanDelete(); |
|
||||
mScanActive = false; |
|
||||
} |
|
||||
} |
|
||||
break; |
|
||||
case SCAN_READY: |
|
||||
mStaConn = CONNECTING; |
|
||||
mCnt = 0; |
|
||||
DBGPRINT(F("try to connect to AP with BSSID:")); |
|
||||
uint8_t bssid[6]; |
|
||||
for (int j = 0; j < 6; j++) { |
|
||||
bssid[j] = mBSSIDList.front(); |
|
||||
mBSSIDList.pop_front(); |
|
||||
DBGPRINT(" " + String(bssid[j], HEX)); |
|
||||
} |
|
||||
DBGPRINTLN(""); |
|
||||
mGotDisconnect = false; |
|
||||
WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, 0, &bssid[0]); |
|
||||
|
|
||||
break; |
|
||||
case CONNECTING: |
|
||||
if (isTimeout(TIMEOUT)) { |
|
||||
WiFi.disconnect(); |
|
||||
mStaConn = mBSSIDList.empty() ? DISCONNECTED : SCAN_READY; |
|
||||
} |
|
||||
break; |
|
||||
case CONNECTED: |
|
||||
// Connection but no IP yet
|
|
||||
if (isTimeout(TIMEOUT) || mGotDisconnect) { |
|
||||
mStaConn = RESET; |
|
||||
} |
|
||||
break; |
|
||||
case GOT_IP: |
|
||||
welcome(WiFi.localIP().toString(), F(" (Station)")); |
|
||||
if(mStopApAllowed) { |
|
||||
WiFi.softAPdisconnect(); |
|
||||
WiFi.mode(WIFI_STA); |
|
||||
DBGPRINTLN(F("[WiFi] AP disabled")); |
|
||||
delay(100); |
|
||||
} |
|
||||
mAppWifiCb(true); |
|
||||
mGotDisconnect = false; |
|
||||
mStaConn = IN_STA_MODE; |
|
||||
|
|
||||
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 RESET: |
|
||||
mGotDisconnect = false; |
|
||||
mStaConn = DISCONNECTED; |
|
||||
mCnt = 5; // try to reconnect in 5 sec
|
|
||||
setupWifi(); // reconnect with AP / Station setup
|
|
||||
mAppWifiCb(false); |
|
||||
DPRINTLN(DBG_INFO, "[WiFi] Connection Lost"); |
|
||||
break; |
|
||||
default: |
|
||||
DBGPRINTLN(F("Unhandled status")); |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoywifi::setupAp(void) { |
|
||||
DPRINTLN(DBG_VERBOSE, F("wifi::setupAp")); |
|
||||
|
|
||||
DBGPRINTLN(F("\n---------\nAhoyDTU Info:")); |
|
||||
DBGPRINT(F("Version: ")); |
|
||||
DBGPRINT(String(VERSION_MAJOR)); |
|
||||
DBGPRINT(F(".")); |
|
||||
DBGPRINT(String(VERSION_MINOR)); |
|
||||
DBGPRINT(F(".")); |
|
||||
DBGPRINTLN(String(VERSION_PATCH)); |
|
||||
DBGPRINT(F("Github Hash: ")); |
|
||||
DBGPRINTLN(String(AUTO_GIT_HASH)); |
|
||||
|
|
||||
DBGPRINT(F("\n---------\nAP MODE\nSSID: ")); |
|
||||
DBGPRINTLN(WIFI_AP_SSID); |
|
||||
DBGPRINT(F("PWD: ")); |
|
||||
DBGPRINTLN(mConfig->sys.apPwd); |
|
||||
DBGPRINT(F("IP Address: http://")); |
|
||||
DBGPRINTLN(mApIp.toString()); |
|
||||
DBGPRINTLN(F("---------\n")); |
|
||||
|
|
||||
if(String(mConfig->sys.deviceName) != "") |
|
||||
WiFi.hostname(mConfig->sys.deviceName); |
|
||||
|
|
||||
WiFi.mode(WIFI_AP_STA); |
|
||||
WiFi.softAPConfig(mApIp, mApIp, IPAddress(255, 255, 255, 0)); |
|
||||
WiFi.softAP(WIFI_AP_SSID, mConfig->sys.apPwd); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoywifi::setupStation(void) { |
|
||||
DPRINTLN(DBG_VERBOSE, F("wifi::setupStation")); |
|
||||
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(!WiFi.config(ip, gateway, mask, dns1, dns2)) |
|
||||
DPRINTLN(DBG_ERROR, F("failed to set static IP!")); |
|
||||
} |
|
||||
mBSSIDList.clear(); |
|
||||
if(String(mConfig->sys.deviceName) != "") |
|
||||
WiFi.hostname(mConfig->sys.deviceName); |
|
||||
WiFi.mode(WIFI_AP_STA); |
|
||||
|
|
||||
DBGPRINT(F("connect to network '")); |
|
||||
DBGPRINT(mConfig->sys.stationSsid); |
|
||||
DBGPRINTLN(F("' ...")); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
bool ahoywifi::updateNtpTime(void) { |
|
||||
if(IN_STA_MODE != mStaConn) |
|
||||
return false; |
|
||||
|
|
||||
IPAddress timeServer; |
|
||||
uint8_t buf[NTP_PACKET_SIZE]; |
|
||||
uint8_t retry = 0; |
|
||||
|
|
||||
if (WiFi.hostByName(mConfig->ntp.addr, timeServer) != 1) |
|
||||
return false; |
|
||||
|
|
||||
mUdp.begin(mConfig->ntp.port); |
|
||||
sendNTPpacket(timeServer); |
|
||||
|
|
||||
while(retry++ < 5) { |
|
||||
int wait = 150; |
|
||||
while(--wait) { |
|
||||
if(NTP_PACKET_SIZE <= mUdp.parsePacket()) { |
|
||||
uint64_t secsSince1900; |
|
||||
mUdp.read(buf, NTP_PACKET_SIZE); |
|
||||
secsSince1900 = ((uint64_t)buf[40] << 24); |
|
||||
secsSince1900 |= (buf[41] << 16); |
|
||||
secsSince1900 |= (buf[42] << 8); |
|
||||
secsSince1900 |= (buf[43] ); |
|
||||
|
|
||||
*mUtcTimestamp = secsSince1900 - 2208988800UL; // UTC time
|
|
||||
DPRINTLN(DBG_INFO, "[NTP]: " + ah::getDateTimeStr(*mUtcTimestamp) + " UTC"); |
|
||||
mOnTimeCb(true); |
|
||||
return true; |
|
||||
} else |
|
||||
delay(10); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
DPRINTLN(DBG_INFO, F("[NTP]: getNtpTime failed")); |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoywifi::sendNTPpacket(IPAddress& address) { |
|
||||
//DPRINTLN(DBG_VERBOSE, F("wifi::sendNTPpacket"));
|
|
||||
uint8_t buf[NTP_PACKET_SIZE] = {0}; |
|
||||
|
|
||||
buf[0] = B11100011; // 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 ahoywifi::sortRSSI(int *sort, int n) { |
|
||||
for (int i = 0; i < n; i++) |
|
||||
sort[i] = i; |
|
||||
for (int i = 0; i < n; i++) |
|
||||
for (int j = i + 1; j < n; j++) |
|
||||
if (WiFi.RSSI(sort[j]) > WiFi.RSSI(sort[i])) |
|
||||
std::swap(sort[i], sort[j]); |
|
||||
} |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoywifi::scanAvailNetworks(void) { |
|
||||
if(!mScanActive) { |
|
||||
mScanActive = true; |
|
||||
if(WIFI_AP == WiFi.getMode()) |
|
||||
WiFi.mode(WIFI_AP_STA); |
|
||||
WiFi.scanNetworks(true); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
bool ahoywifi::getAvailNetworks(JsonObject obj) { |
|
||||
JsonArray nets = obj.createNestedArray("networks"); |
|
||||
|
|
||||
int n = WiFi.scanComplete(); |
|
||||
if (n < 0) |
|
||||
return false; |
|
||||
if(n > 0) { |
|
||||
int sort[n]; |
|
||||
sortRSSI(&sort[0], n); |
|
||||
for (int i = 0; i < n; ++i) { |
|
||||
nets[i]["ssid"] = WiFi.SSID(sort[i]); |
|
||||
nets[i]["rssi"] = WiFi.RSSI(sort[i]); |
|
||||
} |
|
||||
} |
|
||||
mScanActive = false; |
|
||||
WiFi.scanDelete(); |
|
||||
if(mStaConn == IN_AP_MODE) |
|
||||
WiFi.mode(WIFI_AP); |
|
||||
|
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
bool ahoywifi::getBSSIDs() { |
|
||||
bool result = false; |
|
||||
int n = WiFi.scanComplete(); |
|
||||
if (n < 0) { |
|
||||
if (++mScanCnt < 20) |
|
||||
return false; |
|
||||
} |
|
||||
if(n > 0) { |
|
||||
mBSSIDList.clear(); |
|
||||
int sort[n]; |
|
||||
sortRSSI(&sort[0], n); |
|
||||
for (int i = 0; i < n; i++) { |
|
||||
DBGPRINT("BSSID " + String(i) + ":"); |
|
||||
uint8_t *bssid = WiFi.BSSID(sort[i]); |
|
||||
for (int j = 0; j < 6; j++){ |
|
||||
DBGPRINT(" " + String(bssid[j], HEX)); |
|
||||
mBSSIDList.push_back(bssid[j]); |
|
||||
} |
|
||||
DBGPRINTLN(""); |
|
||||
} |
|
||||
result = true; |
|
||||
} |
|
||||
mScanActive = false; |
|
||||
WiFi.scanDelete(); |
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoywifi::connectionEvent(WiFiStatus_t status) { |
|
||||
DPRINTLN(DBG_INFO, "connectionEvent"); |
|
||||
|
|
||||
switch(status) { |
|
||||
case CONNECTED: |
|
||||
if(mStaConn != CONNECTED) { |
|
||||
mStaConn = CONNECTED; |
|
||||
mGotDisconnect = false; |
|
||||
DBGPRINTLN(F("\n[WiFi] Connected")); |
|
||||
} |
|
||||
break; |
|
||||
|
|
||||
case GOT_IP: |
|
||||
mStaConn = GOT_IP; |
|
||||
break; |
|
||||
|
|
||||
case DISCONNECTED: |
|
||||
mGotDisconnect = true; |
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
#if defined(ESP8266) |
|
||||
//-------------------------------------------------------------------------
|
|
||||
void ahoywifi::onConnect(const WiFiEventStationModeConnected& event) { |
|
||||
connectionEvent(CONNECTED); |
|
||||
} |
|
||||
|
|
||||
//-------------------------------------------------------------------------
|
|
||||
void ahoywifi::onGotIP(const WiFiEventStationModeGotIP& event) { |
|
||||
connectionEvent(GOT_IP); |
|
||||
} |
|
||||
|
|
||||
//-------------------------------------------------------------------------
|
|
||||
void ahoywifi::onDisconnect(const WiFiEventStationModeDisconnected& event) { |
|
||||
connectionEvent(DISCONNECTED); |
|
||||
} |
|
||||
|
|
||||
#else |
|
||||
//-------------------------------------------------------------------------
|
|
||||
void ahoywifi::onWiFiEvent(WiFiEvent_t event) { |
|
||||
DBGPRINT(F("Wifi event: ")); |
|
||||
DBGPRINTLN(String(event)); |
|
||||
|
|
||||
switch(event) { |
|
||||
case SYSTEM_EVENT_STA_CONNECTED: |
|
||||
connectionEvent(CONNECTED); |
|
||||
break; |
|
||||
|
|
||||
case SYSTEM_EVENT_STA_GOT_IP: |
|
||||
connectionEvent(GOT_IP); |
|
||||
break; |
|
||||
|
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED: |
|
||||
connectionEvent(DISCONNECTED); |
|
||||
break; |
|
||||
|
|
||||
default: |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
#endif |
|
||||
|
|
||||
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
void ahoywifi::welcome(String ip, String mode) { |
|
||||
DBGPRINTLN(F("\n\n--------------------------------")); |
|
||||
DBGPRINTLN(F("Welcome to AHOY!")); |
|
||||
DBGPRINT(F("\npoint your browser to http://")); |
|
||||
DBGPRINT(ip); |
|
||||
DBGPRINTLN(mode); |
|
||||
DBGPRINTLN(F("to configure your device")); |
|
||||
DBGPRINTLN(F("--------------------------------\n")); |
|
||||
} |
|
||||
|
|
||||
#endif /* !defined(ETHERNET) */ |
|
@ -1,100 +0,0 @@ |
|||||
//------------------------------------//-----------------------------------------------------------------------------
|
|
||||
// 2024 Ahoy, https://github.com/lumpapu/ahoy
|
|
||||
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
|
|
||||
//-----------------------------------------------------------------------------
|
|
||||
|
|
||||
#if !defined(ETHERNET) |
|
||||
#ifndef __AHOYWIFI_H__ |
|
||||
#define __AHOYWIFI_H__ |
|
||||
|
|
||||
#include "../utils/dbg.h" |
|
||||
#include <Arduino.h> |
|
||||
#include <list> |
|
||||
#include <WiFiUdp.h> |
|
||||
#include <DNSServer.h> |
|
||||
#include "ESPAsyncWebServer.h" |
|
||||
|
|
||||
#include "../config/settings.h" |
|
||||
|
|
||||
class app; |
|
||||
|
|
||||
class ahoywifi { |
|
||||
public: |
|
||||
typedef std::function<void(bool)> appWifiCb; |
|
||||
typedef std::function<void(bool)> OnTimeCB; |
|
||||
|
|
||||
ahoywifi(); |
|
||||
|
|
||||
|
|
||||
void setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb, OnTimeCB onTimeCB); |
|
||||
void tickWifiLoop(void); |
|
||||
bool updateNtpTime(void); |
|
||||
void scanAvailNetworks(void); |
|
||||
bool getAvailNetworks(JsonObject obj); |
|
||||
void setStopApAllowedMode(bool allowed) { |
|
||||
mStopApAllowed = allowed; |
|
||||
} |
|
||||
String getStationIp(void) { |
|
||||
return WiFi.localIP().toString(); |
|
||||
} |
|
||||
void setupStation(void); |
|
||||
|
|
||||
bool getWasInCh12to14() const { |
|
||||
return mWasInCh12to14; |
|
||||
} |
|
||||
|
|
||||
private: |
|
||||
typedef enum WiFiStatus { |
|
||||
DISCONNECTED = 0, |
|
||||
SCAN_READY, |
|
||||
CONNECTING, |
|
||||
CONNECTED, |
|
||||
IN_AP_MODE, |
|
||||
GOT_IP, |
|
||||
IN_STA_MODE, |
|
||||
RESET |
|
||||
} WiFiStatus_t; |
|
||||
|
|
||||
void setupWifi(bool startAP); |
|
||||
void setupAp(void); |
|
||||
void sendNTPpacket(IPAddress& address); |
|
||||
void sortRSSI(int *sort, int n); |
|
||||
bool getBSSIDs(void); |
|
||||
void connectionEvent(WiFiStatus_t status); |
|
||||
bool isTimeout(uint8_t timeout) { return (mCnt % timeout) == 0; } |
|
||||
|
|
||||
#if defined(ESP8266) |
|
||||
void onConnect(const WiFiEventStationModeConnected& event); |
|
||||
void onGotIP(const WiFiEventStationModeGotIP& event); |
|
||||
void onDisconnect(const WiFiEventStationModeDisconnected& event); |
|
||||
#else |
|
||||
void onWiFiEvent(WiFiEvent_t event); |
|
||||
#endif |
|
||||
void welcome(String ip, String mode); |
|
||||
|
|
||||
|
|
||||
settings_t *mConfig = nullptr; |
|
||||
appWifiCb mAppWifiCb; |
|
||||
OnTimeCB mOnTimeCb; |
|
||||
|
|
||||
DNSServer mDns; |
|
||||
IPAddress mApIp; |
|
||||
WiFiUDP mUdp; // for time server
|
|
||||
#if defined(ESP8266) |
|
||||
WiFiEventHandler wifiConnectHandler, wifiDisconnectHandler, wifiGotIPHandler; |
|
||||
#endif |
|
||||
|
|
||||
WiFiStatus_t mStaConn = DISCONNECTED; |
|
||||
uint8_t mCnt = 0; |
|
||||
uint32_t *mUtcTimestamp = nullptr; |
|
||||
|
|
||||
uint8_t mScanCnt = 0; |
|
||||
bool mScanActive = false; |
|
||||
bool mGotDisconnect = false; |
|
||||
std::list<uint8_t> mBSSIDList; |
|
||||
bool mStopApAllowed = false; |
|
||||
bool mWasInCh12to14 = false; |
|
||||
}; |
|
||||
|
|
||||
#endif /*__AHOYWIFI_H__*/ |
|
||||
#endif /* !defined(ETHERNET) */ |
|
Loading…
Reference in new issue