From dad701045c42d2693f5ecc312637aea0602b5034 Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Sun, 18 Sep 2016 10:30:34 +0200 Subject: [PATCH] Refactor endpoints --- spejsiot/Endpoint.cpp | 48 ++++++++++++++++++++++ spejsiot/Endpoint.h | 82 ++++++++++++++++++++++++++++++++++++++ spejsiot/SpejsNode.cpp | 57 ++++++++++++++------------ spejsiot/SpejsNode.h | 11 ++++- switch/app/application.cpp | 12 +----- 5 files changed, 171 insertions(+), 39 deletions(-) create mode 100644 spejsiot/Endpoint.cpp create mode 100644 spejsiot/Endpoint.h diff --git a/spejsiot/Endpoint.cpp b/spejsiot/Endpoint.cpp new file mode 100644 index 0000000..07e25a6 --- /dev/null +++ b/spejsiot/Endpoint.cpp @@ -0,0 +1,48 @@ +#include +#include + +void Endpoint::bind(String key, SpejsNode* _parent) { + parent = _parent; +} + +void Endpoint::notify(String value) { + /*if(parent) + parent->notify(this, value);*/ +} + +template void InputEndpoint::updateValue(T newValue) { + value = newValue; + //if(parent) + // parent->notify(String("xD"), String(value)); +} + +EndpointResult ControlEndpoint::onValue(String key, String value) { + // TODO + + if (value == "ota") { + return 200; + } else if(value == "restart") { + return 200; + } else { + return 400; + } +} + +void OutputEndpoint::fillValue(JsonObject& obj) { + obj["value"] = currentValue; +} + +EndpointResult OutputEndpoint::onValue(String key, String value) { + if (value == "1" or value == "on") { + currentValue = 1; + } else if (value == "0" or value == "off") { + currentValue = 0; + } else if (value == "toggle") { + currentValue = !currentValue; + } else { + return 400; + } + + digitalWrite(pin, inverted ^ currentValue); + return 200; +} diff --git a/spejsiot/Endpoint.h b/spejsiot/Endpoint.h new file mode 100644 index 0000000..ede94bd --- /dev/null +++ b/spejsiot/Endpoint.h @@ -0,0 +1,82 @@ +#ifndef ENDPOINT_H +#define ENDPOINT_H + +#include + +class SpejsNode; + +class EndpointResult { +public: + int status; + String description; + + EndpointResult(int _status) : status(_status) {} + EndpointResult(int _status, String _description) : + status(_status), description(_description) {} +}; + +class Endpoint { +protected: + const SpejsNode* parent; + +public: + String type; + + Endpoint(String _type = "unknown") : type(_type) { } + + virtual void bind(String key, SpejsNode* _parent); + void notify(String value); + + virtual EndpointResult onValue(String key, String value) { + return 400; + } + + virtual void fillValue(JsonObject& obj) { } +}; + +class ControlEndpoint : public Endpoint { +public: + ControlEndpoint() : Endpoint("control") {} + EndpointResult onValue(String key, String value); +}; + +class OutputEndpoint : public Endpoint { +private: + int pin; + bool inverted; + bool currentValue; + +public: + OutputEndpoint(int _pin, bool _inverted = false) : + Endpoint("output"), pin(_pin), inverted(_inverted), currentValue(inverted) { + pinMode(pin, OUTPUT); + digitalWrite(pin, currentValue); + } + + EndpointResult onValue(String key, String value); + void fillValue(JsonObject& obj); +}; + +template class InputEndpoint : public Endpoint { +protected: + T value; + void updateValue(T newValue); + +public: + InputEndpoint(String _type) : Endpoint(_type) {} +}; + +#include + +class DHT22Endpoint : public InputEndpoint { +private: + DHT sensor; + Timer samplingTimer; + int samplingRate; + +public: + DHT22Endpoint(int _pin, int _samplingRate = 10000) : + InputEndpoint("dht22"), sensor(_pin), samplingRate(_samplingRate) {} +}; + +#endif diff --git a/spejsiot/SpejsNode.cpp b/spejsiot/SpejsNode.cpp index 01e6b1c..d61b5c1 100644 --- a/spejsiot/SpejsNode.cpp +++ b/spejsiot/SpejsNode.cpp @@ -1,4 +1,5 @@ #include +#include #include void SpejsNode::init() { @@ -15,10 +16,9 @@ void SpejsNode::init() { Serial.print(deviceID); Serial.printf(", current rom: %d\r\n", currentSlot); - WifiStation.config(WIFI_SSID, WIFI_PWD); - WifiStation.enable(true); - WifiAccessPoint.enable(false); + WifiStation.enable(true); + WifiStation.config(WIFI_SSID, WIFI_PWD); WifiStation.waitConnection( ConnectionDelegate(&SpejsNode::onConnected, this), @@ -26,7 +26,7 @@ void SpejsNode::init() { Serial.println("Connection failed"); }); - inputs["control"] = MqttStringSubscriptionCallback(&SpejsNode::controlHandler, this); + registerEndpoint("control", new ControlEndpoint()); } void SpejsNode::keepAliveHandler() { @@ -50,6 +50,7 @@ void SpejsNode::keepAliveHandler() { void SpejsNode::httpIndex(HttpRequest &request, HttpResponse &response) { + response.sendString("This is spejsiot device, take a look at: https://wiki.hackerspace.pl/projects:spejsiot"); } void SpejsNode::httpMetadata(HttpRequest &request, HttpResponse &response) @@ -61,10 +62,15 @@ void SpejsNode::httpMetadata(HttpRequest &request, HttpResponse &response) json["device_type"] = deviceType; json["rom_slot"] = currentSlot; json["rom_rev"] = BUILD_ID; + json["uptime"] = millis(); - JsonArray& endpoints = json.createNestedArray("endpoints"); - for(unsigned int i = 0; i < inputs.count(); i++) { - endpoints.add(inputs.keyAt(i)); + JsonArray& endpoints_list = json.createNestedArray("endpoints"); + for(unsigned int i = 0; i < endpoints.count(); i++) { + JsonObject& obj = endpoints_list.createNestedObject(); + obj["name"] = endpoints.keyAt(i); + obj["type"] = endpoints.valueAt(i)->type; + + endpoints.valueAt(i)->fillValue(obj); } response.sendJsonObject(stream); } @@ -81,13 +87,13 @@ void SpejsNode::httpFile(HttpRequest &request, HttpResponse &response) String key = req.substring(0, req.indexOf("/")); String value = req.substring(req.indexOf("/") + 1); - if(key.length() == 0 || value.length() == 0 || !inputs.contains(key)) { + if(key.length() == 0 || value.length() == 0 || !endpoints.contains(key)) { response.badRequest(); } else { - inputs[key](key, value); + EndpointResult result = endpoints[key]->onValue(key, value); JsonObjectStream* stream = new JsonObjectStream(); JsonObject& json = stream->getRoot(); - json["status"] = (bool)true; + json["status"] = result.status; response.sendJsonObject(stream); } } else if (file[0] == '.') { @@ -112,10 +118,8 @@ void SpejsNode::onConnected() { mqtt.connect("iot-" + deviceID); #endif - mqtt.subscribe(TOPIC_PREFIX + deviceID + "/control"); - - for(unsigned int i = 0 ; i < inputs.count() ; i++) { - mqtt.subscribe(TOPIC_PREFIX + deviceID + "/" + inputs.keyAt(i)); + for(unsigned int i = 0 ; i < endpoints.count() ; i++) { + mqtt.subscribe(TOPIC_PREFIX + deviceID + "/" + endpoints.keyAt(i)); } mqtt.publish(TOPIC_PREFIX + deviceID + "/state", "online"); @@ -130,20 +134,20 @@ void SpejsNode::onConnected() { http.setDefaultHandler(HttpPathDelegate(&SpejsNode::httpFile, this)); - static struct mdns_info info;// *info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info)); + static struct mdns_info *info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info)); char tmp_name[32]; ("iot-" + deviceID).toCharArray(tmp_name, 32); - info.host_name = tmp_name; // You can replace test with your own host name - info.ipAddr = WifiStation.getIP(); - info.server_name = (char *) "spejsiot"; - info.server_port = 80; - info.txt_data[0] = (char *) "version = now"; + info->host_name = tmp_name; // You can replace test with your own host name + info->ipAddr = WifiStation.getIP(); + info->server_name = (char *) "spejsiot"; + info->server_port = 80; + info->txt_data[0] = (char *) "version = now"; char tmp_type[32] = "type = "; deviceType.toCharArray(tmp_type + 7, 32-7); - info.txt_data[1] = tmp_type; + info->txt_data[1] = tmp_type; - espconn_mdns_init(&info); + espconn_mdns_init(info); } bool SpejsNode::notify(String key, String value) { @@ -155,8 +159,9 @@ bool SpejsNode::notify(String key, String value) { return false; } -void SpejsNode::registerInput(String key, MqttStringSubscriptionCallback callback) { - inputs[key] = callback; +void SpejsNode::registerEndpoint(String key, Endpoint* endpoint) { + endpoints[key] = endpoint; + endpoint->bind(key, this); } void SpejsNode::mqttCallback(String origtopic, String value) { @@ -172,8 +177,8 @@ void SpejsNode::mqttCallback(String origtopic, String value) { Serial.println(topic); Serial.println(value); - if(inputs.contains(topic)) { - inputs[topic](origtopic, value); + if(endpoints.contains(topic)) { + endpoints[topic]->onValue(origtopic, value); } else { Serial.println("unknown topic?"); } diff --git a/spejsiot/SpejsNode.h b/spejsiot/SpejsNode.h index 4a7f7c3..cd55b3f 100644 --- a/spejsiot/SpejsNode.h +++ b/spejsiot/SpejsNode.h @@ -1,6 +1,10 @@ +#ifndef SPEJSNODE_H +#define SPEJSNODE_H + #include #include #include +#include class SpejsNode { protected: @@ -14,13 +18,14 @@ protected: rBootHttpUpdate* otaUpdater = 0; - HashMap inputs; + HashMap endpoints; void onConnected(); void startOTA(); void keepAliveHandler(); uint8_t currentSlot; + public: SpejsNode(String _deviceType) : mqtt(MQTT_BROKER, MQTT_PORT, MqttStringSubscriptionCallback(&SpejsNode::mqttCallback, this)), @@ -30,7 +35,7 @@ public: void init(); bool notify(String key, String value); - void registerInput(String key, MqttStringSubscriptionCallback cb); + void registerEndpoint(String key, Endpoint* cb); void mqttCallback(String, String); void controlHandler(String, String); void otaUpdateCallback(rBootHttpUpdate& updater, bool result); @@ -38,3 +43,5 @@ public: void httpIndex(HttpRequest &request, HttpResponse &response); void httpMetadata(HttpRequest &request, HttpResponse &response); }; + +#endif diff --git a/switch/app/application.cpp b/switch/app/application.cpp index 763fb00..14af955 100644 --- a/switch/app/application.cpp +++ b/switch/app/application.cpp @@ -4,15 +4,5 @@ SpejsNode node("switch"); void init() { node.init(); - node.registerInput("relay", *[](String key, String value) { - Serial.println("handler"); - digitalWrite(5, value == "1" ? HIGH : LOW); - }); - pinMode(5, OUTPUT); - digitalWrite(5, LOW); - attachInterrupt(BTN_PIN, *[] { - node.notify("btn", String(digitalRead(BTN_PIN))); - }, CHANGE); - //node.registerInputGPIO("btn", BTN_PIN); - //node.registerOutputGPIO("led", LED_PIN); + node.registerEndpoint("relay", new OutputEndpoint(5)); }