Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
According to the sticker inside, I’ve been using my RayTek IR Thermometer since 2000. At some point in the last dozen or so year, Fluke Borged RayTek, which means yellow plastic instead of gray.
The pushbutton switch behind the trigger has recently gone from intermittent to nonfunctional, but everything else still works fine: some simple surgery should suffice…
The handle has a flip-down cover, for the battery compartment and °C/°F switch, that pivots on molded hinges. The cover’s hinge pins are rectangular with a slight bevel and the case sockets have a notch that will just clear a properly aligned pin. Given this hint, you’ll get the cover off much faster than I did:
RayTek IR Thermometer – handle joint
Remove the obvious screw and press the latches while prying the two halves apart. A small screwdriver helps persuade the latches to release their death grip:
RayTek IR Thermometer – case latches
The parts heap didn’t have any suitable through-hole pushbutton switches, but I managed to solder an SMD switch in place; the original switch is parked atop the IC for reference. Yes, the white button is slightly taller than the original black one, but it doesn’t matter:
RayTek IR Thermometer – new switch installed
Then it’s just a matter of tucking everything in place:
This may not be a LibreOffice problem, but that’s where it shows up: the font selection dialog won’t display fonts with nonstandard Style names. There is, of course, no documentation anywhere (that I can find, anyway) on what Style names are permitted, so you discover this only when a font style that’s properly installed and accessible by other programs (like, say, Inkscape or Scribus) doesn’t render properly and doesn’t appear in the list.
In Xubuntu 12.10, LibreOffice 3.6.2.2 can’t handle the American Typewriter font style called Medium, which is what I’ve been using for the return address field on my (very few, these days) mail envelopes. Over the years, various versions of OpenOffice and LibreOffice have alternately accepted and rejected the Medium style, so this isn’t exactly a regression. It is, however, Yet Another Annoyance.
The solution, hinted at in that thread, involves using FontForge to rename the offending Style to, say, Regular, then saving the font. It’s actually the Weight property, hidden in Element → Font Info → PS Names tab. In this case, I changed the word “Medium” in the Fontname, Name for Humans, and Weight fields to “Regular”, which also updates the values in the TTF Names tab.
I save the modified font files in ~/.local/share/fonts using TrueType format, just to be sure I don’t confuse them with the original Postscript version in /usr/share/fonts/custom, delete the original, and then run fc-cache -v -f to update the caches. This surely isn’t the cleanest way to make it happen and almost certainly isn’t allowed by the Adobe EULA I agreed to, back when I actually bought the fonts, but so it goes.
It turns out that if you put convenient symlinks in your directories, then use them to build a LibreOffice document, LO will cheerfully put those paths into the graphic file links inside its XML files. That will produce horrible breakage on a new system without those links. We’ve come to the conclusion that the only way to keep LO happy is to create a Pictures directory in whatever directory holds the document file, then put all of the document’s image files into that directory, and make sure LO stores relative paths. Of course, this leaves us with the prospect of updating a whole bunch of existing (and, alas, horribly broken) documents by hand, which is unappealing. My previous solution worked for a single file, but now it’s time for some scripting…
This would probably be easier in Python, but Bash works fine after you get the quoting straightened out. This script builds several other scripts that actually do the heavy lifting, because that way you can inspect the scripts before running them to verify that you’re not about to make a bad situation much, much worse. I recommend copying the presentations into another directory, running this script, check the output scripts, run them by hand, and then copy the fixed files and the Pictures directory back where they belong.
You must tweak the actual paths to the pictures to match your situation; for these documents, one simple change sufficed for all the image files. Those paths are not variables, because I can barely keep the quoting straight without adding another layer of indirection. Make sure all the paths match up, verify the scripts before you run them, and don’t trust anything you see.
CAUTION: It’s highly likely that the multiple levels of character escaping required to make these listings appear correctly on the screen will produce incorrect results when copied-and-pasted. You can download the script file as FixGraphics.sh.odt, which is a bare-ASCII TXT file (which you must rename to eliminate the ODT extension, then make executable as a shell script), to see how it compares.
The main FixGraphics.sh script, with some key lines highlighted:
#!/bin/bash
echo "Extract list of images from all ODP files"
rm images.txt
for f in *odp
do
unzip -p "$f" content.xml | sed 's/></>\n</g' | grep Cameras | cut -d \" -f 2 | sort -u >> images.txt
done
echo "Make source file name list"
# strip off leading relative pathing, set actual absolute path, un-quote blanks and special characters, add quotes
sed 's/..\/..\/..\/../\/mnt/' images.txt | sed 's/%20/ /g' | sed 's/&/\&/g' | sed 's/^.*/\"&\"/' > source.lst
echo "Make target file name list"
# set relative to current directory
sed 's/\/mnt\/bulkdata\/Cameras\/MCWN/\.\/Pictures/' source.lst > target.lst
echo "Make target directory list"
# must add trailing quote stripped by dirname
rm dirs.lst
cat target.lst | while read tline ; do
tdir=`dirname "$tline"`
echo ${tdir}\"
done > dirs.lst
echo "Create target directory structure script"
rm mkdirs.sh
sort -u dirs.lst | while read dline ; do
echo mkdir --parents ${dline}
done > mkdirs.sh
chmod u+x mkdirs.sh
echo "Create image file copy script"
rm cpjpgs.sh
cat dirs.lst | while read dline ; do
echo cp -n -t ${dline}
done > cptemp.txt
paste cptemp.txt source.lst > cpjpgs.sh
chmod u+x cpjpgs.sh
echo "Create ODP fixup script"
echo "for f in *odp ; do" > fixodp.sh
echo "unzip -p \"\$f\" content.xml > raw.xml" >> fixodp.sh
echo "sed 's/..\/..\/..\/..\/bulkdata\/Cameras\/MCWN/\.\.\/Pictures/g' raw.xml > content.xml" >> fixodp.sh
echo "zip \"\$f\" content.xml" >> fixodp.sh
echo "done" >> fixodp.sh
echo "rm raw.xml content.xml" >> fixodp.sh
chmod u+x fixodp.sh
Run mkdirs.sh, cpjpgs.sh, and fixodp.sh: then it Just Works.
Some of the tricky parts:
The content.xml file may be stored in unformatted mode, with everything mushed together into one huge line. To make it readable and parse-able, insert a newline between each pair of adjoining angle brackets:
sed 's/></>\n</g'
This burst of line noise un-escapes the file name from the way LO stores it internally. Note that the middle sed command really does have the literal escape sequence ampersand-amp-semicolon in it and the ampersand in the last one is the sed-ism for “the whole matching string”:
sed 's/%20/ /g' | sed 's/&/\&/g' | sed 's/^.*/\"&\"/'
The difference between these two sed strings indicates the actual relative path to the Pictures subdirectory in the filesystem and the faked relative path from the LO pseudo-subdirectory where the document stores its internal state. The string of periods in the second command shows what LO stored for the original files in our documents; your mileage will certainly differ:
sed 's/\/mnt\/bulkdata\/Cameras\/MCWN/\.\/Pictures/' source.lst > target.lst
sed 's/..\/..\/..\/..\/bulkdata\/Cameras\/MCWN/\.\.\/Pictures/' raw.xml > content.xml
I don’t know how they could make the file linkages work better, but it’d be really nice if there were a less horrible way to fix the breakage.
The brass plate from this plaque rattled down the basement stairs(*) a while ago:
League of American Wheelmen plaque
As you might expect, the adhesive failed and has been replaced at least once. This time, I drilled a pair of 2-56 clearance holes in the plate, match-marked the wood with a punch, drilled a pair of tapping holes, and put it all back together.
There’s not much to see, but I’m pretty sure that plate won’t fall off ever again:
League of American Wheelmen plaque – detail
The lacquer finish has begun disintegrating, but I wasn’t in the mood to strip-and-restore that. The tile remains firmly affixed; when that falls out, it won’t be pretty.
The LAW long ago morphed into the League of American Bicyclists, after deeming Wheelmen as too gender-specific for the modern era.
(*) We hang plaques, certificates, diplomas, and suchlike on the walls beside the basement stairs. Every time we pass by, it’s an Ego Trip…
Three rack protectors have gone missing over the last few months, presumably being digested by the dishwasher’s grinder, so I ran off another batch:
Dishwasher Rack Protectors – on platform
I used the original solid model, shown here with the support structure outside for visibility:
Dishwasher rack protector – support model
I re-sliced the model to pick up whatever printer config tweakage happened since then. Those ribbed doodads snapped out easily and, in fact, some remained bonded to the platform:
Dishwasher Rack Protectors – support structures
No finishing required: just slide them over the pins atop a blob of acrylic caulk. Despite the few missing protectors, it does a good job of bonding them to the rack and sealing gaps in the worn vinyl coating.
I picked up a jar of ReRack glop on closeout duing my last pass through the Big Box Home Repair Store. It seemed a bit stiff, so I’ve added generous dollops of xylene, acetone, and MEK to thin it out; that’ll take a while to stabilize.
After beating the Samsung’s nozzle handle and hose into submission, I made a set of floor brush strips for the hard-floor attachment:
Floor brush strips – replacements in place
The original brushes had non-woven felt glued to a cleverly molded strip of white plastic, which lasted not very long at all. I’d replaced them (*) with wool fabric glued to hand-hewn strips of polypropylene cut from the usual blister pack material, but that was so labor-intensive as to make no sense at all; it did show that replacement brushes would work, though, which was the whole point. This view looks through a finished strip to the urethane glue and wool fabric:
Floor brush strip – manual version
Fortunately, there’s an easier way to make the strips:
Floor brush strip – solid model
Note that the smaller tab (the one in the front) is not centered on the midline. The openings for the larger tab in the floor brush housing seem to have a small offset, but it’s not worth worrying about. The printed ones are 4 layers thick, but I think 3 layers will work as well; that’s what the OpenSCAD source will produce.
This is one of the few situation where the hand-knitted top surface of a 3D-printed object is an advantage: that, plus the holes, provides enough griptitude for urethane glue to hold the fabric strips firmly in place.
Obviously, you print them in multiples:
Floor brush strips – on platform
A trial fit:
Floor brush strip – trial fit
They really are bowed slightly outward in the middle, which ensures there’s more pressure on the middle of the strip against the floor. I think the weird indented pattern in the brush housing under the strips was for a complex spring assembly that never made it into production; the OEM strips looked just like the ones I’m making, minus the perforations.
I glued two strips individually to make sure everything lined up, then glued these two in one operation and separated them with a razor knife:
Floor brush strips – gluing fabric
(*) It goes without saying that OEM replacement brushes weren’t available and, in fact, they have never been available at any time when we’ve owned the vacuum cleaner. Maybe I’m not looking in the right place, but so it goes.
The OpenSCAD source code, which you’ll want to print with Multiply set to maybe 8:
// Samsung Vacuum cleaner nozzle floor strips
// Ed Nisley KE4ZNU January 2013
Layout = "Build"; // Show, Build
//- Extrusion parameters must match reality!
// Print with +0 shells and 3 solid layers
ThreadThick = 0.25;
ThreadWidth = 2.0 * ThreadThick;
HoleWindage = 0.75;
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
Protrusion = 0.1; // make holes end cleanly
//----------------------
// Dimensions
Body = [6.0,59.0,3*ThreadThick]; // width, length, thick
Tab1 = [4.5,5.0,0.0]; // width, length, offset from centerline
Tab2 = [3.5,5.0,0.5];
HoleOC = 8.0; // adhesive anchoring holes
HoleDia = 1.0;
HoleSides = 4;
HoleMax = floor(Body[1]/(2*HoleOC));
echo("HoleMax: ",HoleMax);
//----------------------
// 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);
}
module ShowPegGrid(Space = 10.0,Size = 1.0) {
Range = floor(50 / Space);
for (x=[-Range:Range])
for (y=[-Range:Range])
translate([x*Space,y*Space,Size/2])
%cube(Size,center=true);
}
module BackingStrip() {
difference() {
union() {
translate([0,0,Body[2]/2])
cube(Body,center=true);
translate([Tab1[2],-1*Body[1]/2,Body[2]/2])
cube([Tab1[0],2*Tab1[1],Body[2]],center=true);
translate([Tab2[2],+1*Body[1]/2,Body[2]/2])
cube([Tab2[0],2*Tab2[1],Body[2]],center=true);
}
for (i = [-HoleMax:HoleMax])
translate([0,i*HoleOC,-Protrusion])
rotate(45)
PolyCyl(HoleDia,(Body[2] + 2*Protrusion),HoleSides);
}
}
//----------------------
// Build it!
ShowPegGrid();
if (Layout == "Show")
BackingStrip();
if (Layout == "Build")
rotate(90) BackingStrip();