Boot as AP, Configuration, TempSensor etc

This commit is contained in:
Roar Fredriksen 2018-03-20 01:21:49 +01:00
parent f8fe34a454
commit c991403e25
6 changed files with 534 additions and 79 deletions

View File

@ -5,20 +5,40 @@
*/
#include <DallasTemperature.h>
#include <OneWire.h>
#include <ArduinoJson.h>
#include <PubSubClient.h>
#include "configuration.h"
#include "accesspoint.h"
#include <HanReader.h>
#include <Kaifa.h>
#include <Kamstrup.h>
#define WIFI_CONNECTION_TIMEOUT 30000;
#define TEMP_SENSOR_PIN 5 // Temperature sensor connected to GPIO5
OneWire oneWire(TEMP_SENSOR_PIN);
DallasTemperature tempSensor(&oneWire);
long lastTempDebug = 0;
accesspoint ap;
WiFiClient *client;
PubSubClient mqtt;
HardwareSerial* debugger;
// The HAN Port reader
HanReader hanReader;
// the setup function runs once when you press reset or power the board
void setup()
{
debugger = &Serial;
// Setup serial port for debugging
Serial.begin(115200);
while (!Serial);
Serial.println("Started...");
debugger->begin(2400, SERIAL_8E1);
while (!&debugger);
debugger->println("Started...");
// Assign pin for boot as AP
delay(1000);
@ -33,13 +53,376 @@ void setup()
// Turn off the blue LED
digitalWrite(2, HIGH);
if (!ap.isActivated)
{
setupWiFi();
hanReader.setup(&Serial, 2400, SERIAL_8E1, debugger);
hanReader.compensateFor09HeaderBug = (ap.config.meterType == 1); // To compensate for the known Kaifa bug
}
}
void setupWiFi()
{
if (ap.config.isSecure())
client = new WiFiClientSecure();
else
client = new WiFiClient();
mqtt = PubSubClient(*client);
WiFi.enableAP(false);
WiFi.begin(ap.config.ssid, ap.config.ssidPassword);
mqtt.setServer(ap.config.mqtt, ap.config.mqttPort);
//std::function<void(char*, unsigned char*, unsigned int)> vCallback = MakeDelegate(this, xnsClientClass::mqttMessageReceived);
mqtt.setCallback(mqttMessageReceived);
MQTT_connect();
sendMqttData("Connected!");
}
void mqttMessageReceived(char* topic, unsigned char* payload, unsigned int length)
{
// make it a null-terminated string
char message[1000];
for (int i = 0; i < length; i++)
message[i] = payload[i];
message[length] = 0;
debugger->println("Incoming MQTT message:");
debugger->print("[");
debugger->print(topic);
debugger->print("] ");
debugger->println(message);
}
// the loop function runs over and over again until power down or reset
void loop()
{
// Only do normal stupp if we're not booted as AP
if (!ap.loop())
{
// Only do normal stupp if we're not booted as AP
mqtt.loop();
delay(10); // <- fixes some issues with WiFi stability
if (!mqtt.connected()) {
MQTT_connect();
}
else
{
debugTemperature();
readHanPort();
}
}
}
void debugTemperature()
{
if (lastTempDebug + 5000 < millis())
{
lastTempDebug = millis();
tempSensor.requestTemperatures();
float temperature = tempSensor.getTempCByIndex(0);
debugger->print("Temperature is ");
debugger->print(temperature);
debugger->println(" degrees");
}
}
void readHanPort()
{
switch (ap.config.meterType)
{
case 1: // Kaifa
readHanPort_Kaifa();
break;
case 2: // Kamstrup
readHanPort_Kamstrup();
break;
case 3: // Aidon
readHanPort_Aidon();
break;
default:
debugger->print("Meter type ");
debugger->print(ap.config.meterType, HEX);
debugger->println(" is unknown");
delay(10000);
break;
}
}
void readHanPort_Aidon()
{
debugger->println("Meter type Aidon is not yet implemented");
delay(10000);
}
void readHanPort_Kamstrup()
{
if (hanReader.read())
{
// Get the list identifier
int listSize = hanReader.getListSize();
// Only care for the ACtive Power Imported, which is found in the first list
if (listSize == (int)Kamstrup::List1 || listSize == (int)Kamstrup::List2)
{
if (listSize == (int)Kamstrup::List1)
{
String id = hanReader.getString((int)Kamstrup_List1::ListVersionIdentifier);
if (debugger) debugger->println(id);
}
else if (listSize == (int)Kamstrup::List2)
{
String id = hanReader.getString((int)Kamstrup_List2::ListVersionIdentifier);
if (debugger) debugger->println(id);
}
// Get the timestamp (as unix time) from the package
time_t time = hanReader.getPackageTime();
if (debugger) debugger->print("Time of the package is: ");
if (debugger) debugger->println(time);
// Define a json object to keep the data
StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
// Any generic useful info here
root["id"] = WiFi.macAddress();
root["up"] = millis();
root["t"] = time;
// Add a sub-structure to the json object,
// to keep the data from the meter itself
JsonObject& data = root.createNestedObject("data");
// Get the temperature too
tempSensor.requestTemperatures();
float temperature = tempSensor.getTempCByIndex(0);
data["temp"] = temperature;
// Based on the list number, get all details
// according to OBIS specifications for the meter
if (listSize == (int)Kamstrup::List1)
{
data["lv"] = hanReader.getString((int)Kamstrup_List1::ListVersionIdentifier);
data["id"] = hanReader.getString((int)Kamstrup_List1::MeterID);
data["type"] = hanReader.getString((int)Kamstrup_List1::MeterType);
data["P"] = hanReader.getInt((int)Kamstrup_List1::ActiveImportPower);
data["Q"] = hanReader.getInt((int)Kamstrup_List1::ReactiveImportPower);
data["I1"] = hanReader.getInt((int)Kamstrup_List1::CurrentL1);
data["I2"] = hanReader.getInt((int)Kamstrup_List1::CurrentL2);
data["I3"] = hanReader.getInt((int)Kamstrup_List1::CurrentL3);
data["U1"] = hanReader.getInt((int)Kamstrup_List1::VoltageL1);
data["U2"] = hanReader.getInt((int)Kamstrup_List1::VoltageL2);
data["U3"] = hanReader.getInt((int)Kamstrup_List1::VoltageL3);
}
else if (listSize == (int)Kamstrup::List2)
{
data["lv"] = hanReader.getString((int)Kamstrup_List2::ListVersionIdentifier);;
data["id"] = hanReader.getString((int)Kamstrup_List2::MeterID);
data["type"] = hanReader.getString((int)Kamstrup_List2::MeterType);
data["P"] = hanReader.getInt((int)Kamstrup_List2::ActiveImportPower);
data["Q"] = hanReader.getInt((int)Kamstrup_List2::ReactiveImportPower);
data["I1"] = hanReader.getInt((int)Kamstrup_List2::CurrentL1);
data["I2"] = hanReader.getInt((int)Kamstrup_List2::CurrentL2);
data["I3"] = hanReader.getInt((int)Kamstrup_List2::CurrentL3);
data["U1"] = hanReader.getInt((int)Kamstrup_List2::VoltageL1);
data["U2"] = hanReader.getInt((int)Kamstrup_List2::VoltageL2);
data["U3"] = hanReader.getInt((int)Kamstrup_List2::VoltageL3);
data["tPI"] = hanReader.getInt((int)Kamstrup_List2::CumulativeActiveImportEnergy);
data["tPO"] = hanReader.getInt((int)Kamstrup_List2::CumulativeActiveExportEnergy);
data["tQI"] = hanReader.getInt((int)Kamstrup_List2::CumulativeReactiveImportEnergy);
data["tQO"] = hanReader.getInt((int)Kamstrup_List2::CumulativeReactiveExportEnergy);
}
// Write the json to the debug port
root.printTo(Serial1);
Serial1.println();
// Publish the json to the MQTT server
char msg[1024];
root.printTo(msg, 1024);
mqtt.publish(ap.config.mqttPublishTopic, msg);
}
}
}
void readHanPort_Kaifa() {
if (hanReader.read())
{
// Get the list identifier
int listSize = hanReader.getListSize();
// Only care for the ACtive Power Imported, which is found in the first list
if (listSize == (int)Kaifa::List1 || listSize == (int)Kaifa::List2 || listSize == (int)Kaifa::List3)
{
if (listSize == (int)Kaifa::List1)
{
if (debugger) debugger->println(" (list #1 has no ID)");
}
else
{
String id = hanReader.getString((int)Kaifa_List2::ListVersionIdentifier);
if (debugger) debugger->println(id);
}
// Get the timestamp (as unix time) from the package
time_t time = hanReader.getPackageTime();
if (debugger) debugger->print("Time of the package is: ");
if (debugger) debugger->println(time);
// Define a json object to keep the data
StaticJsonBuffer<500> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
// Any generic useful info here
root["id"] = WiFi.macAddress();
root["up"] = millis();
root["t"] = time;
// Add a sub-structure to the json object,
// to keep the data from the meter itself
JsonObject& data = root.createNestedObject("data");
// Get the temperature too
tempSensor.requestTemperatures();
float temperature = tempSensor.getTempCByIndex(0);
data["temp"] = temperature;
// Based on the list number, get all details
// according to OBIS specifications for the meter
if (listSize == (int)Kaifa::List1)
{
data["P"] = hanReader.getInt((int)Kaifa_List1::ActivePowerImported);
}
else if (listSize == (int)Kaifa::List2)
{
data["lv"] = hanReader.getString((int)Kaifa_List2::ListVersionIdentifier);
data["id"] = hanReader.getString((int)Kaifa_List2::MeterID);
data["type"] = hanReader.getString((int)Kaifa_List2::MeterType);
data["P"] = hanReader.getInt((int)Kaifa_List2::ActiveImportPower);
data["Q"] = hanReader.getInt((int)Kaifa_List2::ReactiveImportPower);
data["I1"] = hanReader.getInt((int)Kaifa_List2::CurrentL1);
data["I2"] = hanReader.getInt((int)Kaifa_List2::CurrentL2);
data["I3"] = hanReader.getInt((int)Kaifa_List2::CurrentL3);
data["U1"] = hanReader.getInt((int)Kaifa_List2::VoltageL1);
data["U2"] = hanReader.getInt((int)Kaifa_List2::VoltageL2);
data["U3"] = hanReader.getInt((int)Kaifa_List2::VoltageL3);
}
else if (listSize == (int)Kaifa::List3)
{
data["lv"] = hanReader.getString((int)Kaifa_List3::ListVersionIdentifier);;
data["id"] = hanReader.getString((int)Kaifa_List3::MeterID);
data["type"] = hanReader.getString((int)Kaifa_List3::MeterType);
data["P"] = hanReader.getInt((int)Kaifa_List3::ActiveImportPower);
data["Q"] = hanReader.getInt((int)Kaifa_List3::ReactiveImportPower);
data["I1"] = hanReader.getInt((int)Kaifa_List3::CurrentL1);
data["I2"] = hanReader.getInt((int)Kaifa_List3::CurrentL2);
data["I3"] = hanReader.getInt((int)Kaifa_List3::CurrentL3);
data["U1"] = hanReader.getInt((int)Kaifa_List3::VoltageL1);
data["U2"] = hanReader.getInt((int)Kaifa_List3::VoltageL2);
data["U3"] = hanReader.getInt((int)Kaifa_List3::VoltageL3);
data["tPI"] = hanReader.getInt((int)Kaifa_List3::CumulativeActiveImportEnergy);
data["tPO"] = hanReader.getInt((int)Kaifa_List3::CumulativeActiveExportEnergy);
data["tQI"] = hanReader.getInt((int)Kaifa_List3::CumulativeReactiveImportEnergy);
data["tQO"] = hanReader.getInt((int)Kaifa_List3::CumulativeReactiveExportEnergy);
}
// Write the json to the debug port
root.printTo(Serial1);
Serial1.println();
// Publish the json to the MQTT server
char msg[1024];
root.printTo(msg, 1024);
mqtt.publish("sensors/out/espdebugger", msg);
}
}
}
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
// Connect to WiFi access point.
if (debugger) debugger->println(); if (debugger) debugger->println();
if (debugger) debugger->print("Connecting to WiFi network ");
if (debugger) debugger->println(ap.config.ssid);
long vTimeout = millis() + WIFI_CONNECTION_TIMEOUT;
while (WiFi.status() != WL_CONNECTED) {
delay(50);
if (debugger) debugger->print(".");
if (vTimeout < millis())
{
if (debugger)
{
debugger->print("Timout during connect. WiFi status is: ");
debugger->println(WiFi.status());
}
WiFi.disconnect();
WiFi.begin(ap.config.ssid, ap.config.ssidPassword);
vTimeout = millis() + WIFI_CONNECTION_TIMEOUT;
}
yield();
}
if (debugger) {
debugger->println();
debugger->println("WiFi connected");
debugger->println("IP address: ");
debugger->println(WiFi.localIP());
debugger->print("\nconnecting to MQTT: ");
debugger->print(ap.config.mqtt);
debugger->print(", port: ");
debugger->print(ap.config.mqttPort);
debugger->println();
}
while (!mqtt.connected()) {
if ((ap.config.mqttUser == 0 && mqtt.connect(ap.config.mqttClientID)) ||
(ap.config.mqttUser != 0 && mqtt.connect(ap.config.mqttClientID, ap.config.mqttUser, ap.config.mqttPass)))
{
if (debugger) debugger->println("\nSuccessfully connected to MQTT!");
if (ap.config.mqttSubscribeTopic != 0 && strlen(ap.config.mqttSubscribeTopic) > 0)
{
mqtt.subscribe(ap.config.mqttSubscribeTopic);
if (debugger) debugger->printf(" Subscribing to [%s]\r\n", ap.config.mqttSubscribeTopic);
}
}
else
{
if (debugger) debugger->print(".");
if (debugger) debugger->print("failed, mqtt.state() = ");
if (debugger) debugger->print(mqtt.state());
if (debugger) debugger->println(" trying again in 5 seconds");
// Wait 2 seconds before retrying
mqtt.disconnect();
delay(2000);
}
yield();
}
}
void sendMqttData(String data)
{
if (ap.config.mqttPublishTopic == 0 || strlen(ap.config.mqttPublishTopic) == 0)
return;
if (!client->connected() || !mqtt.connected()) {
MQTT_connect();
}
StaticJsonBuffer<500> jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["id"] = WiFi.macAddress();
json["up"] = millis() / 1000;
json["data"] = data;
String msg;
json.printTo(msg);
mqtt.publish(ap.config.mqttPublishTopic, msg.c_str());
}

View File

@ -5,6 +5,11 @@
#include "accesspoint.h"
ESP8266WebServer accesspoint::server(80);
Stream* accesspoint::debugger;
bool accesspoint::hasConfig() {
return config.hasConfig();
}
void accesspoint::setup(int accessPointButtonPin, Stream& debugger)
{
@ -13,22 +18,27 @@ void accesspoint::setup(int accessPointButtonPin, Stream& debugger)
// Test if we're missing configuration
if (!config.hasConfig())
{
this->print("No config. We're booting as AP. Look for SSID ");
this->println(this->AP_SSID);
print("No config. We're booting as AP. Look for SSID ");
println(this->AP_SSID);
isActivated = true;
}
else
{
// Load the configuration
config.load();
if (this->debugger) config.print(debugger);
// Test if we're holding down the AP pin, over 5 seconds
int time = millis() + 5000;
this->print("Press the AP button now to boot as access point");
print("Press the AP button now to boot as access point");
while (millis() < time)
{
this->print(".");
print(".");
if (digitalRead(accessPointButtonPin) == LOW)
{
this->println("");
this->println("AP button was pressed. Booting as access point now");
println("");
print("AP button was pressed. Booting as access point now. Look for SSID ");
println(this->AP_SSID);
isActivated = true;
break;
}
@ -38,6 +48,7 @@ void accesspoint::setup(int accessPointButtonPin, Stream& debugger)
if (isActivated)
{
// Setup AP
WiFi.disconnect(true);
WiFi.softAPdisconnect(true);
WiFi.mode(WIFI_OFF);
@ -51,34 +62,89 @@ void accesspoint::setup(int accessPointButtonPin, Stream& debugger)
dnsServer.start(DNS_PORT, "*", WiFi.softAPIP());
server.on("/", handleRoot);
server.on("/save", handleSave);
server.begin(); // Web server start
this->print("Web server is ready for config at http://");
this->print(WiFi.softAPIP());
this->println("/");
print("Web server is ready for config at http://");
print(WiFi.softAPIP());
println("/");
}
}
/** Handle root or redirect to captive portal */
void accesspoint::handleRoot() {
Serial.println("Serving / over http...");
println("Serving / over http...");
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1");
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server.sendContent(
"<html><head></head><body>"
"<h1>HELLO WORLD!!</h1>"
);
server.sendContent(
"<p>You may want to <a href='/wifi'>config the wifi connection</a>.</p>"
"</body></html>"
);
String html = String("<html>\r\n\r\n<head>\r\n\t<style type=\"text/css\">\r\n\t\tbody div {\r\n\t\t\tfont-family: Roboto, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif;\r\n\t\t}\r\n\r\n\t\t.wrapper {\r\n\t\t\twidth: 70%;\r\n\t\t\tposition: absolute;\r\n\t\t\tpadding: 30px;\r\n\t\t\tbackground-color: #FFF;\r\n\t\t\tborder-radius: 1px;\r\n\t\t\tcolor: #333;\r\n\t\t\tborder-color: rgba(0, 0, 0, 0.03);\r\n\t\t\tbox-shadow: 0 2px 2px rgba(0, 0, 0, .24), 0 0 2px rgba(0, 0, 0, .12);\r\n\t\t\tmargin-left: 20px;\r\n\t\t\tmargin-top: 20px;\r\n\t\t}\r\n\r\n\t\tdiv {\r\n\t\t\tpadding-bottom: 5px;\r\n\t\t}\r\n\r\n\t\tinput {\r\n\t\t\tbottom: 30px;\r\n\t\t\tborder: none;\r\n\t\t\tborder-bottom: 1px solid #d4d4d4;\r\n\t\t\tpadding: 10px;\r\n\t\t\twidth: 80%;\r\n\t\t\tbackground: transparent;\r\n\t\t\ttransition: all .25s ease;\r\n\t\t}\r\n\r\n\t\tinput[type=number] {\r\n\t\t\twidth: 70px;\r\n\t\t\tmargin-left: 5px;\r\n\t\t}\r\n\r\n\t\tinput:focus {\r\n\t\t\toutline: none;\r\n\t\t\tborder-bottom: 1px solid #3f51b5;\r\n\t\t}\r\n\r\n\t\th2 {\r\n\t\t\ttext-align: left;\r\n\t\t\tfont-size: 20px;\r\n\t\t\tfont-weight: bold;\r\n\t\t\tletter-spacing: 3px;\r\n\t\t\tline-height: 28px;\r\n\t\t}\r\n\r\n\t\t.submit-button {\r\n\t\t\tposition: absolute;\r\n\t\t\ttext-align: right;\r\n\t\t\tborder-radius: 30px;\r\n\t\t\tborder-bottom-right-radius: 0;\r\n\t\t\tborder-top-right-radius: 0;\r\n\t\t\tbackground-color: #3f51b5;\r\n\t\t\tcolor: #FFF;\r\n\t\t\tpadding: 12px 25px;\r\n\t\t\tdisplay: inline-block;\r\n\t\t\tfont-size: 12px;\r\n\t\t\tfont-weight: bold;\r\n\t\t\tletter-spacing: 2px;\r\n\t\t\tright: 0px;\r\n\t\t\tbottom: 10px;\r\n\t\t\tcursor: pointer;\r\n\t\t\ttransition: all .25s ease;\r\n\t\t\tbox-shadow: 0 2px 2px rgba(0, 0, 0, .24), 0 0 2px rgba(0, 0, 0, .12);\r\n\t\t\twidth: 100px;\r\n\t\t}\r\n\t</style>\r\n</head>\r\n\r\n<body>\r\n\t<form method='post' action='/save'>\r\n\t\t<div class=\"wrapper\">\r\n\t\t\t<div class=\"inner-wrapper\">\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<h2>WiFi</h2>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='text' name='ssid' placeholder=\"SSID\">\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='password' name='ssidPassword' placeholder=\"Password\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"inner-wrapper\">\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<h2>AMS Meter</h2>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='text' name='meterType' placeholder=\"Meter Type (1=Kaifa, 2=Kamstrup, 3=Aidon)\">\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"inner-wrapper\">\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<h2>MQTT</h2>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='text' name='mqtt' placeholder=\"Server\">\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='number' name='mqttPort' placeholder=\"port\">\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='text' name='mqttClientID' placeholder=\"Client ID\">\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='text' name='mqttPublishTopic' placeholder=\"Publish Topic\">\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='text' name='mqttSubscribeTopic' placeholder=\"Subscribe Topic\">\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='text' name='mqttUser' placeholder=\"Username (leave blank for unsecure)\">\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input type='password' name='mqttPass' placeholder=\"Password\">\r\n\t\t\t\t</div>\r\n\t\t\t\t<div>\r\n\t\t\t\t\t<input class=\"submit-button\" type='submit' value='save'>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</form>\r\n\r\n\t<body>\r\n\r\n</html>");
server.sendContent(html);
server.client().stop(); // Stop is needed because we sent no content length
}
void accesspoint::handleSave() {
configuration *config = new configuration();
String temp;
temp = server.arg("ssid");
config->ssid = new char[temp.length() + 1];
temp.toCharArray(config->ssid, temp.length() + 1, 0);
temp = server.arg("ssidPassword");
config->ssidPassword = new char[temp.length() + 1];
temp.toCharArray(config->ssidPassword, temp.length() + 1, 0);
config->meterType = (byte)server.arg("meterType").toInt();
temp = server.arg("mqtt");
config->mqtt = new char[temp.length() + 1];
temp.toCharArray(config->mqtt, temp.length() + 1, 0);
config->mqttPort = (int)server.arg("mqttPort").toInt();
temp = server.arg("mqttClientID");
config->mqttClientID = new char[temp.length() + 1];
temp.toCharArray(config->mqttClientID, temp.length() + 1, 0);
temp = server.arg("mqttPublishTopic");
config->mqttPublishTopic = new char[temp.length() + 1];
temp.toCharArray(config->mqttPublishTopic, temp.length() + 1, 0);
temp = server.arg("mqttSubscribeTopic");
config->mqttSubscribeTopic = new char[temp.length() + 1];
temp.toCharArray(config->mqttSubscribeTopic, temp.length() + 1, 0);
temp = server.arg("mqttUser");
config->mqttUser = new char[temp.length() + 1];
temp.toCharArray(config->mqttUser, temp.length() + 1, 0);
temp = server.arg("mqttPass");
config->mqttPass = new char[temp.length() + 1];
temp.toCharArray(config->mqttPass, temp.length() + 1, 0);
println("Saving configuration now...");
if (accesspoint::debugger) config->print(*accesspoint::debugger);
if (config->save())
{
println("Successfully saved. Will roboot now.");
String html = "<html><body><h1>Successfully Saved!</h1><h3>Device is restarting now...</h3></form>";
server.send(200, "text/html", html);
ESP.reset();
}
else
{
println("Error saving configuration");
String html = "<html><body><h1>Error saving configuration!</h1></form>";
server.send(500, "text/html", html);
}
}
bool accesspoint::loop() {
if (isActivated)
{
@ -97,17 +163,17 @@ bool accesspoint::loop() {
size_t accesspoint::print(const char* text)
{
if (this->debugger) this->debugger->print(text);
if (debugger) debugger->print(text);
}
size_t accesspoint::println(const char* text)
{
if (this->debugger) this->debugger->println(text);
if (debugger) debugger->println(text);
}
size_t accesspoint::print(const Printable& data)
{
if (this->debugger) this->debugger->print(data);
if (debugger) debugger->print(data);
}
size_t accesspoint::println(const Printable& data)
{
if (this->debugger) this->debugger->println(data);
if (debugger) debugger->println(data);
}

View File

@ -18,26 +18,28 @@ class accesspoint {
public:
void setup(int accessPointButtonPin, Stream& debugger);
bool loop();
bool hasConfig();
configuration config;
bool isActivated = false;
private:
const char* AP_SSID = "AMS2MQTT";
configuration config;
bool isActivated = false;
Stream* debugger = NULL;
// DNS server
const byte DNS_PORT = 53;
DNSServer dnsServer;
size_t print(const char* text);
size_t println(const char* text);
size_t print(const Printable& data);
size_t println(const Printable& data);
static size_t print(const char* text);
static size_t println(const char* text);
static size_t print(const Printable& data);
static size_t println(const Printable& data);
// Web server
static void handleRoot();
static void handleSave();
static ESP8266WebServer server;
static Stream* debugger;
};
#endif

View File

@ -6,11 +6,11 @@
bool configuration::hasConfig()
{
bool has = false;
bool hasConfig = false;
EEPROM.begin(EEPROM_SIZE);
has = EEPROM.read(EEPROM_CONFIG_ADDRESS) == EEPROM_CHECK_SUM;
hasConfig = EEPROM.read(EEPROM_CONFIG_ADDRESS) == EEPROM_CHECK_SUM;
EEPROM.end();
return has;
return hasConfig;
}
bool configuration::save()
@ -23,6 +23,7 @@ bool configuration::save()
address += saveString(address, ssid);
address += saveString(address, ssidPassword);
address += saveByte(address, meterType);
address += saveString(address, mqtt);
address += saveInt(address, mqttPort);
address += saveString(address, mqttClientID);
@ -37,10 +38,10 @@ bool configuration::save()
else
address += saveBool(address, false);
bool vRet = EEPROM.commit();
bool success = EEPROM.commit();
EEPROM.end();
return vRet;
return success;
}
@ -56,6 +57,7 @@ bool configuration::load()
address += readString(address, &ssid);
address += readString(address, &ssidPassword);
address += readByte(address, &meterType);
address += readString(address, &mqtt);
address += readInt(address, &mqttPort);
address += readString(address, &mqttClientID);
@ -82,6 +84,7 @@ bool configuration::load()
{
ssid = (char*)String("").c_str();
ssidPassword = (char*)String("").c_str();
meterType = (byte)0;
mqtt = (char*)String("").c_str();
mqttClientID = (char*)String("").c_str();
mqttPublishTopic = (char*)String("").c_str();
@ -99,45 +102,55 @@ bool configuration::isSecure()
return (mqttUser != 0) && (String(mqttUser).length() > 0);
}
int configuration::readInt(int pAddress, int *pValue)
int configuration::readInt(int address, int *value)
{
int lower = EEPROM.read(pAddress);
int higher = EEPROM.read(pAddress + 1);
*pValue = lower + (higher << 8);
int lower = EEPROM.read(address);
int higher = EEPROM.read(address + 1);
*value = lower + (higher << 8);
return 2;
}
int configuration::saveInt(int pAddress, int pValue)
int configuration::saveInt(int address, int value)
{
byte lowByte = pValue & 0xFF;
byte highByte = ((pValue >> 8) & 0xFF);
byte lowByte = value & 0xFF;
byte highByte = ((value >> 8) & 0xFF);
EEPROM.write(pAddress, lowByte);
EEPROM.write(pAddress + 1, highByte);
EEPROM.write(address, lowByte);
EEPROM.write(address + 1, highByte);
return 2;
}
int configuration::readBool(int pAddress, bool *pValue)
int configuration::readBool(int address, bool *value)
{
byte y = EEPROM.read(pAddress);
*pValue = (bool)y;
//Serial.printf("Read bool as %#x [%s]\r\n", y, (*pValue ? "true" : "false"));
byte y = EEPROM.read(address);
*value = (bool)y;
return 1;
}
int configuration::saveBool(int pAddress, bool pValue)
int configuration::saveBool(int address, bool value)
{
byte y = (byte)pValue;
//Serial.printf("Writing bool as %#x [%s]\r\n", y, (pValue ? "true" : "false"));
EEPROM.write(pAddress, y);
byte y = (byte)value;
EEPROM.write(address, y);
return 1;
}
int configuration::readByte(int address, byte *value)
{
*value = EEPROM.read(address);
return 1;
}
int configuration::saveByte(int address, byte value)
{
EEPROM.write(address, value);
return 1;
}
void configuration::print(Stream& serial)
{
/*
char* ssid;
char* ssidPassword;
byte meterType;
char* mqtt;
int mqttPort;
char* mqttClientID;
@ -152,6 +165,7 @@ void configuration::print(Stream& serial)
serial.println("-----------------------------------------------");
serial.printf("ssid: %s\r\n", this->ssid);
serial.printf("ssidPassword: %s\r\n", this->ssidPassword);
serial.printf("meterType: %i\r\n", this->meterType);
serial.printf("mqtt: %s\r\n", this->mqtt);
serial.printf("mqttPort: %i\r\n", this->mqttPort);
serial.printf("mqttClientID: %s\r\n", this->mqttClientID);
@ -167,8 +181,6 @@ void configuration::print(Stream& serial)
serial.println("-----------------------------------------------");
}
template <class T> int configuration::writeAnything(int ee, const T& value)
{
const byte* p = (const byte*)(const void*)&value;
@ -190,38 +202,25 @@ template <class T> int configuration::readAnything(int ee, T& value)
int configuration::readString(int pAddress, char* pString[])
{
int address = 0;
byte vLength = EEPROM.read(pAddress + address);
byte length = EEPROM.read(pAddress + address);
address++;
//Serial.print("Found length of string: ");
//Serial.println(vLength);
char* buffer = new char[vLength];
for (int i = 0; i<vLength; i++)
char* buffer = new char[length];
for (int i = 0; i<length; i++)
{
buffer[i] = EEPROM.read(pAddress + address++);
}
*pString = buffer;
//Serial.print("Read string from EEPROM: [");
//Serial.print(*pString);
//Serial.println("]");
return address;
}
int configuration::saveString(int pAddress, char* pString)
{
int address = 0;
int vLength = strlen(pString) + 1;
//Serial.print("Storing length of string: ");
//Serial.println(vLength);
EEPROM.put(pAddress + address, vLength);
int length = strlen(pString) + 1;
EEPROM.put(pAddress + address, length);
address++;
//Serial.print("Storing string: ");
//Serial.println(pString);
for (int i = 0; i<vLength; i++)
for (int i = 0; i < length; i++)
{
EEPROM.put(pAddress + address, pString[i]);
address++;

View File

@ -23,6 +23,7 @@ public:
char* mqttSubscribeTopic;
char* mqttUser;
char* mqttPass;
byte meterType;
bool hasConfig();
bool isSecure();
@ -34,7 +35,7 @@ protected:
private:
const int EEPROM_SIZE = 512;
const byte EEPROM_CHECK_SUM = 124; // Used to check if config is stored. Change if structure changes
const byte EEPROM_CHECK_SUM = 71; // Used to check if config is stored. Change if structure changes
const int EEPROM_CONFIG_ADDRESS = 0;
int saveString(int pAddress, char* pString);
@ -43,6 +44,8 @@ private:
int readInt(int pAddress, int *pValue);
int saveBool(int pAddress, bool pValue);
int readBool(int pAddress, bool *pValue);
int saveByte(int pAddress, byte pValue);
int readByte(int pAddress, byte *pValue);
template <class T> int writeAnything(int ee, const T& value);

View File

@ -81,6 +81,8 @@ void HanReader::debugPrint(byte *buffer, int start, int length)
debug->println("");
else if ((i - start + 1) % 4 == 0)
debug->print(" ");
yield(); // Let other get some resources too
}
debug->println("");
}