Turning My Lights On At Sunset
5th June 2017
Last week I bought & wrote about some wi-fi controlled lights. The Osram iOS app allows you to schedule a time when the lights will turn on & off. I don’t really want to mess around changing the time the lights will come on as the time of sunset changes throughout the year. I want the lights to come on at sunset, then go off at 11pm – currently something the iOS app does not support.
This weekend I started playing with some code to build this functionality. I plan on adding it to my Raspberry Pi based home automation system.
The solution I came up with is split into two main parts – the first one being to figure out what time the sun will set (on a day to day basis) then the second part is to turn the lights on at that time.
Figuring out what time the sun will set
I found a rather neat NPM module called SunCalc which can be used to calculate everything from sunset times & lunar phases, right through to planetary positions. It may be a little overkill for what I need, but it works. Another good feature is the ability to calculate based on coordinates so I can get the exact sunset time for my house.
// include module
const SunCalc = require('suncalc')
// get the sunset time based on coordinates (of Tower Bridge)
let times = SunCalc.getTimes(new Date(), 51.5055, 0.0754)
// extract the time (hours and minutes)
let sunSet = `${times.sunset.getHours()}:${times.sunset.getMinutes()}`
The above code is pretty self-explanatory and will give me the sunet time.
Turn the lights on at sunset – cron
Now that I can figure out the time of sunset, I want to do it every day using a cron job. The initial cron will run at a set time every day. It will get the sunset time, then initiate another cron using that time to turn the lights on.
I chose a NPM module called node-cron which make creating cron jobs really easy.
// include modules
const SunCalc = require('suncalc')
const cron = require('node-cron')
// run at 12:15 every day
cron.schedule('15 12 * * *', () => {
// get the sunset time
let times = SunCalc.getTimes(new Date(), 51.5055, 0.0754)
// format the minutes & hours for the cron job
let sunSet = `${times.sunset.getMinutes()} ${times.sunset.getHours()}`
// create a new cron job to run at the sunset time
let sunsetLightsON = cron.schedule(`${sunSet} * * *`, () => {
// turn the lights on here
// only needs to run once a day so destroy after it has run once
sunsetLightsON.destroy()
})
// start the cron job to turn the lights on
sunsetLightsON.start()
})
The code above is the basic structure which makes use of 2 cron jobs. One runs every day which creates another one which will turn the lights on then destroy itself ready for another to be created the next day. This process will just repeat over & over turning the lights on at sunset without me having to change a time manually.
Comments
Getting AirSonos Working
10th April 2017
AirSonos is a node based implementation of the AirPlay protocol which allows you to wirelessly stream any audio from an iOS device to your Sonos speakers. Why does this matter?
I listen to a lot of podcasts on my iPhone using Overcast & really love the Smart Speed & Voice Boost features. AirSonos allows me to stream from the app to my Sonos system and still use the features. The speakers appear as any Airplay speaker would in the pop-up menu at the bottom.
Whilst setting this up I had 2 main issues which seem to be common for lots of other users. After spending a few hours on forums to fix the issues, I thought it may be helpful to document the fixes in this short article.
Issue One
Once AirSonos is installed, it won’t run. You see an error that looks like this:
$ airsonos
Searching for Sonos devices on network...
/usr/local/lib/node_modules/airsonos/node_modules/bluebird/js/main/promise.js:677
throw e;
^
Error: Internal Server Error
at maybeWrapAsError (/usr/local/lib/node_modules/airsonos/node_modules/bluebird/js/main/util.js:70:12)
at /usr/local/lib/node_modules/airsonos/node_modules/bluebird/js/main/promise_resolver.js:41:50
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/lib/logicalDevice.js:112:20
at done (/usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:126:15)
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:32:16
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/lib/logicalDevice.js:106:22
at done (/usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:126:15)
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:32:16
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:251:17
at done (/usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:126:15)
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:32:16
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:248:21
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/async/lib/async.js:572:34
at /usr/local/lib/node_modules/airsonos/node_modules/sonos/lib/events/volumeListener.js:24:14
at Listener. (/usr/local/lib/node_modules/airsonos/node_modules/sonos/lib/events/listener.js:123:9)
at Request.self.callback (/usr/local/lib/node_modules/airsonos/node_modules/sonos/node_modules/request/request.js:129:22)
This issue appears to be caused by how your Sonos network is setup. If you are using a Bridge, the speakers are communicating on a private network separate to your normal Wi-fi network. AirSonos is looking for the speakers on the same network it is running on, but they are are not there.
Try removing your Bridge as it is not needed anymore. In a recent software update, Sonos now made it possible that you can run the system on your existing Wi-fi network.
Following the setup guide on the Sonos website, try setting up your system without the Bridge. Now try running AirSonos again and it should work. You should see a list of all your speakers which will show up in all your Airplay enabled apps.
Issue Two
When AirSonos is running, selecting a speaker to stream too won’t do anything & AirSonos will crash. The error will look something like this:
Error: Invalid key length
at Error (native)
at new Decipheriv (crypto.js:232:16)
at Object.Decipheriv (crypto.js:229:12)
at Object.decryptAudioData (/usr/local/lib/node_modules/airsonos/node_modules/nodetunes/lib/helper.js:141:25)
at RtpServer. (/usr/local/lib/node_modules/airsonos/node_modules/nodetunes/lib/rtp.js:32:23)
at emitTwo (events.js:106:13)
at Socket.emit (events.js:191:7)
at UDP.onMessage (dgram.js:540:8)
This is caused by an issue in the nodetunes package which has been fixed (see the PR here), but not merged into the codebase yet. If you want to apply the fix yourself open up this file:
/usr/local/lib/node_modules/airsonos/node_modules/nodetunes/lib/helper.js
On around line 141 replace this line:
var decipher = crypto.createDecipheriv('aes-128-cbc', audioAesKey, audioAesIv);
With these 2 lines:
var audioAesKeyBuffer = new Buffer(audioAesKey, 'binary');
var decipher = crypto.createDecipheriv('aes-128-cbc', audioAesKeyBuffer, audioAesIv);
Now start AirSonos & try to play something to one of your Sonos speakers again. It should now be working.
I hope you found this quick article helpful – please share it if you did.
Comments
ES6 Basics Part 4 – Classes
8th April 2017
ES6 can be thought of as a new version of Javascript. Currently most JS is ES5.
Over the next few articles, I’m going to break down the new features & syntax of ES6 into bite-size chunks. Please note that some experience writing JS is required to make full uses of these articles.
This is part 4 of many so please keep checking back for the next article in the series.
Part 1 – const & let can be found here.
Part 2 – Template Strings can be found here.
Part 3 – Arrow Functions can be found here.
Anyone that has ever tried to write OOP JavaScript will know that the syntax is very verbose. It is not easy to understand. The example below shows a constructor function setting up a Person class. The person should have 2 properties & there is also a method which will print a short bio based on the properties.
function Person(characteristics) {
this.name = characteristics.name;
this.age = characteristics.age;
}
Person.prototype.bio = function() {
return "Hi my name is " + this.name + ". I am " + this.age + " years old. Who are you?";
}
The code below shows a Person object being created & the method being used to return the short bio.
var person1 = new Person({name: 'Joe', age: 30});
person1.bio();
This will output “Hi my name is Joe. I am 30 years old. Who are you?”.
This code is not the easiest to explain – what is prototype? Why is the word class not mentioned anywhere like it is on other OOP based languages? The above example does not even go into inheritance (sub-classes) which is outside the scope of this article.
Thankfully ES6 classes make OOP JavaScript a lot simpler, as the example below shows.
class Person {
constructor(characteristics) {
this.name = characteristics.name;
this.age = characteristics.age;
}
bio() {
return `Hi my name is ${this.name}. I am ${this.age} years old. Who are you?`;
}
}
The code above is creating the exact same Person class with the same properties and methods as the first example, but it is much easier to read & understand. Make note of the constructor function inside the class. This carries out the initialization & setup within the class – it is run anytime the new keyword is used to create a new instance of the class. There is also no need to separate the methods with a comma – doing so will throw an error.
To create a new Person object & call the method the code is the same (using let instead of var keywords).
let person1 = new Person({name: 'Joe', age: 30});
person1.bio();
This will output “Hi my name is Joe. I am 30 years old. Who are you?”. There is no reference to anything odd looking like a prototype keyword & the code is generally easier to understand.
I have not included anything about sub-classes (inheritance) in this article – if you want me to do a more detailed article explaining this then please let me know in the comments.
Check back shortly for the part 5 – ES6 forEach array helper.
As not all browsers support ES6 code yet, Babel should be used to transpile (convert) the code into ES5 code.
Comments
Starting the Gate Sensor Code
28th March 2017
This article is part of a series about a project I am working on. Taken out of context it may be a little random, so make sure you check out the original article about how I am going to build my own gate sensor.
I spent an hour or so yesterday evening working on code which will execute on the Puck.js itself.
// based level of magnetic fields
let base = Puck.mag();
// advertise value for open/closed gate + batter precentage
let advertise = gate => {
NRF.setAdvertising({
0x180A : [gate], 0x180F : [Puck.getBatteryPercentage()]
},{interval: 100});
}
// set a good base for the magnetic field
// check if value over threshold then pass value to advertise
let onMag = level => {
level.x -= base.x;
level.y -= base.y;
level.z -= base.z;
let magLevel = Math.sqrt(level.x*level.x + level.y*level.y + level.z*level.z);
magLevel > 3000 ? advertise(02) : advertise(01);
}
Puck.on('mag', onMag);
Puck.magOn();
The magnetic field sensor returns 3 values – coordinates of X, Y & Z which allow me to pinpoint the location a magnetic field is coming from. The 3 values are not really needed for a simple gate sensor. All that is needed is the strength of the magnetic field, such as a single integer, which will give an indication of how close the magnet is. This can be achieved with some basic trigonometry – I multiply each of the 3 values by themselves, then add them together & take the square root of that sum. This will give me a nice number to work with.
The math needs one further step. Magnetic fields are everywhere so the sensor is picking up background fields without a magnet being close to it. A baseline, or zero reading, needs to be set without the magnet being near the sensor. To do this I am getting an initial single reading of the 3 values when the code is uploaded to the Puck.js which I am then subtracting from the sensor reading before the basic trigonometry mentioned above is executed. This gives a good baseline, but I need to remember to get a new single baseline reading once the Puck.js is in its final location as the background magnetic fields may differ from where it is located now, on my desk.
Now I have a good number to work with which shows me the strength of the magnetic field. For the rest of this article, I will refer that variable as magLevel. When magLevel is larger the field is stronger, so the magnet is closer. When magLevel is smaller the field is weaker, so the magnet is further away. Whilst testing on my desk I have seen that magLevel falls below 3000 with no magnet near it and above 3000 with the magnet next to it. By using a simple if statement it is now possible to tell if the magnet is close or not, which is the basic way of telling if the gate is open or closed. Simple.
So now the Puck.js knows if the gate is open or closed I have to get that data to the Raspberry Pi so it can then trigger the push notification. To achieve this I have decided to make the Puck.js advertise (using NRF.setAdvertising) the information. A simple 01 or 02 is advertised based on the outcome of the above mentioned if statement. I have also included the battery level of the Puck.js in the advertised date so I can extend the functionality to also include a push notification when the battery is running low.
From my research so far I think this is the most battery efficient method. The code has been executing on the Puck.js all night and the battery level has not dropped.
Security wise anyone can pick up the Bluetooth Advertising, but they could also just look to see if the gate is open or closed so I don’t see that as a major security concern.
Next Steps
I need to write the Node.js side of the system which will run on the Raspbery Pi.
I also want to make the security on the Puck.js a little better, not in terms of the Bluetooth Advertising but protect it so no one can connect to it without a password.
Check back soon for my next article on the project.
Comments
ES6 Basics Part 3 – Arrow Functions
27th February 2017
ES6 can be thought of as a new version of Javascript. Currently most JS is ES5.
Over the next few articles, I’m going to break down the new features & syntax of ES6 into bite-size chunks. Please note that some experience writing JS is required to make full uses of these articles.
This is part 3 of many so please keep checking back for the next article in the series.
Part 1 – const & let can be found here.
Part 2 – Template Strings can be found here.
Part 4 – Classes can be found here.
Currently, to declare a function in JS you would do this:
const multiply = function(a, b){
return a * b;
};
With ES6 the function keyword is no longer needed. It is replaced with a fat arrow => after the argument list.
const multiply = (a, b) => {
return a * b;
};
It is possible to reduce the syntax even further. In functions that only have a single JS expression, it is possible to remove the curley braces & drop the return keyword. This creates an implicit return – just a way of saying automatically return.
const multiply = (a, b) => a * b;
In functions with a single argument, you can also drop the parentheses around it.
const tripple = a => 3 * a;
Where a function has no arguments you need the parentheses.
Why & How?
It can reduce code clutter, making function declarations shorter & easier to read. There is also another benefit. Look at the code below and see if you can spot the issue.
const cars = {
models: ['s1', 's3', 's4', 's5', 's6', 's7', 's8'],
manufacturer: 'Audi',
carSummary: function() {
return this.models.map(function(model) {
return `The ${model} is a car made by ${this.manufacturer}`;
});
}
};
This code will throw an error – this.manufacturer will not work as the function is being passed off to somewhere else, so the value of this is lost. This could be solved by using bind, but Arrow Functions can help with this issue.
By making use of the fat arrow function below, the code below will now work because it is using Lexical This.
const cars = {
models: ['s1', 's3', 's4', 's5', 's6', 's7', 's8'],
manufacturer: 'Audi',
carSummary: function() {
return this.models.map((model) => {
return `The ${model} is a car made by ${this.manufacturer}`;
});
}
};
This means that the placement of the this keyword influences how it is evaluated. When it is placed inside a fat arrow function, it is set to the same value as what it would mean in the surrounding code. In the example above, this = team.
Check back shortly for the part 4– ES6 Classes.
As not all browsers support ES6 code yet, Babel should be used to transpile (convert) the code into ES5 code.
Comments
ES6 Basics Part 2 – Template Strings
20th February 2017
ES6 can be thought of as a new version of Javascript. Currently most JS is ES5.
Over the next few articles, I’m going to break down the new features & syntax of ES6 into bite-size chunks. Please note that some experience writing JS is required to make full uses of these articles.
This is part 2 of many so please keep checking back for the next article in the series.
Part 1 – const & let can be found here.
Part 3 – Arrow Functions can be found here.
Part 4 – Classes can be found here.
Currently, to declare a template string or template literal in JS, variables need to be concatenated into the final string.
var string = "Hello " + username + ", Welcome back.";
With ES6 it is now a lot easier – when declaring the string it should now be wrapped in backticks (“). Within the new string, any variable can be injected into it using ${}.
var string = `Hello ${username}, Welcome back.`;
It is possible to include any JS expression inside ${}.
var string = `Here is a random number: ${Math.random()}`;
Why?
Complex strings are a lot easier to write & read – they are more like simple sentences with placeholders inside them instead of a mixture of opening and closing ” with + signs.
Check back shortly for the part 3 – Arrow Functions.
As not all browsers support ES6 code yet, Babel should be used to transpile (convert) the code into ES5 code.
Comments
ES6 Basics Part 1 – const and let
15th February 2017
ES6 can be thought of as a new version of Javascript. Currently, most JS is ES5.
Over the next few articles, I’m going to break down the new features & syntax of ES6 into bite-size chunks. Please note that some experience writing JS is required to make full uses of these articles.
This is part 1 of many so please keep checking back for the next article in the series.
Part 2 – Template Strings can be found here.
Part 3 – Arrow Functions can be found here.
Part 4 – Classes can be found here.
Currently, to declare a variable in JS the var keyword is used.
var string = 'abc';
var num = 1;
With ES6 come two new keywords which can be used to declare variables. They are const & let.
const
When a variable is declared using the const keyword, the value assigned should not change. An example of this would be in a user system where once the user is registered, their unique identifier would never change.
const userId = 'somethingUnique';
Once a const is set no changes can be made to it. JS will throw an error if this happens.
let
When a variable is declared using the let keyword, the value assigned is expected to change. An example of this would be a users password. They may at any time chose to change it.
let userPwd = 'Password123';
Variables declared using let can be changed at any time – it can be used in the say way as the var keyword.
Why?
The code is more expressive & easier to read. If you are looking at a large piece of code, it is immediately obvious which variables won’t change and which may change.
Check back shortly for the part 2 – Template Strings.
As not all browsers support ES6 code yet, Babel should be used to transpile (convert) the code into ES5 code.
Comments
Use wp_enqueue, Conditionally
24th May 2015
When adding CSS or Javascript files to a WordPress theme it should be done via the functions.php file by using either wp_enqueue_style for CSS files, or wp_enqueue_script for JavaScript files. WordPress will automatically add the necessary code to link to the files either before the closing </head> or </body> tag (based on the parameters passed to either function). This will happen on every page of the website, but sometimes this may not be desired. What if you want to conditionally load certain files on certain pages?
Real Example
On this very website I use a JavaScript library called prism.js (it has a JavaScript file & a CSS file) – it is used to style any code snippets that are on a page, like the ones below. I want this website to be as fast & lightweight as possible, so I want to conditionally load them only on pages which require them – pages with code snippets.
In the snippet below I am adding the base CSS file for the theme, plus the prism.css file & the prism.js file. By using this code all three files will be included on every page of the website.
function add_theme_files() {
//Theme style sheet
wp_enqueue_style( 'theme-styles', get_stylesheet_uri() );
wp_enqueue_style( 'prism', get_template_directory_uri() . '/prism.css' );
wp_enqueue_script( 'prism-js', get_template_directory_uri() . '/js/vendor/prism.js', array(), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'add_theme_files' );
This is not ideal as there are not code snippets on every page – the two Prism library files are not needed all the time. By making use of the WordPress Conditional Tags it is possible to control which pages the Prism library files are added too.
On this website any post with a code snippet is in the ‘Code’ category. Using the in_category conditional tag will allow a check to be carried out to see if the current page being displayed needs the Prism library.
On line 5 in the snippet below I am checking to see if the page is in the ‘Code’ category. If it is, the wp_enqeue_style & wp_enqeue_script statements contained within the if statement are executed. If not, they are ignored.
function add_theme_files() {
//Theme style sheet
wp_enqueue_style( 'theme-styles', get_stylesheet_uri() );
if(in_category('Code')){
wp_enqueue_style( 'prism', get_template_directory_uri() . '/prism.css' );
wp_enqueue_script( 'prism-js', get_template_directory_uri() . '/js/vendor/prism.js', array(), '1.0.0', true );
}
}
add_action( 'wp_enqueue_scripts', 'add_theme_files' );
By using this method, the two Prism library files are only added the the pages that need them.
In this example I am using only one conditional tag (in_category) but there are many more available. Visit the WordPress Conditional Tags Codex page to find out all the ones which you can use.
Comments