diff --git a/.cproject b/.cproject index 5ad54d7..236f73a 100644 --- a/.cproject +++ b/.cproject @@ -28,12 +28,14 @@ + diff --git a/MqttClient.cpp b/MqttClient.cpp index 206158f..95780c2 100644 --- a/MqttClient.cpp +++ b/MqttClient.cpp @@ -11,12 +11,94 @@ #include #include #include +#include +#include +#include "cmd.h" +#include "config.h" -byte MQTT_BROKER[] = { 172, 16, 2, 16 }; +char MQTT_BROKER_DEFAULT[] = "192.168.75.1"; const uint16_t MQTT_PORT = 1883; + + +String MqttConfig::exec(String params) { + String res = "failed"; + + Print *out = m_server; + MqttClient *mc = (MqttClient*)m_mqttClient; + if (params.equalsIgnoreCase("help")) { + *out << "help ..... this help page" << endl; + *out << "show ..... shows the whole configuration" << endl; + *out << "broker ... set the broker's address" << endl; + *out << " followed by a restart, you need to" << endl; + *out << " about a minute" << endl; + *out << "add ...... add an mbus client, params: token address period" << endl; + *out << "del ...... delete an mbus client, params: index" << endl; + *out << "reset .... reset configuration" << endl; + *out << " followed by a restart, you need to" << endl; + *out << " about a minute" << endl; + *out << endl; + res = "done"; + } else if (params.equalsIgnoreCase("show")) { + // show the whole configuration + *out << "Clients:" << endl; + *out << "(index, token, address, period)" << endl; + for (uint8_t i = 0; i < NUM_OF_DEVICES; i++) { + *out << i << ": " << mc->m_mbusDevTuple[i].token << ", " << + mc->m_mbusDevTuple[i].address << ", " << + mc->m_mbusDevTuple[i].queryPeriod << endl; + } + *out << "Broker: " << mc->m_mqttBroker << endl; + *out << "Watchdog resets: " << WDOG_RSTCNT << endl; + res = "done"; + } else if (params.startsWith("broker ")) { + // set the broker's address + int space = params.indexOf(' '); + if (space == -1) { + res = "missing argument"; + } else { + String broker = params.substring(space+1); + strcpy(mc->m_mqttBroker, broker.c_str()); + configWrite(CONFIG_BROKER, sizeof(mc->m_mqttBroker), (char*)mc->m_mqttBroker); + *out << "Stopping gateway, wait for reset" << endl; + while (true); + res = "done"; + } + } else if (params.startsWith("add ")) { + // add an mbus client, params: token address period + + configWrite(CONFIG_DEVICES, sizeof(mc->m_mbusDevTuple), (char*)mc->m_mbusDevTuple); + res = "done"; + } else if (params.startsWith("del ")) { + // delete an mbus client, params: index + int space = params.indexOf(' '); + if (space == -1) { + res = "missing argument"; + } else { + String arg0 = params.substring(space); + int idx = atoi(arg0.c_str()); + if (idx < 0 || idx >= NUM_OF_DEVICES) { + res = "illegal index"; + } else { + *out << "Index " << arg0 << " (" << idx << ") to be deleted" << endl; + mc->m_mbusDevTuple[idx] = {0, 0, 0, 0}; + configWrite(CONFIG_DEVICES, sizeof(mc->m_mbusDevTuple), (char*)mc->m_mbusDevTuple); + res = "done"; + } + } + } else if (params.equalsIgnoreCase("reset")) { + configReset(); + *out << "Stopping gateway, wait for reset" << endl; + while (true); + res = "done"; + } + return res; +} + + + void callback(char* topic, byte* payload, unsigned int length) { } @@ -24,16 +106,10 @@ void callback(char* topic, byte* payload, unsigned int length) { Metro secondTick = Metro(1000); -MqttClient::MqttClient(RequestSender *meterBusMaster) : - m_client(), m_meterBusMaster(meterBusMaster), m_mqttClient(MQTT_BROKER, MQTT_PORT, callback, m_client), +MqttClient::MqttClient(RequestSender *meterBusMaster) : m_mqttConfig(this), + m_client(), m_meterBusMaster(meterBusMaster), m_mqttClient(m_client), m_disconnectState(3), m_disconnectTime(millis()), m_uptime(0), m_deviceIdx(0) { - for (uint8_t i = 0; i < NUM_OF_DEVICES; i++) { - m_mbusDevTuple[i] = { 0, 0, 0, 0 }; - } - - m_mbusDevTuple[0] = { 1, 0x53, 10, 0 }; // light meter - m_mbusDevTuple[1] = { 2, 32, 10, 0 }; // electrity } void MqttClient::sendResponse(uint8_t *responseBuffer, uint16_t responseBufferLength, uint8_t token) { @@ -67,7 +143,7 @@ void MqttClient::sendResponse(uint8_t *responseBuffer, uint16_t responseBufferLe if (m_disconnectState == 0) { //Serial << "publishing " << strbuf << endl; //Serial << "length: " << buf.length() << endl; - m_mqttClient.publish("MeterbusHub/Measurement", strbuf); + m_mqttClient.publish("IoT/MeterbusHub/Measurement", strbuf); } else { Serial << "no MQTT connection, message lost: " << endl << strbuf << endl; @@ -80,13 +156,34 @@ void MqttClient::sendError(uint8_t code, uint8_t token) { if (m_disconnectState == 0) { //Serial << "publishing " << msg << endl; //Serial << "length: " << msg.length() << endl; - m_mqttClient.publish("MeterbusHub/Measurement", (char*)msg.c_str()); + m_mqttClient.publish("IoT/MeterbusHub/Measurement", (char*)msg.c_str()); } else { Serial << "no MQTT connection, message lost: " << msg << endl; } } -void MqttClient::begin() { +void MqttClient::begin(CmdServer *cmdServer) { + m_mqttConfig.registerYourself(cmdServer); + + if (! configIsValid()) { + for (uint8_t i = 0; i < NUM_OF_DEVICES; i++) { + m_mbusDevTuple[i] = { 0, 0, 0, 0 }; + } + m_mbusDevTuple[0] = { 1, 0x53, 10, 0 }; // light meter + m_mbusDevTuple[1] = { 2, 32, 10, 0 }; // electrity + configWrite(CONFIG_DEVICES, sizeof(m_mbusDevTuple), (char*)m_mbusDevTuple); + + strcpy(m_mqttBroker, MQTT_BROKER_DEFAULT); + configWrite(CONFIG_BROKER, sizeof(m_mqttBroker), (char*)m_mqttBroker); + } + + + configRead(CONFIG_DEVICES, sizeof(m_mbusDevTuple), (char*)m_mbusDevTuple); + configRead(CONFIG_BROKER, sizeof(m_mqttBroker), (char*)m_mqttBroker); + + + + m_mqttClient = PubSubClient(m_mqttBroker, MQTT_PORT, callback, m_client); } void MqttClient::exec() { @@ -133,9 +230,10 @@ void MqttClient::exec() { m_uptime++; //Serial << "Tick " << m_uptime << endl; - String msg = String("{ \"metadata\": { \"device\": \"MeterbusHub\" }, \"data\": { \"uptime\": ") + m_uptime + String("}}"); + byte wdogCnt = WDOG_RSTCNT; + String msg = String("{ \"metadata\": { \"device\": \"MeterbusHub\" }, \"data\": { \"uptime\": ") + m_uptime + String(", \"watchdogCnt\": ") + wdogCnt + String("}}"); if (m_disconnectState == 0) { - m_mqttClient.publish("MeterbusHub/Heartbeat", (char*)msg.c_str()); + m_mqttClient.publish("IoT/MeterbusHub/Heartbeat", (char*)msg.c_str()); } else { Serial << "no MQTT connection, message lost: " << msg << endl; } diff --git a/MqttClient.h b/MqttClient.h index bf5053f..f2b8029 100644 --- a/MqttClient.h +++ b/MqttClient.h @@ -12,6 +12,7 @@ #include #include "mBusDialog.h" #include +#include "cmd.h" #define NUM_OF_DEVICES 10 @@ -23,14 +24,31 @@ typedef struct { uint16_t timer; } mbusDevTuple_t; + +class MqttClient; + +class MqttConfig : public Cmd { +public: + MqttConfig(MqttClient *mqttClient) : m_mqttClient(mqttClient) {}; + virtual String getCmdName() { return "MQ"; } + virtual String getHelp() { return "MQTT Client Config"; } + virtual String exec(String params); +private: + MqttClient *m_mqttClient; +}; + + class MqttClient : public ResponseCallback { public: MqttClient(RequestSender *meterBusMaster); - void begin(); + void begin(CmdServer *cmdServer); void exec(); virtual void sendResponse(uint8_t *responseBuffer, uint16_t responseBufferLength, uint8_t token); virtual void sendError(uint8_t code, uint8_t token); + friend class MqttConfig; private: + MqttConfig m_mqttConfig; + char m_mqttBroker[64]; EthernetClient m_client; RequestSender *m_meterBusMaster; PubSubClient m_mqttClient; diff --git a/NetMeterBusMaster2.cpp b/NetMeterBusMaster2.cpp index cfb5ae1..0699d25 100644 --- a/NetMeterBusMaster2.cpp +++ b/NetMeterBusMaster2.cpp @@ -12,6 +12,8 @@ #include #include "MqttClient.h" #include +#include +#include "config.h" const uint8_t POWER_LED = 4; @@ -29,15 +31,37 @@ static MqttClient mqttClient(&meterBusMaster); // static MeterBusServer meterBusServer(2001, &meterBusMaster); static OverCurrentProt overCurrentProt; +Metro wdogTick = Metro(1000); +Metro dhcpTick = Metro(5* 60 * 1000); + +extern "C" { + void startup_early_hook( ) __attribute__ ((weak)); + void startup_early_hook() { + // enable watchdog + WDOG_UNLOCK = WDOG_UNLOCK_SEQ1; + WDOG_UNLOCK = WDOG_UNLOCK_SEQ2; + + // one minute + WDOG_TOVALL = 0xea60; + WDOG_TOVALH = 0; + WDOG_PRESC = 0; + + WDOG_STCTRLH = WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_ALLOWUPDATE | WDOG_STCTRLH_STOPEN | WDOG_STCTRLH_WAITEN; + } +} // extern "C" void setup() { + pinMode(POWER_LED, OUTPUT); + digitalWrite(POWER_LED, HIGH); + Serial.begin(115200); delay(100); Serial.println("Starting up ..."); - pinMode(POWER_LED, OUTPUT); digitalWrite(POWER_LED, LOW); + configInit(); + pinMode(ETHERNET_RESET, OUTPUT); digitalWrite(ETHERNET_RESET, LOW); delay(100); @@ -53,12 +77,33 @@ void setup() { overCurrentProt.begin(&cmdServer); meterBusMaster.begin(&cmdServer); // meterBusServer.begin(); - mqttClient.begin(); + mqttClient.begin(&cmdServer); digitalWrite(POWER_LED, HIGH); + } void loop() { + // watchdog refresh + cli(); + WDOG_REFRESH = 0xa602; + WDOG_REFRESH = 0xb480; + sei(); + + + if (wdogTick.check() == 1) { + uint16_t h = WDOG_TMROUTH; + uint16_t l = WDOG_TMROUTL; + uint16_t c = WDOG_RSTCNT; + + Serial << "WDog, h: " << _HEX(h) << ", l: " << _HEX(l) << ", c: " << _HEX(c) << endl; + } + + if (dhcpTick.check() == 1) { + byte r = Ethernet.maintain(); + Serial << "Ethernet.maintain: " << r << endl; + } + //Serial << "*** 1" << endl; cmdServer.exec(); //Serial << "*** 2" << endl; diff --git a/config.cpp b/config.cpp new file mode 100644 index 0000000..c136775 --- /dev/null +++ b/config.cpp @@ -0,0 +1,50 @@ +/* + * config.cpp + * + * Created on: 11.05.2015 + * Author: wn + */ + +#include +#include +#include "config.h" + +static bool __configIsValid = false; + +void configInit() { + uint32_t magic; + configRead(CONFIG_MAGIC, 4, (char*)&magic); + __configIsValid = (magic != 0xdeadbeef); + + if (! __configIsValid) { + Serial << "Initialize config" << endl; + uint32_t setMagic = 0xdeadbeef; + configWrite(CONFIG_MAGIC, 4, (char*)&setMagic); + } else { + Serial << "Config valid" << endl; + } +} + +bool configIsValid() { + return __configIsValid; +} + +void configReset() { + Serial << "Reset config" << endl; + uint32_t setMagic = 0xa5a5a5a5; + configWrite(CONFIG_MAGIC, 4, (char*)&setMagic); +} + +void configRead(int addr, uint8_t len, char *buffer) { + for (uint8_t i = 0; i < len; i++) { + *(buffer + i) = EEPROM.read(addr + i); + //Serial << "Read " << *(buffer + i) << " from " << addr + i << endl; + } +} + +void configWrite(int addr, uint8_t len, char *buffer) { + for (uint8_t i = 0; i < len; i++) { + //Serial << "Write " << _HEX(*(buffer + i)) << " to " << addr + i << endl; + EEPROM.write(addr + i, *(buffer + i)); + } +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..744f90a --- /dev/null +++ b/config.h @@ -0,0 +1,24 @@ +/* + * config.h + * + * Created on: 11.05.2015 + * Author: wn + */ + +#ifndef CONFIG_H_ +#define CONFIG_H_ + + +void configInit(); +bool configIsValid(); +void configReset(); + +void configRead(int addr, uint8_t len, char *buffer); +void configWrite(int addr, uint8_t len, char *buffer); + +#define CONFIG_MAGIC 0 // 4 +#define CONFIG_DEVICES 4 // 64 +#define CONFIG_BROKER 68 // 64 +#define CONFIG_NEXT 132 + +#endif /* CONFIG_H_ */