Close

The Gate/Door Control Web Page

A project log for Lightweight Personal IoT Framework

Reducing the complex nature of more mature automation and IoT frameworks by way of limiting components and scope.

krichkrich 03/16/2016 at 22:560 Comments

In this section, I am going to attempt to show and describe the Javascript, CSS, and HTML used to interact with the MQTT server. I don't know if I will be successful. The entire control.html file is also added to the files section of this website.

The Paho MQTT client requires a couple Javascript libraries. Link directly to them or load them on your server. You'll need jquery and mqttws31. Google finds them pretty easily.

<script type='text/javascript' src='/source/jquery-1.8.3.js'></script>
<script type='text/javascript' src="/source/mqttws31.js"></script>

All the important stuff is set up and handled in the Javascript load function:

<script type='text/javascript'>//<![CDATA[
	$(window).load(function(){
		var client = new Paho.MQTT.Client("myserver.somewhere.com", Number(8080), "clientId" + Date.now().toString());
		// set callback handlers
		client.onConnectionLost = onConnectionLost;
		client.onMessageArrived = onMessageArrived;
		//Options object for connection
		var connect_options = {
			timeout: 3,
			onSuccess: function () {
				// Connection succeeded; subscribe to our topic
				client.subscribe('feeds/Garage/Door/Status', {qos: 0});
				client.subscribe('feeds/Garage/Sensor/Status', {qos: 0});
				client.subscribe('feeds/Driveway/Gate/Status', {qos: 0});
				client.subscribe('feeds/Driveway/Sensor/Status', {qos: 0});
			},
			onFailure: function (message) {
				window.location.reload(false);
			}
		};
		// connect the client
		client.connect(connect_options);
		// called when the client loses its connection
		function onConnectionLost(responseObject) {
			if (responseObject.errorCode !== 0) {
				window.location.reload(false);
			}
		}

		// called when a message arrives
		function onMessageArrived(message) {
			if (message.destinationName == "feeds/Garage/Door/Status") {
				if (message.payloadString == "Moving...") {     // neither sensor set (opening?)
					$("#gdstatus").html("Moving...");
					$("#gdaction").html("Moving...");
				} else if (message.payloadString == "Closed") { // open sensor set
					$("#gdstatus").html("Closed");
					$("#gdaction").html("Open Garage Door");
				} else if (message.payloadString == "Open") {   // close sensor set
					$("#gdstatus").html("Open");
					$("#gdaction").html("Close Garage Door");
				} else {
					$("#gdstatus").html(message.payloadString);
					$("#gdaction").html("Unknown Status");
				}
			} else if (message.destinationName == "feeds/Driveway/Gate/Status") {
				if (message.payloadString == "Moving...") {     // neither sensor set (opening?)
					$("#gatestatus").html("Moving...");
					$("#gateaction").html("Moving...");
				} else if (message.payloadString == "Closed") { // open sensor set
					$("#gatestatus").html("Closed");
					$("#gateaction").html("Open Gate");
				} else if (message.payloadString == "Open") {   // close sensor set
					$("#gatestatus").html("Open");
					$("#gateaction").html("Close Gate");
				} else {
					$("#gatestatus").html(message.payloadString);
					$("#gateaction").html("Unknown Status");
				}
			} else if (message.destinationName == "feeds/Garage/Sensor/Status") {
				$("#sensor").html(message.payloadString);
			} else if (message.destinationName == "feeds/Driveway/Sensor/Status") {
				$("#gatesensor").html(message.payloadString);
			}
		}
		//Do this when button is clicked.
		$( "#gdbutton" ).click(function() {
			message = new Paho.MQTT.Message("1");
			message.destinationName = "feeds/Garage/Door/Activate";
			client.send(message);
		});
		$( "#gatebutton" ).click(function() {
			message = new Paho.MQTT.Message("1");
			message.destinationName = "feeds/Driveway/Gate/Activate";
			client.send(message);
		});
	});//]]>
</script>
Much of this is self explanatory to those familiar with Javascript. Some of the more odd things in this code are around making sure that when a smartphone brings up the web page after being screen locked or the app has been in the background for a while the proper status is shown. I found that many smartphones, most importantly my wife's smartphone, would disconnect from the wifi and/or the cellular data connection to save battery which disconnected the MQTT Websockets connection. So, I had to come up with a way for the page to reload when the page was displayed after being in the background or behind a locked screen.

I created an inline style sheet mainly because I just wanted to deal with a single file. Again, simplicity. I may move it out into it's own file eventually. Easy enough.

Oh, and yeah, I cheated and used a CSS button tool to make buttons that didn't look like crap.

<style media="screen" type="text/css">
	.gdbuttonclass {
		-moz-box-shadow: 0px 10px 14px -7px #3e7327;
		-webkit-box-shadow: 0px 10px 14px -7px #3e7327;
		box-shadow: 0px 10px 14px -7px #3e7327;
		background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #77b55a), color-stop(1, #72b352));
		background:-moz-linear-gradient(top, #77b55a 5%, #72b352 100%);
		background:-webkit-linear-gradient(top, #77b55a 5%, #72b352 100%);
		background:-o-linear-gradient(top, #77b55a 5%, #72b352 100%);
		background:-ms-linear-gradient(top, #77b55a 5%, #72b352 100%);
		background:linear-gradient(to bottom, #77b55a 5%, #72b352 100%);
		filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#77b55a', endColorstr='#72b352',GradientType=0);
		background-color:#77b55a;
		-moz-border-radius:4px;
		-webkit-border-radius:4px;
		border-radius:4px;
		border:1px solid #4b8f29;
		display:inline-block;
		cursor:pointer;
		color:#ffffff;
		font-family:Trebuchet MS;
		font-size:28px;
		font-weight:bold;
		padding:6px 12px;
		text-decoration:none;
		text-shadow:0px 1px 0px #5b8a3c;
		text-align: center;
	}
	.gdbuttonclass:hover {
		background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #72b352), color-stop(1, #77b55a));
		background:-moz-linear-gradient(top, #72b352 5%, #77b55a 100%);
		background:-webkit-linear-gradient(top, #72b352 5%, #77b55a 100%);
		background:-o-linear-gradient(top, #72b352 5%, #77b55a 100%);
		background:-ms-linear-gradient(top, #72b352 5%, #77b55a 100%);
		background:linear-gradient(to bottom, #72b352 5%, #77b55a 100%);
		filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#72b352', endColorstr='#77b55a',GradientType=0);
		background-color:#72b352;
	}
	.gdbuttonclass:active {
		position:relative;
		top:1px;
	}
	.gdtextclass {
		color:#000000;
		font-family:Trebuchet MS;
		font-size:28px;
		padding:6px 12px;
		text-shadow:0px 1px 0px #5b8a3c;
		text-align: center;
	}
	.gdtextclassbold {
		color:#000000;
		background-color: #dddddd;
		border:3px solid #4b8f29;
		font-family:Trebuchet MS;
		font-size:28px;
		font-weight:bold;
		padding:6px 12px;
		text-shadow:0px 1px 0px #5b8a3c;
		text-align: center;
	}

</style>

And finally the body of the web page. Very simple compared to the above.

<body>
  <div style="text-align: center; background-color: #ccccff; width: 300px; border: 2px solid #ffffff">
	<br>
	<span class="gdtextclass">Garage Door Status</span>
	<br> <br>
	<span id="gdstatus" class="gdtextclassbold"></span>
	<br> <br> <br>
	<a  href="#" id="gdbutton" class="gdbuttonclass"><span id="gdaction"></span></a>
	<br> <br>
  </div>
  <div style="text-align: center; background-color: #99cc99; width: 300px; border: 2px solid #ffffff">
	<br>
	<span class="gdtextclass">Driveway Gate Status</span>
	<br> <br>
	<span id="gatestatus" class="gdtextclassbold"></span>
	<br> <br> <br>
	<a  href="#" id="gatebutton" class="gdbuttonclass"><span id="gateaction"></span></a>
	<br> <br>
  </div>
  <div style="font-family:Trebuchet MS; font-size:8px">
	Garage: <span id="sensor">Unknown</span> / Gate: <span id="gatesensor">Unknown</span>
  </div>
  <br><br>
</body>

Discussions