The Modern Yahoo Pipes Alternative … Azure Logic Apps!

Back in 2015, Yahoo! shut down a service I used to love called Yahoo Pipes. It allowed you to combine and filter XML-based RSS feeds to create a new RSS feed containing the data you wanted.

At the time, I looked for a decent alternative and didn’t find anything.. until recently, when I realised that Logic Apps (which I’d been creating for over a year at work) were actually comparable to a next-gen version of Yahoo Pipes, with A LOT more functionality.

Since Logic Apps / Power Automate (used to be called Flow) is a lot more feature-rich, it does mean it’s a little harder to do what you want with the data, but once you’ve developed a few, you’ll see how much more flexible they are, especially when the world has moved to JSON-based APIs, with XML-based RSS taking a backseat.

While Pipes would just output RSS, Logic Apps can output the result into pretty much anything you want.. JSON, email, other APIs, Twitter, spreadsheets (Office 365 and Google Sheets).. the list goes on and on!

You can get started with Logic Apps for free.. and they’re very low cost to run beyond the Azure trial period. You’re talking pennies to run them monthly, depending on run-frequency & complexity. The pricing calculator can help you if you’re worried about cost. If you created 10 Logic Apps, each containing 10 basic actions and 10 standard actions, and ran them all once a day for 30 days it’d cost you 34p a month;

Actions in Logic Apps are the blocks you see in a flow;

It starts with a ‘Trigger’.. so in this case I’ve chosen a Recurrence (schedule), but you could set one up to trigger on a HTTP call from an RSS reader app, something happening on Twitter, or pretty much anything.. here’s a few of the triggers to choose from…

Just some of the Trigger actions available!

Non-Microsoft products are well represented, so don’t go thinking you’re limited to Sharepoint or Office 365, that’s not the case.

You then design the flow how you want it to behave, e.g. get data from X and Y, merge it together, filter it, query an API, persist some data in a sheet, then send back a piece of JSON.

Choose from Built-In, Standard or Enterprise actions.. you can even build your own custom connectors for systems that aren’t currently listed.

List of the Built-In actions (April 2020)

As you’ll see in the video I put together, to replace Yahoo Pipes, you need to be able to merge, filter, manipulate, and sort JSON. You can do a lot of this with the  built-in actions, but you can use Inline Code to achieve anything else.

Inline Code runs NodeJS and has access to standard built-in Javascript objects.

The one thing that’s Logic Apps aren’t great for compared to Yahoo Pipes is sharing what you’ve created.. it was really easy to adapt what someone else made to suit your needs. Logic Apps don’t work like that at all, and you’ll need to roll your own, which takes some trial-and-error & patience.

Basic filtering (etc) is quite straightforward …

… but Inline Code might take you longer to figure out, so to get you started, here are some Inline Code snippets you might find useful;

Simple Text Filter

const filtered = workflowContext.actions.Current_JSON.outputs.filter(item => item.display_name=='My search string');
return filtered;

view raw
simpleTextFilter.js
hosted with ❤ by GitHub

Multi-Filter Example Including Regex

var titles = workflowContext.actions.Filter_array_on_year.outputs.body;
var newTitles = [];
const regex = /(.*)(2019|2020|2021).*/i; // Regex for year filtering
titles.forEach(function(item) {
// Additional filter for titles containing 1080p only
if (item.title.indexOf('1080p') > 1) {
// Extract the title and year only
var titleMatch = regex.exec(item.title);
if (titleMatch!=null && titleMatch.length>0) {
var tidyTitle = titleMatch[1]+titleMatch[2];
var pubDay = item.pubdate.substr(5, 2); // Get the day number
tidyTitle = pubDay + " – " + tidyTitle;
// Simple dedupe
if (!newTitles.includes(tidyTitle)) newTitles.push(tidyTitle);
} else {
newTitles.push(item.title);
}
}
});
return newTitles;

view raw
multiFilter.js
hosted with ❤ by GitHub

Generate HTML for an Email

var titles = workflowContext.actions.Execute_JavaScript_Code.outputs.body;
var html = '';
titles.forEach(function(fulltitle) {
var title = fulltitle.substr(5); // Strip off the first 5 characters.. '12 – Headline' becomes 'Headline'
html += fulltitle +
' | <a href="https://www.somesite.com/find?q=&#39;+title+'">Somesite</a>' +
' | <a href="https://anothersite.net/search/&#39;+title+'">Another</a>' +
'<br>';
});
html += '<br><br>Footer of email goes here';
return html;

view raw
emailBody.js
hosted with ❤ by GitHub

This hasn’t been a step-by-step guide, but has hopefully shown you enough to spark your interest.. get yourself a free trial of Azure, and give it a go!

 

How to list Azure Resources that don’t have Alerts enabled

Alerts are great for letting you know when Logic Apps or Function Apps fail to run for any reason.. the problem is, while you can list out which resources have Alerts, you can’t get a list of resources which don’t have Alerts!

So how do you find out which resources you need to add Alerts to? Well, the CLI has the tools you need, but it’s a bit more complicated than it should be!

First you need a list of resources which have alerts.. you can do that with a command like this;

az resource list --output tsv --resource-type "Microsoft.Insights/metricAlerts" --query [].id

You can run that as part of this command, which is supposed to take the Alert ID list, pipe it into az resource show, and output the value in properties.scopes[0], which is the ID of the resource the alert is set up to monitor.

az resource show --ids $(az resource list --output tsv --resource-type "Microsoft.Insights/metricAlerts" --query [].id) --query properties.scopes[0] --output tsv

However, this fails miserably when the Alert name has a space in it; there ends up being a space in the Alert ID, which makes our command throw an error. UPDATE – Microsoft are figuring out if they can fig it in this bug report I raised.

What I ended up having to do is break up the commands inside a Bash script & use a loop.

alerts=$(az resource list –output tsv –resource-type "Microsoft.Insights/metricAlerts" –query [].id)
alerts=${alerts// /SPACEFIX}
for alert in $alerts
do
az resource show –ids "${alert//SPACEFIX/ }" –query properties.scopes[0] –output tsv
done

view raw
listAlertIds.sh
hosted with ❤ by GitHub

This will assign all the Alert IDs to a variable, then replaces spaces with ‘SPACEFIX’. We then loop over the Alert IDs, querying the Alert to find what resource they’re monitoring. ‘SPACEFIX’ is replaced within the loop. It’s somewhat of a hack to get round this silly issue!

There might be a better way to handle this, but I didn’t find it in a hurry.

Now we’ve got a list of resources that have alerting enabled, we need to list out all the resources we want to check.. for this example I’m just interested in Logic Apps, and this script will list them out, one resource per line;

logicapps=$(az resource list –output tsv –resource-type "Microsoft.Logic/workflows" –query [].id)
for logicapp in $logicapps
do
echo "$logicapp"
done

view raw
listLogicApps.sh
hosted with ❤ by GitHub

Now we can redirect the output of the 2 scripts into temporary files, and use the ‘comm’ command to show us the lines that exist in one file that don’t in the other.. here’s how it looks;

echo Finding what Alerts exist already …
./listAlertIds.sh > listAlertIds.tmp
echo Finding what Logic Apps exist …
./listLogicApps.sh > listLogicApps.tmp
echo Logic Apps without an Alert are …
comm -23 <(sort -u ./listLogicApps.tmp) <(sort -u ./listAlertIds.tmp)

view raw
listMissingAlerts.sh
hosted with ❤ by GitHub

This gets us what we want.. a list of Logic Apps that don’t have Alerts set up for them. You can pipe the results through grep to check certain Resource Groups, or whatever you need.

Hope this helps save you some time, and gives you a few ideas for useful scripts.

I’ve published some videos on YouTube showing various Azure tips, which you might want to check out!

 

How to Automate PageSpeed Insights for Multiple URLs on a Schedule using Logic Apps or Flow

For the website I’m responsible for, I was interested in capturing the data from the Google PageSpeed Insights tool, and having the data recorded somewhere on a schedule. There’s a blog post on Moz.com that talked about doing this with a Google Sheet, but it wasn’t quite what I was after; I wanted the data to be collected more regularly.

Instead of using Google Sheets (and a fair amount of code), I decided to use an Azure Logic App (you can use this or Microsoft Flow), which is part of Microsoft’s Cloud platform.

The Logic App is run on a Recurrence trigger which I set to every 6 hours. By collecting the results automatically over time, you’ll see how the changes you’re making to your site affect your PageSpeed scores.

recurrence-hr

The first step simply defines the URLs you want to check, then it’ll loop over each one & call the PageSpeed API. Go get an API key, and make sure PageSpeed API is enabled.

Results from the API call are parsed out and pushed into a new row in an Excel Online sheet.

If you’re interested in setting this up yourself, I recorded a short video which shows how it works in more detail.

There are a few foibles in Logic Apps which caught me out, first, getting the list of URLs into an Array didn’t work as expected. I had to switch to Code View to correct the escaping of the return character to read;

@split(variables('urlList'), '\n')

The JSON payload from the PageSpeed API is pretty large, so I’ve listed the path to the elements you’ll be interested in below. I’m using split (on space) purely to get at the numerical value, which is more useful in the spreadsheet;

First Contentful Paint

@{split(body('HTTP')?['lighthouseResult']?['audits']?['first-contentful-paint']?['displayValue'], ' ')[0]}

First Meaningful Paint

@{split(body('HTTP')?['lighthouseResult']?['audits']?['first-meaningful-paint']?['displayValue'], ' ')[0]}

Speed Index

@{split(body('HTTP')?['lighthouseResult']?['audits']?['speed-index']?['displayValue'], ' ')[0]}

Time To Interactive

@{split(body('HTTP')['lighthouseResult']['audits']['interactive']['displayValue'], ' ')[0]}

Time to First Byte

@{split(body('HTTP')?['lighthouseResult']?['audits']?['time-to-first-byte']?['displayValue'], ' ')[3]}

Overall, this was quite easy to put together and shows the power of Azure Logic Apps. Being able to do this without any code or (your own) servers, and getting things live in a couple of hours is a fantastic tool to have at your disposal.

Make your own £5 ambient TV backlight

After clearing out some junk, which included an old halogen desk lamp, I was thinking about putting in an LED light behind the PC monitor.

Then I remembered I’d bought a ring of 24 RGB LEDs from Aliexpress last year & hadn’t used it in a project.

I also had a spare Arduino Nano, and all the things I’d need to allow me to hook up a dial (potentiometer) for the light level, and button to cycle through different colour modes.

Here’s a quick video of it in action..

Parts

LED Ring – £2
Arduino Nano – £1.75
Breadboard & bits – £1.25

Wiring it up

It’s an easy one to wire up.. I took a few basic examples and mashed them together to get what I wanted from the design.

I’m not an electronics expert, and approached this like I approach software development; write it in manageable/testable chunks, which I can implement and test individually, then bolt it all together.

fritz-led-ring

The code for the project is pretty simple.. I think the most complicated bit is handling the button, which needed debounce functionality.

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 6 // pin on the Arduino is connected to the LED ring
#define NUMPIXELS 24 // Number of pixels on the LED ring
#define POT_PIN 0 // Potentiometer pin
#define BUTTON_PIN 2 // Button pin
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int showType = 0;
bool oldState = HIGH;
void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); // Declare pushbutton as input
pixels.begin(); // This initializes the NeoPixel library.
}
void loop() {
// Read the potentiometer value and translate to how many pixels we want to illuminate
int value = analogRead(POT_PIN);
value = map(value, 0, 1023, 0, 25);
// Switch colours if the button is pressed
bool newState = digitalRead(BUTTON_PIN);
if (newState == LOW && oldState == HIGH) {
delay(20); // Short delay to debounce button.
// Check if button is still low after debounce.
newState = digitalRead(BUTTON_PIN);
if (newState == LOW) {
// Cycle through different colour schemes
showType++;
if (showType > 8) showType=0;
}
}
oldState = newState; // Set the last button state to the old state.
uint32_t color = pixels.Color(255,255,255); // default to white when first booted
if (showType==1) color = pixels.Color(0,0,255); // blue
if (showType==2) color = pixels.Color(0,255,0); // green
if (showType==3) color = pixels.Color(255,0,0); // red
if (showType==4) color = pixels.Color(0,127,255);
if (showType==5) color = pixels.Color(255,127,0);
if (showType==6) color = pixels.Color(255,0,127);
if (showType==7) color = pixels.Color(0,255,255);
if (showType==8) color = pixels.Color(127,127,255);
// Illuminate X pixels depending on how far the potentiometer is turned
for(int i=0;i<NUMPIXELS;i++){
if (i<value) {
pixels.setPixelColor(i, color);
} else {
pixels.setPixelColor(i, pixels.Color(0,0,0)); // Don't show anything
}
}
pixels.show(); // This sends the updated pixel configuration to the hardware.
}

And here are a few pictures of it in place behind the PC monitor..

Automated mains socket power-off for OSMC on a Raspberry Pi

I’ve chosen to replace an ageing mini-PC which I’ve used since 2010 with a new Raspberry Pi 3 B+ running OSMC. It makes for a really capable media centre which can playback newer h.265 HEVC video files at 1080p without any problems, or it can serve 4K files over NFS to a box with a hardware h.265 chip like the Fire TV Box.

This form factor is easy to take on holiday and you can use an old infrared remote control (or Harmony learning remote) with it too.

However, the one thing I’ve struggled with is how to make it easy for my family to use in regard to switching it on and off. The Pi doesn’t have a power button. Some power supplies have an inline rocker switch, which almost fits the bill. I wanted something more automated.

Fortunately I had a spare Energenie power socket from a previous project where I use one to turn off our bass speaker when the TV isn’t on. These power sockets are controlled remotely (over RF) from a Pi which you attach an Energenie control board/shield to.

What I’ve done with the Pi 3 is have it powered through an Energenie socket, and set up a service that executes when it detects OSMC is shutting down. That service will make a quick HTTP call to the Pi with the Energenie controller shield, which will in turn send an RF signal to turn the mains socket off.

 

osmcshutdown

 

Here’s how you can set it up like I have…

Scripts for the Pi running OSMC

First, add a new service script.. create a new file in this folder;

/etc/systemd/system/callenergenie.service

[Unit]
Description=Energenie Remote Call to Secondary Pi
Before=multi-user.target
After=network.target
Conflicts=shutdown.target
[Service]
ExecStart=/bin/true
ExecStop=/bin/sh /home/osmc/callenergenie.sh
Type=oneshot
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

Then enable it with;

sudo systemctl enable callenergenie.service

There are a couple of useful things happening in this service, the After parameter makes sure the code runs before the network code is shut down, and Conflicts parameter is looking for OSMC shutting down.

Now add a helper script… this will make the webserver call as a background task, so control will be given back to the service immediately, rather than it waiting for the wget to complete.

/home/osmc/callenergenie.sh

echo Calling energenie socket…
wget –quiet –background –output-document="callenergenie.log" "http://192.168.1.99/callenergenie.php?delay=10&switch=2&state=off"
echo Sleeping for 2 seconds
sleep 2
echo Done.
exit 0

view raw
callenergenie.sh
hosted with ❤ by GitHub

This calls the PHP script, telling it which socket to turn off, and how long to delay before sending the command, which we’re doing so that the Pi has time to shut down before the power is cut.

Scripts for the Pi with the Energenie shield

This is the PHP script I added to the other Pi which was already configured to be a PHP web server.

/var/www/html/callenergenie.php

<?php
/* MattC – Call this with various parameters..
callenergenie.php?
delay = time in seconds to sleep before calling Energenie
switch = which socket to talk to
state = turn socket on/off
e.g. callenergenie.php?delay=5&switch=2&state=off
*/
print ("Waiting ".$_GET['delay']." seconds");
sleep($_GET['delay']);
print ("Switching socket ".$_GET['switch']." ".$_GET['state']);
exec("sudo python /var/www/callenergenie.py ".$_GET['state']." ".$_GET['switch']);
?>

view raw
callenergenie.php
hosted with ❤ by GitHub

To allow PHP to run the script as root, I needed to add the Apache user to the list of sudo-ers.. not that secure tho :( I’d be interested in anyone who knows how to run the Energenie scripts a regular user.. their Python doesn’t like it when it’s not root.

nano /etc/sudoers

www-data ALL=(ALL) NOPASSWD:ALL

The nice thing about the PHP script is that we can actually call it to turn the Pi on remotely too.. so you could configure that into a widget on your phone, or add it to Alexa.

Basic Automated Testing using FeatherTest for Chrome

There are a fair number of automated testing tools out there like Intern or Puppeteer, but I wanted something super simple and quick to set up to test a variety of pages on a site I develop.

I was making changes to JSON-LD, page metadata, and some of the data that’s sent to Omniture analytics. All the pages types are slightly different, containing things like Documents, Discussions, Blog Posts, landing pages, etc. So I needed to go to a variety of URLs on my local dev environment to see what certain DOM elements got set to, and check the contents of some JavaScript variables.

I’d then need to do the same checks against our Dev, Staging and Production servers to make sure they all looked correct there too.

After a bit of searching I came across FeatherTest which is fed a text file where you use JavaScript/jQuery to define & run the tests.

It’s very easy to set up tests, and the same test script file can be run against whatever site you’re looking at in your browser. For more info go here;

https://xaviesteve.com/5302/feathertest-automated-website-testing-extension-google-chrome/

Typical FeatherTest Script Structure + Syntax

Tip 1 – Preserve Log

The output from FeatherTest goes into the console, so if you’re testing multiple pages, you’ll need to check the ‘Preserve Log’ option, otherwise you’ll lose the output as Chrome navigates between pages.

Tip 2 – Output Formatting

When writing scripts, I’d recommend colouring the console output, and prefixing each line with something easily identifiable. In my case I’m using ‘SUDO – ‘ and colouring the text orange.

You can then simply filter the console to just see your output;

When you’ve filtered the output, you can then save it to a file (right-click, save as..) and format it into shape.

I’ve found this really useful to monitor how my SEO data has improved as I’ve made changes, and to sanity check I’ve not broken anything between releases.

Tip 3 – Variable access

Some of the test scripts I’ve written needed access to variables defined in the scope of the main window.. FeatherTest can’t normally access these variables, so we need a helper function.

The helper function either needs baking into your site’s JavaScript, or you can inject it using an extension like TamperMonkey. Using TamperMonkey means you can use it on whatever site you want, not just ones where you’re able to install the function on.

My code adds an event listener that you can call from FeatherTest which you can request variable values from.

e.g.

window.postMessage({ "action": "variable", "value": "myVar.hierarchy"}, window.origin);

This is the TamperMonkey/GreaseMonkey script I use;

// ==UserScript==
// @name FeatherTest Variable Support
// @namespace http://mysite
// @include http*://mysite/*
// @description Add support for FeatherTest variable access. Matt Collinge.
// @version 1.0
// @grant all
// ==/UserScript==
function featherTestSupport() {
if (typeof(window.addEventListener)!='undefined') window.addEventListener('message',function(event) {
// Make sure the request is coming from our own site (or FeatherTest)
if (event.origin !== window.origin) return;
if (typeof(event.data.action)=='undefined') return;
// Instead, I used this from StackOverflow; https://stackoverflow.com/questions/11924731/get-object-by-name-as-string-without-eval
if (event.data.action=='variable') {
var variableValue = event.data.value.split('.').reduce(function (object, property) {
return object[property];
}, unsafeWindow);
console.log('%c'+event.data.value+' = '+variableValue, 'color:orange');
}
},false);
}
featherTestSupport();

FeatherTest Script – Example 1 – DOM Lookup

Pulling data out of the DOM is straightforward;

'feathertest'
console.log('%cSUDO – HOMEPAGE', 'color:orange');
location.href = '/site_root/'
60000
console.log('%cSUDO – '+location.href, 'color:orange');
console.log('%cSUDO – meta_title = '+$('meta[name="title"]').attr('content'), 'color:orange');
console.log('%cSUDO – meta_og:title = '+$('meta[property="og:title"]').attr('content'), 'color:orange');
console.log('%cSUDO – meta_description = '+$('meta[name="description"]').attr('content'), 'color:orange');
console.log('%cSUDO – meta_og:description = '+$('meta[property="og:description"]').attr('content'), 'color:orange');
console.log('%cSUDO – meta_og:image = '+$('meta[property="og:image"]').attr('content'), 'color:orange');
console.log('%cSUDO – meta_keywords = '+$('meta[name="keywords"]').attr('content'), 'color:orange');
console.log('%cSUDO – ', 'color:orange');

FeatherTest Script – Example 2 – Variable Access & JSON-LD

To access variables we’ll use the TamperMonkey function I posted above. We can also pull out any JSON-LD splats and present them quite nicely in the console output.

'feathertest'
console.log('%cSUDO – HOMEPAGE', 'color:orange');
location.href = '/site_root/'
60000
console.log('%cSUDO – '+location.href, 'color:orange');
// Output JSON-LD on page
$('script[type="application/ld+json"]').each(function(index,json){ console.log('%cSUDO – '+JSON.stringify(JSON.parse(json.innerHTML),null,2), 'color:orange') });
// Output the contents of some JavaScript variables
window.postMessage({ "action": "variable", "value": "myVar.hierarchy"}, window.origin);
window.postMessage({ "action": "variable", "value": "myVar.channel"}, window.origin);
window.postMessage({ "action": "variable", "value": "currentContainer.name"}, window.origin);
console.log('%cSUDO – ', 'color:orange');

 

17 Extensions to help the transition from Firefox to Chrome

I’m finally done with Firefox. When I first started using Firefox, the add-ons were a game-changer & I loved how much extra functionality they added to my day-to-day work.

Today, Chrome dominates the market, is waaay faster, and at the end of 2017 Mozilla is changing the add-on framework so some of the ‘classic’ add-ons I use will cease to work.

The final straw was seeing how fast Chrome way for general browsing and content creation; so much snappier than Firefox. Maybe that’s down to an ageing Firefox user profile.. but, IMO, Chrome is the future.

To ease my transition from Firefox to Chrome I’m using a bunch of extensions that give me the features I’ve grown used to. I thought I’d list out what I’m using so that others might benefit from knowing they’re out there & how useful they can be.

Adblock Plus
Blocks adds. I’d tried uBlock.. but found it breaking a bunch of sites.. so back to this one I’ve used for years in Firefox.

Akamai debug headers
Makes it simple to see what’s happening with websites fronted by the Akamai CDN.

Awesome Screenshot
Full-page screenshots

Cookie Inspector
Enables editing + adding of Cookies (I guess one day the Chrome devs will add this into the core app.. one day).

Downloads Router
Routes certain file types to certain folders. Bit of a faff to set up, but I find it useful for filing downloads into set folders.

Fauxbar
The Chrome omnibar isn’t great for finding URLs I had open hours/days ago (Firefox was brilliant). This sorts out that problem & does a pretty good job at indexing everything nicely.

In addition to that, it gives you a neat menu bar with shortcuts to a whole bunch of things; bookmarks, extensions, apps, options, etc. The configurable tiles for sites is super-handy too.

HostAdmin App
Quick and easy host file editor.. especially useful if you’re using proxy exceptions to speed up access to certain internal sites, and want to be able to configure or toggle the entries easily.

LastPass
Excellent cross-device password manager.

ModHeader
Modify browser headers. Useful for testing things like GeoIP.

Open IE
Adds in a context menu to open the current URL or link in other browsers (IE, Firefox, Opera, etc). Need an external helper program installing in Windows.

Page Monitor
Monitor web pages for changes.. works best when you set the Advanced option to look at a particular part of the page using CSS selectors.

Proxy SwitchyOmega
Set up multiple proxies and easily switch between them via the toolbar button.

SimpleUndoRecents
This will give you a button where you can undo the accidental closing of a tab. (TabMixPlus did something similar in Firefox).

Tampermonkey
Lets you run scripts against web pages each time you load the page.. essentially allowing you to alter the page after it renders. Super handy for removing or adding elements to the page. This extension is the equivalent to Greasemonkey on Firefox.

The Camelizer
Nothing to do with work.. but essential all the same. Lets you see the price history for products on Amazon.. and set alerts for price fluctuations.

Web Developer
Handy tools for developers.

Xmarks Bookmark Sync
Synchronise bookmarks between multiple browsers on multiple PCs.. even has version history in case you delete bookmarks by accident.

 

Honorary mention..

An extension called Postman would have made this list a few months ago.. but it’s moved to a stand-alone application for Windows + Mac. It’s another essential bit of kit for developers; if you’ve not checked it out, go take a look.

MIA…

That covers all but one of the Firefox add-ons I used to use. The one I still miss is Locationbar2, which I simply can’t find an equivalent for in Chrome.

It essentially makes each part of a site’s URL a clickable link.. which is super handy for quickly moving through a site’s structure.

If anyone spots something suitable, hit me up in the comments.

Home Automation Project – Raspberry Pi Heating Controller – Part 1

pi-controlI’m going to build a home automation project which connects a Raspberry Pi to control my central heating. I wasn’t particularly happy ripping out all the existing controls, and wanted to piggyback onto them.. which helps if the Pi ever fails (I’ve still got the old controls to fall back on).

I also didn’t want to mess with the existing heating control board, so bought a duplicate unit (British Gas UP2) from eBay for about £12.. I can perfect the project on that, and install it when I’m ready.

This set of videos goes through each step of the project.. starting off with opening the control board, an overview of what I want to do, and testing out the changes.

Opening up the Control Panel

This was a bit tricky.. it wasn’t quite obvious which plastic clips needed pushing in to pull the board out.. if you were doing this on your actual panel (not an eBay-bought duplicate) then this video should help work out what you need to do to get into it without damaging anything.

 

Project Overview

Next up, I’ll quickly go over what I intend to do to piggyback onto the control board. There’s a project here which did exactly what I wanted to do. He’s not using a PiFace 2 like I intend to use, and he wants to be able to control the hot water as well, but everything else is the same.

 

Safety First – Masking off the High Voltage Area

In this second video, I’ll show how I’m masking off the high voltage area of the board to make it a bit safer when I’m testing things out. Obviously most of the time the board is off, but this helps keep things safer when it is on without the cover.

 

Identifying Solder Points

Luckily this blog gave me a good starting point, but it wasn’t clear where to get the status of the central heating.. I used a multimeter to find a spot which changed voltage when the system was on, and this diagram shows you what I found;

pi-heat-3

Soldering

Since I only needed 4 wires for this project (2 for the switch, and 2 for the system state), I took an old USB cable, cut the ends off, stripped the wires and soldered it to the board without much trouble.

pi-solder

Soldering Complete!

This shows the control board after the soldering has been completed.. it’s pretty simple soldering; the only tricky part was finding the points to connect to for the system state (on/off). I’ve stuck down some of the wires so that they don’t catch or get stuck underneath the control boards buttons.

 

Testing the Wiring

Now that I’ve done the soldering, I’m testing out the wiring.. seeing whether connecting the two wires for the switch turns the central heating on, and when it is on, whether we get voltage on the other two wires to indicate the system state.

 

Controlling from Software

I’ve now hooked it up to the Pi Face 2 board, which can be controlled with a few lines of Python to simulate a button press, and detect the state of the system.

With these basics in place, the rest of the control software can be written to do scheduling, bring in temperature readings, and allow the system to be controlled remotely.

Controlling Power Sockets using a Raspberry Pi

The subwoofer we had in our home cinema setup died a few weeks ago, so I did my research and found a nice replacement. The only thing I didn’t spot was the fact it never goes into standby if there’s no signal (unlike the old one). I tried using some eco plugs which turn off peripherals when the TV was turned off.. but it learns the TV remote signals, and completely turns the TV off as well.. meaning that you have to hit the power button twice to turn the TV back on; that doesn’t work well with the Harmony all-in-one remote we use.

What I decided to do was buy an Energenie socket, which can be switched on/off wirelessly from a Raspberry Pi. The kit comes with 2 sockets and a transmitter to attach to the GPIO headers on the Pi, and costs about £20.

In my subwoofer scenario I basically want it switched on when the TV is on, and off when the TV is off. The TV has a Chromecast plugged into it which is visible on my local network. If you’ve got a Smart TV on your network, maybe that’ll be visible in the same way. So when the TV/Chromecast appear on the network, we know to switch on the power socket.

energeniesockets

Here’s the small Energenie transmitter attached to the GPIO headers on my B+.. it’s pretty tiny and the case I’ve got still fits over the top. Notice the small hole where you can attach an aerial.. if you want extra range, then you’ll need to solder one on.. I added a 135mm wire, since the range I got out of it just wasn’t enough to get from the dining room cupboard to the living room.

energeniepi

 

To put this together, we can use the Raspberry Pi Network Spy code I wrote in my previous blog posts on element14;

Raspberry Pi Network Spy – Part 1 – Initial Setup + d/b Schema
Raspberry Pi Network Spy – Part 2 – D/b Setup + PHP for the scanner

All we need is a new PHP page that’ll call one of the functions we’ve already written.. we need a list of the MAC addresses that are currently visible on the network, then check whether the Chromecast is there. Once we know whether the TV/Chromecast is on or off, we then call a Python script that will turn the Energenie socket on/off.

Here’s the PHP;

arp-chromecast.php

The Python script could follow the Energenie example script, but there’s actually an even more simple Python package which I’ve used in this project. To install it I did the following;

sudo apt-get install python-pip
sudo pip install energenie

Then I wrote this helper Python script (which we’ll call from PHP) that accepts a couple of parameters, like this callenergenie.py [on|off] [switch_number];

callenergenie.py

from energenie import switch_on, switch_off
import sys

if len(sys.argv)==1:
print ‘Please specify arguments like this callenergenie.py [on|off] [switch_number]’
print ‘eg. callenergenie.py on 1’
print ‘eg. callenergenie.py off 2′
else:
on_or_off = sys.argv[1]
which_switch = int(sys.argv[2])

if (on_or_off==’on’):
print ‘Switching on ‘, which_switch
switch_on(which_switch)

if (on_or_off==’off’):
print ‘Switching off ‘, which_switch
switch_off(which_switch)

Now that we’ve written the PHP & Python, all we need to do is run the PHP every minute to scan the network and do the switching. We’ll do this using another cron job;

crontab -e

*/1 * * * * sudo /usr/bin/php /var/www/arp-chromecast.php

 

Project Mentions

This project of mine has been included in PC Pro magazine, and on one of my favourite tech podcasts, TekThing (at 22min 40sec in the video below)!

Using Wireshark and MITM to explore a STB

I’ve recently bought a new Freeview HD box from 3view. It has a whole host of features and can be considered a “connected” device. As with most high-end set-top-boxes (STB) it pulls software firmware updates from the web, and I was interested to see where it went to get these updates & how it knew they were available.

I know about using tools to sniff network traffic, but have only done this to sniff traffic coming directly out of the PC I’m running the capture software on. Buying this 3view box gave me more of an inventive to expand my knowledge & figure out how to capture the traffic from other devices.

It was actually relatively easy. I decided to do a Machine in the Middle (MITM) ‘attack’ which was documented over at the Wireshark wiki.

In my case I didn’t have 2 network cards, but did have a laptop with one network card, and a wireless card. In Windows XP I bridged the NIC to the Wireless adapter, then plugged in a cross-over cable that linked the 3view box to my laptop. Then, after a bit of messing about with IP addresses it started working.. my 3view box was accessing my wireless router via my laptop.

Now that all the traffic from the 3view box was going via my laptop, all I then needed to do was fire up Wireshark & take a look at the packets.

Intercepting the traffic allowed me to see where the box was going for it’s updates, and the User Agent. That’s been documented over at the 3viewer community website I set up for 3view owners.

http://3viewer.elementfx.com/

QR Code Bookmarklet

QR Codes are a useful way of getting data to your mobile phone using it’s built-in camera. They’re basically 2D barcodes that can carry things like URLs and contact details. On Android I’d recommend using the app called Barcode Scanner to read QR Codes.

There were instances where I wanted to open up a webpage with a long URL on my phone & didn’t want to go through the hassle of copying and pasting it into one of those online QR Code generators.

This bookmarklet for Firefox and newer versions of IE lets you create a QR Code for the page you’re on.. it’ll default to the current page, but you can also override this with something else (like a URL from your clipboard, or whatever).

Add a new bookmark to your toolbar, and set the URL to the code below (I’d have put the proper link on here but WordPress disables the Javascript);

javascript:var%20sCode=prompt('Enter%20URL%20to%20encode',window.location);void(window.open('http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl='+encodeURIComponent(sCode),'Qr%20code','top=100,left=200,width=350,height=350,status=yes'));

iPhone and Android development with Titanium

Over the past few months I’ve worked on a couple of mobile applications for the iPhone and Android platforms. I’d looked at Phonegap some time before that, but determined that it wasn’t up to the job, but more recently I stumbled across Titanium from Appcelerator. The idea is that you code up your apps using HTML and Javascript. The Javascript calls the Titanium API to create things like lists, dialog boxes, and phone features such as geolocation.

Some of the advantages of using Titanium are:

– No need to learn Objective-C (iPhone) or Java (Android)
– Leverage existing HTML + Javascript skills
– Write one version of the code that can be deployed to both platforms
– Code is compiled up into native applications which are accepted in the App Store
– Potential to deploy to other platforms in the future (e.g. Blackberry, Symbian)

The level of support provided by the Appcelerator staff on the official forums is brilliant, and the tutorial videos are good for those who want to get an overview of creating apps without wading through documentation.

You’ll still need a Mac if you want to develop for the iPhone, because Titanium makes use of the iPhone SDK. But if you just want to do Android development then you can use Window or Linux as well.

Although you’ll be developing 1 set of code for both the iPhone and Android, you’ll probably want to customise the UI slightly differently for each platform. For example, Android apps often hide away items such as ‘Settings’ and ‘Help’ under the Menu button. It’s simple to code this kind of thing up:

	if (Titanium.Platform.name == 'android') {
		var menu = Titanium.UI.createMenu();
		menu.addItem("Help/About", function() {
			displayWindow('Help / About', 'window_about.html');
		}, Titanium.UI.Android.SystemIcon.HELP);
		Titanium.UI.setMenu(menu);
	} else {
		data.push({title:'Help / About',image:'tabicon_help.png', color:'#ffffff'});
	}

That code will create the Help/About option under a menu on Android, and add it to the home screen’s list on the iPhone. Simple.

Titanium is an awesome framework so if you’re considering developing for the iPhone and/or Android then I’d highly recommend you take a look.

Power Meter Plus in PC Pro Magazine

pc-pro-logo Power Meter Plus has been getting a lot of coverage this month; it’s been mentioned on dozens of blogs and now in PC Pro magazine issue 172, in fact I think Lifehacker might have picked up on it from there & the blogs picked up on Lifehacker’s article.

pcpro-jan-2009

Power Meter Plus featured on Lifehacker

Lifehacker is one of my daily visits, so it was brilliant to see that it had Power Meter Plus as the Featured Windows Download :-D

Creating a Netvibes / iGoogle Gadget for Multi-Image Display

To help make it as easy as possible for family members to see new pictures from the Collinge household I decided to set them up with Netvibes homepages, each containing a widget to display the latest photos from Picasa Web Albums. Picasa Web Albums provide an RSS feed that you can subscribe to which is a good start.. but I couldn’t find a way to display them just as I wanted.

The spec is to display the latest images, over as many columns as the user specifies.. and have the images resize to fit the width of the widget. They pretty much get displayed in a grid style layout.

Step 1) Get the URL for Picasa Web Albums (or whatever service you’re using) and make sure it works. The first gotcha here was that Picasa Web Albums has a limitation which means that images > 800px will not be embedded. They’ll result in a 404 File Not Found. To get around this, append ?imgmax=800 to the RSS’s URL.

Step 2) The feed for Picasa Web Albums is sorted in ascending date order.. I wanted it in descending date order so that the latest photos show first. To do this I chose to re-format the feed using Yahoo Pipes.. it’s a way of tinkering with a feed an invaluable for times when you need to do something simple like this.

Picasa gives you an Atom-based feed which seems to be causing a few issues with my code.. it basically makes the images go into a different node from the one I expected.. and I’ve been unable to work out exactly where it’s putting them. The best way around this is to simply run the RSS feed through a simple Yahoo Pipe; I’ve published one which sorts the images in date descending order. Use that and copy the RSS feed it generates.

Step 3) Create a new widget using UWA so that it works with Netvibes and iGoogle. This is relatively simple.. just requiring a bit of coding to make it happen. As usual I’ve tried to make the code as generic as possible & driven by user preferences. The user can specify which node in the JSON object (returned from the RSS feed) contains the image to display.. useful when dealing with non-standard image enclosures. It will default to the first enclosure at item.enclosures[0].url

The finished widget is published here.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:widget="http://www.netvibes.com/ns/"  >
	<head>
		<title>Multi-Image Display</title>
		
		<meta name="author" content="Matt Collinge" />
		<meta name="email" content="do-not-email@mt2009.com" />
		<meta name="description" content="Display multiple images from an RSS feed. Useful for feeds like those from Picasa Web Albums" />
		<meta name="version" content="1.0" />
		<meta name="website" content="http://eco.netvibes.com/widgets/298784/multi-image-display" />

		<meta name="keywords" content="image, rss, picasa, web album, picture, multiple, display, grid" />
		<meta name="autoRefresh" content="15" />
		<meta name="apiVersion" content="1.2" />
		
		<link rel="stylesheet" type="text/css" href="http://www.netvibes.com/themes/uwa/style.css" />
		<script type="text/javascript" src="http://www.netvibes.com/js/UWA/load.js.php?env=Standalone"></script>
		
		<style type="text/css">
			.imageDisplay {
				margin:0;
				padding:0;
			}
		</style>
		
		<widget:preferences>
			<preference name="title" type="text" label="Title" defaultValue="Multi-Image Display" />

			<preference name="url" type="text" label="RSS Feed" defaultValue="" />
			<preference name="limit" type="range" label="Number of images to display" defaultValue="10" step="1" min="1" max="50" />
			<preference name="columns" type="range" label="Number of columns to use" defaultValue="2" step="1" min="1" max="8" />
			<preference name="imagenode" type="text" label="Node in RSS Feed Containing Image" defaultValue="item.enclosures&#91;0&#93;.url" />
		</widget:preferences>
	
		<script>
			var BasicRSSReader = {};
			 
			BasicRSSReader.feed = false;
			 
			widget.onLoad = function() {
				if (widget.getValue('url') === '' || widget.getValue('url') == undefined) {
					widget.setBody('Please edit the preferences and enter the URL of the RSS feed where you want to take images from.<br><br>. Use a feed re-formatter like Yahoo Pipes if you need to tinker with a 3rd party RSS feed.');
				} else {
					widget.body.addClassName('imageDisplay');
					widget.setTitle(widget.getValue('title'));
					UWA.Data.getFeed(widget.getValue('url'), BasicRSSReader.display);
				}
			}
			
			BasicRSSReader.display = function(feed) {
				var bodyHTML = '';
				if (feed) BasicRSSReader.feed = feed;
				
				var imageWidth = widget.body.getDimensions().width / widget.getValue('columns');
				var imageCount = 0;
				var columnCount = 0;
				
				bodyHTML += '<table border=0 cellpadding=0 cellspacing=0>';
				for(var i=0; i < BasicRSSReader.feed.items.length; i++) {
					var item = BasicRSSReader.feed.items&#91;i&#93;;
					
					if (imageCount >= widget.getValue('limit')) {
						bodyHTML += '</tr>';
						break;
					}
					
					if (columnCount == 0) {
						bodyHTML += '<tr>';
					}
					bodyHTML += '<td><a href="' + item.link + '"><img src="' + eval(widget.getValue('imagenode')) + '" width="' + imageWidth + '" /></a></td>';
					
					columnCount++;
					
					if (columnCount == widget.getValue('columns')) {
						columnCount = 0;
						bodyHTML += '</tr>';
					}
					
					imageCount++;
				}
				bodyHTML += '</table>';
				
				if (imageCount==0) bodyHTML = 'Unable to load feed.';
				widget.setBody(bodyHTML);
			}
		</script>			
	
	</head>
	<body>
		<p>Loading...</p>

	</body>
</html>