I previously wrote an introduction to the Tessel here where I described a program that blinked out tweets in morse code. For my second project with the Tessel I wanted to use some of the modules that came with it to create a basic security device/camera to take pictures and alert me when something bad is happening.

Modules

The Tessel has 4 different ports to plug modules into, each labeled A, B, C and D. The four modules I decided to use for this project were:

Camera Module in port A Light and Sound in port B Accelerometer in port C Climate in port D

The accelerometer is used to check if someone is tampering with the camera, also for Earthquakes which are concerningly frequent in New Zealand.

The light and sound detector can be used to detect sudden changes in light or noise level.

The climate detector can detect if the temperate goes above a threshold, for example if the house is on fire.

The camera is used to take pictures of what is happening and save them for later inspection. Originally I wanted to tweet them, I had some problems with the twitter API to do this.

Code

Full Code is available here

I have divided each of the modules into their own sections of code to make it easier to describe. The code which all of the modules require is the tessel library, and the q library for promises (my usual choice of bluebird does not work on the Tessel):

tessel = require('tessel')

q = require 'q'

Additionally, I found it useful to reimplement bluebird’s promisify function, which turns a callback into a promise:

promisify = (fn, thisArg = null) ->

defer = q.defer()

callback = (err, data) ->

return defer.reject(err) if err

defer.resolve(data)

fn.apply(thisArg, [callback])

defer.promise

Accelerometer

To use a module you only have to require its model number from npm, and then call use on the port it is plugged into. For example, the accelerometers model number is accel-mma84 and is plugged into port C, so to access the module I only need to call require(‘accel-mma84’).use(tessel.port[‘C’]). This is so easy!

The core function I need to create is called is_moving and returns true if the Tessel is moving. This uses the get_xyz function to return a promise for the acceleration of the module in is an array of [x,y,z] values. Then, it waits for a second takes a different measurement and if the two are difference above a sensitivity level.

accel = require('accel-mma84').use(tessel.port['C']);

get_xyz = ->

promisify(accel.getAcceleration, accel) is_moving = (sensitivity = 0.005) ->

xyz1 = null

xyz2 = null

get_xyz()

.then( (xyz) ->

xyz1 = xyz

q.delay(1000).then(-> get_xyz())

)

.then( (xyz) ->

xyz2 = xyz

diffx = Math.abs(xyz2[0] - xyz1[0])

diffy = Math.abs(xyz2[1] - xyz1[1])

diffz = Math.abs(xyz2[2] - xyz1[2])

if (diffx + diffy + diffz) > sensitivity

true

else

false

)

Ambient Sound and Light

Similar to accelerometer, the is_light_sound_changing function measures the light level and sound level twice, a second apart, and if there are differences above a sensitivity it returns true.

ambient = require('ambient-attx4').use(tessel.port['B']); get_light_and_sound = ->

q.all([promisify(ambient.getLightLevel, ambient),promisify(ambient.getSoundLevel, ambient)]) is_light_sound_changing = (light_sensitivity=0.001, sound_sensitivity=0.005) ->

l1 = null

l2 = null

s1 = null

s2 = null

get_light_and_sound()

.then((light_and_sound) ->

l1 = light_and_sound[0]

s1 = light_and_sound[1]

q.delay(1000).then(-> get_light_and_sound())

)

.then((light_and_sound) ->

l2 = light_and_sound[0]

s2 = light_and_sound[1]

diffl = Math.abs(l1 - l2)

diffs = Math.abs(s1 - s2)

console.log 'diff', diffl, diffs

if diffl > light_sensitivity || diffs > sound_sensitivity

true

else

false

)

Climate

The is_burning function measures the temperature and if it is above 30 degrees (which is warm for New Zealand, probably cool for Australia) it returns true.

climate = require('climate-si7020').use(tessel.port['D']) get_temp = ->

promisify(climate.readTemperature, climate) is_burning = (max_temp=30) ->

get_temp()

.then( (temp) ->

console.log temp

if temp > max_temp

true

else

false

)

Camera

The turn_camera_on function is used to initialise the camera, and then the take_a_picture function takes a picture and saves it to the computer that the Tessel is plugged in to.

camera = require('camera-vc0706').use(tessel.port['A']); turn_camera_on = ->

console.log "Turn Camera On"

camera_ready_defer = q.defer()

camera.on('ready', ->

console.log "Camera On"

camera_ready_defer.resolve(true)

)

return camera_ready_defer.promise take_a_picutre = ->

promisify(camera.takePicture, camera)

.then( (image) ->

console.log "Image Taken:", image

name = "picture-#{Date.now()}.jpg"

console.log('Picture saving as', name, '...');

process.sendfile(name, image);

console.log('done.');

)

The Main Loop

First the camera is turned on, then every 10 seconds it checks whether the light or sound is changing, it is too hot, and whether the Tessel is moving. Then, if any of these are true it logs it and takes a picture.

turn_camera_on()

.then( ->

setInterval( ->

q.all([is_light_sound_changing(), is_burning(), is_moving()])

.spread( (lsc, burning, moving) ->

if lsc or burning or moving

console.log "Light or Sound Changing" if lsc

console.log "Burning" if burning

console.log "Moving" if moving

take_a_picutre()

else

console.log "Nothing is happening"

)

, 10000)

)

Executing it

To execute this code first we have to build the javascript code from the coffeescript.

coffee -c tessel_security_camera.coffee

Now we can run it, and give it a directory to put the taken pictures into.

tessel run tessel_security_camera.js \

--upload-dir=/pictures/folder

Conclusion

The Tessel modules are one of its massive advantages over other embedded development platforms. As you can see above, it is incredibly easy to integrate and use these modules. I think that if you want to quickly make some simple, embedded thing that will just work with the least amount of hassle, then you should definitely consider using the Tessel.