LCD Display with rotary encoder on Wemos using MQTT and Node-red

Last Updated or created 2023-03-14

  • Sends a “connected” to Mosquitto
  • Mqtt controls Display
  • Rotary values are displayed, a push on the rotary sends the value to Mosquitto
Schematic : capacitors are 100nF and display has an I2C backpack
Node-red flow example
Node red GUI

Code :

Notes: There is a problem with 4 line LCD using LiquidCrystal_I2C
Lines 3 and 4 will be shifted 4 characters to the right.
Workaround is: lcd.setCursor(-4, 2); // Go to column 0, row 3

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
#include "SoftwareSerial.h"
#include <Ethernet.h>
#include <Arduino.h>
#include <RotaryEncoder.h>
#define wifi_ssid "MYSSID"
#define wifi_password "MYSSIDPASS"
#define mqtt_server "MQTTSERVER"
#define mqtt_port 1883

WiFiClient espClient;
EthernetClient ethClient;

PubSubClient mqtt(espClient);

#include <Wire.h>                  // Include Wire library (required for I2C devices)
#include <LiquidCrystal_I2C.h>     // Include LiquidCrystal_I2C library 
 
LiquidCrystal_I2C lcd(0x27, 16, 4);  // Configure LiquidCrystal_I2C library with 0x27 address, 16 columns and 4 rows
volatile bool flag = false;


#define PIN_IN1 D7
#define PIN_IN2 D6
#define push D5
int temp = 0;

RotaryEncoder *encoder = nullptr;

#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO_EVERY)
// This interrupt routine will be called on any change of one of the input signals
void checkPosition()
{
  encoder->tick(); // just call tick() to check the state.
}

#elif defined(ESP8266)
/**
 * @brief The interrupt service routine will be called on any change of one of the input signals.
 */
IRAM_ATTR void checkPosition()
{
  encoder->tick(); // just call tick() to check the state.
}

#endif

void scrollText(int row, String message, int delayTime, int lcdColumns) {
  for (int i=0; i < lcdColumns; i++) {
    message = " " + message;  
  } 
  message = message + " "; 
  for (int pos = 0; pos < message.length(); pos++) {
    lcd.setCursor(0, row);
    lcd.print(message.substring(pos, pos + lcdColumns));
    delay(delayTime);
  }
}

void setup_wifi() {
  delay(10);
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}
 
void setup() {
    setup_wifi();
  mqtt.setServer(mqtt_server, mqtt_port);
  mqtt.setCallback(callback);
  Serial.begin(115200);
  Serial.println("initializing...");

  WiFiClient espClient;
PubSubClient mqtt(espClient);

 mqtt.setClient(espClient);
  mqtt.setServer(mqtt_server, 1883);
    
mqtt.setCallback(callback);
   mqtt.subscribe("escape/display1/#");

  lcd.init();                        // Initialize I2C LCD module
  lcd.backlight();                   // Turn backlight ON
 
  lcd.setCursor(0, 0);               // Go to column 0, row 0
  lcd.print("Init");
  lcd.setCursor(0, 1);               // Go to column 0, row 1
  lcd.print("Display #1");

  encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

  // register interrupt routine
  attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);

 pinMode(push, INPUT_PULLUP);
}

void reconnect() {
  // Loop until we're reconnected
  while (!mqtt.connected()) {
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (mqtt.connect(clientId.c_str())) {
      // Once connected, publish an announcement...
      mqtt.publish("escape", "display1 connected");
      // ... and resubscribe
      mqtt.subscribe("escape/display1/#");
    } else {
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {

payload[length]= '\0';
char * charPointer = (char *)payload;
String s="";
s =charPointer;
s = s + "               "; 
    String topicStr = topic;

if (topicStr == "escape/display1/clear"){
   lcd.clear();
}
if (topicStr == "escape/display1/1in"){
  lcd.setCursor(0, 0);               // Go to column 0, row 1
  lcd.print(s.substring(0, 16));
}
if (topicStr == "escape/display1/2in"){
  lcd.setCursor(0, 1);               // Go to column 0, row 2
  lcd.print(s.substring(0, 16));
}
if (topicStr == "escape/display1/3in"){
  lcd.setCursor(-4, 2);               // Go to column 0, row 3
  lcd.print(s.substring(0, 16));
}
if (topicStr == "escape/display1/4in"){
  lcd.setCursor(-4, 3);               // Go to column 0, row 4
  lcd.print(s.substring(0, 16));
}
    }
 
void loop() {
   if (!mqtt.connected()) {
    reconnect();
  }
    mqtt.loop();

  static int pos = 0;

  encoder->tick(); // just call tick() to check the state.

  int newPos = encoder->getPosition() / 2;
    if (pos != newPos) {
    String nr="";
    Serial.print("pos:");
    Serial.print(newPos);
    Serial.print(" dir:");
    Serial.println((int)(encoder->getDirection()));
    pos = newPos;
 // hier nog iets mee doen 
   // zonder setPos moet je eerst lang clockwise voordat weer gaat tellen
    // met setPos blijft 0
   // if (pos < 0){
    //  pos = 0;
   //     encoder->setPosition(0);
   // }
    
    nr = pos + "        ";
    lcd.setCursor(10, 3);               // Go to column 10, row 3
  lcd.print(pos);
  lcd.print("   ");
  }

  temp = digitalRead(push);
  if (temp == LOW) {
    
char msg_out[20];
sprintf(msg_out, "%d",pos);
        mqtt.publish("escape/display1/rotary", msg_out);
  }

}

Leave a Reply

Your email address will not be published. Required fields are marked *