mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-17 09:02:11 +00:00
Boot as AP, Configuration, TempSensor etc
This commit is contained in:
parent
f8fe34a454
commit
c991403e25
@ -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());
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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++;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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("");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user