Adeed documentation, examples and the possibility to connect to an MQTT server using anonymous mode.
This commit is contained in:
parent
c3d0d2007e
commit
447115f839
61
examples/01_actions.ino
Normal file
61
examples/01_actions.ino
Normal file
@ -0,0 +1,61 @@
|
||||
#include <simple_iot.h>
|
||||
|
||||
/**
|
||||
* This example shows how to use actions.
|
||||
* Three actions are defined:
|
||||
* * "on" and "off" set Pin 13 to HIGH or LOW, respectively. They are provided as lambda functions
|
||||
* and don't care about the payload they're given.
|
||||
* * "set" is defined as function reference triggering only if the payload is "ON" or "OFF".
|
||||
*
|
||||
* You can access them via HTTP by sending a POST request to `/on`, `/off` or `/set`. There's a
|
||||
* nice-ish website at `/`, listing all registered handlers. If you kept the suggested hostname,
|
||||
* this link should lead you there: http://basic-test/.
|
||||
*
|
||||
* If you enabled MQTT, cou can also publish data via MQTT to trigger those actions. Again, if you
|
||||
* didn't change the topic below, it would be `basic-test-mqtt-topic/on`, `basic-test-mqtt-topic/off`
|
||||
* and `basic-test-mqtt-topic/set`.
|
||||
*/
|
||||
|
||||
SimpleIOT* iot = NULL;
|
||||
|
||||
/** Do something
|
||||
*/
|
||||
bool setValue(String payload) {
|
||||
// Check the payload.
|
||||
if (payload.compareTo("ON")==0) {
|
||||
// Turn the pin to HIGH.
|
||||
digitalWrite(13, HIGH);
|
||||
// return true to indicate that the action was successful.
|
||||
return true;
|
||||
} else if (payload.compareTo("OFF")==0) {
|
||||
// Turn the pin to LOW.
|
||||
digitalWrite(13, LOW);
|
||||
// return true to indicate that the action was successful.
|
||||
return true;
|
||||
}
|
||||
// If we reach this point, the payload was neither "ON" nor "OFF". So we don't do nothing.
|
||||
// If the action was initiated using a HTTP POST request, an error will be returned instead of "OK".
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
// Set pin 13 to be an OUTPUT.
|
||||
pinMode(13, OUTPUT);
|
||||
|
||||
// Initialize SimpleIOT, giving it a WiFi SSID and the matching password to connect as well as a hostname to use.
|
||||
iot = new SimpleIOT("ssid", "password", "basic-test");
|
||||
// Set data for an MQTT server. You can omit this line if you don't want to use MQTT.
|
||||
iot->setMQTTData("1.2.3.4", 1883, "basic-test-mqtt-user", "basic-test-mqtt-password", "basic-test-mqtt-topic/");
|
||||
|
||||
// Define three actions.
|
||||
iot->act_on("on", [](String payload)->bool{ digitalWrite(13, HIGH); return true; });
|
||||
iot->act_on("off", [](String payload)->bool{ digitalWrite(13, LOW); return true; });
|
||||
iot->act_on("set", setValue);
|
||||
|
||||
iot->begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
iot->loop();
|
||||
}
|
45
examples/02_reports.ino
Normal file
45
examples/02_reports.ino
Normal file
@ -0,0 +1,45 @@
|
||||
#include <simple_iot.h>
|
||||
|
||||
/**
|
||||
* This example shows how to use reports.
|
||||
* Two reports are defined:
|
||||
* * "free_heap" returns the amount of free heap space. The method is provided as lambda function.
|
||||
* Since `interval` ist set to 0, it will not be reported via MQTT, making it accessible only
|
||||
* via HTTP.
|
||||
* * "uptime" returns the current uptime in seconds. It will be reported via MQTT (as long as you
|
||||
* keep MQTT enabled) every 10 seconds. Since `cache_only` is set to true, the method won't be
|
||||
* called any more often than that.
|
||||
*
|
||||
* You can access them via HTTP GET request to `/free_heap` or `/uptime`. There's a
|
||||
* nice-ish website at `/`, listing all registered reports along with (cached) data from them.
|
||||
* If you kept the suggested hostname, this link should lead you there: http://basic-test/.
|
||||
*
|
||||
* If you enabled MQTT, "free_heap" will be published every 10 seconds. Again, if you
|
||||
* didn't change the topic below, it would be `basic-test-mqtt-topic/free_heap`.
|
||||
*/
|
||||
|
||||
SimpleIOT* iot = NULL;
|
||||
|
||||
String uptime() {
|
||||
return String(millis() / 1000);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// Set pin 13 to be an OUTPUT.
|
||||
pinMode(13, OUTPUT);
|
||||
|
||||
// Initialize SimpleIOT, giving it a WiFi SSID and the matching password to connect as well as a hostname to use.
|
||||
iot = new SimpleIOT("ssid", "password", "basic-test");
|
||||
// Set data for an MQTT server. You can omit this line if you don't want to use MQTT.
|
||||
iot->setMQTTData("1.2.3.4", 1883, "basic-test-mqtt-user", "basic-test-mqtt-password", "basic-test-mqtt-topic/");
|
||||
|
||||
// Define three actions.
|
||||
iot->report_on("free_heap", []()->String{ return String(ESP.free_heap()); }, 0, false);
|
||||
iot->report_on("uptime", uptime, 10000, true);
|
||||
|
||||
iot->begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
iot->loop();
|
||||
}
|
@ -11,6 +11,9 @@
|
||||
"type": "git",
|
||||
"url": "https://git.schle.nz/fabian/simple-iot"
|
||||
},
|
||||
"export": {
|
||||
"exclude": "examples"
|
||||
},
|
||||
"version": "0.1.0",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "espressif8266",
|
||||
|
206
simple_iot.h
206
simple_iot.h
@ -39,10 +39,13 @@ private:
|
||||
long _mqtt_last_reconnect_attempt = 0;
|
||||
const char* _mqtt_host;
|
||||
uint16_t _mqtt_port;
|
||||
bool _mqtt_auth = false;
|
||||
const char* _mqtt_user;
|
||||
const char* _mqtt_pass;
|
||||
const char* _mqtt_topic;
|
||||
unsigned long _startup_complete_at = 0;
|
||||
bool _chip_id_added = false;
|
||||
bool _initialized = false;
|
||||
|
||||
void _setup();
|
||||
void _wifi_setup();
|
||||
@ -69,15 +72,27 @@ public:
|
||||
void setMQTTData(const char* mqtt_host, uint16_t mqtt_port,
|
||||
const char* mqtt_user, const char* mqtt_pass,
|
||||
const char* mqtt_topic);
|
||||
void setMQTTData(const char* mqtt_host, uint16_t mqtt_port,
|
||||
const char* mqtt_topic);
|
||||
void addChipIdToHostname();
|
||||
void begin();
|
||||
char* hostname;
|
||||
void loop();
|
||||
bool act_on(String topic, IOTActionHandlerFunction f);
|
||||
bool report_on(String topic, IOTReportHandlerFunction f, unsigned long update_interval, bool use_cache);
|
||||
void log(const char* fmt, ...) __attribute__((format (printf, 2, 3)));
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new instance of SimpleIOT.
|
||||
*
|
||||
* @param wifi_ssid SSID of the WiFi to join.
|
||||
* @param wifi_pass Password of the WiFi to join.
|
||||
* @param hostname The hostname this device will use to identify itself.
|
||||
* It will be used as WiFi client name and for the mDNS stuff
|
||||
* of the OTA daemon.
|
||||
*
|
||||
* @see addChipIdToHostname()
|
||||
*/
|
||||
SimpleIOT::SimpleIOT(const char* wifi_ssid, const char* wifi_pass, String hostname) {
|
||||
Serial.begin(74880);
|
||||
_wifi_ssid = wifi_ssid;
|
||||
@ -85,34 +100,108 @@ SimpleIOT::SimpleIOT(const char* wifi_ssid, const char* wifi_pass, String hostna
|
||||
_hostname = hostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the internal ID of the ESP8266 to the hostname given in the constructor.
|
||||
* This makes the hostname a network with multiple ESP8266s.
|
||||
*
|
||||
* Example: `iot_test` becomes `iot_text-13D93B0A`.
|
||||
*
|
||||
* @warning This method has to be called before calling begin().
|
||||
*/
|
||||
void SimpleIOT::addChipIdToHostname() {
|
||||
if (_initialized) return;
|
||||
if (_chip_id_added) return;
|
||||
char* temp = new char[9];
|
||||
snprintf(temp, 9, "-%08X", ESP.getChipId());
|
||||
String temp2(_hostname);
|
||||
temp2.concat(temp);
|
||||
delete temp;
|
||||
_hostname = temp2.c_str();
|
||||
_chip_id_added = true;
|
||||
}
|
||||
|
||||
void SimpleIOT::setStartupDelay(uint16_t seconds) {
|
||||
if (seconds > 0) {
|
||||
_startup_complete_at = millis() + seconds * 1000;
|
||||
/**
|
||||
* Defines a startup delay to give a chance of doing an OTA update.
|
||||
* During development there are situations where a bug in code leads to quickly
|
||||
* rebooting devices. Since this can be quite a nuisance when working with non-
|
||||
* local devices, you can set this to delay the startup a bit to give yourself a
|
||||
* chance of starting an OTA upgrade at the right moment.
|
||||
* Startup will be more or less paused with only OTA being active. This happens
|
||||
* in begin().
|
||||
*
|
||||
* @param delay Delay in seconds to wait during startup. Set to 0 to disable
|
||||
(default).
|
||||
*
|
||||
* @warning This method has to be called before calling begin().
|
||||
*/
|
||||
void SimpleIOT::setStartupDelay(uint16_t delay) {
|
||||
if (_initialized) return;
|
||||
if (delay > 0) {
|
||||
_startup_complete_at = millis() + delay * 1000;
|
||||
} else {
|
||||
_startup_complete_at = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets connection data for use with an MQTT server. This also *enables* using
|
||||
* an MQTT server - not calling this method will lead to SimpleIOT working
|
||||
* happily without MQTT.
|
||||
* This is for connecting with authentication.
|
||||
*
|
||||
* @param host Hostname or IP address of an MQTT server.
|
||||
* @param port Port of the MQTT server (usually 1883 for unencrypted connections).
|
||||
* @param user Username for authentication.
|
||||
* @param pass Password for authentication.
|
||||
* @param topic Base topic to publish and subscribe to. Must end with a slash.
|
||||
*
|
||||
* @warning This method has to be called before calling begin().
|
||||
*/
|
||||
|
||||
void SimpleIOT::setMQTTData(const char* host, uint16_t port,
|
||||
const char* user, const char* pass,
|
||||
const char* topic) {
|
||||
_mqtt_host = host;
|
||||
_mqtt_port = port;
|
||||
if (_initialized) return;
|
||||
setMQTTData(host, port, topic);
|
||||
_mqtt_user = user;
|
||||
_mqtt_pass = pass;
|
||||
_mqtt_auth = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets connection data for use with an MQTT server. This also *enables* using
|
||||
* an MQTT server - not calling this method will lead to SimpleIOT working
|
||||
* happily without MQTT.
|
||||
* This is for connecting anonymously.
|
||||
*
|
||||
* @param host Hostname or IP address of an MQTT server.
|
||||
* @param port Port of the MQTT server (usually 1883 for unencrypted connections).
|
||||
* @param topic Base topic to publish and subscribe to. Must end with a slash.
|
||||
*
|
||||
* @warning This method has to be called before calling begin().
|
||||
*/
|
||||
|
||||
void SimpleIOT::setMQTTData(const char* host, uint16_t port,
|
||||
const char* topic) {
|
||||
if (_initialized) return;
|
||||
_mqtt_host = host;
|
||||
_mqtt_port = port;
|
||||
_mqtt_topic = topic;
|
||||
_mqtt_enabled = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts connecting to services.
|
||||
* 1. A Wifi connection is attempted. If it fails, the ESP is restarted.
|
||||
* 2. OTA is set up.
|
||||
* 3. If setStartupDelay() was used to set a startup delay, this delay will be
|
||||
* spent waiting for a possible upgrade via OTA.
|
||||
* 4. If MQTT was enabled using setMQTTData(), a connection to the server will
|
||||
* be initialized.
|
||||
* 5. A HTTP server will be configured and started on port 80.
|
||||
*
|
||||
* @note You should call this method in your setup() block.
|
||||
*/
|
||||
void SimpleIOT::begin() {
|
||||
log("Core * Setting up Wifi...");
|
||||
_wifi_setup();
|
||||
@ -133,8 +222,16 @@ void SimpleIOT::begin() {
|
||||
}
|
||||
log("Core * Setting up HTTP...");
|
||||
_http_setup();
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for updates.
|
||||
* 1. OTA, MQTT (if enabled) and HTTP are checked for incoming data.
|
||||
* 2. Methods defined using report_on() are checked if an update is in order.
|
||||
*
|
||||
* @note This method should be called from your loop() block.
|
||||
*/
|
||||
void SimpleIOT::loop() {
|
||||
_ota_loop();
|
||||
|
||||
@ -148,6 +245,7 @@ void SimpleIOT::loop() {
|
||||
|
||||
void SimpleIOT::_wifi_setup() {
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.hostname(_hostname);
|
||||
WiFi.begin(_wifi_ssid, _wifi_pass);
|
||||
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
|
||||
Serial.println("WiFi * Connection Failed! Rebooting...");
|
||||
@ -198,7 +296,13 @@ void SimpleIOT::_ota_loop() {
|
||||
bool SimpleIOT::_mqtt_connect() {
|
||||
String topic(_mqtt_topic);
|
||||
topic.concat("status");
|
||||
if (_mqtt_client.connect(_hostname.c_str(), _mqtt_user, _mqtt_pass, topic.c_str(), 0, true, "OFFLINE", true)) {
|
||||
bool connection_successful = false;
|
||||
if (_mqtt_auth) {
|
||||
connection_successful = _mqtt_client.connect(_hostname.c_str(), _mqtt_user, _mqtt_pass, topic.c_str(), 0, true, "OFFLINE");
|
||||
} else {
|
||||
connection_successful = _mqtt_client.connect(_hostname.c_str(), topic.c_str(), 0, true, "OFFLINE");
|
||||
}
|
||||
if (connection_successful) {
|
||||
char buffer[60];
|
||||
#ifdef DEBUG
|
||||
snprintf(buffer, 60, "ONLINE %s %s %s", _hostname.c_str(), WiFi.localIP().toString().c_str(), DEBUG);
|
||||
@ -210,6 +314,8 @@ bool SimpleIOT::_mqtt_connect() {
|
||||
topic = String(_mqtt_topic);
|
||||
topic.concat("#");
|
||||
_mqtt_client.subscribe(topic.c_str());
|
||||
} else {
|
||||
log("Could not connect to MQTT server. Error was %d", _mqtt_client.state());
|
||||
}
|
||||
return _mqtt_client.connected();
|
||||
}
|
||||
@ -340,7 +446,21 @@ bool SimpleIOT::_has_report_handler(String topic) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defines a topic to act on incoming data.
|
||||
* Actions can be anything you want: Switching on a relay, rebooting the ESP, ...
|
||||
* You can trigger this by (up to) two ways:
|
||||
* 1. By sending a POST request to `/<TOPIC>` containing the payload, or
|
||||
* 2. (If you enabled MQTT) by publishing your payload to `<BASE_TOPIC>/<TOPIC>`,
|
||||
* with BASE_TOPIC being the topic you set with setMQTTData().
|
||||
*
|
||||
* @param topic The topic to listen on. May not start or end with a slash and may
|
||||
* also not be `status` or `log`.
|
||||
* @param f A function to call when data for this topic is received. This function
|
||||
* will be given the payload of the request.
|
||||
*
|
||||
* @returns true if the handler function could be added.
|
||||
*/
|
||||
bool SimpleIOT::act_on(String topic, IOTActionHandlerFunction f) {
|
||||
if (topic.startsWith("/") || topic.endsWith("/") || topic.compareTo("status")==0 || topic.compareTo("log")==0) {
|
||||
return false;
|
||||
@ -350,6 +470,27 @@ bool SimpleIOT::act_on(String topic, IOTActionHandlerFunction f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a topic to report data to.
|
||||
* Data is reported using (up to) two ways:
|
||||
* 1. As answer to a GET request to `/<TOPIC>`, or
|
||||
* 2. (If you enabled MQTT) by publishing the data to `<BASE_TOPIC>/<TOPIC>`,
|
||||
* with BASE_TOPIC being the topic you set with setMQTTData().
|
||||
*
|
||||
* @param topic The topic to listen on. May not start or end with a slash and may
|
||||
* also not be `status` or `log`.
|
||||
* @param f A function to call to receive the current data for this topic. This
|
||||
* function has to return the data as a String object.
|
||||
* @param interval Interval in ms to report this data. If MQTT is enabled, this
|
||||
* method will be called in this interval and its result will be
|
||||
* published.
|
||||
* @param cache_only If set to `true`, requesting the data via a GET request to
|
||||
* the HTTP server will return a cached value, unless at least
|
||||
* `interval` has passed. Use this for functions that take a
|
||||
* long time to process.
|
||||
*
|
||||
* @returns true if the handler function could be added.
|
||||
*/
|
||||
bool SimpleIOT::report_on(String topic, IOTReportHandlerFunction f, unsigned long interval, bool cache_only) {
|
||||
if (topic.startsWith("/") || topic.endsWith("/") || topic.compareTo("status")==0 || topic.compareTo("log")==0) {
|
||||
return false;
|
||||
@ -404,6 +545,14 @@ void SimpleIOT::_check_report_handlers() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message using Serial and (if enabled) MQTT.
|
||||
* Message is processed by sprintf with a maximum length of 128.
|
||||
* If MQTT is enabled, log messages are published at `<BASE_TOPIC>/log`.
|
||||
*
|
||||
* @param fmt Message or format string in printf syntax.
|
||||
* @param ... Data to insert into the format string.
|
||||
*/
|
||||
void SimpleIOT::log(const char* fmt, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, fmt);
|
||||
@ -417,3 +566,42 @@ void SimpleIOT::log(const char* fmt, ...) {
|
||||
}
|
||||
Serial.println(buffer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @example 01_actions.ino
|
||||
*
|
||||
* This example shows how to use actions.
|
||||
* Three actions are defined:
|
||||
* * "on" and "off" set Pin 13 to HIGH or LOW, respectively. They are provided as lambda functions
|
||||
* and don't care about the payload they're given.
|
||||
* * "set" is defined as function reference triggering only if the payload is "ON" or "OFF".
|
||||
*
|
||||
* You can access them via HTTP by sending a POST request to `/on`, `/off` or `/set`. There's a
|
||||
* nice-ish website at `/`, listing all registered handlers. If you kept the suggested hostname,
|
||||
* this link should lead you there: http://basic-test/.
|
||||
*
|
||||
* If you enabled MQTT, cou can also publish data via MQTT to trigger those actions. Again, if you
|
||||
* didn't change the topic below, it would be `basic-test-mqtt-topic/on`, `basic-test-mqtt-topic/off`
|
||||
* and `basic-test-mqtt-topic/set`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example 02_reports.ino
|
||||
*
|
||||
* This example shows how to use reports.
|
||||
* Two reports are defined:
|
||||
* * "free_heap" returns the amount of free heap space. The method is provided as lambda function.
|
||||
* Since `interval` ist set to 0, it will not be reported via MQTT, making it accessible only
|
||||
* via HTTP.
|
||||
* * "uptime" returns the current uptime in seconds. It will be reported via MQTT (as long as you
|
||||
* keep MQTT enabled) every 10 seconds. Since `cache_only` is set to true, the method won't be
|
||||
* called any more often than that.
|
||||
*
|
||||
* You can access them via HTTP GET request to `/free_heap` or `/uptime`. There's a
|
||||
* nice-ish website at `/`, listing all registered reports along with (cached) data from them.
|
||||
* If you kept the suggested hostname, this link should lead you there: http://basic-test/.
|
||||
*
|
||||
* If you enabled MQTT, "free_heap" will be published every 10 seconds. Again, if you
|
||||
* didn't change the topic below, it would be `basic-test-mqtt-topic/free_heap`.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user