Skip to content

Latest commit

 

History

History
6 lines (5 loc) · 20.9 KB

04_SimpleWebsite.md

File metadata and controls

6 lines (5 loc) · 20.9 KB

Below you will find an example of how to send and receive HTTPS in NodeRed and parse the LoRa data and check the SHA256 token. Furthermore a website is included to receive and send data from NodeRed. Please refer to the wiki to get more explanation.

Copy the below code, and import through the clipboard in NodeRed

[{"id":"e0e4fb1f.e20908","type":"http in","z":"65bb5a5b.a49fc4","name":"LoRa Post Catcher","url":"/lorapost","method":"post","swaggerDoc":"","x":201.61456298828125,"y":308.0035400390625,"wires":[["5671845e.7e62dc"]]},{"id":"155da7dd.385048","type":"websocket out","z":"65bb5a5b.a49fc4","name":"Send to Website","server":"520d238c.34fbec","client":"","x":1074.8960266113281,"y":307.888916015625,"wires":[]},{"id":"a44ca4ce.d0bfd8","type":"websocket in","z":"65bb5a5b.a49fc4","name":"Receive from website","server":"520d238c.34fbec","client":"","x":237.0001220703125,"y":493.888916015625,"wires":[["bb03950d.4ce068"]]},{"id":"8fce672d.a17fe8","type":"http response","z":"65bb5a5b.a49fc4","name":"","x":638.3401794433594,"y":407.8890380859375,"wires":[]},{"id":"60de4768.f2c2d8","type":"http in","z":"65bb5a5b.a49fc4","name":"Simple Website GET","url":"/simple","method":"get","swaggerDoc":"","x":226.3402099609375,"y":407.88897705078125,"wires":[["9f6149df.d4d0d8"]]},{"id":"9f6149df.d4d0d8","type":"template","z":"65bb5a5b.a49fc4","name":"Simple Web Page","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<!DOCTYPE HTML>\n\n<!-- Below is adjusted from Simple Web Page on http://flows.nodered.org/flow/8666510f94ad422e4765 -->\n\n<html>\n    <head>\n    <title>LoRa Live Data</title>\n    <script type=\"text/javascript\">\n        var ws;\n        var wsUri = \"ws:\";\n        var loc = window.location;\n        console.log(loc);\n        if (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n        // This needs to point to the web socket in the Node-RED flow\n        // ... in this case it's ws/simple\n        wsUri += \"//\" + loc.host + loc.pathname.replace(\"simple\",\"ws/simple\");\n\n        function wsConnect() {\n            console.log(\"connect\",wsUri);\n            ws = new WebSocket(wsUri);\n            //var line = \"\";    // either uncomment this for a building list of messages\n            ws.onmessage = function(msg) {\n                data = msg.data;\n                var jsonObject = JSON.parse(data);\n                if (jsonObject.type==\"LoRaData\"){\n                    var table = document.getElementById(\"webTable\");\n                    var row = table.insertRow(1);\n                    var cell1 = row.insertCell(0);\n                    var cell2 = row.insertCell(1);\n                    var cell3 = row.insertCell(2);\n                    cell1.innerHTML = \"<p>\" + jsonObject.Time + \"<p>\";\n                    cell2.innerHTML = \"<p>\" + jsonObject.DevEUI + \"<p>\";\n                    cell3.innerHTML = \"<p>\" + jsonObject.LoRaPayload + \"<p>\";\n    \n                    /* OLD SCRIPT BELOW\n                    var line = \"\";  // or uncomment this to overwrite the existing message\n                    line += \"<p>\"+data+\"</p>\";\n                    line += data;\n                    document.getElementById('messages').innerHTML = line;\n                    */ \n                } else if (jsonObject.type==\"ServerResponse\") {\n                    document.getElementById('responsestatus').innerHTML = \"\" + jsonObject.ServerResponse;\n                } else if (jsonObject.type==\"DownlinkURL\") {\n                    document.getElementById('urlstatus').innerHTML = \"\" + jsonObject.DownlinkURL;\n                }\n            }\n            ws.onopen = function() {\n                // update the status div with the connection status\n                document.getElementById('status').innerHTML = \"connected\";\n                //ws.send(\"Open for data\");\n                console.log(\"connected\");\n            }\n            ws.onclose = function() {\n                // update the status div with the connection status\n                document.getElementById('status').innerHTML = \"not connected\";\n                // in case of lost connection tries to reconnect every 3 secs\n                setTimeout(wsConnect,3000);\n            }\n        }\n        function isHex(h) {\n            var a = parseInt(h,16);\n            return (a.toString(16) ===h.toLowerCase());\n        }\n        \n        function doit() {\n            if (ws) { \n                var m = document.getElementById(\"downlinkdata\").value;\n                var se = document.getElementById('downlinkstatus');\n                if (isHex(m)) {\n                    ws.send(m);\n                    se.innerHTML = \"Sent '\"+ m +\"'\";\n                } else {\n                    se.innerHTML = \"Error: Downlink should be hexadecimal!\";\n                    document.getElementById('responsestatus').innerHTML = \"N/A\";\n                    document.getElementById('urlstatus').innerHTML = \"N/A\";\n                }\n            }\n        }\n    </script>\n\n    <style>\n        table {\n            font-family: arial, sans-serif;\n            border-collapse: collapse;\n            width: 100%;\n        }\n        \n        td, th {\n            border: 1px solid #dddddd;\n            text-align: left;\n            padding: 2px;\n        }\n        \n        tr:nth-child(even) {\n            background-color: #dddddd;\n        }\n    </style>\n    </head>\n    <body onload=\"wsConnect();\" onunload=\"ws.disconnect();\">\n    \n    <h1>Basic LoRa Live Display</h1>\n    <p>Below data from your Node-Red is displayed. Refresh page to reset table.</p>\n    <table id=\"webTable\">\n      <tr>\n        <th>Time</th>\n        <th>DevEUI</th>\n        <th>LoRaPayload</th>\n      </tr>\n    </table>\n    <br>\n    <p>Respond to your LoRa device with a hexadecimal downlink</p>\n    <input type=\"text\" id=\"downlinkdata\" value=\"\">\n    <button type=\"button\" onclick='doit();'>Send Downlink</button>\n    <hr/>\n    <b>Status of page</b> : <div id=\"status\">unknown</div>\n    <b>Sending payload</b> : <div id=\"downlinkstatus\">N/A</div>\n    <b>Downlink URL</b> : <div id=\"urlstatus\">N/A</div>\n    <b>Server Response</b> : <div id=\"responsestatus\">N/A</div>\n    </body>\n</html>\n","x":466.3401794433594,"y":407.8890380859375,"wires":[["8fce672d.a17fe8"]]},{"id":"c4e87a33.a564f8","type":"http response","z":"65bb5a5b.a49fc4","name":"LoRa Post Catcher","x":1112.8958435058594,"y":225,"wires":[]},{"id":"5671845e.7e62dc","type":"function","z":"65bb5a5b.a49fc4","name":"Parse Catch Input","func":"// Check if the body has a DevEUI_uplink parameter (Thingpark) or uses a simple format (KPN LoRa Developer Portal)\nif (msg.payload.hasOwnProperty(\"DevEUI_uplink\")) {\n    body = msg.payload.DevEUI_uplink;\n} // Check if the body has the right parameters for Developer Portal\nelse if (msg.payload.hasOwnProperty(\"payload_hex\")){\n    // Developer portal has a simpler json format without DevEUI_uplink\n    body = msg.payload;\n}else{\n    node.error(\"Not a valid Thingpark or Developer Portal message\", msg);\n    return;   \n}\n\n// Check if the query paramaters are there before continuing\nvar RequiredKeys = [\"LrnDevEui\",\"LrnFPort\",\"LrnInfos\",\"AS_ID\",\"Time\",\"Token\"];\nfor(var i=0; i < RequiredKeys.length; i++) {\n    key = RequiredKeys[i];\n    if (!msg.req.query.hasOwnProperty(key)){\n        node.error(\"Missing Query Parameter '\" + key + \"'\", msg);\n        return;\n    }\n}\n\n// Check if the body has the right parameters\nRequiredBodyElements = [\"CustomerID\",\"DevEUI\",\"FPort\",\"FCntUp\",\"payload_hex\"];\nfor(var i=0; i < RequiredBodyElements.length; i++) {\n    key = RequiredBodyElements[i];\n    if (!body.hasOwnProperty(key)){\n        node.error(\"Missing DevEUI_uplink Element  '\" + key + \"'\", msg);\n        return;\n    }\n}\n\nmsg.lorapayload = body.payload_hex;\nmsg.body = body;\n\n//Enter your LRC-AS key below\nvar LRC_AS_key = \"xxxxxx\";\n\n//Read body msg.payload for SHA\nmsg.body_parameters = body.CustomerID + body.DevEUI + body.FPort + body.FCntUp + body.payload_hex;\n\n//Read query parameters with msg.req.query\nmsg.query_sha = msg.req.query;\n\n//Store Token to compare\nmsg.PostToken = msg.req.query.Token;\n\n//Node-Red does not get the + in the ThingPark timestamp correctly and needs to be added\nmsg.query_sha.Time = msg.query_sha.Time.replace(\" \", \"+\"); \n\n// Create a string of query parameters without Token\nvar query_str = \"\";\nfor(var k in msg.query_sha) {\n    if (k != \"Token\"){\n        query_str += k + \"=\" + msg.query_sha[k] + \"&\";\n    }\n}\nmsg.query_str = query_str.slice(0,-1); // Delete last '&' sign in the string\n\nmsg.SHA_string_no_key = msg.body_parameters + msg.query_str; // Save a SHA string withouth a key\nmsg.SHA_string = msg.SHA_string_no_key + LRC_AS_key;  // Save a SHA string, including the key\n\nreturn msg;","outputs":1,"noerr":0,"x":412.8957824707031,"y":308,"wires":[["de9d1630.c91118"]]},{"id":"1954c90d.e316a7","type":"catch","z":"65bb5a5b.a49fc4","name":"","scope":null,"x":452.1632080078125,"y":225.2916717529297,"wires":[["ef742052.e5f7a"]]},{"id":"ef742052.e5f7a","type":"function","z":"65bb5a5b.a49fc4","name":"Handle Error","func":"// Add a topic property to our message to let other nodes know\n// that this message is an error.\nmsg.topic = \"error\";\n\n// The payload of this error message should say something \n// about the error. This payload is going to be passed back\n// to our HTTPS Response node. Note that the msg.error.message\n// is the message we gave as input in the node.error()\nmsg.payload = \"Encoutered Error: \"+ msg.error.message;\n\nreturn msg;","outputs":1,"noerr":0,"x":625.4514465332031,"y":225,"wires":[["a05a01db.44e9b"]]},{"id":"a05a01db.44e9b","type":"function","z":"65bb5a5b.a49fc4","name":"Create Post Resp","func":"if (msg.topic === \"error\"){\n    // In case of an error, do nothing with the message and\n    // pass it on to the reponse node. The msg.payload\n    // already contains the right information\n    return msg;\n}else{\n    // We know we have received a valid message\n    // Let's just pass back the lora data we have received\n    msg.payload = \"Received payload: \" + msg.lorapayload;\n}\nreturn msg;","outputs":1,"noerr":0,"x":866.4514465332031,"y":225,"wires":[["c4e87a33.a564f8"]]},{"id":"de9d1630.c91118","type":"function","z":"65bb5a5b.a49fc4","name":"SHA256 Check","func":"/**\n * [js-sha256]{@link https://github.com/emn178/js-sha256}\n *\n * @version 0.3.1\n * @author Chen, Yi-Cyuan [emn178@gmail.com]\n * @copyright Chen, Yi-Cyuan 2014-2016\n * @license MIT\n */\n(function (root) {\n  'use strict';\n \n  var NODE_JS = typeof process == 'object' && process.versions && process.versions.node;\n  if (NODE_JS) {\n    root = global;\n  }\n  var TYPED_ARRAY = typeof Uint8Array != 'undefined';\n  var HEX_CHARS = '0123456789abcdef'.split('');\n  var EXTRA = [-2147483648, 8388608, 32768, 128];\n  var SHIFT = [24, 16, 8, 0];\n  var K =[0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n          0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n          0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n          0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n          0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n          0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n          0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n          0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];\n \n  var blocks = [];\n \n  var sha224 = function (message) {\n    return sha256(message, true);\n  };\n \n  var sha256 = function (message, is224) {\n    var notString = typeof message != 'string';\n    if (notString && message.constructor == root.ArrayBuffer) {\n      message = new Uint8Array(message);\n    }\n \n    var h0, h1, h2, h3, h4, h5, h6, h7, block, code, first = true, end = false,\n        i, j, index = 0, start = 0, bytes = 0, length = message.length,\n        s0, s1, maj, t1, t2, ch, ab, da, cd, bc;\n \n    if (is224) {\n      h0 = 0xc1059ed8;\n      h1 = 0x367cd507;\n      h2 = 0x3070dd17;\n      h3 = 0xf70e5939;\n      h4 = 0xffc00b31;\n      h5 = 0x68581511;\n      h6 = 0x64f98fa7;\n      h7 = 0xbefa4fa4;\n    } else { // 256\n      h0 = 0x6a09e667;\n      h1 = 0xbb67ae85;\n      h2 = 0x3c6ef372;\n      h3 = 0xa54ff53a;\n      h4 = 0x510e527f;\n      h5 = 0x9b05688c;\n      h6 = 0x1f83d9ab;\n      h7 = 0x5be0cd19;\n    }\n    block = 0;\n    do {\n      blocks[0] = block;\n      blocks[16] = blocks[1] = blocks[2] = blocks[3] =\n      blocks[4] = blocks[5] = blocks[6] = blocks[7] =\n      blocks[8] = blocks[9] = blocks[10] = blocks[11] =\n      blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n      if (notString) {\n        for (i = start;index < length && i < 64;++index) {\n          blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];\n        }\n      } else {\n        for (i = start;index < length && i < 64;++index) {\n          code = message.charCodeAt(index);\n          if (code < 0x80) {\n            blocks[i >> 2] |= code << SHIFT[i++ & 3];\n          } else if (code < 0x800) {\n            blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n          } else if (code < 0xd800 || code >= 0xe000) {\n            blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n          } else {\n            code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));\n            blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];\n            blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];\n          }\n        }\n      }\n      bytes += i - start;\n      start = i - 64;\n      if (index == length) {\n        blocks[i >> 2] |= EXTRA[i & 3];\n        ++index;\n      }\n      block = blocks[16];\n      if (index > length && i < 56) {\n        blocks[15] = bytes << 3;\n        end = true;\n      }\n \n      var a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7;\n      for (j = 16;j < 64;++j) {\n        // rightrotate\n        t1 = blocks[j - 15];\n        s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3);\n        t1 = blocks[j - 2];\n        s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10);\n        blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0;\n      }\n \n      bc = b & c;\n      for (j = 0;j < 64;j += 4) {\n        if (first) {\n          if (is224) {\n            ab = 300032;\n            t1 = blocks[0] - 1413257819;\n            h = t1 - 150054599 << 0;\n            d = t1 + 24177077 << 0;\n          } else {\n            ab = 704751109;\n            t1 = blocks[0] - 210244248;\n            h = t1 - 1521486534 << 0;\n            d = t1 + 143694565 << 0;\n          }\n          first = false;\n        } else {\n          s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));\n          s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));\n          ab = a & b;\n          maj = ab ^ (a & c) ^ bc;\n          ch = (e & f) ^ (~e & g);\n          t1 = h + s1 + ch + K[j] + blocks[j];\n          t2 = s0 + maj;\n          h = d + t1 << 0;\n          d = t1 + t2 << 0;\n        }\n        s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10));\n        s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7));\n        da = d & a;\n        maj = da ^ (d & b) ^ ab;\n        ch = (h & e) ^ (~h & f);\n        t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];\n        t2 = s0 + maj;\n        g = c + t1 << 0;\n        c = t1 + t2 << 0;\n        s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10));\n        s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7));\n        cd = c & d;\n        maj = cd ^ (c & a) ^ da;\n        ch = (g & h) ^ (~g & e);\n        t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];\n        t2 = s0 + maj;\n        f = b + t1 << 0;\n        b = t1 + t2 << 0;\n        s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10));\n        s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7));\n        bc = b & c;\n        maj = bc ^ (b & d) ^ cd;\n        ch = (f & g) ^ (~f & h);\n        t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];\n        t2 = s0 + maj;\n        e = a + t1 << 0;\n        a = t1 + t2 << 0;\n      }\n \n      h0 = h0 + a << 0;\n      h1 = h1 + b << 0;\n      h2 = h2 + c << 0;\n      h3 = h3 + d << 0;\n      h4 = h4 + e << 0;\n      h5 = h5 + f << 0;\n      h6 = h6 + g << 0;\n      h7 = h7 + h << 0;\n    } while (!end);\n \n    var hex = HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +\n              HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +\n              HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +\n              HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +\n              HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +\n              HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +\n              HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +\n              HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +\n              HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +\n              HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +\n              HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +\n              HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +\n              HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] +\n              HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +\n              HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +\n              HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +\n              HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] +\n              HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] +\n              HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] +\n              HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F] +\n              HEX_CHARS[(h5 >> 28) & 0x0F] + HEX_CHARS[(h5 >> 24) & 0x0F] +\n              HEX_CHARS[(h5 >> 20) & 0x0F] + HEX_CHARS[(h5 >> 16) & 0x0F] +\n              HEX_CHARS[(h5 >> 12) & 0x0F] + HEX_CHARS[(h5 >> 8) & 0x0F] +\n              HEX_CHARS[(h5 >> 4) & 0x0F] + HEX_CHARS[h5 & 0x0F] +\n              HEX_CHARS[(h6 >> 28) & 0x0F] + HEX_CHARS[(h6 >> 24) & 0x0F] +\n              HEX_CHARS[(h6 >> 20) & 0x0F] + HEX_CHARS[(h6 >> 16) & 0x0F] +\n              HEX_CHARS[(h6 >> 12) & 0x0F] + HEX_CHARS[(h6 >> 8) & 0x0F] +\n              HEX_CHARS[(h6 >> 4) & 0x0F] + HEX_CHARS[h6 & 0x0F];\n    if (!is224) {\n      hex += HEX_CHARS[(h7 >> 28) & 0x0F] + HEX_CHARS[(h7 >> 24) & 0x0F] +\n             HEX_CHARS[(h7 >> 20) & 0x0F] + HEX_CHARS[(h7 >> 16) & 0x0F] +\n             HEX_CHARS[(h7 >> 12) & 0x0F] + HEX_CHARS[(h7 >> 8) & 0x0F] +\n             HEX_CHARS[(h7 >> 4) & 0x0F] + HEX_CHARS[h7 & 0x0F];\n    }\n    return hex;\n  };\n   \n  if (!root.JS_SHA256_TEST && NODE_JS) {\n    sha256.sha256 = sha256;\n    sha256.sha224 = sha224;\n    module.exports = sha256;\n  } else if (root) {\n    root.sha256 = sha256;\n    root.sha224 = sha224;\n  }\n}(this));\n\n// The code above is a sha256() function\n// Below we do the actual check\nvar Token = sha256(msg.SHA_string);\nif (Token != msg.PostToken) {\n    // Pass an error with the SHA string (no key!!) back for debugging\n    node.error(\"Token did not match on \" + msg.SHA_string_no_key, msg);\n    return;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":630.1632385253906,"y":307.7708435058594,"wires":[["a05a01db.44e9b","e1e7c940.035178"]]},{"id":"e1e7c940.035178","type":"function","z":"65bb5a5b.a49fc4","name":"Format Data","func":"NewMsg = {\n    \"payload\" : {\n        \"DevEUI\" : msg.body.DevEUI,\n        \"LoRaPayload\" : msg.lorapayload,\n        \"Time\" : msg.body.Time,\n        \"ServerTime\" : Date.now(),\n        \"type\" : \"LoRaData\"\n    }\n};\n\nreturn NewMsg;","outputs":1,"noerr":0,"x":862.4514465332031,"y":308,"wires":[["155da7dd.385048"]]},{"id":"bb03950d.4ce068","type":"debug","z":"65bb5a5b.a49fc4","name":"","active":true,"console":"false","complete":"false","x":457.1667175292969,"y":493.88201904296875,"wires":[]},{"id":"520d238c.34fbec","type":"websocket-listener","z":"65bb5a5b.a49fc4","path":"/ws/simple","wholemsg":"false"}]