The Raspberry Pi Powered Speaking Doorbell – Part 1: The Input Circuit

<< Previous post – The Raspberry Pi Powered Speaking Doorbell – Video

The first step of building the Raspberry Pi-powered speaking doorbell is building a simple input circuit. The purpose of the input circuit is to protect the Pi from damage by electrically isolating the doorbell and its power supply from the Raspberry Pi itself.

The circuit design and a full description of how it works can be found here. The power supply I used is rated at 12V, but the LTV-847 optocoupler used in the design copes just fine with an input voltage of 12V. It is a 4 channel optocoupler, so you can read 4 different inputs using the same optocoupler. I like using veroboard / stripboard for my circuits because the soldered connections are a bit more robust than a breadboard setup.

Input Circuit

Input Circuit – Top view

On the left are the 2 single-core cables that are connected to my doorbell and its 12V power supply. The + (anode) of the 12V power supply is wired to my doorbell button which in turn is connected to the input circuit (top left cable). The bottom-left cable on the input circuit is then connected to the – (cathode) of the power supply.

On the right-hand side, you’ll notice a ribbon cable. I have a model B Raspberry Pi, which has a 26 pin P1 header. I bought a 26pin IDC crimp connector and some ribbon cable, which fits perfectly on the P1 header.

IDC

The red cable indicates Pin 1 on the Raspberry Pi, so in the input circuit picture, the top right cable is connected to the 22nd cable of the ribbon cable (which corresponds to pin 22 on the Raspberry Pi) and the bottom-right cable is connected to the 20th cable (pin 20 on the Pi).

GPIOs

(Diagram from eLinux.org)

As you can see from the pin mapping diagram, pin 22 is GPIO 25 and pin 20 is Ground.

Input Circuit - Bottom view

Input Circuit – Bottom view

You’ll notice on the bottom view of the input circuit that the tracks on the stripboard is scratched off between the input and output sides of the optocoupler. It is a good idea to test with a multimeter to make sure there is no continuity when measuring on either side of the “break” in the track to be sure that the connection is properly broken.

If you are like me and your soldering skills are not great, I would recommend testing the circuit before connecting it to your Pi. Get a friend to press your doorbell button while you measure continuity on the output side of the optocoupler – when the doorbell is pressed, the output side should be closed. When it is not pressed, it should be open.

I also like to test to make sure there is no continuity between consecutive tracks on the stripboard to make sure I didn’t accidentally solder a connection between tracks.

In the next post – how to display the camera overlay in Kodi.

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}}