diff --git a/hardware/37-rpi-piface.html b/hardware/37-rpi-piface.html
new file mode 100644
index 00000000..3e3ac043
--- /dev/null
+++ b/hardware/37-rpi-piface.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hardware/37-rpi-piface.js b/hardware/37-rpi-piface.js
new file mode 100644
index 00000000..0d692efd
--- /dev/null
+++ b/hardware/37-rpi-piface.js
@@ -0,0 +1,134 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var RED = require("../../red/red");
+var util = require("util");
+var exec = require('child_process').exec;
+var fs = require('fs');
+
+if (!fs.existsSync("/usr/local/bin/gpio")) {
+ exec("cat /proc/cpuinfo | grep BCM27",function(err,stdout,stderr) {
+ if (stdout.indexOf('BCM27') > -1) {
+ util.log('[37-rpi-piface.js] Error: Cannot find Wiring-Pi "gpio" command');
+ }
+ // else not on a Pi so don't worry anyone with needless messages.
+ });
+ return;
+}
+
+// Map names of pins to Gordon's gpio PiFace pin numbers
+var pintable = {
+// Physical : WiringPi
+ "Button S1":"200",
+ "Button S2":"201",
+ "Button S3":"202",
+ "Button S4":"203",
+ "Input 5":"204",
+ "Input 6":"205",
+ "Input 7":"206",
+ "Input 8":"207",
+ "Output0":"208",
+ "Output1":"209",
+ "Output2":"210",
+ "Output3":"211",
+ "Output4":"212",
+ "Output5":"213",
+ "Output6":"214",
+ "Output7":"215",
+ "LED 0 / Relay 0":"200",
+ "LED 1 / Relay 1":"201",
+ "LED 2":"202",
+ "LED 3":"203",
+ "LED 4":"204",
+ "LED 5":"205",
+ "LED 6":"206",
+ "LED 7":"207"
+}
+
+function PiFACEInNode(n) {
+ RED.nodes.createNode(this,n);
+ this.buttonState = -1;
+ this.pin = pintable[n.pin];
+ this.intype = n.intype;
+ var node = this;
+ if (node.pin) {
+ exec("gpio -p mode "+node.pin+" "+node.intype, function(err,stdout,stderr) {
+ if (err) node.error(err);
+ else {
+ node._interval = setInterval( function() {
+ exec("gpio -p read "+node.pin, function(err,stdout,stderr) {
+ if (err) node.error(err);
+ else {
+ if (node.buttonState !== Number(stdout)) {
+ var previousState = node.buttonState;
+ node.buttonState = Number(stdout);
+ if (previousState !== -1) {
+ var msg = {topic:"pi/"+node.pin, payload:node.buttonState};
+ node.send(msg);
+ }
+ }
+ }
+ });
+ }, 250);
+ }
+ });
+ }
+ else {
+ node.error("Invalid PiFACE pin: "+node.pin);
+ }
+}
+
+function PiFACEOutNode(n) {
+ RED.nodes.createNode(this,n);
+ this.pin = pintable[n.pin];
+ var node = this;
+ if (node.pin) {
+ node.on("input", function(msg) {
+ if (msg.payload === "true") msg.payload = true;
+ if (msg.payload === "false") msg.payload = false;
+ var out = Number(msg.payload);
+ if ((out == 0)|(out == 1)) {
+ exec("gpio -p write "+node.pin+" "+out, function(err,stdout,stderr) {
+ if (err) node.error(err);
+ });
+ }
+ else node.warn("Invalid input - not 0 or 1");
+ });
+ }
+ else {
+ node.error("Invalid PiFACE pin: "+node.pin);
+ }
+}
+
+
+
+exec("gpio load spi",function(err,stdout,stderr) {
+ if (err) {
+ util.log('[37-rpi-piface.js] Error: "gpio load spi" command failed for some reason.');
+ }
+ exec("gpio -p reset",function(err,stdout,stderr) {
+ if (err) {
+ util.log('[37-rpi-piface.js] Error: "gpio -p reset" command failed for some reason.');
+ }
+ RED.nodes.registerType("rpi-piface in",PiFACEInNode);
+ RED.nodes.registerType("rpi-piface out",PiFACEOutNode);
+ PiFACEInNode.prototype.close = function() {
+ clearInterval(this._interval);
+ }
+ PiFACEOutNode.prototype.close = function() {
+ }
+ });
+});
diff --git a/hardware/78-ledborg.html b/hardware/78-ledborg.html
new file mode 100644
index 00000000..e97da1b0
--- /dev/null
+++ b/hardware/78-ledborg.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
diff --git a/hardware/78-ledborg.js b/hardware/78-ledborg.js
new file mode 100644
index 00000000..80f6e316
--- /dev/null
+++ b/hardware/78-ledborg.js
@@ -0,0 +1,53 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+var RED = require("../../red/red");
+var util = require('util');
+var fs = require('fs');
+
+// check if /dev/ledborg exists - if not then don't even show the node.
+if (!fs.existsSync("/dev/ledborg")) {
+ util.log("[78-ledborg.js] Error: PiBorg hardware : LedBorg not found");
+ return;
+}
+
+function LedBorgNode(n) {
+ RED.nodes.createNode(this,n);
+ var p1 = /[0-2][0-2][0-2]/
+ var p2 = /^\#[A-Fa-f0-9]{6}$/
+ var node = this;
+
+ this.on("input", function(msg) {
+ if (p1.test(msg.payload)) {
+ fs.writeFile('/dev/ledborg', msg.payload, function (err) {
+ if (err) node.warn(msg.payload+" : No LedBorg found");
+ });
+ }
+ if (p2.test(msg.payload)) {
+ var r = Math.floor(parseInt(msg.payload.slice(1,3),16)/88).toString();
+ var g = Math.floor(parseInt(msg.payload.slice(3,5),16)/88).toString();
+ var b = Math.floor(parseInt(msg.payload.slice(5),16)/88).toString();
+ fs.writeFile('/dev/ledborg', r+g+b, function (err) {
+ if (err) node.warn(r+g+b+" : No LedBorg found");
+ });
+ }
+ else {
+ node.warn("Invalid LedBorg colour code");
+ }
+ });
+}
+
+RED.nodes.registerType("ledborg",LedBorgNode);