Eink Multi Line Text?

Evening - Just setting up a 2.9 inch waveshare - i have Hello World working :slight_smile: and have moved onto displaying text from MQTT - ie from the basic example:

lambda: |-
      it.printf(20, 20, id(roboto), id(mysensor).state.c_str());

The Q is - my text is all on one line, how do i split the text over multiple lines, i kind of hoped it would auto format :slight_smile:

Andy

Did you ever figure this out? I have a multi-line string coming from Home Assistant but it’s always displayed as a single line on the E-Ink display.

Sadly not - i went down a different route in the end for multiline data, pulling it in seperatly via an html page (so sadly not from HA).

I put a tutorial online at: https://connected-environments.org/blog/node-js-node-express-and-puppeteer-for-epaper-eink-displays-how-to-open-a-web-page-save-as-an-image/

Andy

Any news since the last post ? I’m still looking for a solution without using any external program :slight_smile:

For anyone in the future looking for a solution to this… Not pretty but it works. Adjust limit and Y addition as required.:

std::string s = id(weather).state;

      int limit = 35;

      int space = 0;

      int i = 0;

      int line = 0;

      y= 305; // start Y

      while(i<s.length()){ //loop through string, counting all the spaces, and replacing the last one with ~ [marked by space variable] if the count exceeds limit of 35

        if(s.substr(i,1) == " "){space = i; }

        if(line>limit-1){s=s.substr(0,space)+"~"+s.substr(space+1);line = 0;}

          i++;line++;}

      size_t pos = s.find("~"); //find the first line break

 

      int linecount = 1; //need number of lines to store the break positions in an array

      int breakpositions[10]; //store breakpositions [the '~']

      breakpositions[0] = -1; // start at -1 cause we need to truncate the replaced characters and without this will cut off 1st character of message

      while ( pos != std::string::npos) //loop through  replacing the ~ with CR - though this doesnt matter here it will never be displayed, but need to change them to keep the loop from repeating at the start

      {

        s.replace(pos,1, "\n");

        breakpositions[linecount] = pos; //store the position of the break in an array

        pos = s.find("~"); // move forward

     

        linecount++; // we have a new line, count it

      }

 

      breakpositions[linecount] = s.length(); //set the last entry in array to the length of string for calculation below

      std::string singleline; //this will be the line we print

 

      i = 0;

      while (i < linecount ) {  // count through the lines

        singleline = s.substr(breakpositions[i]+1,(breakpositions[i+1]-breakpositions[i]-1)); //extract each line of text from the string - strip off the CRLF and the space.

        it.printf(10, y, id(font_footer), "%s", singleline.c_str()); //print it!

        y=y+30; // increment y to print properly on display

      i++;

      }
4 Likes

Just wondering for those of us that are not coders (but give it a red hot go lol) can you provide this is context of the greater config file?

And is there a way to say replace characters. My sensor is pulling in a list that looks like;

['Work on lights', 'Walk home', 'Fix Formatting ESP32', 'Get liteneasy']

And I just want it to be;

Work on lights
Walk home
Fix Formatting ESP32
Get liteneasy

Thanks in advance :slight_smile:

So been trying to get this working the last couple of days and have this as my code;

std::string s = id(alexa_to_do_list).state;

          int limit = 35;

          int space = 0;

          int i = 0;

          int line = 0;

          y= 105; // start Y

          while(i<s.length()){ //loop through string, counting all the spaces, and replacing the last one with ~ [marked by space variable] if the count exceeds limit of 35

            if(s.substr(i,1) == " "){space = i; }

            if(line>limSit-1){s=s.substr(0,space)+"~"+s.substr(space+1);line = 0;}

              i++;line++;}

          size_t pos = s.find("~"); //find the first line break

          int linecount = 1; //need number of lines to store the break positions in an array

          int breakpositions[10]; //store breakpositions [the '~']

          breakpositions[0] = -1; // start at -1 cause we need to truncate the replaced characters and without this will cut off 1st character of message

          while ( pos != std::string::npos) //loop through  replacing the ~ with CR - though this doesnt matter here it will never be displayed, but need to change them to keep the loop from repeating at the start

          {

            s.replace(pos,1, "\n");

            breakpositions[linecount] = pos; //store the position of the break in an array

            pos = s.find("~"); // move forward

            linecount++; // we have a new line, count it

          }

          breakpositions[linecount] = s.length(); //set the last entry in array to the length of string for calculation below

          std::string singleline; //this will be the line we print

          i = 0;

          while (i < linecount ) {  // count through the lines

            singleline = s.substr(breakpositions[i]+1,(breakpositions[i+1]-breakpositions[i]-1)); //extract each line of text from the string - strip off the CRLF and the space.

            it.printf(10, y, id(font_small_bold), "%s", singleline.c_str()); //print it!

            y=y+30; // increment y to print properly on display

          i++;

       }

But Im getting the following error

/config/esphome/to-do.yaml:201:11: error: 'y' was not declared in this scope
           y= 105; // start Y
           ^
/config/esphome/to-do.yaml:201:11: note: suggested alternative: 'yn'
           y= 105; // start Y
           ^
           yn
/config/esphome/to-do.yaml:204:21: error: 'limSit' was not declared in this scope
             if(line>limSit-1){s=s.substr(0,space)+"~"+s.substr(space+1);line = 0;}
                     ^~~~~~
/config/esphome/to-do.yaml:204:21: note: suggested alternative: 'limit'
             if(line>limSit-1){s=s.substr(0,space)+"~"+s.substr(space+1);line = 0;}
                     ^~~~~~
                     limit

Any ideas?

Ahhh, some of the variables like Y I’ve declared much further up. Every variable you use must be declared a type before use. Type means string [words] or integer [whole numbers] etc.
add an int y=0; [or whatever Y position you’d like to start the wording at at top. The LimSit error is likely because of a typo - it should be limit.

1 Like

LOL see that’s the thing, if you don’t know, you don’t know.

Thats so cool thanks!

Once I got it working, I can understand it a bit better and changed the limit from 35 to 20, which looks better for me.

I’m just wondering is anyone can help me to create code for the following.

replace [ and ] with nothing

replace “,” with “~” to perform the line break.

Would that work?

That simple change would give me just a list right?

Even if this is as far as I get, its still really cool, so thanks for that :slight_smile:

EDIT

How did you figure this out LOL??? Im looking at the ESPHome doco and if has nothing about line breaks ect :frowning:

Oh ok, I think I misinterpreted your code here. It seemed like you were saying that anytime ESPHome sees ~ it performs a line break. But that must be wrong lol

However adding

| replace('[','') | replace(']','') | replace(',','~') }}"

To the value template did allow me to get rid of some of those characters which is great. I just need to know how to turn “,” into a line break :slight_smile:

EDIT

Sorry that I’m basically adding my working for everyone to scroll past HAHA

So its “\n” that needs to be added. I cant do the value template thing, it doesn’t seem to work.

If anyone knows, Id appreciate it :slight_smile:

EDIT again,

Ok, giving up for today lol, ChatGPT gave me this;

        std::string shopping_list = id(alexa_shopping_list).state;
        std::replace(shopping_list.begin(), shopping_list.end(), ',', '\n');
        it.printf(20, 440, id(font_small_bold), TextAlign::BASELINE_LEFT, "%s", shopping_list.c_str());

And it displays, but does not return the line, just turns the comma into an X character of some kind :frowning:

Would be curious to understand how to simply add newlines too. Same problem.

Thanks for the directions. For who it might help, this worked for my Nextion display:

Under lambda: |- add (add the text_sensors…):

     // Fetch the weather state
      // std::string s = id(weather).state.c_str();
      int rounded_temp = static_cast<int>(round(id(outside_temperature).state));
      std::string s = "Het is buiten " + std::to_string(rounded_temp) + " graden. De weersverwachting is: " + id(weather).state.c_str();

      int limit = 56;
      int space = 0;
      int i = 0;
      int line = 0;

      // Loop through string, counting spaces and replacing the last one with ~ if the count exceeds the limit
      while (i < s.length()) {
        if (s.substr(i, 1) == " ") {
          space = i;
        }
        if (line > limit - 1) {
          s = s.substr(0, space) + "~" + s.substr(space + 1);
          line = 0;
        }
        i++;
        line++;
      }

      // Find the first line break
      size_t pos = s.find("~");

      // Loop through, replacing ~ with \r characters
      while (pos != std::string::npos) {
        s.replace(pos, 1, "\\r");
        pos = s.find("~", pos + 1);
      }

      // Send the formatted string to the Nextion display component "verlichting.t11"
      it.set_component_text_printf("verlichting.t11", "%s", s.c_str());