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.

Category: Machine Shop

Mechanical widgetry

  • Whirlpool Clothes Dryer: Heater Examination

    Whirlpool Clothes Dryer: Heater Examination

    A correspondent (you know who you are: thanks!) pointed out the Thermal Cutoff can trip should the 240 V heater coil sag enough to contact the grounded steel air duct surrounding it. Think of a connection from the heater in the lower right corner of the wiring diagram to the neutral wire:

    Whirlpool dryer - wiring diagram - detail
    Whirlpool dryer – wiring diagram – detail

    If the short is close to the middle of the heating element, the right half the heater will remain active even when all of the normal thermostats cut off the left half. The two half-elements will see about their usual 120 V and won’t burn out, but the right half will continue to heat the air until the Thermal Cutoff trips at 350 °F.

    A short near either end of the heating element will subject that section to a higher voltage than usual and promptly burn it out, in which case the dryer will fail to heat due to the much lower power dissipated in the remaining section.

    So I took the dryer apart after a (successful!) washing day to see if that had happened.

    A spring clip holds the top of the heater duct in place:

    Whirlpool Clothes Dryer - bulkhead parts - heater duct clip
    Whirlpool Clothes Dryer – bulkhead parts – heater duct clip

    AFAICT the clip cannot be disengaged from the duct in situ without removing the hex-head sheet metal screw holding it to the bulkhead, which requires inserting a 5/16 inch socket on the end of a 6 inch extension through a hole in the non-removable upper back cover. You (well, I) cannot see the screw from any position, so the process requires reaching up over the duct to position the socket by feel.

    This view looking up inside the dryer with the duct removed shows the clip on the bulkhead:

    Whirlpool Clothes Dryer - heater duct clip
    Whirlpool Clothes Dryer – heater duct clip

    The heating element looked to be in fine shape, with no sags or distortions:

    Whirlpool Clothes Dryer - heater top view
    Whirlpool Clothes Dryer – heater top view

    A side view:

    Whirlpool Clothes Dryer - heater side view
    Whirlpool Clothes Dryer – heater side view

    Taking a picture of the duct’s interior is impossible, but an eyeballometric inspection shows no burns / scorches / pits from contact with the coils:

    Whirlpool Clothes Dryer - heater duct interior
    Whirlpool Clothes Dryer – heater duct interior

    So AFAICT the Thermal Cutoff tripped due to Inherent Defect, rather than an overly high temperature.

    Reinstalling the duct requires fitting the spring clip into its slot in the duct, maneuvering the duct onto its lower bulkhead brackets without dropping the clip, persuading the top of the duct with the clip into position, getting the screw into the clip and the hole, then aligning the socket with the screw. If I were doing this for a living, I would definitely charge you extra; newer dryers have an easily removable heating element for well and good reason.

    So the dryer is, once again, back together again and, once again, works as well as it ever did, with another set of thermostats / cutoffs in the box of dryer and washer parts against future need.

    For reference, the heater seems to be a WP4391960.

  • Window Mount for Bamboo Bee Tunnel Nests

    Window Mount for Bamboo Bee Tunnel Nests

    Mary suggested converting wild bamboo up the hill into tunnel nests (per a xerces.org paper) for native bees buzzing around flowers in the yard, so:

    Bee Tunnel Nest - downspout installation
    Bee Tunnel Nest – downspout installation

    I hung bundles of larger tubes in trees out back, in hopes of attracting huge carpenter bees.

    3D printed mounts hold smaller bundles on the windows to let us keep an eye on the proceedings:

    Bee Tunnel Nest Mount - installed-]
    Bee Tunnel Nest Mount – installed

    Which look better when not seen though two layers of glass in desperate need of Spring Cleaning:

    Bee Tunnel Nest Mounts
    Bee Tunnel Nest Mounts

    The tabs provide a bit of pressure to hold the mounts in place, although I don’t know if they have enough springiness or will survive contact with the elements:

    Bee Tunnel Nest Mount - tab section - solid model
    Bee Tunnel Nest Mount – tab section – solid model

    The key advantage of not building bigger bee motels: these little bundles don’t need annual cleaning / maintenance and will eventually fall apart.

    If the bees find them suitable, more power to ’em!

    And I realized the cut-off ends fit in the rotary. Witticisms engraved on bamboo could become the New Hotness:

    Laser engraved bamboo
    Laser engraved bamboo

    Stipulated: I’m barely half-right about being a wit …

    The OpenSCAD source code as a GitHub Gist:

    // Bee Tunnel Nest Mount
    // Ed Nisley – KE4ZNU
    // 2026-04-26
    include <BOSL2/std.scad>
    Layout = "Show"; // [Build,Show,Window,Bundle,Tabs]
    BundleOD = 35.0;
    BundleOffset = 0.0;
    SlotDepth = 18.0;
    SlotGap = 1.2;
    /* [Hidden] */
    HoleWindage = 0.2;
    Protrusion = 0.01;
    NumSides = 3*2*4;
    Clearance = 0.3;
    //$fn=NumSides;
    WallThick = 2.0;
    MountHeight = 1.5*BundleOD;
    MountWidth = 1.5*BundleOD + BundleOffset;
    ClipOA = [SlotDepth + WallThick,SlotGap + 2*WallThick,MountHeight];
    BundleCtr = [-WallThick/2,ClipOA.y + MountWidth/2 + BundleOffset/2,MountHeight/2];
    TabOA = [0.7*SlotDepth,5.0,0.7*WallThick];
    TabOffset = 0.2*SlotDepth;
    TabOC = MountHeight/2;
    TabClearance = [4*Clearance,0,Clearance];
    //—–
    // Define things
    module BundleMount() {
    difference() {
    cuboid([WallThick,MountWidth + ClipOA.y,MountHeight],
    rounding=3.0,edges=[TOP+BACK,BOTTOM+BACK],anchor=FRONT+RIGHT);
    back(BundleCtr.y)
    xcyl(3*WallThick,d=BundleOD);
    for (j=[-1,1],k=[-1,1])
    translate([BundleCtr.x,j*BundleOD/2 + BundleCtr.y,k*BundleOD/2])
    xcyl(3*WallThick,d=3.0,$fn=6);
    }
    }
    module WindowMount() {
    difference() {
    cuboid(ClipOA,rounding=3.0,edges=[TOP+LEFT,BOTTOM+LEFT],
    anchor=FRONT+RIGHT);
    left(WallThick) back(WallThick)
    cuboid([2*SlotDepth,SlotGap,2*MountHeight],anchor=FRONT+RIGHT);
    for (k=[-1,1])
    translate([-(ClipOA.x – TabOffset),-Protrusion,k*TabOC/2])
    cuboid([TabOA.x + TabClearance.x,WallThick + 2*Protrusion,TabOA.y + 2*TabClearance.z],anchor=FRONT+LEFT);
    }
    }
    module Tabs() {
    for (j=[-1,1])
    fwd(j*TabOC/2)
    cuboid(TabOA,anchor=BOTTOM+LEFT) position(LEFT+TOP)
    prismoid(size1=[3*SlotGap,TabOA.y],size2=[0,TabOA.y/2],
    h=(WallThick – TabOA.z) + SlotGap/3,anchor=BOTTOM+LEFT);
    }
    module Assembly() {
    union() {
    BundleMount();
    WindowMount();
    left(ClipOA.x – TabOffset – TabClearance.x)
    xrot(-90)
    Tabs();
    }
    }
    //—–
    // Build things
    if (Layout == "Bundle") {
    BundleMount();
    }
    if (Layout == "Window") {
    WindowMount();
    }
    if (Layout == "Tabs") {
    Tabs();
    }
    if (Layout == "Show") {
    Assembly();
    }
    if (Layout == "Build") {
    yrot(90)
    Assembly();
    }
  • Battery Organizer

    Battery Organizer

    A small box has been holding an assortment of batteries during their out-of-service phase and I finally made a lid to keep the contents from flopping around:

    Battery organizer
    Battery organizer

    The cardboard prototypes record the journey toward the black acrylic lid. The final LightBurn layout:

    Battery Collector - LightBurn layout
    Battery Collector – LightBurn layout

    For whatever it’s worth, the box holds:

    The first four suitable & identical screws from the Tray o’ Tiny Screws hold the lid down. The ToTS contains screws and suchlike harvested from all the gadgetry headed for the recycling pile, making it a reliable source for any occasion.

  • Pressure-washed Stove Grates

    Pressure-washed Stove Grates

    Be it hereby declared: laying the absurdly heavy cast-iron grates from the stove on sawhorses in the driveway and pressure-washing them produces a dramatic improvement:

    Pressure-washed stove grates
    Pressure-washed stove grates

    They’re now devoid of the oil / grease / carbon accumulated during their decade of existence, little of which can be removed by hand; the shiny spots on the front right shrug off all solvents in my armory. The black finish still has plenty of scrapes & scuffs, but it’s no longer annoying.

    You might think Samsung stove grates would fit in a Samsung dishwasher, but they’re too big and too heavy.

    Also for the record: cyanoacrylate adhesive works wonderfully well to hold their little rubber feet in place.

  • Whirlpool Clothes Dryer: Thermal Cutoff Trip

    Whirlpool Clothes Dryer: Thermal Cutoff Trip

    A bit less than a year after replacing all the thermal switches / cutoffs / thermostats in the Whirlpool clothes dryer, the Thermal Cutoff went open-circuit. It’s located at the top of the heater duct:

    Whirlpool dryer - heater duct top
    Whirlpool dryer – heater duct top

    The wiring diagram lists it as tripping at 350 °F and “NOT RESETTABLE”:

    Whirlpool dryer - wiring diagram - detail
    Whirlpool dryer – wiring diagram – detail

    Curiously, the replacement switch had only one mark:

    Whirlpool Clothes Dryer - thermal cutoff - marking
    Whirlpool Clothes Dryer – thermal cutoff – marking

    I find it difficult to believe anybody would build a thermal cutout at 309°F = 154 °C.

    Crushing it with a Vise-Grip reveals the interior:

    Whirlpool Clothes Dryer - thermal cutoff - disassembled
    Whirlpool Clothes Dryer – thermal cutoff – disassembled

    I don’t know what permanently opens the circuit in there, but it definitely happened. The contacts remain unblemished, so they were pressed firmly together until the end.

    With nothing to lose, I reinstalled the Thermal Cutoff I removed last year (*) and the dryer works fine again.

    It is possible lint accumulating in the filter bag I added to the exhaust vent restricted the airflow enough to overheat the cutoff, but the Operating Thermostat should keep the air around 155 °F and the Hi Limit thermostat should have tripped at 250 °F, long before the temperature reached 350°F.

    Another cutoff will arrive shortly and will remain in the Box o’ Dryer Parts against future need.

    (*) Which is why I keep the old parts around, because a dubious part on hand is much better than the new part I might not be able to get due to, oh, “supply chain issues”.

  • Oak Stool Leg Creak

    Oak Stool Leg Creak

    Our square oak stool developed an annoying creak in two of its legs, resulting in a teardown & glue-up.

    The legs come in pairs held in place by snug screw fittings:

    Oak Stool Legs - mechanical joint
    Oak Stool Legs – mechanical joint

    The screw on the left slides into the tapered fitting on the right and latches firmly in place: no creaks in there! I have no idea what that fitting is called; my search-fu is unavailing.

    In any event, the offending legs were loose enough to admit a 6 mil = 0.16 mm miniblind snippet shim:

    Oak Stool Legs - loose joint
    Oak Stool Legs – loose joint

    Our Young Engineer, having taken up woodworking as a serious hobby, suggested the joint might have a loose dowel, which will be difficult to fix. Peering into the gap with a flashlight below showed that was the case:

    Oak Stool Legs - dowel revealed
    Oak Stool Legs – dowel revealed

    While it might be possible to force the joint apart enough to properly re-glue the dowels, I opted for a half measure by applying a spreader and easing wood glue into the gaps using the shim:

    Oak Stool Legs - gluing
    Oak Stool Legs – gluing

    An overnight session with the pipe clamp eliminated the creak, at least for now:

    Oak Stool Legs - clamping
    Oak Stool Legs – clamping

    The blue-and-yellow clamp fixed the loose splinter you didn’t notice in the second picture.

    Traces of glue along inside the joints suggest I’d done something like in the deep past. Ideally, I’ve learned enough to get it right this time.

  • Steel Shelving Foot Pads

    Steel Shelving Foot Pads

    All of the plastic pads vanished from the legs of a steel shelf unit somewhere along the way:

    Steel Shelving Foot Pads - post shape
    Steel Shelving Foot Pads – post shape

    Some solid modeling produced a suitable replacement shape:

    Steel Shelving Foot Pads - no pegs - solid model
    Steel Shelving Foot Pads – no pegs – solid model

    A few prototypes (with a broken OEM version at lower left) matched the model to reality:

    Steel Shelving Foot Pads - test pieces
    Steel Shelving Foot Pads – test pieces

    They’re natural & black TPU, because the job requirements include being tough and bendy:

    Steel Shelving Foot Pads - installed
    Steel Shelving Foot Pads – installed

    Each one takes about half an hour to ooze from the Makergear M2, so after verifying the prototype’s fit, printing four at a time makes sense:

    Steel Shelving Foot Pads - slicer
    Steel Shelving Foot Pads – slicer

    The OpenSCAD code includes the pegs in the original and the first chunky TPU version:

    Steel Shelving Foot Pads - with pegs - solid model
    Steel Shelving Foot Pads – with pegs – solid model

    It turns out they don’t have any obvious benefit in a TPU pad, so they’re disabled in the code.

    Now those legs sit firmly on the floor and the post tops aren’t nearly so threatening.

    The OpenSCAD source code as a GitHub Gist:

    // Steel Shelf Foot Pads
    // Ed Nisley – KE4ZNU
    // 2026-04-18
    include <BOSL2/std.scad>
    /* [Hidden] */
    Protrusion = 0.01;
    NumSides = 4*9;
    $fn=NumSides;
    Clearance = 1.0/2;
    WallThick = 1.0 + Clearance;
    BaseThick = 2.0;
    PadOAH = BaseThick + 11.0;
    RollID = 6.4;
    RollOD = 7.4 + Clearance;
    RollOffset = 29.5;
    LegThick = 0.5 + 2*Clearance;
    Pins = [
    [-(RollOD/2), (RollOffset + RollOD/2),0],
    [(RollOffset + RollOD/2), -(RollOD/2),0],
    ];
    //—–
    // Build things
    union() {
    difference() {
    union() {
    for (pin = Pins)
    translate(pin)
    cyl(PadOAH,d=RollOD + 2*WallThick,anchor=BOTTOM);
    translate([-(WallThick + LegThick),-(WallThick + LegThick),0])
    cuboid([2*WallThick + LegThick,WallThick + LegThick + Pins[0].y,PadOAH],
    anchor=BOTTOM+LEFT+FRONT);
    translate([-(WallThick + LegThick),-(WallThick + LegThick),0])
    cuboid([WallThick + LegThick + Pins[1].x,2*WallThick + LegThick,PadOAH],
    anchor=BOTTOM+LEFT+FRONT);
    cyl(PadOAH,r=(WallThick + LegThick),anchor=BOTTOM);
    }
    up(BaseThick)
    cyl(PadOAH,r=LegThick,anchor=BOTTOM);
    up(BaseThick)
    for (pin = Pins)
    translate(pin)
    cyl(PadOAH,d=RollOD,anchor=BOTTOM);
    up(BaseThick) {
    translate(Pins[0])
    cuboid([RollOD/2,RollOD/2,PadOAH],anchor=BOTTOM+LEFT+BACK);
    translate(Pins[1])
    cuboid([RollOD/2,RollOD/2,PadOAH],anchor=BOTTOM+RIGHT+FRONT);
    }
    up(BaseThick) {
    fwd(LegThick)
    cuboid([LegThick,Pins[0].y + LegThick,PadOAH],anchor=BOTTOM+RIGHT+FRONT);
    left(LegThick)
    cuboid([Pins[1].x + LegThick,LegThick,PadOAH],anchor=BOTTOM+LEFT+BACK);
    }
    }
    if (false)
    for (pin = Pins)
    translate(pin) {
    cyl(PadOAH,d=RollID/2,anchor=BOTTOM);
    for (a = [0,90])
    zrot(a)
    cuboid([1.0,RollID – 2*Clearance,PadOAH],anchor=BOTTOM);
    }
    }