Creating a beautiful front-end for Domoticz

In a previous post (here), we created a simple front-end for Domoticz running on a Raspberry. In this post, we’ll take it a step further and style it a bit to look beautiful. It’s good if you go through the previous post first since we are going to build on that code base.

Areas you need to be familiar with to follow this post

  • Code base used in previous post (here)
  • Bootstrap (you can download it here)
  • CSS

Starting with the design

At the end of this post we want to have a design of our user interface looking like this:

front-end_design

Adding the Bootstrap structure to the HTML file

We have downloaded Bootstrap and extracted the folders in the folder where we have our HTML file from previous post. We add the following two lines of code to include the Bootstrap CSS and JS libraries.

[code language=”html”]
<!DOCTYPE html>
<html>
<head>
<title>Home Security Frontend</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="http://code.jquery.com/jquery.js"></script>
<!– Bootstrap –>
<script src="js/bootstrap.min.js"></script>
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
[/code]

Adding rows for the Bootstrap structure

In the body of our HTML file, we add three Bootstrap rows. The first one is for adding a nice logo and a ticking clock, the second one is for adding the house icon and the status of the security panel, and the final one is for listing all the sensor information. All three rows must be wrapped in a <div> with a class labeled “container”.

[code language=”html”]

&lt;div class="container"&gt;

&lt;div class="row"&gt;

&lt;div class="col-sm-12" id="top-bar"&gt;
&lt;img id="yellington_logo" src="https://www.yellington.com/yellington_logo.png"&gt;

&lt;div id="clock"&gt;&lt;/div&gt;

&lt;/div&gt;

&lt;/div&gt;

&lt;div class="row"&gt;

&lt;div class="col-sm-6 v-align" style="text-align: right;"&gt;

&lt;span class="glyphicon glyphicon-home" id="house-image"&gt;&lt;/span&gt;

&lt;/div&gt;
&lt;div class="col-sm-6 v-align" id="house-status-text"&gt;&lt;!– keep the opening a closing div tags together to avoid white space causing line breaks in the user interface–&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;div class="row" id="sensor-container"&gt;
&lt;/div&gt;

&lt;/div&gt;

[/code]

The glyphicon image is part of the Bootstrap package and we will use it as our house image in the first row. The “v-align” class will be used in the CSS/style part of our HTML file to align the house image vertically in the middle with the status text of the security panel. Keeping <div></div> on line 14 together is intentional to avoid adding any whitespace when rendering the two columns on the same row in the browser.

Expanding the JavaScript functionality

We will expand the JavaScript part of our HTML file with the following:

  • Wrap the functionality of updating the sensor data in a separate function: updateSensors()
  • Add a function: getSensorImage() to borrow some nice looking sensor images from Domoticz
  • Add the time in the top row. This will be a ticking clock since we update the data automatically with one-second intervals
  • Fetch the status of the security panel
  • Finally set a timer with a one-second interval to update all data automatically.

The script code looks like this:

[code language=”javascript”]
&lt;script&gt;
$(document).ready(function(){

var domoticzURL = "http://192.168.1.99:8080/"; //use this format if you want to place this file on another computer on your home network.
//var domoticzURL = "../"; //use this format if you place this file in a folder in the www folder on your Domoticz server.

$(function() {
updateSensors();
});

function getSensorImage(sensorType){
//This function returns the image of the sensor that is stored in the image folder on your Domoticz server

var sensorURL = "";

//The list of sensor types can be expanded dependant on what type of sensors you have
switch(sensorType) {
case "Light/Switch":
return domoticzURL + "images/Light48_On.png";
break;
case "Temp + Humidity":
return domoticzURL + "images/temp-20-25.png";
break;
default:
return domoticzURL + "images/Light48on.png";
}

}

function updateSensors() {

var sensorInfo = "";

//First we publish the time in our user interface
var d = new Date();
var hours = d.getHours();
if (hours &lt; 10) { hours = ‘0’ + hours;}
var minutes = d.getMinutes();
if (minutes &lt; 10) { minutes = ‘0’ + minutes;}
var seconds = d.getSeconds();
if (seconds &lt; 10) { seconds = ‘0’ + seconds;}
document.getElementById("clock").innerHTML = hours + ":" + minutes + ":" + seconds;

//We request a list of all sensor data and loop through it to publish on our web page
$.getJSON(domoticzURL + "json.htm?type=devices&amp;filter=all&amp;used=true&amp;order=Name", function(result){

for (i = 0; i &lt; result.result.length; i++) {
sensorInfo += ‘
&lt;div class="col-sm-6 col-md-4 col-lg-3 sensor-outer-box"&gt;’+

&lt;div class="sensor-box"&gt;’+
‘&lt;img class="sensor-icon" src="’ + getSensorImage(result.result[i].Type) +’"&gt;’+

&lt;div class="sensor-data"&gt;’+

&lt;h4&gt;’ + result.result[i].Name + ‘&lt;/h4&gt;

‘+

&lt;h5&gt;Status: ‘ + result.result[i].Data + ‘&lt;/h5&gt;

‘+

Updated: ‘ + result.result[i].LastUpdate +’

‘+
‘&lt;/div&gt;

‘+
‘&lt;/div&gt;

‘+
‘&lt;/div&gt;

‘;
}

document.getElementById("sensor-container").innerHTML = sensorInfo;

//We retrieve the status of the security system, baically Disarmed, Armed Away, or Armed Home
$.getJSON(domoticzURL + "json.htm?type=command&amp;param=getsecstatus", function(result){

var homeSecurityStatus="";

if (result.secstatus==0) homeSecurityStatus="Disarmed";
else if (result.secstatus==1) homeSecurityStatus="Armed Home";
else if (result.secstatus==2) homeSecurityStatus="Armed Away";
else homeSecurityStatus="Unknown";

document.getElementById("house-status-text").innerHTML = ‘
&lt;h5&gt;Home Security Status&lt;/h5&gt;

‘+

&lt;h2&gt;’ + homeSecurityStatus + ‘&lt;/h2&gt;

‘;

//Finally we set a timer to repeatedly poll the status of the sensors
setTimeout(updateSensors(),1000);

});
});

}

});

&lt;/script&gt;
[/code]

Note that the final getJSON call is nested within the callback function from the first getJSON call to get the sensor data. The domoticzURL variable could either be set to the IP number of your Raspberry + port 8080 or, if you upload the HTML file in the www root of your Domoticz server, you can set it to “../” or “./” dependant on if you put it in a subfolder or not. If you open the HTML file in a browser it looks something like this, still not very beautiful.

front-end_without_css

Styling the user interface with CSS

For the simplicity of this post, we will put all the styling in the HTML file. You can just as well put it in a separate CSS file and include it in the <head>. We add the following styling:

[code language=”html”]
&lt;/script&gt;

&lt;style&gt;
body{background-color: grey; padding: 0px 1% 0% 1%;}
.container{padding: 0px 20px 20px 20px;border-radius: 5px; background-color: white; border-style: solid; border-color: grey; border-width: 2px;box-shadow: 0px 0px 10px white;margin-top: 2%}
.row {border-bottom-style: solid; border-color: grey; border-width: 1px;}
#yellington_logo {max-width: 100px; margin: 5px; }
#top-bar{text-align: left; margin-bottom: 1px; padding: 0px;}
#clock{float: right; margin: 5px;}

.v-align {float: none; display: inline-block;vertical-align: middle;} /*class for vertically aligning elements in a row*/

#house-image{font-size: 9em; vertical-align: middle; display: inline-block; margin-top: 10px; margin-bottom: 10px;}
#house-status-text{text-align: left;}

.sensor-outer-box {padding: 0px;}
.sensor-box{padding: 0px;margin: 5px; background-color: white; box-shadow: 5px 5px 10px #888888; border-style: solid; border-color: grey; border-width: 1px; border-radius: 5px;}
.sensor-icon{vertical-align: 80%; margin: 0px;}
.sensor-data {display: inline-block; margin: 0px;}

&lt;/style&gt;

&lt;div class="container"&gt;
[/code]

The result is a user interface with responsive design

Thanks to Bootstrap, we automatically get a user interface with a responsive design that works just as well on a laptop and tablet as it does on a smartphone.

On a laptop:

front-end_domoticz_wide

On a smartphone:

front-end_design

You can play around with the style part of the file and the Bootstrap columns definitions to completely change the look and feel of the user interface to your liking.

Creating a simple web frontend for Domoticz

In this post we will create a simple web user interface for Domoticz running on a Raspberry Pi. This will allow us to check the status of our sensors and the status of the security panel of Domoticz.

In order to follow the steps we go through here, you should have a fair understanding of:

  • HTML, Javascript, and jQuery (and ideally CSS)
  • JSON data format
  • How to upload your HTML file to your Raspberry using FTP or SFTP (useful guide)

Retrieving sensor data using JSON http request

Domoticz provides a JSON http interface for reading the sensor values remotely. Use can test it by typing a JSON http request in the address field of your web browser. If you type the below request, it should fetch all the sensor data to your browser:

192.168.1.99:8080/json.htm?type=devices&filter=all&used=true&order=Name

The response contains a lot of information.

{
   "ActTime" : 1457448022,
   "ServerTime" : "2016-03-08 15:40:22",
   "Sunrise" : "06:41",
   "Sunset" : "17:56",
   "result" : [
      {
         "AddjMulti" : 1.0,
         "AddjMulti2" : 1.0,
         "AddjValue" : 0.0,
         "AddjValue2" : 0.0,
         "BatteryLevel" : 255,
         "CustomImage" : 0,
         "Data" : "On",
         "Description" : "",
         "Favorite" : 1,
         "HardwareID" : 3,
         ---

We will create an HTML file with JavaScript that extracts the information that is relevant for us. This will primarily be the sensor name, value and time when it was last updated.

Creating a basic HTML file with a JSON http request using Javascript

We start with a basic HTML file prepared with the jQuery library included. We create one <div> element with the id “sensor-container”. It’s within this <div> we will publish the sensor data.

<!DOCTYPE html>
<html>
 <head>
  <title>Home Security Frontend</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://code.jquery.com/jquery.js"></script>
 </head>
 <body>
  <div id="sensor-container">
  </div>
 </body>
</html>

Next we add a simple script to publish the name, status and update time of the first of our sensors. This script uses a JSON http request to retrieve the data from your Domoticz server. The response data will be accessible through the callback function with the parameter “result”.

<body>
 <script>
  $(document).ready(function(){

   //We request a list of all sensor data
   $.getJSON("http://192.168.1.99:8080/json.htm?type=devices&filter=all&used=true&order=Name", function(result){
 
 document.getElementById("sensor-container").innerHTML += '<div>'+
     '<h4>' + result.result[0].Name + '</h4>'+
     '<h5>Status: ' + result.result[0].Data + '</h5>'+
     '<p>Updated: ' + result.result[0].LastUpdate +'</p>'+
    '</div>';
   });
});
 </script>
<div id="sensor-container">
</div>

To extract the desired data we access the “result” array by indexing it with the number of the sensor. The number [0] corresponds to the first sensor in the array. The HMTL file with the JSON scripts gives the following output in our browser when we run it from our laptop.

Our power plug
Status: On
Updated: 2016-03-08 19:21:00

It’s not super beautiful but it works. The name of our first sensor is “Our power plug”, the status in “On” and it the information was last updated 19:21. Since we want to make our frontend work with all the sensors with have set up with Domoticz, we simply have to loop through the “result” array given to us in the JSON http request. We update our scripts with a for loop like this.

<script>
 $(document).ready(function(){

  var sensorInfo = "";

  //We request a list of all sensor data and loop through it to publish on our web page
  $.getJSON("http://192.168.1.99:8080/json.htm?type=devices&filter=all&used=true&order=Name", function(result){
 
   for (i = 0; i < result.result.length; i++) { 
    sensorInfo += '<div>'+
                   '<h4>' + result.result[i].Name + '</h4>'+
                   '<h5>Status: ' + result.result[i].Data + '</h5>'+
                   '<p>Updated: ' + result.result[i].LastUpdate +'</p>'+
                  '</div>';
   }
 
   document.getElementById("sensor-container").innerHTML = sensorInfo;
 
  });
 });
</script>

This gives an output in a browser that shows the status of all our sensors.

Our power plug
Status: On
Updated: 2016-03-08 19:21:00
Our motion sensor
Status: Off
Updated: 2016-03-08 11:06:46
Temperature & Humidity
Status: 22.2 C, 34 %
Updated: 2016-03-08 20:16:54
Sound Siren Dummy
Status: Off
Updated: 2016-03-08 15:14:59

Regardless of how many sensors we have, this script will loop through them all and present their status. In an upcoming post, we’ll go through how to make this look more beautiful och also have a responsive design dependant on whether you’re using a laptop, smartphone or a tablet.