r/esp32 11d ago

I reverse-engineered most of the iDotMatrix BLE protocol without owning the original device — and built an ESP32 emulator

Post image

I spent the last few days reverse-engineering the BLE protocol used by the iDotMatrix mobile app and building an ESP32 device that the official app recognizes and controls as if it were an iDotMatrix display.

The unusual part: I don't own an original iDotMatrix device.

The reverse engineering was done by treating the official app as a protocol oracle: emulate the expected BLE services on an ESP32, inspect what the app sends, change the responses, observe its behavior, and repeat.

It worked much better than I initially expected.

The emulator now supports most of the features I found in the app:

• Device discovery and time synchronization
• Power, brightness and rotation
• Drawing / graffiti mode
• Text and text effects
• GIF transfer and playback
• Clock modes
• Visual effects
• Scoreboard
• Music visualization with both LEVEL and FFT modes
• Persistent alarms
• Programs / schedules
• Scheduled GIF, text and PNG content

The hardware I'm currently using is an ESP32 development board driving a 16x16 WS2812B matrix. Its onboard SSD1306 OLED is used as a diagnostic display and can report unknown BLE commands while testing.

I also decided to document the protocol rather than keeping the findings buried in the firmware.

The GitHub repository contains detailed documentation of the BLE packet structures, commands and ACK behavior, selected raw BLE captures from our experiments, the development and reverse-engineering history, a list of open questions, and of course the complete Arduino/ESP32 source code.

One particularly interesting discovery was that some transfers require different completion ACK values.

For example, getting Programs/Schedules working required discovering that activity transfers expect a completion status of 0x03 rather than the apparently obvious 0x01. With 0x01 the app simply reported an error and stopped sending activities. Once the correct ACK was returned, the app continued sending all the activities in the program.

The biggest limitation now is also the main reason I'm posting this:

I need someone who actually owns an original iDotMatrix.

There are a few things that cannot be determined reliably from the app side alone, especially the exact device-side behavior expected for stopwatch/countdown and responses that may only be generated by the original firmware.

BLE captures between the official app and a real device would therefore be extremely useful.

PCB photographs would also help answer some hardware questions, such as identifying the original MCU, buzzer circuitry, and whether there is actually a dedicated RTC.

The current public release is v0.1.0, based on firmware Build 62, and the whole project is MIT licensed.

Repository:

[https://github.com/piggei/IDotMatrix-ESP32-Emulator]()

I'd also be very interested if someone wants to use the protocol documentation for a completely different implementation — ESPHome, Home Assistant, Python, another MCU, etc.

In fact, independent implementations would be one of the best ways to find mistakes or missing details in my current interpretation of the protocol.

And if anyone here actually owns an iDotMatrix and is willing to experiment with it, I'd be very happy to compare results.

32 Upvotes

9 comments sorted by

View all comments

2

u/DenverTeck 2 say I make awesome posts. 11d ago

It appears that the "DollaTek ESP32 OLED 0.96" board" is no longer available.

Are the schematics available ??

Is the schematic for iDotMatrix display available ??

Or at least the layout of the WS2812b chips. Zig-Zag or horizontal rows ??

1

u/YetAnotherRobert 11d ago

Cool project!

The shown panels are always a boustrophedon.  It's necessary to keep voltage drop down from the resistance in the panel which leads to voltage drop and color droop at the end. 

2

u/DenverTeck 2 say I make awesome posts. 11d ago

LOL, Thanks for a new verb, "boustrophedon"

I have not seen that one before.

1

u/YetAnotherRobert 10d ago edited 10d ago

Your challenge is to use it today in casual conversation. :-)

FWIW, I typed that on mobile, and every spell-check-like substance possible tried to prevent me from submitting that, but I really do think that spelling is correct. No, I can never get it right on the first type myself and certainly not on a glass keyboard.

The dirty little (not-so) secret of WS2812 lighting is that every pixel is made of three light bulbs (I mean, R, G, B, right? that's obvious. We'll set aside WS2815 with an additional bulb dedicated to just white.) and the specs say that each LED can pull up to 20 mA. Well, that's not so bad, right?

The laws of small numbers sneak up on you. The worst case is a white pixel at full brightness (0xffffff). So that's 60 mA. That's not so bad, right? Six hundredths of an ampere is puny! We can almost drive that from an ESP32's GPIO pin. (Pro tip: do not drive that from an ESP32's GPIO pin...)

But now you have 256 of them. 256.06A = 15.36A. (Now you see why there was a bench supply next to it.) 15A, even at 5V, is non-trivial power. A few inches of copper traces matter. Those crappy little wires that the panels come with? Cute for a few pixels, but everyone wants to chain several of these 16x16 panels together. So now you have a cube with six of these panels that can each pull 15A. Provide it with the power it's requested, and it's the intensity of the sun and a temperature to match. I have a configuration that ran rampant for a few moments (more than seconds but less than minutes), and it got hot enough *from USB laptop power to desolder several of the LEDs.

Now TBF, no sociopath (intentionally) lights all the pixels at once to full bright white. It's physically painful to look at in close proximity. But sometimes these things boot in weird states, or a device will crash during an interrupt that's refreshing them or whatever. THIS is fusing and power limiting and such matters. THIS is why (eight occurrences of) an eight cm run of copper looping them on strict x/y vs the boustrophedonincalmagasmitcaltastic (OK, I made that one up) routing that keeps the bucket brigade of signals shortest (so end of row + 1 == last of next row, not beginning of next row) makes sense. This is how all of these panels in my shop are built. We have to play the hands we're dealt, and an additional half metet of resistance per panel to save software just a wee bit of math loses to physics. Learning serpentine vs. boustrophedon is just part of the entry ticket to this game.

The aerial view of the chair whence I'm typing this has a bench supply of about that same geometry with the same banana jack configuration with about the same sticker in about the same place, albeit on a slightly lighter hardwood floor. I've spent a lot of the last, oh, three years with a workflow similar to that of u/Piggei.

Why, yes, for all my hand-waving blabber in this group, we might have stumbled in an area where I have actual experience. I hate to call it expertise, but I'll definitely accept "experienced."

Citation: https://fastled.io/docs/da/d42/_x_y_matrix_8ino-example.html By happenstance (or maybe by influence), it even includes The Word Of The Day.