Arduino Text Scrolling on 16x02 I2c on NodeMcu (esp8266-12)

Hi everyone,

I have managed to get my 1602 I2C lcd working on a NodeMCU devkit. I can display text parsed from the web but I am not sure how to set it to autroscroll if message is > than 16 characters. I tried the lcd.ScrollDisplayLeft() but it doesn’t work. I figured I would have to do it manually and it is a matter of getting string length and then looping the characters.

This is what I have so far:

#include <ESP8266WiFi.h>
#include <Wire.h>  // This library is already built in to the Arduino IDE
#include <LiquidCrystal_I2C.h> //This library you can add via Include Library > Manage Library >  

LiquidCrystal_I2C lcd(0x3F, 16, 2);

const char* ssid = "ssid"; 
const char* password = "pass";
const char* host = "api.thingspeak.com";

int find_text(String needle, String haystack, int from) {
  int foundpos = -1;
  if (haystack.length() < needle.length())
    return foundpos;
  for (int i = from; (i < haystack.length() - needle.length()); i++) {
    if (haystack.substring(i, needle.length() + i) == needle) {
      foundpos = i;
      return foundpos;
    }
  }
  return foundpos;
}

void setup() {
  Serial.begin(115200);
  delay(100);
  lcd.init();   // initializing the LCD
  lcd.backlight(); // Enable or Turn On the backlight
  delay(200);

  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println();
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  lcd.setCursor(0, 0);
  Serial.print("Connecting to ");
  lcd.print("Connecting");
  lcd.setCursor(1, 1);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    lcd.print(".");    
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Connected!!");
  delay(1000);
}
int value = 0;

void loop() {

  Serial.print("connecting to ");
  Serial.println(host);

  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");

  }

  // We now create a URI for the request
  String url = "/apps/thinghttp/send_request?api_key=345345345345345";
  Serial.print("Requesting URL: ");
  Serial.println(url);
  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  lcd.clear();
  lcd.setCursor(0, 0);               
  lcd.print("Fetching Data..");
  delay(10000);

  // Read all the lines of the reply from server and print them to Serial
  while (client.available()) {
    String line = client.readStringUntil('\r');

    int start_loc = find_text("<b>", line, 0);
    int end_loc = find_text("</b>", line, 0);    
    if (start_loc > 0 && end_loc > 0)
    {
      lcd.clear();
      Serial.println("data:  ");
      lcd.print("data: ");
      lcd.setCursor(1, 1);
      for (int i = start_loc + 3; i < end_loc; i++)
      {
        Serial.print(line[i]);
        lcd.print(line[i]);
     }

  Serial.println();
  Serial.println("closing connection");
  delay(2000);

}
  }
}

With all those delay() function calls in the loop(), your scrolling text will be a misery to watch.
I'd probably write a function which takes a buffer matching the whole text you want to display, say XX characters, which, when called, simply writes out 16 characters (your display line length) from the buffer to the display and advances a pointer by 1, so the next time it is called, the text in the display appears shunted by one character.
The function would be called at say half second intervals by a timer ( see: ticker() for ESP8266 ) so the scrolling rate would be independent of any delays etc. in your loop.

Thanks. I will have a look at optimising it once I figure out how to actually get a scroll working. I just checked the ticker library and it looks useful and I will implement it at a later stage :slight_smile: I understand the concept you suggest but have no idea how to actually implement and code it.

Can you by any chance give me some sample code so I have a starting point? I don't want to be spoon-fed obviously but at the same time by knowledge level is not yet at the point where I know where to start. I would really appreciate the help :slight_smile:

Scrolling text on those displays looks absolutely awful....

Regards,
Ray L.

Here is a crude version for the serial monitor which you can add the LCD stuff to.
If that gets you started, we can then look at improving it along the lines I originally suggested.

String line = "This is my long String to scroll" ;

void setup() {
  Serial.begin ( 9600 ) ;
  if ( line.length() <= 16 ) {
    Serial.println( line ) ;
  }
  else {
    for ( int i = 0 ; i <= line.length() - 16 ; i++ ) {
      Serial.println( line.substring( i, i + 16 ) ) ;
      delay( 500 ) ;
    }
  }
}

void loop() { }

@Ray, I completely agree but this is just for a project to put in my classroom so my friends can see what period is next, so it should suffice.

@6v6gt. Thanks! I get the logic behind it now and that is a great starting point for me :slight_smile: I assume I have to convert my line to a string before doing this. Thanks again, much appreciated Sir.

Your variable line is already a string:

String line = client.readStringUntil('\r');

Hve fun with it.

Oh I see. I have done this:

      for (int i = start_loc + 3; i < end_loc; i++)
      {
       // scroll
       lcd.setCursor(1,1);
          if ( line[i].length() <= 16 ) {
            lcd.print(line[i]) ;
          }
          else {
            for ( int i = 0 ; i <= line[i].length() - 16 ; i++ ) {
              lcd.print( line[i].substring( i, i + 16 ) ) ;
              delay( 500 ) ;
            }
          }
      
       // scroll
      }

But I get the following error in my console:

request for member 'length' in 'line.String::operator[](((unsigned int)i))', which is of non-class type 'char'

The main part of the code, based on your original sketch, should look like this:

 // Read all the lines of the reply from server and print them to Serial
  while (client.available()) {
    String line = client.readStringUntil('\r');

    int start_loc = find_text("<b>", line, 0);
    int end_loc = find_text("</b>", line, 0);   
    if (start_loc > 0 && end_loc > 0)
    {
      lcd.clear();
      Serial.println("data:  ");
      lcd.print("data: ");
      lcd.setCursor(1, 1);
      // dump line read to lcd. scroll if necessary . . .
      if ( line.length() <= 16 ) {
        Serial.println( line ) ;
        lcd.print( line ) ;
      }
      else {
        for ( int i = 0 ; i <= line.length() - 16 ; i++ ) {
          Serial.println( line.substring( i, i + 16 ) ) ;
          lcd.print( line.substring( i, i + 16 ) ) ;
          delay( 500 ) ;
        }
      }
    }
    Serial.println();
    Serial.println("closing connection");
    delay(2000);
  }

Aha! I actually have multiple lines which I was parsing and therefore only posted some of the code, but I understand better now. Thanks for taking the time to teach me, I really appreciate it.

The OLEDs displays ars really great on the ESP's:
I have a few projects here.

Ray

Some really nice projects you have there Ray! I'll definitely refer to them when I get an OLED display. Bookmarked! Thanks