ESP8266 MAX7219 Message Board - HTTP and MQTT

My packages

max:

    input_number:
      dot_matrix_brightness:
        name: Dot Matrix Brightness
        initial: 7
        min: 0
        max: 15
        step: 1

        
      dot_matrix_scroll_delay:
        name: Dot Matrix Scroll Delay
        initial: 35
        min: 0
        max: 100
        step: 1

        
      dot_matrix_buzzer:
        name: Dot Matrix Buzzer
        initial: 10
        min: 0
        max: 100
        step: 1
        
      dot_matrix_msg_repeat:
        name: Dot Matrix Msg Repea
        initial: 10
        min: 0
        max: 100
        step: 1
        
    input_select:
      rda_dot_matrix_mqtt_topic:
        name: Dot Matrix MQTT Topic
        options:
          - rdadotmatrix
          - rdadotmatrix/json
          - rdadotmatrix/generic
          - rdadotmatrix/generic/json
        
      dot_matrix_device_list:
        name: Dot Matrix Device List
        options:
          - Living Room
          - Home Office

          
    input_text:
      dot_matrix_text:
        name: Text 1
        initial: Dot Matrix Text
        
      dot_matrix_ip:
        name: Dot Matrix Device IP
        initial: 192.168.1.5




    rest_command:
      message_dot_matrix_arg_http:
        url: "http://{{ states('input_text.dot_matrix_ip') }}/api"
        method: POST
        headers:
          authorization: !secret dot_matrix_secret_header
          content-type: "application/json"
        payload: "{MSG:'{{ states('input_text.dot_matrix_text') }}',REP:{{ states('input_number.dot_matrix_msg_repeat') }},BUZ:{{ states('input_number.dot_matrix_buzzer') }},DEL:{{ states('input_number.dot_matrix_scroll_delay') }},BRI:{{ states('input_number.dot_matrix_brightness') }},ASC:1}"
      clear_dot_matrix_arg_http:
        url: "http://{{ states('input_text.dot_matrix_ip') }}/arg"
        method: GET
        headers:
          authorization: !secret dot_matrix_secret_header
          

    automation:
    
    
      - id: Change Value of Dot Matrix Input Text
        alias: Change Value of Dot Matrix Input Text
        description: ''
        trigger:
          - platform: state
            entity_id: input_select.dot_matrix_device_list
        condition: []
        action:
          - service: input_text.set_value
            target:
              entity_id: input_text.dot_matrix_ip
            data_template:
              value: >
                {% if is_state('input_select.dot_matrix_device_list', 'Living Room') %}
                  192.168.1.5
                {% elif is_state('input_select.dot_matrix_device_list', 'Home Office')
                %}
                  192.168.1.5
                {% endif %}
        mode: single 
        
        
    script:
      message_dot_matrix:
        sequence:
          - service: rest_command.message_dot_matrix_arg_http
            data: {}
        mode: single
        alias: Message Dot Matrix
        
      clear_dot_matrix:
        sequence:
          - service: rest_command.clear_dot_matrix_arg_http
            data: {}
        mode: single
        alias: Clear Dot Matrix
        
      message_dot_matrix_mqtt:
        alias: Message Dot Matrix MQTT
        sequence:
          - service: mqtt.publish
            data:
              topic: '{{ states(''input_select.rda_dot_matrix_mqtt_topic'') }}'
              payload: |-
                { MSG: "{{ states('input_text.dot_matrix_text') }}",
                  REP: "{{ states('input_number.dot_matrix_msg_repeat') }}",
                  BUZ: "{{ states('input_number.dot_matrix_buzzer') }}", 
                  DEL: "{{ states('input_number.dot_matrix_scroll_delay') }}",
                  BRI: "{{ states('input_number.dot_matrix_brightness') }}",
                  ASC: '1' 
                }
        mode: single
      
      clear_dot_matrix_mqtt:
        alias: Clear Dot Matrix MQTT
        sequence:
          - service: mqtt.publish
            data:
              topic: '{{ states(''input_select.rda_dot_matrix_mqtt_topic'') }}'
              payload: |-
                { MSG: ""
                }
        mode: single
      
      
      
1 Like

Is that working ok?
Since there is no question I’m assuming it is.

Doesn’t work well
no idea how it works
I gave up on this idea.

@rdeangel I would like to use your code below but need the message sent over MQTT to be displayed whenever IO5 is taken low and the time display to resume after the entire message has been displayed.
I cannot get this to work,due to poor coding skills !
If you could assist please ?

// 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 "SSID"        // Enter your WiFi SSID here
#define STAPSK  "pass"    // Enter your Wifi password here
String newHostname = "KeezerScroller";

//#define MYTZ TZ_Europe_London        // Set your timezone here - check for your nearest city in TZ.h
#define MYTZ TZ_Africa_Johannesburg

#define timeServer "192.168.100.250"  // Set your timeserver here

const char* mqtt_server = "192.168.100.225";  // Set your MQTT server address here
const char* mqttUser = "";                       // Set your MQTT username here (if used)
const char* mqttPassword = "";                   // Set your MQTT password here (if used)

const char* willTopic = "beerscroller/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 = D4;                             // Attach CS to this pin, DIN to MOSI and CLK to SCK (cf http://arduino.cc/en/Reference/SPI )
int numberOfHorizontalDisplays = 4;         // 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 = "Beer-";
    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("beerscroller/inmsg");             // Subscribe to mqtt messages in this topic (eg nodeNTP_1/inmsg "Hello World" - will display text message)
      client.subscribe("beerscroller/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, "beerscroller/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, "beerscroller/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);
  pinMode(5, INPUT_PULLUP);  // Set D1 (IO5) as input with active pullup for PIR
  Serial.println();
  Serial.println("Booted");
  Serial.println("Init Matrix");

  matrix.setPosition(0, 3, 0);     // This fixes MAX7219  8 x 8 displaying in wrong order - (Display-Nr ab Einspeisung, X, Y)
  matrix.setPosition(1, 2, 0);
  matrix.setPosition(2, 1, 0);
  matrix.setPosition(3, 0, 0);

  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
  display_message("Ready");

  delay(1000);

  Serial.println("Connecting to Wi-Fi");

  // start network
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  //Set new hostname defined above
  WiFi.hostname(newHostname.c_str());
  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(1, 0, time_value[0], HIGH, LOW, 1); // H
    matrix.drawChar(9, 0, time_value[1], HIGH, LOW, 1); // HH
    //matrix.drawChar(14,0, time_value[2], HIGH,LOW,1); // HH: // Static ':' Symbol
    if (actualSecond % 2 == 0) {
      matrix.drawChar(14, 0, ':', HIGH, LOW, 1);
    } else {
      matrix.drawChar(14, 0, ' ', HIGH, LOW, 1);
    }
    matrix.drawChar(19, 0, time_value[3], HIGH, LOW, 1); // HH:M
    matrix.drawChar(26, 0, time_value[4], HIGH, LOW, 1); // HH:MM
    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);

  if (digitalRead(5) == LOW)   {                       // D1 Mini input D1 =  IO5
    // What goes here ?
  }
}