Partial Home Assistant Control of Mr. Robot Badge Mk. 2

Once I had Mr Robot Badge Mk. 2 up and running on Arduino, I thought: what about Home Assistant? After all, ESPHome is built on compiling ESP8266 Arduino Core code using PlatformIO command-line tools. The challenging part of ESPHome is always that initial firmware flash, which I’m already set up to do, and after that I could do updates wirelessly.

I started easy: getting badge buttons to be recognized as binary sensors in Home Assistant.

binary_sensor:
  - platform: gpio
    pin:
      number: 0
      mode:
        input: true
        pullup: true
      inverted: true
    name: "Left"
    filters:
      - delayed_on_off: 20ms
  - platform: gpio
    pin:
      number: 16
      mode:
        input: true
      inverted: true
    name: "Down"
    filters:
      - delayed_on_off: 20ms
  - platform: gpio
    pin:
      number: 15
      mode:
        input: true
        pullup: true
    name: "Right"
    filters:
      - delayed_on_off: 20ms
  - platform: gpio
    pin:
      number: 13
      mode:
        input: true
        pullup: true
      inverted: true
    name: "Up"
    filters:
      - delayed_on_off: 20ms
  - platform: gpio
    pin:
      number: 12
      mode:
        input: true
        pullup: true
      inverted: true
    name: "A"
    filters:
      - delayed_on_off: 20ms
  - platform: gpio
    pin:
      number: 14
      mode:
        input: true
        pullup: true
      inverted: true
    name: "B"
    filters:
      - delayed_on_off: 20ms

Piece of cake! Now on to the more interesting (and more challenging) part: using the LEDs. I followed ESPHome examples to create a custom component. This exposed a single custom output that treated the entire array as a single color (monochromatic) dimmable light.

C header file with custom class declaration:

#include "esphome.h"
#include "Adafruit_IS31FL3741.h"
using namespace esphome;

class MrRobotBadgeFloatOutput : public Component, public FloatOutput
{
    Adafruit_IS31FL3741 ledArray;

    public:
        void setup() override
        {
            ledArray.begin();
            ledArray.setLEDscaling(0x3F); // 25% of max
            ledArray.setGlobalCurrent(0x3F); // 25% of max
            ledArray.enable(true);  // bring out of shutdown
        }

        void write_state(float state) override
        {
            int8_t value = state * 128; // 50% of max
            ledArray.fill(value);
        }
};

YAML:

output:
  - platform: custom
    type: float
    lambda: |-
      auto badge_float = new MrRobotBadgeFloatOutput();
      App.register_component(badge_float);
      return {badge_float};
    outputs:
      id: badge_float

light:
  - platform: monochromatic
    name: "Badge Lights"
    output: badge_float

Tada! I’m back at the same test I had using Arduino, lighting up all the pixels to highlight problematic LEDs.

The next step in this progression is to expose the entire 18×18 array as individually addressable pixels. Doing so would allow using ESPHome’s display rendering engine to draw text and graphics, much as Adafruit GFX does. I found the Addressable Light base class but I got stuck trying to make it happen. I’ve had no luck finding examples on how to implement a custom addressable light, and didn’t get much of anywhere bumping my head in the dark. Digging through existing Addressable Light implementations on GitHub, I’ve found many object classes that may or may not be required to implement my own addressable light.

I imagine there’s an architecture diagram somewhere that describes how these components interact, but my search has come up empty so far and there’s not much in the way of code comments. Most of the online discussions about addressable LED pixels in Home Assistant are centered around WLED, which as of this writing does not support the IS31LF3741 control chip. I’m going to put further exploration on hold until I have more experience with ESPHome custom components to understand their object hierarchy.

Programming Mr Robot Badge Mk. 2 with Arduino

This particular Mr. Robot Badge Mk. 2 was deemed a defective unit with several dark LEDs. I used it as a practice subject for working with surface-mounted electronic devices, bringing two LEDs back into running order though one of them is the wrong color. Is the badge fully repaired? I couldn’t quite tell. The default firmware is big on blinking and flashing patterns, making it difficult to determine if a specific LED is functioning or not. What I needed was a test pattern, something as simple as illuminate all of the LEDs to see if they come up. Fortunately, there was a URL right on the badge that took me to a GitHub repository with sample code and instructions. It used Arduino framework to generate code for this ESP8266, and that’s something I’ve worked with. I think we’re in business.

On the hardware side, I soldered sockets to the unpopulated programmer header and then created a programming cable to connect to my FTDI serial adapter (*). For the software, I cloned the “Starter Pack” repository, followed installation directions, and encountered a build failure:

Arduino\libraries\Brzo_I2C\src\brzo_i2c.c: In function 'brzo_i2c_write':
Arduino\libraries\Brzo_I2C\src\brzo_i2c.c:72:2: error: cannot find a register in class 'RL_REGS' while reloading 'asm'
   72 |  asm volatile (
      |  ^~~
Arduino\libraries\Brzo_I2C\src\brzo_i2c.c:72:2: error: 'asm' operand has impossible constraints
exit status 1
Error compiling for board Generic ESP8266 Module.

This looks like issue #44 in the Brzo library, unfixed at time of this writing. Hmm, this is a problem. Reading the code some more, I learned Brzo is used to create I2C communication routines with the IS31FL3741 driver chip controlling the LED array. Aha, there’s a relatively easy solution. Since the time the badge was created, Adafruit has released a product using the same LED driver chip and corresponding software libraries to go with it. I could remove this custom I2C communication code using Brzo and replace it with Adafruit’s library.

Most of the conversion was straightforward except for the LED pixel coordinate lookup. The IS31Fl3741 chip treats the LEDs as a linear array, and something had to translate the linear index to their X,Y coordinates. The badge example code has a lookup table mapping linear index to X,Y coordinates. To use Adafruit library’s frame buffer, I needed the reverse: a table that converts X,Y coordinates to linear index. I started typing it up by hand before deciding that was stupid: this is the kind of task we use computers for. So I wrote this piece of quick-and-dirty code to cycle through the existing lookup table and print the information back out organized by X,Y coordinates.


      for(uint8_t x = 0; x < 18; x++)
      {
        for(uint8_t y = 0; y < 18; y++)
        {
          reverseLookup[x][y]=-1;
        }
      }
      for(uint8_t i = 0; i < PAGE_0_SZ; i++)
      {
        reverseLookup[page0LUT[i].x][page0LUT[i].y] = i;
      }
      for(uint16_t i = 0; i < PAGE_1_SZ; i++)
      {
        // Unused locations were marked with (-1, -1) but x and y are
        // declared as unsigned which means -1 is actually 0xFF so
        // instead of checking for >0 we check for <18
        if(page1LUT[i].x < 18 && page1LUT[i].y < 18)
        {
          reverseLookup[page1LUT[i].x][page1LUT[i].y] = i+PAGE_0_SZ;
        }
      }
      for(uint8_t y = 0; y < 18; y++)
      {
        Serial.print("{");
        for(uint8_t x = 0; x < 18; x++)
        {
          Serial.print(reverseLookup[x][y]);
          if (x<17)
          {
            Serial.print(",");
          }
        }
        if (y<17)
        {
          Serial.println("},");
        }
        else
        {
          Serial.println("}");
        }
      }

This gave me the numbers I needed in Arduino serial monitor, and I could copy it from there. Some spacing adjustment to make things a little more readable, and we have this:

const uint16_t Lookup[ARRAY_HEIGHT][ARRAY_WIDTH] = {
  {  17,  47,  77, 107, 137, 167, 197, 227, 257,  18,  48,  78, 108, 138, 168, 198, 228, 258},
  {  16,  46,  76, 106, 136, 166, 196, 226, 256,  19,  49,  79, 109, 139, 169, 199, 229, 259},
  {  15,  45,  75, 105, 135, 165, 195, 225, 255,  20,  50,  80, 110, 140, 170, 200, 230, 260},
  {  14,  44,  74, 104, 134, 164, 194, 224, 254,  21,  51,  81, 111, 141, 171, 201, 231, 261},
  {  13,  43,  73, 103, 133, 163, 193, 223, 253,  22,  52,  82, 112, 142, 172, 202, 232, 262},
  {  12,  42,  72, 102, 132, 162, 192, 222, 252,  23,  53,  83, 113, 143, 173, 203, 233, 263},
  {  11,  41,  71, 101, 131, 161, 191, 221, 251,  24,  54,  84, 114, 144, 174, 204, 234, 264},
  {  10,  40,  70, 100, 130, 160, 190, 220, 250,  25,  55,  85, 115, 145, 175, 205, 235, 265},
  {   9,  39,  69,  99, 129, 159, 189, 219, 249,  26,  56,  86, 116, 146, 176, 206, 236, 266},
  {   8,  38,  68,  98, 128, 158, 188, 218, 248,  27,  57,  87, 117, 147, 177, 207, 237, 267},
  {   7,  37,  67,  97, 127, 157, 187, 217, 247,  28,  58,  88, 118, 148, 178, 208, 238, 268},
  {   6,  36,  66,  96, 126, 156, 186, 216, 246,  29,  59,  89, 119, 149, 179, 209, 239, 269},
  {   5,  35,  65,  95, 125, 155, 185, 215, 245, 270, 279, 288, 297, 306, 315, 324, 333, 342},
  {   4,  34,  64,  94, 124, 154, 184, 214, 244, 271, 280, 289, 298, 307, 316, 325, 334, 343},
  {   3,  33,  63,  93, 123, 153, 183, 213, 243, 272, 281, 290, 299, 308, 317, 326, 335, 344},
  {   2,  32,  62,  92, 122, 152, 182, 212, 242, 273, 282, 291, 300, 309, 318, 327, 336, 345},
  {   1,  31,  61,  91, 121, 151, 181, 211, 241, 274, 283, 292, 301, 310, 319, 328, 337, 346},
  {   0,  30,  60,  90, 120, 150, 180, 210, 240, 275, 284, 293, 302, 311, 320, 329, 338, 347}
};

This lookup table got Mr. Robot Badge Mk. 2 up and running without Brzo library! I could write that simple “turn on all LED” test I wanted.

The test exposed two more problematic LEDs. One of them was intermittent: I tapped it and it illuminated for this picture. If it starts flickering again, I’ll give it a dab of solder to see if that helps. The other one is dark and stayed dark through (unscientific) tapping and (scientific) LED test equipment. It looks like I need to find two more surface-mount red LEDs to fully repair this array.

In case anybody else wants to play with Mr. Robot Badge and runs into the same problem, I have collected my changes and updated the README installation instructions in pull request #3 of the badge code sample repository. If that PR rejected, clone my fork directly.


(*) Disclosure: As an Amazon Associate I earn from qualifying purchases.

Surface Mount Repair Practice with Mr. Robot Badge

Years ago at a past Hackaday Superconference, I had the chance to play with a small batch of “Mr. Robot Badge” that were deemed defective for one reason or another. After a long story that isn’t relevant right now, I eventually ended up with a single unit from that batch with (at least) two dark LEDs in its 18×18=324 array of LEDs. I thought trying to fix it would be a good practice exercise for working with surface-mount electronics, and set it aside for later. I unearthed it again during a recent workshop cleanup and decided it was a good time to check my current surface mount skill level.

I’m missing a few tools that I thought would be useful, like a heat plate or hot air rework station. And while my skills are better than they were when I was originally gifted with the badge, it’s still far from “skilled” at surface mount stuff. (SMD for surface-mount devices, or SMT for surface-mount technology.) One relatively new tool is a dedicated LED tester, and I used it to probe the two dark LEDs. One of them would illuminate with the test probe in place, and a dab of solder was enough to make proper electrical connection and bring it to life. The other one stayed dark even with test probe and would need to be replaced.

Looking in my pile of electronics for a suitable doner, I picked out my ESP32 dev module with a flawed voltage regulator that went up in smoke with 13V DC input (when it should have been able to handle up to 15V DC). This module has a red LED for power and a blue LED for status. I probed the red LED and found it dead, but the blue LED lit up fine. Between “keep looking for a red LED” and “use the blue one in my hand” I chose the latter out of laziness. This is a practice exercise with low odds of success anyway.

Lacking a hot air rework station or a hot plate, I didn’t have a good way to heat up both sides of a LED so there was a lot of clumsy application of solder and flux as I worked to remove the dead badge LED. It came apart in two pieces, so I practiced removal again with the dead red LED on my ESP32 dev module. Once I removed it intact, I tossed it aside and used my newfound (ha!) skill to successfully remove the blue LED in one piece. I might be getting the hang of this? Every LED removal was easier than the last, but I still think a hot air station would make this easier. After I cleaned up the badge LED pads, I was able to solder one side of the salvaged LED then the other. I could see a little bit of green on one side of the LED indicating polarity, so I lined it up to be consistent with the rest of the LEDs on the badge.

I turned on the badge and… the LED stayed dark. It then occurred to me I should have verified the polarity of the LED. Pulling out the LED tester again I confirmed I have soldered it on backwards. Valuable lesson: LED manufacturers are not consistent about how they used the little bit of green on a LED to indicate polarity. So now I get to practice LED removal once again, followed by soldering it back on the correct way. I would not have been surprised if the blue LED had failed after all this gross abuse. On the upside a failure would motivate me to go find another red LED somewhere.

Here is a closeup of the problematic area on the badge. The circle on the right was the LED that just needed a bit of solder for proper contact. The circle on the left represents the scorched disaster zone that resulted from SMT rework amateur hour as I unsoldered and resoldered multiple times. The little blue LED clung on to life through all this hardship I had inflicted and shone brightly when the badge was turned on. I’ll call that a successful practice session.

[Update: I didn’t originally intend to do anything with the badge beyond soldering practice, but I looked into trying to write my own code to run on the badge and successfully did so.]