The Raspberry Pi Powered Speaking Doorbell

Doorbells are so last century. While watching an episode of the futuristic, sci-fi thriller Extant, I realized that the future of the doorbell is now! In the episode, a voice, presumably the product of some smart home automation system, announces that a visitor is at the front door. Easily achievable with a Raspberry Pi and some Python code!

 

 

Our future-is-now speaking doorbell uses a Raspberry Pi with a simple input circuit wired to our existing doorbell button. When a visitor presses the doorbell, the Raspberry Pi does a number of things: Firstly, it pauses the currently playing video and displays an on-screen message on both of our media center PC’s. Then, using a text-to-speech converter on the living room media PC, it announces that there is a visitor at the front door. And finally, an on-screen video from an IP camera mounted at the front door is displayed on both TV’s.

>> Next post – Part 1: The Input Circuit

XBMC’s JSON-RPC API – REALLY Pausing a video

In an earlier post, “Calling XBMC’s JSON-RPC API using Python’s requests library – Pause a video“, I showed an example of pausing the actively playing file using the XBMC JSON-RPC API’s Player.PlayPause method. The problem with this method, as you could probably already tell from its name, is that it acts like a toggle – if the video is playing, it pauses it. If it is already paused, it is unpaused. Great for remote controls, but useless for anything else.

It took quite a bit of searching to figure out how to only pause a file if it is currently busy playing. The answer is to use the Player.GetProperties method to retrieve the “speed” of the currently playing file, which tells us if the file is playing or not. So, to pause we need 3 calls to the API:

– Player.GetActivePlayers to get the actively playing file’s “playerid”
– Player.GetProperties passing the playerid from the response of Player.GetActivePlayers to get the “speed” which should tell us if the file is paused or not
– Player.PlayPause called only if the speed returned is not 0

The code:

import requests
import json
import urllib

#Required header for XBMC JSON-RPC calls, otherwise you'll get a
#415 HTTP response code - Unsupported media type
headers = {'content-type': 'application/json'}

#Host name where XBMC is running, leave as localhost if on this PC
#Make sure "Allow control of XBMC via HTTP" is set to ON in Settings ->
#Services -> Webserver
xbmc_host = 'localhost'

#Configured in Settings -> Services -> Webserver -> Port
xbmc_port = 8888

#Base URL of the json RPC calls. For GET calls we append a "request" URI
#parameter. For POSTs, we add the payload as JSON the the HTTP request body
xbmc_json_rpc_url = "http://" + xbmc_host + ":" + str(xbmc_port) + "/jsonrpc"

#Payload for the method to get the currently playing / paused video or audio
payload = {"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}
url_param = urllib.urlencode({'request': json.dumps(payload)})

response = requests.get(xbmc_json_rpc_url + '?' + url_param,
                        headers=headers)

#response.text will look like this if something is playing
#{"id":1,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}
#and if nothing is playing:
#{"id":1,"jsonrpc":"2.0","result":[]}

data = json.loads(response.text)
#result is an empty list if nothing is playing or paused.
if data['result']:
    #We need the specific "playerid" of the currently playing file in order
    #to pause it
    player_id = data['result'][0]["playerid"]
    
    payload = {"jsonrpc": "2.0", "method": "Player.GetProperties",
               "params": { "playerid": player_id, "properties" : ["speed"] }, "id": 1}
    url_param = urllib.urlencode({'request': json.dumps(payload)})
    response = requests.get(xbmc_json_rpc_url + '?' + url_param,
                        headers=headers)
                        
    data = json.loads(response.text)         

    if data["result"]["speed"]:
        payload = {"jsonrpc": "2.0", "method": "Player.PlayPause",
                   "params": { "playerid": player_id }, "id": 1}
        response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload),
                                 headers=headers)

        #response.text will look like this if we're successful:
        #{"id":1,"jsonrpc":"2.0","result":{"speed":0}}

Calling XBMC’s (Kodi) JSON-RPC API using Python’s requests library – Pause a video

There aren’t many examples of using XBMC’s JSON-RPC API online, especially Python examples. Here is a simple example in Python, using the requests library.

Prerequisites: Make sure “Allow control of XBMC via HTTP” is set to ON in Settings -> Services -> Webserver.

The following code performs 2 requests: first, it performs an HTTP GET request to retrieve the currently playing or paused file (if any). If a result is returned, we perform a POST to the JSON-RPC to pause the currently playing file using the “playerid” returned from our GET request.

Edit – The Player.PlayPause method toggles between playing a video and pausing it. If a video is already paused, the code below will cause it to to start playing again. Please see my follow up post “XBMC’s JSON-RPC API – REALLY Pausing a video” for an example of how to only pause a video if it is already busy playing.

import requests
import json
import urllib

#Required header for XBMC JSON-RPC calls, otherwise you'll get a 
#415 HTTP response code - Unsupported media type
headers = {'content-type': 'application/json'}

#Host name where XBMC is running, leave as localhost if on this PC
#Make sure "Allow control of XBMC via HTTP" is set to ON in Settings -> 
#Services -> Webserver
xbmc_host = 'localhost'

#Configured in Settings -> Services -> Webserver -> Port
xbmc_port = 8888

#Base URL of the json RPC calls. For GET calls we append a "request" URI 
#parameter. For POSTs, we add the payload as JSON the the HTTP request body
xbmc_json_rpc_url = "http://" + xbmc_host + ":" + str(xbmc_port) + "/jsonrpc"

#Payload for the method to get the currently playing / paused video or audio
payload = {"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}
url_param = urllib.urlencode({'request': json.dumps(payload)})

response = requests.get(xbmc_json_rpc_url + '?' + url_param, 
                        headers=headers)

#response.text will look like this if something is playing
#{"id":1,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}
#and if nothing is playing:
#{"id":1,"jsonrpc":"2.0","result":[]}
    
data = json.loads(response.text)
#result is an empty list if nothing is playing or paused. 
if data['result']:
    #We need the specific "playerid" of the currently playing file in order 
    #to pause it
    player_id = data['result'][0]["playerid"]

    payload = {"jsonrpc": "2.0", "method": "Player.PlayPause", 
               "params": { "playerid": player_id }, "id": 1}
    response = requests.post(xbmc_json_rpc_url, data=json.dumps(payload), 
                             headers=headers)
    
    #response.text will look like this if we're successful:
    #{"id":1,"jsonrpc":"2.0","result":{"speed":0}}