Robs Blog

Blog containing all sorts of info and help from my day to day life

Categories

Using node.js WebSockets to get live MQTT updates

To keep some of my pages up to date with the live sensor data I am using websockets to get MQTT publications.

On the server there are two parts. A Python script which is monitoring a serial port for data and then publishing it accordingly. Information about this can be found at  XRF Temperature Sensor -> XRF Slice of Pi

The second part on the server is a node.js application which is runs a websocket server. For further information about installing Node.js take a look at Install Node.js v0.8.2 on Raspbian The server application creates an mqtt subscription for every connection, it subscribes to the topic according to the url that the client has come in on i.e. xxxx.xxx.xxx.xx/MyTopic will cause a subscription on MyTopic.

Node.js server code

#!/usr/bin/env node
var util   = require('util');
sys = require("sys");
url = require("url");
var WebSocketServer = require('websocket').server;
var http = require('http');
spawn = require('child_process').spawn;

var args = { /* defaults */
    port: '8000',
    debug: 'true'
};
/* Parse command line options */
var pattern = /^--(.*?)(?:=(.*))?$/;
process.argv.forEach(function(value) {
    var match = pattern.exec(value);
    if (match) {
        args[match[1]] = match[2] ? match[2] : true;
    }
});
var port = parseInt(args.port, 10);
var debug = (args.debug == 'true');

var server = http.createServer(function(request, response) {
    console.log((new Date()) + ' Received request for ' + request.url);
    response.writeHead(404);
    response.end();
});
server.listen(port, function() {
    console.log((new Date()) + ' Server is listening on port ' + port);
});

wsServer = new WebSocketServer({
    httpServer: server,
    // You should not use autoAcceptConnections for production
    // applications, as it defeats all standard cross-origin protection
    // facilities built into the protocol and the browser.  You should
    // *always* verify the connection's origin and decide whether or not
    // to accept it.
    autoAcceptConnections: false
});

function originIsAllowed(origin) {
  // put logic here to detect whether the specified origin is allowed.
  return true;
}

wsServer.on('request', function(request) {
    if (!originIsAllowed(request.origin)) {
      // Make sure we only accept requests from an allowed origin
      request.reject();
      console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
      return;
    }
    var myProcs=new Array();

    var connection = request.accept('currentcostdata', request.origin);
    console.log((new Date()) + " connection accepted from " + connection.remoteAddress + " via " + request.origin);
    var topicString = request.resource.substring(1);
    console.log((new Date()) + ' Connection Topic: ' + topicString);
    var mosquittopid = request.key;

	console.log((new Date()) + ' Connection ID: ' + mosquittopid);
	mosq = spawn('mosquitto_sub',['-t',topicString]);
	mosq.stdout.setEncoding('utf8')
	console.log((new Date()) + 'PID of mosquitto_sub for ' + topicString + ' ConID: ' + mosquittopid + ' is ' +mosq.pid);
	myProcs[mosquittopid] = mosq.pid;

	mosq.stdout.on('data', function (data) {
		connection.sendUTF(data)
		data=data.replace("\r","").replace("\n","");
		data=data.replace("\r\n","");
		console.log((new Date()) + 'Topic: ' + topicString + ' - ' + data);
	});

    connection.on('message', function(message) {
        if (message.type === 'utf8') {
            console.log('Received Message: ' + message.utf8Data);
            connection.sendUTF(message.utf8Data);
        }
    });

    connection.on('close', function(reasonCode, description) {
		//console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
		console.log((new Date()) + ' ' + mosquittopid + ' disconnected');
		console.log((new Date()) + ' ' + topicString + ' Closed: pid: ' + myProcs[mosquittopid] + '.');
		process.kill(myProcs[mosquittopid]);
		delete myProcs[mosquittopid];
    });
});

On the client side there is some JavaScript which opens the websockets connection to the server and then listens for updates and acts accoridingly

<script type="text/javascript">// <![CDATA[
		$(document).ready(function() {
			/* Define handler for websocket debug information*/
			function debug(str) {
				$("#debug_txt").html("

"+str+"

");
			};
			function rtrim(str) {
				return str.replace(/\s+$/,"");
			}
			/* Create a websocket connection */
			ws = new WebSocket("ws://myip:8000/CurrentCostTemp","currentcostdata");
			/* Define websocket handlers */
			ws.onmessage = function(evt) {
				var data = rtrim(evt.data);
				var temptitle = data +'\u00B0C';
				$("#TempValue").text(temptitle);
				debug('Temp - ' + temptitle);
			};
			ws.onclose = function() {
				debug("socket closed");
			};
			ws.onopen = function() {
				debug("connected...");
			};
		});

// ]]></script>

August 8th, 2012 by robconvery

Heating Control System – Hardware/Software Configuration

Below is a little diagram showing some of the components of my heating Control System. This is mainly based around the monitoring side. Soon I will be adding the XRF Relay board which will be used to control the central heating.

August 1st, 2012 by robconvery

Install Node.js v0.8.2 on Raspbian

Perform the following steps to get Node.js v0.8.2 installed on Raspbian (The latest OS release for the Raspberry Pi)

Prep the system and get all the components needed to compile

sudo apt-get install git-core build-essential

Download the source and patch it

git clone https://github.com/gflarity/node_pi.git
git clone https://github.com/joyent/node.git
cd node
git checkout origin/v0.8.2-release -b v0.8.2-release
git apply --stat ../node_pi/v0.8.2-release-raspberrypi.patch

Set the flags needed for compilation

export GYP_DEFINES="armv7=0"
export CXXFLAGS='-march=armv6 -mfpu=vfp -mfloat-abi=hard -DUSE_EABI_HARDFLOAT'
export CCFLAGS='-march=armv6 -mfpu=vfp -mfloat-abi=hard -DUSE_EABI_HARDFLOAT'

Configure the compilation

./configure --shared-openssl --without-snapshot

Make & install

make
sudo GYP_DEFINES="armv7=0" CXXFLAGS='-march=armv6 -mfpu=vfp -mfloat-abi=hard -DUSE_EABI_HARDFLOAT' CCFLAGS='-march=armv6 -mfpu=vfp -mfloat-abi=hard -DUSE_EABI_HARDFLOAT' make install
l

Credits

https://github.com/gflarity/node_pi

July 23rd, 2012 by robconvery

Home Automation – Raspberry Pi Links

Below is a number of links that have helped me setting up my Raspberry Pi

iWebKit – Great framework for developing web apps that look like native iPhone apps

Building iPhone Apps with HTML, CSS, and JavaScript – Making App Store Apps Without Objective-C or Cocoa

Making Electricity Usage Graphs with the Current Cost device – Great for getting started with a CurrentCost device

How to install Node.js on your Raspberry Pi – Tom Gallacher – Great site on how to install Node.js onto the pi – Not quite but it gets there in the end

Install node.js v0.8.2 – Nice simple instructions on how to install the latest version.

Node.js, MQTT and Websockets – Good tutorial getting started with web sockets

An MQTT/Websocket based Thermometer using the html5 meter tag – Good follow on to use for dynamic sites.

July 12th, 2012 by robconvery

XRF -Sensors + Relays

Following on my post about automating my central heating I have decided on the main wireless technology to use – XRF. These are small 3.3v wireless serial transmitters that retail for <£10 each.

I am planning to use these for two parts of the system

1) Temperature Sensors ~£15 each

I will be using these for measuring the temperature around the house and also outside. They are small wireless devices that last around 1-2 months when powered by a CR2032 battery (setup to send a signal every few minutes). I am planning to use 2x AA batteries with a holder as this will give me a much longer time period – expected around 1 year.

 + 

2) Central Heating Relay – ~£18

This will be used for controlling the 240v central heating lines. To start with it will be connected in parallel with the existing controller (which will be set in permanent off mode). This will enable me to house the Raspberry Pi anywhere in the house and not need to be housed in the kitchen where the existing control unit is.

 

Unfortunately the Relay board does not come with a 240v PSU, it requires a  6v to 14v DC supply. As a result of this I will need to find a suitable PCB which will be used to power the relay box. All of this will be housed in a small box with fly-leads attached.

Receiver

The main receiver will be a slice of Pi combined with a XRC model.

To start I will test using 2 temp sensors – 2 internal (Living Room & Bedroom & 1 external)

July 9th, 2012 by robconvery

Internet Enabled Central Heating Controls

This is the start of me trying to build a small Internet Enabled central heating controls. The idea is to replace my existing Drayton Tempus 7 unit. I have the following requirements

  • Web Front End
  • 7 Day Planner for Central Heating
  • 7 Day Planner for Hot Water
  • 1/2/3 Hour Boost
  • Advance
  • Switching for 2A 240v ac
  • Survive power outage

Extras

  • Remote Temperature Sensors – Wireless?

At the moment I can see two products which could be used – Raspberry Pi or Arduino.

Current Thinking is

In terms of System Design…
Application A – Monitoring Application which will log the temperature to Mysql? or RRDTool
Application B – Control Centra Heating
WebServer – Display Temperatures & Update Heating Schedule
June 27th, 2012 by robconvery