Retrieve text (strings) by date

Would like to get your opinion on how I should best address my problem situation: I am planning a daily motivation text (eg a Bible verse) to get via my Hoverlabs Beam.

The text is available as a download of the publisher, the Herrenhuter solutions, at www.losungen.de already in different data types.

The output on the Hoverlabs Beam has also been treated in another thread and should not be a problem.

It is simply a matter of selecting a platform where the available text can be imported (eg in this structure: ID, date, Biblestelle, Bible verses) and then the appropriate text is retrieved and displayed on the basis of the date.

Unfortunately, the publisher does not provide a bindable API.

A first import to thingspeak I did not succeed.

Do you have any suggestions for me?

Can you just save tons of bible verses in memory and just display them daily at random?

The P1 Module has the 1MB of extra memory which should allow for tons of verses to be stored.

Adding to @RWB’s suggestion, adding a microSD would give you limitless access to verses!

I found this site with an API for my case.

I decide to generate a webhook to subscribe to this offer (hope I´m on the right way).
My settings:
Event Name : tageslosung
Full URL : http://losungen.klose.cloud/api/today
Request Type : GET
Device : any device

Now I got an error: ETIMEDOUT in case I do a test.

1 Like

Today I´m going a step further in my project to display a daily motivation string on my beams:

a.) I register a webhook > which works fine now.
b.) I am not so practiced in the coding and wished me your help in these 4 points:

  • ToDo1: How to split data in variable and payload

  • ToDo2: I like only “date”, “wtag”, “solution text” and “solution verse” to display

  • ToDo3: loop once a day: trigger at night is enough - text will change 1x per day 00: 00h and

  • ToDo4: set photon after trigger in system mode “sleep”

    #include “application.h”
    #include “beam.h”

    /* pin definitions for Beam */
    #define RSTPIN 2 //use any digital pin
    #define IRQPIN 9 //currently not used - leave unconnected
    #define BEAMCOUNT 4 //number of beams daisy chained together

    /* Iniitialize an instance of Beam */
    Beam b = Beam(RSTPIN, IRQPIN, BEAMCOUNT);

    void setup() {
    Serial.begin(9600);

    // Subscribe to the integration response event
    Particle.subscribe("hook-response/tageslosung", myHandler, MY_DEVICES);
    
    // Beam Init
    Wire.begin();
    Serial.println("Starting Beam example");
    b.begin();
    

    }

    int i = 0;

    void myHandler(const char *event, const char data)
    {
    i++;
    Serial.print(i);
    Serial.print(event);
    Serial.print(", data: ");
    if (data) {
    Serial.println(data);
    // ToDo1: split data in Variable and payload and
    // ToDo2: I like only “Datum”, “Wtag”, “Losungstext” and “Losungsvers”
    /
    JSON Source - https://losungen.klose.cloud/api/today
    {
    “Datum”: “2017-05-05T00:00:00”,
    “Wtag”: “Freitag”,
    “Sonntag”: {},
    “Losungstext”: “Du sollst dein Herz nicht verhärten und deine Hand nicht zuhalten gegenüber deinem armen Bruder.”,
    “Losungsvers”: “5.Mose 15,7”,
    “Lehrtext”: “Wenn jemand dieser Welt Güter hat und sieht seinen Bruder darben und verschließt sein Herz vor ihm, wie bleibt dann die Liebe Gottes in ihm?”,
    “Lehrtextvers”: “1.Johannes 3,17”
    }
    */

          //  Beam can begin scrolling text with just print() and play()
          b.print(String(data));
          b.play();
          //b.display();
          delay(45000);
    }
    else
      Serial.println("NULL");
    

    }

    void loop() {
    // Get some data
    String data = String(“Hallo Ingo”); // String(10);
    // Trigger the integration
    Particle.publish(“tageslosung”, data, PRIVATE);

    //Particle.subscribe("hook-response/tageslosung", myHandler, MY_DEVICES);
    // Wait 60 seconds
    delay(60000);
    
    // ToDo3: loop once a day: trigger at night is enough - text will change 1x per day 00:00h,
    // ToDo4: set photon after trigger in system-mode "sleep"
    

    }

The answer to b.1 & b.2 would best be done with the SparkJson library - have a look at the samples

b.3 & b.4 is just a matter of calling System.sleep() with 86400 sec sleep periode. Then the device will only wake once a day.
If you want to wake exactly the same time every day you might want to calculate that value a bit more precise

  int hour = 12;
  int minute = 0;
  int second = 0; 
  int sec2sleep = (86400 - (Time.local() % 86400) + 3600*hour + 60*minute + second) % 86400;

Thx! - that is what I need a JSON Parser. I will give me a try.

One step further in my project: now i can display all strings which I like :slight_smile:
Included the sparkjson-libary and adapted this informations to parse my webhook.

StaticJsonBuffer<256> jsonBuffer;

char *mutableCopy = strdup(data);
JsonObject& root = jsonBuffer.parseObject(mutableCopy);

       if (!root.success()) {
         Serial.println("parseObject() failed");
         return;
         }
         
datum = root["Datum"];
wochentag = root["Wtag"];

losungstext = root["Losungstext"];
losungsvers = root["Losungsvers"];
lehrtext = root["Lehrtext"];
lehrtextvers = root["Lehrtextvers"];
free(mutableCopy);

Later I will check my ToDo3 and 4 that my photon reads the webhook 1x per day.

In this moment I feel good to read the strings, but In Germany we have umlauts like ä, ü, ö and ß.
How can I do the necessary conversion in the charactermap.h for these characters?

As example the definitions in my charactermap.h for my beam is as described:
uint8_t charactermap[66][7] = {
{0x00,0x00,0xFF,0xFF,0xFF,0xFF}, // SPACE
{0x17,0x0,0xFF,0xFF,0xFF,0xFF,0xFF}, // !
{0x3,0x0,0x3,0x0,0xFF,0x0,0xFF}, // "
{0xA,0x1F,0xA,0x1F,0xA,0x0,0xFF}, // #
{0x17,0x15,0x1F,0x15,0x1D,0x0,0xFF}, // $
{0x12,0x8,0x4,0x12,0x0,0xFF,0xFF}, // %
{0xA,0x15,0xE,0x10,0x0,0xFF,0xFF}, // &
and so on

Can I define my necessary ö, ä, ü and ß here with a characterline on top or should I convert it with a bit code?

That’s a tricky one since the way to go depends on both sides of the equation.
Where does the data come from and how (what format)?
And where will you be using the received data?

Especially the lattet question will demand for multiple implementations.
To send to a dot display you’d need to create the correct bit pattern at the correct place in the font definitions.
For different higher level targets you may need to translate the 8bit ASCII code to the required target.

For the String output I use a Hoverlabs Beam with own Libary. For this I had already opened a thread. Within the Libary there is a charactermap.h file, which takes the translation into pixels that can be displayed for the LED. Unfortunately the German umlauts are missing here and I am looking for a way to supplement this as in the example above in the simplest case in the list.
I do not know how the ASCII code looks for ä, ö, ü and ß for a test.

The best would be to extend the pixels table in that header and put the Umlaute in their usual places (Ä=0xC4=196, Ö=0xD6=214, Ü=0xDC=220, ß=0xDF=223, ä=0xE4=228, ö=0xF6=246, ü=0xFC=252).

If you are using Windows you can open charmap.exe to get the ASCII codes, or you can google too :wink:

Thx ScruffR - this sounds to easy. I checked it reversed:
Z = 0x5A with charmap but in the lib file charactermap.h from the beam is Z defined as:

{0xF,0x10,0xC,0x10,0xF,0x00,0xFF}, // W
{0x11,0xA,0x4,0xA,0x11,0x00,0xFF}, // X
{0x1,0x2,0x1C,0x2,0x1,0x00,0xFF}, // Y
{0x11,0x19,0x15,0x13,0x0,0xFF,0xFF}, // Z

I am missing the anchor as a landing point.
Why are 7 characters required to display 1 character on beam?
Google throws me to uint8_t charactermap [66] [7] for me not usable.

I guess since there is a constant offset, to keep the array smaller and just skip the non-printables 0x00..0x1F, but I'd assume the rest are consecutive characters.

What character is the first in the array?
Look up it's normal ASCII position and subtract that from 0x5A and then count the position of the Z-line.

Have a look at the binary representation of the seven bytes
{0x11,0x19,0x15,0x13,0x0,0xFF,0xFF}, // Z
would translate to

0x 11 = 0b 00010001 |   .   .|
0x 19 = 0b 00011001 |   ..  .|
0x 15 = 0b 00010101 |   . . .|
0x 13 = 0b 00010011 |   .  ..|
0x 00 = 0b 00000000 |        |
0x FF = 0b 11111111 |........|
0x FF = 0b 11111111 |........|

Flip that dot pattern 90° and look at a Z

2 Likes

I can only partially follow: I have not yet the bridge of one ASCII character (at the example of a Z = 0x5A) to the division in 4 Parts after
0x 11 = 0b 00010001
0x 19 = 0b 00011001
0x 15 = 0b 00010101
0x 13 = 0b 00010011
How did you deduce this?

As I have tried, charmap.exe is also no help.

I add the function completely to:

uint8_t charactermap[66][7] = {
{0x00,0x00,0xFF,0xFF,0xFF,0xFF},      // SPACE
{0x17,0x0,0xFF,0xFF,0xFF,0xFF,0xFF},      // !
{0x3,0x0,0x3,0x0,0xFF,0x0,0xFF},       // "
{0xA,0x1F,0xA,0x1F,0xA,0x0,0xFF},     // #
{0x17,0x15,0x1F,0x15,0x1D,0x0,0xFF},  // $
{0x12,0x8,0x4,0x12,0x0,0xFF,0xFF},     // %
{0xA,0x15,0xE,0x10,0x0,0xFF,0xFF},     // &
{0x3,0x0,0xFF,0xFF,0xFF,0xFF,0xFF},       // '
{0xE,0x11,0x0,0xFF,0xFF,0xFF,0xFF},      // (
{0x11,0xE,0x0,0xFF,0xFF,0xFF,0xFF},      // )
{0x5,0x2,0x5,0x0,0xFF,0xFF,0xFF},       // *
{0x8,0x1C,0x8,0x0,0xFF,0xFF,0xFF},      // +
{0x10,0x8,0x0,0xFF,0xFF,0xFF,0xFF},      // ,
{0x4,0x4,0x0,0xFF,0xFF,0xFF,0xFF},       // -
{0x10,0x0,0xFF,0xFF,0xFF,0xFF,0xFF},      // .
{0x18,0xE,0x3,0x0,0xFF,0xFF,0xFF},      // /
{0x1F,0x11,0x1F,0x0,0xFF,0xFF,0xFF},    // 0
{0x2,0x1F,0x0,0xFF,0xFF,0xFF,0xFF},      // 1
{0x1D,0x15,0x17,0x0,0xFF,0xFF,0xFF},    // 2
{0x15,0x15,0x1F,0x0,0xFF,0xFF,0xFF},    // 3
{0x7,0x4,0x1F,0x0,0xFF,0xFF,0xFF},      // 4
{0x17,0x15,0x1D,0x0,0xFF,0xFF,0xFF},    // 5
{0x1F,0x15,0x1D,0x0,0xFF,0xFF,0xFF},    // 6
{0x1,0x1,0x1F,0x0,0xFF,0xFF,0xFF},      // 7
{0x1F,0x15,0x1F,0x0,0xFF,0xFF,0xFF},    // 8
{0x17,0x15,0x1F,0x0,0xFF,0xFF,0xFF},    // 9
{0xA,0x0,0xFF,0xFF,0xFF,0xFF,0xFF},       // :
{0xA,0x0,0xFF,0xFF,0xFF,0xFF,0xFF},       // ;
{0x4,0xA,0x11,0x0,0xFF,0xFF,0xFF},      // <
{0xA,0xA,0xA,0x0,0xFF,0xFF,0xFF},       // =
{0x11,0xA,0x4,0x0,0xFF,0xFF,0xFF},      // >
{0x1,0x15,0x7,0x0,0xFF,0xFF,0xFF},      // ?
{0x1F,0x11,0x1D,0x15,0x1F,0x0,0xFF},  // @
{0x1F,0x05,0x05,0x1F,0x00,0xFF,0xFF},  // A
{0x1F,0x15,0x15,0x0A,0x00,0xFF,0xFF},  // B
{0x0E,0x11,0x11,0x0A,0x00,0xFF,0xFF},  // C
{0x1F,0x11,0x11,0x0E,0x00,0xFF,0xFF},  // D
{0x1F,0x15,0x15,0x15,0x00,0xFF,0xFF},  // E
{0x1F,0x5,0x5,0x0,0xFF,0xFF,0xFF},     // F
{0x1F,0x11,0x15,0x1D,0x0,0xFF,0xFF},   // G
{0x1F,0x4,0x4,0x1F,0x0,0xFF,0xFF},     // H
{0x11,0x1F,0x11,0x0,0xFF,0xFF,0xFF},   // I
{0x18,0x10,0x1F,0x0,0xFF,0xFF,0xFF},   // J
{0x1F,0x4,0x1B,0x0,0xFF,0xFF,0xFF},    // K
{0x1F,0x10,0x10,0x0,0xFF,0xFF,0xFF},   // L
{0x1F,0x2,0x4,0x2,0x1F,0x00,0xFF},     // M
{0x1F,0x2,0x4,0x8,0x1F,0x00,0xFF},     // N
{0xE,0x11,0x11,0x11,0xE,0x00,0xFF},    // O
{0x1F,0x5,0x7,0x0,0xFF,0xFF,0xFF},     // P
{0x1F,0x11,0x15,0x19,0x1F,0x00,0xFF},  // Q
{0x1F,0x5,0xD,0x17,0x0,0xFF,0xFF},     // R
{0x17,0x15,0x15,0x1D,0x0,0xFF,0xFF},   // S
{0x1,0x1F,0x1,0x0,0xFF,0xFF,0xFF},     // T
{0x1F,0x10,0x10,0x1F,0x0,0xFF,0xFF},   // U
{0x7,0x8,0x10,0x8,0x7,0x00,0xFF},      // V
{0xF,0x10,0xC,0x10,0xF,0x00,0xFF},     // W
{0x11,0xA,0x4,0xA,0x11,0x00,0xFF},     // X
{0x1,0x2,0x1C,0x2,0x1,0x00,0xFF},      // Y
{0x11,0x19,0x15,0x13,0x0,0xFF,0xFF},   // Z

{0x1F,0x11,0x0,0xFF,0xFF,0xFF,0xFF},       //[
{0x3,0xE,0x18,0x0,0xFF,0xFF,0xFF},        ///
{0x11,0x1F,0x0,0x0,0xFF,0xFF,0xFF},       //]
{0x6,0xE,0x1C,0xE,0x6,0x0,0xFF},        //^
{0x10,0x10,0x10,0x0,0xFF,0xFF,0xFF},      //_
{0x1,0x2,0x0,0xFF,0xFF,0xFF,0xFF},         //'
};

I would like to insert the lowercase letters and the umlauts.

I am on the state that is expanding a line around
0x5A, 0x00, 0xFF, 0xFF (possibly further up to 7) would have to suffice for the representation of the Z.

That is basic binary/hex conversion.
Each hex digit can be represented by four bits.
And bits are calculated as powers of 2 depending on their position.

0x0 = 0b0000 = 0*2^3 + 0*2^2 + 0*2^1 + 0*2^1 =  0
0x1 = 0b0001 = 0*2^3 + 0*2^2 + 0*2^1 + 1*2^1 =  1
0x2 = 0b0010 = 0*2^3 + 0*2^2 + 1*2^1 + 0*2^1 =  2
0x3 = 0b0011 = 0*2^3 + 0*2^2 + 1*2^1 + 1*2^1 =  3
0x4 = 0b0100 = 0*2^3 + 1*2^2 + 0*2^1 + 0*2^1 =  4
...
0x8 = 0b1000 = 1*2^3 + 0*2^2 + 0*2^1 + 0*2^1 =  8
...
0xA = 0b1010 = 1*2^3 + 0*2^2 + 1*2^1 + 0*2^1 = 10
...
0xF = 0b1111 = 1*2^3 + 1*2^2 + 1*2^1 + 1*2^1 = 15

You get the system?
If you want to add the Umlaute, you need to get the hang of that in order to create the pixel matrix for your custom symbols.
Draw up a 7x8 matrix, draw your set pixels in it till you like your symbol and then put a 1 for each set pixel and a 0 for each clear pixel.
Or just use binary (0b00000000) instead of hex (0x00) - just remember the 90° flip.

If the first letter in your charmap[][] is the blank/space character you have an offset of 32, since this is the ASCII code for it, but the index in the array is 0.
Consequently the exclamation mark (index 1 will be ASCII 33 or 0x20). But the capital Z (0xFA = 250 -> 250 - 32 = 218) would be outside of that 66 element array, so there must be some extra logic that bridges some gaps in the character definition.
You need to locate that logic and add some special treatment for the Umlaute there.
You also need to extend the charmap to add the extra characters.

1 Like

Thank you for the path you showed - I will go to Him!

Today I created the necessary hex codes to complement charactermap.h and add my Excel template for documentation. So far I am quite happy and have taken a step further.

When adding the charactermap.h to my special characters I made from the original array “uint8_t charactermap [66] [7] = {” [71] [7]: but without success.

In my second try, I decided to keep the original array and to exchange a few existing special characters with my desired one.

Both paths did not lead to success!

Your help “Search for an extension logic” following, I have the frames.h viewed, but does not open up to me their contents:

int frame0[0x0F] = {                    //Frame 0
  0b00000000, 0b00000000, 0b00000000,     
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
};
int frame1[0x0F] = {                    //Frame 0
  0b10000000, 0b00000000, 0b00000001,     
  0b10000000, 0b00000000, 0b00000001,
  0b10000000, 0b00000000, 0b00000001,
  0b10000000, 0b00000000, 0b00000001,
  0b10000000, 0b00000000, 0b00000001,
};
int frame2[0x0F] = {                    //Frame 0
  0b11000000, 0b00000000, 0b00000011,     
  0b11000000, 0b00000000, 0b00000011,
  0b11000000, 0b00000000, 0b00000011,
  0b11000000, 0b00000000, 0b00000011,
  0b11000000, 0b00000000, 0b00000011,
};
int frame3[0x0F] = {                    //Frame 0
  0b01100000, 0b00000000, 0b00000110,     
  0b01100000, 0b00000000, 0b00000110,
  0b01100000, 0b00000000, 0b00000110,
  0b01100000, 0b00000000, 0b00000110,
  0b01100000, 0b00000000, 0b00000110,
};
int frame4[0x0F] = {                    //Frame 0
  0b00110000, 0b00000000, 0b00001100,     
  0b00110000, 0b00000000, 0b00001100,
  0b00110000, 0b00000000, 0b00001100,
  0b00110000, 0b00000000, 0b00001100,
  0b00110000, 0b00000000, 0b00001100,
};
int frame5[0x0F] = {                    //Frame 0
  0b00011000, 0b00000000, 0b00011000,     
  0b00011000, 0b00000000, 0b00011000,
  0b00011000, 0b00000000, 0b00011000,
  0b00011000, 0b00000000, 0b00011000,
  0b00011000, 0b00000000, 0b00011000,
};
int frame6[0x0F] = {                    //Frame 0
  0b00001100, 0b00000000, 0b00110000,     
  0b00001100, 0b00000000, 0b00110000,
  0b00001100, 0b00000000, 0b00110000,
  0b00001100, 0b00000000, 0b00110000,
  0b00001100, 0b00000000, 0b00110000,
};
int frame7[0x0F] = {                    //Frame 0
  0b00000110, 0b00000000, 0b01100000,     
  0b00000110, 0b00000000, 0b01100000,
  0b00000110, 0b00000000, 0b01100000,
  0b00000110, 0b00000000, 0b01100000,
  0b00000110, 0b00000000, 0b01100000,
};
int frame8[0x0F] = {                    //Frame 0
  0b00000011, 0b00000000, 0b11000000,     
  0b00000011, 0b00000000, 0b11000000,
  0b00000011, 0b00000000, 0b11000000,
  0b00000011, 0b00000000, 0b11000000,
  0b00000011, 0b00000000, 0b11000000,
};
int frame9[0x0F] = {
  0b00000011, 0b11000011, 0b11000000,     //Frame 9
  0b00000011, 0b11000011, 0b11000000,
  0b00000011, 0b11000011, 0b11000000,
  0b00000011, 0b11000011, 0b11000000,
  0b00000011, 0b11000011, 0b11000000,
};
int frame10[0x0F] = {
  0b00000000, 0b00111100, 0b00000000,     //Frame 10
  0b00000000, 0b00111100, 0b00000000,
  0b00000000, 0b00111100, 0b00000000,
  0b00000000, 0b00111100, 0b00000000,
  0b00000000, 0b00111100, 0b00000000,
};
int frame11[0x0F] = {
  0b00000000, 0b00011000, 0b00000000,     //Frame 11
  0b00000000, 0b00011000, 0b00000000,
  0b00000000, 0b00011000, 0b00000000,
  0b00000000, 0b00011000, 0b00000000,
  0b00000000, 0b00011000, 0b00000000,
};
int frame12[0x0F] = {
  0b00000000, 0b00010000, 0b00000000,     
  0b00000000, 0b00101000, 0b00000000,
  0b00000000, 0b01000100, 0b00000000,
  0b00000000, 0b00101000, 0b00000000,
  0b00000000, 0b00010000, 0b00000000,
};
int frame13[0x0F] = {
  0b00000000, 0b00101000, 0b00000000,     
  0b00000000, 0b01000100, 0b00000000,
  0b00000000, 0b10000010, 0b00000000,
  0b00000000, 0b01000100, 0b00000000,
  0b00000000, 0b00101000, 0b00000000,
};
int frame14[0x0F] = {
  0b00000000, 0b01000010, 0b00000000,     
  0b00000000, 0b10000001, 0b00000000,
  0b00000001, 0b00000000, 0b10000000,
  0b00000000, 0b10000001, 0b00000000,
  0b00000000, 0b01000010, 0b00000000,
};
int frame15[0x0F] = {
  0b00000000, 0b01000010, 0b00000000,     
  0b00000000, 0b10000001, 0b00000000,
  0b00000001, 0b00000000, 0b10000000,
  0b00000000, 0b10000001, 0b00000000,
  0b00000000, 0b01000010, 0b00000000,
};
int frame16[0x0F] = {
  0b00000000, 0b11000011, 0b00000000,     
  0b00000001, 0b10000001, 0b10000000,
  0b00000011, 0b00000000, 0b11000000,
  0b00000001, 0b10000001, 0b10000000,
  0b00000000, 0b11000011, 0b00000000,
};
int frame17[0x0F] = {
  0b00000011, 0b00000000, 0b11000000,     
  0b00000110, 0b00000000, 0b01100000,
  0b00001100, 0b00000000, 0b00110000,
  0b00000110, 0b00000000, 0b01100000,
  0b00000011, 0b00000000, 0b11000000,
};
int frame18[0x0F] = {
  0b00000110, 0b00000000, 0b01100000,     
  0b00001100, 0b00000000, 0b00110000,
  0b00011000, 0b00000000, 0b00011000,
  0b00001100, 0b00000000, 0b00110000,
  0b00000110, 0b00000000, 0b01100000,
};
int frame19[0x0F] = {
  0b00001100, 0b00000000, 0b00110000,     
  0b00011000, 0b00000000, 0b00011000,
  0b00110000, 0b00000000, 0b00001100,
  0b00011000, 0b00000000, 0b00011000,
  0b00001100, 0b00000000, 0b00110000,
};
int frame20[0x0F] = {
  0b00011000, 0b00000000, 0b00011000,     
  0b00110000, 0b00000000, 0b00001100,
  0b01100000, 0b00000000, 0b00000110,
  0b00110000, 0b00000000, 0b00001100,
  0b00011000, 0b00000000, 0b00011000,
};
int frame21[0x0F] = {
  0b00110000, 0b00000000, 0b00001100,     
  0b01100000, 0b00000000, 0b00000110,
  0b11000000, 0b00000000, 0b00000011,
  0b01100000, 0b00000000, 0b00000110,
  0b00110000, 0b00000000, 0b00001100,
};
int frame22[0x0F] = {
  0b11100111, 0b10111101, 0b00010000,     //Frame 22
  0b10010100, 0b00100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b00100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
};
int frame23[0x0F] = {
  0b00011000, 0b01000010, 0b11101111,     //Frame 22
  0b01101011, 0b11011010, 0b01001111,
  0b00011000, 0b01000010, 0b10101111,
  0b01101011, 0b11011010, 0b11101111,
  0b00011000, 0b01011010, 0b11101111,
};
int frame24[0x0F] = {
  0b11100111, 0b10111101, 0b00010000,     //Frame 22
  0b10010100, 0b10100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b10100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
};
int frame25[0x0F] = {
  0b00011000, 0b01000010, 0b11101111,     //Frame 22
  0b01101011, 0b11011010, 0b01001111,
  0b00011000, 0b01000010, 0b10101111,
  0b01101011, 0b11011010, 0b11101111,
  0b00011000, 0b01011010, 0b11101111,
};
int frame26[0x0F] = {
  0b11100111, 0b10111101, 0b00010000,     //Frame 22
  0b10010100, 0b10100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b10100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
};
int frame27[0x0F] = {
  0b00011000, 0b01000010, 0b11101111,     //Frame 22
  0b01101011, 0b11011010, 0b01001111,
  0b00011000, 0b01000010, 0b10101111,
  0b01101011, 0b11011010, 0b11101111,
  0b00011000, 0b01011010, 0b11101111,
};
int frame28[0x0F] = {
  0b11100111, 0b10111101, 0b00010000,     //Frame 22
  0b10010100, 0b10100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b10100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
};
int frame29[0x0F] = {
  0b00011000, 0b01000010, 0b11101111,     //Frame 22
  0b01101011, 0b11011010, 0b01001111,
  0b00011000, 0b01000010, 0b10101111,
  0b01101011, 0b11011010, 0b11101111,
  0b00011000, 0b01011010, 0b11101111,
};
int frame30[0x0F] = {
  0b11100111, 0b10111101, 0b00010000,     //Frame 22
  0b10010100, 0b10100101, 0b10110000,
  0b11100111, 0b10111101, 0b01010000,
  0b10010100, 0b10100101, 0b00010000,
  0b11100111, 0b10100101, 0b00010000,
};
int frame31[0x0F] = {
  0b11111111, 0b11111111, 0b11111111,     //Frame 31
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b11111111, 0b11111111, 0b11111111,
};
int frame32[0x0F] = {
  0b00000000, 0b00000000, 0b00000000,     //Frame 32
  0b11111111, 0b11111111, 0b11111111,
  0b00000000, 0b00000000, 0b00000000,
  0b11111111, 0b11111111, 0b11111111,
  0b00000000, 0b00000000, 0b00000000,
};
int frame33[0x0F] = {
  0b00000000, 0b00000000, 0b00000000,     //Frame 33
  0b00000000, 0b00000000, 0b00000000,
  0b11111111, 0b11111111, 0b11111111,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
};
int frame34[0x0F] = {
  0b00000000, 0b00000000, 0b00000000,     //Frame 34
  0b00000000, 0b00000000, 0b00000000,
  0b00011111, 0b11111111, 0b11111000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
};
int frame35[0x0F] = {
  0b00000000, 0b00000000, 0b00000000,     //Frame 35
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
  0b00000000, 0b00000000, 0b00000000,
};


int * frameList[36]= {&frame0[0],
                          &frame1[0],
                          &frame2[0],
                          &frame3[0],
                          &frame4[0],
                          &frame5[0],
                          &frame6[0],
                          &frame7[0],
                          &frame8[0],
                          &frame9[0],
                          &frame10[0],
                          &frame11[0],
                          &frame12[0],
                          &frame13[0],
                          &frame14[0],
                          &frame15[0],
                          &frame16[0],
                          &frame17[0],
                          &frame18[0],
                          &frame19[0],
                          &frame20[0],
                          &frame21[0],
                          &frame22[0],
                          &frame23[0],
                          &frame24[0],
                          &frame25[0],
                          &frame26[0],
                          &frame27[0],
                          &frame28[0],
                          &frame29[0],
                          &frame30[0],
                          &frame31[0],
                          &frame32[0],
                          &frame33[0],
                          &frame34[0],
                          &frame35[0]
                          };

Can you post a link to the library you are using?

Libary: https://github.com/hoverlabs/beam_particle

This part in beam.cpp needs extending to cater for the extra characters

      asciiVal = toupper(text[i]);
      if (asciiVal == 32){
        fontptr = &charactermap[0][0];   //set fontptr to matching font
      } else {
        fontptr = &charactermap[(asciiVal-32)][0];   //set fontptr to matching font
      }

although this logic isn’t too safe to start with :wink:

I’d change this to something like

      asciiVal = toupper(text[i]);
      if ( 32 <= asciiVal && asciiVal <= 64 ) {
        fontptr = &charactermap[(asciiVal-32)][0];   //set fontptr to matching font
      }
      else {
        switch(asciiVal) {
          case 'Ä':
            fontptr = &charactermap[65][0];
            break;
          case 'Ö':
            fontptr = &charactermap[66][0];
            break;
          case 'Ü':
            fontptr = &charactermap[67][0];
            break;
          case 'ß':
            fontptr = &charactermap[(68)][0];
            break;
          default:
            fontptr = &charactermap[0][0];
            break;
        }
      }

BTW, ' isn’t actually index 66 but only 64, hence my check goes for 64 and ‘Ä’ will be found at 65.