Commit 1d090ccc authored by Eric Duminil's avatar Eric Duminil
Browse files

Too long but kinda working

parent d741d85f
/**
* IotWebConf03TypedParameters.ino -- IotWebConf is an ESP8266/ESP32
* non blocking WiFi/AP web configuration library for Arduino.
* https://github.com/prampec/IotWebConf
*
* Copyright (C) 2020 Balazs Kelemen <prampec+arduino@gmail.com>
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#include <IotWebConf.h>
#include <IotWebConfTParameter.h>
/**
* Example: Custom parameters
* Description:
* Typed Parameters are a new approach to store/handle parameter data.
* This part of the software is very experimental, and certainly
* not recommended for beginners.
* The goal of this particular example is to compare the original
* approach of IotWebConf03CustomParameters to this new typed
* parameters, as both examples should work the same.
*
* Hardware setup for this example:
* - An LED is attached to LED_BUILTIN pin with setup On=LOW.
* - [Optional] A push button is attached to pin D2, the other leg of the
* button should be attached to GND.
/** Other scripts can use this namespace, in order to define commands, via callbacks.
* Those callbacks can then be used to send commands to the sensor (reset, calibrate, led on/off, ...)
* The callbacks can either have no parameter, one int32_t parameter or one char pointer.
*/
#include <IotWebConf.h>
#include <IotWebConfTParameter.h>
namespace sensor_console {
void defineCommand(const char *name, void (*function)(), const __FlashStringHelper *doc_fstring);
void defineIntCommand(const char *name, void (*function)(int32_t), const __FlashStringHelper *doc_fstring);
void defineStringCommand(const char *name, void (*function)(char*), const __FlashStringHelper *doc_fstring);
void checkSerialInput();
void execute(const char *command_line);
}
// -- Initial name of the Thing. Used e.g. as SSID of the own Access Point.
const char thingName[] = "testThing";
......@@ -38,16 +26,7 @@ const char wifiInitialApPassword[] = "smrtTHNG8266";
#define NUMBER_LEN 32
// -- Configuration specific key. The value should be modified if config structure was changed.
#define CONFIG_VERSION "dem4"
// -- When CONFIG_PIN is pulled to ground on startup, the Thing will use the initial
// password to buld an AP. (E.g. in case of lost password)
#define CONFIG_PIN 2 // D2
// -- Status indicator pin.
// First it will light up (kept LOW), on Wifi connection it will blink,
// when connected to the Wifi it will turn off (kept HIGH).
#define STATUS_PIN LED_BUILTIN
#define CONFIG_VERSION "dem99"
// -- Method declarations.
void handleRoot();
......@@ -129,8 +108,6 @@ void setup()
group2.addItem(&dateParam);
group2.addItem(&timeParam);
iotWebConf.setStatusPin(STATUS_PIN);
iotWebConf.setConfigPin(CONFIG_PIN);
iotWebConf.addSystemParameter(&stringParam);
iotWebConf.addParameterGroup(&group1);
iotWebConf.addParameterGroup(&group2);
......@@ -144,6 +121,34 @@ void setup()
server.on("/", handleRoot);
server.on("/config", []{ iotWebConf.handleConfig(); });
server.onNotFound([](){ iotWebConf.handleNotFound(); });
sensor_console::defineCommand("reset", [](){ ESP.restart(); }, F("(Restarts the ESP)"));
sensor_console::defineCommand("save_config", [](){ iotWebConf.saveConfig(); }, F("(Saves the config to EEPROM)"));
sensor_console::defineCommand("reset_config", []() {
Serial.println(F("Resetting config..."));
iotWebConf.getRootParameterGroup()->applyDefaultValue();
Serial.println(F("Done!"));
}, F("(Resets the complete IotWeb config)"));
sensor_console::defineStringCommand("ssid", [](char *ssid) {
Serial.print(F("Setting WiFi ssid to "));
Serial.println(ssid);
strlcpy(iotWebConf.getWifiSsidParameter()->valueBuffer, ssid, iotWebConf.getWifiSsidParameter()->getLength());
}, F("name (Sets SSID to name)"));
sensor_console::defineStringCommand("wifi_pwd", [](char *pwd) {
Serial.print(F("Setting WiFi password to "));
Serial.println(pwd);
strlcpy(iotWebConf.getWifiPasswordParameter()->valueBuffer, pwd, iotWebConf.getWifiPasswordParameter()->getLength());
}, F("abc (Sets WiFi password to abc)"));
sensor_console::defineStringCommand("ap_pwd", [](char *pwd) {
Serial.print(F("Setting AP password to "));
Serial.println(pwd);
strlcpy(iotWebConf.getWifiPasswordParameter()->valueBuffer, pwd, iotWebConf.getWifiPasswordParameter()->getLength());
}, F("abc (Sets AP password to abc)"));
Serial.println("Ready.");
}
......@@ -152,6 +157,7 @@ void loop()
{
// -- doLoop should be called as frequently as possible.
iotWebConf.doLoop();
sensor_console::checkSerialInput();
}
/**
......@@ -198,3 +204,199 @@ void configSaved()
{
Serial.println("Configuration was updated.");
}
/***
* Sensor console
*/
namespace sensor_console {
const uint8_t MAX_COMMANDS = 10;
const uint8_t MAX_COMMAND_SIZE = 40;
uint8_t commands_count = 0;
enum input_type {
NONE,
INT32,
STRING
};
struct Command {
const char *name;
union {
void (*voidFunction)();
void (*intFunction)(int32_t);
void (*strFunction)(char*);
};
const char *doc;
input_type parameter_type;
};
struct CommandLine {
char function_name[MAX_COMMAND_SIZE];
input_type argument_type;
int32_t int_argument;
char str_argument[MAX_COMMAND_SIZE];
};
Command commands[MAX_COMMANDS];
bool addCommand(const char *name, const __FlashStringHelper *doc_fstring) {
if (commands_count < MAX_COMMANDS) {
commands[commands_count].name = name;
commands[commands_count].doc = (const char*) doc_fstring;
return true;
} else {
Serial.println(F("Too many commands have been defined."));
return false;
}
}
void defineCommand(const char *name, void (*function)(), const __FlashStringHelper *doc_fstring) {
if (addCommand(name, doc_fstring)) {
commands[commands_count].voidFunction = function;
commands[commands_count++].parameter_type = NONE;
}
}
void defineIntCommand(const char *name, void (*function)(int32_t), const __FlashStringHelper *doc_fstring) {
if (addCommand(name, doc_fstring)) {
commands[commands_count].intFunction = function;
commands[commands_count++].parameter_type = INT32;
}
}
void defineStringCommand(const char *name, void (*function)(char*), const __FlashStringHelper *doc_fstring) {
if (addCommand(name, doc_fstring)) {
commands[commands_count].strFunction = function;
commands[commands_count++].parameter_type = STRING;
}
}
/*
* Tries to split a string command (e.g. 'mqtt 60' or 'show_csv') into
* a CommandLine struct (function_name, argument_type and argument)
*/
void parseCommand(const char *command, CommandLine &command_line) {
if (strlen(command) == 0) {
Serial.println(F("Received empty command"));
command_line.argument_type = NONE;
return;
}
char *first_space;
first_space = strchr(command, ' ');
if (first_space == NULL) {
command_line.argument_type = NONE;
strlcpy(command_line.function_name, command, MAX_COMMAND_SIZE);
return;
}
strlcpy(command_line.function_name, command, first_space - command + 1);
strlcpy(command_line.str_argument, first_space + 1, MAX_COMMAND_SIZE - (first_space - command) - 1);
char *end;
command_line.int_argument = strtol(command_line.str_argument, &end, 0); // Accepts 123 or 0xFF00FF
if (*end) {
command_line.argument_type = STRING;
} else {
command_line.argument_type = INT32;
}
}
int compareCommandNames(const void *s1, const void *s2) {
struct Command *c1 = (struct Command*) s1;
struct Command *c2 = (struct Command*) s2;
return strcmp(c1->name, c2->name);
}
void listAvailableCommands() {
qsort(commands, commands_count, sizeof(commands[0]), compareCommandNames);
for (uint8_t i = 0; i < commands_count; i++) {
Serial.print(F(" "));
Serial.print(commands[i].name);
Serial.print(F(" "));
Serial.print(commands[i].doc);
Serial.println(F("."));
}
}
/*
* Saves bytes from Serial.read() until enter is pressed, and tries to run the corresponding command.
* http://www.gammon.com.au/serial
*/
void processSerialInput(const byte input_byte) {
static char input_line[MAX_COMMAND_SIZE];
static unsigned int input_pos = 0;
switch (input_byte) {
case '\n': // end of text
Serial.println();
input_line[input_pos] = 0;
execute(input_line);
input_pos = 0;
break;
case '\r': // discard carriage return
break;
case '\b': // backspace
if (input_pos > 0) {
input_pos--;
Serial.print(F("\b \b"));
}
break;
default:
if (input_pos == 0) {
Serial.print(F("> "));
}
// keep adding if not full ... allow for terminating null byte
if (input_pos < (MAX_COMMAND_SIZE - 1)) {
input_line[input_pos++] = input_byte;
Serial.print((char) input_byte);
}
break;
}
}
void checkSerialInput() {
while (Serial.available() > 0) {
sensor_console::processSerialInput(Serial.read());
}
}
/*
* Tries to find the corresponding callback for a given command. Name and parameter type should fit.
*/
void execute(const char *command_str) {
CommandLine input;
parseCommand(command_str, input);
for (uint8_t i = 0; i < commands_count; i++) {
if (!strcmp(input.function_name, commands[i].name) && input.argument_type == commands[i].parameter_type) {
Serial.print(F("Calling : "));
Serial.print(input.function_name);
switch (input.argument_type) {
case NONE:
Serial.println(F("()"));
commands[i].voidFunction();
return;
case INT32:
Serial.print(F("("));
Serial.print(input.int_argument);
Serial.println(F(")"));
commands[i].intFunction(input.int_argument);
return;
case STRING:
Serial.print(F("('"));
Serial.print(input.str_argument);
Serial.println(F("')"));
commands[i].strFunction(input.str_argument);
return;
}
}
}
Serial.print(F("'"));
Serial.print(command_str);
Serial.println(F("' not supported. Available commands :"));
listAvailableCommands();
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment