558 lines
16 KiB
C++
Raw Permalink Normal View History

/*
wificonfig.cpp - wifi functions class
Copyright (c) 2014 Luc Lebosse. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef ARDUINO_ARCH_ESP32
#include "config.h"
#ifdef ENABLE_WIFI
#include <WiFi.h>
#include <esp_wifi.h>
#include <ESPmDNS.h>
#include <FS.h>
#include <SPIFFS.h>
#include <Preferences.h>
#include "wificonfig.h"
#include "wifiservices.h"
#include "commands.h"
#include "report.h"
WiFiConfig wifi_config;
String WiFiConfig::_hostname = "";
bool WiFiConfig::_events_registered = false;
WiFiConfig::WiFiConfig(){
}
WiFiConfig::~WiFiConfig(){
end();
}
//just simple helper to convert mac address to string
char * WiFiConfig::mac2str (uint8_t mac [8])
{
static char macstr [18];
if (0 > sprintf (macstr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) ) {
strcpy (macstr, "00:00:00:00:00:00");
}
return macstr;
}
const char *WiFiConfig::info(){
static String result;
String tmp;
result = "[MSG:";
if((WiFi.getMode() == WIFI_MODE_STA ) || (WiFi.getMode() == WIFI_MODE_APSTA )) {
result += "Mode=STA:SSID=";
result += WiFi.SSID();
result += ":Status=";
result += (WiFi.status()==WL_CONNECTED)?"Connected":"Not connected";
result += ":IP=";
result += WiFi.localIP().toString();
result += ":MAC=";
tmp = WiFi.macAddress();
tmp.replace(":","-");
result += tmp;
}
if((WiFi.getMode() == WIFI_MODE_AP ) || (WiFi.getMode() == WIFI_MODE_APSTA )) {
if(WiFi.getMode() == WIFI_MODE_APSTA ) {
result+= "]\r\n[MSG:";
}
result+="Mode=AP:SSDI=";
wifi_config_t conf;
esp_wifi_get_config (ESP_IF_WIFI_AP, &conf);
result+= (const char*)conf.ap.ssid;
result+=":IP=";
result+=WiFi.softAPIP().toString();
result+=":MAC=";
tmp = WiFi.softAPmacAddress();
tmp.replace(":","-");
result += tmp;
}
if(WiFi.getMode() == WIFI_MODE_NULL)result+="No Wifi";
result+= "]\r\n";
return result.c_str();
}
/**
* Helper to convert IP string to int
*/
uint32_t WiFiConfig::IP_int_from_string(String & s){
uint32_t ip_int = 0;
IPAddress ipaddr;
if (ipaddr.fromString(s)) ip_int = ipaddr;
return ip_int;
}
/**
* Helper to convert int to IP string
*/
String WiFiConfig::IP_string_from_int(uint32_t ip_int){
IPAddress ipaddr(ip_int);
return ipaddr.toString();
}
/**
* Check if Hostname string is valid
*/
bool WiFiConfig::isHostnameValid (const char * hostname)
{
//limited size
char c;
if (strlen (hostname) > MAX_HOSTNAME_LENGTH || strlen (hostname) < MIN_HOSTNAME_LENGTH) {
return false;
}
//only letter and digit
for (int i = 0; i < strlen (hostname); i++) {
c = hostname[i];
if (! (isdigit (c) || isalpha (c) || c == '-') ) {
return false;
}
if (c == ' ') {
return false;
}
}
return true;
}
/**
* Check if SSID string is valid
*/
bool WiFiConfig::isSSIDValid (const char * ssid)
{
//limited size
//char c;
if (strlen (ssid) > MAX_SSID_LENGTH || strlen (ssid) < MIN_SSID_LENGTH) {
return false;
}
//only printable
for (int i = 0; i < strlen (ssid); i++) {
if (!isPrintable (ssid[i]) ) {
return false;
}
}
return true;
}
/**
* Check if password string is valid
*/
bool WiFiConfig::isPasswordValid (const char * password)
{
if (strlen (password) == 0) return true; //open network
//limited size
if ((strlen (password) > MAX_PASSWORD_LENGTH) || (strlen (password) < MIN_PASSWORD_LENGTH)) {
return false;
}
//no space allowed ?
/* for (int i = 0; i < strlen (password); i++)
if (password[i] == ' ') {
return false;
}*/
return true;
}
/**
* Check if IP string is valid
*/
bool WiFiConfig::isValidIP(const char * string){
IPAddress ip;
return ip.fromString(string);
}
/**
* WiFi events
* SYSTEM_EVENT_WIFI_READY < ESP32 WiFi ready
* SYSTEM_EVENT_SCAN_DONE < ESP32 finish scanning AP
* SYSTEM_EVENT_STA_START < ESP32 station start
* SYSTEM_EVENT_STA_STOP < ESP32 station stop
* SYSTEM_EVENT_STA_CONNECTED < ESP32 station connected to AP
* SYSTEM_EVENT_STA_DISCONNECTED < ESP32 station disconnected from AP
* SYSTEM_EVENT_STA_AUTHMODE_CHANGE < the auth mode of AP connected by ESP32 station changed
* SYSTEM_EVENT_STA_GOT_IP < ESP32 station got IP from connected AP
* SYSTEM_EVENT_STA_LOST_IP < ESP32 station lost IP and the IP is reset to 0
* SYSTEM_EVENT_STA_WPS_ER_SUCCESS < ESP32 station wps succeeds in enrollee mode
* SYSTEM_EVENT_STA_WPS_ER_FAILED < ESP32 station wps fails in enrollee mode
* SYSTEM_EVENT_STA_WPS_ER_TIMEOUT < ESP32 station wps timeout in enrollee mode
* SYSTEM_EVENT_STA_WPS_ER_PIN < ESP32 station wps pin code in enrollee mode
* SYSTEM_EVENT_AP_START < ESP32 soft-AP start
* SYSTEM_EVENT_AP_STOP < ESP32 soft-AP stop
* SYSTEM_EVENT_AP_STACONNECTED < a station connected to ESP32 soft-AP
* SYSTEM_EVENT_AP_STADISCONNECTED < a station disconnected from ESP32 soft-AP
* SYSTEM_EVENT_AP_PROBEREQRECVED < Receive probe request packet in soft-AP interface
* SYSTEM_EVENT_GOT_IP6 < ESP32 station or ap or ethernet interface v6IP addr is preferred
* SYSTEM_EVENT_ETH_START < ESP32 ethernet start
* SYSTEM_EVENT_ETH_STOP < ESP32 ethernet stop
* SYSTEM_EVENT_ETH_CONNECTED < ESP32 ethernet phy link up
* SYSTEM_EVENT_ETH_DISCONNECTED < ESP32 ethernet phy link down
* SYSTEM_EVENT_ETH_GOT_IP < ESP32 ethernet got IP from connected AP
* SYSTEM_EVENT_MAX
*/
void WiFiConfig::WiFiEvent(WiFiEvent_t event)
{
switch (event)
{
case SYSTEM_EVENT_STA_GOT_IP:
grbl_sendf(CLIENT_ALL,"[MSG:Connected with %s]\r\n",WiFi.localIP().toString().c_str());
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
grbl_send(CLIENT_ALL,"[MSG:Disconnected]\r\n");
break;
default:
break;
}
}
/*
* Get WiFi signal strength
*/
int32_t WiFiConfig::getSignal (int32_t RSSI)
{
if (RSSI <= -100) {
return 0;
}
if (RSSI >= -50) {
return 100;
}
return (2 * (RSSI + 100) );
}
/*
* Connect client to AP
*/
bool WiFiConfig::ConnectSTA2AP(){
String msg, msg_out;
uint8_t count = 0;
uint8_t dot = 0;
wl_status_t status = WiFi.status();
while (status != WL_CONNECTED && count < 40) {
switch (status) {
case WL_NO_SSID_AVAIL:
msg="No SSID";
break;
case WL_CONNECT_FAILED:
msg="Connection failed";
break;
case WL_CONNECTED:
break;
default:
if ((dot>3) || (dot==0) ){
dot=0;
msg_out = "Connecting";
}
msg_out+=".";
msg= msg_out;
dot++;
break;
}
grbl_sendf(CLIENT_ALL,"[MSG:%s]\r\n",msg.c_str());
COMMANDS::wait (500);
count++;
status = WiFi.status();
}
return (status == WL_CONNECTED);
}
/*
* Start client mode (Station)
*/
bool WiFiConfig::StartSTA(){
String defV;
Preferences prefs;
//stop active service
wifi_services.end();
//Sanity check
if((WiFi.getMode() == WIFI_STA) || (WiFi.getMode() == WIFI_AP_STA))WiFi.disconnect();
if((WiFi.getMode() == WIFI_AP) || (WiFi.getMode() == WIFI_AP_STA))WiFi.softAPdisconnect();
WiFi.enableAP (false);
WiFi.mode(WIFI_STA);
//Get parameters for STA
prefs.begin(NAMESPACE, true);
defV = DEFAULT_HOSTNAME;
String h = prefs.getString(HOSTNAME_ENTRY, defV);
WiFi.setHostname(h.c_str());
//SSID
defV = DEFAULT_STA_SSID;
String SSID = prefs.getString(STA_SSID_ENTRY, defV);
if (SSID.length() == 0)SSID = DEFAULT_STA_SSID;
//password
defV = DEFAULT_STA_PWD;
String password = prefs.getString(STA_PWD_ENTRY, defV);
int8_t IP_mode = prefs.getChar(STA_IP_MODE_ENTRY, DHCP_MODE);
//IP
defV = DEFAULT_STA_IP;
int32_t IP = prefs.getInt(STA_IP_ENTRY, IP_int_from_string(defV));
//GW
defV = DEFAULT_STA_GW;
int32_t GW = prefs.getInt(STA_GW_ENTRY, IP_int_from_string(defV));
//MK
defV = DEFAULT_STA_MK;
int32_t MK = prefs.getInt(STA_MK_ENTRY, IP_int_from_string(defV));
prefs.end();
//if not DHCP
if (IP_mode != DHCP_MODE) {
IPAddress ip(IP), mask(MK), gateway(GW);
WiFi.config(ip, gateway,mask);
}
if (WiFi.begin(SSID.c_str(), (password.length() > 0)?password.c_str():NULL)){
grbl_send(CLIENT_ALL,"\n[MSG:Client Started]\r\n");
grbl_sendf(CLIENT_ALL,"[MSG:Connecting %s]\r\n", SSID.c_str());
return ConnectSTA2AP();
} else {
grbl_send(CLIENT_ALL,"[MSG:Starting client failed]\r\n");
return false;
}
}
/**
* Setup and start Access point
*/
bool WiFiConfig::StartAP(){
String defV;
Preferences prefs;
//stop active services
wifi_services.end();
//Sanity check
if((WiFi.getMode() == WIFI_STA) || (WiFi.getMode() == WIFI_AP_STA))WiFi.disconnect();
if((WiFi.getMode() == WIFI_AP) || (WiFi.getMode() == WIFI_AP_STA))WiFi.softAPdisconnect();
WiFi.enableSTA (false);
WiFi.mode(WIFI_AP);
//Get parameters for AP
prefs.begin(NAMESPACE, true);
//SSID
defV = DEFAULT_AP_SSID;
String SSID = prefs.getString(AP_SSID_ENTRY, defV);
if (SSID.length() == 0)SSID = DEFAULT_AP_SSID;
//password
defV = DEFAULT_AP_PWD;
String password = prefs.getString(AP_PWD_ENTRY, defV);
//channel
int8_t channel = prefs.getChar(AP_CHANNEL_ENTRY, DEFAULT_AP_CHANNEL);
if (channel == 0)channel = DEFAULT_AP_CHANNEL;
//IP
defV = DEFAULT_AP_IP;
int32_t IP = prefs.getInt(AP_IP_ENTRY, IP_int_from_string(defV));
if (IP==0){
IP = IP_int_from_string(defV);
}
prefs.end();
IPAddress ip(IP);
IPAddress mask;
mask.fromString(DEFAULT_AP_MK);
//Set static IP
WiFi.softAPConfig(ip, ip, mask);
//Start AP
if(WiFi.softAP(SSID.c_str(), (password.length() > 0)?password.c_str():NULL, channel)) {
grbl_sendf(CLIENT_ALL,"\n[MSG:Local access point %s started, %s]\r\n", SSID.c_str(), WiFi.softAPIP().toString().c_str());
return true;
} else {
grbl_send(CLIENT_ALL,"[MSG:Starting AP failed]\r\n");
return false;
}
}
/**
* Stop WiFi
*/
void WiFiConfig::StopWiFi(){
//Sanity check
if((WiFi.getMode() == WIFI_STA) || (WiFi.getMode() == WIFI_AP_STA))WiFi.disconnect(true);
if((WiFi.getMode() == WIFI_AP) || (WiFi.getMode() == WIFI_AP_STA))WiFi.softAPdisconnect(true);
wifi_services.end();
WiFi.enableSTA (false);
WiFi.enableAP (false);
WiFi.mode(WIFI_OFF);
grbl_send(CLIENT_ALL,"\n[MSG:WiFi Off]\r\n");
}
/**
* begin WiFi setup
*/
void WiFiConfig::begin() {
Preferences prefs;
//stop active services
wifi_services.end();
//setup events
if (!_events_registered) {
//cumulative function and no remove so only do once
WiFi.onEvent(WiFiConfig::WiFiEvent);
_events_registered = true;
}
//open preferences as read-only
prefs.begin(NAMESPACE, true);
//Get hostname
String defV = DEFAULT_HOSTNAME;
_hostname = prefs.getString(HOSTNAME_ENTRY, defV);
int8_t wifiMode = prefs.getChar(ESP_RADIO_MODE, DEFAULT_RADIO_MODE);
if (wifiMode == ESP_WIFI_AP) {
StartAP();
//start services
wifi_services.begin();
} else if (wifiMode == ESP_WIFI_STA){
if(!StartSTA()){
defV = DEFAULT_STA_SSID;
grbl_sendf(CLIENT_ALL,"[MSG:Cannot connect to %s]\r\n", prefs.getString(STA_SSID_ENTRY, defV).c_str());
StartAP();
}
//start services
wifi_services.begin();
}else WiFi.mode(WIFI_OFF);
prefs.end();
}
/**
* End WiFi
*/
void WiFiConfig::end() {
StopWiFi();
}
/**
* Reset ESP
*/
void WiFiConfig::reset_settings(){
Preferences prefs;
prefs.begin(NAMESPACE, false);
String sval;
int8_t bbuf;
int16_t ibuf;
bool error = false;
sval = DEFAULT_HOSTNAME;
if (prefs.putString(HOSTNAME_ENTRY, sval) == 0){
error = true;
}
bbuf = DEFAULT_NOTIFICATION_TYPE;
if (prefs.putChar(NOTIFICATION_TYPE, bbuf) ==0 ) {
error = true;
}
sval = DEFAULT_TOKEN;
if (prefs.putString(NOTIFICATION_T1, sval) != sval.length()){
error = true;
}
if (prefs.putString(NOTIFICATION_T2, sval) != sval.length()){
error = true;
}
if (prefs.putString(NOTIFICATION_TS, sval) != sval.length()){
error = true;
}
sval = DEFAULT_STA_SSID;
if (prefs.putString(STA_SSID_ENTRY, sval) == 0){
error = true;
}
sval = DEFAULT_STA_PWD;
if (prefs.putString(STA_PWD_ENTRY, sval) != sval.length()){
error = true;
}
sval = DEFAULT_AP_SSID;
if (prefs.putString(AP_SSID_ENTRY, sval) == 0){
error = true;
}
sval = DEFAULT_AP_PWD;
if (prefs.putString(AP_PWD_ENTRY, sval) != sval.length()){
error = true;
}
bbuf = DEFAULT_AP_CHANNEL;
if (prefs.putChar(AP_CHANNEL_ENTRY, bbuf) ==0 ) {
error = true;
}
bbuf = DEFAULT_STA_IP_MODE;
if (prefs.putChar(STA_IP_MODE_ENTRY, bbuf) ==0 ) {
error = true;
}
bbuf = DEFAULT_HTTP_STATE;
if (prefs.putChar(HTTP_ENABLE_ENTRY, bbuf) ==0 ) {
error = true;
}
bbuf = DEFAULT_TELNET_STATE;
if (prefs.putChar(TELNET_ENABLE_ENTRY, bbuf) ==0 ) {
error = true;
}
bbuf = DEFAULT_RADIO_MODE;
if (prefs.putChar(ESP_RADIO_MODE, bbuf) ==0 ) {
error = true;
}
ibuf = DEFAULT_WEBSERVER_PORT;
if (prefs.putUShort(HTTP_PORT_ENTRY, ibuf) == 0) {
error = true;
}
ibuf = DEFAULT_TELNETSERVER_PORT;
if (prefs.putUShort(TELNET_PORT_ENTRY, ibuf) == 0) {
error = true;
}
sval = DEFAULT_STA_IP;
if (prefs.putInt(STA_IP_ENTRY, wifi_config.IP_int_from_string(sval)) == 0) {
error = true;
}
sval = DEFAULT_STA_GW;
if (prefs.putInt(STA_GW_ENTRY, wifi_config.IP_int_from_string(sval)) == 0) {
error = true;
}
sval = DEFAULT_STA_MK;
if (prefs.putInt(STA_MK_ENTRY, wifi_config.IP_int_from_string(sval)) == 0) {
error = true;
}
sval = DEFAULT_AP_IP;
if (prefs.putInt(AP_IP_ENTRY, wifi_config.IP_int_from_string(sval)) == 0) {
error = true;
}
prefs.end();
if (error) {
grbl_send(CLIENT_ALL,"[MSG:WiFi reset error]\r\n");
} else {
grbl_send(CLIENT_ALL,"[MSG:WiFi reset done]\r\n");
}
}
bool WiFiConfig::Is_WiFi_on(){
return !(WiFi.getMode() == WIFI_MODE_NULL);
}
/**
* Handle not critical actions that must be done in sync environement
*/
void WiFiConfig::handle() {
//Services
COMMANDS::wait(0);
wifi_services.handle();
}
#endif // ENABLE_WIFI
#endif // ARDUINO_ARCH_ESP32