aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2016-03-13 11:10:51 +0100
committerTrygve Laugstøl <trygvis@inamo.no>2016-03-13 11:10:51 +0100
commit1effc988e95a7c39ed673bbcc840ff20cec4bb75 (patch)
tree33590ebdc9bf2263b18824329c8c522121ec3d62 /src
downloaddiller-1effc988e95a7c39ed673bbcc840ff20cec4bb75.tar.gz
diller-1effc988e95a7c39ed673bbcc840ff20cec4bb75.tar.bz2
diller-1effc988e95a7c39ed673bbcc840ff20cec4bb75.tar.xz
diller-1effc988e95a7c39ed673bbcc840ff20cec4bb75.zip
o Initial import of Diller Arduino library.
Diffstat (limited to 'src')
-rw-r--r--src/diller_client.h209
-rw-r--r--src/diller_core.h71
-rw-r--r--src/diller_serial.h45
-rw-r--r--src/diller_utils.h348
-rw-r--r--src/impl/diller_core_impl.h150
-rw-r--r--src/impl/diller_serial_impl.h183
6 files changed, 1006 insertions, 0 deletions
diff --git a/src/diller_client.h b/src/diller_client.h
new file mode 100644
index 0000000..988db98
--- /dev/null
+++ b/src/diller_client.h
@@ -0,0 +1,209 @@
+#pragma once
+
+#include <SoftwareSerial.h>
+#include <Arduino.h>
+#include "diller_utils.h"
+
+namespace diller {
+namespace client {
+
+using namespace diller::utils;
+
+enum class diller_cmd : uint8_t {
+ UNKNOWN,
+ STATUS,
+ NETWORK,
+ WLAN,
+ PROPERTY,
+ PROPERTIES
+};
+
+class diller_event_listener {
+ public:
+ virtual void on_diller_event(const key_value_map &params) = 0;
+};
+
+class client {
+ public:
+ client() : listener(nullptr) {
+ }
+
+ virtual ~client() {
+ }
+
+ virtual void property(const char *property, const char *value, const char *name) = 0;
+ virtual void property_value(const char *property, const char *value) = 0;
+ virtual void property_name(const char *property, const char *name) = 0;
+ virtual void property_description(const char *property, const char *description) = 0;
+
+ void set_diller_event_listener(diller_event_listener *l) {
+ listener = l;
+ }
+
+ protected:
+ diller_event_listener *listener;
+};
+
+template<typename io_t, typename key_value_map_t = diller::utils::fixed_size_key_value_map<10>>
+class client_software_serial : public client {
+ public:
+ client_software_serial() : client(), params(), parser(params) {
+ }
+
+ void wlan(const char *ssid, const char *password) {
+ io_t::print("wlan ssid=");
+ escape(ssid);
+ io_t::print(" password=");
+ escape(password);
+ }
+
+ void property(const char *property, const char *value, const char *name) {
+ io_t::print("property id=");
+ escape(property);
+ io_t::print(" value=");
+ escape(value);
+ io_t::print(" name=");
+ escape(name);
+ }
+
+ void property_value(const char *property, const char *value) {
+ io_t::print("property id=");
+ escape(property);
+ io_t::print(" value=");
+ escape(value);
+ }
+
+ void property_name(const char *property, const char *name) {
+ io_t::print("property id=");
+ escape(property);
+ io_t::print(" name=");
+ escape(name);
+ }
+
+ void property_description(const char *property, const char *description) {
+ io_t::print("property id=");
+ escape(property);
+ io_t::print(" description=");
+ escape(description);
+ }
+
+ void loop() {
+ auto x = tty.readline();
+ // Serial.print("x=");
+ // Serial.println(static_cast<int>(x));
+ if (x == tty_status::FULL_LINE) {
+ parser.parse(tty.line);
+
+ process_command();
+ }
+ }
+
+ protected:
+ void escape(const char *s) {
+ char c;
+ while ((c = *s++) != '\0') {
+ if (c == ' ') {
+ io_t::print('\\');
+ }
+ io_t::print(c);
+ }
+ }
+
+ void process_command() {
+ if (params.is_empty()) {
+ return;
+ }
+
+ if (!listener) {
+ return;
+ }
+
+ listener->on_diller_event(params);
+ params.clear();
+ }
+
+ private:
+ // SoftwareSerial serial;
+ key_value_map_t params;
+ diller::utils::diller_parser parser;
+ diller::utils::tty<io_t, 100, 3000, false> tty;
+};
+
+void print_diller_event(const key_value_map &params) {
+ if (!params.size()) {
+ return;
+ }
+
+ Serial.print("Diller: ");
+ Serial.print(params.key(0));
+ Serial.print(' ');
+
+ for (uint8_t i = 1; i < params.size(); i++) {
+ auto key = params.key(i);
+ auto value = params.value(i);
+
+ Serial.print(key);
+ if (value) {
+ Serial.print("=");
+ Serial.print(value);
+ }
+ Serial.print(" ");
+ }
+ Serial.println();
+}
+
+class printing_diller_event_listener : public diller_event_listener {
+ public:
+ void on_diller_event(const key_value_map &params) {
+ print_diller_event(params);
+ }
+};
+
+class noop_diller_event_listener : public diller_event_listener {
+ public:
+ void on_diller_event(const key_value_map &params) {
+ auto key = params.key(0);
+ if (strcmp("network", key) == 0) {
+ on_network(params);
+ } else if (strcmp("status", key) == 0) {
+ on_status(params);
+ } else if (strcmp("property", key) == 0) {
+ on_property(params);
+ } else if (strcmp("properties", key) == 0) {
+ on_properties(params);
+ } else if (strcmp("debug", key) == 0) {
+ on_debug(params);
+ } else {
+ on_unknown(params);
+ }
+ }
+
+ protected:
+ virtual void on_network(const key_value_map &params) {
+ static_cast<void>(params);
+ }
+
+ virtual void on_status(const key_value_map &params) {
+ static_cast<void>(params);
+ }
+
+ virtual void on_property(const key_value_map &params) {
+ static_cast<void>(params);
+ }
+
+ virtual void on_properties(const key_value_map &params) {
+ static_cast<void>(params);
+ }
+
+ virtual void on_unknown(const key_value_map &params) {
+ static_cast<void>(params);
+ }
+
+ virtual void on_debug(const key_value_map &params) {
+ static_cast<void>(params);
+ }
+};
+
+} // namespace client
+} // namespace diller
+
diff --git a/src/diller_core.h b/src/diller_core.h
new file mode 100644
index 0000000..a38779c
--- /dev/null
+++ b/src/diller_core.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "diller_utils.h"
+#include <Arduino.h>
+#include <ESP8266WiFi.h>
+
+namespace diller {
+namespace core {
+
+using diller::utils::property;
+
+template<uint8_t max_property_count>
+using props = diller::utils::properties<max_property_count>;
+
+enum class diller_error : uint8_t {
+ OK, INVAL, NOMEM
+};
+
+static
+const char * to_string(diller_error err) {
+ switch (err) {
+ case diller_error::OK:
+ return "ok";
+ case diller_error::INVAL:
+ return "inval";
+ case diller_error::NOMEM:
+ return "nomem";
+ default:
+ return "unknown";
+ }
+}
+
+enum class property_action : uint8_t {
+ VALUE,
+ NAME,
+ DESCRIPTION,
+};
+
+class property_action_listener {
+ public:
+ virtual void on_property_action(const property *, property_action) = 0;
+};
+
+template<uint8_t number_of_properties>
+class core {
+ public:
+ core(const String &mqtt_host, int mqtt_port);
+ void set_property_action_listener(property_action_listener *);
+
+ void setup();
+ void loop();
+
+ bool connected() const;
+
+ diller_error cmd_property(const char *id, const char *value, const char *name);
+ props<number_of_properties> properties;
+
+ const String mqtt_host;
+ const int mqtt_port = 1883;
+ String mac;
+ String client_id;
+
+ private:
+ void callback(char* topic_, byte* payload, unsigned int length);
+ property_action_listener *property_action_listener_;
+};
+
+} // namespace core
+} // namespace diller
+
+#include "impl/diller_core_impl.h"
diff --git a/src/diller_serial.h b/src/diller_serial.h
new file mode 100644
index 0000000..a9a2de4
--- /dev/null
+++ b/src/diller_serial.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "diller_utils.h"
+#include <Arduino.h>
+#include <ESP8266WiFi.h>
+
+namespace diller {
+namespace serial {
+
+using diller::utils::property;
+using diller::core::diller_error;
+using diller::core::property_action;
+
+template<typename d_core, typename io_t>
+class diller_serial : protected diller::core::property_action_listener {
+ public:
+ diller_serial(d_core &diller) : diller(diller), params(), diller_parser(params) {
+ }
+
+ void setup();
+ void loop();
+
+ private:
+ void process_command();
+ void on_property_action(const property *, property_action);
+
+ void cmd_network();
+ void cmd_wlan();
+ void cmd_wlan(const char* ssid, const char* password);
+ void cmd_property(const char *id, const char *value, const char *name);
+ void cmd_list_properties();
+ void show_status(wl_status_t wl_status);
+
+ d_core &diller;
+ diller::utils::fixed_size_key_value_map<10> params;
+ diller::utils::diller_parser diller_parser;
+ diller::utils::tty<io_t, 100, 1000> tty;
+
+ static const bool send_wlan_password = false;
+};
+
+} // namespace serial
+} // namespace diller
+
+#include "impl/diller_serial_impl.h"
diff --git a/src/diller_utils.h b/src/diller_utils.h
new file mode 100644
index 0000000..5b1224d
--- /dev/null
+++ b/src/diller_utils.h
@@ -0,0 +1,348 @@
+#pragma once
+
+#include <Arduino.h>
+
+namespace diller {
+namespace utils {
+
+enum class tty_status : uint8_t {
+ NEED_MORE,
+ TIMEOUT,
+ EMPTY_LINE,
+ FULL_LINE,
+ LINE_OVERFLOW,
+};
+
+class serial_io {
+ public:
+ static auto available() -> decltype(Serial.available()) {
+ return Serial.available();
+ }
+
+ static auto read() -> decltype(Serial.read()) {
+ return Serial.read();
+ }
+
+ template<typename A>
+ static auto print(A a) -> decltype(Serial.print(a)) {
+ return Serial.print(a);
+ }
+
+ template<typename A>
+ static auto println(A a) -> decltype(Serial.println(a)) {
+ return Serial.println(a);
+ }
+};
+
+template<typename instance>
+class software_serial_io {
+ public:
+ static auto available() -> decltype(instance::software_serial.available()) {
+ return instance::software_serial.available();
+ }
+
+ static auto read() -> decltype(instance::software_serial.read()) {
+ return instance::software_serial.read();
+ }
+
+ template<typename A>
+ static auto print(A a) -> decltype(instance::software_serial.print(a)) {
+ return instance::software_serial.print(a);
+ }
+
+ template<typename A>
+ static auto println(A a) -> decltype(instance::software_serial.println(a)) {
+ return instance::software_serial.println(a);
+ }
+};
+
+template<typename io, uint8_t buffer_size, int timeout_ms_, bool debug_ = false>
+class tty {
+ public:
+ char line[buffer_size];
+ uint8_t size = 0;
+ const bool debug = debug_;
+ const unsigned long timeout_ms = timeout_ms_;
+
+ void init(bool reset = false) {
+ if (reset) {
+ line[0] = '\0';
+ }
+
+ size = 0;
+ last_char = 0;
+ }
+
+ void quote(const String &s) {
+ Serial.print(s.c_str());
+ }
+
+ void quote(const char *str) {
+ Serial.print(str);
+ }
+
+ void escape(const char *str) {
+ Serial.print(str);
+ }
+
+ tty_status readline() {
+ while (io::available()) {
+ int c = io::read();
+
+ if (debug) {
+ Serial.print("read: c=");
+ Serial.println(c, HEX);
+ }
+
+ if (c == '\n') {
+ // ignore
+ last_char = millis();
+ } else if (c == '\r') {
+ line[size] = '\0';
+ auto status = size > 0 ? tty_status::FULL_LINE : tty_status::EMPTY_LINE;
+ init();
+
+ if (debug) {
+ Serial.print("debug src=tty state=\"new line\" size=");
+ Serial.print(size, DEC);
+ Serial.print(" line=");
+ quote(line);
+ Serial.println();
+ }
+
+ return status;
+ } else {
+ if (size == buffer_size - 1) {
+
+ if (debug) {
+ Serial.print("debug src=tty state=overflow size=");
+ Serial.print(size, DEC);
+ Serial.print(" line=");
+ quote(line);
+ Serial.println();
+ }
+ init();
+
+ return tty_status::LINE_OVERFLOW;
+ }
+ line[size++] = static_cast<char>(c);
+ last_char = millis();
+ }
+ }
+
+ unsigned long now = millis();
+
+ if (last_char > 0 && now >= (last_char + timeout_ms)) {
+ if (debug) {
+ line[size] = '\0';
+ Serial.print("debug src=tty state=\"timeout\" line=");
+ quote(line);
+ Serial.println();
+ }
+
+ init(true);
+ return tty_status::TIMEOUT;
+ }
+
+ return tty_status::NEED_MORE;
+ }
+ private:
+ unsigned long last_char = 0;
+};
+
+class key_value_map {
+ public:
+ virtual void clear();
+ virtual void put(char *key, char *value) = 0;
+ virtual const char *key(uint8_t index) const = 0;
+ virtual const char *value(uint8_t index) const = 0;
+ virtual const char *find(const char *key) const = 0;
+ virtual uint8_t size() const = 0;
+ virtual bool is_empty() const = 0;
+ virtual bool is_full() const = 0;
+};
+
+template<int max_args>
+class fixed_size_key_value_map : public key_value_map {
+ public:
+ uint8_t size_;
+ static_assert(max_args <= 256, "max_args is too big");
+ char *keys[max_args];
+ char *values[max_args];
+
+ void clear() {
+ size_ = 0;
+ }
+
+ void put(char *key, char *value) {
+ if (size_ < max_args) {
+ keys[size_] = key;
+ values[size_] = value;
+ size_++;
+ }
+ }
+
+ const char *key(uint8_t index) const {
+ return keys[index];
+ }
+
+ const char *value(uint8_t index) const {
+ return values[index];
+ }
+
+ const char *find(const char *key) const {
+ for (int i = 0; i < size_; i++) {
+ if (strcmp(keys[i], key) == 0) {
+ return values[i];
+ }
+ }
+
+ return nullptr;
+ }
+
+ uint8_t size() const {
+ return size_;
+ }
+
+ bool is_empty() const {
+ return size_ >= max_args;
+ }
+
+ bool is_full() const {
+ return size_ >= max_args;
+ }
+};
+
+class diller_parser {
+ public:
+ diller_parser(key_value_map &map) : map(map) {
+ }
+
+ void parse(char *line) {
+ char *c = line;
+ map.clear();
+
+ while (*c != '\0') {
+ while (*c == ' ') {
+ c++;
+ }
+ if (*c == '\0') {
+ break;
+ }
+ char *key = c,
+ *value = nullptr;
+
+ while (*c != ' ' && *c != '\0') {
+ if (*c == '=') {
+ *c = '\0';
+ c++;
+ value = c;
+ }
+
+ c++;
+ }
+
+ map.put(key, value);
+
+ if (*c == '\0' || map.is_full()) {
+ break;
+ }
+
+ *c++ = '\0';
+ }
+ }
+ protected:
+ key_value_map &map;
+};
+
+class property {
+ public:
+ property() : new_(true) {
+ }
+
+ const String &id() const {
+ return id_;
+ }
+
+ const String &value() const {
+ return value_;
+ }
+
+ const String &name() const {
+ return name_;
+ }
+
+ const String &description() const {
+ return description_;
+ }
+
+ bool dirty() const {
+ return dirty_;
+ }
+
+ void init(const String &id) {
+ id_ = id;
+ dirty_ = false;
+ }
+
+ bool is_new() const {
+ return new_;
+ }
+
+ void set_old() {
+ new_ = false;
+ }
+
+ private:
+ String id_;
+ boolean dirty_;
+ boolean new_;
+
+ String value_;
+ String name_;
+ String description_;
+};
+
+template<size_t max_property_count>
+class properties {
+ public:
+ properties() : size_(0) {
+ }
+
+ property* operator[](uint8_t i) {
+ if (i >= size_) {
+ return nullptr;
+ }
+
+ return &properties_[i];
+ }
+
+ property* find(const char *id) {
+ for (int i = 0; i < size_; i++) {
+ if (properties_[i].id() == id) {
+ return &properties_[i];
+ }
+ }
+
+ if (size_ < max_property_count) {
+ auto p = &properties_[size_];
+ size_++;
+ p->init(id);
+ return p;
+ }
+
+ return nullptr;
+ }
+
+ uint8_t size() {
+ return size_;
+ }
+
+ private:
+ property properties_[max_property_count];
+ uint8_t size_;
+};
+
+} // namespace utils
+} // namespace diller
+
diff --git a/src/impl/diller_core_impl.h b/src/impl/diller_core_impl.h
new file mode 100644
index 0000000..1246e59
--- /dev/null
+++ b/src/impl/diller_core_impl.h
@@ -0,0 +1,150 @@
+#include <Arduino.h>
+#include <ESP8266WiFi.h>
+#include <PubSubClient.h>
+
+extern WiFiClient wifi_client;
+extern PubSubClient mqtt_client;
+
+namespace diller {
+namespace core {
+
+using diller::utils::tty_status;
+using diller::utils::property;
+
+// core::core
+
+template<uint8_t number_of_properties>
+core<number_of_properties>::core(const String &mqtt_host, int mqtt_port) :
+ mqtt_host(mqtt_host), mqtt_port(mqtt_port), property_action_listener_(nullptr) {
+ mac = WiFi.macAddress();
+ mac.toLowerCase();
+ client_id = "diller-" + mac;
+}
+
+template<uint8_t number_of_properties>
+void core<number_of_properties>::callback(char* topic_, byte* payload, unsigned int length) {
+ Serial.print("got message on ");
+ Serial.println(topic_);
+ Serial.println("payload");
+ Serial.write(payload, length);
+ Serial.println();
+
+ String prefix = "/diller/" + mac + "/property/";
+ String topic(topic_);
+ if (!topic.startsWith(prefix)) {
+ Serial.print("debug bad-prefix: ");
+ Serial.println(topic);
+ return;
+ }
+
+ topic.remove(0, prefix.length());
+ property *p = nullptr;
+ for (auto i = 0; i < properties.size(); i++) {
+ auto *x = properties[i];
+ if (topic.startsWith(x->id())) {
+ p = x;
+ break;
+ }
+ }
+
+ if (p) {
+ topic.remove(0, p->id().length() + 1);
+
+ Serial.print("debug property=");
+ Serial.print(p->id());
+ Serial.print(", topic=");
+ Serial.println(topic);
+
+ property_action a;
+
+ if (topic == "value") {
+ Serial.println("debug action=value");
+ a = property_action::VALUE;
+ } else if (topic == "name") {
+ Serial.println("debug action=name");
+ a = property_action::NAME;
+ } else if (topic == "description") {
+ Serial.println("debug action=description");
+ a = property_action::DESCRIPTION;
+ } else {
+ return;
+ }
+
+ if (property_action_listener_) {
+ property_action_listener_->on_property_action(p, a);
+ }
+ } else {
+ Serial.print("debug unknown-property");
+ }
+}
+
+template<uint8_t number_of_properties>
+bool core<number_of_properties>::connected() const {
+ return mqtt_client.connected();
+}
+
+template<uint8_t number_of_properties>
+void core<number_of_properties>::setup() {
+ mqtt_client.setServer(mqtt_host.c_str(), mqtt_port);
+ mqtt_client.setCallback([this](char* topic_, byte* payload, unsigned int length) {
+ callback(topic_, payload, length);
+ });
+}
+
+template<uint8_t number_of_properties>
+void core<number_of_properties>::loop() {
+ auto wl_status = WiFi.status();
+
+ if (wl_status == WL_CONNECTED) {
+ if (!mqtt_client.loop()) {
+ Serial.println("status mqtt=connecting");
+ if (mqtt_client.connect(client_id.c_str())) {
+ Serial.println("status mqtt=connected");
+ } else {
+ Serial.println("status mqtt=disconnected");
+ }
+ }
+ }
+}
+
+template<uint8_t number_of_properties>
+diller_error core<number_of_properties>::cmd_property(const char *id, const char *value, const char *name) {
+ if (!id) {
+ return diller_error::INVAL;
+ }
+
+ auto p = properties.find(id);
+
+ if (!p) {
+ return diller_error::NOMEM;
+ }
+
+ if (value) {
+ String topic = "/diller/" + mac + "/property/" + id + "/value";
+ mqtt_client.publish(topic.c_str(), value);
+ }
+
+ if (name) {
+ String topic = "/diller/" + mac + "/property/" + id + "/name";
+ mqtt_client.publish(topic.c_str(), name);
+ }
+
+ if (p->is_new()) {
+ String topic = "/diller/" + mac + "/property/" + id + "/#";
+ mqtt_client.subscribe(topic.c_str());
+ Serial.print("debug subscribing=");
+ Serial.println(topic);
+
+ p->set_old();
+ }
+
+ return diller_error::OK;
+}
+
+template<uint8_t number_of_properties>
+void core<number_of_properties>::set_property_action_listener(property_action_listener *l) {
+ this->property_action_listener_ = l;
+}
+
+} // namespace core
+} // namespace diller
diff --git a/src/impl/diller_serial_impl.h b/src/impl/diller_serial_impl.h
new file mode 100644
index 0000000..47c18b5
--- /dev/null
+++ b/src/impl/diller_serial_impl.h
@@ -0,0 +1,183 @@
+// #include <Arduino.h>
+#include <ESP8266WiFi.h>
+// #include <PubSubClient.h>
+
+extern WiFiClient wifi_client;
+extern PubSubClient mqtt_client;
+
+namespace diller {
+namespace serial {
+
+using diller::utils::tty_status;
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::cmd_network() {
+ Serial.print("ok ip=");
+ WiFi.localIP().printTo(Serial);
+ Serial.print(" gateway=");
+ WiFi.gatewayIP().printTo(Serial);
+ Serial.print(" netmask=");
+ WiFi.subnetMask().printTo(Serial);
+ Serial.println();
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::cmd_wlan() {
+ Serial.print("ok ssid=");
+ tty.quote(WiFi.SSID());
+ if (send_wlan_password) {
+ Serial.print(" password=");
+ Serial.print(WiFi.psk());
+ }
+
+ Serial.print(" mac=");
+ Serial.println(diller.mac);
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::cmd_wlan(const char* ssid, const char* password) {
+ WiFi.begin(ssid, password);
+ Serial.println("ok");
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::cmd_property(const char *id, const char *value, const char *name) {
+ auto ret = diller.cmd_property(id, value, name);
+
+ if (ret != diller_error::OK) {
+ Serial.print("fail error=");
+ Serial.println(to_string(ret));
+ }
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::cmd_list_properties() {
+ Serial.print("ok count=");
+ Serial.println(diller.properties.size());
+ for (auto i = 0; i < diller.properties.size(); i++) {
+ auto p = diller.properties[i];
+ Serial.print("property id=");
+ Serial.print(p->id());
+ Serial.print(" name=");
+ Serial.print(p->name());
+ Serial.print(" description=");
+ Serial.print(p->description());
+ Serial.println();
+ }
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::show_status(wl_status_t wl_status) {
+ const char *wl_status_s;
+ if (wl_status == WL_IDLE_STATUS) {
+ wl_status_s = "idle";
+ } else if (wl_status == WL_NO_SSID_AVAIL) {
+ wl_status_s = "no-ssid";
+ } else if (wl_status == WL_SCAN_COMPLETED) {
+ wl_status_s = "scan-completed";
+ } else if (wl_status == WL_CONNECTED) {
+ wl_status_s = "connected";
+ } else if (wl_status == WL_CONNECT_FAILED) {
+ wl_status_s = "connect-failed";
+ } else if (wl_status == WL_CONNECTION_LOST) {
+ wl_status_s = "connection-lost";
+ } else if (wl_status == WL_DISCONNECTED) {
+ wl_status_s = "disconnected";
+ } else {
+ wl_status_s = "unknown";
+ }
+
+ const char *mqtt_status_s;
+ if (diller.connected()) {
+ mqtt_status_s = "connected";
+ } else {
+ mqtt_status_s = "disconnected";
+ }
+
+ Serial.print("status wlan=");
+ Serial.print(wl_status_s);
+ Serial.print(" mqtt=");
+ Serial.println(mqtt_status_s);
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::process_command() {
+ if (params.is_empty()) {
+ return;
+ }
+
+ auto cmd = params.key(0);
+
+ if (strcmp("network", cmd) == 0) {
+ if (params.size() == 1) {
+ cmd_network();
+ } else {
+ Serial.println("fail error=invalid_argument");
+ }
+ } else if (strcmp("wlan", cmd) == 0) {
+ if (params.size() == 1) {
+ cmd_wlan();
+ } else if (params.size() == 3) {
+ const char* ssid = params.find("ssid");
+ const char* password = params.find("password");
+ cmd_wlan(ssid, password);
+ } else {
+ Serial.println("fail error=invalid_argument");
+ }
+ } else if (strcmp("property", cmd) == 0) {
+ auto id = params.find("id");
+ auto value = params.find("value");
+ auto name = params.find("name");
+ cmd_property(id, value, name);
+ } else if (strcmp("list-properties", cmd) == 0) {
+ cmd_list_properties();
+ } else {
+ Serial.print("fail error=unknown_command cmd=");
+ tty.escape(cmd);
+ Serial.println();
+ }
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::setup() {
+ diller.set_property_action_listener(this);
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::loop() {
+ if (tty.readline() == tty_status::FULL_LINE) {
+ diller_parser.parse(tty.line);
+
+ process_command();
+ }
+
+ static auto last_wl_status = WiFi.status();
+ auto wl_status = WiFi.status();
+
+ static auto last_status = millis();
+ auto now = millis();
+ static const auto show_status_interval = 5000;
+
+ if (last_wl_status != wl_status) {
+ show_status(wl_status);
+ last_wl_status = wl_status;
+ last_status = now;
+ } else if (now > (last_status + show_status_interval)) {
+ show_status(wl_status);
+ last_status = now;
+ }
+}
+
+template<typename d_core, typename io_t>
+void diller_serial<d_core, io_t>::on_property_action(const property *p, property_action) {
+ Serial.print("property id=");
+ tty.quote(p->id());
+ Serial.print(" value=");
+ tty.quote(p->value());
+ Serial.print(" description=");
+ tty.quote(p->description());
+ Serial.println();
+}
+
+} // namespace serial
+} // namespace diller