Archives for posts with tag: JavaScript

Using NodeJS to develop a temperature server with the Raspberry Pi

The Raspbian Linux distribution for the Raspberry Pi includes some useful kernel drivers for accessing devices connected to the Pi’s GPIO pins. Based on the tutorial from the University of Cambridge Computer Laboratory I’ve been playing around with the DS18B20 digital thermometer on the Pi. I’ve connected the sensor to the Pi using a standard electronics breadboard and the excellent Adafruit Pi Cobbler breakout connector kit (kudos to Mills for her excellent soldering skills). When the required GPIO kernel modules are loaded a file containing sensor output is written to the /sys/bus directory (see tutorial link above for more) which contains the current thermometer reading.

Raspberry Pi & DS18B20

Raspberry Pi & DS18B20 digital thermometer

Developing with NodeJS

I originally wrote a Python CGI script as part of the CPC Pi Hack event to parse the sensor file and display the temperature on a web page (although we didn’t submit our hack in the end), but I’ve also been looking for a project for a while to try out NodeJS.The result is a prototype JavaScript server/client app to serve temperature from the Pi as a JSON string and display a graph of current temperature on the client.

This was my first NodeJS app and I was impressed with the speed of development and the readability of documentation/examples – so much so that I managed to write the bulk of the server on my netbook during a flight from Leeds to London! The biggest disadvantage of using NodeJS on the Pi is the time it takes to compile (1hr 58 minutes, Pi CPU clocked at 950MHz). While this may put some developers off, the build process was painless and is more than made up for by the efficient asynchronous nature of NodeJS once you get it running (first-pass testing shows no noticeable increase in memory/CPU when the server is under load although I’ve not investigated this thoroughly).

The server code is divided into two parts: a dynamic server response which is called when a request for the “temperature.json” URL is received. The server reads the sensor file, parses the data and returns the temperature with a Unix time-stamp in JSON notation. Here’s a snippet from the server code parsing and returning the temperature data:

// Read data from file (using fast node ASCII encoding).
var data = buffer.toString('ascii').split(" "); // Split by space

// Extract temperature from string and divide by 1000 to give celsius
var temp = parseFloat(data[data.length-1].split("=")[1])/1000.0;

// Round to one decimal place
temp = Math.round(temp * 10) / 10

// Add date/time to temperature
var jsonData = [Date.now(), temp];

// Return JSON data
response.writeHead(200, { "Content-type": "application/json" });
response.end(JSON.stringify(jsonData), "ascii");

The second section of the server uses the node-static module to serve a client-side page which performs an AJAX call for “temperature.json” and plots current temperature. The plot is created using the highcharts JavaScript package to create a dynamic graph which moves along the x-axis over time (check out the highcharts demo page to get a better idea of dynamic charts). One thing to note is that the sensor precision is ±0.5 °C, and while the temperature data is rounded to one decimal place, the default highcharts y-axis precision may be a bit misleading. Overall though the highcharts package is pretty slick, and the plot looks great on my new Nexus 7!

Temperature Plot

Raspberry Pi Temperature Sensor Plot

I’ve pushed the code to GitHub as it may be useful to others who are also new to the Pi and NodeJS. One of the features of NodeJS I like the most is the ease of testing and deployment – you can run the server right in the terminal window without super-user permissions and get debugging info straight away. Furthermore, given the ease of creating web-apps and the small resource footprint (obviously depending on what you’re doing) I’ll definitely be looking to use NodeJS/JavaScript as development platform for the Pi in the future.

Visualising London’s buildings with 3D mapping

I recently discovered a JavaScript library called OSM Buildings which provides a 3D representation of buildings from Open Street Map (OSM) data on a 2D map. OSM Buildings doesn’t generate a complete 3D model but uses a clever shading technique to make buildings appear ’3D’. OSM Buildings and can be used with either OpenLayers or the Leaflet JavaScript map API’s.

3DLondon map screenshot

I was interested in whether OSM Buildings could be used to visualise non-OSM data, in particular the Geoinformation group’s UKMap product, to create a complete ’3D’ city map. The UK map database is a commercial, attribute rich, map database designed to compete with the UK’s Ordnance Survey products, and contains a LiDAR derived height for most structures in urban areas. Furthermore, UK academics can access the UKMap data via the MIMAS Landmap service. As part of my PhD research I obtained a copy of the UKMap basemap and building heights for London from the Landmap team.

The OSM Buildings API provides a method to add a buildings layer from a GeoJSON object, so I wrote a simple Python CGI script to grab building features from the UKMap PostGIS database and return it as GeoJSON. The embedded SQL query (via the excellent Psycopg module) uses the new PostGIS 2.0 function ST_AsGeoJSON to return a JSON representation of the geometry. Unfortunately this isn’t as straight forward as it seems as PostGIS doesn’t return any feature attributes. However after reading this blog at the Postgres online journal and installing Andrew Dunstan’s backport of JSON support for PostgreSQL 9.1, I managed to get the query to return proper JSON representation of the attributes and geometry.

To reduce data volume (there are ~5 million features in the database) the CGI script accepts a bounding box parameter in well known text form, and only features within the bounding box are returned. Here’s a snippet showing the SQL query:

SELECT row_to_json(fc)
FROM (SELECT 'FeatureCollection' As type, array_to_json(array_agg(f)) As features
      FROM (SELECT 'Feature' As type,
            ST_AsGeoJSON(ST_Transform(lg.the_geom,4326))::json As geometry,
            row_to_json((SELECT l FROM (SELECT height) As l)) As properties
            FROM "3DLondon" As lg
            WHERE ST_Within(lg.the_geom,
            ST_Transform(ST_GeomFromText(%s,4326),27700))
            LIMIT 100000)
      As f )
As fc;',[bbox_wkt])

A sample of the features and their geometry returned as GeoJSON:

{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-0.099928777847266,51.514483900172905],[-0.100343210931384,51.514457880418973],
//...

Thanks to some good documentation at OSM Buildings the front end is a simple JavaScript function to add the buildings to the map via a jQuery post AJAX call.

//Request data from GeoJson server and add to map
function getBuildings(bounds_wkt){
	jQuery.postJSON('/3DLondon/get_geojson.py?bbox_wkt='+bounds_wkt,
   function(data){
		build
     		.addTo(map)
	        .setStyle({ wallColor: 'rgb(200,190,180)', roofColor: 'null',
                        strokeRoofs: true })
     		.geoJSON(data)
		;
		});
};

Using this function it was fairly straightforward to add some functions to listen for Leaflet map events to refresh the building data when the map was moved or zoomed.

//Listen for map pan events and get new buildings data
map.on('moveend', function(e) {
   getBuildings(getBBoxWKT());
});

From the screenshot above you can see that OSM Buildings is doing a great job of rendering stuff in ’3D’. The basemap is Open Street Map data, styled and served by CloudMade with OSM building footprints removed for clarity. In a nutshell I was pretty impressed with both the OSM Buildings and the Leaflet libraries. You can check out the complete source code at https://github.com/talltom/3DLondon, and here’s another screenshot over a larger area with the buildings rendered in blue.

3DLondon map screenshot

3DLondon map of St Paul’s/The City and surrounds

Follow

Get every new post delivered to your Inbox.