Posts Tagged RPi

Icecast and Ezstream Configuration

Plugging a 64 GB USB stick with directories full of MP3 / OGG files into an always-on Raspberry Pi running Pi-Hole, one can use Icecast to stream them for clients on the LAN, so as to avoid over-the-Intertubes streaming issues.

The only changes in the /etc/icecast2/icecast.xml file cover passwords, the number of source streams, and the hostname. It’s that simple, really.

Given a directory of files, generate a file-per-line playlist:

find /mnt/music/goodmusic/ -name \*mp3 | sort > /mnt/music/goodmusic/playlist.m3u

Then set up a corresponding Ezstream XML file, perhaps imaginatively named goodmusic.xml:

    <svrinfoname>Good Music</svrinfoname>
    <svrinfogenre>Good Music Streaming 24x7</svrinfogenre>
    <svrinfodescription>Techno Dub</svrinfodescription>

Fire off the source stream in /etc/rc.local:

ezstream -c /home/pi/Icecast/goodmusic.xml &

The ampersand tells Bash to fire-and-forget the process, so it runs all the time. One could, I suppose, put it in crontab to start after each boot or puzzle out the corresponding systemd incantation, but …

Add the station to your streaming media player:

         'KEY_KP5'   : ['Good Music',False,['mplayer','-playlist','']],

And then It Just Works™.



Leave a comment

Raspberry Pi vs. MicroSD-as-Disk Memory

The MPCNC has bCNC running on a Raspberry Pi, with a Samsung EVO MicroSD card serving as the “hard drive”:

Sandisk Extreme Plus vs. Samsung EVO MicroSD cards

Sandisk Extreme Plus vs. Samsung EVO MicroSD cards

The picture also shows a defunct Sandisk Extreme Plus killed by continuous video recording in my Fly6 bike camera. I later replaced the EVO with a video-rated Samsung card which has been running fine ever since, albeit with the occasional crash-and-reformat expected with “action” cameras.

With that as background, a different Samsung EVO card from the same batch has been running the MPCNC’s Raspberry Pi for about a year. Over the course of a few days last week, the RPi went from an occasional stall to a complete lockup, although waiting for minutes to hours would sometimes resolve the problem. As I’ve learned by now, it’s not a software crash, it’s the controller inside the card suffering from write amplification while trying to move data from failing sectors.

Applying f3write to the card shows the problem:

MPCNC MicroSD - f3write slowdown

MPCNC MicroSD – f3write slowdown

The write speed started out absurdly high as the card’s write cache fills, then slowed to to the flash memory’s ability to absorb data, and eventually ran out of steam during the last few files.

But, as you might not expect, f3read reported the data was fine:

sudo f3read /mnt/part
F3 read 7.0
Copyright (C) 2010 Digirati Internet LTDA.
This is free software; see the source for copying conditions.

                  SECTORS      ok/corrupted/changed/overwritten
Validating file 1.h2w ... 2097152/        0/      0/      0
Validating file 2.h2w ... 2097152/        0/      0/      0
Validating file 3.h2w ... 2097152/        0/      0/      0
Validating file 4.h2w ... 2097152/        0/      0/      0
Validating file 5.h2w ... 2097152/        0/      0/      0
Validating file 6.h2w ... 2097152/        0/      0/      0
Validating file 7.h2w ... 2097152/        0/      0/      0
Validating file 8.h2w ... 2097152/        0/      0/      0
Validating file 9.h2w ... 2097152/        0/      0/      0
Validating file 10.h2w ... 2097152/        0/      0/      0
Validating file 11.h2w ... 2097152/        0/      0/      0
Validating file 12.h2w ... 2097152/        0/      0/      0
Validating file 13.h2w ... 2097152/        0/      0/      0
Validating file 14.h2w ... 2097152/        0/      0/      0
Validating file 15.h2w ... 2097152/        0/      0/      0
Validating file 16.h2w ... 2097152/        0/      0/      0
Validating file 17.h2w ... 2097152/        0/      0/      0
Validating file 18.h2w ... 2097152/        0/      0/      0
Validating file 19.h2w ... 2097152/        0/      0/      0
Validating file 20.h2w ... 2097152/        0/      0/      0
Validating file 21.h2w ... 1322894/        0/      0/      0

  Data OK: 20.63 GB (43265934 sectors)
Data LOST: 0.00 Byte (0 sectors)
	       Corrupted: 0.00 Byte (0 sectors)
	Slightly changed: 0.00 Byte (0 sectors)
	     Overwritten: 0.00 Byte (0 sectors)
Average reading speed: 43.04 MB/s

Obviously, the card’s read speed isn’t affected by the write problems.

Assuming the actual data & programs on the card were still good, I slurped the partitions:

sudo partimage save /dev/sdf1 mpcnc_boot.gz
sudo partimage save /dev/sdf2 mpcnc_partition.gz

And wrote them back:

sudo partimage restmbr  mpcnc_boot.gz.000 
sudo partimage restore /dev/sdf1 mpcnc_boot.gz.000 
sudo partimage restore /dev/sdf2 mpcnc_partition.gz.000

Unshown: a finger fumble requiring MBR restoration.

Having forced the card controller to reallocate all the failed sectors, the card works now fine and runs at full speed again. This won’t last long, but it’ll be interesting to see how it plays out.

While I was at it, I wrote the partitions to a new-ish / unused Samsung EVO Plus card, now tucked under the MPCNC’s monitor in case of emergency.

An old SFF Optiplex with an SSD may be a better fallback.

, ,

Leave a comment

Pi-Hole with DNS-over-HTTPS

With none other than Troy Hunt recommending Pi-Hole, I got a Round Tuit:

unzip -d /tmp
sudo dcfldd status=progress bs=1M of=/dev/sde if=/tmp/2018-06-27-raspbian-stretch-lite.img

Raspbian now arrives with ssh disabled, so the first boot requires a keyboard and display:

Pi-Hole first boot wiring

Pi-Hole first boot wiring

Then do some configuration required to get a fresh Raspberry Pi ready for remote access:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install screen iotop
sudo raspi-config   # enable ssh
ssh-keygen -t rsa
cd ~/.ssh
cp -a /my/public/key authorized_keys
chmod go-rwx authorized_keys
sudo nano /etc/ssh/sshd_config  # unusual port, no root login, etc
sudo service ssh restart

As the good folks at Pi-Hole say, “Piping to bash is controversial, as it prevents you from reading code that is about to run on your system.” I took a look, it’s beyond my comprehension, so just get it done:

curl -sSL | bash

Configure Pi-Hole:

  • Static IP:
  • DNS using, say, Cloudflare’s
  • DHCP turned off, which is the default

Configure the router’s DHCP to hand out the Pi-Hole’s IP, with, say, as a backup.

Boot a few random PCs and whatnot to verify it works as expected, which it did the second time around, thus this particular post.

Install the Cloudflare Argo Tunnel dæmon, approximately according to suggestions:

mkdir Downloads
cd Downloads/
tar zxvf cloudflared-stable-linux-arm.tgz
sudo mkdir /opt/cloudflare
sudo cp cloudflared /opt/cloudflare/

Start the daemon from within a screen session, also as suggested:

sudo /opt/cloudflare/cloudflared proxy-dns --port 54 --upstream --upstream
INFO[0000] Adding DNS upstream                           url=""
INFO[0000] Adding DNS upstream                           url=""
INFO[0000] Starting metrics server                       addr=""
INFO[0000] Starting DNS over HTTPS proxy server          addr="dns://localhost:54"

Contrary to the suggestions, you can configure Pi-Hole to use the DoH tunnel (or whatever it’s called) by tweaking its upstream DNS configuration:

Pi-Hole - Cloudflare DNS config

Pi-Hole – Cloudflare DNS config

Then set up systemd to start the daemon automagically:

sudo nano /etc/systemd/system/dnsproxy.service

Because I put the daemon in /opt/cloudflare, that file differs slightly from the suggestion:

Description=CloudFlare DNS over HTTPS Proxy

ExecStart=/opt/cloudflare/cloudflared proxy-dns --port 54 --upstream --upstream$

And then It Just Worked.

Controversies over the ethics of ad and tracker blocking will go nowhere here, as I’ve cleaned out enough Windows machines to have absolutely no sympathy with the unholy spawn of adtech (not just the company, which I didn’t know existed until just now, but, yeah, them too).



Debranded HP w2408 Monitor: Revived

Three years ago I found a bulgy electrolytic cap inside a failed HP w2408 monitor:

HP 2408 monitor power supply - HV cap bulge

HP 2408 monitor power supply – HV cap bulge

Back then, a 150 µF 450 V cap of the proper size (the 30 mm height being critical) was difficult to find and relatively expensive to purchase in onesies from the usual reliable sources, particularly as the repair advice I could find suggested it probably wasn’t the causing the monitor’s problems. So the monitor sat in pieces in an out-of-the-way corner of the Basement Laboratory while other events transpired.

As part of a long-delayed Great Cleanup of Small Projects, I discovered the caps are now four bucks delivered from halfway around the planet, so I got one, did the swap, reassembled the pieces, and the monitor works just like new. No pix, but you get the general idea.

For another few years, anyway.

For whatever reason, the 3.5 mm audio output seems dead. The monitor has a pair of teeny speakers that don’t do justice to its magnificent HDMI audio, but they’re entirely adequate for my simple needs: pre-SSH Raspberry Pi setup doesn’t call for much.



Streamripper Setup

The Intertubes occasionally clog up while streaming low-bit-rate audio, for no reason I can fathom, leading to discontent in the User Community when it affects quiet classical music played in the dead of night. Given that the stream from far-off Switzerland consists entirely of public-domain performances, I set up Raspbian Lite on a headless Raspberry Pi 1 Model B+ in a spot where it won’t be disturbed:

Raspberry Pi 1 for streamripper

Raspberry Pi 1 for streamripper

Connecting to the Pi with a screen session, so as to allow disconnection & reconnection without anguish, I fired streamripper thusly:

streamripper -xs2 -o larger -u "MPlayer2" -m 30 -r -R 6 --with-id3v1

The -r -R 6 options set up a relay stream on http://ripper.local:8000 for the benefit of my local streamers, so only one trickle of bits crosses the Atlantic.

The total CPU load amounts to a percent or two, tops, so a single-core 700 MHz Pi has no trouble keeping up.

Because streamripper slings bits in more-or-less real time, the local servers don’t get any track title data when they start up, so the OLED display doesn’t update immediately. This is less of a problem than you might think, as we’re generally not hanging on the display to find out exactly which Vivaldi bassoon concerto is playing.

Given a suitable collection of tracks, I’ll set up an icecast server as the classical music “station” for the streamers, but that’s an adventure for another day. I also want to splice separate movements back into continuous symphonies, the way they’re suppose to be heard.


Leave a comment

Streaming Radio Player: I2C Display

Although I2C on the Raspberry Pi fails with devices using clock stretching, cheap I2C OLED displays seem to work well enough to not generate any problems search-able with the obvious keywords:



Given a picture of the header pinout, the wiring is trivially easy:

RPi I2C OLED - RPi header detail

RPi I2C OLED – RPi header detail

Using yellow for the ground hurts a bit, but that’s what I get for peeling the SPI cable down to four wires. The pin directly adjacent to the green wire is also ground, should that be easier to reach.

Tweaking the Luma driver to use I2C doesn’t require much:

#from luma.core.interface.serial import spi
from luma.core.interface.serial import i2c

... snippage ...

# reduce SPI bus from default 8 MHz to (maybe) avoid OLED failure-to-start
#serial = spi(device=0,port=0,bus_speed_hz=1000000)

# use I2C bus to avoid SPI timing spec failure
serial = i2c(port=1,address=(0x78 >> 1))     # PCB label = 0x78, low bit = R/W

The OLED PCB lists the I2C address with the R/W bit

And then It Just Works, with one gotcha. Although the Python program shuts itself and the system down, the wall wart continues to supply power and, because the I2C bus doesn’t include a Reset line, the OLED display doesn’t know the RPi has gone away. So you must issue a command to turn it off before shutting down:

device.cleanup()        # ideally, switches to low-power mode
rc =['sudo','shutdown','-P','now'])

Now, to discover what works … oddly … with these displays.



Raspberry Pi I2C Bus Timing vs. BNO055 Clock Stretching

An Adafruit BNO055 connected to a Raspberry Pi 3 I2C bus, despite knowing it won’t work:

I2C 100kHz - BNO055 SCL 1 mA-div - B7 Rd error

I2C 100kHz – BNO055 SCL 1 mA-div – B7 Rd error

The I2C bus ticks along at 100 kHz (nominal) = 62.5 kHz (actual), as described a while ago.

The three digital traces along the bottom are D0 = SCL, D1 = SDA, and D2 = trigger raised when the Python program detects an error.

The upper trace shows the SCL current (1 mA/div) between the Pi and the BNO055, as described yesterday, with the latter stretching the clock whenever the current goes negative.

The fourth burst is the BNO055 sending the chip’s temperature in response to a simple request:

temp_c = bno.read_temp()

A closer look at the last transaction:

I2C 100kHz - BNO055 SCL 1 mA-div - B7 Rd error - SCL glitch

I2C 100kHz – BNO055 SCL 1 mA-div – B7 Rd error – SCL glitch

I commend to your attention a useful tutorial on I2C bus protocols / transactions / signalling.

Over on the left, the BNO055 has SCL held low (-2 mA) during the ACK phase of the previous byte. The first upward SCL edge marks the ACK, with the BNO055 holding SDA low during the edge until the Pi drops SCL.

The BNO releases SDA when SCL goes low again, whereupon SDA goes high, exactly as it should.

Now, things gets ugly.

The -1 mA current on SCL shows both the Pi (+1 mA) and the BNO (-2 mA) are pulling SCL low.  The BNO is clock-stretching after the ACK, which the Pi can’t handle.

The Pi seems to think the rising edge of SCL occurs when it stops pulling SCL down, at the point where the SCL current goes from -1 mA to -2 mA, halfway though the high SDA pulse. It reads SDA at that point and receives an incorrect binary 1 bit from SDA, because the BNO hasn’t yet seen a rising SCL edge.

The SCL rising edge occurs when the BNO055 releases SCL and produces the SCL sliver.

Here’s a very close look at the sliver:

I2C 100kHz - BNO055 SCL 1 mA-div - B7 Rd error - Pi SCL mistiming

I2C 100kHz – BNO055 SCL 1 mA-div – B7 Rd error – Pi SCL mistiming

The two vertical cursors bracketing the sliver mark the 16 µs SCL timing produced by the Pi’s SCL clock, which is not the 10 µs you’d expect at 100 kHz.

The right cursor sits on the next rising edge, so the left cursor marks where SCL should rise: exactly where the Pi releases its hold on SCL and expects it to pop up.

That error happens about 6% of the time, producing a chip temperature 128 °C higher than reality. The other 94% of the reads either work correctly or, perhaps, encounter a bogus SDA state coincidentally delivering a binary zero that looks good.

Here’s a sample of a “good” read:

I2C 100kHz - BNO055 SCL 1 mA-div - B7 Rd OK - long SCL high

I2C 100kHz – BNO055 SCL 1 mA-div – B7 Rd OK – long SCL high

The stop bit is now off to the right, so the last rising SCL edge is the ACK. Counting leftward eight edges from the ACK, the left cursor marks where the SCL edge should be for bit B7. Instead it occurs instantly after the BNO releases its hold on SCL, shown by the transition from -2 mA to 0 mA. I don’t know the setup and hold times for the Pi’s I2C port, but 250-ish ns seem aggressive; I think the data transitions should happen close to the down-going SCL edges.

Running the I2C bus at 200 kHz seems to work fine, but it still has the same aggressive SDA-to-SCL setup time. Here’s a close look at the same situation as in the previous photo, with SCL set for 200 kHz:

I2C 200kHz - BNO055 SCL 1 mA-div - Rd OK - 250 ns SDA-SCL setup

I2C 200kHz – BNO055 SCL 1 mA-div – Rd OK – 250 ns SDA-SCL setup

This being a read, the BNO sets SDA to whatever it should be, then releases its clock-stretching hold on SCL about 200 ns later. The Pi raises SCL shortly thereafter and it apparently Just Works. Maybe it’s Good Enough to be consistent, but I’d like to run more tests before trusting it.

Anyhow, that’s how the Pi’s I2C hardware doesn’t handle a chip using clock stretching.

1 Comment