spejsiot/spejsiot/SpejsNode.cpp

257 lines
7.6 KiB
C++
Raw Normal View History

2016-06-29 15:00:22 +00:00
#include <SpejsNode.h>
2016-09-18 08:30:34 +00:00
#include <Endpoint.h>
#include <ver.h>
2016-06-29 15:00:22 +00:00
2017-03-06 16:56:37 +00:00
#include <endpoints/ImplementationEndpoint.h>
2017-10-01 21:24:41 +00:00
#define CONFIG_FILE "config.json"
2016-06-29 15:00:22 +00:00
void SpejsNode::init() {
deviceID = WifiStation.getMAC().substring(6, 12);
2016-08-30 19:24:34 +00:00
currentSlot = 0;
if(!rboot_get_last_boot_rom(&currentSlot)) {
currentSlot = rboot_get_current_rom();
2016-08-30 19:24:34 +00:00
}
2016-06-29 15:00:22 +00:00
Serial.begin(115200);
Serial.systemDebugOutput(false); // Debug output to serial
Serial.print("*** SpejsNode init, running on: ");
2016-08-30 19:24:34 +00:00
Serial.print(deviceID);
Serial.printf(", current rom: %d\r\n", currentSlot);
2016-06-29 15:00:22 +00:00
WifiAccessPoint.enable(false);
2016-09-18 08:30:34 +00:00
WifiStation.enable(true);
WifiStation.config(WIFI_SSID, WIFI_PWD);
2016-06-29 15:00:22 +00:00
2017-09-19 23:33:18 +00:00
WifiEvents.onStationGotIP(StationGotIPDelegate(&SpejsNode::gotIP, this));
2016-08-30 19:24:34 +00:00
registerEndpoint("$implementation", new ImplementationEndpoint());
2017-03-06 16:56:37 +00:00
2017-06-12 20:39:38 +00:00
// Keepalive Timer initialization
keepaliveTimer.initializeMs(10000, TimerDelegate(&SpejsNode::keepAliveHandler, this)).start();
2017-09-29 17:34:23 +00:00
statusLED.high();
2017-03-06 16:56:37 +00:00
}
2017-10-01 21:24:41 +00:00
void SpejsNode::loadJSON(std::vector<EndpointInitializer> initializers) {
#ifdef RBOOT_SPIFFS_0
debugf("trying to mount spiffs at 0x%08x, length %d", RBOOT_SPIFFS_0, SPIFF_SIZE);
spiffs_mount_manual(RBOOT_SPIFFS_0, SPIFF_SIZE);
#else
debugf("trying to mount spiffs at 0x%08x, length %d", 0x100000, SPIFF_SIZE);
spiffs_mount_manual(0x100000, SPIFF_SIZE);
#endif
DynamicJsonBuffer jsonBuffer;
if (fileExist(CONFIG_FILE)) {
Serial.println("Found config file");
int size = fileGetSize(CONFIG_FILE);
Serial.printf("%d bytes\n", size);
char* jsonString = new char[size + 1];
fileGetContent(CONFIG_FILE, jsonString, size + 1);
JsonObject& root = jsonBuffer.parseObject(jsonString);
if (root.containsKey("name"))
deviceType = (root["name"]).asString();
2017-03-06 16:56:37 +00:00
2017-10-01 21:24:41 +00:00
JsonObject& data = root["endpoints"].asObject();
for (auto it: data) {
bool found = false;
2017-03-06 16:56:37 +00:00
2017-10-01 21:24:41 +00:00
for(auto init: initializers) {
Endpoint* ep = init(it.value);
if (ep != NULL) {
Serial.printf("%s: got object\n", it.key);
registerEndpoint(it.key, ep);
found = true;
break;
}
}
2017-03-06 16:56:37 +00:00
2017-10-01 21:24:41 +00:00
if (!found) {
Serial.printf("%s: nothing found\n", it.key);
}
}
} else {
Serial.println("No configuration");
2017-03-06 16:56:37 +00:00
}
2016-06-29 15:00:22 +00:00
}
void SpejsNode::keepAliveHandler() {
2016-12-04 22:45:25 +00:00
static int failureCounter = 0;
2017-06-12 20:39:38 +00:00
if(!WifiStation.isConnected()) {
2017-09-29 17:34:23 +00:00
statusLED.high();
2017-06-12 20:39:38 +00:00
Serial.println("keepalive: Network reconnect");
if(failureCounter++ < 5)
WifiStation.connect();
else
System.restart();
} else if(mqtt.getConnectionState() != eTCS_Connected) {
2017-09-29 17:34:23 +00:00
statusLED.high();
2017-06-12 20:39:38 +00:00
Serial.println("keepalive: MQTT reconnect");
2016-12-04 22:45:25 +00:00
if(failureCounter++ < 5)
onConnected();
else
System.restart();
2016-08-30 19:24:34 +00:00
} else {
2017-09-29 17:34:23 +00:00
statusLED.idle();
2016-12-04 22:45:25 +00:00
failureCounter = 0;
uint8_t mode;
2017-06-12 20:39:38 +00:00
if(rboot_get_last_boot_mode(&mode) && mode == MODE_TEMP_ROM) {
rboot_set_current_rom(currentSlot);
Serial.println("Successfuly connected, accepting temp rom");
}
}
}
2017-03-06 16:56:37 +00:00
inline String SpejsNode::DEV_TOPIC(String t) {
return TOPIC_PREFIX + deviceID + "/" + t;
}
void SpejsNode::httpIndex(HttpRequest &request, HttpResponse &response)
{
response.sendString("This is spejsiot device, take a look at: https://wiki.hackerspace.pl/projects:spejsiot\n"
"\nDevice type: " + deviceType +
"\nFirmware version: " + String(BUILD_ID) +
"\nMAC: " + WifiStation.getMAC());
}
/*
* Successful network connection handler
*/
2017-09-19 23:33:18 +00:00
void SpejsNode::gotIP(IPAddress ip, IPAddress netmask, IPAddress gateway) {
onConnected();
}
void SpejsNode::onConnected() {
2017-09-29 17:34:23 +00:00
statusLED.idle();
Serial.println("Connection successful");
// MQTT initialization
mqtt.setWill(DEV_TOPIC("$online"), "false", 1, true);
#ifdef ENABLE_SSL
const uint8_t sha1Fingerprint[] = SSL_FINGERPRINT;
mqtt.connect("iot-" + deviceID, "", "", true);
mqtt.addSslOptions(SSL_SERVER_VERIFY_LATER);
mqtt.setSslFingerprint(sha1Fingerprint, 20);
#else
mqtt.connect("iot-" + deviceID);
#endif
for(unsigned int i = 0 ; i < endpoints.count() ; i++) {
endpoints.valueAt(i)->onConnected();
}
subscribe("$implementation/+");
// Say hello
notify("$online", "true");
notify("$homie", "2");
notify("$name", deviceType);
notify("$localip", WifiStation.getIP().toString());
notify("$mac", WifiStation.getMAC());
notify("$fw/name", "spejsiot");
notify("$fw/version", BUILD_ID);
notify("$fw/slot", String(currentSlot));
// HTTP initialization
http.listen(80);
http.addPath("/", HttpPathDelegate(&SpejsNode::httpIndex, this));
http.setDefaultHandler(HttpPathDelegate(&SpejsNode::httpFile, this));
// mDNS initialization
initializeMDNS();
}
void SpejsNode::httpFile(HttpRequest &request, HttpResponse &response)
{
String file = request.getPath();
if (file[0] == '/')
file = file.substring(1);
if (file.startsWith("api/1/")) {
String req = file.substring(6);
String key = req.substring(0, req.indexOf("/"));
String value = req.substring(req.indexOf("/") + 1);
2016-09-18 08:30:34 +00:00
if(key.length() == 0 || value.length() == 0 || !endpoints.contains(key)) {
2017-09-19 23:33:18 +00:00
response.code = 400;
} else {
2016-09-18 08:30:34 +00:00
EndpointResult result = endpoints[key]->onValue(key, value);
JsonObjectStream* stream = new JsonObjectStream();
JsonObject& json = stream->getRoot();
2016-09-18 08:30:34 +00:00
json["status"] = result.status;
response.sendJsonObject(stream);
}
2016-06-29 15:00:22 +00:00
}
}
void SpejsNode::initializeMDNS() {
2017-03-06 16:56:37 +00:00
/*
2016-09-18 08:30:34 +00:00
static struct mdns_info *info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info));
char tmp_name[32];
("iot-" + deviceID).toCharArray(tmp_name, 32);
2016-09-18 08:30:34 +00:00
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;
char tmp_version[32] = "version=";
int prefix_len = strlen(tmp_version);
strncat(tmp_version, BUILD_ID, 32);
info->txt_data[0] = tmp_version;
char tmp_type[32];
("type=" + deviceType).toCharArray(tmp_type, 32);
2016-09-18 08:30:34 +00:00
info->txt_data[1] = tmp_type;
2016-09-18 08:30:34 +00:00
espconn_mdns_init(info);
2017-03-06 16:56:37 +00:00
*/
2016-06-29 15:00:22 +00:00
}
/*
* Publish on device-specific topic
*/
2016-06-29 15:00:22 +00:00
bool SpejsNode::notify(String key, String value) {
mqtt.publish(DEV_TOPIC(key), value, true);
return mqtt.getConnectionState() == eTCS_Connected;
}
2016-06-29 15:00:22 +00:00
/*
* Subsribe to device-specific topic
*/
bool SpejsNode::subscribe(String topic) {
mqtt.subscribe(DEV_TOPIC(topic));
return mqtt.getConnectionState() == eTCS_Connected;
2016-06-29 15:00:22 +00:00
}
/*
* Register new endpoint
*/
2016-09-18 08:30:34 +00:00
void SpejsNode::registerEndpoint(String key, Endpoint* endpoint) {
2016-10-04 19:06:45 +00:00
endpoints[key] = endpoint;
endpoint->bind(key, this);
2016-06-29 15:00:22 +00:00
}
2016-08-30 19:24:34 +00:00
void SpejsNode::mqttCallback(String origtopic, String value) {
2017-03-06 16:56:37 +00:00
/*int propPos = origtopic.indexOf("/", devicePrefix.length());
String endpoint = origtopic.substring(devicePrefix.length(), propPos);
String property = origtopic.substring(propPos+1, origtopic.indexOf("/", propPos+1));
2016-06-29 15:00:22 +00:00
if(endpoints.contains(endpoint)) {
Serial.printf("%s - %s response: %d\n", endpoint.c_str(), property.c_str(), endpoints[endpoint]->onValue(property, value).status);
2016-08-30 19:24:34 +00:00
} else {
Serial.println("unknown topic? " + endpoint);
2017-03-06 16:56:37 +00:00
}*/
for(unsigned int i = 0 ; i < endpoints.count() ; i++) {
endpoints.valueAt(i)->onMessage(origtopic, value);
2016-08-30 19:24:34 +00:00
}
}