Tag Archives: Code

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

Advertisement

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