Skip to content

Android app for WaveShare passive NFC-powered E-Ink displays, to generate and update content

License

Notifications You must be signed in to change notification settings

mk-fg/nfc-epaper-writer

 
 

Repository files navigation

NFC E-Ink Writer

Android application to generate/process images for and upload to WaveShare Passive NFC-Powered (aka parasitic) E-Paper / E-Ink displays.

Contents:

It's only intended to interact with WaveShare displays through their Android SDK, and unlikely to work with similar displays from any other vendor, unless they are intentionally designed to be compatible.
WaveShare documentation explicitly says "This product is not compatible with Samsung smartphones", but not sure why specifically - could be that it's just their original app that doesn't work on these.
This application requires Android 11+ OS (API level 30 or higher).

Passive NFC E-Paper devices supported by the app are typically intended for commercial usage like shelf labels and product tags, other informational notes, or smaller color ones also seem to be for decorative uses (like a chain/keyfob toy).
Some of the compatible epaper device links: 1.54", 2.13", 2.7", 2.9", 4.2", 7.5", etc.

WaveShare 1.54" Passive NFC-Powered EInk Display, showing an image of car from Initial D anime

WaveShare 2.9" Passive NFC-Powered EInk Display, showing the text "Hello World" with a waving hand emoji at the end

This particular version of the app is a code fork of the original version, written by Joshua Tzucker (in joshuatz/nfc-epaper-writer repository), with fixes/features merged from other forks, aimed to fix some build and UI issues that popped-up when I tried to use it, since first-party WaveShare application straight-up doesn't work on my device.

Alternative URLs for this repository:

Features

Main application screen should contain following elements, top-to-bottom:

  • Screen size selection (in top toolbar, remembered) - determines image size and crop/scaling.

  • Re-upload last-used image box (with preview) - tap to immediately go do that.

  • Select exact image to upload - for pre-made images of exactly right size that don't need any processing.

  • Select/take and crop/scale/dither image - for using camera or image files of any size from any source.

    Cropping dialog will allow to pick part of the image with right aspect ratio for selected screen, which will then be scaled to its size, and converted to 3-color (BWR) image using color dithering (added in DevPika/nfc-epaper-writer-update fork).

  • Create image from any composed text. Supports emojis.

  • Draw image on the phone screen, using JSPaint as WYSIWYG editor.

App should work with all screen sizes supported by WaveShare SDK.

Not sure how well last two sources work, main use-case for mk-fg/nfc-epaper-writer fork is exact image upload - there are plenty of good tools to make/edit images.

Floyd-Steinberg black-white-red (BWR) color dithering (merged from DevPika's fork) used for processing non-exact images might work suboptimally with 1-bit black-and-white displays - also didn't test it much here.

How to build and install this to an Android device

Steps below require any system with modern docker (aka Docker Engine) installed (via e.g. apt install docker on ubuntu/debian linux), any terminal console app available to also run its command-line tools from, ~5 GiB of peak memory and about 3 GiB of disk space temporarily.

  • Copy or download Dockerfile from this repository into any directory.

    Doesn't really matter which dir, it'll only be used to copy build result (apk file) into by "docker build" command below.

    For example, to fetch it using curl from the command line:

    curl -OL https://raw.githubusercontent.com/mk-fg/nfc-epaper-writer/main/Dockerfile
    
  • Build and copy Android application package (APK) to the current directory:

    docker build --output type=local,dest=. .
    

    This will use Dockerfile as a recipe for app-debug.apk and will put it next to that Dockerfile afterwards.

    An older docker setup might give "unknown --output option" error, in which case docker-buildx plugin might be required, and command will be docker buildx build --output type=local,dest=. . instead of the one above.

  • Copy generated app-debug.apk file to an Android device, and open it there (e.g. find and tap on it in Files app). Note that Android 11+ is required for this app, shouldn't work on older devices.

  • Follow Android OS instruction popups from there on how to enable necessary settings to be able to install this tool from a sideloaded APK file.

    This type of app installation from an APK file is called "sideloading", and steps required to allow it change between Android versions, but should be easy to lookup for specific one on the internet, if Android's built-in prompts don't make it clear enough.

  • Installed tool should show up among the usual "application drawer" icons with "NFC E-Ink Writer" name and a generic "android robot head" icon.

Another, more developer-focused option, is to build APK using Android Studio IDE, which might be more or less complicated, depending on one's experience working with such tools/ecosystem (vs command-line steps above) - open the project there, and pick APK option from the Build menu.

Demos

These showcase application version from the original repository and displays packaged separately from the control board.

  • Updating from a local image file:

    Animated GIF showing this application letting a user select a local image file from their gallery, cropping it, and then updating EInk NFC display

  • Updating from typed-in text:

    Animated GIF showing the user being able to input custom text, having the text captured as an image, and then updating EInk NFC Display with resulting image

  • WYSIWYG image creator:

    Animated GIF showing user creating a custom image via WYSIWYG paint editor, having the image captured to bitmap, and then uploading generated bitmap to EInk NFC Display

Known Issues

NFC can be a little finnicky, and especially with these EInk displays. Depending on the power and capabilities of your phone, it may take time perfecting the exact distance and position to hold your phone in proximity to the EInk display in order to get successful updates.

On certain Android phones, you might also see a high rate of your NFC radio / chipset randomly "dying". This happens at a lower level of system APIs, so it is really hard for my application to detect or attempt to recover from.

When detected by the lower-level APIs, Android will throw this as a android.os.DeadObjectException, with the entry: NFC service dead - attempting to recover. You can see the internal recovery efforts here.

Additionally, sometimes you might see corrupted writes, where something goes wrong during the transceiving process and the display ends up with random noise:

Animated GIF showing a failed update, with random noise appearing over previous image

Disabling-enabling NFC on the phone (by tapping its Quick Settings tile at the top) and re-sending the image afterwards works for me to work around the issue. NFC reset is needed because usually it stops working when this happens (like due to problem being "NFC dying" mentioned above), sometimes crashing/restarting the app as well.

Task Backlog

  • Replace "flashing" wording from original app with "update" or "upload", as don't think it's called that in WaveShare docs, and memory is only used as a temp buffer here, so seem to be a wrong/misleading word to use.

  • Better recovery methods for NFC adapter dying.

  • When caching generated image, prefix or suffix with resolution, and then only allow cached image for re-upload if saved resolution matches.

  • App Icon.

  • Publish APK and/or provide better build options.

Technical Details from the original project

(from the original joshuatz/nfc-epaper-writer repository)

Building this project was my first time touching Kotlin, Java, or Android APIs, of which this project uses all three. I opted to go this route (native Android dev) instead of React Native or Flutter, because I knew I was going to need access to a lot of lower level APIs, and saw it as an opportunity to learn some new skills.

This project uses a bunch of different technologies, and takes some interesting "shortcuts":

  • For the custom image generation options - both the text editor or WYSIWYG editor - I used WebView so that I could use HTML + JS + Web Canvas, and pass back the bitmap data to Android.

    • The WYSIWYG editor is actually just JSPaint, but with injected JavaScript for capturing the bitmap data from the app's canvas.

    • The text editor is a custom tiny webpage I put together that renders the text to a Canvas element, and then captures the raw bitmap data.

  • Local image option with processing uses CanHub/Android-Image-Cropper for cropping and resizing.

  • By using scoped storage and the right APIs, no special permissions (other than NFC and Internet) are required from the User.

  • For actually sending the bitmap data over the NFC protocol, this uses the WaveShare Android SDK, and the JAR file that they provided.

  • Kotlin coroutines are used throughout, as there are a lot of operations that are blocking in nature - main transceive operation is basically one long blocking sequence.

About

Android app for WaveShare passive NFC-powered E-Ink displays, to generate and update content

Topics

Resources

License

Stars

Watchers

Forks

Languages

  • Kotlin 79.4%
  • JavaScript 13.2%
  • Dockerfile 3.8%
  • HTML 2.0%
  • CSS 1.5%
  • Batchfile 0.1%