With the amber front running light blinking away, it’s time to replace the decade-old Planet Bike Superflash behind the seat:

The new mount descends directly from the clamps holding the fairing strut on the handlebars and various hose clamps:

The central block has two quartets of brass inserts epoxied inside:

That means I can install the light, then mount the whole affair on the bike, without holding everything together while fiddling with overly long screws.
A trial fit with the not-yet-cut-to-length 25.3 (-ish) PVC pipe body tube:

The aluminum plates have the standard used-car finish: nice polish over deep scratches.
Although I’ve been thinking of mounting the light below the seat rail, as shown, it can also sit above the rail.
Mary hauls seedlings and suchlike to the garden in a plastic drawer bungied to the rack, with the SuperFlash serving as an anchor point; this light may need fine tuning for that purpose.
The OpenSCAD source code as a GitHub Gist:
// Rear running light clamp for Tour Easy seat strut | |
// Ed Nisley - KE4ZNU - 2021-09 | |
Layout = "Show"; // [Show,Build,Block] | |
Section = true; | |
/* [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; | |
LENGTH = 2; | |
inch = 25.4; | |
//---------------------- | |
// Dimensions | |
// Light case along X axis, seat strut along Y, Z=0 at strut centerline | |
LightOD = 25.4 + HoleWindage; | |
StrutOD = 5/8 * inch + HoleWindage; | |
PlateThick = 1/16 * inch; | |
WallThick = 2.0; | |
Kerf = ThreadThick; | |
Screw = [3.0,6.8,4.0]; // M3 OD=washer, length=nut + washers | |
Insert = [3.0,5.4,8.0 + 1.0]; // splined brass insert | |
RoundRadius = IntegerMultiple(Screw[OD]/2,0.5); // corner rounding | |
ScrewOC = [IntegerMultiple(StrutOD + 2*WallThick + Screw[ID],1.0), | |
IntegerMultiple(LightOD + 2*WallThick + Screw[ID],1.0)]; | |
echo(str("Screw OC: ",ScrewOC)); | |
BlockSize = [ScrewOC.x + Insert[OD] + 2*WallThick, | |
ScrewOC.y + Insert[OD] + 2*WallThick, | |
LightOD + StrutOD + 3*WallThick]; | |
echo(str("Block: ",BlockSize)); | |
BaseOffset = -(WallThick + LightOD/2); // block bottom to centerline | |
StrutOffset = LightOD/2 + WallThick + StrutOD/2; // light centerline to strut centerline | |
echo(str("Strut screw min: ",IntegerMultiple(PlateThick + WallThick + StrutOD/2 + Insert[LENGTH]/2,1.0))); | |
echo(str("Light screw min: ",IntegerMultiple(PlateThick + WallThick + LightOD/2 + Insert[LENGTH]/2,1.0))); | |
NumSides = 2*3*4; | |
//---------------------- | |
// 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, | |
h=Height, | |
$fn=Sides); | |
} | |
// Block with light along X axis | |
module Block() { | |
difference() { | |
hull() | |
for (i=[-1,1], j=[-1,1]) | |
translate([i*(BlockSize.x/2 - RoundRadius),j*(BlockSize.y/2 - RoundRadius),BaseOffset]) | |
cylinder(r=RoundRadius,h=BlockSize.z,$fn=NumSides); | |
for (i=[-1,1], j=[-1,1]) | |
translate([i*ScrewOC.x/2,j*ScrewOC.y/2,BaseOffset - Protrusion]) | |
rotate(180/8) | |
PolyCyl(Screw[ID],BlockSize.z + 2*Protrusion,8); | |
for (i=[-1,1], j=[-1,1]) | |
translate([i*ScrewOC.x/2,j*ScrewOC.y/2,0]) { | |
translate([0,0,-Protrusion]) | |
rotate(180/8) | |
PolyCyl(Insert[OD],Insert[LENGTH] + 1*Protrusion,8); | |
translate([0,0,(StrutOffset - Insert[LENGTH] - Kerf/2 + Protrusion)]) | |
rotate(180/8) | |
PolyCyl(Insert[OD],Insert[LENGTH] + 1*Protrusion,8); | |
} | |
translate([-BlockSize.x,0,0]) | |
rotate([0,90,0]) | |
cylinder(d=LightOD,h=2*BlockSize.x,$fn=NumSides); | |
translate([0,BlockSize.y,StrutOffset]) | |
rotate([90,0,0]) | |
cylinder(d=StrutOD,h=2*BlockSize.y,$fn=NumSides); | |
translate([0,0,StrutOffset]) | |
cube([2*BlockSize.x,2*BlockSize.y,Kerf],center=true); | |
cube([2*BlockSize.x,2*BlockSize.y,Kerf],center=true); | |
} | |
} | |
//- Build it | |
if (Layout == "Block") | |
if (Section) | |
difference() { | |
Block(); | |
rotate(atan(ScrewOC.y/ScrewOC.x)) | |
translate([0,BlockSize.y,0]) | |
cube(2*BlockSize,center=true); | |
} | |
else | |
Block(); | |
if (Layout == "Show") { | |
Block(); | |
color("Green",0.25) | |
translate([-BlockSize.x,0,0]) | |
rotate([0,90,0]) | |
cylinder(d=LightOD,h=2*BlockSize.x,$fn=NumSides); | |
color("Green",0.25) | |
translate([0,BlockSize.y,StrutOffset]) | |
rotate([90,0,0]) | |
cylinder(d=StrutOD,h=2*BlockSize.y,$fn=NumSides); | |
} | |
if (Layout == "Build") { | |
translate([-1.2*BlockSize.x,0,-BaseOffset]) | |
difference() { | |
Block(); | |
translate([0,0,BlockSize.z]) | |
cube(2*BlockSize,center=true); | |
} | |
translate([1.2*BlockSize.x,0,StrutOD/2 + WallThick]) | |
difference() { | |
rotate([180,0,0]) | |
translate([0,0,-StrutOffset]) | |
Block(); | |
translate([0,0,BlockSize.z]) | |
cube(2*BlockSize,center=true); | |
} | |
translate([0,0,StrutOffset - Kerf/2]) | |
rotate([180,0,0]) | |
intersection() { | |
Block(); | |
translate([0,0,StrutOffset/2]) | |
cube([2*BlockSize.x,2*BlockSize.y,StrutOffset],center=true); | |
} | |
} |