Full disclosure: I started this project a while ago – according to the photo app on my phone, almost 12 months ago! I originally wanted to build it so I could control my TV, Yamaha receiver, Foxtel set-top box and Apple TV from my phone and watch. I like to listen to music while I cook, but changing the song, or the volume is a pain – I have to stop, wash and dry my hands, then walk over to find the remote.
The project got shelved for a while (Oooh! shiny things!), as I worked on my garage door project, but then I had an excuse to resurrect it.
My wife casually mentioned that she wanted to be able to stream music, and listen to the radio at the back of the house. And even in the front room, she found turning on the Apple TV to stream Spotify annoying. She also hated having to turn on the TV just to play.
There was only one solution I could see: Purchase a Sonos!
I actually purchased two: A Sonos Play:1, that we can move around the house as we need it – it usually lives in the bedroom, but we can easily take it outside when we have people over; and a Sonos CONNECT – I already have a perfectly good receiver and speaker setup, replacing all of it sounded like over kill.
Now we could stream music around the house easily without it stopping if the phone rang, and without draining our phone batteries. There was still a small issue though: the Play:1 turns on as soon as your press play on the phone app, as does the CONNECT. Unfortunately, my receiver didn’t.
Time to dust off the IR blaster.
The CONNECT publishes uPNP data, which homeassistant.io already listens to. This in turn fires an event when ever the devices starts playing music, which I consume using node-red, which makes an API call to another node app I have running on a Raspberry PI, which in turn blasts out some IR via LIRC.
Simple really :)Stripping a Raspberry PI
I had a couple of the original Raspberry PIs on my desk, and since they were just sitting gathering dust they seemed like the perfect candidate for this project.
I don’t know why, by the composite port really irks me. I’m never going to use it, and it really juts out, and realistically this was going to be WiFi only, so I could get rid of the network port. Also, plugging in a Wifi adapter made the board unnecessarily long.
Time to trim it down a bit.
First, I removed the composite port by clipping the leads and desoldering the remains.
Then I removed the network plug. The two holes that held it in will come in handy later…
Finally, I removed the USB sockets.
Much neater! And regular shaped. Of course, there is now no way to interface with it. I took a perfectly good USB WiFi module and gutted that.
And then direct soldered it to the PI.
Now I have a minimalist WiFi-enabled RaspberryPI! If I need to make any changes, I just ssh in and do it via command line. If I really need a keyboard, I’ll just put the SD card in another PI that is more fully featured, and do it there.The IR Blaster
I am not the first person to build an IR blaster for a RaspberryPI, and I sure won’t be the last. Thanks to the LIRC gpio module, the circuit required is super simple:
One side is the transmitter – 3 IR LEDs in series, with a 56ohm resistor, driven by a bog-standard BC547 transistor.
The LEDs I used have a 1.2V at 20mA. forward voltage, so the three in series drop 3.6V. R2 needs to drop 1.4V (to add up to 5V). R = V/I, so R2 needs 70 ohm. For some reason, I picked a 56 ohm resistors, so the LEDs will get driven a little harder at 25mA, which is still well with in their spec (They max out at 50mA).
The transmitter side is even easier – the device does all the work, so there is just a pull down resistor on the signal leg. I picked GPIO 17 and 18 at random – any GPIO line will work, and you can configure it in software.CEC
CEC is actually a very simple protocol. Each packet is at least two bytes, the first nibble: an integer between 0 and 16 representing the sender, the second an integer between 0 and 16 representing the receiver, followed by a byte-long opcode. Some opcodes allow additional parameters.
All devices talk in “party line” mode, meaning everyone hears every message (there is a maximum of 16 devices, so routing and partitioning is overkill). It also means every device knows what is going on all the time.
The protocol allows you to find out all sorts of interesting information: is a device turned in? What device is currently active?
You can also ask devices to do stuff: turn up the volume, schedule a recording, or switch inputs.
The problem is: no body seems to implement the spec completely. And many manufacturers don’t do it correctly.
For example: my Yamaha receiver (a RX-V347) supports the user control opcode (0x44) and the change AV input opcode (0x69) which is supposed to take another parameter to denote the input you wish to choose. If the input entered is 0, then the next input is selected. This receiver only accepts 0 as a input code, which makes selecting a specific input (without knowledge of what the current input is) impossible.
There was a fun work around for this though; my RaspberryPI is connected to a HDMI input in my receiver, which I know the number of. By working out the distance each input number is from that input, I can select the RaspberryPi as the active input then send a change AV input a number of times until the right one is selected. Do it fast enough and no one would notice.
Why don’t I just interrogate the amp and ask it what input is currently selected? I could, but there is only facilities to find out what HDMI input is active. If the AV1 input is active (which has my Sonos attached) I’m out of luck.
Of course, none of this stuff is documented any where so there is a lot of trial and error going on to work out what opcodes each device handles, and whether they handle it correctly.
I hacked together a little node-red script that listens for events from my homeassistant.io installation using a quick eventsource module that I knocked up, which is generally working pretty well – occasionally, it selects the wrong input, because I’m relying on my CEC hack but I’ll deal with that later.A 3D Printer case
I did up a quick design in FreeCAD and printed it out. Originally, I based the design off the Apple TV, as I thought I could have some sort of visual symmetry.
It looked terrible.
It was way bigger than it needed to be, and looked cheap and nasty. And once I decided to add CEC, I needed access to the HDMI port, so a redesign was in order.
After printing it out, I put everything together and placed it next to my receiver. But there was a problem – the network kept dropping out. It turns out that as the temperature rose inside the case, the wifi chip would reset. Boo.
I tried drilling some holes in it, and it didn’t make too much difference. At this point, it was Christmas, so I removed the top of the case and hide it behind the receiver (I didn’t need the IR bit at the moment – the CEC did what I needed).
Fast forward a month, and I decided to revisit. I had just bought a Raspberry PI 3, with an official case for a project at work, and I noticed that it had no air holes, so I wondered if something was wrong with the WIFI dongle. It was sitting at a weird angle over a chip that did get warm, so I unsoldered it, and re-soldered it at a different weird angle, away from the chip.
Of course, I overcooked it.
Luckily, I had a spare, which looks like a more robust unit. I took that one apart, and soldered it in.
I’m sure it’s breaking some sort of USB spec, but it works.
I put it back in the case
and screwed it back together
The case still isn’t perfect. The front left corner needs a screw stalk (The gap is because there is nothing holding it together). I could fix it with some sort of clip, but I’m thinking about a completely different design, which will have LEDs on an angle and on the back, but that would require a new PCB, so I’ll stick with this for the moment. I still can’t work out how to get a less streaky top. I clearly need some more 3D printing practice.
Here is a picture of it in situ:
It’s on an angle, because I bounce the IR off the coffee table. The audio receiver works perfectly, the foxtel works pretty well (though that is more to do with my LIRC setup). The TV doesn’t really work – it’s a bit far away, which is why I want to redesign the case.
It’s good enough for now. I’m going to spend some time on the software.