Posts

pgrep -f Matches Itself: Why Your "Wait for the Job" Loop Never Ends (and the PID-File Fix)

A common way to wait for a background job in a shell script is to poll for it by name: while pgrep -f "train.py" > /dev/null; do sleep 10; done echo "training finished" It looks right, and in an interactive terminal it usually works. But I've had this loop never finish twice on my home server, long after the job had exited. Both times the cause was the same: pgrep -f was finding a process that wasn't the job. Reproducing it This script starts a fake job (a 3-second sleep renamed to look like python train.py ), then waits for it with the loop above, run through bash -c , the way cron, ssh, nohup and many tools start commands: #!/bin/bash # Reproduce: a waiter started with `bash -c "..."` matches its own command line. # A fake "training job" that runs for 3 seconds: bash -c 'exec -a "python train.py" sleep 3' & # The waiter, started the way cron / ssh / nohup / systemd often start things: timeout 10 bash -c...

Local OCR with Ollama and Qwen2.5-VL: Perfect on Screenshots, Confidently Wrong on Blurry Photos

Image
I often need to get a table out of a screenshot: a parts list from a supplier page, a spec table from a PDF, a statement from an app that won't export. Cloud vision models do this well, but some screenshots I'd rather not upload anywhere. So I run OCR locally with Ollama and qwen2.5vl:7b , a 7B vision-language model, on my ASUS Ascent GX10. For this post I tested it on a parts table I generated, so the correct answer is known exactly. The short version: on a clean screenshot it was perfect, in about 5 seconds. On a small, blurry image it invented a part that isn't there , and it can't be trusted to add up the numbers it reads. Setup ollama pull qwen2.5vl:7b # about 6 GB Then a small script that sends the image to Ollama's chat API. It uses only the Python standard library: #!/usr/bin/env python3 """Local OCR with Ollama + qwen2.5vl: turn a screenshot (e.g. a table) into Markdown. The image never leaves your machine. Usage: python3 ocr_tabl...

Blogger API 403 "The caller does not have permission": Check Which Account Your Token Belongs To

I publish to two Blogger blogs from Python: this one, and a Traditional Chinese sister blog. One day every write to the Chinese blog started failing. Creating a page, updating an old post: everything came back with the same response: 403 { "error": { "code": 403, "message": "The caller does not have permission", "errors": [ { "message": "The caller does not have permission", "domain": "global", "reason": "forbidden" } ], "status": "PERMISSION_DENIED" } } The token was valid. Reading the blog worked. Writing to this English blog with the same token still worked. Only writes to the other blog failed. Here's how I tracked it down, and the checks I now run first whenever Blogger says "The caller does not have permission" . What the 403 actually means A 403 from the Blogger API is not a...

Transistor Base Resistor Calculator: NPN Switch Base Current, E24 Resistor and MCU Pin Limit

An NPN transistor can switch a load connected between the positive supply and its collector, with the emitter connected to ground. This calculator estimates the base current and resistor needed to drive it from a logic output. It rounds the resistor down to the next E24 value and checks the base current against your MCU pin limit. Logic high voltage (V) Load current Ic (mA) Minimum hFE Vbe (V) Overdrive factor MCU pin limit (mA) Calculate Enter values and press Calculate. The formula I b = overdrive factor × I c ÷ h FE R b = (V logic − V BE ) ÷ I b Use amperes for current when calculating resistance in ohms. The overdrive factor increases base current above the active-region estimate to help drive the transistor into saturation. The effective forced gain is h FE divided by the overdrive factor. Example: with a 5 V logic high, 100 mA load, minimum h FE of 100, V BE of 0.7 V, and an overdrive factor of 5, the target base current is 5 mA . The exact resistor is (5...

Battery Life Calculator: Runtime from mAh, Average Current, or an Active/Sleep Duty Cycle

Estimate how long a battery will last from its capacity and average current draw. If your circuit wakes briefly and then sleeps, enter the active and sleep currents and times instead. The usable-capacity percentage leaves room for capacity lost to temperature, battery age, and the circuit cutoff voltage. Mode Average current draw Active/sleep duty profile Capacity (mAh) Usable capacity (%) Average current draw (mA) Active current (mA) Active seconds per cycle Sleep current (µA) Sleep seconds per cycle Calculate Enter values and press Calculate. The formula Runtime (hours) = capacity (mAh) × usable capacity (%) ÷ 100 ÷ average current (mA) For an active/sleep cycle, first convert sleep current from µA to mA by dividing by 1000, then calculate the time-weighted average: I avg = (I active × t active + I sleep × t sleep ) ÷ (t active + t sleep ) Example: a 2000 mAh battery at 80% usable capacity provides 1600 mAh. A circuit drawing 100 mA for 2 seconds and 100 µ...

systemd "start-pre operation timed out": Why Your ExecStartPre Wait Loop Dies After 90 Seconds

A common way to make a service wait for the network is a small retry loop in ExecStartPre : try to reach the server, sleep, try again. I use one in the systemd user service that keeps Claude Code Remote Control running 24/7 on my GX10, because After=network-online.target does nothing in a user unit. It worked fine, until a reboot where the network came up slowly and unreliably . Then systemd itself started killing my wait loop: "start-pre operation timed out. Terminating." This post covers why that happens and the two fixes I made. The second one I only found while writing the first one. The symptom After the machine rebooted, the connection to the API kept dropping in and out for a while. The service never got past its pre-start step. The journal showed the same pair of lines over and over, about every 100 seconds: $ journalctl --user -u claude-remote-hub.service | grep -E "timed out|result" ... 12:46:33 systemd[...]: claude-remote-hub.service: start-pre ope...

RC Filter Calculator: Cutoff Frequency, Picking R or C, and How Much Signal Gets Through

One resistor and one capacitor make the simplest filter there is: a low-pass that smooths a noisy sensor or a PWM output, or a high-pass that blocks DC and passes the signal. This calculator gives the cutoff frequency from R and C, or picks a standard resistor (E24) or capacitor (E6) for a target cutoff. Enter a signal frequency too, and it tells you how much of that signal gets through. Mode Known R and C → cutoff frequency Target cutoff and C → pick R Target cutoff and R → pick C R (kΩ) C (nF) Cutoff fc (Hz) Filter type Low-pass (R in series, C to ground) High-pass (C in series, R to ground) Check a signal frequency (Hz, optional) Calculate Enter values and press Calculate. The formula f c = 1 ÷ (2π × R × C) At the cutoff frequency, the output is 70.7% of the input (−3 dB), with a 45° phase shift. Example: R = 10 kΩ and C = 100 nF give f c ≈ 159 Hz. That low-pass passes 50 Hz almost untouched (95% of the amplitude) but cuts 1.6 kHz down to about 10%. The rolloff...