Home automation field notes All concepts

audio

The subwoofer, in full

One Bluetooth link that wants to hear from one caller, a loudness curve drawn by ear, three presets on a schedule, a database for albums mixed without bass, a rounding bug that hid behind even numbers, and a knob that waits until you let go.

The box is an SVS SB-1000 Pro in the living room. It is fed a stereo RCA pair by the same streamer that drives the active monitors, which is the rest of the signal path; a Zigbee remote steps the streamer's volume; and the subwoofer itself is controlled over Bluetooth LE by a community integration that exposes twenty-eight knobs, most of which we have now given opinions to.

A subwoofer that hangs up, politely

The subwoofer accepts exactly one Bluetooth connection at a time. Its integration therefore does something civilised: sixty seconds after the last command it hangs up, so the manufacturer's phone app can get a word in, and it silently redials whenever the next command arrives.

We learned this by building it wrong. Our first volume automation was guarded by "only when connected", which reads as prudence and works as a bug: the guard blocked precisely the common case, a sub sleeping between commands, even though writing to it is what wakes it. The connection sensor spends most of its life reading "disconnected" while everything is perfectly healthy.

We would like to say we would do it differently next time. We would do it exactly the same, and be exactly as surprised that it works.

Lesson: never condition an automation on a sensor whose "off" is a healthy state. Some connections are meant to flap; guarding on them turns a design feature into an outage. (The field guide gains another entry.)

Loudness, drawn through three points

Human hearing loses low frequencies faster than the rest as volume drops, which is why quiet late night listening always sounds thin. The textbook answer is a loudness contour. The household answer: sit on the couch, find the subwoofer level that sounds right at a few volumes, and connect the dots.

It began as two points and a straight line. Then a third point arrived from a quieter evening (volume 20, ear says minus 10) and bent the line where the straight version was one decibel too generous. The curve is now piecewise: sub_dB = -1 - 0.5 x volume up to volume 30, 2 - 0.6 x volume above it, continuous at the joint, clamped to the subwoofer's range. The curve lives in a template sensor of its own, so anything that wants to know what the bass should be can simply read it.

An automation holds the bass to that curve whenever the streamer's volume moves. The remote's volume steps arrive in bursts of three, so it waits out the burst and writes once; the subwoofer does not enjoy being dialled like a rotary phone.

Fletcher and Munson mapped this in 1933 with headphones and a generation of patient test subjects, and their contours do exactly what our third point did: they change slope as the level drops. We reproduced the useful part with three data points and two evenings. The curve is not science; it is a preference, made repeatable, drifting toward science one calibration at a time.

A footnote two days later: after some hours of use the driver loosened up and the whole curve moved down by one decibel, measured the only way it can be, by the same ear at the same evening volume. A loudness curve is not a constant of the room; it is a constant of the room, the box and the month.

Three personalities and a scheduler

The subwoofer stores presets, so it now has three characters. Music is the reference: the ear-tuned crossover, phase and nothing else, because for music the correct amount of subwoofer is the amount you cannot point at.

Movie adds a single decibel and a gentle 3 dB bump around 30 Hz, since film soundtracks carry an effects channel mixed with headroom that living rooms never use. Night is the diplomatic one: eight decibels down and a room gain cut that removes precisely the deep bass that travels through concrete to the neighbours, while the couch keeps most of the illusion.

An automation switches between them: television sound on the eARC path means Movie, anything else means Music, ten in the evening or the house-wide sleep flag means Night. A manual pick from the dashboard is respected for six hours against the source switches; the ten o'clock bell and the sleep flag override it regardless, and eight in the morning hands control back to the sources. It is the convention the light switches in this flat already follow: the human is always allowed to overrule the script, and the script is always allowed to forget about it by morning.

The trap worth exporting: the subwoofer reports which preset is active only in the moment one is loaded, and its preset selector reads "unknown" the rest of the time. The first version of the volume logic keyed off that selector and quietly applied an offset of zero, whatever the preset.

The fix is a rule as old as SCADA: keep your own source of truth. A helper in Home Assistant declares which character the subwoofer is supposed to have; the device's selector is demoted to an actuator; every other automation reads the helper. The subwoofer is consulted about reality only when it volunteers it.

The ninety degree ear

The subwoofer's phase control ended up at 90 degrees because that is where it sounded best, which invited the obvious question: is that a real setting or a superstition? The arithmetic says real. At a 60 Hz crossover the wavelength is about 5.7 metres, so 90 degrees is a quarter of that, roughly a metre and a half of effective path difference, which is comfortably what you get from speaker placement plus the few milliseconds a DSP subwoofer spends thinking. At the crossover the sub and the mains play the same notes; misalign them and they subtract.

The ear found the alignment first and the physics signed off afterwards, which is the correct order for a living room and the reverse of how it usually goes in this house. For the sceptical there is a classic verification: invert the sub's polarity, sweep the phase for the deepest null at the listening position, then flip polarity back. The deepest hole, inverted, is the tallest sum.

Some albums were mixed without a subwoofer in the room

A loudness curve assumes the recording did its part. Some recordings did not. A drummer's 1990 debut album needed a good deal more sub than the same drummer's 1994 record at the same volume, and no curve drawn through the room can know which year the mastering engineer was having.

It took us three tries to store this sensibly. First we reached for release-year tiers, which is astrology with a discography. Then we reached for absolute targets per album, which lasted until we remembered that the sub sits anywhere from -6 to -40 dB depending on the master volume. An absolute target is a preference frozen at one evening's loudness. On reflection the only sane thing to store is an offset: a number added on top of the curve, so the curve keeps handling the volume and the album keeps its opinion.

The database is a small JSON file keyed artist, then album, then track, most specific wins, and an artist with no entry gets zero. The drummer currently reads: everything of his +3, Master Plan +8, Hard-Wired +5, the last of which began life at +3 and was revised by the button, which is what a living preference looks like. Adding an album is not data entry. Set the bass by ear while it plays, press "remember this album", and a script stores the current sub level minus the curve value. The offset takes effect at once and survives every volume change afterwards, which is the whole point.

A second automation watches the streamer, looks the current album up when a track starts and parks the offset in a helper. It never touches the subwoofer. That restraint turned out to matter.

The single-writer rule

Exactly one automation writes the subwoofer's level. Everything else, the curve sensor, the album offset, the preset shift, the fans in the room, only produces a number, and the one writer adds the numbers up, clamps the result and sends it. When a new influence turns up it becomes one more term in the curve sensor, never a second writer. The sanctioned exception is a human thumb on the knob, which the writer politely overrules at the next volume change unless "remember this album" has turned the thumb's opinion into a term.

The reason is partly the radio, one BLE link, sixty seconds of patience, no appetite for being argued with by two scripts at once, and partly hygiene: when the bass is wrong there is one place to look, and the answer is always a sum. The writer now triggers on the curve sensor itself, so a new term does not even need a new trigger. It just appears in the total, like a service charge.

The air purifier, and the half decibel that was not there

The air conditioner had already earned two decibels on a simple argument: its fan is a steady hiss on the bottom octave, and the ear, which is very good at subtracting steady noise, subtracts a little of the bass along with it. The air purifier joined on the same precedent: from its second speed upwards, one decibel more. This took four lines and should have been the end of the story.

It was not, because the curve rounds, and it rounded the base and the terms together. On the quiet half of the curve the base ends in .5 at every odd volume, and the template engine rounds halves to the nearest even number, so an even term added before rounding lands where it always did while an odd one lands on whichever side parity prefers. The purifier was worth 0, 1 or 2 dB depending on the volume; at one particular volume it was worth nothing at all, which we found by measuring rather than by trusting the configuration, a habit this house acquired the expensive way.

Lesson: round the base first, then add the integer terms. Nobody had noticed because every term before was even.

A knob, because sliders are for people who do not care

Fine bass adjustment wants a big round knob, and no dashboard card we could find would draw one for a plain number entity; the knobs that exist are all married to thermostats. So we wrote one in an afternoon: plain JavaScript and SVG, a 270 degree arc, tick marks, and a minus and plus for single steps.

The one design decision that matters is that it draws while you turn and writes only when you let go. The loudness automation had already paid for that lesson with its burst-of-three remote; a knob that wrote on every pixel of drag would have re-learned it in about a second. When something else changes the level, the knob follows, unless a thumb is on it, in which case the thumb wins.

The subwoofer, for its part, has no idea any of this exists. It receives one number every now and then, from one automation and, occasionally, one thumb, and is asleep the rest of the time. Of everything in this flat, it may have the healthiest relationship with automation.