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

Commit fc1ca02

Browse files
committed
Add FireThing, main class for project. Includes config storage and retrieval from eeprom.
1 parent 9ae404e commit fc1ca02

File tree

9 files changed

+269
-33
lines changed

9 files changed

+269
-33
lines changed

src/Thing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "thing/FireThing.h"
12
#include "thing/Transcriber.h"
23
#include "thing/Portal.h"
34
#include "thing/WiFiManager.h"

src/thing/Config.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "Arduino.h"
2+
#include "thing/Config.h"
3+
#include "third-party/arduino-json-5.6.7/include/ArduinoJson.h"
4+
5+
namespace thing {
6+
7+
void Config::SerializeToJson(Stream* output, std::function<void(int size)> handle_size) const {
8+
DynamicJsonBuffer jsonBuffer;
9+
JsonObject& root = jsonBuffer.createObject();
10+
root["host"] = host.c_str();
11+
root["auth"] = auth.c_str();
12+
root["path"] = path.c_str();
13+
root["wifi_ssid"] = wifi_ssid.c_str();
14+
root["wifi_key"] = wifi_key.c_str();
15+
root["analog_activation"] = analog_activation_threshold;
16+
root["wifi_connect_attempts"] = wifi_connect_attempts;
17+
18+
JsonObject& pins_root = root.createNestedObject("pins");
19+
pins_root["digital_in"] = pins.digital_in;
20+
pins_root["digital_out"] = pins.digital_out;
21+
pins_root["analog_in"] = pins.analog_in;
22+
pins_root["analog_out"] = pins.analog_out;
23+
pins_root["config_mode_button"] = pins.config_mode_button;
24+
25+
handle_size(root.measureLength());
26+
root.printTo(*output);
27+
}
28+
29+
void Config::ReadFromJson(const char* string) {
30+
DynamicJsonBuffer jsonBuffer;
31+
JsonObject& root = jsonBuffer.parseObject(string);
32+
host = root["host"].asString();
33+
auth = root["auth"].asString();
34+
path = root["path"].asString();
35+
wifi_ssid = root["wifi_ssid"].asString();
36+
wifi_key = root["wifi_key"].asString();
37+
analog_activation_threshold = root["activation_threshold"];
38+
wifi_connect_attempts = root["wifi_connect_attempts"];
39+
40+
pins.digital_in = root["pins"]["digital_in"];
41+
pins.digital_out = root["pins"]["digital_out"];
42+
pins.analog_in = root["pins"]["analog_in"];
43+
pins.analog_out = root["pins"]["analog_out"];
44+
pins.config_mode_button = root["pins"]["config_mode_button"];
45+
}
46+
47+
};
48+

src/thing/Config.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
#ifndef THING_CONFIG_H
22
#define THING_CONFIG_H
33

4+
#include "Arduino.h"
5+
#include <string>
6+
#include <functional>
7+
48
namespace thing {
59

10+
struct Pins {
11+
int digital_in;
12+
int digital_out;
13+
int analog_in;
14+
int analog_out;
15+
int config_mode_button;
16+
};
17+
618
struct Config {
719
std::string host;
820
std::string auth;
@@ -14,11 +26,12 @@ struct Config {
1426
// If the change is analog value is less than this amount we don't send an
1527
// update.
1628
float analog_activation_threshold;
29+
int wifi_connect_attempts;
30+
31+
Pins pins;
1732

18-
int pin_digital_in;
19-
int pin_digital_out;
20-
int pin_analog_in;
21-
int pin_analog_out;
33+
void SerializeToJson(Stream* output, std::function<void(int size)> handle_size) const;
34+
void ReadFromJson(const char* string);
2235
};
2336

2437
} // namespace thing

src/thing/FireThing.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include "thing/FireThing.h"
2+
#include "Arduino.h"
3+
#include "FS.h"
4+
5+
namespace thing {
6+
namespace {
7+
8+
Config kDefaultConfig = {
9+
"", // firebase host
10+
"", // firebase auth
11+
"/fthing", // path in firebase
12+
"", // wifi ssid
13+
"", // wifi key
14+
0.1, // analog activation threshold
15+
D1, // digital in
16+
BUILTIN_LED, // digital out
17+
A0, // analog in
18+
D1, // analog out
19+
D0, // config mode button
20+
};
21+
22+
} // namespace
23+
24+
FireThing::FireThing() : debug_([](const char*) {}) {}
25+
26+
bool FireThing::Setup() {
27+
Config config;
28+
if (!ReadConfigFromStorage(&config)) {
29+
debug_("Failed to read config from storage.");
30+
return false;
31+
}
32+
SetPinModes(config);
33+
34+
if (digitalRead(config.pins.config_mode_button) || !ConnectToWiFi(config)) {
35+
wifi_.StartAP();
36+
}
37+
38+
portal_.NotifyOnUpdate([this](const Config& config) {
39+
if (!WriteConfigToStorage(config)) {
40+
debug_("Failed to write config to storage.");
41+
}
42+
SetPinModes(config);
43+
transcriber_.UpdateConfig(config);
44+
ConnectToWiFi(config);
45+
});
46+
portal_.Start(config);
47+
}
48+
49+
void FireThing::Loop() {
50+
wifi_.Loop();
51+
portal_.Loop();
52+
transcriber_.Loop();
53+
}
54+
55+
bool FireThing::ConnectToWiFi(const Config& config) {
56+
debug_("Connecting to wifi:");
57+
debug_(config.wifi_ssid.c_str());
58+
debug_(config.wifi_key.c_str());
59+
if (wifi_.Connect(config.wifi_ssid, config.wifi_key)) {
60+
debug_("Connected");
61+
return true;
62+
}
63+
debug_("Failed to Connect.");
64+
return false;
65+
}
66+
67+
void FireThing::SetPinModes(const Config& config) {
68+
pinMode(config.pins.digital_in, INPUT);
69+
pinMode(config.pins.digital_out, OUTPUT);
70+
pinMode(config.pins.analog_in, INPUT);
71+
pinMode(config.pins.analog_out, OUTPUT);
72+
73+
pinMode(config.pins.config_mode_button, INPUT);
74+
}
75+
76+
bool FireThing::ReadConfigFromStorage(Config* config) {
77+
if (!SPIFFS.begin()) {
78+
debug_("Failed to mount FS.");
79+
return false;
80+
}
81+
82+
if (!SPIFFS.exists("fthing.cfg")) {
83+
debug_("Config not found, using default.");
84+
*config = kDefaultConfig;
85+
} else {
86+
File cfg = SPIFFS.open("fthing.cfg", "r");
87+
if (!cfg) {
88+
debug_("Failed to open config for read");
89+
SPIFFS.end();
90+
return false;
91+
}
92+
config->ReadFromJson(cfg.readString().c_str());
93+
debug_("Config read from disk.");
94+
}
95+
96+
SPIFFS.end();
97+
return true;
98+
}
99+
100+
bool FireThing::WriteConfigToStorage(const Config& config) {
101+
if (!SPIFFS.begin()) {
102+
debug_("Failed to mount FS.");
103+
return false;
104+
}
105+
106+
File cfg = SPIFFS.open("fthing.cfg", "w");
107+
if (!cfg) {
108+
debug_("Failed to open config for write");
109+
SPIFFS.end();
110+
return false;
111+
}
112+
config.SerializeToJson(&cfg, [](int){});
113+
114+
SPIFFS.end();
115+
return true;
116+
}
117+
118+
void FireThing::SetDebugHandler(std::function<void(const char* message)> debug) {
119+
debug_ = debug;
120+
wifi_.SetDebugHandler(debug);
121+
portal_.SetDebugHandler(debug);
122+
transcriber_.SetDebugHandler(debug);
123+
}
124+
125+
} // namespace thing

src/thing/FireThing.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#ifndef THING_FIRETHING_H
2+
#define THING_FIRETHING_H
3+
4+
#include "thing/Config.h"
5+
#include "thing/WiFiManager.h"
6+
#include "thing/Transcriber.h"
7+
#include "thing/Portal.h"
8+
9+
namespace thing {
10+
11+
// Operates the device as a FireThing which manages a connection
12+
// between several pins and a firebase database. The configuration
13+
// will be read from and persisted too flash.
14+
class FireThing {
15+
public:
16+
FireThing();
17+
bool Setup();
18+
void Loop();
19+
20+
void SetDebugHandler(std::function<void(const char* message)> debug);
21+
22+
private:
23+
bool ReadConfigFromStorage(Config* config);
24+
bool WriteConfigToStorage(const Config& config);
25+
26+
bool ConnectToWiFi(const Config& config);
27+
void SetPinModes(const Config& config);
28+
29+
WiFiManager wifi_;
30+
Portal portal_;
31+
Transcriber transcriber_;
32+
std::function<void(const char* message)> debug_;
33+
};
34+
35+
} // namespace thing
36+
37+
38+
#endif // THING_FIRETHING_H

src/thing/Portal.cpp

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33

44
namespace thing {
55

6-
Portal::Portal(const Config& config)
7-
: config_(config),
8-
callback_([](const Config&){}),
6+
Portal::Portal()
7+
: callback_([](const Config&){}),
98
debug_([](const char*){}) {}
109

1110
void Portal::SetDebugHandler(std::function<void(const char* message)> handler) {
1211
debug_ = std::move(handler);
1312
}
1413

15-
void Portal::Start() {
14+
void Portal::Start(const Config& config) {
15+
config_ = config;
1616
server_.on("/", [&] () {
1717
static const PROGMEM char page[] = R"(
1818
<head>
@@ -109,32 +109,24 @@ void Portal::Start() {
109109
});
110110

111111
server_.on("/config", [&] () {
112-
DynamicJsonBuffer jsonBuffer;
113112
if (server_.method() == HTTP_GET) {
114-
JsonObject& root = jsonBuffer.createObject();
115-
root["host"] = config_.host.c_str();
116-
root["auth"] = config_.auth.c_str();
117-
root["path"] = config_.path.c_str();
118-
root["wifi_ssid"] = config_.wifi_ssid.c_str();
119-
root["wifi_key"] = config_.wifi_key.c_str();
113+
auto client = server_.client();
114+
config_.SerializeToJson(&client,
115+
[this](int size) {
116+
server_.setContentLength(size);
117+
server_.send(200, "application/json");
118+
});
120119

121-
String buffer;
122-
root.printTo(buffer);
123-
server_.send(200, "application/json", buffer);
124120
debug_("config retrieved");
125121
} else if (server_.method() == HTTP_POST) {
122+
DynamicJsonBuffer jsonBuffer;
126123
if (!server_.hasArg("config")) {
127124
server_.send(500, "text/plain", "Missing config.\r\n");
128125
debug_("Config updated called without param.");
129126
return;
130127
}
131128
String config = server_.arg("config");
132-
JsonObject& root = jsonBuffer.parseObject(config.c_str());
133-
config_.host = root["host"].asString();
134-
config_.auth = root["auth"].asString();
135-
config_.path = root["path"].asString();
136-
config_.wifi_ssid = root["wifi_ssid"].asString();
137-
config_.wifi_key = root["wifi_key"].asString();
129+
config_.ReadFromJson(config.c_str());
138130
callback_(config_);
139131
server_.send(200, "text/plain", "");
140132
debug_("config updated.");

src/thing/Portal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ namespace thing {
88

99
class Portal {
1010
public:
11-
Portal(const Config& config);
11+
Portal();
1212

13-
void Start();
13+
void Start(const Config& config);
1414
void Loop();
1515
void NotifyOnUpdate(std::function<void(const Config& config)> cb);
1616

src/thing/Transcriber.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ namespace {
1010
} // namespace
1111

1212

13-
Transcriber::Transcriber(const Config& config) {
13+
Transcriber::Transcriber() : debug_([](const char*) {}) {}
14+
15+
void Transcriber::Setup(const Config& config) {
1416
Init(config);
1517
}
1618

@@ -21,13 +23,12 @@ void Transcriber::UpdateConfig(const Config& config) {
2123
void Transcriber::Init(const Config& config) {
2224
path_ = config.path;
2325
analog_activation_threshold_ = config.analog_activation_threshold;
24-
pin_digital_out_ = config.pin_digital_out;
25-
pin_digital_in_ = config.pin_digital_in;
26-
pin_analog_out_ = config.pin_analog_out;
27-
pin_analog_in_ = config.pin_analog_in;
26+
pin_digital_out_ = config.pins.digital_out;
27+
pin_digital_in_ = config.pins.digital_in;
28+
pin_analog_out_ = config.pins.analog_out;
29+
pin_analog_in_ = config.pins.analog_in;
2830

2931
fbase_.reset(new Firebase(config.host, config.auth));
30-
stream_ = fbase_->streamPtr(path_);
3132
}
3233

3334
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) {
3839

3940
void Transcriber::Loop() {
4041
if (WiFi.status() != WL_CONNECTED) {
42+
connected_ = false;
4143
return;
4244
}
4345

46+
// If first time connecting start stream.
47+
if (!connected_) {
48+
debug_("Transcriber connected.");
49+
stream_ = fbase_->streamPtr(path_);
50+
connected_ = true;
51+
}
52+
4453
// Read incoming data
4554
if (stream_->available()) {
4655
std::string event_str;
@@ -98,4 +107,8 @@ void Transcriber::ProcessIncrementalUpdate(const FirebaseObject& update) {
98107
}
99108
}
100109

110+
void Transcriber::SetDebugHandler(std::function<void(const char* message)> debug) {
111+
debug_ = debug;
112+
}
113+
101114
} // thing

0 commit comments

Comments
 (0)