From fc1ca027a223e1621032f9249f16340aa1bdc1a5 Mon Sep 17 00:00:00 2001 From: Ed Coyne Date: Fri, 2 Dec 2016 16:43:49 -0800 Subject: [PATCH 1/7] Add FireThing, main class for project. Includes config storage and retrieval from eeprom. --- src/Thing.h | 1 + src/thing/Config.cpp | 48 +++++++++++++++ src/thing/Config.h | 21 +++++-- src/thing/FireThing.cpp | 125 ++++++++++++++++++++++++++++++++++++++ src/thing/FireThing.h | 38 ++++++++++++ src/thing/Portal.cpp | 32 ++++------ src/thing/Portal.h | 4 +- src/thing/Transcriber.cpp | 25 ++++++-- src/thing/Transcriber.h | 8 ++- 9 files changed, 269 insertions(+), 33 deletions(-) create mode 100644 src/thing/Config.cpp create mode 100644 src/thing/FireThing.cpp create mode 100644 src/thing/FireThing.h diff --git a/src/Thing.h b/src/Thing.h index 6e4e09ca..5a5ed0e8 100644 --- a/src/Thing.h +++ b/src/Thing.h @@ -1,3 +1,4 @@ +#include "thing/FireThing.h" #include "thing/Transcriber.h" #include "thing/Portal.h" #include "thing/WiFiManager.h" diff --git a/src/thing/Config.cpp b/src/thing/Config.cpp new file mode 100644 index 00000000..f2aa6183 --- /dev/null +++ b/src/thing/Config.cpp @@ -0,0 +1,48 @@ +#include "Arduino.h" +#include "thing/Config.h" +#include "third-party/arduino-json-5.6.7/include/ArduinoJson.h" + +namespace thing { + +void Config::SerializeToJson(Stream* output, std::function handle_size) const { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.createObject(); + root["host"] = host.c_str(); + root["auth"] = auth.c_str(); + root["path"] = path.c_str(); + root["wifi_ssid"] = wifi_ssid.c_str(); + root["wifi_key"] = wifi_key.c_str(); + root["analog_activation"] = analog_activation_threshold; + root["wifi_connect_attempts"] = wifi_connect_attempts; + + JsonObject& pins_root = root.createNestedObject("pins"); + pins_root["digital_in"] = pins.digital_in; + pins_root["digital_out"] = pins.digital_out; + pins_root["analog_in"] = pins.analog_in; + pins_root["analog_out"] = pins.analog_out; + pins_root["config_mode_button"] = pins.config_mode_button; + + handle_size(root.measureLength()); + root.printTo(*output); +} + +void Config::ReadFromJson(const char* string) { + DynamicJsonBuffer jsonBuffer; + JsonObject& root = jsonBuffer.parseObject(string); + host = root["host"].asString(); + auth = root["auth"].asString(); + path = root["path"].asString(); + wifi_ssid = root["wifi_ssid"].asString(); + wifi_key = root["wifi_key"].asString(); + analog_activation_threshold = root["activation_threshold"]; + wifi_connect_attempts = root["wifi_connect_attempts"]; + + pins.digital_in = root["pins"]["digital_in"]; + pins.digital_out = root["pins"]["digital_out"]; + pins.analog_in = root["pins"]["analog_in"]; + pins.analog_out = root["pins"]["analog_out"]; + pins.config_mode_button = root["pins"]["config_mode_button"]; +} + +}; + diff --git a/src/thing/Config.h b/src/thing/Config.h index 3c3d5af3..418ad8cc 100644 --- a/src/thing/Config.h +++ b/src/thing/Config.h @@ -1,8 +1,20 @@ #ifndef THING_CONFIG_H #define THING_CONFIG_H +#include "Arduino.h" +#include +#include + namespace thing { +struct Pins { + int digital_in; + int digital_out; + int analog_in; + int analog_out; + int config_mode_button; +}; + struct Config { std::string host; std::string auth; @@ -14,11 +26,12 @@ struct Config { // If the change is analog value is less than this amount we don't send an // update. float analog_activation_threshold; + int wifi_connect_attempts; + + Pins pins; - int pin_digital_in; - int pin_digital_out; - int pin_analog_in; - int pin_analog_out; + void SerializeToJson(Stream* output, std::function handle_size) const; + void ReadFromJson(const char* string); }; } // namespace thing diff --git a/src/thing/FireThing.cpp b/src/thing/FireThing.cpp new file mode 100644 index 00000000..fdaa485e --- /dev/null +++ b/src/thing/FireThing.cpp @@ -0,0 +1,125 @@ +#include "thing/FireThing.h" +#include "Arduino.h" +#include "FS.h" + +namespace thing { +namespace { + +Config kDefaultConfig = { + "", // firebase host + "", // firebase auth + "/fthing", // path in firebase + "", // wifi ssid + "", // wifi key + 0.1, // analog activation threshold + D1, // digital in + BUILTIN_LED, // digital out + A0, // analog in + D1, // analog out + D0, // config mode button +}; + +} // namespace + +FireThing::FireThing() : debug_([](const char*) {}) {} + +bool FireThing::Setup() { + Config config; + if (!ReadConfigFromStorage(&config)) { + debug_("Failed to read config from storage."); + return false; + } + SetPinModes(config); + + if (digitalRead(config.pins.config_mode_button) || !ConnectToWiFi(config)) { + wifi_.StartAP(); + } + + portal_.NotifyOnUpdate([this](const Config& config) { + if (!WriteConfigToStorage(config)) { + debug_("Failed to write config to storage."); + } + SetPinModes(config); + transcriber_.UpdateConfig(config); + ConnectToWiFi(config); + }); + portal_.Start(config); +} + +void FireThing::Loop() { + wifi_.Loop(); + portal_.Loop(); + transcriber_.Loop(); +} + +bool FireThing::ConnectToWiFi(const Config& config) { + debug_("Connecting to wifi:"); + debug_(config.wifi_ssid.c_str()); + debug_(config.wifi_key.c_str()); + if (wifi_.Connect(config.wifi_ssid, config.wifi_key)) { + debug_("Connected"); + return true; + } + debug_("Failed to Connect."); + return false; +} + +void FireThing::SetPinModes(const Config& config) { + pinMode(config.pins.digital_in, INPUT); + pinMode(config.pins.digital_out, OUTPUT); + pinMode(config.pins.analog_in, INPUT); + pinMode(config.pins.analog_out, OUTPUT); + + pinMode(config.pins.config_mode_button, INPUT); +} + +bool FireThing::ReadConfigFromStorage(Config* config) { + if (!SPIFFS.begin()) { + debug_("Failed to mount FS."); + return false; + } + + if (!SPIFFS.exists("fthing.cfg")) { + debug_("Config not found, using default."); + *config = kDefaultConfig; + } else { + File cfg = SPIFFS.open("fthing.cfg", "r"); + if (!cfg) { + debug_("Failed to open config for read"); + SPIFFS.end(); + return false; + } + config->ReadFromJson(cfg.readString().c_str()); + debug_("Config read from disk."); + } + + SPIFFS.end(); + return true; +} + +bool FireThing::WriteConfigToStorage(const Config& config) { + if (!SPIFFS.begin()) { + debug_("Failed to mount FS."); + return false; + } + + File cfg = SPIFFS.open("fthing.cfg", "w"); + if (!cfg) { + debug_("Failed to open config for write"); + SPIFFS.end(); + return false; + } + config.SerializeToJson(&cfg, [](int){}); + + SPIFFS.end(); + return true; +} + +void FireThing::SetDebugHandler(std::function debug) { + debug_ = debug; + wifi_.SetDebugHandler(debug); + portal_.SetDebugHandler(debug); + transcriber_.SetDebugHandler(debug); +} + +} // namespace thing diff --git a/src/thing/FireThing.h b/src/thing/FireThing.h new file mode 100644 index 00000000..594d9acc --- /dev/null +++ b/src/thing/FireThing.h @@ -0,0 +1,38 @@ +#ifndef THING_FIRETHING_H +#define THING_FIRETHING_H + +#include "thing/Config.h" +#include "thing/WiFiManager.h" +#include "thing/Transcriber.h" +#include "thing/Portal.h" + +namespace thing { + +// Operates the device as a FireThing which manages a connection +// between several pins and a firebase database. The configuration +// will be read from and persisted too flash. +class FireThing { + public: + FireThing(); + bool Setup(); + void Loop(); + + void SetDebugHandler(std::function debug); + + private: + bool ReadConfigFromStorage(Config* config); + bool WriteConfigToStorage(const Config& config); + + bool ConnectToWiFi(const Config& config); + void SetPinModes(const Config& config); + + WiFiManager wifi_; + Portal portal_; + Transcriber transcriber_; + std::function debug_; +}; + +} // namespace thing + + +#endif // THING_FIRETHING_H diff --git a/src/thing/Portal.cpp b/src/thing/Portal.cpp index 8135ba8c..63234c47 100644 --- a/src/thing/Portal.cpp +++ b/src/thing/Portal.cpp @@ -3,16 +3,16 @@ namespace thing { -Portal::Portal(const Config& config) - : config_(config), - callback_([](const Config&){}), +Portal::Portal() + : callback_([](const Config&){}), debug_([](const char*){}) {} void Portal::SetDebugHandler(std::function handler) { debug_ = std::move(handler); } -void Portal::Start() { +void Portal::Start(const Config& config) { + config_ = config; server_.on("/", [&] () { static const PROGMEM char page[] = R"( @@ -109,32 +109,24 @@ void Portal::Start() { }); server_.on("/config", [&] () { - DynamicJsonBuffer jsonBuffer; if (server_.method() == HTTP_GET) { - JsonObject& root = jsonBuffer.createObject(); - root["host"] = config_.host.c_str(); - root["auth"] = config_.auth.c_str(); - root["path"] = config_.path.c_str(); - root["wifi_ssid"] = config_.wifi_ssid.c_str(); - root["wifi_key"] = config_.wifi_key.c_str(); + auto client = server_.client(); + config_.SerializeToJson(&client, + [this](int size) { + server_.setContentLength(size); + server_.send(200, "application/json"); + }); - String buffer; - root.printTo(buffer); - server_.send(200, "application/json", buffer); debug_("config retrieved"); } else if (server_.method() == HTTP_POST) { + DynamicJsonBuffer jsonBuffer; if (!server_.hasArg("config")) { server_.send(500, "text/plain", "Missing config.\r\n"); debug_("Config updated called without param."); return; } String config = server_.arg("config"); - JsonObject& root = jsonBuffer.parseObject(config.c_str()); - config_.host = root["host"].asString(); - config_.auth = root["auth"].asString(); - config_.path = root["path"].asString(); - config_.wifi_ssid = root["wifi_ssid"].asString(); - config_.wifi_key = root["wifi_key"].asString(); + config_.ReadFromJson(config.c_str()); callback_(config_); server_.send(200, "text/plain", ""); debug_("config updated."); diff --git a/src/thing/Portal.h b/src/thing/Portal.h index 7fcd6de1..8aa17630 100644 --- a/src/thing/Portal.h +++ b/src/thing/Portal.h @@ -8,9 +8,9 @@ namespace thing { class Portal { public: - Portal(const Config& config); + Portal(); - void Start(); + void Start(const Config& config); void Loop(); void NotifyOnUpdate(std::function cb); diff --git a/src/thing/Transcriber.cpp b/src/thing/Transcriber.cpp index bd967149..967c2229 100644 --- a/src/thing/Transcriber.cpp +++ b/src/thing/Transcriber.cpp @@ -10,7 +10,9 @@ namespace { } // namespace -Transcriber::Transcriber(const Config& config) { +Transcriber::Transcriber() : debug_([](const char*) {}) {} + +void Transcriber::Setup(const Config& config) { Init(config); } @@ -21,13 +23,12 @@ void Transcriber::UpdateConfig(const Config& config) { void Transcriber::Init(const Config& config) { path_ = config.path; analog_activation_threshold_ = config.analog_activation_threshold; - pin_digital_out_ = config.pin_digital_out; - pin_digital_in_ = config.pin_digital_in; - pin_analog_out_ = config.pin_analog_out; - pin_analog_in_ = config.pin_analog_in; + pin_digital_out_ = config.pins.digital_out; + pin_digital_in_ = config.pins.digital_in; + pin_analog_out_ = config.pins.analog_out; + pin_analog_in_ = config.pins.analog_in; fbase_.reset(new Firebase(config.host, config.auth)); - stream_ = fbase_->streamPtr(path_); } void Transcriber::SetValue(const std::string& path, const std::string& value) { @@ -38,9 +39,17 @@ void Transcriber::SetValue(const std::string& path, const std::string& value) { void Transcriber::Loop() { if (WiFi.status() != WL_CONNECTED) { + connected_ = false; return; } + // If first time connecting start stream. + if (!connected_) { + debug_("Transcriber connected."); + stream_ = fbase_->streamPtr(path_); + connected_ = true; + } + // Read incoming data if (stream_->available()) { std::string event_str; @@ -98,4 +107,8 @@ void Transcriber::ProcessIncrementalUpdate(const FirebaseObject& update) { } } +void Transcriber::SetDebugHandler(std::function debug) { + debug_ = debug; +} + } // thing diff --git a/src/thing/Transcriber.h b/src/thing/Transcriber.h index 0727c17e..a03fdd5f 100644 --- a/src/thing/Transcriber.h +++ b/src/thing/Transcriber.h @@ -29,10 +29,13 @@ namespace thing { class Transcriber { public: - Transcriber(const Config& config); + Transcriber(); + void Setup(const Config& config); void UpdateConfig(const Config& config); void Loop(); + void SetDebugHandler(std::function handler); + private: void Init(const Config& config); @@ -57,6 +60,9 @@ class Transcriber { int pin_analog_in_; std::string path_; + + bool connected_ = false; + std::function debug_; }; }; // thing From 6614c878efdc86fa50c2d9020a000269e33e7b43 Mon Sep 17 00:00:00 2001 From: Ed Coyne Date: Fri, 2 Dec 2016 16:50:53 -0800 Subject: [PATCH 2/7] Removed Transcriber example and added full Firething example. --- .../FirebaseTranscriber_ESP8266.ino | 73 ------------------- .../Firething_ESP8266/Firething_ESP8266.ino | 39 ++++++++++ 2 files changed, 39 insertions(+), 73 deletions(-) delete mode 100644 examples/FirebaseTranscriber_ESP8266/FirebaseTranscriber_ESP8266.ino create mode 100644 examples/Firething_ESP8266/Firething_ESP8266.ino diff --git a/examples/FirebaseTranscriber_ESP8266/FirebaseTranscriber_ESP8266.ino b/examples/FirebaseTranscriber_ESP8266/FirebaseTranscriber_ESP8266.ino deleted file mode 100644 index e3aee423..00000000 --- a/examples/FirebaseTranscriber_ESP8266/FirebaseTranscriber_ESP8266.ino +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright 2016 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// FirebaseDemo_ESP8266 is a sample that binds several pins to paths in -// firebase using the transcriber object. - -#include -#include - -// Set these to run example. -#define FIREBASE_HOST "example.firebaseio.com" -#define FIREBASE_AUTH "token_or_secret" -#define WIFI_SSID "SSID" -#define WIFI_PASSWORD "PASSWORD" - -#define FIREBASE_PATH "/fthing" -#define DIGITAL_IN D1 -#define DIGITAL_OUT BUILTIN_LED -#define ANALOG_IN A0 -#define ANALOG_OUT D8 -#define ANALOG_ACTIVATION_THRESHOLD 0.1 - - -thing::Config config = { - FIREBASE_HOST, - FIREBASE_AUTH, - FIREBASE_PATH, - WIFI_SSID, - WIFI_PASSWORD, - ANALOG_ACTIVATION_THRESHOLD, - DIGITAL_IN, - DIGITAL_OUT, - ANALOG_IN, - ANALOG_OUT}; - -void setup() { - Serial.begin(9600); - - // connect to wifi. - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - Serial.print("connecting"); - while (WiFi.status() != WL_CONNECTED) { - Serial.print("."); - delay(500); - } - Serial.println(); - Serial.print("connected: "); - Serial.println(WiFi.localIP()); - - pinMode(DIGITAL_IN, INPUT); - pinMode(DIGITAL_OUT, OUTPUT); - pinMode(ANALOG_IN, INPUT); - pinMode(ANALOG_OUT, OUTPUT); -} - -void loop() { - static thing::Transcriber tscribe(config); - tscribe.Loop(); - delay(200); -} diff --git a/examples/Firething_ESP8266/Firething_ESP8266.ino b/examples/Firething_ESP8266/Firething_ESP8266.ino new file mode 100644 index 00000000..e6095bbb --- /dev/null +++ b/examples/Firething_ESP8266/Firething_ESP8266.ino @@ -0,0 +1,39 @@ +// +// Copyright 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// FirethingDemo_ESP8266 is a sample that demos operation of the firething +// portion of this library. This is a firmware for the esp that acts as +// a bridge between pins on the esp and a firebase database. This includes +// a captive configuration portal. + + +#include +#include + +thing::FireThing fire_thing; + +void setup() { + Serial.begin(9600); + Serial.println("Firething starting up..."); + fire_thing.SetDebugHandler([](const char* message) { Serial.println(message); }); + fire_thing.Setup(); +} + +void loop() { + Serial.println("."); + fire_thing.Loop(); + delay(100); +} From 702a49b427f7afd1036d92fd98144f38583ab199 Mon Sep 17 00:00:00 2001 From: Ed Coyne Date: Fri, 2 Dec 2016 16:56:32 -0800 Subject: [PATCH 3/7] Fix for travis test without config variables --- examples/Firething_ESP8266/Firething_ESP8266.ino | 3 +++ test/travis/check_all_examples_use_standard_init.sh | 2 ++ test/travis/no_config_init.cc.snip | 1 + 3 files changed, 6 insertions(+) create mode 100644 test/travis/no_config_init.cc.snip diff --git a/examples/Firething_ESP8266/Firething_ESP8266.ino b/examples/Firething_ESP8266/Firething_ESP8266.ino index e6095bbb..e96c73b4 100644 --- a/examples/Firething_ESP8266/Firething_ESP8266.ino +++ b/examples/Firething_ESP8266/Firething_ESP8266.ino @@ -23,6 +23,9 @@ #include #include +// No config variables. +// Everything is handled through portal. + thing::FireThing fire_thing; void setup() { diff --git a/test/travis/check_all_examples_use_standard_init.sh b/test/travis/check_all_examples_use_standard_init.sh index 6f9785eb..82a2270e 100755 --- a/test/travis/check_all_examples_use_standard_init.sh +++ b/test/travis/check_all_examples_use_standard_init.sh @@ -1,11 +1,13 @@ #!/bin/bash FBASE_SNIPPET=test/travis/firebase_init.cc.snip FBASE_NOAUTH_SNIPPET=test/travis/no_firebase_init.cc.snip +FBASE_NOCONFIG_SNIPPET=test/travis/no_config_init.cc.snip for example in `find examples/ -name *.ino`; do echo $example; (xxd -p $example | tr -d '\n' | grep -q `xxd -p $FBASE_SNIPPET | tr -d '\n'`) || (xxd -p $example | tr -d '\n' | grep -q `xxd -p $FBASE_NOAUTH_SNIPPET | tr -d '\n'`) || + (xxd -p $example | tr -d '\n' | grep -q `xxd -p $FBASE_NOCONFIG_SNIPPET | tr -d '\n'`) || if [ $? -ne 0 ]; then echo $example does not contain standard defined in test/travis/*_init.cc.snip. diff --git a/test/travis/no_config_init.cc.snip b/test/travis/no_config_init.cc.snip new file mode 100644 index 00000000..ee370500 --- /dev/null +++ b/test/travis/no_config_init.cc.snip @@ -0,0 +1 @@ +// No config variables. From d2fad69de70ebb952d9122a6c1249d5b6a3d7c2e Mon Sep 17 00:00:00 2001 From: Ed Coyne Date: Fri, 2 Dec 2016 17:06:05 -0800 Subject: [PATCH 4/7] minor cleanups --- examples/Firething_ESP8266/Firething_ESP8266.ino | 7 ++++++- src/thing/FireThing.cpp | 8 +++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/Firething_ESP8266/Firething_ESP8266.ino b/examples/Firething_ESP8266/Firething_ESP8266.ino index e96c73b4..52b6fc3c 100644 --- a/examples/Firething_ESP8266/Firething_ESP8266.ino +++ b/examples/Firething_ESP8266/Firething_ESP8266.ino @@ -36,7 +36,12 @@ void setup() { } void loop() { - Serial.println("."); fire_thing.Loop(); + + if (i++ % 10) { + Serial.print("."); + }else { + Serial.println("."); + } delay(100); } diff --git a/src/thing/FireThing.cpp b/src/thing/FireThing.cpp index fdaa485e..e1f8fe80 100644 --- a/src/thing/FireThing.cpp +++ b/src/thing/FireThing.cpp @@ -19,6 +19,8 @@ Config kDefaultConfig = { D0, // config mode button }; +const char kStorageFilename[] = "fthing.cfg"; + } // namespace FireThing::FireThing() : debug_([](const char*) {}) {} @@ -79,11 +81,11 @@ bool FireThing::ReadConfigFromStorage(Config* config) { return false; } - if (!SPIFFS.exists("fthing.cfg")) { + if (!SPIFFS.exists(kStorageFilename)) { debug_("Config not found, using default."); *config = kDefaultConfig; } else { - File cfg = SPIFFS.open("fthing.cfg", "r"); + File cfg = SPIFFS.open(kStorageFilename, "r"); if (!cfg) { debug_("Failed to open config for read"); SPIFFS.end(); @@ -103,7 +105,7 @@ bool FireThing::WriteConfigToStorage(const Config& config) { return false; } - File cfg = SPIFFS.open("fthing.cfg", "w"); + File cfg = SPIFFS.open(kStorageFilename, "w"); if (!cfg) { debug_("Failed to open config for write"); SPIFFS.end(); From a9a0e7e43f33a670f4a25b3b790507bf617d5808 Mon Sep 17 00:00:00 2001 From: Ed Coyne Date: Fri, 2 Dec 2016 17:08:17 -0800 Subject: [PATCH 5/7] back to what I know works --- examples/Firething_ESP8266/Firething_ESP8266.ino | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/Firething_ESP8266/Firething_ESP8266.ino b/examples/Firething_ESP8266/Firething_ESP8266.ino index 52b6fc3c..b2e6b628 100644 --- a/examples/Firething_ESP8266/Firething_ESP8266.ino +++ b/examples/Firething_ESP8266/Firething_ESP8266.ino @@ -38,10 +38,6 @@ void setup() { void loop() { fire_thing.Loop(); - if (i++ % 10) { - Serial.print("."); - }else { - Serial.println("."); - } - delay(100); + Serial.println("."); + delay(250); } From 01864ad205774874b6cc3fad1582b42c0473707f Mon Sep 17 00:00:00 2001 From: Ed Coyne Date: Mon, 5 Dec 2016 10:10:43 -0800 Subject: [PATCH 6/7] Changed to mutable char* for reading config --- src/thing/Config.cpp | 2 +- src/thing/Config.h | 4 +++- src/thing/FireThing.cpp | 4 +++- src/thing/Portal.cpp | 12 ++++++++++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/thing/Config.cpp b/src/thing/Config.cpp index f2aa6183..559ce508 100644 --- a/src/thing/Config.cpp +++ b/src/thing/Config.cpp @@ -26,7 +26,7 @@ void Config::SerializeToJson(Stream* output, std::function handl root.printTo(*output); } -void Config::ReadFromJson(const char* string) { +void Config::ReadFromJson(char* string) { DynamicJsonBuffer jsonBuffer; JsonObject& root = jsonBuffer.parseObject(string); host = root["host"].asString(); diff --git a/src/thing/Config.h b/src/thing/Config.h index 418ad8cc..c2dcdac1 100644 --- a/src/thing/Config.h +++ b/src/thing/Config.h @@ -31,7 +31,9 @@ struct Config { Pins pins; void SerializeToJson(Stream* output, std::function handle_size) const; - void ReadFromJson(const char* string); + + // We need a mutable char array here, otherwise a copy will be made. + void ReadFromJson(char* string); }; } // namespace thing diff --git a/src/thing/FireThing.cpp b/src/thing/FireThing.cpp index e1f8fe80..00696d8b 100644 --- a/src/thing/FireThing.cpp +++ b/src/thing/FireThing.cpp @@ -91,7 +91,9 @@ bool FireThing::ReadConfigFromStorage(Config* config) { SPIFFS.end(); return false; } - config->ReadFromJson(cfg.readString().c_str()); + char buffer[cfg.size()]; + cfg.readBytes(buffer, cfg.size()); + config->ReadFromJson(buffer); debug_("Config read from disk."); } diff --git a/src/thing/Portal.cpp b/src/thing/Portal.cpp index 63234c47..76925a38 100644 --- a/src/thing/Portal.cpp +++ b/src/thing/Portal.cpp @@ -125,8 +125,16 @@ void Portal::Start(const Config& config) { debug_("Config updated called without param."); return; } - String config = server_.arg("config"); - config_.ReadFromJson(config.c_str()); + + char* buffer; + { // Scoped to free String memory. + String config = server_.arg("config"); + buffer = (char*)malloc(config.length+1()); + memcpy(buffer, config.c_str(), config.length()+1); + } + config_.ReadFromJson(buffer); + free(buffer); + callback_(config_); server_.send(200, "text/plain", ""); debug_("config updated."); From 67c880d543d47612eca34c5a62a18555a3cabf74 Mon Sep 17 00:00:00 2001 From: Ed Coyne Date: Fri, 9 Dec 2016 10:09:12 -0800 Subject: [PATCH 7/7] fixed typo --- src/thing/Portal.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thing/Portal.cpp b/src/thing/Portal.cpp index 76925a38..672873e3 100644 --- a/src/thing/Portal.cpp +++ b/src/thing/Portal.cpp @@ -129,7 +129,7 @@ void Portal::Start(const Config& config) { char* buffer; { // Scoped to free String memory. String config = server_.arg("config"); - buffer = (char*)malloc(config.length+1()); + buffer = (char*)malloc(config.length()+1); memcpy(buffer, config.c_str(), config.length()+1); } config_.ReadFromJson(buffer);