Good old summer time. I’m back at home and my grandma is visiting too. Problem is, she doesn’t speak English but wants to watch Chinese news while she’s here at home. Ok. But we don’t have satellite television, so the only option is to watch it on Youtube. Fine. But she’s getting old and finds it uncomfortable to watch videos on a tablet. Good news, we got a Chromecast a few months ago, so we can just cast it onto the living room television.
So here are the steps she needs to take to watch the news (mind you, all of our electronics are set in English, so that just compounds the difficulty in the learning curve)
Turn on the iPad → Start up Youtube → Set the keyboard to Chinese → Type in the news name and date → Cast to the TV
I think it’s very apparent how involved this process is for someone her age.
Thing is, I didn’t think twice about making anything until I realized how predictable the process is. Most of the steps are constant; the only thing that changes is the date in the search query.
With this in mind, I set out to see if this could be automated. (Also, somewhat annoyingly, my grandma seems to be unwilling to ask me for help whenever I’m at home. From what I heard from my parents, she was pretty worked up about not being able to watch the news, yet never spoke a word of it to me.)
Materials on hand
I’ve recently gotten into the hardware side of electronics, and I have to say that it’s pretty fun. Just having some basic understanding of hardware really compliments my software skills and lets me do a whole lot more. This would be a perfect chance to mess with stuff and actually ship a finished product when I’m done.
Things I had on hand with Wifi
- Raspberry Pi 3
- Raspberry Pi Zero W
- NodeMCU (ESP8266)
Along with these chips, I had a handful of buttons and LEDs. This should be a simple task to wire up a button that casts, right?
At first I was unable to find any relevant information. When I searched for ways to automatically cast, most of the results were people on forums talking about what seemed to be bugs.
First signs of something promising were a list of Chromecast HTTP commands. It appeared that the Chromecast was hosting a local server on port 8008. By sending it POST and GET requests, you could play videos on Youtube or look at what’s currently casting.
The solution would be simple – hook up a button to the NodeMCU. It then should be easy to pull up the Youtube API, grab the video link, and then post it.
Only problem was that it didn’t work. Well it did work a little, just not how I wanted it to.
- No video, only audio
- Image stuck on Youtube splash screen
- “Phantom cast” Other devices did not recognize that something was casting, and it did not mesh well with other devices trying to cast
With unofficial APIs, things will change and break. It may be a long time between new protocols and successful reverse engineering.
Gathering the Pieces
Hmmm, this is interesting. All the posts about the HTTP protocols are 3 or 4 years old. As I continued to search for “Chromecast Protocol” and “Chromecast HTTP commands”, I found that nobody had posted information on them since 2015… when the Chromecast 2 came out.
A quick search lead me to the cast-v2 protocol. Of course! The new protocol would explain the limited backwards compatibility. Also, just by knowing that the name of the protocol was cast-v2 greatly improved my search results.
In the second generation, the Chromecast protocol got complicated. Cast-v2 uses Protobuf to exchange casting information, and there’s also a heartbeat signal clients have to send. If the Chromecast doesn’t receive them, then it automatically kicks the client off and stops casting. There was no way that I was going to be able to implement this on NodeMCU in any timely fashion. Now I was going to have to move up to the Pi Zero W. This way, I would have wireless connectivity and a decent processor in a compact package that I could easily solder buttons to.
Most of the implementations were in NodeJS, which I didn’t think much of at the time. I decided to go with a Java implementation because that’s the language I’m most familiar with. Of course, that didn’t work either. As I was testing it on my laptop, it kept crashing when trying to communicate with the Chromecast. I couldn’t use Youtube with it, and by the looks of it, the project was dead.
If the vast majority of people are doing the same thing (implementing in Node), there’s probably a good reason. It’s more likely that the popularity will lead to more bug fixes and features.
Of course, in the end I went with castnow, which is written in Node. I’ll gloss over the troubles I had installing Node, as that’s my fault, not Node’s. After an afternoon of fumbling around, I managed to cast a mp3 file from the internet to my TV. I then proceeded to get Node up and running on the Pi Zero W.
The thing is, unlike the Raspberry Pi 3, which has an ARMv8 processor, the Pi W has a ARMv6 CPU. What makes this so bad is that ARMv6 is no longer supported by Node. This meant that both the NodeMCU and Pi Zero W are out of the picture. I’m going to have to use a Raspberry Pi 3 to act as a server.
The bad part about this is that if I use a Raspberry Pi 3 as a server, I’m going to need a client. I hesitated to use the NodeMCU, but I didn’t have any better options. With more moving parts, the more likely something is going to go wrong. It’s common sense, really.
The setup will have more latency. There will be noticable time delays between sending a command from the NodeMCU to having the Raspberry Pi accept it, to having the Pi being able to cast to the television.
It might break down while I’m away. I’m going to be leaving soon and going back to my normal life, but Grandma’s staying until mid October. If anything breaks down in these months, I won’t be around to fix it. This project needs to last for more than three months without anything breaking.
Getting a Product out the Door
In this section, I’m going to be describing all sorts of random solutions I had to bodge together in order to make this work. The main impetus is that I’m going on vacation next week, meaning that my grandma won’t even be able to ask me for help when watching the news.
(I had hoped to get this article out before I went on vacation too, but it’s a week late because now I’m back. I had a draft ready to go before I left, but I only just got around to finalizing this post.)
Part 1: Chromecast Workaround
I tried to cast Youtube videos on my laptop after failing to setup castnow on the Pi Zero W only to find that it didn’t work on my laptop either. The sole open issue on the castnow Github page was that it didn’t work for Youtube. Great. The good news was that there was a workaround until someone reverse engineers the Youtube protocol (which seems to be independent of cast-v2): download the Youtube video, and then cast the local video file to the Chromecast.
Part 2: Inefficiencies in the Remote
The NodeMCU remote is really bad, and I apologize for anyone going through it in the future. I couldn’t get a TCP/IP client working in Lua, so I used the Arduino ESP8266 core. The code is bad as I really rushed to get it out the door.
I couldn’t get interrupts working, so it’s constantly polling. That’s going to wear down on the NodeMCU’s lifespan.
The only “debugging” method is to watch two blinking LEDs on the side. I would love to have something more robust so I can easily give tech support over the phone.
This is my first time working with Arduino’s Wifi, so I think there are some problems with how the NodeMCU connects to Wifi. I think it can be improved to be more power and time efficient.
Part 3: Has it always been this slow?
In two days I finished all of the code and soldered the remote together on a piece of perfboard. For some reason, though, it’s painfully slow on the Raspberry Pi. The processor just isn’t up to the task of simultaneously downloading videos and simultaneously feeding it to the Chromecast. I guess this is what the real world of software development is like. Things could be optimized, but the pressure of getting something out there is far to great to worry if it works well – it just needs to work.
In the end, it was well received with the older members of the household, and I think I can declare this project a success. As far as I know, it recieves regular use, and I curcumvented some problems with the remote by telling everyone to leave it unplugged (it runs on USB power) when not in use.
And finally, I think this is the greatest lesson I learned while working on this project:
Old people don’t care about latency.
One thing that I lost sight of was whom I was making the remote for. My grandma just doesn’t care if she has to wait 5 minutes or 5 seconds to watch the news. For her, the ease of pushing a single button versus going through that whole mess to cast the news far outweighed the burden of having to wait.
Or maybe, if read another way, this lesson is that young people are really impatient with tech?
In the end, I was able to ship, and that in of itself is something I should celebrate.
Thanks for reading!