diff --git a/.gitignore b/.gitignore index db03415..cc2351c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ +/.pio .pioenvs +.pio .clang_complete .gcc-flags.json diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..84062ca --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +sudo: false + +language: python +python: + - "2.7" + +cache: + directories: + - "~/.platformio" + +install: + - pip install -U platformio + - platformio update + +script: + - platformio ci -c platformio.ini --lib="./src" --lib="./lib/*" ./examples/simple/ + +notifications: + email: + on_success: never + on_failure: always diff --git a/README.md b/README.md index fcbf443..ee7d96e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ ![Logo](http://svg.wiersma.co.za/github/project?lang=cpp&title=ConfigManager&tag=wifi%20configuration%20manager) +[![Build Status](https://travis-ci.com/nrwiersma/ConfigManager.svg?branch=master)](https://travis-ci.com/nrwiersma/ConfigManager) [![arduino-library-badge](http://www.ardu-badge.com/badge/ConfigManager.svg)](http://www.ardu-badge.com/ConfigManager) Wifi connection and configuration manager for ESP8266 and ESP32. @@ -109,7 +110,7 @@ on the most common IDEs: ### Enabling -By default, ConfigManager runs in `DEBUG_MODE` off. This is to allow the serial iterface to communicate as needed. +By default, ConfigManager runs in `DEBUG_MODE` off. This is to allow the serial iterface to communicate as needed. To turn on debugging, add the following line inside your `setup` routine: ``` @@ -295,7 +296,7 @@ ssid=access point&password=some password ```json { "ssid": "access point name", - "strength": *int*, + "strength": *int*, "security": *bool* } ``` diff --git a/lib/ConfigParameter/BaseParameter.h b/lib/ConfigParameter/BaseParameter.h new file mode 100644 index 0000000..ab8ff0c --- /dev/null +++ b/lib/ConfigParameter/BaseParameter.h @@ -0,0 +1,20 @@ +#ifndef __BASE_PARAMETER_H__ +#define __BASE_PARAMETER_H__ + +#include +#include + +enum ParameterMode { get, set, both}; + +/** + * Base Parameter + */ +class BaseParameter { +public: + virtual ParameterMode getMode() = 0; + virtual void fromJson(JsonObject *json) = 0; + virtual void toJson(JsonObject *json) = 0; + virtual void clearData() = 0; +}; + +#endif /* __BASE_PARAMETER_H__ */ diff --git a/lib/ConfigParameter/ConfigParameter.h b/lib/ConfigParameter/ConfigParameter.h new file mode 100644 index 0000000..513932f --- /dev/null +++ b/lib/ConfigParameter/ConfigParameter.h @@ -0,0 +1,44 @@ +#ifndef __CONFIG_PARAMETER_H__ +#define __CONFIG_PARAMETER_H__ + +#include + +/** + * Config Parameter + */ +template +class ConfigParameter : public BaseParameter { +public: + ConfigParameter(const char *name, T *ptr, ParameterMode mode = both) { + this->name = name; + this->ptr = ptr; + this->mode = mode; + } + + ParameterMode getMode() { + return this->mode; + } + + void fromJson(JsonObject *json) { + if (json->containsKey(name) && json->is(name)) { + *ptr = json->get(name); + } + } + + void toJson(JsonObject *json) { + json->set(name, *ptr); + } + + void clearData() { + DebugPrint("Clearing: "); + DebugPrintln(name); + *ptr = T(); + } + +private: + const char *name; + T *ptr; + ParameterMode mode; +}; + +#endif /* __CONFIG_PARAMETER_H__ */ diff --git a/lib/ConfigParameter/ConfigStringParameter.h b/lib/ConfigParameter/ConfigStringParameter.h new file mode 100644 index 0000000..3680724 --- /dev/null +++ b/lib/ConfigParameter/ConfigStringParameter.h @@ -0,0 +1,50 @@ +#ifndef __CONFIG_STRING_PARAMETER_H__ +#define __CONFIG_STRING_PARAMETER_H__ + +#include + +/** + * Config String Parameter + */ +class ConfigStringParameter : public BaseParameter { +public: + ConfigStringParameter(const char *name, char *ptr, size_t length, ParameterMode mode = both) { + this->name = name; + this->ptr = ptr; + this->length = length; + this->mode = mode; + } + + ParameterMode getMode() { + return this->mode; + } + + void fromJson(JsonObject *json) { + if (json->containsKey(name) && json->is(name)) { + const char * value = json->get(name); + + memset(ptr, NULL, length); + strncpy(ptr, const_cast(value), length - 1); + } + } + + void toJson(JsonObject *json) { + json->set(name, ptr); + } + + void clearData() { + DebugPrint("Clearing: "); + DebugPrintln(name); + memset(ptr, NULL, length); + } + + +private: + const char *name; + char *ptr; + size_t length; + ParameterMode mode; +}; + + +#endif /* __CONFIG_STRING_PARAMETER_H__ */ diff --git a/lib/DebugPrint/DebugPrint.h b/lib/DebugPrint/DebugPrint.h new file mode 100644 index 0000000..b7c60ab --- /dev/null +++ b/lib/DebugPrint/DebugPrint.h @@ -0,0 +1,9 @@ +#ifndef __DEBUG_PRINT_H__ +#define __DEBUG_PRINT_H__ + +extern bool DEBUG_MODE; + +#define DebugPrintln(a) (DEBUG_MODE ? Serial.println(a) : false) +#define DebugPrint(a) (DEBUG_MODE ? Serial.print(a) : false) + +#endif /* __DEBUG_PRINT_H__ */ diff --git a/library.json b/library.json index 2fbe62c..ec62ace 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ConfigManager", - "version": "1.5", + "version": "1.5.1", "keywords": "wifi, wi-fi, config", "description": "WiFi connection manager for ESP8266 and ESP32", "repository": diff --git a/library.properties b/library.properties index d63a1ae..43373f9 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ConfigManager -version=1.5 +version=1.5.1 author=Nick Wiersma maintainer=Nick Wiersma sentence=WiFi connection manager for ESP8266 and ESP32 diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..e52187c --- /dev/null +++ b/platformio.ini @@ -0,0 +1,28 @@ +[platformio] +default_envs = nodemcuv2 + +[common] +lib_deps = + ArduinoJson@5.13.4 + +[env:nodemcuv2] +platform = https://github.com/platformio/platform-espressif8266.git +board = d1_mini +framework = arduino +monitor_speed = 115200 +build_flags = -std=c++11, -Wl,-Teagle.flash.4m3m.ld, -D PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH, -DARDUINO_ARCH_ESP8266 +lib_ldf_mode = deep +board_build.f_flash = 80000000L +upload_speed = 115200 +lib_deps = ${common.lib_deps} +test_filter = embedded + +[env:esp32] +platform = https://github.com/platformio/platform-espressif32.git +board = esp-wrover-kit +framework = arduino +board_build.partitions = noota_3g.csv +build_flags = -std=c++11, -DARDUINO_ARCH_ESP32 +lib_ldf_mode = deep +lib_deps = ${common.lib_deps} +test_filter = embedded diff --git a/src/ConfigManager.cpp b/src/ConfigManager.cpp index ff024c6..c56f07f 100644 --- a/src/ConfigManager.cpp +++ b/src/ConfigManager.cpp @@ -2,7 +2,7 @@ const byte DNS_PORT = 53; const char magicBytes[MAGIC_LENGTH] = {'C', 'M'}; -const char magicBytesEmpty[MAGIC_LENGTH] = {NULL, NULL}; +const char magicBytesEmpty[MAGIC_LENGTH] = {'\0', '\0'}; const char mimeHTML[] PROGMEM = "text/html"; const char mimeJSON[] PROGMEM = "application/json"; @@ -128,7 +128,7 @@ void ConfigManager::handleAPPost() { storeWifiSettings(ssid, password, false); server->send(204, FPSTR(mimePlain), F("Saved. Will attempt to reboot.")); - + ESP.restart(); } @@ -148,7 +148,7 @@ void ConfigManager::handleScanGet() { for (int i = 0; i < n; ++i) { String ssid = WiFi.SSID(i); int rssi = WiFi.RSSI(i); - String security = WiFi.encryptionType(i) == ENC_TYPE_NONE ? "none" : "enabled"; + String security = WiFi.encryptionType(i) == WIFI_OPEN ? "none" : "enabled"; DebugPrint("Name: "); DebugPrint(ssid); @@ -215,12 +215,12 @@ void ConfigManager::handleRESTPut() { void ConfigManager::handleNotFound() { String URI = toStringIP(server->client().localIP()) + String(":") + String(webPort); String header = server->hostHeader(); - + if ( !isIp(header) && header != URI) { DebugPrint(F("Unknown URL: ")); DebugPrintln(header); server->sendHeader("Location", String("http://") + URI, true); - server->send(302, FPSTR(mimePlain), ""); + server->send(302, FPSTR(mimePlain), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. server->client().stop(); return; @@ -298,13 +298,13 @@ void ConfigManager::startAP() { WiFi.mode(WIFI_AP); WiFi.softAP(apName, apPassword); - + delay(500); // Need to wait to get IP - + IPAddress ip(192, 168, 1, 1); IPAddress NMask(255, 255, 255, 0); WiFi.softAPConfig(ip, ip, NMask); - + DebugPrint("AP Name: "); DebugPrintln(apName); @@ -348,7 +348,7 @@ void ConfigManager::createBaseWebServer() { server.reset(new WebServer(this->webPort)); DebugPrint(F("Webserver enabled on port: ")); DebugPrintln(webPort); - + server->collectHeaders(headerKeys, headerKeysSize); server->on("/", HTTPMethod::HTTP_GET, std::bind(&ConfigManager::handleAPGet, this)); @@ -361,8 +361,8 @@ void ConfigManager::createBaseWebServer() { void ConfigManager::clearWifiSettings(bool reboot) { char ssid[SSID_LENGTH]; char password[PASSWORD_LENGTH]; - memset(ssid, NULL, SSID_LENGTH); - memset(password, NULL, PASSWORD_LENGTH); + memset(ssid, 0, SSID_LENGTH); + memset(password, 0, PASSWORD_LENGTH); DebugPrintln(F("Clearing WiFi connection.")); storeWifiSettings(ssid, password, true); @@ -429,7 +429,7 @@ void ConfigManager::writeConfig() { } boolean ConfigManager::isIp(String str) { - for (int i = 0; i < str.length(); i++) { + for (uint i = 0; i < str.length(); i++) { int c = str.charAt(i); if (c != '.' && (c < '0' || c > '9')) { return false; diff --git a/src/ConfigManager.h b/src/ConfigManager.h index 25aa2d7..df97467 100644 --- a/src/ConfigManager.h +++ b/src/ConfigManager.h @@ -18,6 +18,15 @@ #include #include "ArduinoJson.h" +#if defined(ARDUINO_ARCH_ESP8266) //ESP8266 + #define WIFI_OPEN ENC_TYPE_NONE +#elif defined(ARDUINO_ARCH_ESP32) //ESP32 + #define WIFI_OPEN WIFI_AUTH_OPEN +#endif + +#include "ConfigParameter.h" +#include "ConfigStringParameter.h" + #define MAGIC_LENGTH 2 #define SSID_LENGTH 32 #define PASSWORD_LENGTH 64 @@ -27,11 +36,6 @@ using WebServer = ESP8266WebServer; #endif -extern bool DEBUG_MODE; - -#define DebugPrintln(a) (DEBUG_MODE ? Serial.println(a) : false) -#define DebugPrint(a) (DEBUG_MODE ? Serial.print(a) : false) - extern const char mimeHTML[]; extern const char mimeJSON[]; extern const char mimePlain[]; @@ -39,100 +43,6 @@ extern const char mimeCSS[]; extern const char mimeJS[]; enum Mode {ap, api}; -enum ParameterMode { get, set, both}; - -/** - * Base Parameter - */ -class BaseParameter { -public: - virtual ParameterMode getMode() = 0; - virtual void fromJson(JsonObject *json) = 0; - virtual void toJson(JsonObject *json) = 0; - virtual void clearData() = 0; -}; - -/** - * Config Parameter - */ -template -class ConfigParameter : public BaseParameter { -public: - ConfigParameter(const char *name, T *ptr, ParameterMode mode = both) { - this->name = name; - this->ptr = ptr; - this->mode = mode; - } - - ParameterMode getMode() { - return this->mode; - } - - void fromJson(JsonObject *json) { - if (json->containsKey(name) && json->is(name)) { - *ptr = json->get(name); - } - } - - void toJson(JsonObject *json) { - json->set(name, *ptr); - } - - void clearData() { - DebugPrint("Clearing: "); - DebugPrintln(name); - *ptr = T(); - } - -private: - const char *name; - T *ptr; - std::function cb; - ParameterMode mode; -}; - -/** - * Config String Parameter - */ -class ConfigStringParameter : public BaseParameter { -public: - ConfigStringParameter(const char *name, char *ptr, size_t length, ParameterMode mode = both) { - this->name = name; - this->ptr = ptr; - this->length = length; - this->mode = mode; - } - - ParameterMode getMode() { - return this->mode; - } - - void fromJson(JsonObject *json) { - if (json->containsKey(name) && json->is(name)) { - const char * value = json->get(name); - - memset(ptr, NULL, length); - strncpy(ptr, const_cast(value), length - 1); - } - } - - void toJson(JsonObject *json) { - json->set(name, ptr); - } - - void clearData() { - DebugPrint("Clearing: "); - DebugPrintln(name); - memset(ptr, NULL, length); - } - - -private: - const char *name; - char *ptr; - size_t length; - ParameterMode mode; -}; /** * Config Manager diff --git a/test/embedded/ConfigParameterTest.h b/test/embedded/ConfigParameterTest.h new file mode 100644 index 0000000..bed52ed --- /dev/null +++ b/test/embedded/ConfigParameterTest.h @@ -0,0 +1,63 @@ +#include + +#include +#include + +void test_sets_config_parameter_mode() { + const char *variable = "baphled"; + ConfigParameter parameter = ConfigParameter("username", &variable, both); + + TEST_ASSERT_EQUAL(both, parameter.getMode()); +} + +void test_config_parameter_stored_as_json() { + const char *variable = "baphled"; + const char *expected = "{\"username\":\"baphled\"}"; + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + + char body[50] = "\n"; + + ConfigParameter parameter = ConfigParameter("username", &variable, get); + + parameter.toJson(&obj); + obj.printTo(body); + + TEST_ASSERT_EQUAL_STRING(expected, body); +} + +void test_config_parameter_stored_from_json() { + const char *variable = "foo"; + const char *expected = "{\"username\":\"baphled\"}"; + char body[50] = "\n"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.parseObject(expected); + + ConfigParameter parameter = ConfigParameter("username", &variable, set); + + parameter.fromJson(&obj); + + parameter.toJson(&obj); + obj.printTo(body); + + TEST_ASSERT_EQUAL_STRING(expected, body); +} + +void test_config_parameter_clear_data() { + const char *variable = "foo"; + const char *expected = "{\"username\":null}"; + char body[50] = "\n"; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + + ConfigParameter parameter = ConfigParameter("username", &variable, set); + + parameter.clearData(); + + parameter.toJson(&obj); + obj.printTo(body); + + TEST_ASSERT_EQUAL_STRING(expected, body); +} diff --git a/test/embedded/ConfigStringParameterTest.h b/test/embedded/ConfigStringParameterTest.h new file mode 100644 index 0000000..3e63717 --- /dev/null +++ b/test/embedded/ConfigStringParameterTest.h @@ -0,0 +1,67 @@ +#include + +#include +#include + +void test_sets_config_string_parameter_mode() { + char *variable = "baphled"; + size_t length = 10; + ConfigStringParameter parameter = ConfigStringParameter("username", variable, length, both); + + TEST_ASSERT_EQUAL(both, parameter.getMode()); +} + +void test_config_string_parameter_stored_as_json() { + char *variable = "baphled"; + const char *expected = "{\"username\":\"baphled\"}"; + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + + char body[50] = "\n"; + size_t length = 10; + + ConfigStringParameter parameter = ConfigStringParameter("username", variable, length, set); + + parameter.toJson(&obj); + obj.printTo(body); + + TEST_ASSERT_EQUAL_STRING(expected, body); +} + +void test_config_string_parameter_stored_from_json() { + char *variable = "foo"; + const char *expected = "{\"username\":\"baphled\"}"; + char body[50] = "\n"; + size_t length = 10; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.parseObject(expected); + + ConfigStringParameter parameter = ConfigStringParameter("username", variable, length, set); + + parameter.fromJson(&obj); + + parameter.toJson(&obj); + obj.printTo(body); + + TEST_ASSERT_EQUAL_STRING(expected, body); +} + +void test_config_string_parameter_clear_data() { + char *variable = "foo"; + const char *expected = "{\"username\":\"\"}"; + char body[50] = "\n"; + size_t length = 10; + + DynamicJsonBuffer jsonBuffer; + JsonObject& obj = jsonBuffer.createObject(); + + ConfigStringParameter parameter = ConfigStringParameter("username", variable, length, set); + + parameter.clearData(); + + parameter.toJson(&obj); + obj.printTo(body); + + TEST_ASSERT_EQUAL_STRING(expected, body); +} diff --git a/test/embedded/main.cpp b/test/embedded/main.cpp new file mode 100644 index 0000000..909a025 --- /dev/null +++ b/test/embedded/main.cpp @@ -0,0 +1,32 @@ +#if defined(ARDUINO) && defined(UNIT_TEST) +#include "Arduino.h" + +#include + +#include "ConfigParameterTest.h" +#include "ConfigStringParameterTest.h" + +bool DEBUG_MODE = false; + +void setup() { + delay(2000); + + UNITY_BEGIN(); + + // ConfigParameterTest + RUN_TEST(test_sets_config_parameter_mode); + RUN_TEST(test_config_parameter_stored_as_json); + RUN_TEST(test_config_parameter_stored_from_json); + RUN_TEST(test_config_parameter_clear_data); + + // ConfigStringParameterTest + RUN_TEST(test_sets_config_string_parameter_mode); + RUN_TEST(test_config_string_parameter_stored_as_json); + RUN_TEST(test_config_string_parameter_stored_from_json); + RUN_TEST(test_config_string_parameter_clear_data); + + UNITY_END(); +} + +void loop() {} +#endif