/** * Copyright 2016 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. **/ module.exports = function(RED) { "use strict"; var fs = require('fs'); var spawn = require('child_process').spawn; var colours = require('./colours'); var hatCommand = __dirname+'/sensehat'; if ( !(1 & parseInt ((fs.statSync(hatCommand).mode & parseInt ("777", 8)).toString (8)[0]) )) { RED.log.error(hatCommand + " command is not executable"); throw "Error : "+RED._("node-red:rpi-gpio.errors.mustbeexecutable"); } // the magic to make python print stuff immediately process.env.PYTHONUNBUFFERED = 1; // Xaccel.x,y,z,gyro.x,y,z,orientation.roll,pitch,yaw,compass var HF_RE = /^X(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+)$/; // Ytemperature,humidity,pressure var LF_RE = /^Y(.+),(.+),(.+)$/; // K[U|L|R|D|E][0|1|2] - joystick event: direction,state var KEY_RE = /^K(.)(.)$/; var KEY_MAP = { "U":"UP", "D":"DOWN", "L":"LEFT", "R":"RIGHT", "E":"ENTER" }; var HAT = (function() { var hat = null; var onclose = null; var users = []; var motionUsers = 0; var envUsers = 0; var reconnectTimer = null; var connect = function() { reconnectTimer = null; var buffer = ""; hat = spawn(hatCommand); hat.stdout.on('data', function (data) { buffer += data.toString(); var lines = buffer.split("\n"); if (lines.length == 1) { return; } buffer = lines.pop(); var m,msg; for (var i=0;i 0) { hat.stdin.write('X1\n'); } if (envUsers > 0) { hat.stdin.write('Y1\n'); } } var disconnect = function(done) { if (hat !== null) { onclose = done; hat.kill('SIGKILL'); hat = null; } if (reconnectTimer) { clearTimeout(reconnectTimer); } } return { open: function(node) { if (!hat) { connect(); } if (!reconnectTimer) { node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"}); } if (node.motion) { if (motionUsers === 0) { hat.stdin.write('X1\n'); } motionUsers++; } if (node.env) { if (envUsers === 0) { hat.stdin.write('Y1\n'); } envUsers++; } users.push(node); }, close: function(node,done) { if (node.motion) { motionUsers--; if (motionUsers === 0) { hat.stdin.write('X0\n'); } } if (node.env) { envUsers--; if (envUsers === 0) { hat.stdin.write('Y0\n'); } } users.splice(users.indexOf(node),1); if (users.length === 0) { disconnect(done); } else { done(); } }, send: function(msg) { if (hat) { hat.stdin.write(msg+'\n'); } } } })(); function SenseHatInNode(n) { RED.nodes.createNode(this,n); this.motion = n.motion; this.env = n.env; this.stick = n.stick; var node = this; node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"}); HAT.open(this); node.on("close", function(done) { HAT.close(this,done); }); } RED.nodes.registerType("rpi-sensehat in",SenseHatInNode); function SenseHatOutNode(n) { RED.nodes.createNode(this,n); var node = this; node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"}); HAT.open(this); node.on("close", function(done) { HAT.close(this,done); }); var handleTextMessage = function(line,msg) { var textCol = colours.getRGB(msg.color||msg.colour)||"255,255,255"; var backCol = colours.getRGB(msg.background)||"0,0,0"; var speed = null; if (!isNaN(msg.speed)) { speed = msg.speed; } var command = "T"; if (textCol) { command += textCol; if (backCol) { command += ","+backCol; } } if (speed) { var s = parseInt(speed); if (s >= 1 && s <= 5) { s = 0.1 + (3-s)*0.03; } command = command + ((command.length === 1)?"":",") + s; } command += ":" + line; return command; } node.on("input",function(msg) { var command; var parts; var col; if (typeof msg.payload === 'number') { HAT.send(handleTextMessage(""+msg.payload,msg)); } else if (typeof msg.payload === 'string') { var lines = msg.payload.split("\n"); lines.forEach(function(line) { command = null; col = colours.getRGB(line); if ( /^(([0-7]|\*),([0-7]|\*),(\d{1,3},\d{1,3},\d{1,3}|#[a-f0-9]{3,6}|[a-z]+))(,([0-7]|\*),([0-7]|\*),(\d{1,3},\d{1,3},\d{1,3}|#[a-f0-9]{3,6}|[a-z]+))*$/i.test(line)) { parts = line.split(","); var expanded = []; var i=0; var j=0; while (i 0) { var pixels = {}; var rules = []; for (i=expanded.length-1;i>=0;i--) { var rule = expanded[i]; if (!pixels[rule[0]+","+rule[1]]) { rules.unshift(rule.join(",")); pixels[rule[0]+","+rule[1]] = true; } } if (rules.length > 0) { command = "P"+rules.join(","); } } } if (!command) { if (/^R(0|90|180|270)$/i.test(line)) { command = line.toUpperCase(); } else if (/^F(H|V)$/i.test(line)) { command = line.toUpperCase(); } else if (/^D(0|1)$/i.test(line)) { command = line.toUpperCase(); } else { command = handleTextMessage(line,msg); } } if (command) { //console.log(command); HAT.send(command); } }); } }); } RED.nodes.registerType("rpi-sensehat out",SenseHatOutNode); }