Category Archives: How to

Philips Hue Entertainment setup and testing

Now that Philips has launched its Entertainment facility for the Hue lights, it’s time to implement and test the features.

What is Entertainment?

It’s a new method for the Bulbs to communicate, meaning that light effects and changes can be synchronised to the split second. This means that the bulbs can react to films, broadcasts, games and music without any lag.  The instructions are sent out in bursts and then carried out all at the same time by the bulbs themselves.  This, in the purest form, means that the bulbs are truly “smart”.

Setting an Entertainment area

You need to tell Hue where your entertainment area(s) are.  An entertainment area is a collection of lights that you want to join together when you’re doing an activity that will use Hue Entertainment – such as playing a video game or watching a film.  You set this up through the Hue app.  Open the app, go to Settings (the gears icon) then choose Entertainment areas.

Select a room or rooms where the entertainment area is to be set up.

HueEnt-01

Select the lights that will be used in your entertainment area.  Notice that Hue recommends the ones that will work best with this feature.  The recommended ones have increased range for brightness and can also show all colours more vividly.

HueEnt-02

Your selected lights appear on a pretend ‘map’ of your entertainment area.  Drag each one into where it is physically positioned in the room.  As you drag, the light in your room will flash so you know which one you are moving on the screen.  Each one will turn from orange to green once you have moved it.

HueEnt-03

When you have positioned the lights on the screen to match where they are, press Test area.

HueEnt-04

The lights will all change colour at the same time, to match the colours showing on the app.

HueEnt-05

Finally, the app will flash each light separately.

Once set up, the area is stored in the bridge’s memory for use later.  At this time the bridge also works out which bulb in the entertainment area should be used as the first point of contact to send out messages to the other bulbs in the area.  You can change this in the app but the automatic decision seems to work well.

Testing the Entertainment area

At the time of writing this entry, there is only one Entertainment partner available on the app – this is Razer hardware (a gaming hardware company).  However, there’s another way to test your new Entertainment area.

A reddit user called CrustaceanSoup has developed a Windows app called Huestacean which can be downloaded and run easily.  The app samples what is displayed on the screen and then converts this to colours in the entertainment area.  For example, you can watch a film or a YouTube video on your computer and your Hue lights sync perfectly to the action on screen.

Thoughts

Thanks to people like CrustaceanSoup we can see the potential for this amazing immersive experience.  The level of synchronicity takes my breath away.

I cannot wait to see how other partners join in with this.  More than merely matching what is on screen, I can see streamed films coming with encoded Hue light programs and live broadcasts sending their stage lighting to Hue to recreate in your living room.

For now, I would be really happy if Hue extended their already strong partnership with Apple and brought a similar screen-mirroring function to the Apple TV, this would mean that practically everything we watch could be extended outwards into the whole living room.

Advertisement

Creating a custom HTML front end for Domoticz Part 4 – YouTube companion article

You can click here for the related YouTube video.

My previous front end for Domoticz was very well received, thank you to everyone who asked for a copy or gave feedback.  I was encouraged to create a simpler to implement but still good-looking design.

The new look is based upon primarily grey and black, with the occasional flash of red or green.  This scheme can be changed easily in the css file of course.  The whole front end has been designed to look great on landscape tablets and portrait smartphones alike.

The front end has been primarily designed to work closely with Domoticz and has several options to insert onto the screen.  The options have been specifically designed to look different to each other even though through Domoticz they would look very much the same.  This is because people who do not routinely use Domoticz generally prefer a little variation in their screen to help them navigate functions.

The functions that look different are:

Feedback switch: Lights up a segment to the right when switch is on and remains dark when off.  Can be pressed anywhere to toggle the switch.

Non-feedback button: A large button which (usually) will switch on a Domoticz switch.  Can be used to activate things like scenes or timed functions such as heating boost.

Temperature / Humidity: Shows in readable text the status of a multifunction sensor.

Sensor: Provides colour feedback on the status of the sensor as well as data on when the sensor was last seen by the system (so for door sensors and doorbells etc this shows the last time the item was used).

Navigation bar: Shows icons which are used to help the user group and navigate across the web app.  Icons were obtained from Flaticon.com and therefore without providing different icons this code cannot be used for commercial gain.

The screen is set up in two ways depending on the orientation of the screen.

Landscape – used for tablet installations: the main section is to the left, with groups of switches in a smaller column to the right.

Portrait – used on smartphones: main screen is at the top of the visible screen, with groups of switches or sensors at the rear of the screen, provided in two columns.

The code is available to download and improve over on github at https://github.com/fountside/domoticz-tiles-user-interface  so you can access copies whenever you like.  You will need the css and at least one html page to get started, then use the elements and change the variables stated at the beginning of the page to match your own setup.  I would encourage anyone who improves this code to publish it within the repository so that others (including me!) can benefit from it.

From feedback I have recently received from readers and YouTube followers, it looks like Domoticz requires the security protocols to be in place, and this version has security built in.  You’ll need to convert your username and password into base64 (follow the instructions on the Domoticz page https://www.domoticz.com/wiki/Domoticz_API/JSON_URL’s to do this).

The only additional type of html document is specifically for Sonos using node-sonos-http-api.  If you already use this then all you’ll need to do is change the variables at the start of the HTML in the audio.htm file to match your rooms set up.  From this screen you can directly control individual rooms (click on the room name to change) and there is a clear graphical display showing album art.  You can launch your favourites and skip tracks.

I hope that this design work and code is of use to you, it is the next iteration of a long-term project of mine to design a near-perfect user interface for the smart home.

 

Creating a custom HTML front end for Domotiz Part 3 – YouTube companion article

We’re going to get a bit more clever now. When we have taught Domoticz a list of devices (be they switches or lights or door contacts) we may want to list them all in one go without manually entering a long list of html for each device. Also, if we can get the HTML front end to gather all the information about each switch, it means that we can update the contents of the buttons automatically, for example if we change the name of a device, it will automatically update in the HTML front end.

I’ve created some code to do this and the commentary on this is over on my YouTube video.

Here’s the code and two css files that you’ll need. Please note that the css files contain more than is needed at the moment: however the css will be needed in future articles.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<head>
<title>Home Control</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />

<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
	<link rel="shortcut icon" href="favicon.ico" />
	<link rel="apple-touch-icon" href="iphone-icon.png"/>
	<link rel="icon" sizes="196x196" href="logo.png">
	<link rel="icon" sizes="192x192" href="logo192.png">
	<link rel="stylesheet" media="(orientation: portrait)" href="portrait.css">
	<link rel="stylesheet" media="(orientation: landscape)" href="landscape.css">
	<link href="https://fonts.googleapis.com/css?family=Baloo|Comfortaa" rel="stylesheet">

<script language="JavaScript" type="text/JavaScript">
<!--
<!--

var devicestodisplay =[36,35,31,141,32,134,132,29,136,140,33,1617];
var nod=0;
var domoticzurl="192.168.1.163";
var domoticzport="8080";

function speak(textToSpeak) {
 // Create a new instance of SpeechSynthesisUtterance
 var newUtterance = new SpeechSynthesisUtterance();

 // Set the text
 newUtterance.text = textToSpeak;

 // Add this text to the utterance queue
 window.speechSynthesis.speak(newUtterance);
}

function switchon(devicecode){
 execute('PUT', 'http://'+domoticzurl+':'+domoticzport+'/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=On', '');
}

function switchoff(devicecode){
 execute('PUT', 'http://'+domoticzurl+':'+domoticzport+'/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Off', '');
}

function toggle(devicecode){
 execute('PUT', 'http://'+domoticzurl+':'+domoticzport+'/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Toggle', '');
}

function dim(devicecode,dimlevel){
 execute('PUT', 'http://'+domoticzurl+':'+domoticzport+'/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Set%20Level&level='+dimlevel, '');
}


function execute($method,$url,$message){
xmlhttp=new XMLHttpRequest();
xmlhttp.open($method,$url,true)
xmlhttp.send($message);
}
window.onload = function() {
 // all of your code goes in here
 // it runs after the DOM is built

 //updateweather();
 getalldevices();
 updatealldevices();
 }
 
window.setInterval(function(){
 updatealldevices();
 }, 1000);



function updatedevice(idx){
 var location="DEVICE"+idx;
 console.log("checking status of idx "+idx);
 var xmlhttp = new XMLHttpRequest();
 var url = 'http://'+domoticzurl+':'+domoticzport+'/json.htm?type=devices&rid='+idx;
 var onoff;
 xmlhttp.onreadystatechange = function() {
 if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
 var myArr = JSON.parse(xmlhttp.responseText);
 onoff = myArr.result[0].Status;
 devicename = myArr.result[0].Name;
 // myFunction(myArr);
 document.getElementById(location).innerHTML='<span class="device">'+devicename+'</span>';
 }
 if (onoff == "On") {
 document.getElementById(location).style.background = "red";
 } 
 if (onoff == "Off") {
 document.getElementById(location).style.background = "grey";
 }
 if (onoff == "Open") {
 document.getElementById(location).style.background = "red";
 } 
 if (onoff == "Closed") {
 document.getElementById(location).style.background = "grey";
 }
 }
xmlhttp.open("GET", url, true);
xmlhttp.send();
}

function getalldevices(){
fLen = devicestodisplay.length;
for (i = 0; i < fLen; i++) {
 preparediv(devicestodisplay[i]);
 getdevice(devicestodisplay[i]);
 }
}

function preparediv(deviceidx){
nod=nod+1;
var div = document.createElement("div");
div.className = 'devicecontainer';
div.id = "DEVICE"+deviceidx;
document.getElementById("devicesdiv").appendChild(div);
}

function updatealldevices(){
fLen = devicestodisplay.length;
for (i = 0; i < fLen; i++) {
 updatedevice(devicestodisplay[i]);
 }
}

function getdevice(idx){
 console.log("getting device idx" + idx);
 var xmlhttp = new XMLHttpRequest();
 var url = "http://"+domoticzurl+":"+domoticzport+"/json.htm?type=devices&rid="+idx;
 xmlhttp.onreadystatechange = function() {
 console.log(devicestodisplay[i] + " " +xmlhttp.readyState)
 if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
 var myArr = JSON.parse(xmlhttp.responseText);
 devicename = myArr.result[0].Name;
 devicestatus = myArr.result[0].Status;
 console.log(devicename + "(" + devicestatus+")");
 adddevice(idx,devicename,devicestatus);
 }
 }
xmlhttp.open("GET", url, true);
xmlhttp.send();
}

function adddevice(deviceidx,devicenametext,devicestatus){
nod=nod+1;
var div = document.createElement("div");
//div.style.width = "100px";
//div.style.height = "100px";
//div.style.background = "red";
//div.style.color = "white";
div.className = 'devicecontainer';
div.innerHTML = devicenametext;
div.id = "DEVICE"+deviceidx;

if (devicestatus=="On"){
 div.style.background = "red";
}

if (devicestatus=="Open"){
 div.style.background = "red";
}

if (devicestatus=="Off"){
 div.style.background = "grey";
}

if (devicestatus=="Closed"){
 div.style.background = "grey";
}

console.log("-------------"+div.id);
//document.getElementById("devicesdiv").appendChild(div);
document.getElementById(div.id).addEventListener('click', function() {
 { toggle(deviceidx); };
}, false);
}

function myFunction(arr) {
 var out = "";
 out += arr[0].result.Status;
 document.getElementById("id01").innerHTML = out;
}

//-->
</script>


<body>

<audio id="scene" src="assets/sounds/beep2.mp3" preload="auto"></audio>
<div align="left" class="toplinks">
<a href="index.htm"><span class="menutext">Home</span></a>
<a href="lights.htm"><span class="menutext">Lights</span></a>
<a href="devices.htm"><span class="menutext">Devices</span></a>
<a href="audiotrial.htm"><span class="menutext">Audio</span></a>
<a href="climate.htm"><span class="menutext">Environment</span></a>
<a href="security.htm"><span class="menutext">Security</span></a>
<a href="activities.htm"><span class="menutext">Other screens</span></a></div>
<div id="notification" align="center" class="notificationpane" onClick="clearnotification(11);"></div>
<div id="devicesdiv"></div>
</body>
</html>

Here’s the landscape.css file


body {
background-color:#000000;
font-family: 'Comfortaa', sans-serif;
margin: 0 0 0 0;
padding: 0 0 0 0 ;
}

.back-to-top {
background: none;
margin: 0;
position: fixed;
bottom: 50px;
right: 20px;
width: 150px;
height: 50px;
z-index: 100;
display: none;
text-decoration: none;
}

.back-to-top i {
font-size: 60px;
}

.timerselecttext {
font-size: 60px;
color:#FFFFFF;
}

.clockdisplay {
font-size: 250px;
color:grey;
}

div.clocktext {
font-size: 100px;
color:#000000;
}

div.weathertext {
font-size: 70px;
color:#000000;
}


div.standardcontainer {
background-color:grey;
position:relative;
width:25%;
height:25vh;
float:left;
padding-top:10px;
overflow:auto;
color:white;
font-size: 4vw;
text-align:center;
box-shadow:inset 0px 0px 0px 1px black;
}

div.doublecontainer {
background-color:grey;
position:relative;
width:50%;
height:25vh;
float:left;
padding-top:10px;
overflow:auto;
color:white;
font-size: 4vw;
text-align:center;
box-shadow:inset 0px 0px 0px 1px black;
}

div.devicecontainer {
background-color:grey;
width:25%;
height:12vh;
float:left;
padding-top:10px;
overflow:auto;
color:white;
font-size: 2vw;
box-shadow:inset 0px 0px 0px 1px black;
}


div.albumcontainer {
width:28vw;
height:28vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.trackcontainer {
width:70vw;
height:10vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.audiocontrols {
background-color:grey;
width:100vw;
height:10vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.audioactivitycontainer {

width:70vw;
height:10vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.camera {
background-color:grey;
width:100vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.camcontrols {
background-color:green;
width:300px;
float:right;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

span {
background-color: #ffffff;
color: #75099b;
font-size:20px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

div.nightclock {
background-color:#333333;
position:relative;
width:100%;
float:left;
padding-top:10px;
overflow:auto;
color:#666666;
font-size: 5vw;
text-align:center;
box-shadow:inset 0px 0px 0px 1px black;
}

span.title {
background-color:#666666;
color:#FFFFFF;
font-size:35px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.timertext {
background-color:green;
color:#FFFFFF;
font-size:70px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.playstate {
background-color:green;
color:#FFFFFF;
font-size:12px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.temptext {
background-color:green;
color:#FFFFFF;
font-size:40px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.roomname {
background-color:green;
color:#FFFFFF;
font-size:40px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.lightroom {
background-color:green;
color:#FFFFFF;
font-size:30px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}


span.device {
background-color:#666666;
color:#FFFFFF;
font-size:20px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.sensor {
background-color:#666666;
color:#FFFFFF;
font-size:18px;
display: inline-block;
padding: 3px 10px;
margin: 0px 5px;
font-weight: bold;
border-radius: 5px;
}


span.screentitle {
background-color:#666666;
font-family: 'Baloo', sans-serif;
color:#FFFFFF;
font-size:30px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
border-radius: 5px;
}

span.menutext {
background-color:#0066FF;
color:#FFFFFF;
font-size:24px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.datetime {
background-color:#009900;
color:#FFFFFF;
font-size:16px;
display: inline-block;
padding: 5px 5px;
margin: 0px 5px;
border-radius: 5px;
}


div.audioroomcontainer {
background-color:#66FF99;
float:left;
height:200px;
padding-top:10px;
overflow:auto;
font-size: 25px;
margin: 0 0 10px 10px;
}

div.nightmodecontainer {
background-color:#666666;
width:150px;
float:left;
height:200px;
padding-top:10px;
overflow:auto;
font-size: 25px;
margin: 0 0 10px 10px;
}


div.notificationpane {
background-color:#FFFFCC;
width:100%;
font-size: 2.5vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.nightnotificationpane {
background-color:grey;
width:100%;
font-size: 2.5vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.toplinks {
background-color:#66CCFF;
top:0px;
left:0px;
width:100%;
font-size: 30px;
box-shadow:inset 0px 0px 0px 1px black;
}

div.popuppanel {
background-color:grey;
width:100vw;
float:left;
padding-top:10px;
overflow:auto;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

and here’s the portrait.css file


body {
background-color:#000000;
font-family: 'Comfortaa', sans-serif;
margin: 0 0 0 0;
padding: 0 0 0 0 ;
}

.back-to-top {
background: none;
margin: 0;
position: fixed;
bottom: 50px;
right: 20px;
width: 150px;
height: 50px;
z-index: 100;
display: none;
text-decoration: none;
}

.back-to-top i {
font-size: 60px;
}

.timerselecttext {
font-size: 60px;
color:#FFFFFF;
}

.clockdisplay {
font-size: 200px;
color:#000000;
}

div.clocktext {
font-size: 100px;
color:#000000;
}

div.weathertext {
font-size: 70px;
color:#000000;
}


div.nightclock {
background-color:#333333;
position:relative;
width:100%;
float:left;
padding-top:10px;
overflow:auto;
color:#666666;
font-size: 5vw;
text-align:center;
box-shadow:inset 0px 0px 0px 1px black;
}

div.doublecontainer {
background-color:grey;
position:relative;
width:100%;
height:25vh;
float:left;
padding-top:10px;
overflow:auto;
color:white;
font-size: 4vw;
text-align:center;
box-shadow:inset 0px 0px 0px 1px black;
}

div.standardcontainer {
background-color:grey;
position:relative;
width:50%;
height:15vh;
float:left;
padding-top:10px;
overflow:auto;
color:white;
font-size: 2vw;
text-align:center;
box-shadow:inset 0px 0px 0px 1px black;
}

div.nightclock {
background-color:#333333;
position:relative;
width:100%;
float:left;
padding-top:10px;
overflow:auto;
color:#666666;
font-size: 5vw;
text-align:center;
box-shadow:inset 0px 0px 0px 1px black;
}

div.devicecontainer {
background-color:grey;
width:50%;
height:10vh;
float:left;
padding-top:10px;
overflow:auto;
color:white;
font-size: 2vw;
box-shadow:inset 0px 0px 0px 1px black;
}


div.albumcontainer {
background-color:grey;
width:100vw;
height:100vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.trackcontainer {
background-color:grey;
width:100vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.audiocontrols {
background-color:grey;
width:100vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.audioactivitycontainer {
background-color:grey;
width:100vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.camera {
background-color:grey;
width:100vw;
float:left;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

div.camcontrols {
background-color:green;
width:100vw;
float:right;
padding-top:0px;
color:white;
font-size: 3vw;
box-shadow:inset 0px 0px 0px 1px black;
}

span.menutext {
background-color: #ffffff;
color: #75099b;
font-size:3vw;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span {
background-color: #ffffff;
color: #75099b;
font-size:18px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.title {
background-color:#666666;
color:#FFFFFF;
font-size:18px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.timertext {
background-color:green;
color:#FFFFFF;
font-size:20px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.lightroom {
background-color:green;
color:#FFFFFF;
font-size:16px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}
span.temptext {
background-color:green;
color:#FFFFFF;
font-size:20px;
display: inline-block;
padding: 10px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}
span.device {
background-color:#666666;
color:#FFFFFF;
font-size:18px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.screentitle {
background-color:#666666;
font-family: 'Baloo', sans-serif;
color:#FFFFFF;
font-size:18px;
display: inline-block;
padding: 5px 5px;
margin: 5px;
border-radius: 5px;
}


span.menutext {
background-color:#0066FF;
color:#FFFFFF;
font-size:24px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.datetime {
background-color:#009900;
color:#FFFFFF;
font-size:12px;
display: inline-block;
padding: 5px 5px;
margin: 0px 5px;
border-radius: 5px;
}

span.sensor {
background-color:#666666;
color:#FFFFFF;
font-size:14px;
display: inline-block;
padding: 3px 10px;
margin: 0px 5px;
font-weight: bold;
border-radius: 5px;
}

div.audioroomcontainer {
background-color:#66FF99;
float:left;
height:200px;
padding-top:10px;
overflow:auto;
font-size: 25px;
margin: 0 0 10px 10px;
}

div.nightmodecontainer {
background-color:#666666;
width:150px;
float:left;
height:200px;
padding-top:10px;
overflow:auto;
font-size: 25px;
margin: 0 0 10px 10px;
}


div.notificationpane {
background-color:#FFFFCC;
width:100%;
font-size: 16px;
box-shadow:inset 0px 0px 0px 1px black;
}


div.toplinks {
background-color:#66CCFF;
top:0px;
left:0px;
width:100%;
font-size: 30px;
overflow:scroll;
box-shadow:inset 0px 0px 0px 1px black;
}

div.popuppanel {
background-color:grey;
width:100vw;
float:left;
padding-top:10px;
overflow:auto;
color:white;
font-size: 2vw;
box-shadow:inset 0px 0px 0px 1px black;
}

Creating a custom HTML front end for Domoticz part 2 – YouTube companion article

This article just shows the code that accompanies the next in the multi-part series explaining how I created my (reasonably popular!) HTML front end.

The icon I used can be downloaded from Flaticon.com but remember to download two versions, one you should rename dehumidifier-on.png and one dehumidifier-off.png

Here’s the code.

index.htm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<head>
<title>Home Control</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
		<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
		<meta name="apple-mobile-web-app-capable" content="yes" />
		<meta name="mobile-web-app-capable" content="yes" />
		<meta name="apple-mobile-web-app-status-bar-style" content="black" />

		<meta http-equiv="content-type" content="text/html; charset=utf-8" />
		<meta name="description" content="" />
		<meta name="keywords" content="" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
			<link rel="shortcut icon" href="favicon.ico" />
			<link rel="apple-touch-icon" href="iphone-icon.png"/>
			<link rel="icon" sizes="196x196" href="logo.png">
			<link rel="icon" sizes="192x192" href="logo192.png">
			<link rel="stylesheet" media="(orientation: portrait)" href="portrait.css">
			<link rel="stylesheet" media="(orientation: landscape)" href="landscape.css">

  	<link href="https://fonts.googleapis.com/css?family=Baloo|Comfortaa" rel="stylesheet">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<script language="JavaScript" type="text/JavaScript">

var domoticzurl="192.168.1.163"

function MM_goToURL() { //v3.0
  var i, args=MM_goToURL.arguments; document.MM_returnValue = false;
  for (i=0; i<(args.length-1); i+=2) eval(args[i]+".location='"+args[i+1]+"'");
}
function speak(textToSpeak) {
   // Create a new instance of SpeechSynthesisUtterance
   var newUtterance = new SpeechSynthesisUtterance();

   // Set the text
   newUtterance.text = textToSpeak;

   // Add this text to the utterance queue
   window.speechSynthesis.speak(newUtterance);
}

function switchon(devicecode){
	execute('PUT', 'http://' + domoticzurl + ':8080/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=On', '');
}

function switchoff(devicecode){
	execute('PUT', 'http://' + domoticzurl + ':8080/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Off', '');
}

function toggle(devicecode){
	execute('PUT', 'http://' + domoticzurl + ':8080/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Toggle', '');
}

function dim(devicecode,dimlevel){
	execute('PUT', 'http://' + domoticzurl + ':8080/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Set%20Level&level='+dimlevel, '');
}


function execute($method,$url,$message){
xmlhttp=new XMLHttpRequest();
xmlhttp.open($method,$url,true)
xmlhttp.send($message);
}

function toggleDiv(divId) {
   $("#"+divId).toggle(100);
}

function hideDiv(divId) {
   $("#"+divId).hide();
}
	
window.addEventListener("load", function(){
});;

function hideallDivs() {
    hideDiv("lights");
	hideDiv("devices");
}

//the following functions will run every second (due to the 1000 at the end).
window.setInterval(function(){
	updatedevice(36,'dehumidifier',"dehumidifier-on.png","dehumidifier-off.png");
	}, 1000);


// the following function checks to see if the idx is "on" or "off" and updates the image accordingly
function updatedevice(idx,location,onimage,offimage){
	console.log("checking status of idx "+idx);
	var xmlhttp = new XMLHttpRequest();
	var url = "http://"+domoticzurl+":8080/json.htm?type=devices&rid="+idx;
	var onoff;
	xmlhttp.onreadystatechange = function() {
    	if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
        	var myArr = JSON.parse(xmlhttp.responseText);
			onoff = myArr.result[0].Status;
       // myFunction(myArr);
    	}
		if (onoff == "On") {
		document.getElementById(location).src = onimage;
		} 
		if (onoff == "Off") {
		document.getElementById(location).src = offimage;
		}
		if (onoff == "Open") {
		document.getElementById(location).src = onimage;
		} 
		if (onoff == "Closed") {
		document.getElementById(location).src = offimage;
		}
	}
xmlhttp.open("GET", url, true);
xmlhttp.send();
}


</script>

</head>

<body>

<a href="javascript:;"  onclick="toggleDiv('lights');"><span class="navtitle">Lights</span></a>
<div id="lights" class="navlights">
Desk Lamp

<a href="javascript:;" onclick="dim(594,16);toggleDiv('lights');"><span class="buttontext">Max</span></a>
<a href="javascript:;" onclick="dim(594,12);toggleDiv('lights');"><span class="buttontext">75%</span></a>
<a href="javascript:;" onclick="dim(594,8);toggleDiv('lights');"><span class="buttontext">50%</span></a>
<a href="javascript:;" onclick="dim(594,4);toggleDiv('lights');"><span class="buttontext">25%</span></a>
<a href="javascript:;" onclick="switchoff(594);toggleDiv('lights');"><span class="buttontext">Off</span></a>

<hr width="90%" style="dashed" color="#FFFFFF" size="2">

Ceiling Lamp

<a href="javascript:;" onclick="dim(81,100);toggleDiv('lights');"><span class="buttontext">Max</span></a>
<a href="javascript:;" onclick="dim(81,75);toggleDiv('lights');"><span class="buttontext">75%</span></a>
<a href="javascript:;" onclick="dim(81,50);toggleDiv('lights');"><span class="buttontext">50%</span></a>
<a href="javascript:;" onclick="dim(81,25);toggleDiv('lights');"><span class="buttontext">25%</span></a>
<a href="javascript:;" onclick="switchoff(81);toggleDiv('lights');"><span class="buttontext">Off</span></a></div>
<a href="javascript:;"  onclick="toggleDiv('devices');"><span class="navtitle">Devices</span></a>
<div id="devices" class="navlights">
Dehumidifier

<a href="javascript:;" onclick="toggle(36);"><img id="dehumidifier" src="dehumidifier-off.png"></a></div>
</body>

And here are the 2 css sheets you need (I don’t know why I have done this yet but these will be useful when we start looking at device orientation.

Portrait.css

html {
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
background-color:#000000;
}
div.navlights {
display:block;
text-align:center;
position:relative;
width: 100vw;
margin:0vw;
background-color:#CCCCCC;
font-family: 'Comfortaa', cursive;
font-size:6vw;
font-color:#000000;
}
span.buttontext {
background-color: #ffffff;
color: #75099b;
font-size:6vw;
display: inline-block;
padding: 3px 10px;
margin: 1vw;
font-weight: bold;
border-radius: 5px;
}

span.toggletext {
background-color: #FF66CC;
color:#ffffff;
font-size:6vw;
display: inline-block;
padding: 3px 10px;
margin: 1vw;
font-weight: bold;
border-radius: 5px;
}

span.navtitle {
color: #FFFFFF;
font-size:5vw;
display: inline-block;
margin: 3vw;
font-family: 'Baloo',cursive;
font-weight: normal;
}

landscape.css

html {
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
background-color:#000000;
}
div.navlights {
display:block;
text-align:center;
position:relative;
width: 100vw;
margin:0vw;
background-color:#CCCCCC;
font-family: 'Comfortaa', cursive;
font-size:40px;
font-color:#000000;
}
span.buttontext {
background-color: #ffffff;
color: #75099b;
font-size:36px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.toggletext {
background-color: #FF66CC;
color:#ffffff;
font-size:36px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.navtitle {
color: #FFFFFF;
font-size:50px;
display: inline-block;
margin: 5px;
font-family: 'Baloo',cursive;
font-weight: normal;
}

 

Creating a custom HTML front end for Domoticz Part 1- YouTube companion article

ere’s the HTML and CSS you’ll need if you want to follow my guide over on my YouTube channel on how to create a custom user interface using HTML for Domoticz.

I’ve been asked many times for the code for my HTML interface and others have asked how to develop their own, so this step by step guide should help you to build a great looking interface that you can be proud of, and your family can use with ease.

In the index.htm file, when copied into a text editor, change the line:

var domoticzurl="192.168.1.163"

to the address of your Domoticz system.

Go to the Domoticz folder, then to the www folder, then create a folder called whatever you want your creation to be called.  I’ve called the folder fab for now.

Copy the three files into the folder.  Once complete, the Domoticz HTML server will serve up the page to whomever requests it.

Try it out by opening any browser and typing in

addressofyourdomoticzsystem:port/yourfoldername/index.htm

In my case this would be

192.168.1.200:8080/fab/index.htm

If all is well you should see your masterpiece!  Have a go at changing the names and idx codes of the devices and re-uploading and testing again.

As this HTML code sends HTTP requests, your browser may ask if you want to enable content.  This has happened on my desktop version of Google Chrome a few times.

There is some code at the top of the index.htm page that tells your browser that if you’re using a smartphone to open this page, you can save it to your homescreen.  The next time you open it, there will be no address bar and it will look like a web app.

save this text as index.htm


 


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<head>
<title>Home Control</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />

<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<link rel="shortcut icon" href="favicon.ico" />
		<link rel="apple-touch-icon" href="iphone-icon.png"/>
		<link rel="icon" sizes="196x196" href="logo.png">
		<link rel="icon" sizes="192x192" href="logo192.png">
		<link rel="stylesheet" media="(orientation: portrait)" href="portrait.css">
		<link rel="stylesheet" media="(orientation: landscape)" href="landscape.css">

		<link href="https://fonts.googleapis.com/css?family=Baloo|Comfortaa" rel="stylesheet">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<script language="JavaScript" type="text/JavaScript">

var domoticzurl="192.168.1.163"

function MM_goToURL() { //v3.0
 var i, args=MM_goToURL.arguments; document.MM_returnValue = false;
 for (i=0; i<(args.length-1); i+=2) eval(args[i]+".location='"+args[i+1]+"'");
}
function speak(textToSpeak) {
 // Create a new instance of SpeechSynthesisUtterance
 var newUtterance = new SpeechSynthesisUtterance();

// Set the text
 newUtterance.text = textToSpeak;

// Add this text to the utterance queue
 window.speechSynthesis.speak(newUtterance);
}

function switchon(devicecode){
 execute('PUT', 'http://' + domoticzurl + ':8080/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=On', '');
}

function switchoff(devicecode){
 execute('PUT', 'http://' + domoticzurl + ':8080/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Off', '');
}

function toggle(devicecode){
 execute('PUT', 'http://' + domoticzurl + ':8080/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Toggle', '');
}

function dim(devicecode,dimlevel){
 execute('PUT', 'http://' + domoticzurl + ':8080/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Set%20Level&level='+dimlevel, '');
}

function execute($method,$url,$message){
xmlhttp=new XMLHttpRequest();
xmlhttp.open($method,$url,true)
xmlhttp.send($message);
}

function toggleDiv(divId) {
 $("#"+divId).toggle(100);
}

function hideDiv(divId) {
 $("#"+divId).hide();
}

window.addEventListener("load", function(){
 hideallDivs();
});;

function hideallDivs() {
 hideDiv("lights");
 hideDiv("devices");
}

</script>

</head>

<body>

<a href="javascript:;" onclick="toggleDiv('lights');"><span class="navtitle">Lights</span></a>
<div id="lights" class="navlights">
Desk Lamp

<a href="javascript:;" onclick="dim(594,16);toggleDiv('lights');"><span class="buttontext">Max</span></a>
<a href="javascript:;" onclick="dim(594,12);toggleDiv('lights');"><span class="buttontext">75%</span></a>
<a href="javascript:;" onclick="dim(594,8);toggleDiv('lights');"><span class="buttontext">50%</span></a>
<a href="javascript:;" onclick="dim(594,4);toggleDiv('lights');"><span class="buttontext">25%</span></a>
<a href="javascript:;" onclick="switchoff(594);toggleDiv('lights');"><span class="buttontext">Off</span></a>

<hr width="90%" style="dashed" color="#FFFFFF" size="2">

Ceiling Lamp

<a href="javascript:;" onclick="dim(81,100);toggleDiv('lights');"><span class="buttontext">Max</span></a>
<a href="javascript:;" onclick="dim(81,75);toggleDiv('lights');"><span class="buttontext">75%</span></a>
<a href="javascript:;" onclick="dim(81,50);toggleDiv('lights');"><span class="buttontext">50%</span></a>
<a href="javascript:;" onclick="dim(81,25);toggleDiv('lights');"><span class="buttontext">25%</span></a>
<a href="javascript:;" onclick="switchoff(81);toggleDiv('lights');"><span class="buttontext">Off</span></a></div>
<a href="javascript:;" onclick="toggleDiv('devices');"><span class="navtitle">Devices</span></a>
<div id="devices" class="navlights">
Dehumidifier

<a href="javascript:;" onclick="switchon(29);toggleDiv('devices');"><span class="buttontext">On</span></a>
<a href="javascript:;" onclick="switchoff(29);toggleDiv('devices');"><span class="buttontext">Off</span></a>
<a href="javascript:;" onclick="toggleDiv('devices');"><span class="toggletext">Auto</span></a></div>
</body>


Save this text as portrait.css


html {
margin: 0;
padding: 0;
}

body {
margin: 0;
padding: 0;
background-color:#000000;
}

div.navlights {
display:block;
text-align:center;
position:relative;
width: 100vw;
margin:0vw;
background-color:#CCCCCC;
font-family: 'Comfortaa', cursive;
font-size:6vw;
font-color:#000000;
}

span.buttontext {
background-color: #ffffff;
color: #75099b;
font-size:6vw;
display: inline-block;
padding: 3px 10px;
margin: 1vw;
font-weight: bold;
border-radius: 5px;
}

span.toggletext {
background-color: #FF66CC;
color:#ffffff;
font-size:6vw;
display: inline-block;
padding: 3px 10px;
margin: 1vw;
font-weight: bold;
border-radius: 5px;
}

span.navtitle {
color: #FFFFFF;
font-size:5vw;
display: inline-block;
margin: 3vw;
font-family: 'Baloo',cursive;
font-weight: normal;
}


And finally save this as landscape.css


html {
margin: 0;
padding: 0;
}

body {
margin: 0;
padding: 0;
background-color:#000000;
}

div.navlights {
display:block;
text-align:center;
position:relative;
width: 100vw;
margin:0vw;
background-color:#CCCCCC;
font-family: 'Comfortaa', cursive;
font-size:40px;
font-color:#000000;
}

span.buttontext {
background-color: #ffffff;
color: #75099b;
font-size:36px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.toggletext {
background-color: #FF66CC;
color:#ffffff;
font-size:36px;
display: inline-block;
padding: 3px 10px;
margin: 5px;
font-weight: bold;
border-radius: 5px;
}

span.navtitle {
color: #FFFFFF;
font-size:50px;
display: inline-block;
margin: 5px;
font-family: 'Baloo',cursive;
font-weight: normal;
}

Syncing your Hue lights to Sonos – part 2

I successfully built a program to sync up Phillips Hue lights with Sonos in this post.  Unfortunately the Echonest API is no longer in use and I have run up to difficulties with authorising the replacement Spotify API (any help with that is gratefully received!).

I’ve also always fancied myself as a lighting technician and the responsiveness of the Hue lights got me thinking that there might be a way to sync my lights to a specific track or a bunch of tracks.  Imagine a party where the lights “do their own thing” until a track comes on that is recognised, and then the lights sync up in exactly the way you have programmed them.

I wanted to make the program do as a minimum the following:

  • Have a “default” setting where the lights change in a generic but random way
  • When a track starts, to detect that the track has “light cues” associated with it and to start playing the light cues alongside the track
  • To be synced to the second, so that the lights always “keep up” with the track
  • To be able to “join in” and catch up with the track, even if it is paused or rewound (completely or partly)

The attached files are small, and are by no means polished, but they do the job and the program can run all night successfully changing between “I don’t know this song so I’ll just do a random light show” to “Oooh! I know this song, let me load up the light cues and join in!”.

There are two parts: and Excel spreadsheet where the lights are encoded, and a small python program that is run to manage the current playing track and loading of the associated light cues if they exist.

This program also relies on the node-sonos-http-api code by Jishi available here (https://github.com/jishi/node-sonos-http-api)  with installation instructions mentioned in my previous Hue/Sonos post.  This node program should be running (it always is on my Raspberry Pi as I use it to control all Sonos throughout the flat using HTTP commands).

The Excel spreadsheet:

The spreadsheet is a macro-enabled spreadsheet that allows you to create, load, edit and save light cue files (saved as *.lig files).  Simply open the spreadsheet and listen to your music.  When you come to a part of the music that deserves a light change, you go to that line and then choose a function and type in some numbers.

At the top of the spreadsheet, type in the name of the track you want to set up a light cue datafile for.  Enter the whole location of the file but without any extension.  For example, if the track is called Like a Cat, and you want it to be saved in your C:\Users\Sample\Documents folder, in cell C5 type in C:\Users\Sample\Documents\Like a Cat

A word of caution here: run the program and change the Sonos to the track you want to encode first.  The program will show the exact name of the file it is looking for.  In order to simplify the program, it strips out brackets and hyphens, as well as commas and full stops (periods).  You may therefore end up with a track name that has a few extra spaces in it, so look out for that.

In cells C9 to L9 enter the reference numbers of each light you want to use in this song.  You can use all available lights or just some.  You don’t have to select the same lights for each song, but remember if one known song comes on after the other, some lights may remain as you left them in the first song if you don’t include them in the second song’s list.

In cell C11 enter the group number of the Hue lights you want to control.  This is useful as some of the light cues you can use address the whole group rather than individual bulbs in sequence.  You can set groups using the Hue API.

Listen to a song and then work out in your head what would be a good lighting effect.  Maybe you’d like each bulb to flick between strong random colours every 2 seconds, or maybe you want a low orange glow on all lights until the chorus, and then raise up the lights to a vivid red, maybe making them flash at just the right moment.

For each song you can enter as many or as few lines of light cues as you like, even just one at the beginning of the track, to change the lights to match the mood of the music for the whole song, or maybe an epic display matched perfectly to each bar.

Functions available are:

ALLSET which changes in sequence each light you have specified to use

CHGALL which changes the whole group of lights instead of each individual light

FLASH which pulses the lights either once or twice (depending on how fast your host machine is)

INDIV which controls one individual bulb (enter this in the Lightref/delay column). If you want to change 2 bulbs together just put two INDIV lines together, one after the other, a second apart.

ALLBRI ignores a lot of the variables supplied and just changes the whole group of lights to a specific brightness

ALLOFF and ALLON switch the whole group of lights off or on, at a transition time you specify

CHGSEQ changes each light sequentially, just like ALLSET, but waits a certain number of seconds you specify (enter this in the Lightref/delay column)

How to write a light cue line:

First choose what you want to do.  Let’s say in the very first second of the track we want to bring up all the lights to a dark, moody red colour.  Enter the following line.

hms1

I want to force the lights to one specific colour, so I have entered the same number into MinHue and MaxHue so that I am sure that colour 0 (red) will be chosen.

Then we want to spring into vibrant colours which change every 10 seconds, from the 15th second of the track.

hms2

Notice this time I have set MinHue to 0 and MaxHue to 65000 – this gives a good range of colours, in fact the whole spectrum.  I set MaxSat and MinSat to 255 as I don’t want to mix the colours with any white.  The closer you get to 0 for Sat, the more white is mixed in with the colour.  I have set TransTime to 10 because I want them to change over the period of 1 second.  I could have put 5 or 1 in there if I wanted a faster or instant response.  There is some randomness between the brightness too, from 100 (mid-dim) to 255 (bright).

I then copy this line from column D to column L and then paste into 25 seconds, 30 seconds, 35 seconds and so on.

When I get to the end of the song I just finish.  Nothing else to do unless you want to add some other flourishes.  Let’s go back to 2 minutes and 24 seconds, as there is one enormous drum solo that starts there and I would like to put pulsing white lights for 10 seconds.

hms3

Now just click the Export button at the top.  Excel won’t reportanything (I told you it wasn’t finished) but the light cue file will be saved in the location and with the name you specified in cell C5.  Make sure it has shown up.

You can quickly build up quite a catalogue of “*.lig” light cue files.

When done, copy these files to the location where you’ll be running the python program (oh, you’ll need to create or download one called “default.lig” which is the file that the program will open if the track playing does not have its own file).

Inside the python program change 192.168.1.94:5005 to the address of the server that is running for node-sonos-http-api (the address where server.js is running) and then change the Sonos zone name from “Living%20Room” to the one that will be playing the music.  If you want more than one player to play music (at a party for example) make sure the player you specify here is the “main” player and additional speakers are grouped to it.

Run the python program (in python 3) and you’ll see it start to wait for the Sonos player to start playing something.  Play one of the songs you have created a light cue file for and make sure it opens.  If it does, you’ll enjoy the fruits of your labour! If not, first check what file the program was actually looking for (each title is printed out by the program when the Sonos player changes track).

I hope you enjoy this small program and light cue creation spreadsheet.  Please let me know how you’d improve it or if you use it!  Thanks as always for your comments, they keep me writing these posts.

Downloads

Take off the “.doc” extension before using – WordPress does not allow me to upload *.py, *.xlsx or my own *.lig files.

hms.py

Default.lig

Hue Music Encoder 2.xlsm

Writing a home control front end in HTML.

I’ve been asked a few times about my custom front-end for my Domoticz, Hue and Sonos setup, so here are a few HTML snippets and where to put them, assuming you are running Domoticz on your home control server.

Right from the offset I must stress that the Icons I have used are made by various incredibly skilled designers at http://www.flaticon.com/ and therefore this front end cannot be used for any commercial purpose.

I have previously written an extensive post about the continuous development of a home control user interface and have posed a video containing my front end, so this post will not be about the thought process behind creating a UI, rather how I have managed to put one together using HTML.

I must also stress that I am not an expert in baking a web app.  Developers may read my code and scoff at its inefficiency but it works for me, and hopefully can give you some inspiration.

Layout

The layout of all panels follows the same template: A main area where the actual buttons and controls live, changing depending on which screen the user selects; the ‘scenes’ bar, a blue strip towards the bottom of the display which is a kind of ‘quick access’ ribbon for regularly used commands; and a Links bar which permanently shows the pages that can be displayed.

layout

There is also a ‘notifications’ display which shows up just above the scenes bar with information provided by a variable in Domoticz.  This text can be ‘cleared’ by touching it (more on this later).

All screens use variations on the same HTML so not every screen is shown in detail in this post.

Home Screen

Home

Home is where the heart is.  I like the home screen to be simple, uncluttered and good looking.  It’s by far the screen shown most regularly so less is more here.

The interesting part of this screen is the background.  It changes depending on the weather.  First I saved six 2000×600 backgrounds with names ranging from weatherback-rain.png to weatherback-fog.png.  You need cloudy, fog, partlycloudy, rain, snow and sunny.  I set the size of these backgrounds to fit the tablet which the screen is displayed on so you may need to adjust accordingly.

The HTML code to change the background depending on the weather is as follows (change xx, yyyy and zz to the address of your Domoticz server, the port Domoticz is using and the idx code of your weather source in Domoticz):

function updateweather(){

                var forecast

                var xmlhttp = new XMLHttpRequest();

                var url = "http://192.168.1.xx:yyyy/json.htm?type=devices&rid=zz";

                var forecast

                xmlhttp.onreadystatechange = function() {

                 if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

                 var myArr = JSON.parse(xmlhttp.responseText);

                                                forecast = myArr.result[0].ForecastStr;

                                                console.log("Forecast is " + forecast + ".")

       // myFunction(myArr);

                                                 if (forecast == "Partly Cloudy") {

                                                 document.getElementById("weatherindicator").src = "weatherback-partlycloudy.png";

                                                                }

                                                 if (forecast == "Sunny") {

                                                 document.getElementById("weatherindicator").src = "weatherback-sunny.png";

                                                                }                                                              

                                                if (forecast == "Rain") {

                                                 document.getElementById("weatherindicator").src = "weatherback-rain.png";

                                                                }              

                                                if (forecast == "Fog") {

                                                 document.getElementById("weatherindicator").src = "weatherback-fog.png";

                                                                }                              

                                                if (forecast == "Snow") {

                                                 document.getElementById("weatherindicator").src = "weatherback-snow.png";

                                                                }

                                                if (forecast == "Cloudy") {

                                                 document.getElementById("weatherindicator").src = "weatherback-cloudy.png";

                                                                }                                              

                                                }

                }

xmlhttp.open("GET", url, true);

xmlhttp.send();

setTimeout(updateweather,60000);

}

Notice that the last line of this code sets up the web page to update the weather picture every 60 seconds.  Ok, in the body of your HTML you’ll need something like

<div id="weatherdisplay" align="left" class="weatherback"><img id="weatherindicator" src=""></div>

And you’ll need something like this wherever you save your CSS:

div.weatherback {

    position: fixed;

    top: 0px;

    left: 0px;

    width: 1000px;

                height:600px;

}

Activating Hue scenes

The API for Hue is relatively easy to use.  I used the API to save scenes to each room and then can recall them from the press of an icon on the scenes bar.  The HTML at the scene bar is easy:

<a href="javascript:;" onClick="groupscene(1,7);switchoff(24)"><img src="scene-cinema.png" width="150" height="150" border="0"></a>

The button called scene-cinema.png does two things actually, sets the group 1 to scene 7 and then switches of a switch in Domoticz.  Let’s see the code for each of these functions:

function groupscene(group,scene){

                execute('PUT', 'http://192.168.1.aa/api/bbbbbbb/groups/'+group+'/action', '{"scene":"'+scene+'"}');

}

Change aa to the address of your Hue bridge and bbbbbb to the name of the developer (if you followed the Hue API instructions from the Hue website this might be “newdeveloper”.  If your scene does not change straight away then your control panel might not be authorised to the Hue bridge.  If this is the case, press the button on the Hue bridge and then try again a couple of times.

function switchon(devicecode){

                execute('PUT', 'http://192.168.1.xx:yyyy/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=On', '');

}

 

function switchoff(devicecode){

                execute('PUT', 'http://192.168.1.xx:yyyy/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Off', '');

}

 

function toggle(devicecode){

                execute('PUT', 'http://192.168.1.xx:yyyy/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Toggle', '');

}

 

function dim(devicecode,dimlevel){

                execute('PUT', 'http://192.168.1.xx:yyyy/json.htm?type=command&param=switchlight&idx='+devicecode+'&switchcmd=Set%20Level&level='+dimlevel, '');

}

The above codes (again change xx to the address of your Domoticz server and yyyy to the port number) are all similar. Switchon, switchoff do what they say on the tin.  Toggle changes the state of an on/off switch and then dim sets a certain switch you specify (idx) to the dim level you select (dimlevel).

While we’re here, here’s a list of the other Hue functions I put into the home control system:

function lightoff(light){

                execute('PUT', 'http://192.168.1.aa/api/bbbbbb/lights/'+light+'/state', '{"on":false}');

}

 

function lightmax(light){

                execute('PUT', 'http://192.168.1.aa/api/bbbbbb/lights/'+light+'/state', '{"on":true,"bri":255,"sat":0,"hue":0}');

}

 

function briup(group){

                execute('PUT', 'http://192.168.1.aa/api/bbbbbb/groups/'+group+'/action', '{"bri_inc":40}');

}

 

function bridn(group){

                execute('PUT', 'http://192.168.1.aa/api/bbbbbb/groups/'+group+'/action', '{"bri_inc":-40}');

}

 

function groupcontrol(group,hue,bri,sat){

                execute('PUT', 'http://192.168.1.aa/api/bbbbbb/groups/'+group+'/action', '{"on":true,"bri":'+bri+',"sat":'+sat+',"hue":'+hue+'}');

}

 

function groupscene(group,scene){

                execute('PUT', 'http://192.168.1.aa/api/bbbbbb/groups/'+group+'/action', '{"scene":"'+scene+'"}');

}

So these are the main components of the home page – and here’s a snippet of how I go the inside and outside temperature (change zz to the idx of your temperature sensor):

function updateintemp(){

                var instatus

                var xmlhttp = new XMLHttpRequest();

                var url = "http://192.168.1.xx:yyyy/json.htm?type=devices&rid=zz";

                xmlhttp.onreadystatechange = function() {

                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

               var myArr = JSON.parse(xmlhttp.responseText);

                                                instatus =  "Inside: " + myArr.result[0].Data;

                                                console.log(instatus)

                                                document.getElementById("intemp").innerHTML = instatus

                }

                }

xmlhttp.open("GET", url, true);

xmlhttp.send();

setTimeout(updateintemp,20000);

}

You need a div with id “intemp” positioned where you like, and again the last part of the above code sets up the web app to update the temperature each 20 seconds.

Devices screen

devices

The devices screen updates the icons with a green bar when the switch is on and a grey bar when off.  I save two identical png pictures, one with -on.png at the end and one with -off.png.  I enter this HTML repeatedly, changing the id and the source of the picture for each button:

<a href="javascript:;" onClick=”toggle(xx)"><img src="chesterlampoff.png" width="125" height="125" hspace="5" vspace="5" border="0" id="chesterlamp"></a>

Change xx to the idx of the device in Domoticz (you can find the idx of the device in the ‘Devices’ tab of the Domoticz interface.

Change the id=”chesterlamp” to id=”whateveryourdeviceiscalled” then change the img src to the ‘off’ picture for your device.

In the code part you need the following:

function updatedevice(idx,location,onimage,offimage){

                console.log("checking status of idx "+idx)

                var xmlhttp = new XMLHttpRequest();

                var url = "http://192.168.1.94:8080/json.htm?type=devices&rid="+idx;

                var onoff

                xmlhttp.onreadystatechange = function() {

                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

               var myArr = JSON.parse(xmlhttp.responseText);

                                                onoff = myArr.result[0].Status;

       // myFunction(myArr);

                }

                                if (onoff == "On") {

                                document.getElementById(location).src = onimage;

                                }

                                if (onoff == "Off") {

                                document.getElementById(location).src = offimage;

                                }

                                if (onoff == "Open") {

                                document.getElementById(location).src = onimage;

                                }

                                if (onoff == "Closed") {

                                document.getElementById(location).src = offimage;

                                }

                }

xmlhttp.open("GET", url, true);

xmlhttp.send();

}

Then another function where you will put all the code to tell the web app to update the icons depending on how Domoticz reports the switch (on or off, or even open or closed if you’re using door sensors too):

window.setInterval(function(){

                updatedevice(187,'chesterlamp',"chesterlampon.png","chesterlampoff.png");

                updatedevice(132,'washingmachine',"washingmachineon.png","washingmachineoff.png");

                countup();

                updatenotification(11)

                }, 1000);

I’ve put two switches here, Chester’s lamp and the washing machine.  You can add as many switches as you like here, as long as they have been set up in the body of the HTML.

There are two other functions that are called each second too: countup() and updatenotification(11)

Automatically reverting to the Home Screen

If you want the screen to revert to home after two minutes of inactivity, you can use this code:

First put

var ticker = 0;

at the start of your code block, then put:

function countup(){

                ticker=ticker+1

                console.log("Ticker is " + ticker);

                if (ticker>120) {

                                console.log("Moving to index...")

                                MM_goToURL('self','index.htm');

                                }

                }

This means that once the variable ‘ticker’ has incremented to 120, the screen will go to the page called index.htm.  If you use this code, remember to put this at the end of each function:

ticker = 0;

This will reset the timer so that another 2 minutes have been added to the time before the page will switch to the Home Screen.

Notifications from Domoticz

I have set up the screens to show a strip which indicates what Domoticz is up to.  Some of my LUA scripts in Domoticz update a variable with a string of text in English to tell the user what Domoticz is doing.  This could be confirmation that a switch has been turned on/off or it could report is something has been triggered automatically.

First, create a string variable in Domoticz called LastEvent and then note down its idx.  In the below case the idx is 11 (and there’s already a string update in there too, yours will be empty when you first set it up).

variables

Back to the home control HTML:

function updatenotification(idx){

                console.log("checking status of idx "+idx)

                var xmlhttp = new XMLHttpRequest();

                var url = "http://192.168.1.xx:yyyy/json.htm?type=command&param=getuservariable&idx="+idx;

                var textentry

                xmlhttp.onreadystatechange = function() {

                if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

               var myArr = JSON.parse(xmlhttp.responseText);

                                                textentry = myArr.result[0].Value;

       // myFunction(myArr);




                                document.getElementById("notification").innerHTML = textentry;

                                }

                                }

xmlhttp.open("GET", url, true);

xmlhttp.send();

}

And:

function clearnotification(idx){

                execute('PUT', "http://192.168.1.94:8080/json.htm?type=command&param=updateuservariable&idx="+idx+"&vname=LastEvent&vtype=2&vvalue=%00", '');

}

And in the body of the HTML (so once the text is clicked the variable in Domoticz is reset to null):

Something like this for the CSS: div.notificationpane {     position: fixed;     bottom: 250px;     left: 0px;                 width: 100%;                 font-size: 30pt;                 background-color: #333333;                 text-indent: 25px;                 opacity: 0.6; }

Then in the LUA script, when you want to notify the user about something, you can add a line like this:

commandArray['Variable:LastEvent'] = tostring(os.date("%H") .. ':' .. os.date("%M") .. ' Rear balcony door opened, lights on for 15 minutes.')

This adds the time and the text to the variable, which then almost immediately pops up on the Home Control screen until it is clicked.

Where to store your HTML

When you have created your masterpiece, you can save it in a new folder of your choice below the /domoticz/www/ folder.  You can use something like WinSCP to create a folder and then transfer all your files in one go.

Then, when you usually navigate to 192.168.1.1:8080 to go to the Domoticz home screen, add / then the name of your folder then /index.htm or whatever your home screen address is.

Summary

Due to the jerry-rigged nature of my HTML code I am not going to publish it in its entirety.  I also don’t know the ins and outs of using the flaticons.com icons and publishing them directly.  Hopefully, however, this post will give you some inspiration to write your own home control front end.

Creating a security system

A major plus for home automation is the ability to give any device multiple purposes.  With a little imagination, a Sonos speaker can become a voice announcer, a lightbulb can become an effective method of simulating occupancy in a home.

Everyone wants to feel their possessions are secure.  A standard house alarm is useful- and many are becoming smarter- but there is always the chance that a ringing alarm box is less of a call-to-arms and more of an annoyance to be ignored.  With that in mind, I would suggest building your own security system to notify you as soon as something is out of the ordinary.

This security system is created wholly from home automation products and is armed when you select a switch called “Leaving” on Domoticz, waits for 5 minutes to allow you time to come back in if you have forgotten anything (which I always do!), then after a further 5 minutes attempts to detect your phone(s) and if they are in wifi range, disarms the system again.

What you’ll need

  • Raspberry Pi running Domoticz
  • RFXCOM RFXtrx433
  • A number of door sensors, vibration sensors or PIRs (or any combination of these)
  • Python running on the Raspberry Pi
  • Maybe a network IP camera if you want to capture a photo when the alarm is triggered

How long it will take

Depending on the number of door sensors/PIRs/Cameras that you want to install, it could take anything from 15 minutes to several hours.

Step One – Install your devices

Choose entry points to your home.  The obvious one is the front door but also think about other places where someone may try to gain entry.

For doors, place the sensor towards the top of the door.  Remember to look at where the battery will need changing from, and ensure this will be easy to access by orienting the battery compartment/drawer towards the ground.  If space is limited, remember that there’s nothing to stop you attaching the larger part of the sensor (the transmitter) on the door itself and the smaller part (housing the magnet) on the frame of the door.  Use sticky strips first to test, even if you plan to screw the sensor to the door later.

For vibration sensors you can usually affix these directly to the window using suction cups.  If the type you have requires a more permanent fixing, try taping the sensor to the window first to ensure you (and other family members) are happy with their placement.

For PIRs, install these unobtrusive but accessible areas.  Remember that as these devices are wireless, you can even place them on shelves.  You don’t need to put them in corners of rooms like wired sensors.  Choose places where it would be impossible not to cross the detector if moving from room to room (hallways are a great position).  Remember that if you have pets the sensors should be raised up so that they can only be activated by humans.

Learn and name each sensor into Domoticz.  Remember to specify what type of device you are adding (PIR, Door sensor etc).

Step Two – Create a few Dummy switches

Create a dummy switch called “Leaving”.  This will be ON when you have left the home and OFF when you return.

Another dummy switch called “Security Alarm” is needed.  This is the switch that tells the scripts whether to send you an alert when a sensor is triggered.  You don’t want to get alerts when you are at home (as you’re probably the one triggering them!)

Another dummy switch called “Waiting for Phones” needs to be created.  This will be ON when the security system is waiting for you to return home.

Then create a switch for each phone you want to automatically disarm the system with.  I use two switches (“Chesters Phone” and “Harrys Phone”).

Finally, we need one more dummy switch – “Arm Security”.

Step Three – Write the scripts

A few scripts are needed now.  What will happen when you switch on the “Leaving” switch?  What about when it is turned off?  What happens when a sensor is activated and the “Security Alarm” switch is on?

The first code I write is saved as “device_SECURITY_Leave.lua” and is saved in the domoticz/scripts/lua/ folder

commandArray = {}
if devicechanged['Leaving'] == 'On' then
 commandArray['Environment Automation'] = 'Off'
 commandArray['Living Room Camera'] = 'On'
 commandArray['Security Alarm'] = 'Off'
 commandArray['Arm Security'] = 'On'
 commandArray['TEMP Set to 15'] = 'On'
 end
 return commandArray


This script (which I have reduced down as there are tens more switches to change when the flat is left unoccupied) runs once the Leaving switch is turned on.

We need a script to say when the alarm is activated – notice that I don’t switch the “Security Alarm” switch on with the above code.  If I did, once the Leaving switch was set, notifications would be sent to my phone as I walk through the flat to leave and open the front door.  I want to add a delay to the arming of the system.  This script is a timed script so starts with the text”script_time” instead of “script_device” – I’ve called it “script_time_SECURITY_Leaving.lua”

t1 = os.time()
s = otherdevices_lastupdate['Arm Security']
 
year = string.sub(s, 1, 4)
month = string.sub(s, 6, 7)
day = string.sub(s, 9, 10)
hour = string.sub(s, 12, 13)
minutes = string.sub(s, 15, 16)
seconds = string.sub(s, 18, 19)
 
commandArray = {}
 
t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
difference = (os.difftime (t1, t2))
print ('Leaving difference ' .. difference)

if (difference > 300 and otherdevices['Security Alarm'] == 'Off' and otherdevices['Arm Security'] == 'On') then
 commandArray['Security Alarm'] = 'On'
 commandArray['Arm Security'] = 'Off'
 print ('Security Alarm is now armed.')
 commandArray['SendNotification']='Security Armed#Security alarm is now armed.'
end 

if (difference > 600 and otherdevices['Waiting for Phone'] == 'Off' and otherdevices['Leaving'] == 'On') then
 commandArray['Waiting for Phone'] = 'On'
 commandArray['Harry Phone'] = 'Off'
 commandArray['Chester Phone'] = 'Off'
 print ('Waiting for phones to return.')
end 

return commandArray

Again, I’ve removed quite a few of the potential sensors to activate the alarm, but you get the idea.  You may notice another switch in there – “SECURITY Living Room”.  This switch is linked to a network camera we have in the living room, and thanks to the inbuilt scripting in Domoticz, sends a picture from the camera via email to multiple recipients.

The Security Screen of my homemade home control panel

The above script checks how long it has been since the “Arm Security” switch has been activated.  If 5 minutes, then the “Security Alarm” switch is turned on.  If 10 minutes, then the system starts searching for phones.  Living in a block of flats it is hard to judge the best interval for this.  On more than one occasions Chester and I have left the flat for the day, only to bump into a neighbour on the stairwell and have a gossip with them.  This has turned into more than a 10 minute delay, and as we’re still in range of our WiFi, this in turn switches off the “Security Alarm” switch.

Now we need the script to watch out for our phones to automatically disarm the system.  This is in three parts.  One part controls the timing (i.e. run a script every minute if waiting for phones to return) while the other two try to find our phones using a quick Python script.  The first goes in the domoticz/scripts/lua folder and I have called it script_time_SECURITY_Phones.lua:

commandArray = {}
if otherdevices['Waiting for Phone'] == 'On' then
 os.execute('python3 ./Security-Detection-Harry.py &')
 os.execute('python3 ./Security-Detection-Chester.py &')
end 
return commandArray

As you can guess, we now need some Python programs.  They are both the same (except each phone has its own static IP address and its own switch in Domoticz).  These are stored in the domoticz folder itself (not in any subfolder):

This one is called Security-Detection-Harry.py

import urllib
import requests
from random import randint 
import base64,requests,json,time,datetime
import os
"""
Detects Harry's phone and switches Domoticz if found.
"""
hostname = "192.168.1.1"
response = os.system("ping -c 1 " + hostname)
#and then check the response...
if response == 0:
   print (hostname, 'is up!')
   req = requests.get('http://192.168.1.94:8080/json.htm?type=command&param=switchlight&idx=176&switchcmd=On')
else:
   print (hostname, 'is down!')
   req = requests.get('http://192.168.1.94:8080/json.htm?type=command&param=switchlight&idx=176&switchcmd=Off')

So the above script searches for my phone (the IP address of my phone is fixed to 192.168.1.1) and switches a switch in Domoticz if my phone is detected or not.  In the above example Domoticz has given my “Harrys Phone” switch the number 17, so that’s the one I want to alter depending on whether the phone is present or not.

The next script deactivates the security alarm if the phones are detected.  Saved in domoticz/scripts/lua it is called script_device_SECURITY_Phones.lua:

commandArray = {}
if devicechanged['Waiting for Phone'] == 'On' then
 commandArray['Harry Phone'] = 'Off'
 commandArray['Chester Phone'] = 'Off'
end
if (devicechanged['Chester Phone'] == 'On' and otherdevices['Waiting for Phone'] == 'On' and otherdevices['Leaving'] == 'On') then
        commandArray['Leaving'] = 'Off'
        print("Chester's phone detected.")
 commandArray['SendNotification'] = 'Security Message#Chesters phone detected.  Disarming system and switching on devices.'
end
if (devicechanged['Harry Phone'] == 'On' and otherdevices['Waiting for Phone'] == 'On' and otherdevices['Leaving'] == 'On') then
        commandArray['Leaving'] = 'Off'
        print("Harry's phone detected.")
 commandArray['SendNotification'] = 'Security Message#Harrys phone detected.  Disarming system and switching on devices.'
end
if (devicechanged['Chester Phone'] == 'On' and otherdevices['Waiting for Phone'] == 'On' and otherdevices['Leaving'] == 'Off') then
        commandArray['Waiting for Phone'] = 'Off'
        print("Chester's phone detected.  No action taken.")
end
if (devicechanged['Harry Phone'] == 'On' and otherdevices['Waiting for Phone'] == 'On' and otherdevices['Leaving'] == 'Off') then
        commandArray['Waiting for Phone'] = 'Off'
 print("Harry's phone detected.  No action taken.")
end
return commandArray

Very nearly there!  This script is saved in domoticz/scripts/lua and is called script_device_SECURITY_Return.lua and tells Domoticz what to switch back on when one of us arrives home.

commandArray = {}
if devicechanged['Leaving'] == 'Off' then
        commandArray['Power Up'] = 'On'
        commandArray['Living Room Camera'] = 'Off'
        commandArray['Arm Security'] = 'Off'
        commandArray['Waiting for Phone'] = 'Off'
        commandArray['Security Alarm'] = 'Off'
        commandArray['Environment Automation'] = 'On'
 if otherdevices['VAR Dusk'] == 'On' then
         commandArray['DIMMER TV Lamps'] = 'Set level 100'
         os.execute('./Hue-LR-Darkday.py')
  commandArray['Front Balcony Lights'] = 'On'
 end
        commandArray['Air Purifier'] = 'On'
        commandArray['Living Room TV'] = 'On'
        commandArray['Washing Machine'] = 'On'
 commandArray['Cat Sitter'] = 'Off'
end
return commandArray

Now there’s only one thing left to do: decide what happens when the alarm is activated.  You could turn on lights, make sound come out of a network speaker, switch on the TV, contact you using the Domoticz alerts function… the list is endless.  Here’s some of my code, again stored in domoticz/scripts/lua and this is called script_device_SECURITY_Sensors.lua

commandArray = {}

if (devicechanged['DOOR Entrance'] == 'Open' and otherdevices['Security Alarm'] == 'On') then
 commandArray['SendNotification'] = 'Security Message#Front door opened.'
 commandArray['VAR Entrance'] = 'On'
        commandArray['SECURITY Entrance'] = 'On'
 print('ALARM ACTIVATED - FRONT DOOR SENSOR')

elseif (devicechanged['DOOR Hallway'] == 'Open' and otherdevices['Security Alarm'] == 'On') then
 commandArray['SendNotification'] = 'Security Message#Hallway door opened.'
        commandArray['SECURITY Living Room'] = 'On'
        print('ALARM ACTIVATED - HALLWAY SENSOR')

elseif (devicechanged['DOOR Hallway'] == 'Closed' and otherdevices['Security Alarm'] == 'On') then
 commandArray['SendNotification'] = 'Important Security Message#Hallway door closed!'
        commandArray['SECURITY Living Room'] = 'On'
        commandArray['VAR Entrance'] = 'On'
        print('ALARM ACTIVATED - HALLWAY SENSOR')end
return commandArray
This is a small (but functioning) fragment of all the sensors that will trigger a security alert in the flat if we are away and something unexpected happens.
Summary
I have probably made this system more difficult than it needs to be over time, but this security system does work flawlessly and does provide peace of mind when we’re away.  If you have some home automation sensors doing one type of job, why not get them involved in creating a bespoke security system… and make them earn their keep around your home.  Your family will thank you for it – as long as the process of arming and disarming the system is as user friendly as possible.

Controlling Sonos via LightwaveRF Mood Controllers

I had a request to write about how I control my Sonos players via my LightwaveRF Mood Controllers.  Actually, it’s a good call: re-engineering the mood controllers from simple light switches to pads which can control both lighting moods and audio more closely reflects the ‘built-in’ panels found in expensive custom installs.  In fact, using the technique below there’s nothing to stop you from controlling any number of home control activities from your mood controllers or handheld remotes.

I can say with authority that without these wall-mounted controllers all over the flat, I would never have been allowed to continue developing the system.  Having a familiar controller in each room ensures that users don’t need to run to the central controller or get out their smartphones whenever they want to make quick and regular changes to the light, heating or audio settings.

What you’ll need:

A summary is that node-sonos-http-api does the vast majority of the work, by ‘listening’ to all connected Sonos controllers and controlling them by very simple http requests.  These http requests are triggered by Domoticz once a signal is received from the mood controller.

How long this will take:

  • If you already have the Pi running Domoticz, and have been using a Sonos player already, and maybe have just bought a LigtwaveRF mood controller or other wall controller compatible with Domoticz, the whole thing will take about 30-40 minutes if you take your time.

Add the mood controller to Domoticz

From the Domoticz interface select the Switches screen, then select Learn Light/Switch at the top.  You should imagine the mood controller as two distinct switches stuck together: as far as Domoticz is concerned the two largest buttons are a completely different device compared to the four smaller buttons.

Immediately press the large OFF button (marked with a zero) on the mood controller.  In the box that appears give the mood controller a name – remembering that this is only the name given to the top two buttons of the controller (e.g Bathroom Lights).

This time we’re going to learn the lower row of the mood controller (the four smaller buttons). Repeat the above by pressing Learn Light/Switch and this time immediately press any one of the smaller buttons on the controller.  Name these too (e.g. Bathroom Audio).

Back up your Domoticz database

Just in case the next step causes problems for you it might be good to back up your system.  I’ve only needed to restore the system once – when I made a complete mess of installing node and npm.

Install node-sonos-http-api

I did this to install and it worked.  You may have a different setup or you may want to select another way of doing this.

Make sure you have node and npm installed.  If you don’t, search for and follow the instructions on how to install these carefully as I have messed this up more than once, by being all “I know how to do this, I’ll just skip this step”.  When will I ever learn?!

Get to the Domoticz folder and create a folder called sonos.

In the sonos folder, clone the node-sonos-http-api program by typing


git clone https://github.com/jishi/node-sonos-http-api.git

Navigate to the new node-sonos-http-api folder and fix the dependencies by typing


npm install

You can now run the program by typing


node server.js

Now the magic starts!  Open a browser and navigate to http://192.0.0.0:5005/Kitchen/play, where 192.0.0.0 is the address of your Pi and Kitchen is the name of your Sonos speaker.

The browser will ‘open’ a blank page, but the speaker in the room will start playing (assuming something is in the play queue.  If not use http://192.0.0.0/Kitchen/playlist/My%20Playlist.  This time, the playlist “My Playlist” is selected (make sure you use hex codes such as %20 instead of spaces in the URL- this includes rooms, so Living Room becomes Living%20Room).

Use the commands listed here to control your Sonos players.

Create scripts

Consider the commands you will want to send to Sonos via the mood controllers.

In this example my room is called Bathroom and the functions I want to add to the mood controller are play, pause, Radio 4 and a playlist called Harry 1.

I’ll need to create four scripts.  The easiest way to create scripts on the Pi  is to use nano, or off the Pi I use WinSCP.

Make sure the scripts are stored in the domoticz folder (not any subfolder).

The scripts will be called Sonos-BR-Play,.sh Sonos-BR-Pause.sh, Sonos-BR-R4.sh and Sonos-BR-Harry1.sh

Sonos-BR-Play will include the following text (just one line is needed to send an http request via a command called curl):

curl http://192.0.0.0:5005/Bathroom/play

Where 192.0.0.0 is the address of the Pi and ‘Bathroom’ is the exact name of the Sonos player.

The other 3 files contain very similar commands:

curl http://192.0.0.0:5005/Bathroom/pause

curl http://192.0.0.0:5005/Bathroom/favorite/BBC%20Radio%204

and

curl http://192.0.0.0:5005/Bathroom/playlist/Harry%201

So now I have these files in the domoticz folder.  I need to make them executable by Domoticz, so in the domoticz folder type


chmod u+x *.sh

We’re coming to the last part now!

Create LUA scripts for Domoticz

We need to run the scripts we created when Domoticz detects the button being pressed on the mood controller.  Let’s imagine the 4 small buttons on the mood controller are going to control the 4 functions we’ve just created scripts for.  The four buttons change the Domoticz device to Group Off, Group Mood 1, Group Mood 2 or Group Mood 3.  You can test this by pressing the buttons and waiting to see Domoticz change the status of the device.

I’m going to imagine that the mood controller’s set of 4 buttons is called ‘Bathroom Audio’ in Domoticz.

Go to the domoticz/scripts/lua folder and create a new file called script_device_BathroomAudio.lua

In the script I’m going to put this text in (you should see by the contents how you can change this):


commandArray = {}

if devicechanged['Bathroom Audio'] == 'Group Off' then

os.execute('./Sonos-BR-Play.sh')
print ('Bathroom Play via mood controller')

elseif devicechanged['Bathroom Audio'] == 'Group Mood 1' then
os.execute('./Sonos-BR-Pause.sh')
print ('Bathroom Pause via mood controller')

elseif devicechanged['Bathroom Audio'] == 'Group Mood 2' then
os.execute('./Sonos-BR-R4.sh')
print ('Bathroom Radio 4 via mood controller')

elseif devicechanged['Bathroom Audio'] == 'Group Mood 3' then
os.execute('./Sonos-BR-Harry1.sh')
print ('Bathroom Harry Playlist via mood controller')

end

return commandArray

That’s it! You should be able to control your Sonos anywhere you can stick a LightwaveRF mood controller.  Let me know how you get on!

Designing a user interface

Introduction

Something that I give a lot of thought regarding my home control set up to is the interface.  I have changed the ‘look and feel’ of the interface tens of times in the last few years (much to Chester’s frustration) and to be honest I don’t think I’ve ever found the ‘holy grail’.  But what makes a good home control interface and how would we recognise one?  I explore these questions with my guide to designing and implementing your own home control interface.

Step 1: Who will be using your interface, and on what?

One of the first things to think about is which devices will be displaying the interface.  In my household the interface is accessed via a fixed large tablet, a computer screen and smaller smartphone screens.  Therefore I may think about designing two types of interface, maybe that look and behave very similarly, one portrait (for holding a smartphone) and one landscape (for the computer screen and the permanent tablet on the wall).  I have designed two types in the past, but using a 100% web interface means that the content can adapt to multiple display types, therefore saving time and resources.

Step 2: Look at what is out there for inspiration (but don’t get too depressed with what you find).

If you search the internet for images of ‘home control interfaces’, you’ll see a few common themes.  I think the main thing that hits me is that although millions of pounds have been spent on perfectly attuning user interfaces in smartphones and computers (for example with the upcoming Windows 10 operating system), home automation interface design seems to have remained the same since its introduction. Without wishing to offend anyone here, I get the distinct impression that the interface is last on the development list.  It seems to me that the hardware takes priority, and then the interface is designed by someone in the existing team who really did not want the job.  I honestly believe this to be the main reason why home automation has not yet become mainstream.  It’s not the hardware: it’s the interface.

If you look hard enough however, you’ll find some clear and well-designed interfaces out there.  The companies that have chosen to invest in design are clearly the market leaders, and therefore can afford to spent time and money developing a look and feel that homeowners can use and appreciate.

What is the one design element that proves to me that the interface has been developed professionally?  Space.  Too many home control screens are jammed full of buttons, sliders and album art.  It’s hard to know where to look, and although this may be something of a visual trophy for the geek community – think how confusing this will look to others in your household.  This leads nicely on to my next step…

Step 3: Think about the order of things.  How will your commands ‘flow’?

As far as I am concerned, there are two main ways to organise your home control screens: by location or by function.  Organising by location means that you gather all your controls for one room onto one screen, so for the living room you’d have all the lights, the dehumidifier, the air conditioner and the TV controls all together.  Conversely, organising by function means that you’d put the controls for all your lights on one screen, heating and cooling on another screen, security on another screen etc.

I have created dozens of versions of both, and I personally prefer the latter.  For me it means that the user starts from the home screen with a definite decision on what they are intending to do.  The interface becomes less of a show-home piece and more of a practical and logical day-to-day assistant.

There is a balance to be achieved between the number of options displayed on the screen at one time and the number of selections required to perform an action.  Instead of scrolling through one giant page of options, or having to reduce button size down to miniscule proportions, it may be better to increase the number of screens and create a ‘flow’ for the user.  So instead of selecting ‘Audio’ and immediately being presented with a screen full of options, it may be better to then ask ‘Where do you want to the audio to play?’ and further ‘What kind of audio?’.

flowexample

Step 4: Write it down!  Plan your screens.

I have wasted literally days of my life not following this simple step.  Plan your screens on paper.  Falling out from this step will be all the buttons you will need for each screen.  Don’t worry about what the screens will look like yet, just think about what options you want to show.

Navigation is a consideration here.  How will your users know where they are?  If you provide ‘breadcrumbs’ on your display (Home > Audio > Living Room) you’ll need to reserve the same area on each screen for that.  To get back to the main screen, will the ‘home’ button be in the same place for each screen?

Step 5: Get ‘the look’ and stick to it.

Decide on a look and feel for your interface.  You may choose to compliment your home décor or to stand out as an ultramodern feature.  Either way, this step requires as much external input as possible.  If you’ve found some designs that you liked from step 2, speak to your users about which ones they prefer, and what they’d like to see.

When you’ve selected a look – stick to it.  By that I mean don’t be tempted to bend your own rules.  Future-proof your design.  For each of your screens ensure that there will be scope to add new devices in the future with ease.  Don’t make your icons or buttons so intricate that you’ll not be able to match them easily.

If each of your buttons contains an icon and some text, make sure the icons are roughly the same size and the text is the same size and font.  Little things like ensuring there is consistent capitalisation across your interface can make a huge difference.  “Living Room Lights On” next to “Living room lights OFF” leaves an unprofessional air.

hc-fsexample

After years of designing interfaces for my own home, I have some pearls of wisdom for you here.  The first is to use perfectly square, flat buttons.  These look modern and will not go out of fashion (if you are reading this in 2020 and flat buttons are out of fashion, then I apologise).  Another reason I prefer perfectly squared icons, is that depending on what interface controller you use, you may be disappointed at how the controller renders curved corners, and your beautiful vision becomes a pixelated mess.  The bigger the button, the better.  Our cleaner visits once a week, and if she needs to use her glasses to see an option, I change the button immediately.  Larger buttons also means that fewer options can fit on each screen, and I am all for that.

Get each button you need from step 4 designed now.  I would recommend you put a selection of these buttons in one mocked-up screen to ensure they are the right size and they look right.  Choose unobtrusive wallpaper or a solid inconspicuous colour for the display.

Step 6: Think about feedback.

The devices your user will be controlling may not be in the same room as the interface, so remember that they may need reassuring that what they have requested has been carried out.  There are a few ways to achieve this.

A button which changes its look depending on the state of the device is one way to go.  This approach is more common in consumer installations and requires constant sensing (called ‘polling’ in home automation terms) to ensure that all interfaces ‘keep up’ with the device’s status.  Don’t forget that someone could switch on a device from their smartphone, so then the corresponding button will need to update on all screens to reflect this.   One such controller that is capable of keeping track of devices is Openremote – more on this in step 8.

Another idea is that a pop-up box could appear to confirm your selection, for example confirming “Fan in Living Room has been switched on.”

The panel itself could speak to you.  I have elected to use this as my primary feedback method in my latest interface design.  The display is not obstructed by pop-ups, and the user can walk away from the panel and will still hear the announcement.

Feedback should also be provided automatically, for example when a security alert is activated or when a user needs to do something that cannot be completed automatically (such as a reminder to close a door).  Users could be anywhere when this feedback needs to be given, so thinking beyond the physical interface of a screen, what other devices could be used?  In our home, we have Sonos speakers in every room, so urgent feedback can be given via spoken word through them.  For smoke alarms triggered by Nest, the Hue lights in each room will flash momentarily, alerting occupants that action needs to be taken.  I also use Notify My Android (NMA) via Domoticz to keep me informed via short ‘texts’.

Step 7: Remember the ‘automation’ in ‘home automation’.

Advanced controls that only you will use can be tucked away at the ‘back’ of your interface.  Settings and variables can be as hidden away as you like, followed by screens for ‘fine tuning’ settings for devices that other users will probably never use.  It’s sometimes useful to control one individual lamp in the living room, to set brightness, colour and saturation until it’s just perfect.  But how often do you actually do that? It would be wiser to initially show a list of pre-set scenes to be selected from, and then have the option to move to a different screen to change individual lights if required.

Just because your system can do something, don’t give it pride of place and assume that every user will want to do it.  I have been guilty of re-building my interface around that a newly-purchased piece of hardware, just to show it off its new features.  This is a waste of time and ultimately confuses other users.

Step 8: Where to host your interface?

This depends on your home control set up.  I have used a few different downloadable options here, one being Openremote which is a program that runs on your computer or Raspberry Pi and ‘serves’ up information to panels around the home.  By polling your home control hardware at intervals you can select, Openremote can keep track of your devices.

Domoticz also has its own user interface that can be used on a plethora of screen sizes, however although I absolutely adore Domoticz and use it as the basis of all my home control activities, I think that the user interface is – dare I say it – where there has been less development.  By no means do I think this is a let-down however, as I would not have been able to thoroughly automate our home without Domoticz.

Another route – which is the one I have taken – is to design a web-based interface from scratch.  As Domoticz has a ‘www’ folder that can serve up any html document in that folder, I don’t need a separate web server.  I just upload all the html screens into a sub-folder of the Domoticz/www folder and then navigate to that page from any panel in the home network.  Here’s the secret.  Controlling Domoticz devices from a web-page is really easy.  You just have to navigate to a specific address and Domoticz will turn on a device.  You can get more information about that on the Domoticz API/JSON URLs page.

The only thing I had to work out for myself is – when I navigate to a URL asking Domoticz to turn on a device, the screen shows a ‘result page’.  The user would have to then click the browser’s ‘back’ button to get away from this result page and then back to the interface.  To solve this, I use a very small frame at the bottom of the screen.  When the user clicks a selection in the main screen, the link is followed in the small frame at the bottom, so as not to disrupt the main window.

Step 9: Testing and Rollout

Before announcing to your loved ones that you have created a masterpiece, I would encourage you to test every function on every page of your home control interface, especially those functions which will affect many devices in the home.  As an example, choose a time when no-one else is around and activate your ‘leave’ function and see if it does actually behave in the way you expect.  It’s too late when your family is ready to leave and you proudly press the button, only for the whole system to crash.  Trust in the system as a whole can also be eroded in this way.

Personally, I have the flat to myself every other Friday, only having to navigate around our cat.  I use this opportunity to test new functions I have added.  Our neighbours must think the flat goes crazy every two weeks, but it’s worth it.

Once everything is ready, you can add links to your interface on every device that will access it.  You can now go back to step one to restart the process.  I say this with confidence because as I stated at the start of this article, there is no ‘perfect’ user interface and there are always improvements to be made.  I truly believe that I will always be in pursuit of user interface perfection.