tinkering – Chris Mullins https://blog.christophermullins.com I occasionally write about things. Usually these things are about computers. Thu, 29 Sep 2022 20:14:21 +0000 en-US hourly 1 https://wordpress.org/?v=5.7.15 Automating Blinds with a Retrofitted External Motor https://blog.christophermullins.com/2020/02/16/automating-blinds-with-a-retrofitted-external-motor/ https://blog.christophermullins.com/2020/02/16/automating-blinds-with-a-retrofitted-external-motor/#comments Mon, 17 Feb 2020 00:45:05 +0000 https://blog.christophermullins.com/?p=650 It’d be a real stretch to say I needed to automate the blinds in my apartment, but it was fun, and I’m loving the result. Blinds open automatically at sunrise and close at sundown. It’s nice to wake up to the sun!

I designed most of this setup myself, and wanted to share how I approached it. There was a lot of prior art (a particular shoutout to The Hookup’s Guide), but nothing that worked the way I was wanting. Guides I ran across either mounted a motor inside of a 2″ track (mine are 1″), or were for pull-cord style blinds.

I wanted a motor mounted on the outside of the track to drive the existing worm gear. I rent and don’t want to be kicking myself too hard when I move out. These are super easy to (un-)install.

There are few parts I’ll cover in this post:

  1. The 3D-printed mount design w/ assembly instructions
  2. The driver circuit PCB
  3. Driver firmware (esphome w/ cover component) + Integration with HomeAssistant
  4. Wiring tips

Bill of Materials

Before going into any detail, here’s a bill of materials (links may contain affiliate codes). If you’re into tinkering, you’ll probably have most of these parts already.

Driver

  1. Wemos D1 Mini ESP8266 dev board
  2. A4988 unipolar stepper driver
  3. 28BYJ stepper motor (important: converted to bipolar, see below)
  4. 1000 µF electrolytic capacitor
  5. LM2596 DC/DC buck converter
  6. Barrel jack
  7. 2A 12V power supply
  8. 4 Pin screw terminal
  9. Driver circuit PCB (Available on OSH Park). Gerber files on Github.

Mount

  1. A 3D printer
  2. eSun White PETG
  3. M3 screws, etc. for assembly (this kit has all but the M3*30 screws):
    1. 2x M3*30
    2. 3x M3*20
    3. 5x M3 nuts
    4. 6x M3 washers

3D-Printed Mount

The STLs are available on Thingiverse and PrusaPrinters. PrusaPrinters has gcode for the mounting arm, which requires support in some strategic locations.

The mount’s design is simple — it slides into the track and holds the motor in place. Angles and lengths are adjustable so that the motor can be moved into the appropriate position. It’s held together with some M3 screws.

The only piece of this that is not one-size-fits-all is the motor adapter. It connects the shaft of the stepper motor and the worm gear driver. While the 28BYJ end probably always looks the same, I had three different worm driver shafts across my apartment.

Assembly should be pretty self-evident. Let me know if not and I can elaborate.

Convert 28BYJ stepper to bipolar

28BYJ motors are unipolar steppers. In order to use them with the A4988 driver (which supports a higher supply voltage), they must be converted to bipolar. Fortunately, this is pretty simple. Just crack open the blue casing on the side and cut the center PCB trace. I used a small file to do this, but an X-Acto knife or small screwdriver would work just as well.

You’ll probably need to break some of the plastic legs on the casing to get it open, but it closes back up well enough without them. I also snipped the lead wire going to this trace to avoid future confusion.

Driver Board

The schematic for this board is pretty simple and has three main components: an ESP8266, an A4988 stepper driver, and a voltage regulator (I used an LM2596-based board).

This worked just fine on a perfboard, but because I wanted several of these, I used this project as an excuse to familiarize myself with Kicad and get some PCBs made from OSH Park (project available here, all kicad+gerber files are on Github). I was very happy with the result:

Assembly Instructions

  • Make sure to adjust the output voltage of the LM2596 to 3.3v! You’ll fry the D1 Mini if you don’t do this.
  • Soldering components should be pretty straightforward as they’re all through-hole.
  • I would recommend using headers for the A4988 and Wemos D1 Mini in case either gets damaged.
  • Most D1 Mini kits come with two sets of 8-pin headers. Since the A4988 is a 2×8 pin board as well, this works out perfectly.

Driver Firmware

For this project, I wanted to try out ESPHome. I’ve written my own firmware for almost all of my EPS8266 projects. It was fun while it lasted, but the thought of gluing MQTT libraries to crappy C++ code didn’t sound exciting this time.

ESPHome’s Template Cover component does the trick quite nicely. I’ve put the YAML definition on Github. Flashing the D1 Mini with generated firmware is pretty simple. I used this command:

esphome office_blinds.yaml compile && \
  esptool.py -b 460800 write_flash 0x0000 office_blinds/.pioenvs/office_blinds/firmware.bin

(obviously you’ll need to have esphome and esptool installed).

You’ll also need a secrets.yaml that contains your wifi credentials and a setup password:

wifi_ssid: "your wifi network name"
wifi_password: "your wifi password"
fallback_ap_password: "a random password"

The meat of the definition is in the template .blinds.yaml, including pin mappings from the ESP8266 and the A4988. If you chose pins different from those shown in the schematic above, make sure to correct them.

Parameters that are specific to a particular installation are substituted. In addition to names, you may also want to adjust the target parameter in the definition. This controls how many turns the motor completes when transitioning from one step to another. You can also negate it if you need to invert the direction (although you can accomplish this by reversing wiring as well).

The stepper position and cover state should be persisted across reboots.

HomeAssistant Integration

ESPHome works really seamlessly with HomeAssistant. Just add an ESPHome integration (Configuration > Integrations > + > ESPHome) using the hostname or IP of the ESP8266 (if you’re having trouble finding this, it’ll appear in serial logs after flashing the firmware).

This adds the cover component and allows you to control the blinds:

To address a situation where I need to calibrate the position, I have these scripts:

office_blinds_set_open:
  alias: Office Blinds - Set Open Position
  sequence:
    - service: esphome.office_blinds_set_open_position
office_blinds_set_closed:
  alias: Office Blinds - Set Closed Position
  sequence:
    - service: esphome.office_blinds_set_closed_position

Calling them will tell ESPHome to consider its current position as either open or closed. In combination with the up/down/stop action buttons, this will allow you to get your blinds into the desired state.

Wiring Tips

You can use any sufficiently large four-wire cable to connect the driver to the motor. Ethernet cable works really well. I used one twisted pair for each lead. Stranded ethernet + crimped header would be best, but I only had solid core ethernet, so I soldered some headers on and called it a day.

Here are some pictures that hopefully help as a wire guide:

Note that you can reverse the order in which they’re connected (1/2/3/4 -> 1/4/2/3) to invert the directions the stepper turns for open/close.

Updates

September 29, 2022

  • Significant updates to the ESPHome yaml definitions
    • Stepper position persisted across reboots
    • Adds pin definitions for MS1/MS2/MS3 on A4988 used to control step granularity. These need to be pulled LOW during operation.
    • By default D4 is used for MS1. D4 is also tied to the internal LED on the D1 Mini. I have this pin kept HIGH during idle so the LED stays off. It’s pulled LOW while the stepper is running, which has the nice side-effect of the LED lighting up while the motor is (or should be) running.

Links

]]>
https://blog.christophermullins.com/2020/02/16/automating-blinds-with-a-retrofitted-external-motor/feed/ 18
Rescue Your Amazon Dash Buttons https://blog.christophermullins.com/2019/12/20/rescue-your-amazon-dash-buttons/ https://blog.christophermullins.com/2019/12/20/rescue-your-amazon-dash-buttons/#comments Fri, 20 Dec 2019 22:45:10 +0000 https://blog.christophermullins.com/?p=614 Earlier this year, Amazon announced that they’ll discontinue Dash Buttons. I don’t know how successful Dash Buttons were for their intended use, but Home Automation hackers have loved (mis-)using them for everything from warming up their coffee pot to keeping track of bodily functions.

Unfortunately for us hackers, Amazon is an unforgiving god. Not only have they stopped selling Dash Buttons, but they’ve removed the part of their app used to set new ones up. Even worse, to any button unfortunate enough to connect to The Mothership, Amazon has promised to issue a firmware update that bricks the device. It is therefore critical that you set up your buttons in an environment where they will not be able to phone home.

Fortunately for us hackers, Amazon is not an infallible god. Versions of their dash button firmware built on May 2016 and earlier are vulnerable to a buffer overflow attack during the high-frequency audio setup (Hunz did some truly awesome reverse engineering work to find this).

We can exploit this vulnerability to complete the setup.

How-To

In the following section, I’ll go into more detail about how this works.

For now, let’s do this!

  1. Put Dash Button in setup mode by holding down the button until the LED flashes blue.
    1. Connect to the Amazon ConfigureMe WiFi network and visit http://192.168.0.1.
    2. You’ll see the button’s hardware (MAC) address. Block its Internet access in your router’s settings. If you don’t do this, the button will get an over-the-air update when it phones home and get bricked.
  2. While in setup mode, play this .wav file through some earbuds aimed at the Dash Button.
    • If the LED turns green, the exploit worked! Carry on to step (3).
    • If the LED turns off, you’re probably on a firmware version that fixed the vulnerability. Unfortunately, you’re out of luck if this is the case. (unless someone finds another vulnerability)
  3. Put the Button in setup mode again.
  4. Connect to the WiFi network it creates — Amazon ConfigureMe.
  5. Visit this URL*: http://192.168.0.1/?amzn_ssid=<wifi_network_name>&amzn_pw=<wifi_network_pw>. (obviously substituting wifi_network_name and wifi_network_pw for the desired values)

That’s it! It should work now.

[ * ]: Note that the setup AP is unsecured and this request is sent over HTTP. You’re sending this request in plaintext over the air. Don’t do this unless you’re comfortable with that. The buttons support a configuration flow that involves exchanging crypto keys, but this is far more involved. If there’s enough interest, I can write a script.

How this works

The Dash Button setup process has two high-level steps:

  1. Getting WiFi credentials from you.
  2. Exchanging a pair of secrets with The Mothership. Under normal operation, these are used to authenticate with Amazon when placing an order (it uses them to generate an HMAC secret).
    1. The button transfers a device secret baked into the firmware to Bezos HQ.
    2. The button retrieves and stores a customer secret from Amazon.

(1) is easy for us to fake. In fact, all we need is the final step from the previous section — visiting the URL with the amzn_ssid and amzn_pw parameters.

It’s (2) that’s keeping everyone from setting up their buttons. Amazon has stopped responding to these exchange requests, meaning the buttons will never complete the setup process unless we get creative.

The part of the firmware that handles high-frequency audio packets is vulnerable to a buffer overflow attack. From Hunz’s slides, you can see that it’s doing a memcpy without a length check:

Hunz put together some excellent scripts that pack an exploit payload in ARM assembly into an audio file.

I needed to do some reverse engineering of my own to find the function responsible for writing the customer secret to flash. I’d never so much as opened a disassembler, so this was a pretty fun challenge. Since IDA costs an arm, a leg, and the souls of any present and future offspring, I used Ghidra (I have no complaints, although a professional might). I put the archive file on Github.

The raw function that writes a customer secret to flash is at address 0x40FAA4:

It takes in a pointer and a length (which appears to always be 20). This function is normally wrapped in a bunch of code that calls Amazon’s servers, does validation, etc., but since we’ve got arbitrary code execution, we can just call it directly.

My exploit payload follows:

/* 
 The following three lines are parsed by Hunzs' scripts.
 Registers R1, R2, and R3 will be pre-populated with the
 specified values.
*/

// r1 = 0x400000 -- flash start
// r2 = 0x40faa5 -- write customer secret function ptr (+1 due to thumb)
// r3 = 0x40e721 -- set LED color function ptr +1

/* set up function call parameters */
PUSH {R1-R3}
MOV  R0, R1
MOV  R1, #0x14
/* call avocado_writeCustomerSecret */
BLX  R2
POP  {R1-R3}

/* set LED to green */
LDR R0, =0x00FF00
BLX R3

/* let watchdog expire */
done:
  B done

Since it doesn’t matter what the value of this secret is so long as we’re not intending to connect to Amazon, I pass an arbitrary address (0x400000 — the start of ROM) along with a length of 20 to the writeCustomerSecret function.

Then it sets the LED to green to indicate success. Firmware versions that have patched this vulnerability shut down when they receive the exploit.

Further fun

When starting on this effort, I soldered some magnet wire onto the UART test pads to get serial access. Hunz labels the pins in his talk:

Here’s a photo of my test rig:

The most interesting thing you can do with UART access is execute more code. The audio exploit payload is limited to a small number of instructions. Hunz supplied a payload that reads data from UART into SRAM and executes it (there may be a more convenient way to do this, but I’ve not dug in yet). Soldering onto these tiny pads is pretty challenging, so I modeled and 3D-printed a crude pogo pin fixture:

Pogo pin fixture. Connects to UART RX/TX pins. Gnd is connected separately.

I’d initially thought this was necessary in order to configure wifi credentials, but turns out you can do that using the setup AP, which is much easier.

You can’t do much of anything interesting in the serial console, but it at least appears that someone over at Amazon has a sense of humor:

****    TAOS Bootloader 0.2.11    ****

0x00000004 ms    0x000000FB us
Reset Trigger : FIRST POWER UP
(APP)(INFO)Chip ID 1503a0
(APP)(INFO)DriverVerInfo: 0x134a134a
(APP)(INFO)Firmware ver   : 19.4.10 Svnrev 13806
(APP)(INFO)Firmware Build Oct 26 2016 Time 17:55:34
(APP)(INFO)Firmware Min driver ver : 19.3.0
(APP)(INFO)Driver ver: 19.4.10 Svnrev 12577
(APP)(INFO)Driver SVN URL branches/WIFIIOT-1400_2
(APP)(INFO)Driver built at Mar  3 2017	15:19:38
DBG: Set MAC address 18:74:2E:4D:01:D3
DMA OVERRUN
DMA OVERRUN
> exit

    There is no exit from here. You are stuck in a forever loop...MUAHAHAHA!

>

Acknowledgements

  • Hunz’s reverse engineering work is incredible. If you’re into this sort of stuff at all (and if you’re reading this, you probably are), you’d very likely get a huge kick out of his 33c3 talk, which is where I learned about the audio vulnerability.

Future Work

The Dash Button hardware is pretty remarkable. It’s got a beefy microcontroller, (obviously) builtin wifi, a BLE chip, a microphone for the HFA audio configuration, and so on. I’ve not seen any official-looking estimates at the cost Amazon was paying for these things, but some have guessed in the ballpark of $20 — even at Amazon’s scale.

If we can find a way to flash custom firmware, they’d be perfect IoT buttons. As-is, they’re obviously a little janky. We’re monitoring networks for side-effects to trigger actions. This should theoretically be possible given that Amazon issues OTA firmware updates (the code that handles the OTA update process appears to be at 0x42391C).

I don’t know how much gas is left in my motivation-for-reading-assembly tank, but this is what I’d work on next with what’s left.

It’d be really neat if Amazon open-sourced an SDK. Yes, they’ve said they have a recycling program, but something tells me most buttons are gonna end up in the landfill.

Caveats

  1. Amazon fixed the buffer overflow vulnerability in a later version of the firmware, but almost every button I have uses the May 2016 version out of the box (there’s been ~1/20 exceptions).
  2. Buttons get OTA updates if they connect to the Internet. So if you have a button that’s been phoning home, in all likelihood it’s been patched.
  3. My setup triggers on 802.11 probe requests, meaning I don’t need (or want) the button to connect to a network, only to try. As far as I can tell, though, they will.

Donating

If this work has brought you happiness or utility, it’s more than enough for me to hear those words.

If you’re feeling especially generous, and are open to a charitable donation, that’d make me very happy. Here are some whose mission I support (in no particular order):

]]>
https://blog.christophermullins.com/2019/12/20/rescue-your-amazon-dash-buttons/feed/ 72
DIY Pet Treat Dispenser https://blog.christophermullins.com/2019/06/11/pet-treat-dispenser/ https://blog.christophermullins.com/2019/06/11/pet-treat-dispenser/#comments Wed, 12 Jun 2019 02:57:13 +0000 https://blog.christophermullins.com/?p=436 When I first saw Internet-connected pet treat dispensers like PetCube, I laughed them off. “Who would ever want such a thing?” I have cats, but this just felt silly.

Then we went on vacation and left our cats at home (we hired a sitter, of course). There was one day where our sitter’s car broke down, and wasn’t able to come on the day he’d planned. We have an automatic food dispenser and a water filter, but we naturally started worrying about the furrier members of our family. Then I understood why these goofy treat dispenser products exist.

You’re a kitty!

I’ve seen PetCube used, and it seems like a good product. But cloud-based home video products aren’t something I’m terribly comfortable with. So I set out to build my own. (Also, if I’m being honest, I was looking for a tinker project anyway).

Design

The list of features I wanted were:

  • 3D-printable. I wanted to make as much of the body out of 3D-printable parts as possible.
  • Local control. Cameras that phone home spook me. I planned on hooking it up through HomeAssistant to allow remote access.
  • Camera. Of course the whole point is to spy on cats.
  • Audio. Play short sound clips to let the kitties know they’ll get a treat if they come look cute in front of the camera.
  • Dispense on command. No stringent requirements on treat size, consistent dispense count, etc. Enough to make it worth Eleanor’s while, but not enough to make her too fat.

There are readily available components for all of these things. Tying them together on one perfboard was a pain in the butt, but doable. If I were competent at circuit design, I’d probably have done that instead.

Shopping List

These are the components I used to get the job done. (note that any links contain Amazon Affiliate referral codes.)

All told, this was probably around $50 in parts, plus a bunch of crap I already had lying around.

Printing and Assembling the Body

STLs are on Thingiverse.

I did not adjust parts to be in the proper printing orientation. It’s usually mostly obvious which way they should be oriented. The only slightly tricky ones are the upper half of the main body, which should be printed with the top facing the printbed (i.e., upside-down), and the hopper, which should also be printed upside-down. There are 10 parts in total

These parts are not very difficult to print for the most part, but there are some bridges that are a stretch. Make sure you’ve got your cooling settings dialed in. PLA is probably fine for everything, but I used PETG for the gears and shaft.

Assembly should be mostly straightforward, but I can post some pictures or a video if there’s confusion.

Controller Circuit

There’s nothing fancy going on here. It’s just connecting components together, but there are quite a lot of things to connect. There’s a sloppy Fritzing diagram and a pin mapping table on the Github project, so I won’t rehash it here.

I soldered everything together on perfboard. For what it was, it came out reasonably clean, but it was definitely a stretch. If I were doing this again, I might take the time to lay out an actual PCB and have one printed.

Software

I have the ESP32 controller firmware I wrote on Github.

When first connecting, a setup AP named ESPXXXX (with random XXXX) will appear allowing you to enter your wifi details.

There’s currently no UI. After connecting to your wifi, the easiest way to configure it is via the REST API (use PUT /settings).

The REST API is documented in the Github README. If there’s enough interest, I can document the setup procedure in greater detail.

The Finished Product

Here are some additional pictures of the guts:

Conclusions

This was a really fun and challenging project. The end result is certainly not as polished as an off-the-shelf product, but I’ve been pretty surprised with how well it works.

My cats are unfortunately only occasionally interested in treats, but when they are, they come running. It serves the intended purpose as well as it can.

There are a ton of independent steps you’d need to follow to reproduce this. Honestly, I wouldn’t recommend it unless you’re looking to get your hands really dirty–no really, like encased in dirt.

Links

]]>
https://blog.christophermullins.com/2019/06/11/pet-treat-dispenser/feed/ 4
Reusable Dash Button Case https://blog.christophermullins.com/2018/09/02/reusable-dash-button-case/ https://blog.christophermullins.com/2018/09/02/reusable-dash-button-case/#comments Sun, 02 Sep 2018 08:08:32 +0000 https://blog.christophermullins.com/?p=375 I use Dash Buttons* in quite a few places around my home — mostly as a substitute for a light switch where one is inconveniently located, or not present at all.

I prefer them to alternative options like the Flic Button* because they’re dramatically cheaper (a Dash is $5, compared to $35 for a Flic).  They’re also occasionally on sale for $0.99.

My only frustration with Dash buttons is that they’re meant to be disposable, despite being powered by a replaceable AAA battery.  The electronics are encased by two pieces of welded plastic.  It’s easy to break the weld, but difficult to reassemble in a pretty way.

Having recently started dabbling in 3D design and printing, I decided to create a reusable case.  The humble fruit of my efforts is here:

https://www.thingiverse.com/thing:3079607

I’m happy with how this turned out — it’s easy to open the case and replace the battery without damaging anything.

(Dis-)assembly

Pretty straightforward.  I took apart the stock case using some channel locks to break the welds:

With a little bit of elbow grease, and a T5 screwdriver to remove the battery enclosure, it comes apart like so:

A pry tool can be used to remove the PCB if it doesn’t come off by itself.

Assembly is straightforward.  First, put the plastic button and the rubber seal in place.

Then the PCB is placed back on the pegs, battery enclosure placed on top, and T5 screws added back.  Do not over-tighten the screws!  The printed pegs are quite fragile and will break under too much pressure.

After adding the battery back, the lid can be pressed onto the body:

And that’s it!  Fully assembled Dash case.

Update: Sept 4, 2018

I’ve uploaded a slightly modified version.  The main change makes it harder to over-tighten screws making the button unpressable.

[ * ] Contains Amazon affiliate link

]]>
https://blog.christophermullins.com/2018/09/02/reusable-dash-button-case/feed/ 1
Customizable e-Paper Information Display with 3D Printed Case https://blog.christophermullins.com/2018/06/30/e-paper-information-display-with-3d-printed-case/ https://blog.christophermullins.com/2018/06/30/e-paper-information-display-with-3d-printed-case/#comments Sat, 30 Jun 2018 21:43:08 +0000 https://blog.christophermullins.com/?p=344 I recently finished a project which tied together a bunch of different tinkering skills I’ve had a lot of fun learning about over the last couple of years.

The finished product is this:

It shows me:

  • The time
  • Weather: current, weekly forecast, readings from an outdoor thermometer, and temperature in the city I work in.
  • Probably most usefully — the times that the next BART trains are showing up.

Obviously the same thing could be accomplished with a cheap tablet.  And probably with way less effort involved.  However, I really like the aesthetic of e-paper, and it’s kind of nice to not have yet another glowing rectangle glued to my wall.

I’m going to go into a bit of detail on the build, but keep in mind that this is still pretty rough around the edges.  This works well for me, but I would by no means call it a finished product. 🙂

Hardware

This is made up of the following components:

  1. 400×300 4.2″ Waveshare e-Paper display module *
  2. HiLetgo ESP32 Dev Board *
  3. 60x40mm prototype board *
  4. Command strips (for sticking to the wall)
  5. Some patch wires
  6. MicroUSB Cable
  7. Custom 3D Printed enclosure (details follow)

Depending on where you get the components, this will run you between $40 and $50.

Hookup

The e-Paper display module connects to the ESP32 over SPI.  Check out this guide to connecting the two.

I chose to connect using headers, sockets, and soldered wires.  This makes for a more reliable connection, and it’s easier to replace either component if need be.  I cut the female jacks from the jumper bus that came with my display and soldered the wires onto header pins.  I then put a whole mess of hot glue to prevent things from moving around.

Firmware

I’m using something I wrote called epaper_templates (clearly I was feeling very inspired when I named it).

The idea here is that you can input a JSON template defined in terms of variables bound to particular regions on the screen.  Values for those variables can be plumbed in via a REST API or to appropriately named MQTT topics.

The variables can either be displayed as text, or be used to dynamically choose a bitmap to display.

My vision for this project is to have an easy to use GUI to generate the JSON templates, but right now you have to input it by hand.  Here is the template used in the picture above as an example.

Configuration

The only variable that the firmware fills in for you is a timestamp.  Everything else must be provided externally.

I found Node-RED to be a fantastic vehicle for this.  It’s super easy to pull data from a bunch of different sources, format it appropriately, and shove it into some MQTT topics.  The flow looks like this:

Here is an export of the flow (note that some URLs reference internal services).

Enclosure

I designed a box in Fusion 360.  I’m a complete newbie at 3D design, but I was really pleased with how easy it was to create something like this.

The display mounts onto the lid of the box with the provided screws and hex nuts.  The lid sticks to the bottom of the box with two tabs.  The bottom has a hole for the USB cable and some tabs to hold the prototype board in place.

My box is printed on a Prusa i3 MK3.

3D files:

Tips on printing:

  • The top should be printed in PETG or some other slightly flexible material.  The tabs will probably break if printed in PLA.  Material does not matter much for the bottom.  Mine is PLA.
  • Both pieces should be printed with supports.  For the top, the recessed screw holes need it.  For the bottom, the tabs, lid tab holes and USB cable hold need them.

* Contains Amazon affiliate link

]]>
https://blog.christophermullins.com/2018/06/30/e-paper-information-display-with-3d-printed-case/feed/ 1