diff --git a/hardware/sensehatsim/LICENSE b/hardware/sensehatsim/LICENSE new file mode 100644 index 00000000..f433b1a5 --- /dev/null +++ b/hardware/sensehatsim/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/hardware/sensehatsim/README.md b/hardware/sensehatsim/README.md new file mode 100644 index 00000000..8d7000f4 --- /dev/null +++ b/hardware/sensehatsim/README.md @@ -0,0 +1,126 @@ +node-red-node-pi-sense-hat-simulator +==================================== + +A Node-RED node to simulate a +Raspberry Pi Sense HAT. + +This allows you to create flows that interact with a virtual Sense HAT without the actual +hardware - whether you're running on a Raspberry Pi, a laptop or elsewhere. + +Once a Sense HAT simulator node has been deployed, the web page that provides +a UI to the simulator can be accessed by clicking the link in the node's info panel. + +## Install + +Run the following command in your Node-RED user directory (typically `~/.node-red`): + + npm install node-red-node-pi-sense-hat-simulator + +## Usage + +### Input Node + +This node sends readings from the various sensors on the Sense HAT, grouped into +three sets; motion events, environment events and joystick events. + +#### Motion events + +*** The current version of the simulator does not support Motion events *** + +Motion events include readings from the accelerometer, gyroscope and magnetometer, +as well as the current compass heading. They are sent at a rate of approximately 10 +per second. The `topic` is set to `motion` and the `payload` is an object with the +following values: + + - `acceleration.x/y/z` : the acceleration intensity in Gs + - `gyroscope.x/y/z` : the rotational intensity in radians/s + - `orientation.roll/pitch/yaw` : the angle of the axis in degrees + - `compass` : the direction of North in degrees + +#### Environment events + +Environment events include readings from the temperature, humidity and pressure +sensors. They are sent at a rate of approximately 1 per second. The `topic` +is set to `environment` and the `payload` is an object +with the following values: + + - `temperature` : degrees Celsius + - `humidity` : percentage of relative humidity + - `pressure` : Millibars + +#### Joystick events + +Joystick events are sent when the Sense HAT joystick is interacted with. The +`topic` is set to `joystick` and the `payload` is an object with the following values: + + - `key` : one of `UP`, `DOWN`, `LEFT`, `RIGHT`, `ENTER` + - `state` : the state of the key: + - `0` : the key has been released + - `1` : the key has been pressed + - `2` : the key is being held down + + +### Output Node + +This node sends commands to the 8x8 LED display on the Sense HAT. + +Commands are sent to the node in `msg.payload`. Multiple commands can +be sent in a single message by separating them with newline (\n) characters. + +#### Set the colour of individual pixels + +Format: `,,` + +`x` and `y` must either be a value from 0 to 7, a `*` to indicate the entire row +or column, or a range such as `3-6`. + +`colour` must be one of: + + - the well-known HTML colour names - eg `red` or `aquamarine`, + - the CheerLights colour names, + - a HEX colour value - eg `#aa9900` + - an RGB triple - `190,255,0` + - or simply `off` + +To set the entire screen to red: `*,*,red` + +To set the four corners of the display to red, green (#00ff00), yellow and blue (0,0,255): + +`0,0,red,0,7,#00ff00,7,7,yellow,7,0,0,0,255` + +To set a 3-pixel wide column to purple: `4-6,*,purple` + + +#### Rotate the screen + +Format: `R` + +`angle` must be 0, 90, 180 or 270. + +#### Flip the screen + +Format: `R` + +`axis` must be either `H` or `V` to flip on the horizontal or vertical axis respectively. + +#### Scroll a message + +*** The current version of the simulator does not support displaying text *** + +If `msg.payload` is not recognised as any of the above commands, it is treated +as a text message to be scrolled across the screen. + +If the text is a single character, it will be displayed without scrolling. To +scroll a single character, append a blank space after it - `"A "`.

+ +The following message properties can be used to customise the appearance: + + - `msg.color` - the colour of the text, default: `white` + - `msg.background` - the colour of the background, default: `off` + - `msg.speed` - the scroll speed. A value in the range 1 (slower) to 5 (faster), default: `3` + +#### Set the screen brightness + +Format: `D` + +`level` must be 0 (low) or 1 (high). diff --git a/hardware/sensehatsim/colours.js b/hardware/sensehatsim/colours.js new file mode 100644 index 00000000..fa0fa1aa --- /dev/null +++ b/hardware/sensehatsim/colours.js @@ -0,0 +1,220 @@ +/** + * 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. + **/ + +var colours = { + 'aqua':'#00FFFF', + 'aliceblue':'#F0F8FF', + 'antiquewhite':'#FAEBD7', + 'black':'#000000', + 'off':'#000000', + 'blue':'#0000FF', + 'cyan':'#00FFFF', + 'darkblue':'#00008B', + 'darkcyan':'#008B8B', + 'darkgreen':'#006400', + 'darkturquoise':'#00CED1', + 'deepskyblue':'#00BFFF', + 'green':'#008000', + 'lime':'#00FF00', + 'mediumblue':'#0000CD', + 'mediumspringgreen':'#00FA9A', + 'navy':'#000080', + 'springgreen':'#00FF7F', + 'teal':'#008080', + 'midnightblue':'#191970', + 'dodgerblue':'#1E90FF', + 'lightseagreen':'#20B2AA', + 'forestgreen':'#228B22', + 'seagreen':'#2E8B57', + 'darkslategray':'#2F4F4F', + 'darkslategrey':'#2F4F4F', + 'limegreen':'#32CD32', + 'mediumseagreen':'#3CB371', + 'turquoise':'#40E0D0', + 'royalblue':'#4169E1', + 'steelblue':'#4682B4', + 'darkslateblue':'#483D8B', + 'mediumturquoise':'#48D1CC', + 'indigo':'#4B0082', + 'darkolivegreen':'#556B2F', + 'cadetblue':'#5F9EA0', + 'cornflowerblue':'#6495ED', + 'mediumaquamarine':'#66CDAA', + 'dimgray':'#696969', + 'dimgrey':'#696969', + 'slateblue':'#6A5ACD', + 'olivedrab':'#6B8E23', + 'slategray':'#708090', + 'slategrey':'#708090', + 'lightslategray':'#778899', + 'lightslategrey':'#778899', + 'mediumslateblue':'#7B68EE', + 'lawngreen':'#7CFC00', + 'aquamarine':'#7FFFD4', + 'chartreuse':'#7FFF00', + 'gray':'#808080', + 'grey':'#808080', + 'maroon':'#800000', + 'olive':'#808000', + 'purple':'#800080', + 'lightskyblue':'#87CEFA', + 'skyblue':'#87CEEB', + 'blueviolet':'#8A2BE2', + 'darkmagenta':'#8B008B', + 'darkred':'#8B0000', + 'saddlebrown':'#8B4513', + 'darkseagreen':'#8FBC8F', + 'lightgreen':'#90EE90', + 'mediumpurple':'#9370DB', + 'darkviolet':'#9400D3', + 'palegreen':'#98FB98', + 'darkorchid':'#9932CC', + 'yellowgreen':'#9ACD32', + 'sienna':'#A0522D', + 'brown':'#A52A2A', + 'darkgray':'#A9A9A9', + 'darkgrey':'#A9A9A9', + 'greenyellow':'#ADFF2F', + 'lightblue':'#ADD8E6', + 'paleturquoise':'#AFEEEE', + 'lightsteelblue':'#B0C4DE', + 'powderblue':'#B0E0E6', + 'firebrick':'#B22222', + 'darkgoldenrod':'#B8860B', + 'mediumorchid':'#BA55D3', + 'rosybrown':'#BC8F8F', + 'darkkhaki':'#BDB76B', + 'silver':'#C0C0C0', + 'mediumvioletred':'#C71585', + 'indianred':'#CD5C5C', + 'peru':'#CD853F', + 'chocolate':'#D2691E', + 'tan':'#D2B48C', + 'lightgray':'#D3D3D3', + 'lightgrey':'#D3D3D3', + 'thistle':'#D8BFD8', + 'goldenrod':'#DAA520', + 'orchid':'#DA70D6', + 'palevioletred':'#DB7093', + 'crimson':'#DC143C', + 'gainsboro':'#DCDCDC', + 'plum':'#DDA0DD', + 'burlywood':'#DEB887', + 'lightcyan':'#E0FFFF', + 'lavender':'#E6E6FA', + 'darksalmon':'#E9967A', + 'palegoldenrod':'#EEE8AA', + 'violet':'#EE82EE', + 'azure':'#F0FFFF', + 'honeydew':'#F0FFF0', + 'khaki':'#F0E68C', + 'lightcoral':'#F08080', + 'sandybrown':'#F4A460', + 'beige':'#F5F5DC', + 'mintcream':'#F5FFFA', + 'wheat':'#F5DEB3', + 'whitesmoke':'#F5F5F5', + 'ghostwhite':'#F8F8FF', + 'lightgoldenrodyellow':'#FAFAD2', + 'linen':'#FAF0E6', + 'salmon':'#FA8072', + 'oldlace':'#FDF5E6', + 'warmwhite':'#FDF5E6', + 'bisque':'#FFE4C4', + 'blanchedalmond':'#FFEBCD', + 'coral':'#FF7F50', + 'cornsilk':'#FFF8DC', + 'darkorange':'#FF8C00', + 'deeppink':'#FF1493', + 'floralwhite':'#FFFAF0', + 'fuchsia':'#FF00FF', + 'gold':'#FFD700', + 'hotpink':'#FF69B4', + 'ivory':'#FFFFF0', + 'lavenderblush':'#FFF0F5', + 'lemonchiffon':'#FFFACD', + 'lightpink':'#FFB6C1', + 'lightsalmon':'#FFA07A', + 'lightyellow':'#FFFFE0', + 'magenta':'#FF00FF', + 'mistyrose':'#FFE4E1', + 'moccasin':'#FFE4B5', + 'navajowhite':'#FFDEAD', + 'orange':'#FFA500', + 'orangered':'#FF4500', + 'papayawhip':'#FFEFD5', + 'peachpuff':'#FFDAB9', + 'pink':'#FFC0CB', + 'red':'#FF0000', + 'seashell':'#FFF5EE', + 'snow':'#FFFAFA', + 'tomato':'#FF6347', + 'white':'#FFFFFF', + 'yellow':'#FFFF00', + 'amber':'#FFD200' +}; + +var hexColour = /^#([0-9A-F][0-9A-F][0-9A-F]){1,2}$/i; + +module.exports.getRGB = function(col,rgb) { + if (!col) { + return null; + } + if (/^\d{1,3},\d{1,3},\d{1,3}$/.test(col)) { + return col; + } + col = col.toString().toLowerCase(); + if (col in colours) { + col = colours[col]; + } + if (hexColour.test(col)) { + if (col.length === 4) { + col = "#"+col[1]+col[1]+col[2]+col[2]+col[3]+col[3]; + } + if (rgb === "grb") { + g = parseInt(col.slice(1,3),16); + r = parseInt(col.slice(3,5),16); + b = parseInt(col.slice(5),16); + } + else { + r = parseInt(col.slice(1,3),16); + g = parseInt(col.slice(3,5),16); + b = parseInt(col.slice(5),16); + } + return r+","+g+","+b; + } + else { + return null; + } +} + +module.exports.getHex = function(col) { + col = col.toString().toLowerCase(); + if (col in colours) { + return colours[col]; + } + else { return null; } +} + +module.exports.HexRGB = function(hex) { + try { + r = parseInt(hex.slice(1,3),16); + g = parseInt(hex.slice(3,5),16); + b = parseInt(hex.slice(5),16); + return r+","+g+","+b; + } + catch(e) { return null; } +} diff --git a/hardware/sensehatsim/examples/Clock.json b/hardware/sensehatsim/examples/Clock.json new file mode 100644 index 00000000..54525109 --- /dev/null +++ b/hardware/sensehatsim/examples/Clock.json @@ -0,0 +1 @@ +[{"id":"8b346a30.651a88","type":"rpi-sensehat out","z":"7756eff1.08d0a","name":"","x":530,"y":220,"wires":[]},{"id":"c2e7a15d.237bd","type":"function","z":"7756eff1.08d0a","name":"Simple graphical clock","func":"\n// array to hold \"random\" pixels\nvar ranNums = [];\n\n// create a non-overlapping array of random numbers 0-8\nfunction rerand() {\n var nums = [0,1,2,3,4,5,6,7,8];\n var i = nums.length;\n var j;\n ranNums = [];\n while (i--) {\n j = Math.floor(Math.random() * (i+1));\n ranNums.push(nums[j]);\n nums.splice(j,1);\n }\n}\n\n// Get the hours and minutes and split into tens and units\nvar d = new Date();\nvar s = d.getSeconds();\nvar su = s%4;\nif (su === 0) {\n var h = d.getHours();\n var m = d.getMinutes();\n var hu = h%10;\n h = parseInt(h/10);\n var mu = m%10;\n m = parseInt(m/10);\n \n // Do the tens of hours (red)\n rerand();\n node.send({payload:\"1-3,1-3,0,0,0\"});\n for (var i=0; i + + + + + + +
+
+
+
+
+ Temperature +
+ -
+ +
+
+
+ Humidity +
+ -
+ +
+
+
+ Pressure +
+ -
+ +
+
+
+
+ + + +
+
+ + + + diff --git a/hardware/sensehatsim/sensehatsim.html b/hardware/sensehatsim/sensehatsim.html new file mode 100644 index 00000000..8c28e0be --- /dev/null +++ b/hardware/sensehatsim/sensehatsim.html @@ -0,0 +1,182 @@ + + + + + + + + + + diff --git a/hardware/sensehatsim/sensehatsim.js b/hardware/sensehatsim/sensehatsim.js new file mode 100644 index 00000000..2b9d4c9a --- /dev/null +++ b/hardware/sensehatsim/sensehatsim.js @@ -0,0 +1,395 @@ +/** + * 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 path = require("path"); + var ws = require("ws"); + var colours = require('./colours'); + + // 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 currentFlipH = false; + var currentFlipV = false; + var currentRotation = "R0"; + var currentDisplay = []; + var HAT = (function() { + var hatWS = null; + var wsServerListeners = {}; + var wsConnections = {}; + var currentEnvironment = {temperature: 20, humidity: 80, pressure: 1000}; + var hat = null; + var onclose = null; + var users = []; + var motionUsers = 0; + var envUsers = 0; + var reconnectTimer = null; + var envTimer = null; + + var connect = function() { + if (!hatWS) { + currentFlipH = false; + currentFlipV = false; + currentRotation = "R0"; + currentDisplay = []; + for (var y=0;y<8;y++) { + currentDisplay.push([]); + for (var x=0;x<8;x++) { + currentDisplay[y].push('0,0,0'); + } + } + var wsPath = RED.settings.httpNodeRoot || "/"; + wsPath = wsPath + (wsPath.slice(-1) == "/" ? "":"/") + "sensehat-simulator/ws" + + var storeListener = function(event,listener){ + if(event == "error" || event == "upgrade" || event == "listening"){ + wsServerListeners[event] = listener; + } + } + RED.server.addListener('newListener',storeListener); + // Create a WebSocket Server + hatWS = new ws.Server({ + server:RED.server, + path:wsPath, + // Disable the deflate option due to this issue + // https://github.com/websockets/ws/pull/632 + // that is fixed in the 1.x release of the ws module + // that we cannot currently pickup as it drops node 0.10 support + perMessageDeflate: false + }); + RED.server.removeListener('newListener',storeListener); + hatWS.on('connection', function(socket) { + var id = (1+Math.random()*4294967295).toString(16); + wsConnections[id] = socket; + socket.send("Y"+currentEnvironment.temperature+","+currentEnvironment.humidity+","+currentEnvironment.pressure); + socket.send(currentRotation); + if (currentFlipV) { + socket.send("FV"); + } + if (currentFlipH) { + socket.send("FH"); + } + var cmd = ""; + for (var y=0;y<8;y++) { + for (var x=0;x<8;x++) { + cmd += ","+x+","+y+","+currentDisplay[y][x]; + } + } + socket.send("P"+cmd.substring(1)); + + + socket.on('close',function() { + delete wsConnections[id]; + }); + socket.on('message',function(data,flags){ + var m; + var msg; + if ((m = LF_RE.exec(data)) !== null) { + currentEnvironment = {temperature: Number(m[1]), humidity: Number(m[2]), pressure: Number(m[3])}; + msg = "Y"+currentEnvironment.temperature+","+currentEnvironment.humidity+","+currentEnvironment.pressure; + for (var id in wsConnections) { + if (wsConnections.hasOwnProperty(id)) { + var client = wsConnections[id]; + if (client !== socket) { + client.send(msg); + } + } + } + } else if ((m = KEY_RE.exec(data)) !== null) { + msg = { + topic: "joystick", + payload: {key: KEY_MAP[m[1]], state: Number(m[2])} + } + for (var j=0;j= 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; + if ( /^(([0-7]|\*|[0-7]-[0-7]),([0-7]|\*|[0-7]-[0-7]),(\d{1,3},\d{1,3},\d{1,3}|#[a-f0-9]{3,6}|[a-z]+))(,([0-7]|\*|[0-7]-[0-7]),([0-7]|\*|[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(",")); + currentDisplay[Number(rule[1])][Number(rule[0])] = rule[2]; + 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(); + currentRotation = command; + } else if (/^F(H|V)$/i.test(line)) { + command = line.toUpperCase(); + if (command === 'FH') { + currentFlipH = !currentFlipH; + } else { + currentFlipV = !currentFlipV; + } + } 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-sensehatsim out",SenseHatOutNode); + + RED.httpAdmin.get("/sensehat-simulator",function(req,res) { + res.sendFile(path.join(__dirname,"public","index.html")); + }); +}