I Can REST Easy Because My Fireplace is API Controlled Now

I'm not sure why this is a thing, but my last couple apartments have had non-functional fireplaces. At best, it's a decent-looking mantle to put some pictures; at worst, it's just a waste of space. But I endeavor to elevate everything in my apartment! I want a fire!

The idea is to stick an old monitor inside the fireplace, connect it to a Raspberry Pi, and come up with some way to start playing a video of a lovely crackling fire.

How Do I Start the Video?

Because the Raspberry Pi runs Linux, my first thought was "just do a one line bash script to start VLC Player." My second thought was "Nah, I need that Python street cred," and the decision was made.

It turns out there are several ways to run system commands with Python, and it took some experimentation to find the proper way.

The simplest way is just to run it as a system command:

import os
os.system("cvlc -f fireplace_vid.mp4")

However, it seems that my Python installation tries to run this command as root, and VLC doesn't like being run as root. So, I moved to the subprocess library:

import subprocess
subprocess.run(['cvlc','-f','fireplace_vid.mp4'])

This is the newfangled wrapper on top of Popen that tries to make things a little simpler. However, the problem I found is that this command doesn't return until the process is finished. That doesn't really work for a 10 hour video. In light of that, I finally went to the good ol' Popen:

import subprocess
subprocess.Popen(['cvlc','-f','fireplace_vid.mp4'])

This did exactly what I wanted. It ran the call, which started the video, and returned immediately.

How Do I Stop the Video?

Like I mentioned, this is a 10 hour video, and I didn't want to start it and have no way to turn it off other than yanking power to my Raspberry Pi. I ended up going with the simplest approach, which ended up being very useful with the eventual API implementation:

import os
os.system('killall vlc') # Burn it all down!

What's This Flask Thing?

At this point, I started thinking about how to turn it on and off. I didn't want to have to SSH in and run commands every time I wanted a fire, so I started thinking about using an API. It would be so easy, just hit a link in my browser bookmarks and BOOM! Fire!

One of my buddies mentioned an idea of using the Flask package to guide a presentation on HTTP APIs, so I decided to try it out. I found a wonderful tutorial that laid out everything I needed. I had almost all my code laid out minutes later.

from flask import Flask
import os, subproccess

app = Flask(__name__)

@app.route('/fire', method=['GET'])
def start_fire():
    subprocess.Popen(['cvlc','-f','fireplace_vid.mp4','&'])
    return 'Fire Started!'

@app.route('/extinguish', method=['GET'])
def stop_fire():
    os.system('killall vlc')
    return 'No Mo Fire'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

This clearly isn't production-ready code, but it's totally fine for my home use. The decorators just above each function create the endpoint on the web server and call the correct function when an HTTP request comes in.

Can I Turn the Monitor Off, Too?

Now that I'm already really fancy, can I have the monitor go black when there's no fire playing? And can I wake it up just before I start the video? It turns out that Raspbian has a command called tvservice. All I need to do is add that into each of my functions.

from flask import Flask
import os, subproccess

app = Flask(__name__)

@app.route('/fire', method=['GET'])
def start_fire():
    os.system('tvservice --preferred') # Starts the monitor with its preferred settings
    subprocess.Popen(['cvlc','-f','fireplace_vid.mp4','&'])
    return 'Fire Started!'

@app.route('/extinguish', method=['GET'])
def stop_fire():
    os.system('killall vlc')
    os.system('tvservice --off')
    return 'No Mo Fire'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

Is That It?

It is! 15 lines of code to run a smartphone controlled digital fireplace.