Preparing the remote control app for Christmas

Winter is soon to arrive in Sweden and the amount of daylight is decreasing every day. Thus it’s time to set up some extra light sources indoors and outdoors. I have been using my web app for remote controlled outlets (link) for some months now, but with the additional light sources needed for this time of year, I have to extend the application. As Sweden goes into the dark season I would also like to have an on/off schedule for some of the lights so that they are turned on/off automatically according to a set of specified events.

About the original application

For details on the original application, check out my old post. It describes how to sniff/decode the radio signals that need to be recreated from a Raspberry Pi with the help of pi-switch.

Some new receiver outlets

I have now stocked up on some additional receiver sockets for indoor use and also an outdoor outlet from the same brand (Luxorparts, they where on sale) that fits my radio protocol.

Currently I have 10 receivers in total and to address them all I have to use the button number (1-4) and the group code (1-4) in combination. My original remote control application had a fixed group number and could only address 4 receivers, but it can easily be modified so that it handles 4×4=16 receivers.

The new hardware and the updated application will allow me to have remote control of the outdoor Christmas Tree as well as all the compulsory indoor light decorations at this time of year.

So let’s do the software changes…

Modifying the REST API

My app has a REST API backend that runs as a Python Flask service on a Raspberry Pi with Raspbian OS. I will change so that it addresses group number + button number instead of just button number. Using Curl, here are some GET and PUT examples on using the updated API:


# Examples on REST calls to the api
# Replace localhost:5000 with the IP-address and port of the machine where the api is running
# List all defined outlets (GET)
curl -i http://localhost:5000/Outlets/api/outlets
# Turn on power for outlet 1 in group 2
curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"on"}' http://localhost:5000/Outlets/api/outlets/2/1
# Turn on power for outlet 3 in group 1
curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"on"}' http://localhost:5000/Outlets/api/outlets/1/3
# Turn off power for outlet 3 in group 1
curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"off"}' http://localhost:5000/Outlets/api/outlets/1/3

The main script in the updated Flask application looks like this:


from flask import Flask, jsonify, request, render_template, abort
from outletdefinitions import outlets
import codesender
app = Flask(__name__)
@app.route("/Outlets/api/outlets", methods=["GET"])
def get_outlets():
return jsonify({"outlets" : outlets})
@app.route("/Outlets/",methods=["GET"])
def index():
return render_template("index.html")
@app.route("/Outlets/api/outlets/<int:groupNumber>/<int:buttonNumber>",methods=["PUT"])
def clickButton(groupNumber, buttonNumber):
state=request.json.get("state")
if (state is None):
abort(400)
if (state.lower() != 'on' and state.lower() != 'off'):
abort(400)
codesender.sendCode(groupNumber,buttonNumber,state)
return state
if __name__ == "__main__":
app.debug = True
app.run(host="0.0.0.0",port=5000)

It defines end points for getting a list of all defined outlets and for updating the state of an outlet with http PUT. There is also a route for serving up the html page for the Single Page Application (index.html).

The transmission of the radio signals is done in the sendCode method that uses pi-switch:


import pi_switch
from mylogger import logger
byte0codeON = 0x55
byte0codeOFF = 0x54
groupToCodeMap = {
1: 0x15,
2: 0x45,
3: 0x51,
4: 0x54
}
buttonToCodeMap = {
1: 0x15,
2: 0x45,
3: 0x51,
4: 0x54
}
def sendCode(groupNumber,buttonNumber,state):
if not buttonNumber in buttonToCodeMap.keys():
return
if not groupNumber in groupToCodeMap.keys():
return
numberCode = buttonToCodeMap[buttonNumber]
groupCode = groupToCodeMap[groupNumber]
byte0code = byte0codeON
if state == 'off':
byte0code = byte0codeOFF
code = (groupCode << 16) | (numberCode << 8) | byte0code
logger.info("Sending code: " + format(code,'000000x'))
sender = pi_switch.RCSwitchSender()
sender.enableTransmit(0)
sender.sendDecimal(code,24)

view raw

codesender.py

hosted with ❤ by GitHub

Modifying the front end

The application front end is built with AngularJS. It shows a row for each outlet and each row has two columns with an on button in column 1 and an off button in column 2. Instead of binding to just a button number, a binding to both group number and button number will now be used.

RC_APP_V2.PNG

The AngularJS-controller handles the button press events and calls the REST API asynchronously with the specified group- and button numbers.


var myApp = angular.module('myApp', []);
myApp.controller('OutletController', ['$scope', '$http', function($scope, $http) {
$scope.header = 'Outlets';
var getOutletInfo = function() {
$http.get("api/outlets").then(function(response) {
var outlets = response.data.outlets;
$scope.outlets = outlets;
}, function(error) {}
);
};
$scope.pressButton = function(groupNumber,buttonNumber,action) {
$http.put("api/outlets/"+groupNumber+"/"+buttonNumber, { state : action}).then(function(response) {
}, function(error) {}
);
}
getOutletInfo();
}]);

Scheduling on/off events

As this time of year in Sweden means more night than day it would be nice to have some lights turned on and off automatically at certain times. To achieve this, I could make a dedicated scheduler, but as my home automation system is based on a Raspberry Pi running Linux, it is more convenient to just set up a cron job that makes Curl calls to my application’s REST backend according to a schedule.

I use “crontab -e” to edit the event table for my user. It will be automatically parsed by cron at regular intervals and if a matching time expression is found, the associated command will be executed. My crontab file looks like this at the moment:


# Turn on outdoor lights in the afternoon
00 17 * * * curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"on"}' http://localhost:5000/Outlets/api/outlets/2/1
# Turn off outdoor lights in the morning
00 08 * * * curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"off"}' http://localhost:5000/Outlets/api/outlets/2/1
# Turn on downstairs window lights in the afternoon
30 19 * * * curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"on"}' http://localhost:5000/Outlets/api/outlets/1/2
# Turn on upstairs window lights in the evening
30 18 * * * curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"on"}' http://localhost:5000/Outlets/api/outlets/1/1
# Turn off all indoor lights at night
# windows upstairs
00 22 * * * curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"off"}' http://localhost:5000/Outlets/api/outlets/1/1
# windows downstairs
00 22 * * * curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"off"}' http://localhost:5000/Outlets/api/outlets/1/2
# Wall downstairs
00 22 * * * curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"off"}' http://localhost:5000/Outlets/api/outlets/1/3
# Floor upstairs
00 22 * * * curl -i -H "Content-Type: application/json" -X PUT -d '{"state":"off"}' http://localhost:5000/Outlets/api/outlets/1/4

view raw

crontab.sh

hosted with ❤ by GitHub

Let there be lights (and lots of them)

The complete code for this application can be fetched from GitHub: https://github.com/LarsBergqvist/RemoteControlled_Outlets

julgran.jpg

 

Leave a comment