Skip to content

Commit

Permalink
Add WiFi network scan RPC command to Improv Serial (Aircoookie#3271)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aircoookie authored Jun 26, 2023
1 parent f015227 commit 481bd6f
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 76 deletions.
12 changes: 7 additions & 5 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# ------------------------------------------------------------------------------

# CI binaries
;; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
; default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth # ESP32 variant builds are temporarily excluded from CI due to toolchain issues on the GitHub Actions Linux environment
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_8MB

# Release binaries
Expand Down Expand Up @@ -40,6 +40,8 @@ default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, esp32dev, esp32_eth, lolin_
; default_envs = esp32dev_qio80
; default_envs = esp32_eth_ota1mapp
; default_envs = esp32s2_saola
; default_envs = esp32c3dev
; default_envs = lolin_s2_mini

src_dir = ./wled00
data_dir = ./wled00/data
Expand Down Expand Up @@ -460,8 +462,8 @@ board = esp32-c3-devkitm-1
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
build_flags = ${common.build_flags} ${esp32c3.build_flags} #-D WLED_RELEASE_NAME=ESP32-C3
-D WLED_WATCHDOG_TIMEOUT=0
; -DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
-DARDUINO_USB_CDC_ON_BOOT=1 ;; for virtual CDC USB
;-DARDUINO_USB_CDC_ON_BOOT=0 ;; for serial-to-USB chip
upload_speed = 460800
build_unflags = ${common.build_unflags}
lib_deps = ${esp32c3.lib_deps}
Expand Down Expand Up @@ -573,10 +575,10 @@ platform = ${esp32s2.platform}
platform_packages = ${esp32s2.platform_packages}
board = lolin_s2_mini
board_build.partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
build_unflags = ${common.build_unflags} -DARDUINO_USB_CDC_ON_BOOT=1
build_unflags = ${common.build_unflags} #-DARDUINO_USB_CDC_ON_BOOT=1
build_flags = ${common.build_flags} ${esp32s2.build_flags} #-D WLED_RELEASE_NAME=LolinS2
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=0
-DARDUINO_USB_CDC_ON_BOOT=1 # try disabling and enabling unflag above in case of board-specific issues, will disable Serial
-DARDUINO_USB_MSC_ON_BOOT=0
-DARDUINO_USB_DFU_ON_BOOT=0
-DLOLIN_WIFI_FIX ; seems to work much better with this
Expand Down
12 changes: 11 additions & 1 deletion wled00/fcn_declare.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,20 @@ void sendHuePoll();
void onHueData(void* arg, AsyncClient* client, void *data, size_t len);

//improv.cpp
enum ImprovRPCType {
Command_Wifi = 0x01,
Request_State = 0x02,
Request_Info = 0x03,
Request_Scan = 0x04
};

void handleImprovPacket();
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings = 0, const char **strings = nullptr);
void sendImprovStateResponse(uint8_t state, bool error = false);
void sendImprovInfoResponse();
void sendImprovRPCResponse(byte commandId);
void startImprovWifiScan();
void handleImprovWifiScan();
void sendImprovIPRPCResult(ImprovRPCType type);

//ir.cpp
void applyRepeatActions();
Expand Down
169 changes: 101 additions & 68 deletions wled00/improv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
#define DIMPROV_PRINTF(x...)
#endif

#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
#undef WLED_DISABLE_IMPROV_WIFISCAN
#define WLED_DISABLE_IMPROV_WIFISCAN
#endif

#define IMPROV_VERSION 1

void parseWiFiCommand(char *rpcData);
Expand All @@ -28,20 +33,14 @@ enum ImprovPacketByte {
RPC_CommandType = 9
};

enum ImprovRPCType {
Command_Wifi = 0x01,
Request_State = 0x02,
Request_Info = 0x03
};

//File dbgf;
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
static bool improvWifiScanRunning = false;
#endif

//blocking function to parse an Improv Serial packet
void handleImprovPacket() {
uint8_t header[6] = {'I','M','P','R','O','V'};

//dbgf = WLED_FS.open("/improv.log","a");

bool timeout = false;
uint8_t waitTime = 25;
uint16_t packetByte = 0;
Expand All @@ -62,20 +61,18 @@ void handleImprovPacket() {
byte next = Serial.read();

DIMPROV_PRINT("Received improv byte: "); DIMPROV_PRINTF("%x\r\n",next);
//f.write(next);

switch (packetByte) {
case ImprovPacketByte::Version: {
if (next != IMPROV_VERSION) {
DIMPROV_PRINTLN(F("Invalid version"));
//dbgf.close();
return;
}
break;
}
case ImprovPacketByte::PacketType: {
if (next != ImprovPacketType::RPC_Command) {
DIMPROV_PRINTF("Non RPC-command improv packet type %i\n",next);
//dbgf.close();
return;
}
if (!improvActive) improvActive = 1;
Expand All @@ -89,7 +86,6 @@ void handleImprovPacket() {
if (checksum != next) {
DIMPROV_PRINTF("Got RPC checksum %i, expected %i",next,checksum);
sendImprovStateResponse(0x01, true);
//dbgf.close();
return;
}

Expand All @@ -100,22 +96,23 @@ void handleImprovPacket() {
if (WLED_WIFI_CONFIGURED) improvState = 0x03; //provisioning
if (Network.isConnected()) improvState = 0x04; //provisioned
sendImprovStateResponse(improvState, false);
if (improvState == 0x04) sendImprovRPCResponse(ImprovRPCType::Request_State);
if (improvState == 0x04) sendImprovIPRPCResult(ImprovRPCType::Request_State);
break;
}
case ImprovRPCType::Request_Info: sendImprovInfoResponse(); break;
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
case ImprovRPCType::Request_Scan: startImprovWifiScan(); break;
#endif
default: {
DIMPROV_PRINTF("Unknown RPC command %i\n",next);
sendImprovStateResponse(0x02, true);
}
}
//dbgf.close();
return;
}
if (packetByte < 6) { //check header
if (next != header[packetByte]) {
DIMPROV_PRINTLN(F("Invalid improv header"));
//dbgf.close();
return;
}
} else if (packetByte > 9) { //RPC data
Expand All @@ -128,7 +125,6 @@ void handleImprovPacket() {
checksum += next;
packetByte++;
}
//dbgf.close();
}

void sendImprovStateResponse(uint8_t state, bool error) {
Expand All @@ -147,79 +143,116 @@ void sendImprovStateResponse(uint8_t state, bool error) {
Serial.write('\n');
}

void sendImprovRPCResponse(byte commandId) {
// used by sendImprovIPRPCResult(), sendImprovInfoResponse(), and handleImprovWifiScan()
void sendImprovRPCResult(ImprovRPCType type, uint8_t n_strings, const char **strings) {
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
uint8_t packetLen = 12;
char out[64] = {'I','M','P','R','O','V'};
char out[256] = {'I','M','P','R','O','V'};
out[6] = IMPROV_VERSION;
out[7] = ImprovPacketType::RPC_Response;
out[8] = 2; //Length (set below)
out[9] = commandId;
out[10] = 0; //Data len (set below)
out[11] = '\0'; //URL len (set below)
//out[8] = 2; //Length (set below)
out[9] = type;
//out[10] = 0; //Data len (set below)
uint16_t pos = 11;

if (Network.isConnected())
{
IPAddress localIP = Network.localIP();
uint8_t len = sprintf(out+12, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
if (len > 24) return; //sprintf fail?
out[11] = len;
out[10] = 1 + len;
out[8] = 3 + len; //RPC command type + data len + url len + url
packetLen = 13 + len;
for (uint8_t s = 0; s < n_strings; s++) {
size_t len = strlen(strings[s]);
if (pos + len > 254) continue; // simple buffer overflow guard
out[pos++] = len;
strcpy(out + pos, strings[s]);
pos += len;
}

packetLen = pos +1;
out[8] = pos -9; // Length of packet (excluding first 9 header bytes and final checksum byte)
out[10] = pos -11; // Data len

uint8_t checksum = 0;
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i];
out[packetLen -1] = checksum;
Serial.write((uint8_t*)out, packetLen);
Serial.write('\n');
DIMPROV_PRINT("RPC result checksum");
DIMPROV_PRINTLN(checksum);
}

void sendImprovIPRPCResult(ImprovRPCType type) {
if (Network.isConnected())
{
char urlStr[64];
IPAddress localIP = Network.localIP();
uint8_t len = sprintf(urlStr, "http://%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
if (len > 24) return; //sprintf fail?
const char *str[1] = {urlStr};
sendImprovRPCResult(type, 1, str);
} else {
sendImprovRPCResult(type, 0);
}

improvActive = 1; //no longer provisioning
}

void sendImprovInfoResponse() {
if (improvError > 0 && improvError < 3) sendImprovStateResponse(0x00, true);
uint8_t packetLen = 12;
char out[128] = {'I','M','P','R','O','V'};
out[6] = IMPROV_VERSION;
out[7] = ImprovPacketType::RPC_Response;
//out[8] = 2; //Length (set below)
out[9] = ImprovRPCType::Request_Info;
//out[10] = 0; //Data len (set below)
out[11] = 4; //Firmware len ("WLED")
out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D';
uint8_t lengthSum = 17;
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.14.0-b3/%i"),VERSION);
out[16] = vlen; lengthSum += vlen;
uint8_t hlen = 7;
#ifdef ESP8266
strcpy(out+lengthSum+1,"esp8266");
#else
hlen = 5;
strcpy(out+lengthSum+1,"esp32");
#endif
out[lengthSum] = hlen;
lengthSum += hlen + 1;
const char* bString =
#ifdef ESP8266
"esp8266"
#elif CONFIG_IDF_TARGET_ESP32C3
"esp32-c3"
#elif CONFIG_IDF_TARGET_ESP32S2
"esp32-s2"
#elif CONFIG_IDF_TARGET_ESP32S3
"esp32-s3";
#else // ESP32
"esp32";
#endif
;

//Use serverDescription if it has been changed from the default "WLED", else mDNS name
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
strcpy(out+lengthSum+1,useMdnsName ? cmDNS : serverDescription);
uint8_t nlen = strlen(useMdnsName ? cmDNS : serverDescription);
out[lengthSum] = nlen;
lengthSum += nlen + 1;
char vString[20];
sprintf_P(vString, PSTR("0.14.0-b3/%i"), VERSION);
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};

packetLen = lengthSum +1;
out[8] = lengthSum -9;
out[10] = lengthSum -11;
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
}

uint8_t checksum = 0;
for (uint8_t i = 0; i < packetLen -1; i++) checksum += out[i];
out[packetLen -1] = checksum;
Serial.write((uint8_t*)out, packetLen);
Serial.write('\n');
DIMPROV_PRINT("Info checksum");
DIMPROV_PRINTLN(checksum);
#ifndef WLED_DISABLE_IMPROV_WIFISCAN
void startImprovWifiScan() {
if (improvWifiScanRunning) return;
WiFi.scanNetworks(true);
improvWifiScanRunning = true;
}

void handleImprovWifiScan() {
if (!improvWifiScanRunning) return;
int16_t status = WiFi.scanComplete();
if (status == WIFI_SCAN_RUNNING) return;
// here scan completed or failed (-2)
improvWifiScanRunning = false;

for (int i = 0; i < status; i++) {
char rssiStr[8];
sprintf(rssiStr, "%d", WiFi.RSSI(i));
#ifdef ESP8266
bool isOpen = WiFi.encryptionType(i) == ENC_TYPE_NONE;
#else
bool isOpen = WiFi.encryptionType(i) == WIFI_AUTH_OPEN;
#endif

char ssidStr[33];
strcpy(ssidStr, WiFi.SSID(i).c_str());
const char *str[3] = {ssidStr, rssiStr, isOpen ? "NO":"YES"};
sendImprovRPCResult(ImprovRPCType::Request_Scan, 3, str);
}
sendImprovRPCResult(ImprovRPCType::Request_Scan, 0);

WiFi.scanDelete();
}
#else
void startImprovWifiScan() {}
void handleImprovWifiScan() {}
#endif

void parseWiFiCommand(char* rpcData) {
uint8_t len = rpcData[0];
if (!len || len > 126) return;
Expand Down
4 changes: 2 additions & 2 deletions wled00/wled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void WLED::loop()
handleConnection();
handleRemote();
handleSerial();
handleImprovWifiScan();
handleNotifications();
handleTransitions();
#ifdef WLED_ENABLE_DMX
Expand Down Expand Up @@ -646,7 +647,6 @@ void WLED::initConnection()
ws.onEvent(wsEvent);
#endif


WiFi.disconnect(true); // close old connections
#ifdef ESP8266
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
Expand Down Expand Up @@ -845,7 +845,7 @@ void WLED::handleConnection()
if (improvActive) {
if (improvError == 3) sendImprovStateResponse(0x00, true);
sendImprovStateResponse(0x04);
if (improvActive > 1) sendImprovRPCResponse(0x01);
if (improvActive > 1) sendImprovIPRPCResult(ImprovRPCType::Command_Wifi);
}
initInterfaces();
userConnected();
Expand Down

0 comments on commit 481bd6f

Please sign in to comment.