My most recent impulse buy for 20 € was a 
txtr Beagle. It's an ultra-simple e-ink reader
which can't even do rendering by itself, you have to connect it to an Android smartphone via Bluetooth and the phone will convert the whole book
into a stack of bitmaps and push it over the link.
While this is rather unimpressive if you look at it as an e-reader (although it's fairly light and small), I'm looking at it as a Bluetooth-enabled e-paper display, e.g. as an electronic door sign.
Consequently, I needed to figure out how to push content to the device without having to rely on the Android companion app. Apparently, somebody called Ligius had a similar idea and took the whole thing apart:
txtr Beagle teardown
txtr Beagle - Part two - software 
txtr Beagle - part 3 - storage and transfer protocol
Before I was pointed to this blog, I did something very similar to the second post: pull the companion app from my phone with ES3 Explorer, run the APK file through 
dex2jar and
decompile it using 
jd-gui. Look for a class called 
BeagleDevice, which is where the device connection is handled. In fact, most of the information in this class can
already be discovered by just viewing the regular Android debug log (run 
adb logcat on a connected computer), the app is positively chatty and will log all communication with the device.
Side note: to find out some more details about the protocol, I ran an RFCOMM server on my laptop, changed the laptop's Bluetooth name to "Beagle" and let the Android app connect to that fake device. Somewhat to my surprise, this
worked and resulted in a series of gzip-compressed 4-bit images being transferred to my laptop. This is also visible somewhere in the debug log, there's a function 
convertToZipped4bpp or similar.
However, there's one snag: you can decompress these pages using regular 
gunzip, but if you re-compress new pages with 
gzip and send them back to the device, it crashes. After some more digging, I discovered that the conversion
function was located in a native library (probably for speed reasons) and that it indeed uses plain gzip compression created by zlib, but with custom initialization parameters (calls 
deflateInit2 instead of 
deflateInit). The native
function which actually performs the compression is called 
compress2K, so I just guessed that the window size is 2K. I took the zlib sample code, changed the init code to use a 2K window and was able to get a compressed page which
was byte-by-byte identical to the original one.
I've thrown the resulting mess of tools on Github: 
floe/opentxtr. Hope you find it useful - I won't be able to do a lot more for the foreseaable future, but I'd be happy about pull requests.
In particular, the 
UTILITYPAGE command looks like it might be helpful. Also, it's not yet clear what 
OPTION and 
VCOM do...
Update: Ligius has 
extracted the content of the internal SD card and wrote a Java program to analyze it. And you can indeed use 
UTILITYPAGE to update, e.g., the cover page!