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: Electronics Workbench

Electrical & Electronic gadgets

  • Branson 200 Ultrasonic Cleaner: Wiring Fix

    Branson 200 Ultrasonic Cleaner: Wiring Fix

    Our ancient Branson 200 Ultrasonic Cleaner began behaving erratically due to water seeping under the rather casual seal from last year’s fix. Although drying the switches let it start up again, it would run for only a few seconds before shutting down again, which suggested a deeper problem than just the switches.

    Take a picture of the PCB’s component side:

    Branson 200 Ultrasonic Cleaner - PCB component side
    Branson 200 Ultrasonic Cleaner – PCB component side

    And of the solder side:

    Branson 200 Ultrasonic Cleaner - PCB solder side
    Branson 200 Ultrasonic Cleaner – PCB solder side

    Transform those pictures to be the nice real rectangles shown above, resize to a common pixel format, mirror the solder side, turn it into a layer atop the component side, then tweak its opacity to make both sides visible at once:

    Branson 200 Ultrasonic Cleaner - PCB overlay
    Branson 200 Ultrasonic Cleaner – PCB overlay

    Some pondering produces a partial schematic of the left half of the board:

    Branson 200 Ultrasonic Cleaner - partial schematic
    Branson 200 Ultrasonic Cleaner – partial schematic

    The 1:1 transformer is constantly powered, so the ON button connects the 120 V (!) half-wave rectified output to the +12V supply bus, with the 750 Ω resistor dropping most of the voltage while the switch is pressed.

    The hotwired +12V supply forces the relay closed, which (in some as-yet unidentified way) fires up a +12V power source to hold the relay closed, with the 555 timer driving an MC14060 14-bit divider to count down the time until it turns itself off.

    Reminder: this design dates back to the days when a pair of chips and a handful of through-hole components cost less than one of those fancy microcontroller thingies.

    Plug the cleaner into an isolation transformer and trace the half-wave rectified signal through ON button to find it got all the way to the contact on the end of the orange wire in the connector, but did not reach the pin header on the PCB.

    A closer look at the connector revealed a broken contact on the white wire, which I (rather crudely) soldered together while considering my choices:

    Branson 200 Ultrasonic Cleaner - soldered contact
    Branson 200 Ultrasonic Cleaner – soldered contact

    While plugging that wire back in place, this happened:

    Branson 200 Ultrasonic Cleaner - another broken contact
    Branson 200 Ultrasonic Cleaner – another broken contact

    Neither of those are the (presumably) similarly failed orange wire, but even I can get a clue from three similar failures.

    So I replaced the OEM connector with a JST-XHP 2.54 mm connector from an assortment I got for another project, replaced the chunky 22 AWG wires with flexy 26 AWG silicone wires in the same cheerful rainbow colors, and it began working perfectly again.

    The buttons needed another water seal, so I tweaked the previous layout to kiss-cut GITD tape and through-cut colorful vinyl sheets:

    Branson 200 Ultrasonic Cleaner - power button cutting
    Branson 200 Ultrasonic Cleaner – power button cutting

    Capped with a transparent cover sheet cut from a pack of PDA screen protectors (remember PDAs?):

    Branson 200 Ultrasonic Cleaner - power button cover
    Branson 200 Ultrasonic Cleaner – power button cover

    In truth, the GITD tape is too thick, so I’ll probably repeat this dance later this year.

    FWIW, I was totally ready to buy a new ultrasonic cleaner, but all of them have scathing one-star Amazon reviews, to the extent I decided fixing this cleaner would be much easier than fixing a new one that’s been cheapnified to the point of no return. A common complaint seems to be water leaking into their capacitive switches and killing the circuitry stone cold dead: not an improvement over this one.

  • 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.

  • 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”.

  • Kensington Expert Mouse Trackball: Switch Failure

    Kensington Expert Mouse Trackball: Switch Failure

    All of my Kensington Expert Mouse Trackballs have worked fine for the last several years, despite their previous history of scroll ring troubles, until the main button on the trackball at my left hand stopped responding to thumb pressure.

    You can tell that button has done a lot of clicking:

    Kensington Expert Mouse Trackball - worn button
    Kensington Expert Mouse Trackball – worn button

    The switch layout comes as no surprise:

    Kensington Expert Mouse Trackball - switch layout
    Kensington Expert Mouse Trackball – switch layout

    Those are Genuine Omron D2F-01 SPDT switches and the replacements are Genuine Anonymous D2F-01F. While I had the cover off, I replaced all four switches.

    Protip: The black cable on the right must go under the three wires between the PCBs. Arranged as shown, the scroll ring will drag on the cable.

    I dismantled the switches and put their Common bar under the microscope. I believe these contacts rest on the Normally Closed switch terminal, which is electrically inert:

    Kensington Expert Mouse Trackball - NC contacts
    Kensington Expert Mouse Trackball – NC contacts

    Three of them have about the same amount of wear:

    Kensington Expert Mouse Trackball - NC contact 2
    Kensington Expert Mouse Trackball – NC contact 2

    The leftmost one looks worse:

    Kensington Expert Mouse Trackball - NC contact 1
    Kensington Expert Mouse Trackball – NC contact 1

    Flipping them over (in the same order) exposes what I think are their Normally Open contacts responsible for all the button action:

    Kensington Expert Mouse Trackball - NO contacts
    Kensington Expert Mouse Trackball – NO contacts

    Again, the rightmost three look about the same and the contact on the left shows more wear, plus what looks like a soot streak:

    Kensington Expert Mouse Trackball - NO Contacts 1 2
    Kensington Expert Mouse Trackball – NO Contacts 1 2

    A closer look:

    Kensington Expert Mouse Trackball - NO Contact 1
    Kensington Expert Mouse Trackball – NO Contact 1

    These things operate at logic levels, so most of the damage surely comes from mechanical erosion and the soot is pulverized metal.

    While waiting for the switches to arrive, I deployed an Expert Mouse Trackball from a PC in the Basement Shop. The repaired unit went down there, so its new switches should survive longer even if they’re of mediocre quality.

  • Auto Parking Light LED Bulbs: FAIL

    Auto Parking Light LED Bulbs: FAIL

    After about eight years and a similar failure last year, this came as no surprise:

    White W5W Parking Light - failed chips
    White W5W Parking Light – failed chips

    It’s a W5W “parking light” in the same fixture as the melty halogen high-beam bulbs (used as daytime running lights at half power), so it gets toasted on those occasions when we drive somewhere.

    The adhesive holding the LED strip to the aluminum shell fossilized and came loose:

    White W5W Parking Light - failed adhesive
    White W5W Parking Light – failed adhesive

    Now that I know what to look for, I’d get LED bulbs with chips soldered directly to the PCB, although it’s not obvious what holds the PCB to the aluminum frame.

    I reinstalled the original incandescent bulbs.

  • LED Garage Light: Desk Lamp Upcycling

    LED Garage Light: Desk Lamp Upcycling

    One of the heatsink panels from the defunct LED garage light now casts a uniform warm-white glow on my desk:

    LED Garage Light - desk light
    LED Garage Light – desk light

    A PCB intended as a lithium battery charger serves as a constant-current supply:

    LED Garage Light - constant current driver
    LED Garage Light – constant current driver

    The three trimpots, from left to right:

    • Constant-voltage limit adjustment
    • Full-charge current setpoint (irrelevant here)
    • Constant-current limit adjustment

    The as-received trimpot settings will be wildly inappropriate for a nominal 10 W COB LED array, so:

    • Connect the output to about 10 Ω of power resistors
    • … with an ammeter in series
    • Connect the input to a 12 VDC / 1-ish A wall wart
    • Adjust the output voltage to 10 V
    • Adjust the output current to 900 mA

    As long as the voltage limit is over about 10 V, it will (likely) never matter, as the LED forward drop doesn’t vary much with temperature. Setting it to something sensible keeps it out of the way.

    The middle trimpot apparently sets a voltage for a comparator to light an LED when the battery current drops below that level as it reaches full charge.

    Although the regulator touts its high efficiency, it does run hot and a heatsink seemed in order:

    LED Garage Light - heatsink
    LED Garage Light – heatsink

    Stipulated: the fins run the wrong way and it’s sitting in the updraft from the main heatsink. It’s Good Enough™.

    The switch on the top comes from the collection of flashlight tailcap switches and controls the 12 V input power. It’s buried up to its button in a generous dollop of JB Kwik epoxy, which seemed the least awful way to get that done.

    The solid model looks about like you’d expect:

    LED Lamp Driver case - switch housing - show solid model
    LED Lamp Driver case – switch housing – show solid model

    The OpenSCAD code exports the (transparent) lid as an SVG so I can import it into LightBurn and laser-cut some thin acrylic. Two tape snippets hold the lid in place pending more power-on hours, after which I’ll apply a few dots of cyanoacrylate adhesive and call it done.

    The case builds in two pieces that glue together to avoid absurd support structures:

    LED Lamp Driver case - switch housing - build solid model
    LED Lamp Driver case – switch housing – build solid model

    A 3D printed adapter goes between the desk lamp arm and the lamp heatsink bolt:

    LED Lamp Driver case - arm adapter - solid model
    LED Lamp Driver case – arm adapter – solid model

    The OpenSCAD source code files for the case and adapter arm as a GitHub Gist:

    // LED Lamp arm adapter
    // Ed Nisley – KE4ZNU
    // 2026-03-18
    include <BOSL2/std.scad>
    Layout = "Adapter"; // [Show,Build,ArmClamp,SinkClamp,Adapter]
    /* [Hidden] */
    HoleWindage = 0.2;
    Protrusion = 0.01;
    Gap = 5.0;
    $fn=5*3*4;
    HoleOC = 45.0;
    ArmRad = 7.5;
    ArmWidth = 11.3;
    SinkOD = 11.5;
    SinkThick = 3.2;
    SinkOC = 20.0;
    ClampThick = 5.0; // outside sink, watch thinning due to hull()
    // Define things
    // Screw & bushings in lamp arm bracket
    // … over-long bushings to prevent coincident surfaces
    module ArmClamp() {
    BushingThick = 1.5;
    BushingOD = 9.0;
    union() {
    ycyl(ArmWidth,d=4.0 + HoleWindage); // central M4 screw
    for (j=[-1,1]) {
    back(j*(ArmWidth – BushingThick + Protrusion)/2)
    ycyl(BushingThick + Protrusion,d=BushingOD);
    back(j*(ArmWidth + 10)/2)
    cuboid([2*ArmRad,10,2*ArmRad]);
    }
    }
    }
    module SinkClamp() {
    union() {
    ycyl(2*SinkOC,d=6.0 + HoleWindage); // central M6 screw
    for (j=[-1,1])
    back(j*SinkOC/2) {
    ycyl(SinkThick + Protrusion,d=SinkOD);
    cuboid([SinkOD,SinkThick + Protrusion,2*SinkOD]);
    }
    }
    }
    module Adapter() {
    difference() {
    hull() {
    right(HoleOC)
    ycyl(ArmWidth,r=ArmRad);
    ycyl(SinkOC + SinkThick + 2*ClampThick,d=SinkOD);
    }
    right(HoleOC)
    ArmClamp();
    SinkClamp();
    }
    }
    // Build it
    if (Layout == "ArmClamp")
    ArmClamp();
    if (Layout == "SinkClamp")
    SinkClamp();
    if (Layout == "Adapter")
    Adapter();
    if (Layout == "Build")
    up(SinkOD/2)
    yrot(-atan((ArmRad – SinkOD/2)/HoleOC))
    Adapter();
    // LED Constant-current driver case
    // Ed Nisley – KE4ZNU
    // 2026-03-15
    include <BOSL2/std.scad>
    Layout = "Show"; // [Show,Build,Case,Lid,LidSVG,Switch]
    /* [Hidden] */
    ThreadThick = 0.2;
    HoleWindage = 0.2;
    Protrusion = 0.01;
    Gap = 5.0;
    WallThick = 1.8;
    TapeThick = 1.5;
    DriverOA = [48.5,13.5 + TapeThick,23.5]; // PCB forward Y, pots along top to rear
    SinkOA = [31.5,12.0,15.5]; // fins forward
    SinkOffset = [(DriverOA.x – SinkOA.x)/2,0,2.0]; // from lower left front corner of PCB
    AdjPots = [14,24,34]; // screwdriver adjust offsets
    AdjOD = 3.0; // … access hole dia
    CaseOA = DriverOA + [2*WallThick,2*WallThick,2*WallThick];
    echo(CaseOA=CaseOA);
    LidOA = [CaseOA.x – WallThick,CaseOA.z – WallThick,1.0];
    Cables = [8.0,3.0 + WallThick/2,LidOA.z];
    SwitchWireOC = DriverOA.x – 6.0;
    SwitchCapBase = [DriverOA.x + WallThick,DriverOA.y + WallThick];
    SwitchCapTop = [DriverOA.x,12.0];
    SwitchCavity = [25.0,10.5,5.5];
    // Define things
    module Lid() {
    difference() {
    cuboid(LidOA,anchor=BOTTOM+FWD+LEFT);
    for (i = AdjPots)
    translate([i,LidOA.y – AdjOD/2 – WallThick/2,-Protrusion])
    cyl(LidOA.z + 2*Protrusion,d=AdjOD,anchor=BOTTOM,$fn=8,spin=180/8);
    translate([LidOA.x/2,-Protrusion,-Protrusion])
    cuboid(Cables + [0,Protrusion,2*Protrusion],rounding=1.0,edges=[BACK+LEFT,BACK+RIGHT],anchor=BOTTOM+FWD);
    }
    }
    module SwitchBox() {
    difference() {
    prismoid(SwitchCapBase,SwitchCapTop,SwitchCavity.z,anchor=BOTTOM);
    down(Protrusion)
    cuboid(SwitchCavity + [0,0,2*Protrusion],anchor=BOTTOM);
    hull()
    for (i=[-1,1])
    right(i*SwitchWireOC/2)
    zcyl(CaseOA.z,d=3.0,$fn=8,spin=180/8);
    }
    }
    module Case() {
    difference() {
    cuboid(CaseOA,chamfer=WallThick/2,anchor=BOTTOM+FWD+LEFT);
    translate([WallThick,WallThick + Protrusion,WallThick])
    cuboid(DriverOA + [0,WallThick + Protrusion,0],anchor=BOTTOM+FWD+LEFT);
    translate(SinkOffset + [WallThick,WallThick + 2*Protrusion,WallThick])
    cuboid(SinkOA,anchor=BOTTOM+BACK+LEFT);
    for (i=[-1,1])
    translate([i*SwitchWireOC/2 + CaseOA.x/2,CaseOA.y/2,CaseOA.z/2])
    zcyl(CaseOA.z,d=2.0,anchor=BOTTOM,$fn=8,spin=180/8);
    translate([WallThick/2,(CaseOA.y + LidOA.z),WallThick/2])
    xrot(90)
    scale([1,1,2])
    Lid();
    }
    }
    // Build it
    if (Layout == "Switch")
    SwitchBox();
    if (Layout == "Case")
    Case();
    if (Layout == "Lid")
    Lid();
    if (Layout == "LidSVG")
    projection(cut=true)
    Lid();
    if (Layout == "Show") {
    Case();
    translate(SinkOffset + [WallThick,WallThick + 2*Protrusion,WallThick])
    color("Gray",0.7)
    cuboid(SinkOA,anchor=BOTTOM+BACK+LEFT);
    translate([CaseOA.x/2,CaseOA.y/2,CaseOA.z])
    SwitchBox();
    translate([WallThick/2,CaseOA.y,WallThick/2])
    xrot(90)
    color("Gray",0.7)
    Lid();
    }
    if (Layout == "Build") {
    fwd(Gap)
    xrot(90)
    Case();
    translate([CaseOA.x/2,(Gap + CaseOA.y/2),0])
    SwitchBox();
    }
  • Magnetic Stirrer: Interior

    Magnetic Stirrer: Interior

    Of late, the magnetic stirrer mixing my morning cocoa occasionally doesn’t start spinning when I turn it on, which calls for some investigation.

    Removing the four obvious screws concealed under the rubber feet and prying off bottom cover reveals the trivial innards:

    Magnetic stirrer - interior
    Magnetic stirrer – interior

    The speed adjustment pot holds the little circuit board in place, with the green LED setting its jaunty angle.

    The motor spins a pair of neodymium magnets:

    Magnetic stirrer - magnet holder
    Magnetic stirrer – magnet holder

    I expected a gearbox instead of the direct drive setup.

    Perhaps those whirling neodymium magnets have been slowly demagnetizing the motor’s internal (alnico?) magnets.

    The motor brushes seem to be a pair of stiff wires, rather than carbon blocks, contacting the commutator, the wear from which may account for motor’s decreasing startup enthusiasm. Even though I didn’t expect a BLDC motor, this one may have been overly cheapnified.

    Perhaps kickstarting the motor with the steel fork I use to fish the stirrer magnet out of the mug will get the thing going.