Monthly Image: Moonrise

With some heavy weather on the way:

Moonrise in Red Oaks Mill - 2020-04-08
Moonrise in Red Oaks Mill – 2020-04-08

Bracing the Pixel 3a on the deck railing. Despite the star near the top, it decided to not invoke Astrophotography mode.

This was apparently a Pink Moon and a Supermoon and surely some other adjectives nobody cared about until Webbish media discovered they could generate ad revenue using clickbait headlines concerning a monthly event.

We just enjoy the sights out along the driveway, whatever they may be.

Schwab / Symantec VIP Access vs. Yubikey

A Yubikey 5 NFC turns out to be perfectly compatible with any website using Symantec’s (no longer available) hardware key and VIP Access (definitely a misnomer) app to generate TOTP access codes, because the sites use bog-standard TOTP. The only difficulty comes from Symantec’s proprietary protocol creating the token linking an ID with a secret value to generate the TOTP codes, which is how they monetize an open standard.

Fortunately, Cyrozap reverse-engineered the Symantec protocol, dlenski mechanized it with a Python script, and it works perfectly:

python3 -m venv symkey-env
source symkey-env/bin/activate
pip3 install
vipaccess provision -t SYMC

That spits out a file containing the ID and secret, from which you create a QR code for the Yubikey Authenticator app:

qrencode -t UTF8 'otpauth://totp/VIP%20Access:SYMCidnumbers?secret=longsecretgibberish&issuer=Symantec&algorithm=SHA1&digits=6'

Fire up the app, wave the Yubikey behind the phone, scan the QR code, wave the Yubikey again to store it, sign in to the Schwab site, turn on 2FA, enter the ID & current TOTP value from the Yubikey Authenticator, and It Just Works™.

Of course, you can kiss Schwab’s tech support goodbye, because you’re on your own. If you ever lose the Yubikey, make sure you know the answers to your allegedly secret questions.

Equally of course, you’re downloading and running random shit from the Intertubes, but …

Now, if only all my financial institutions would get with the program.

Google Pixel 3a Microscope Adapter

Hand-holding my Google Pixel 3a phone over the microscope eyepiece worked well enough to justify building Yet Another Camera Adapter:

Pixel 3a Microscope Adapter - in action
Pixel 3a Microscope Adapter – in action

The solid model looks about like you’d expect:

Google Pixel 3a Zoom Microscope Mount - solid model - top
Google Pixel 3a Zoom Microscope Mount – solid model – top

The “camera” actually has the outside dimensions of a Spigen case, rather than the bare phone, because dropping a bare phone is never a good idea.

The base plate pretty much fills the M2’s platform:

Pixel 3a Microscope Adapter - M2 platform
Pixel 3a Microscope Adapter – M2 platform

I originally arranged the four corners around the plate to print everything in one go, but an estimated six hours of print time suggested doing the corners separately would maximize local happiness. Which it did, whew, even if the plate ran for a bit over 4-1/2 hours.

The snout is a loose fit around the 5× widefield microscope eyepiece, with the difference made up in a wrap of black tape; it’s much easier to adjust the fit upward than to bore out the snout. An overwrap of tape secures the snout to the eyepiece, which I’ve dedicated to the cause; the scope normally rocks 10× widefield glass.

The tapered hole exposes the phone’s fingerprint reader to simplify unlocking, should it shut down while I’m fiddling with something else.

The microscope doesn’t fully illuminate the camera’s entrance pupil at minimum zoom, with 4.5× filling the screen and (mostly) eliminating the vignette. The corner blocks have oversize holes to allow aligning the camera lens axis over the microscope optical axis. The solid model incorporates Lessons Learned from the version you see here, because you (well, I) can’t measure the camera axis with respect to the outside dimensions accurately enough:

Pixel 3a Microscope Adapter - installed - front
Pixel 3a Microscope Adapter – installed – front

Although it’s less unsteady than it looks, microscopy requires a gentle touch at the best of times. The adapter doesn’t add much wobble to the outcome:

Pixel 3a Microscope Adapter - installed - side
Pixel 3a Microscope Adapter – installed – side

The field is about 14×19 mm with the camera at 4.5× and the microscope at minimum zoom:

Pixel 3a Microscope Adapter - test image - min mag
Pixel 3a Microscope Adapter – test image – min mag

You can see a little darkening on the upper and lower right corners, so the phone’s still minutely leftward.

The field is about 1.5×2 mm at full throttle:

Pixel 3a Microscope Adapter - test image - max mag
Pixel 3a Microscope Adapter – test image – max mag

Color balance with the cold white LED ring isn’t the best, but it’s survivable. Mad props to OpenCamera for exposing All. The. Controls. you might possibly need.

The OpenSCAD source code as a GitHub Gist:

// Google Pixel 3a mount for stereo zoom microscope
// Ed Nisley - KE4ZNU - 2019-12
Layout = "Show"; // [Show,BuildAll,BuildBumpers,BuildPlate,DrillGuide,Phone,Plate,Bumper]
/* [Hidden] */
ThreadThick = 0.25;
ThreadWidth = 0.40;
HoleWindage = 0.2;
Protrusion = 0.1; // make holes end cleanly
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
ID = 0;
OD = 1;
inch = 25.4;
// Dimensions
Phone = [74.5,156.0,12.0]; // inside Spigen case
PhoneRadii = [10.0,10.0,3.0]; // corner rounding, likewise
LensOffset = [-17.0,-18.5,0]; // looking at phone screen, (-) sign = from right/top edge
PrintReader = [0,Phone.y/2 - 44.0,0]; // fingerprint reader from center
PrintReaderDia = [20.0,30.0,0]; // ... hole for access
Eyepiece = [11.5,28.0 + 0.50,27.0]; // ID = lens, OD includes clearance
Insert = [3.0,4.5,4.0]; // M3 threaded brass insert
Screw = [3.0,7.0,3.5]; // OD = washer, LENGTH = washer + head height
WallThick = 3.0; // minimum wall thickness
Bumper = [2*Screw[OD],20.0,Phone.z]; // bumper edge piece
BumperOAL = Bumper.y + Bumper.x; // outside length for corner piece
BumperRadius = 2.0;
MinMargin = 1.2*Bumper.x; // at least this much extra plate for bumpers
echo(str("MinMargin: ",MinMargin));
Plate = [IntegerMultiple(Phone.x + 2*MinMargin,5.0),
IntegerMultiple(Phone.y + 2*MinMargin,5.0),
false ? 3*ThreadThick : max(Insert[LENGTH] + 2*ThreadThick,WallThick)];
PlateRadius = 5.0;
echo(str("Plate: ",Plate," radius: ",PlateRadius));
EmbossDepth = 2*ThreadThick + Protrusion;
DebossHeight = EmbossDepth;
ScrewOffset = Bumper.x/2;
ScrewAdjust = 1.5*Screw[ID];
NumSides = 2*3*4;
Gap = 2.0; // between build layout parts
// Useful routines
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2);
FixDia = Dia / cos(180/Sides);
cylinder(r=(FixDia + HoleWindage)/2,
// Basic shapes
// Overall phone outline
module Phone() {
for (i=[-1,1], j=[-1,1], k=[-1,1])
translate([i*(Phone.x/2 - PhoneRadii.x),j*(Phone.y/2 - PhoneRadii.y),k*(Phone.z/2 - PhoneRadii.z)])
module Plate() {
union() {
difference() {
union() {
for (i=[-1,1], j=[-1,1])
translate([i*(Plate.x/2 - PlateRadius),j*(Plate.y/2 - PlateRadius),0])
translate([Phone.x/2,Phone.y/2,-Eyepiece[LENGTH]/3 + Plate.z/2] + LensOffset)
cylinder(d=Eyepiece[OD] + 2*WallThick,h=Eyepiece[LENGTH]/3,
translate([Phone.x/2,Phone.y/2,-2*Eyepiece[LENGTH]/3 + Plate.z/2 + Protrusion] + LensOffset)
cylinder(d1=Eyepiece[OD] + 10*ThreadThick,
d2=Eyepiece[OD] + 2*WallThick,
translate([Phone.x/2,Phone.y/2,-2*Eyepiece[LENGTH] + Plate.z/2 + Protrusion] + LensOffset)
translate(PrintReader + [0,0,-Plate.z/2 - Protrusion])
cylinder(d1=PrintReaderDia[OD],d2=PrintReaderDia[ID],h=Plate.z + 2*Protrusion,$fn=NumSides);
for (i=[-1,1], j=[-1,1])
translate([i*(Phone.x/2 + Bumper.x/2),j*(Phone.y/2 - Bumper.y/2),-Plate.z])
for (i=[-1,1], j=[-1,1])
translate([i*(Phone.x/2 - Bumper.y/2),j*(Phone.y/2 + Bumper.x/2),-Plate.z])
translate([0,-12,Plate.z/2]) // recess for legend
translate([0,0,Plate.z/2 - EmbossDepth])
text(text="Pixel 3a",size=6,spacing=1.20,
translate([0,-15,Plate.z/2 - EmbossDepth])
text(text="Ed Nisley",size=6,spacing=1.20,
translate([0,-25,Plate.z/2 - EmbossDepth])
module BumperPiece() {
difference() {
translate([0,-BumperOAL/2 + Bumper.x,0])
for (i=[-1,1], j=[-1,1])
translate([i*(Bumper.x/2 - BumperRadius),j*(BumperOAL/2 - BumperRadius),0])
// Side bumpers, XY origin at inner corner
module BumperCorner() {
union() {
//- Build things
if (Layout == "Phone")
if (Layout == "Plate")
if (Layout == "Bumper")
if (Layout == "Show") {
color("LightBlue") Plate();
for (i=[-1,1], j=[-1,1]) {
a =
i > 0 && j > 0 ? 0 :
i < 0 && j > 0 ? 90 :
i > 0 && j < 0 ? -90 :
translate([i*Phone.x/2,j*Phone.y/2,Plate.z/2 + Bumper.z/2])
color("LightGreen") BumperCorner();
translate([0,0,Phone.z/2 + Plate.z/2 + Protrusion])
color("DarkGray",0.5) Phone();
if (Layout == "BuildAll") {
for (i=[-1,1], j=[-1,1]) {
a =
i > 0 && j > 0 ? 0 :
i < 0 && j > 0 ? 90 :
i > 0 && j < 0 ? -90 :
translate([i*(Plate.x/2 + Gap),j*(Plate.y/2 + Gap),Bumper.z/2])
if (Layout == "BuildPlate") {
if (Layout == "BuildBumpers") {
for (i=[-1,1], j=[-1,1]) {
a =
i > 0 && j > 0 ? 180 :
i < 0 && j > 0 ? -90 :
i > 0 && j < 0 ? 90 :
translate([i*(Bumper.x + Gap),j*(Bumper.x + Gap),Bumper.z/2])
if (Layout == "DrillGuide") {

Google Pixel 3a Photomicrography vs. Ballpoint Pens

The Google Pixel 3a camera, unlike the camera in my older Google Pixel XL, takes spectacularly good images through a widefield 5X eyepiece on the stereo zoom microscope:

0.5 1.0 mm ball pens - 0.7 mm lead pencil
0.5 1.0 mm ball pens – 0.7 mm lead pencil

That’s hand-holding the phone against the eyepiece while manipulating it with the other hand. Definitely not the most stable arrangement, but the camera copes well with slight motions. I really need a gripping hand for the camera, to free up another for the microscope’s focus knob.

For the record:

Zooming in (because it’s a stereo zoom microscope and I can), the 1.0 mm ball seems surprisingly un-wetted by its ink:

1.0 mm ball pen
1.0 mm ball pen

The Pilot V5 ball seems more smoothly covered:

0.5 mm ball Pilot V5RT pen
0.5 mm ball Pilot V5RT pen

Those are at the same magnification & crop size, so they’re to the same scale.

This definitely calls for a customized phone-to-eyepiece holder!

Kindle Fire Picture Frame: Copying the Pictures

Being a bear of unbearable consistency, I save edited picture files with a description following the original camera-assigned sequence number:

IMG_20181108_190041 - Kindle Fire Picture Frame - Another Test Image.jpg

Yup, spaces and all.

Kindle Fire Picture Frame - Another Test Image
Kindle Fire Picture Frame – Another Test Image

I store my general-interest pix chronologically by year, in subdirectories for interesting categories, so copying all the edited (a.k.a. “interesting”) pictures to the Kindle Fire becomes a one-liner:

cd /mnt/bulkdata/Cameras
find 20?? -iname \*\ \*jpg -print0 | xargs -0 cp --parents -t /mnt/part/Pictures

The --parents parameter tells cp to recreate the directory structure holding the picture in the target directory, thereby keeping the pix neatly sorted in their places, rather than creating one heap o’ pictures.

Come to find out I’ve edited slightly over 7 k general-interest pictures in the eighteen years I’ve been using digital cameras, of maybe 27 k total pictures. Call it a 25% hit ratio; obviously I’m not nearly fussy enough.

Then there’s another 16 k project-related pictures, of which 10 k were edited into something useful. With an emphasis on utility, rather than aesthetics, a 60% hit ratio seems OK.

Which works out to half a dozen pictures a day, every day, for eighteen years. I loves me some good digital camera action!

Kindle Fire Picture Frame: Side Block

A steel frame that Came With The House™ emerged from a hidden corner and, instants before tossing it in the recycle heap, I realized it had excellent upcycling potential:

Kindle Fire Picture Frame - Test Run
Kindle Fire Picture Frame – Test Run

Stipulated: I need better pictures for not-so-techie audiences.

Anyhow, my long-disused Kindle Fire fits perfectly into the welded-on clips, with just enough room for a right-angle USB cable, and Photo Frame Slideshow Premium does exactly what’s necessary to show pictures from internal storage with no network connection.

All I needed was a small block holding the Kindle against the far side of the frame:

Kindle Frame - side blocks
Kindle Frame – side blocks

A strip of double-stick carpet tape holds the block onto the frame. To extract the Kindle, should the need arise, slide it upward to clear the bottom clips, rotate it rearward, and out it comes.

Getting a good block required three tries, because the basement has cooled off enough to trigger Marlin’s Thermal Runaway protection for the M2’s platform heater. A test fit after the first failure showed the long leg was 1 mm too wide and, after the second failure, I reduced the fan threshold to 15 s and the minimum layer time to 5 s, producing the third block without incident.

The platform heater runs at 40 V and I considered bumping it to 43 V for a 15% power boost, but it has no trouble keeping up when the fan isn’t blowing chilly basement air across its surface.

The OpenSCAD source code, such as it is, doesn’t deserve its own GitHub Gist:

// Block to hold Kindle in a picture frame mount
// Ed Nisley - KE4ZNU
// November 2018

Protrusion = 0.1;

difference() {

    cube([18-4 + Protrusion,44-10 + Protrusion,10 + 2*Protrusion]);


Let the Dead Past Bury Its Dead

My old Gen 1 Kindle Fire hasn’t seen much action lately, so I figured maybe it could end its days by becoming a slide show / picture frame. While fiddling around, I tried to fire up the Amazon Shopping app:

Amazon App Unsupported on Amazon Gen 1 Kindle
Amazon App Unsupported on Amazon Gen 1 Kindle

Clicking the big orange button fired up Amazon’s Silk browser, which promptly crashed.

Some days, the punch line writes itself …