diff --git a/README.md b/README.md new file mode 100644 index 0000000..fb9fad0 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# ArduinoEasy = Arduino Mega 2560 + Ethernet Shield + +This is experimental project that may not be ready for production usage. This project is based on ESPEasy code backported to Arduino. + +Please visit [discussion forum](https://www.letscontrolit.com/forum/viewtopic.php?f=18&t=2234) if you have questions and need help. +Binary image to try ArduinoEasy is available on [wiki page](https://www.letscontrolit.com/wiki/index.php/ArduinoEasy) + +## Building +The latest sources can be build using Arduino 1.8.5 with recent libraries. Arduino will ask to rename src folder to ArduinoEasy once you open ArduinoEasy.ino file. +Make sure to add base64 library. Open Sketch -> Include library -> Add .ZIP library -> select folder /lib/Base64 +Other libraries that should be also available +- Wire at version 1.0 +- SPI at version 1.0 +- SD at version 1.2.2 +- Ethernet at version 1.1.2 +- PubSubClient at version 2.6 +- ArduinoJson at version 5.13.1 + +## Usage +MicroSD card is used to store configuration. Make sure to format microSD or microSDHC card to FAT and insert it into Arduino. Otherwise you will get following error in console. + + PID:0 + Version:0 + INIT : Incorrect PID or version! + +## Mega Switch setup +Arduino Mega has lots of GPIOs and it is possible to control most of them using ArduinoEasy. +List of GPIOs that can be controlled: 3, 5 - 9, 14 - 49, 56 - 69. +56-69 pins are used for A2-A15 pins. A0 and A1 are required to work with SD card. + +### MQTT control +To control GPIO via MQTT send "1" or "0" to corresponding pin number. Here is example of topic to control pin 39 on device named ArduinoEasyRocks. + + /ArduinoEasyRocks/gpio/39 + +### OpenHab configuration +Items configuration with switch defined + + Switch StairsUpHall {mqtt=">[oh2mqtt:/ArduinoEasyRocks/gpio/39:command:ON:1],>[oh2mqtt:/ArduinoEasyRocks/gpio/39:command:OFF:0]"} + +Sitemap with corresponding switch to show it on basic UI + + Switch item=StairsUpHall label="Upstairs hall" + +Make sure to properly configure MQTT binding. diff --git a/src/ArduinoEasy.ino b/src/ArduinoEasy.ino index b806b23..5efb065 100644 --- a/src/ArduinoEasy.ino +++ b/src/ArduinoEasy.ino @@ -195,6 +195,7 @@ EthernetServer MyWebServer(80); #if FEATURE_MQTT EthernetClient mqtt; PubSubClient MQTTclient(mqtt); +long lastMQTTReconnectAttempt = 0; #endif #define EthernetShield_CS_SDCard 4 @@ -831,7 +832,9 @@ void backgroundtasks() { WebServerHandleClient(); #if FEATURE_MQTT - MQTTclient.loop(); + if(!MQTTclient.loop()) { + MQTTCheck(); // MQTT client is no longer connected. Attempt to reconnect + } #endif statusLED(false); checkUDP(); diff --git a/src/Controller.ino b/src/Controller.ino index 9a58de9..0550a29 100644 --- a/src/Controller.ino +++ b/src/Controller.ino @@ -104,36 +104,30 @@ void MQTTConnect() LWTTopic.replace(F("/#"), F("/status")); LWTTopic.replace(F("%sysname%"), Settings.Name); - for (byte x = 1; x < 3; x++) - { - String log = ""; - boolean MQTTresult = false; + String log = ""; + boolean MQTTresult = false; - String msg = F("Connection Lost"); - if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) - MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser, SecuritySettings.ControllerPassword, LWTTopic.c_str(), 0, 0, msg.c_str()); - else - MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 0, msg.c_str()); + String msg = F("Connection Lost"); + if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) + MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser, SecuritySettings.ControllerPassword, LWTTopic.c_str(), 0, 0, msg.c_str()); + else + MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 0, msg.c_str()); - if (MQTTresult) - { - log = F("MQTT : Connected to broker"); - addLog(LOG_LEVEL_INFO, log); - subscribeTo = Settings.MQTTsubscribe; - subscribeTo.replace(F("%sysname%"), Settings.Name); - MQTTclient.subscribe(subscribeTo.c_str()); - log = F("Subscribed to: "); - log += subscribeTo; - addLog(LOG_LEVEL_INFO, log); - break; // end loop if succesfull - } - else - { - log = F("MQTT : Failed to connected to broker"); - addLog(LOG_LEVEL_ERROR, log); - } - - delay(500); + if (MQTTresult) + { + log = F("MQTT : Connected to broker"); + addLog(LOG_LEVEL_INFO, log); + subscribeTo = Settings.MQTTsubscribe; + subscribeTo.replace(F("%sysname%"), Settings.Name); + MQTTclient.subscribe(subscribeTo.c_str()); + log = F("Subscribed to: "); + log += subscribeTo; + addLog(LOG_LEVEL_INFO, log); + } + else + { + log = F("MQTT : Failed to connected to broker"); + addLog(LOG_LEVEL_ERROR, log); } } @@ -147,12 +141,14 @@ void MQTTCheck() if (Protocol[ProtocolIndex].usesMQTT) if (!MQTTclient.connected()) { - String log = F("MQTT : Connection lost"); - addLog(LOG_LEVEL_ERROR, log); - connectionFailures += 2; - MQTTclient.disconnect(); - delay(1000); - MQTTConnect(); + if (millis() - lastMQTTReconnectAttempt > 60000) { + // Reconnect attempts once per minute + String log = F("MQTT : Connection lost"); + addLog(LOG_LEVEL_ERROR, log); + connectionFailures++; + MQTTConnect(); + lastMQTTReconnectAttempt = millis(); + } } else if (connectionFailures) connectionFailures--; diff --git a/src/Misc.ino b/src/Misc.ino index 6c9b7c1..df21deb 100644 --- a/src/Misc.ino +++ b/src/Misc.ino @@ -44,7 +44,7 @@ void SelectSDCard(boolean sd) digitalWrite(EthernetShield_CS_W5100, sd); digitalWrite(EthernetShield_CS_SDCard, !sd); } - + /*********************************************************************************************\ Get value count from sensor type \*********************************************************************************************/ @@ -413,7 +413,7 @@ void fileSystemCheck() pinMode(EthernetShield_CS_SDCard, OUTPUT); pinMode(EthernetShield_CS_W5100, OUTPUT); SelectSDCard(true); - + if (SD.begin(EthernetShield_CS_SDCard)) { String log = F("SD Mount successful"); @@ -659,7 +659,7 @@ void LoadCustomControllerSettings(byte* memAddress, int datasize) \*********************************************************************************************/ void SaveToFile(const __FlashStringHelper* fname, int index, byte* memAddress, int datasize) { - File f = SD.open(fname, FILE_WRITE); + File f = SD.open(fname, O_READ | O_WRITE); if (f) { f.seek(index); @@ -670,7 +670,12 @@ void SaveToFile(const __FlashStringHelper* fname, int index, byte* memAddress, i pointerToByteToSave++; } f.close(); - String log = F("FILE : File saved"); + String log = F("FILE : File saved "); + log += fname; + log += F(" index "); + log += index; + log += F(" size "); + log += datasize; addLog(LOG_LEVEL_INFO, log); } } @@ -861,7 +866,7 @@ void addLog(byte loglevel, const char *line) } logFile.close(); } - + } @@ -1521,7 +1526,7 @@ unsigned long getNtpTime() { const char* ntpServerName = "pool.ntp.org"; unsigned long result=0; - + IPAddress timeServerIP; // The W5100 seems to have an issue with mixing TCP UDP on the same socket. @@ -2004,4 +2009,3 @@ void createRuleEvents(byte TaskIndex) rulesProcessing(eventString); } } - diff --git a/src/_P001_Switch.ino b/src/_P001_Switch.ino index 51c6810..1072cbc 100644 --- a/src/_P001_Switch.ino +++ b/src/_P001_Switch.ino @@ -141,7 +141,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) switchstate[event->TaskIndex] = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]); outputstate[event->TaskIndex] = switchstate[event->TaskIndex]; - + // if boot state must be send, inverse default state if (Settings.TaskDevicePluginConfig[event->TaskIndex][3]) { @@ -218,7 +218,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) if (command == F("gpio")) { success = true; - if (event->Par1 >= 2 && event->Par1 <= 13) + if (Plugin_001_updatable_pin(event->Par1)) { pinMode(event->Par1, OUTPUT); digitalWrite(event->Par1, event->Par2); @@ -232,14 +232,14 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) if (command == F("pwm")) { success = true; - if (event->Par1 >= 2 && event->Par1 <= 13) + if (Plugin_001_updatable_pin(event->Par1)) { pinMode(event->Par1, OUTPUT); - + if(event->Par3 != 0) { byte prev_mode; - uint16_t prev_value; + uint16_t prev_value; getPinState(PLUGIN_ID_001, event->Par1, &prev_mode, &prev_value); if(prev_mode != PIN_MODE_PWM) prev_value = 0; @@ -255,7 +255,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) delay(1); } } - + analogWrite(event->Par1, event->Par2); setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_PWM, event->Par2); log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2); @@ -267,7 +267,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) if (command == F("pulse")) { success = true; - if (event->Par1 >= 2 && event->Par1 <= 13) + if (Plugin_001_updatable_pin(event->Par1)) { pinMode(event->Par1, OUTPUT); digitalWrite(event->Par1, event->Par2); @@ -283,7 +283,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) if (command == F("longpulse")) { success = true; - if (event->Par1 >= 2 && event->Par1 <= 13) + if (Plugin_001_updatable_pin(event->Par1)) { pinMode(event->Par1, OUTPUT); digitalWrite(event->Par1, event->Par2); @@ -344,3 +344,7 @@ boolean Plugin_001(byte function, struct EventStruct *event, String& string) } return success; } + +boolean Plugin_001_updatable_pin(int pin) { + return pin == 3 || ( pin >= 5 && pin <= 9) || ( pin >= 14 && pin <= 49) || ( pin >= 56 && pin <= 69); +}