The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Tag: Improvements

Making the world a better place, one piece at a time

  • Xiaomi Dafang Hacks: Timelapse Images

    With the Wyze and Xiamoi Dafang cameras running the Xiaomi-Dafang Hacks firmware and software, I tried the timelapse functions on the yard camera.

    The config/timelapse.conf file:

    # Interval between snaps, in seconds
    TIMELAPSE_INTERVAL=10
    # Duration of the script should run, in minutes, set to 0 for unlimited
    TIMELAPSE_DURATION=60
    # Save dir config
    SAVE_DIR_PER_DAY=1
    # Enable compression
    COMPRESSION_QUALITY=100

    The images, named along the lines of 13-04-2019_191810_001.jpg, appear in the DCIM/timelapse directory, tucked into daily directories with names like 2019-04-13, a mismatch obviously in need of tweaking. There’s also a time_lapse directory which seems like cruft from an earlier revision; you can configure the target directory in scripts/timelapse.sh.

    Start the script manually or from a crontab entry, wait until it’s done, then transfer the images to somewhere more convenient with a Bash one-liner:

    find /system/sdcard/DCIM/timelapse/ -name \*jpg -exec curl -s -n -T {} ftp://192.168.1.10/Timelapse/ \; 

    The -s silences all curl output; omit it until you’re sure the lashup works as you expect. I always forget the backslash before the semicolon terminating the -exec command.

    The -n pulls the userID and password from the ~/.netrc file you previously set up for manual ftp sessions:

    machine 192.168.1.10
    login ftp-user-id
    password secret-password

    The IP address corresponds to my ancient NAS drive; your mileage may vary.

    From my desktop box, mount the NAS drive:

    sudo mount -t cifs -o "credentials=/root/.nas-id,vers=1.0,uid=ed" "//nasty/Timelapse" /mnt/part

    The drive’s credentials aren’t particularly secret, but tucking them into /root/.nas-id means you could automount the drive with no hassle. The NAS drive requires the oldest possible CIFS version, of course.

    Then view the pix:

    Xiaomi Dafang - 15-04-2019_13.26.18
    Xiaomi Dafang – 15-04-2019_13.26.18

    You could set up the camera as an NFS share, but having all the cameras deposit their pix in a common location seems more convenient, particularly after I get around to automating the image transfer. Regrettably, the NAS drive doesn’t support subdirectories.

  • Anker MicroSD Card Adapter Speeds

    According to its description, the Anker USB 3.0 card reader can handle both a MicroSD and a standard SD card at once:

    Simultaneously read and write on two cards to save yourself the effort of constant unplugging and re-plugging.

    Which looks like this:

    Anker USB Reader - dual card
    Anker USB Reader – dual card

    After you get used to inserting the SD card downside-up, it fits perfectly. The Kapton tape on the MicroSD card eases extraction from the still finger-dent-less M20 camera mount on the back of my Tour Easy ‘bent.

    Plugged into a USB 3.0 port, my file extractor script chugs along at 25.9 MB/s, taking about 18 minutes to transfer 28 GB of video data.

    Splurging another eleven bucks for a second reader produces this setup:

    Anker USB Reader - single card
    Anker USB Reader – single card

    After plugging both readers into adjacent USB 3.0 ports, the script transfers files at 46.6 MB/s and copies 28 GB in 10 minutes.

    So, yes, the reader can handle two cards at once, but at half the speed.

    Not life-changing, but it shows why I like measurements so much …

  • Multiprocess Book-on-CD Ripping

    The most recent iteration of ripping a book-on-CD to bits suitable for a small MP3 player begins by defining the metadata:

    author="Whoever Wrote It"
    title="Whatever It May Be About"

    Set up a suitable directory for the MP3 files, with a subdirectory for the WAV files direct from the CD:

    mkdir "$author - $title"
    cd "$author - $title"
    mkdir waves

    Then unleash cdparanoia on each disk, but with its error checking dialed back to a minimum because most errors don’t produce much audible damage:

    d=01 ; cdparanoia -v -Y --never-skip=1 -B "1-" waves/D$d.wav ; eject cdrom

    In some cases, however, a nasty gouge (the previous owners being careless, alas) can jam cdparanoia midway through a track, so I fetch all the remaining tracks:

    d=10 ; cdparanoia -v -Y --never-skip=1 -B "6-" waves/D$d.wav

    Sometimes re-cleaning the disc and re-reading the offending track produces a better outcome:

    d=10 ; cdparanoia -v -Y --never-skip=1 -B "5-5" waves/D$d.wav

    With all the WAV files collected, I now know how to unleash multiple lame conversions for all the tracks on each disc:

    for d in {01..12} ; do for t in {01..19} ; do if [[ -f waves/track$t.D$d.wav ]] ; then lame --silent --preset tape --tt "D${d}:T${t}" --ta "$author" --tl "$title" --tn $t --tg "Audio Book" --add-id3v2 waves/track${t}.D${d}.wav D${d}-T${t}.mp3  & fi ; done ; wait ; done

    The disc and track ranges correspond to notes written on paper while ripping the CDs, there being no automagic way to collect the information.

    That may be easier to read with the control structures spread out:

    for d in {01..12}
     do for t in {01..19}
      do if [[ -f waves/track$t.D$d.wav ]]
       then
        lame --silent --preset tape --tt "D${d}:T${t}" --ta "$author" --tl "$title" --tn $t --tg "Audio Book" --add-id3v2 waves/track${t}.D${d}.wav D${d}-T${t}.mp3  &
       fi
      done
     wait
    done

    Affixing an ampersand (&) to the lame command drops it into the background, where it runs as CPU time becomes available. The wait after the first loop stalls until all of the lame instances for each CD finish.

    The kernel scheduler manages to keep the GUI responsive while a four-core CPU makes short work of the entire CD.

    When it’s all done, transfer the MP3 files to the player:

    cd ..
    sudo mount -o uid=ed /dev/sde1 /mnt/part
    rsync -vrtu --progress --exclude="waves" "$author - $title"  /mnt/part/Music
    sync
    sudo umount /mnt/part

    Fetching commands from history eliminates the need to remember all that, but now it’s written down where I can find it for the next desktop box.

    Life is good!

  • Desk Lamp Conversion: Round 2

    A bit of rummaging produced a desk lamp arm, minus whatever lamp it originally held, ready to hold the second photo lamp, after a bit of epoxy on one locking knob:

    Lamp arm clamp screw rework
    Lamp arm clamp screw rework

    The flanged nut will seat on the wrecked part of the knob, with the epoxy holding it in place and somewhat reinforcing the perimeter. I’m not sure this will last forever, but it’ll be a start.

    Printing a second cold shoe, though, worked perfectly, and everything fit:

    Photo Lamp - right arm installed
    Photo Lamp – right arm installed

    I love it when a plan comes together!

  • Wyze V2 Cameras: Xiaomi-Dafang Hacks, Round 2

    Another attempt at replacing the Wyze camera firmware went much more smoothly, producing a pair of small cameras with better network manners:

    Wyze Camera hacks - Cam 1 overhead workbench
    Wyze Camera hacks – Cam 1 overhead workbench

    That’s a VLC screen capture from the RTSP stream; obviously, I must up my clutter control game.

    I formatted a 32 GB MicroSD card with a 512 MB partition, which may not be strictly necessary, copied the MicroSD CFW bootloader (as demo.bin, sheesh), and it installed without drama.

    I resized the partition to 32 GB, installed the firmware (per the FAQ) into the root directory, tweaked the configuration files to match my situation, popped it in the camera, plugged the power cable, and It Just Worked™.

    Herewith, a checklist of config directory files requiring tweakage:

    • wpa_supplicant – WiFi SSID and password
    • timezone.conf – America/New_York for us
    • osd.conf – can be tweaked through the Web interface
    • staticip.conf – 192.168.1.11x, as you like
    • resolve.confpihole or router IP, as needed
    • defaultgw.conf – router IP
    • rtspserver.conf – different ports for additional cameras

    It would be possible to have the pihole’s DHCP server assign a fixed IP address to each camera, based on its MAC address, but this way the camera knows who it is right from the start and what it’s supposed to be doing.

    The router isn’t bright enough to route different port numbers on its Internet side to different LAN IP addresses with the same port address, so each camera must stream from a different port number. I don’t plan many world-available video streams, but a friend does enjoy watching the birds during feeder season.

    With the RTSP stream up & running, I flashed the U-Boot bootloader (again, minus drama) and tweaked its uEnv.txt configuration file:

    • Change the memory layout to allow 1920×1080 video
    • ethaddr – set to match hardware MAC address
    • gateway – router IP
    • ipaddr – match the staticip.conf value
    • serverip – router IP (unclear what this does)

    The cameras now produce no objectionable network activity, dramatically down from the Wyze firmware’s desperate attempts to contact various servers, every five minutes, around the clock. I have no way of tracking connections made with direct dotted-quad IP addresses, rather than through the pihole, but … this is a distinct improvement.

  • Seam Ripper Cover

    The cover for Mary’s favorite seam ripper cracked long ago, has been repaired several times, and now needs a replacement:

    Seam Ripper cover - overview
    Seam Ripper cover – overview

    The first pass (at the top) matched the interior and exterior shapes, but was entirely too rigid. Unlike the Clover seam ripper, the handle has too much taper for a thick-walled piece of plastic.

    The flexy thinwall cover on the ripper comes from a model of the interior shape:

    Seam Ripper Cover - handle model
    Seam Ripper Cover – handle model

    It’s not conspicuously tapered, but OpenSCAD’s perspective view makes the taper hard to see. The wedge on top helps the slicer bridge the opening; it’s not perfect, just close enough to work.

    A similar model of the outer surface is one thread width wider on all sides, so subtracting the handle model from the interior produces a single-thread shell with a wedge-shaped interior invisible in this Slic3r preview:

    Seam Ripper Cover - exterior - Slic3r preview
    Seam Ripper Cover – exterior – Slic3r preview

    The brim around the bottom improves platform griptivity. The rounded top (because pretty) precludes building it upside-down, but if you could tolerate a square-ish top, that’s the way to go.

    Both models consist of hulls around eight strategically placed spheres, with the wedge on the top of the handle due to the intersection of the hull and a suitable cube. This view shows the situation without the hull:

    Seam Ripper Cover - handle model - cube intersection
    Seam Ripper Cover – handle model – cube intersection

    The spheres overlap, with the top set barely distinguishable, to produce the proper taper. I measured the handle and cover’s wall thicknesses, then guesstimated the cover’s interior dimensions from its outer size.

    The handle’s spheres have a radius matching its curvature. The cover’s spheres have a radius exactly one thread width larger, so the difference produces the one-thread-wide shell.

    Came out pretty nicely, if I do say so myself: the cover seats fully with an easy push-on fit and stays firmly in place. Best of all, should it get lost (despite the retina-burn orange PETG plastic), I can make another with nearly zero effort.

    The Basement Laboratory remains winter-cool, so I taped a paper shield over the platform as insulation from the fan cooling the PETG:

    Seam Ripper Cover - platform insulation
    Seam Ripper Cover – platform insulation

    The shield goes on after the nozzle finishes the first layer. The masking tape adhesive turned into loathesome goo and required acetone to get it off the platform; fortunately, the borosilicate glass didn’t mind.

    The OpenSCAD source code as a GitHub Gist:

    // Cover for old seam ripper
    // Ed Nisley – KE4ZNU
    // 2019-03
    /* [Layout Options] */
    Layout = "Build"; // [Show,Build]
    Part = "Handle"; // [Handle,CoverSolid,Cover]
    /* [Extrusion Parameters] */
    ThreadWidth = 0.40;
    ThreadThick = 0.25;
    HoleWindage = 0.2;
    Protrusion = 0.1;
    //—–
    // Dimensions
    /* [Dimensions] */
    WallThick = 1*ThreadWidth;
    CapInsideLength = 48.0;
    CornerRadius = 2.0; // handle at base
    Base = [11.0,5.5,0.0]; // handle at base
    Tip = [8.2,3.7,CapInsideLength]; // inferred at tip
    HandleOC = [Base – 2*[CornerRadius,CornerRadius,0.0],
    Tip – 2*[CornerRadius,CornerRadius,CornerRadius/2]
    ];
    NumSides = 2*3*4;
    //—–
    // Useful pieces
    // Handle is basically the interior of the cover
    module Handle() {
    intersection() {
    hull()
    for (i=[-1,1], j=[-1,1], k=[0,1])
    translate([i*HandleOC[k].x/2,j*HandleOC[k].y/2,k*HandleOC[k].z])
    sphere(r=CornerRadius,$fn=NumSides);
    translate([0,0,-CornerRadius/2]) // chop tip for better bridging
    rotate([45,0,0])
    cube([2*Base.x,CapInsideLength*sqrt(2),CapInsideLength*sqrt(2)],center=true);
    }
    }
    module CoverSolid() {
    hull()
    for (i=[-1,1], j=[-1,1], k=[0,1])
    translate([i*HandleOC[k].x/2,j*HandleOC[k].y/2,k*HandleOC[k].z])
    sphere(r=CornerRadius + WallThick,$fn=NumSides);
    }
    module Cover() {
    difference() {
    CoverSolid();
    Handle();
    translate([0,0,-CornerRadius])
    cube(2*Base + [0,0,2*CornerRadius],center=true);
    }
    }
    //—–
    // Build things
    if (Layout == "Build") {
    Cover();
    }
    if (Layout == "Show")
    if (Part == "Handle")
    Handle();
    else if (Part == "CoverSolid")
    CoverSolid();
    else if (Part == "Cover")
    Cover();
  • ANENG AN8008/AN8009 Current Sense Resistor

    Somewhat to my surprise, Aneng AN8008/AN8009 multimeter PCBS sport what looks like a reasonably accurate current sense resistor on the 10 A input:

    AN8009 10 A current shunt - top view
    AN8009 10 A current shunt – top view

    The legend says 0.01R and the conductor doesn’t look quite like pure copper:

    AN8009 10 A current shunt - side view
    AN8009 10 A current shunt – side view

    The indentations look like clamp marks from the bending jig, rather than “calibration” notches made while squeezing the wire with diagonal cutters and watching the resistance on another meter.

    One might quibble about the overall soldering quality, but one would also be splitting hairs. I doubt the meter leads could withstand 10 A for more than a few seconds, anyhow.

    If you buy enough of something, you can buy pretty nearly anything you want, even cheap precision resistors!