ESP-NTP-MQTT2.ino
edited version for 8 max7219 modules, and added date.unknown
plain_text
a year ago
12 kB
4
Indexable
Never
/* * Based on code from https://github.com/G6EJD/ESP8266-MAX7219-LED-4x8x8-Matrix-Clock >> ESP-NTP-MQTT V0.1 > This is designed to connect to WiFi and collect NTP time. 27-MAR-2020. AKA COVID-19 year. >> ESP-NTP-MQTT V0.2 > MQTT Callback added. Send a message to the address below. >> ESP-NTP-MQTT V0.3 > Start to add Led Matrix code for MAX7219. >> ESP-NTP-MQTT V0.4 > Base ESP8266 code has NTP functionality in it now, using that as it only queries NTP once an hour >> > Also added MQTT brightness topic to alter brightness. >> ESP-NTP-MQTT V0.5 > Add 'shutdown' MQTT to switch off MAX displays >> > Add defaultBrightness >> > Add debugMode >> ESP-NTP-MQTT V0.6 > Fixed string handling code >> > Removed 'shutdown' MQTT option, now just set brightness to '0' to turn off >> > Fixed a memory leak issue that was causing reboots >> ESP-NTP-MQTT V0.7 > Added LWT (Last Will and Testament) code to track online status >> ******* Edited version based on https://github.com/JXGA/ESP8266-NTP-Clock for eight modules (8x8x8) the original one only worked with 4, now showing date too. ******* */ //////////////////////////////////////////////////////// // Includes: #include <PubSubClient.h> // MQTT Client #include <SPI.h> // SPI for MAX display #include <Adafruit_GFX.h> // Graphics Generator for MAX display #include <Max72xxPanel.h> // Panel Module for MAX display #include <ESP8266WiFi.h> // WiFi #include <coredecls.h> // settimeofday_cb() #include <PolledTimeout.h> // PolledTimeout #include <time.h> // time() ctime() #include <sys/time.h> // struct timeval #include <TZ.h> // TimeZone Database (includes DST etc.) //////////////////////////////////////////////////////// #define STASSID "yourwifi" // Enter your WiFi SSID here #define STAPSK "wifipassword" // Enter your Wifi password here #define MYTZ TZ_Europe_Copenhagen // Set your timezone here #define timeServer "uk.pool.ntp.org" // Set your timeserver here const char* mqtt_server = "mqttserver"; // Set your MQTT server address here const char* mqttUser = "mqttuser"; // Set your MQTT username here (if used) const char* mqttPassword = "mqttpassword"; // Set your MQTT password here (if used) const char* willTopic = "nodeNTP_2/status/LWT"; // Modify to set LWT topic or message const int willQoS = 0; const bool willRetain = true; const char* willMessage = "disconnected"; // Messages const char* willMessageConnect = "connected"; int pinCS = D6; // Attach CS to this pin, DIN to MOSI and CLK to SCK (cf http://arduino.cc/en/Reference/SPI ) int numberOfHorizontalDisplays = 8; // Display number (horiz) int numberOfVerticalDisplays = 1; // Display number (vert) int wait = 70; // In milliseconds, at the end of the scrolling MQTT message before returning to time int spacer = 1; // Font Spacer int width = 5 + spacer; // The font width is 5 pixels int defaultBrightness = 1; // Default brightness (1-15) or (0 - Off) int debugMode = 0; // Enable (1) or Disable (0) serial outputs of NTP time //////////////////////////////////////////////////////// // for testing purpose: extern "C" int clock_gettime(clockid_t unused, struct timespec *tp); char time_value[20]; // This var will contain the digits for the time Max72xxPanel matrix = Max72xxPanel(pinCS, numberOfHorizontalDisplays, numberOfVerticalDisplays); static time_t now; // An object which can store a time byte actualSecond; static esp8266::polledTimeout::periodicMs showTimeNow(1000); // this uses the PolledTimeout library to allow an action to be performed every 1000 milli seconds WiFiClient espClient; PubSubClient client(espClient); int wifiAttempt = 0; //////////////////////////////////////////////////////// // This is a shortcut to print a bunch of stuff to the serial port. It's very confusing, but shows what values are available #define PTM(w) \ Serial.print(" " #w "="); \ Serial.print(tm->tm_##w); void printTm(const char* what, const tm* tm) { Serial.print(what); PTM(isdst); PTM(yday); PTM(wday); PTM(year); PTM(mon); PTM(mday); PTM(hour); PTM(min); PTM(sec); } // void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Create a random client ID String clientId = "NTPNode-"; clientId += String(random(0xffff), HEX); // Attempt to connect if (client.connect(clientId.c_str(), mqttUser, mqttPassword, willTopic, willQoS, willRetain, willMessage)) { Serial.print("Connected: "); Serial.println(clientId); // Once connected, publish an announcement... client.publish(willTopic, willMessageConnect,1); client.subscribe("nodeNTP_2/inmsg"); // Subscribe to mqtt messages in this topic (eg nodeNTP_2/inmsg "Hello World" - will display text message) client.subscribe("nodeNTP_2/bright"); // Subscribe to messages in this topic (eg nodeNTP_1/bright "5" - sets the display brightness 1-15 or 0 to switch off) } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void callback(char* topic, byte* payload, unsigned int length) { // Handles receiving mqtt messages //char* payloadData; // we start, assuming open //Terminate the payload with 'nul' \0 payload[length] = '\0'; Serial.print("Message arrived in topic: "); Serial.println(topic); if (strcmp(topic,"nodeNTP_2/inmsg")==0) { Serial.print("Message:"); char *payloadData = (char *) payload; Serial.print(payloadData); matrix.fillScreen(LOW); display_message(payloadData); Serial.println(); Serial.println("-----------------------"); delay(1000); } if (strcmp(topic,"nodeNTP_2/bright")==0) { int aNumber = atoi((char *)payload); Serial.print("Brightness set to: "); Serial.println(aNumber); if (aNumber >= 0 || aNumber <= 15) { matrix.shutdown(false); matrix.setIntensity(aNumber); } if (aNumber == 0) { matrix.shutdown(true); } } } void display_message(String message) { // Displays a message on the matrix for ( int i = 0 ; i < width * message.length() + matrix.width() - spacer; i++ ) { int letter = i / width; int x = (matrix.width() - 1) - i % width; int y = (matrix.height() - 8) / 2; // center the text vertically while ( x + width - spacer >= 0 && letter >= 0 ) { if ( letter < message.length() ) { matrix.drawChar(x, y, message[letter], HIGH, LOW, 1); // HIGH LOW means foreground ON, background off, reverse to invert the image } letter--; x -= width; } matrix.write(); // Send bitmap to display delay(wait / 2); } } void showTime() { // This function gets the current time now = time(nullptr); // Updates the 'now' variable to the current time value byte actualHour = localtime(&now)->tm_hour; byte actualMinute = localtime(&now)->tm_min; actualSecond = localtime(&now)->tm_sec; sprintf(time_value, "%02d:%02d:%02d",actualHour,actualMinute,actualSecond); } void time_is_set_scheduled() { // This function is set as the callback when time data is retrieved // In this case we will print the new time to serial port, so the user can see it change (from 1970) showTime(); } void setup() { Serial.begin(115200); delay(1000); Serial.println(); Serial.println("Booted"); Serial.println("Init Matrix"); matrix.fillScreen(0); matrix.setIntensity(defaultBrightness); // Use a value between 0 and 15 for brightness matrix.setRotation(0, 1); // The first display is position upside down matrix.setRotation(1, 1); // The first display is position upside down matrix.setRotation(2, 1); // The first display is position upside down matrix.setRotation(3, 1); // The first display is position upside down matrix.setRotation(4, 1); // The first display is position upside down matrix.setRotation(5, 1); // The first display is position upside down matrix.setRotation(6, 1); // The first display is position upside down matrix.setRotation(7, 1); // The first display is position upside down display_message("Ready"); delay(1000); Serial.println("Connecting to Wi-Fi"); // start network WiFi.persistent(false); WiFi.mode(WIFI_STA); WiFi.begin(STASSID, STAPSK); wifiAttempt = 0; while (WiFi.status() != WL_CONNECTED) { delay(500); wifiAttempt = wifiAttempt + 1; if (wifiAttempt > 40) { ESP.restart(); } Serial.print("."); } String ip = WiFi.localIP().toString().c_str(); Serial.println("WiFi connected:" + ip); display_message("Connected - " + ip); client.setServer(mqtt_server, 1883); client.setCallback(callback); // install callback - called when settimeofday is called (by SNTP or us) // once enabled (by DHCP), SNTP is updated every hour settimeofday_cb(time_is_set_scheduled); // This is where your time zone is set configTime(MYTZ, timeServer); // On boot up the time value will be 0 UTC, which is 1970. // This is just showing you that, so you can see it change when the current data is received Serial.printf("Time is currently set by a constant:\n"); showTime(); } void loop() { //matrix.fillScreen(LOW); //Ensures MQTT client is connected { if (!client.connected()) { reconnect(); } client.loop(); } if (showTimeNow) { showTime(); if (debugMode) { Serial.print("time_value var is: "); Serial.println(time_value); } //matrix.drawChar(11,0, time_value[2], HIGH,LOW,1); // HH: // Static ':' Symbol if (actualSecond % 2 == 0) { matrix.drawChar(11, 0, ':', HIGH, LOW, 1); } else { matrix.drawChar(11, 0, ' ', HIGH, LOW, 1); } matrix.drawChar(1, 0, time_value[0], HIGH, LOW, 1); // H matrix.drawChar(7, 0, time_value[1], HIGH, LOW, 1); // HH matrix.drawChar(15, 0, time_value[3], HIGH, LOW, 1); // HH:M matrix.drawChar(21, 0, time_value[4], HIGH, LOW, 1); // HH:MM // Display date (ddmmm) int day = localtime(&now)->tm_mday; int month = localtime(&now)->tm_mon + 1; // Months are 0-11, so add 1 matrix.drawChar(32, 0, '0' + day / 10, HIGH, LOW, 1); matrix.drawChar(38, 0, '0' + day % 10, HIGH, LOW, 1); // Display abbreviated month name const char* monthNames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; const char* abbreviatedMonth = monthNames[month - 1]; matrix.drawChar(46, 0, abbreviatedMonth[0], HIGH, LOW, 1); matrix.drawChar(52, 0, abbreviatedMonth[1], HIGH, LOW, 1); matrix.drawChar(58, 0, abbreviatedMonth[2], HIGH, LOW, 1); matrix.write(); // Send bitmap to display if (debugMode) { Serial.println(); // human readable serial debug. Switch on debugMode at the vars to enable. Serial.print("ctime: "); Serial.print(ctime(&now)); } } //delay(50); }