GB music events and track position updating

Posted on
  • I made an attempt at a music control app that shows a track position timer, but it has an issue with the track position timer not always resetting to zero when it's receiving the messages from gadgetbridge for a new song. For the last few days I've been trying to figure out how to get it to reset properly when a new song comes on, but it's been a struggle. Since it uses the boot file to receive the GB messages I need to write to storage every time I make a change and want to test it and I haven't found a way to have the console up when connected to GB.

    Also, it is a bit of a battery hog. Either that or it's just from me writing to flash repeatedly, but when using this app my battery does go down pretty fast, it does try to refresh the scrolling text at about 30fps right now which I'm sure doesn't help battery life.

    Anyway, I would appreciate any thoughts or suggestions. Thanks

  • I haven't merged it into my master branch yet, but you can see the code by switching to the music_player branch.

  • I haven't found a way to have the console up when connected to GB.

    Instead of connecting to GB, you could send fake messages manually in the console:

    GB({"t":"musicinfo","artist":"Some Artist Name","album":"The Album Name","track":"The Track Title Goes Here","dur":241,"c":2,"n":2})
  • Hi rigrig, I did use fake messages to test and those do work. Sometimes it will actually reset the position to zero with the way the code is now, other times it won't. It's not consistent so it's very difficult for me to pinpoint where the problem is coming from. I'm going to do some more digging in the gadgetbridge log and see if I can decipher how the messages are being sent and when. Thanks for your suggestion.

  • A seekbar sounds kind of nice!

    Somewhat adjacent to this I've been thinking I'd like it if my bangle knew the different audio levels of my android device. E.g. media, ring or alarm volume.

    Once that was in place there could be a library for drawing interactive sliders that sync with the corresponding levels on the android device.

  • That's a great idea! Like you mentioned, this sort of volume syncing is already built into android for bluetooth speakers and such so we should be able to just make it compatible with that.

    I made a few changes to my program, but I haven't figured it out yet. I did write a little helper file to simply log the music messages from gadgetbridge onto the display with timestamps. It seems to send twice as many messages as normal so I'm thinking maybe this is the cause of my problem?

    let lines = [];
    function breakIntoLines(str, maxWidth) {
      let chunks = str.split(','); // Split by commas
      let lines = [];
      let currentLine = "";
      chunks.forEach(chunk => {
        let words = chunk.trim().split(' '); // Split by spaces
        words.forEach((word, idx) => {
          let separator = idx === 0 ? "" : " ";
          let newContent = (currentLine.length > 0 ? separator : '') + word;
          if (g.stringWidth(currentLine + newContent) <= maxWidth) {
            currentLine += newContent;
          } else {
            if (currentLine.length > 0) {
            currentLine = word;
        currentLine += ',';
      if (currentLine.length > 0) {
      return lines;
    function breakWord(word, maxWidth) {
      let brokenLines = [];
      let currentLine = "";
      for (let char of word) {
        if (g.stringWidth(currentLine + char) <= maxWidth) {
          currentLine += char;
        } else {
          currentLine = char;
      if (currentLine.length > 0) {
      return brokenLines;
    function renderLines() {
      let y = 0;
      lines.forEach((line, index) => {
        let sublines = breakIntoLines(line, g.getWidth() - 5);
        sublines.forEach(subline => {
          // calculate next Y position before drawing
          let nextY = y + g.getFontHeight();
          // if next Y position is outside of screen, remove oldest line
          if (nextY > g.getHeight()) {
            return; // Skip the current iteration
          g.drawString(subline, 0, y);
          y = nextY;
    function formatTimestamp() {
      const date = new Date();
      return `[${date.getHours().toString().padStart(­2, '0')}:${date.getMinutes().toString().pad­Start(2, '0')}:${date.getSeconds().toString().pad­Start(2, '0')}.${date.getMilliseconds().toString(­).padStart(3, '0')}]`;
    function handleGadgetbridgeMessage(msg) {
      if (msg.t === 'musicstate' || msg.t === 'musicinfo') {
        let info = formatTimestamp() +
          (msg.state !== undefined ? ' ' + msg.state + ',' : '') +
          (msg.position !== undefined ? ' ' + msg.position : '') +
          (msg.track !== undefined ? ' ' + msg.track + ',' : '') +
          (msg.artist !== undefined ? ' ' + msg.artist + ',' : '') +
          (msg.album !== undefined ? ' ' + msg.album + ',' : '') +
          (msg.dur !== undefined ? ' ' + msg.dur : '');
        lines.unshift(info); // Add the info at the beginning of the array
        renderLines();  // Draw lines after every new message
  • I took a screenshot of my makeshift log from the bangle 😂 (Hey, whatever works! Right?)

    It actually looks a little different than what I'm currently seeing in my music program, somehow it's sending the duration of the new song as the new current position when the new song comes on whereas in my music program it continues counting from the last songs duration. That kind of explains why it's so hard for me to get it to reset properly.

    A little more context - The song Mercy was playing first and had a duration of 290. The duration ran out on its own and the phone changed to the next song on its own causing the messages above [13:12:49.424] to start being sent, but with the wrong position data. And twice, once with the old album info!

    1 Attachment

  • I haven't found a way to have the console up when connected to GB.

    That is achievable with the new remote connection between the App Loader and the Web IDE. Reference this commet:­/385629/?offset=25#17003042

    Also reference this conversation where @Gordon introduced the new remote connections:­/386264/

  • I did already see that actually. This would be a perfect use case scenario for having both the GB connection and the web IDE console. Unfortunately that option doesn't show up for me in the gadgetbridge app loader, possibly because I'm using the beta version from the play store. At least my music event logging program seems to accomplish the same thing.

    In this post Gordon says:

    Connections from Gadgetbridge are now live! In Gadgetbridge, go to the
    App Loader (3x3 squares icon below the device name) then tap More...
    and Web IDE Remote.

    My "More..." screen in the app loader looks like this:

    1 Attachment

    • Screenshot_2023-06-07-21-08-31-88.jpg
  • Do you maybe have .../index.html instead of .../android.html in your URL config for the apploader?

  • I was always just leaving mine blank at the end of my url.

    Adding .../android.html fixed it and now the Web IDE Remote option shows up. Thanks!

    This should help me figure out the track position not resetting properly.

  • @stweedo I've also been working on this and just rediscovered this conversation. If you'd want to check out what I've done it's in this draft PR. While developing my slider module I've been updating 'Remote for Spotify' along side it to do basically what you talked about here.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

GB music events and track position updating

Posted by Avatar for stweedo @stweedo