Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.

Add second peice of firething, the web config portal. #216

Closed
wants to merge 10 commits into from
Closed
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// 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 <ESP8266WiFi.h>
#include <Transcriber.h>

// 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

thing::Config config = {
FIREBASE_HOST,
FIREBASE_AUTH,
FIREBASE_PATH,
WIFI_SSID,
WIFI_PASSWORD,
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);
}
7 changes: 7 additions & 0 deletions src/Firebase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ FirebaseCall::FirebaseCall(const std::string& host, const std::string& auth,
}
}

FirebaseCall::~FirebaseCall() {
if (http_) {
http_->end();
}
}

const JsonObject& FirebaseCall::json() {
//TODO(edcoyne): This is not efficient, we should do something smarter with
//the buffers.
Expand All @@ -157,6 +163,7 @@ FirebaseSet::FirebaseSet(const std::string& host, const std::string& auth,
json_ = response();
}
}

// FirebasePush
FirebasePush::FirebasePush(const std::string& host, const std::string& auth,
const std::string& path, const std::string& value,
Expand Down
2 changes: 1 addition & 1 deletion src/Firebase.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class FirebaseCall {
const char* method, const std::string& path,
const std::string& data = "",
FirebaseHttpClient* http = NULL);
virtual ~FirebaseCall() {}
virtual ~FirebaseCall();

virtual const FirebaseError& error() const {
return error_;
Expand Down
10 changes: 5 additions & 5 deletions src/FirebaseObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ FirebaseObject::FirebaseObject(const char* data) : data_{data} {
// See: https://github.com/bblanchon/ArduinoJson/issues/279
}

bool FirebaseObject::getBool(const String& path) {
bool FirebaseObject::getBool(const String& path) const {
JsonVariant variant = getJsonVariant(path);
if (!variant.is<bool>()) {
error_ = "failed to convert to bool";
Expand All @@ -34,7 +34,7 @@ bool FirebaseObject::getBool(const String& path) {
return static_cast<bool>(variant);
}

int FirebaseObject::getInt(const String& path) {
int FirebaseObject::getInt(const String& path) const {
JsonVariant variant = getJsonVariant(path);
if (!variant.is<int>() && !variant.is<float>()) {
error_ = "failed to convert to number";
Expand All @@ -43,7 +43,7 @@ int FirebaseObject::getInt(const String& path) {
return static_cast<int>(variant);
}

float FirebaseObject::getFloat(const String& path) {
float FirebaseObject::getFloat(const String& path) const {
JsonVariant variant = getJsonVariant(path);
if (!variant.is<float>() && !variant.is<int>()) {
error_ = "failed to convert to number";
Expand All @@ -52,7 +52,7 @@ float FirebaseObject::getFloat(const String& path) {
return static_cast<float>(variant);
}

String FirebaseObject::getString(const String& path) {
String FirebaseObject::getString(const String& path) const {
JsonVariant variant = getJsonVariant(path);
if (!variant.is<const char *>()) {
error_ = "failed to convert to string";
Expand All @@ -61,7 +61,7 @@ String FirebaseObject::getString(const String& path) {
return static_cast<const char*>(variant);
}

JsonVariant FirebaseObject::getJsonVariant(const String& path) {
JsonVariant FirebaseObject::getJsonVariant(const String& path) const {
String key(path);
char* start = &key[0];
char* end = start + key.length();
Expand Down
12 changes: 6 additions & 6 deletions src/FirebaseObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,35 +41,35 @@ class FirebaseObject {
* \param optional path in the JSON object.
* \return result as a bool.
*/
bool getBool(const String& path = "");
bool getBool(const String& path = "") const;

/**
* Return the value as an int.
* \param optional path in the JSON object.
* \return result as an integer.
*/
int getInt(const String& path = "");
int getInt(const String& path = "") const;

/**
* Return the value as a float.
* \param optional path in the JSON object.
* \return result as a float.
*/
float getFloat(const String& path = "");
float getFloat(const String& path = "") const;

/**
* Return the value as a String.
* \param optional path in the JSON object.
* \return result as a String.
*/
String getString(const String& path = "");
String getString(const String& path = "") const;

/**
* Return the value as a JsonVariant.
* \param optional path in the JSON object.
* \return result as a JsonVariant.
*/
JsonVariant getJsonVariant(const String& path = "");
JsonVariant getJsonVariant(const String& path = "") const;


/**
Expand All @@ -94,7 +94,7 @@ class FirebaseObject {
String data_;
StaticJsonBuffer<FIREBASE_JSONBUFFER_SIZE> buffer_;
JsonVariant json_;
String error_;
mutable String error_;
};

#endif // FIREBASE_OBJECT_H
1 change: 1 addition & 0 deletions src/Transcriber.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "thing/Transcriber.h"
22 changes: 22 additions & 0 deletions src/thing/Config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef THING_CONFIG_H
#define THING_CONFIG_H

namespace thing {

struct Config {
std::string host;
std::string auth;
std::string path;

std::string wifi_ssid;
std::string wifi_key;

int pin_digital_in;
int pin_digital_out;
int pin_analog_in;
int pin_analog_out;
};

} // namespace thing

#endif // THING_CONFIG_H
112 changes: 112 additions & 0 deletions src/thing/Portal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include "thing/Portal.h"
#include "third-party/arduino-json-5.6.7/include/ArduinoJson.h"

namespace thing {

Portal::Portal(const Config& config) : config_(config), callback_([](const Config&){}) {}

void Portal::Start() {
server_.on("/", [&] () {
static const PROGMEM char page[] = R"(
<head>
<script>
function fetch_config() {
document.getElementById('loading').style.display='inline'
var xhr = new XMLHttpRequest();
xhr.open("GET", "/config", true);
xhr.onreadystatechange = function () {
if (xhr.readyState==4 && xhr.status==200) {
populate_values(JSON.parse(xhr.responseText));
document.getElementById('loading').style.display='none'
}
}
xhr.send();
}
function populate_values(config) {
document.getElementById('host').value = config.host;
document.getElementById('auth').value = config.auth;
document.getElementById('path').value = config.path;
document.getElementById('ssid').value = config.wifi_ssid;
document.getElementById('key').value = config.wifi_key;
}
function build_config() {
var config = {
host : document.getElementById('host').value,
auth : document.getElementById('auth').value,
path : document.getElementById('path').value,
wifi_ssid : document.getElementById('ssid').value,
wifi_key : document.getElementById('key').value
};
return config;
}
function send_config() {
document.getElementById('saving').style.display='inline'
var xhr = new XMLHttpRequest();
xhr.open("POST", "/config", true);
xhr.send("config=" + JSON.stringify(build_config()));
xhr.onreadystatechange = function () {
if (xhr.readyState==4 && xhr.status==200) {
document.getElementById('saving').style.display='none'
}
}
}
</script>
</head>
<body>
<div>Host: <input id='host'></div>
<div>Auth: <input id='auth'></div>
<div>Path: <input id='path'></div>
<div>Wifi SSID: <input id='ssid'></div>
<div>Wifi Key: <input id='key'></div>
<div><button onclick='send_config();'>Save</button></div>
<div id='loading'>Loading....</div>
<div id='saving' style='display:none'>Saving....</div>
<script>fetch_config();</script>
</body>
)";
static const PROGMEM char type[] = "text/html";

server_.send_P(200, type, page);
});

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();

String buffer;
root.printTo(buffer);
server_.send(200, "application/json", buffer);
} else if (server_.method() == HTTP_POST) {
if (!server_.hasArg("config")) {
server_.send(500, "text/plain", "Missing config.\r\n");
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();
callback_(config_);
server_.send(200, "text/plain", "");
}
});
server_.begin();
}

void Portal::Loop() {
server_.handleClient();
}

void Portal::NotifyOnUpdate(std::function<void(const Config& config)> callback) {
callback_ = callback;
}

};
26 changes: 26 additions & 0 deletions src/thing/Portal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef THING_PORTAL_H
#define THING_PORTAL_H

#include "ESP8266WebServer.h"
#include "thing/Config.h"

namespace thing {

class Portal {
public:
Portal(const Config& config);

void Start();
void Loop();
void NotifyOnUpdate(std::function<void(const Config& config)> cb);

private:
Config config_;
ESP8266WebServer server_;
std::function<void(const Config& config)> callback_;

};

} // namespace thing

#endif // THING_PORTAL_H
Loading