├── .gitmodules ├── ble-uart.js ├── debian64bit-bin ├── libOpenCL.so └── libccurl.so ├── example.js ├── index.js ├── iota-mam ├── iota-mam.js └── mam.js ├── package-lock.json ├── raspberrypi-bin └── libccurl.so ├── readme.md └── test.js /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ruuvi.endpoints.js"] 2 | path = ruuvi.endpoints.js 3 | url = https://github.com/ruuvi/ruuvi.endpoints.js.git 4 | [submodule "iota.lib.js"] 5 | path = iota.lib.js 6 | url = https://github.com/iotaledger/iota.lib.js.git 7 | -------------------------------------------------------------------------------- /ble-uart.js: -------------------------------------------------------------------------------- 1 | /* 2 | Noble UART service example 3 | This example uses Sandeep Mistry's noble library for node.js to 4 | read and write from Bluetooth LE characteristics. It looks for a UART 5 | characteristic based on a proprietary UART service by Nordic Semiconductor. 6 | You can see this service implemented in Adafruit's BLEFriend library. 7 | created 30 Nov 2015 8 | by Tom Igoe 9 | modified 1 Dec 2015 10 | by Don Coleman 11 | */ 12 | 13 | var noble = require('noble'); //noble library 14 | var util = require('util'); // utilities library 15 | 16 | // make an instance of the eventEmitter library: 17 | var EventEmitter = require('events').EventEmitter; 18 | 19 | // uuids are easier to read with dashes 20 | // this helper removes dashes so comparisons work 21 | var uuid = function(uuid_with_dashes) { 22 | return uuid_with_dashes.replace(/-/g, ''); 23 | }; 24 | 25 | // TX and RX are from Noble's perspective 26 | var knownUartServices = { 27 | nordic: { 28 | serviceUUID: '6e400001-b5a3-f393-e0a9-e50e24dcca9e', 29 | txUUID: '6e400002-b5a3-f393-e0a9-e50e24dcca9e', 30 | rxUUID: '6e400003-b5a3-f393-e0a9-e50e24dcca9e' 31 | }, 32 | redbear: { 33 | serviceUUID: '713d0000-503e-4c75-ba94-3148f18d941e', 34 | txUUID: '713d0003-503e-4c75-ba94-3148f18d941e', 35 | rxUUID: '713d0002-503e-4c75-ba94-3148f18d941e' 36 | }, 37 | laird: { 38 | serviceUUID: '569a1101-b87f-490c-92cb-11ba5ea5167c', 39 | txUUID: '569a2001-b87f-490c-92cb-11ba5ea5167c', 40 | rxUUID: '569a2000-b87f-490c-92cb-11ba5ea5167c' 41 | }, 42 | bluegiga: { 43 | serviceUUID: '1d5688de-866d-3aa4-ec46-a1bddb37ecf6', 44 | txUUID: 'af20fbac-2518-4998-9af7-af42540731b3', 45 | rxUUID: 'af20fbac-2518-4998-9af7-af42540731b3' 46 | } 47 | }; 48 | 49 | var checkService = function(name, uart) { 50 | var error = false; 51 | 52 | if (!name) { 53 | name = "UART Service"; 54 | } 55 | 56 | if (Object.keys(uart).length === 0) { 57 | // Maybe the user typo'd the service name? 58 | console.log("Expecting service name to be one of: " + Object.keys(knownUartServices).join(", ") + "."); 59 | console.log("Or pass serviceUUID, txUUID, & rxUUID in object literal as second argument."); 60 | error = true; 61 | } else { 62 | if (!uart.serviceUUID) { 63 | console.log("ERROR: Expecting serviceUUID for " + name); 64 | error = true; 65 | } 66 | if (!uart.txUUID) { 67 | console.log("ERROR: Expecting txUUID for " + name); 68 | error = true; 69 | } 70 | if (!uart.rxUUID) { 71 | console.log("ERROR: Expecting rxUUID for " + name); 72 | error = true; 73 | } 74 | } 75 | 76 | // TODO handle this better... 77 | if (error) { 78 | console.log(name + " " + JSON.stringify(uart)); 79 | process.exit(-1); 80 | } 81 | }; 82 | 83 | // constructor function, so you can call new BleUart(): 84 | var BleUart = function (name, options) { 85 | 86 | // get known service or empty object 87 | var uart = knownUartServices[name] || {}; 88 | // apply user over rides 89 | Object.assign(uart, options); 90 | 91 | checkService(name, uart); 92 | 93 | var serviceUUID = uuid(uart.serviceUUID); // the service you want 94 | var transmitUUID = uuid(uart.txUUID); // TX from noble's perspective 95 | var receiveUUID = uuid(uart.rxUUID); // RX from noble's perspective 96 | var receive, transmit; // transmit and receive BLE characteristics 97 | var writeWithoutResponse; // flag for write characteristic (based on Bluefruit version) 98 | var self = this; // reference to the instance of BleUart 99 | self.connected = false; // whether the remote peripheral's connected 100 | self.peripheral = null; // the remote peripheral as an object 101 | EventEmitter.call(self); // make a copy of EventEmitter so you can emit events 102 | self.setMaxListeners(20); 103 | 104 | // The scanning function: 105 | self.scan = function(state) { 106 | if (state === 'poweredOn') { // if the radio's on, scan for this service 107 | noble.startScanning([serviceUUID], false); 108 | } 109 | // emit a 'scanning' event: 110 | self.emit('scanning', state); 111 | } 112 | 113 | // the connect function: 114 | self.connect = function(peripheral) { 115 | self.peripheral = peripheral; 116 | peripheral.connect(); // start connection attempts 117 | 118 | // the connect function. This is local to the discovery function 119 | // because it needs to know the peripheral to discover services: 120 | function discover() { 121 | console.log("Discovering"); 122 | // once you know you have a peripheral with the desired 123 | // service, you can stop scanning for others: 124 | // get the service you want on this peripheral: 125 | peripheral.discoverServices(null,explore); 126 | } 127 | 128 | // called only when the peripheral has the service you're looking for: 129 | peripheral.on('connect', discover); 130 | // when a peripheral disconnects, run disconnect: 131 | peripheral.on('disconnect', self.disconnect); 132 | }; 133 | 134 | // the services and characteristics exploration function: 135 | // once you're connected, this gets run: 136 | function explore(error, services) { 137 | // this gets run by the for-loop at the end of the 138 | // explore function, below: 139 | console.log("Exploring"); 140 | function getCharacteristics(error, characteristics) { 141 | console.log("Reading characteristics"); 142 | 143 | characteristics.forEach(function(characteristic) { 144 | console.log(characteristic.toString()); 145 | if (characteristic.uuid === receiveUUID) { 146 | receive = characteristic; 147 | 148 | if (characteristic.properties.indexOf("notify") < 0) { 149 | console.log("ERROR: expecting " + characteristic.uuid + " to have 'notify' property."); 150 | } 151 | receive.notify(true); // turn on notifications 152 | 153 | receive.on('read', function(data, notification) { 154 | if (notification) { // if you got a notification 155 | self.emit('data', data); // emit a data event 156 | } 157 | }); 158 | } 159 | 160 | // separate *if* since some hardware uses the same characteristic for tx and rx 161 | if (characteristic.uuid === transmitUUID) { 162 | transmit = characteristic; 163 | // Older Adafruit hardware is writeWithoutResponse 164 | if (characteristic.properties.indexOf("writeWithoutResponse") > -1) { 165 | writeWithoutResponse = true; 166 | } else { 167 | writeWithoutResponse = false; 168 | } 169 | } 170 | }); 171 | 172 | // if you've got a valid transmit and receive characteristic, 173 | // then you're truly connected. Emit a connected event: 174 | if (transmit && receive) { 175 | self.connected = true; 176 | self.emit('connected', self.connected); 177 | } 178 | } // end of getCharacteristics() 179 | 180 | // iterate over the services discovered. If one matches 181 | // the UART service, look for its characteristics: 182 | for (var s in services) { 183 | console.log("Service found " + services[s].uuid + " comparing to " + serviceUUID + ": " + (services[s].uuid === serviceUUID)); 184 | if (services[s].uuid === serviceUUID) { 185 | console.log("Match " + services[s]); 186 | self.emit('preparing'); 187 | services[s].discoverCharacteristics(null, getCharacteristics); 188 | return; 189 | } 190 | } 191 | } 192 | 193 | // the BLE write function. If there's a valid transmit characteristic, 194 | /// then write data out to it as a Buffer: 195 | self.write = function(data) { 196 | if (transmit) { 197 | // you can only send at most 20 bytes in a Bluetooth LE pacet. 198 | // so slice the data into 20-byte chunks: 199 | while (data.length > 20) { 200 | var output = data.slice(0, 19); 201 | transmit.write(new Buffer(output), writeWithoutResponse); 202 | data = data.slice(20); 203 | } 204 | // send any remainder bytes less than the last 20: 205 | transmit.write(new Buffer(data), writeWithoutResponse); 206 | } 207 | }; 208 | 209 | // the BLE disconnect function: 210 | self.disconnect = function() { 211 | self.connected = false; 212 | self.discovering = false; 213 | }; 214 | 215 | // when the radio turns on, start scanning: 216 | noble.on('stateChange', self.scan); 217 | // if you discover a peripheral with the appropriate service, connect: 218 | noble.on('discover', self.connect); 219 | }; 220 | 221 | util.inherits(BleUart, EventEmitter); // BleUart inherits all the EventEmitter properties 222 | module.exports = BleUart; // export BleUart 223 | 224 | -------------------------------------------------------------------------------- /debian64bit-bin/libOpenCL.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ojousima/ruuvi-nodejs/9c4fb510f86b236e7fe8badc6bb0d37990c0f32c/debian64bit-bin/libOpenCL.so -------------------------------------------------------------------------------- /debian64bit-bin/libccurl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ojousima/ruuvi-nodejs/9c4fb510f86b236e7fe8badc6bb0d37990c0f32c/debian64bit-bin/libccurl.so -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | const util = require('util'); 2 | const setImmediatePromise = util.promisify(setImmediate); 3 | var BleUart = require('./ble-uart'); 4 | var dataHandler = require('./ruuvi.endpoints.js/index.js') 5 | var tryteConverter = require('./iota.lib.js/lib/utils/asciiToTrytes.js') 6 | var MAM = require('./iota-mam/mam') 7 | var sleep = require('sleep'); 8 | var stdin = process.openStdin(); 9 | var singleShotTemperature = new Uint8Array([0x31,0x10,0x01,251,251,252,252,1,0,2,0]); 10 | var continuousTemperature = new Uint8Array([0x31,0x10,0x01,1,251,252,252,1,0,2,0]); 11 | var queryTemperature = new Uint8Array([0x31,0x10,0x05,0,0,0,0,0,0,0,0]); 12 | var queryMAM = new Uint8Array([0xE0,0x10,0x05,0,0,0,0,0,0,0,0]); //XXX PoC for hackathon, only destination matters 13 | 14 | const IOTA = require('iota.lib.js'); 15 | const CCurl = require('ccurl.interface.js'); 16 | const { 17 | promisify 18 | } = require('util'); 19 | 20 | // not really used as we don't do any TX with value changes. 21 | const MWM = 15; 22 | let seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUVWXYZ9'; 23 | let targetAddress = '99999999999999999999999999999999999999999999999999999999999999999RUUVI9LOVES9IOTA'; 24 | let targetTag = 'ALL9THE9TAGGING9YOULL9NEED9'; 25 | let message = 'HSVKSZBJFAI9OUUXZSAYVPHENMYSMDOTXSVUISVGWN9DVUBYTNXCFQK9AAAWHFIBHLPRHXIXPX9HUCRUCILCKVZGYBOJEHGJFA9YFGIHNS99ILCOOKWV9FVLGVKCMPVPDZFXTKOBGVKXVTDLOVYCEYTTGRXVWBVFKFXHWQGQSQNESOEAMSSVBCOQVCWKEHHONFQKIBEHXYBNYIYBBXFZNBLGVHXPJTPSRB9FSVGBNVHADGGLKLIIARULVV9ALN99QTS9JUGTTFCNCXEGUZIUFWMXGYVK9YDKFVXMHDRNHRINXKKCIELUAGIDFUIANFNMSZQJGDYDZDQDURRLXHLYCDLFBRZYTQDJZUVAWXKWHGJHDUHETGNDSP9ABBIU9PAGZMLJKNCXTCZSQJXRBCEJ9PQPFLYKLUMEUGNOOTUFLABBBAPEWTWKTAMLMARRLSYRCWSYZRITTRLLLBP9XTRCFMJYYIZSZEVSXTVBFLAOENMPPKWZOUEBIORBVIWXVCTNKRYJMAXTKKMUR9IJDWEVHUBUJMQZIMAFSGZAIGHWHMOOLLINHNVJSIAEDUAO9ZZRABQ9AFRMEE9GLXHSMZIVZIZSSPHTYDKBFAMCWOPOEMFBJOJBPOVQCMUFPXHKQKQXPJKDTK9SK9LNGWYHCEZTBZWQDRCS9XKYHNXWSPHLEQSP9EODYIVQUJROCJWCPVDYJLZUGENRCUGKCLKALLQNGEVCGGNYZKHSZXADXABVRKJBGLHE9KRBSHODGRWQEGJZDL9OTITSAOUJSOGQYJRNIBCYWVZQTPAKULCGTYYHFPNHANGUR9IFY9SOKLMFWYZFEWZOEUXSU9JLXNWZ9ZPOGBQVWRBUQZVOAADABGWYLGSVIKEJBVARTCOUDOBFBFHSY9WNRYBHLGCAQKNZQNDYQMKOGECWIUVWIZ9ON9VFCLMODZELBZQGHLHWZRMDZXROMRWVAXUKCKVFU9AVTLKROICXLDBSPLCJGMXXTXTWLNIBQEQXWTNLABO9EWESSKZCAEQONSABZOCQJOYANPRVXBVYYUUNWAEHGRITYVZPDEMPQKRIRBQMHYHWXQXTXIUFPRJJRIORNUPFIIKVM9QOQVTLGXIRATSYXELMUAJNLLPMPCVSGJEEONRROUWWBBXC9XIHCOOMHYJHPYVXBRKAWB9KNZDUS9HEFLFSSWPPMFKROKJTXVFFLYJZRSJLCHYCDPEPNHDP9TBZGOPRKDLTNZRALWLIWKH9MSRVIFWLTDMNICQRW9HIQPQBG9WZZLCDOZYIDUSEIPEUGJ9ARCVNQZFVQRRUVPMQYQELADHDQFMBTRXDARMGHOQIJMGKJKGNMZAIGCTIP9VWLVOQVZHWDCOXOWLJHWKMELANENMMLYKL9Y9CI9QAOHHJSZBLAAIOPGQVPXLH9AZUUIWSMMNORKBNDSJVBCQLNMQN9E9QKAWIQUCFTVUEJKQKYDFXJZXGKQJXFD9XZUZZDSNVGJBYXCSWHDDDFIEHUXW9F9XQMOV9TVAPYHPLRNOBNWSIPJ9OLFZTAQEHXVAOYOVPBHYTMRNKVHDFZPAFRJEBZUXDPKSKJCBKLRYEWQUJSDJWEX9UJRRFHKE9AHBBNTTFIIIBHRFJVOMOEGB9VWZED9WADAPKFEAFVV99CAHRXD9RXRJDAULFRTKJLLTB9KRLCOM99BTBKDXMXRJOZSYXLSXDQQDEZ9NPCBJDVHARHHJCPGZTMJAV9PJSAEX9YILZBKUVAVNGFRWETNNFMRJYFXSOAOT9KDXTHAWABGZLWYLZVGABLSWUQGLAVWOFUAVQNAGLQWLGXCUSYXTWWCFWDHERSNXGFHKOEXWMBXBYASSBZGNVBOOPAWYBLDQMBXVBVARTDQPYCZLKWIVVJFLVINRDIIKLGEDWSLMOVLSYGDWZIAYRUPKJATMWBTJUADLJUJXI9XVXF9VXWGIIMEIESHZSCGUNAZBJFUXYJQ9KMBZVGJCOWOXGMTA9V9HI9FXILRKYQIFIGAGGCMYAQU9WKIHSOKKRFMWQZBGHHX9UARCSZJGLNGNMRNVBYMGXVRCSLRKMBWIWJVVWAHKAFQPJWOOMKQDOIKONZXKPZ9FXPNZUVT9ZVIQCBRECOQRZJPPYWQAPEWNVMSS9BPPOXCSOZFGP9NNRLQWEJWBKRXRDJAUGUCLZIVYYIPEH9YHR9VGNLFLTJQVYWXHVFKFFPANVMMKNUNUUFDLAVPQNNSGFGKID9CUQVMWWPBAWN9SPSTFDGUSYSCWTNCMNVPPJFITVKTAIQNHWPOKXCTJGTMPPFFBUIQIHPSOYPPZXLUKKCSGFQLRJLR9GOZIALKBIJOLTKDOTBHUSGMYM9WRPBUK9GIIJKWNTJLPDAXZYCKGLCRLRSVHTYYJNHOQEUVRFDRNJISJEEPAJANACSFPDOHGVNCSSGXAAHS9CYDYQBZOQZCFDOHBFDEVGAIF'; 26 | 27 | // sample MAM payload. 28 | 29 | // construct iota.lib.js instance 30 | let iota = new IOTA({ 31 | 'host': 'http://service.iotasupport.com', 32 | 'port': 14265 33 | }); 34 | 35 | const PCCurl = promisify(CCurl); 36 | const PprepareTransfers = promisify(iota.api.prepareTransfers); 37 | const PgetTransactionsToApprove = async depth => { 38 | return new Promise((resolve, reject) => { 39 | iota.api.getTransactionsToApprove(depth, function(err, suc) { 40 | if (err != undefined) { 41 | reject(err); 42 | } else { 43 | resolve(suc); 44 | } 45 | }); 46 | }); 47 | }; 48 | 49 | const PbroadcastTransactions = async trytes => { 50 | return new Promise((resolve, reject) => { 51 | iota.api.broadcastTransactions(trytes, function(err, suc) { 52 | if (err != undefined) { 53 | reject(err); 54 | } else { 55 | resolve(suc); 56 | } 57 | }); 58 | }); 59 | }; 60 | 61 | 62 | https://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers 63 | function ab2str(buf) { 64 | return String.fromCharCode.apply(null, new Uint8Array(buf)); 65 | } 66 | 67 | 68 | 69 | // use a predefined UART service (nordic, redbear, laird, bluegiga) 70 | var bleSerial = new BleUart('nordic'); 71 | var reconnTimer = null; 72 | function reConn() { 73 | console.log("Connection failed. Retrying"); 74 | bleSerial.peripheral.disconnect(); 75 | bleSerial.scan('poweredOn'); 76 | } 77 | 78 | 79 | 80 | // optionally define a custom service 81 | // var uart = { 82 | // serviceUUID: '6e400001-b5a3-f393-e0a9-e50e24dcca9e', 83 | // txUUID: '6e400002-b5a3-f393-e0a9-e50e24dcca9e', 84 | // rxUUID: '6e400003-b5a3-f393-e0a9-e50e24dcca9e' 85 | // } 86 | // var bleSerial = new BleUart('foo', uart); 87 | 88 | // this function gets called when new data is received from 89 | // the Bluetooth LE serial service: 90 | bleSerial.on('data', function(data){ 91 | //console.log("Got new data: " + data); 92 | let message = dataHandler(data); 93 | if (message.ready){ 94 | let res = (ab2str(message.binary)).split('\n'); 95 | console.log(res[0]); 96 | console.log(res[1]); 97 | //if(message.type === "MAM") 98 | //{ 99 | let trytes = MAM.mam_parse(res[0], res[1], 1).split('\n'); 100 | //} 101 | console.log(trytes); 102 | let ascii = tryteConverter.fromTrytes(trytes[0]); 103 | console.log(ascii); 104 | 105 | PprepareTransfers(seed, [{ 106 | address: targetAddress, 107 | value: 0, 108 | message: res[0], 109 | tag: targetTag 110 | }]).then(transactions => { 111 | return PgetTransactionsToApprove(5).then(toApprove => { 112 | return PCCurl(toApprove.trunkTransaction, toApprove.branchTransaction, MWM, transactions); 113 | }); 114 | }).then(bundle => PbroadcastTransactions(bundle)) 115 | .then(ret => console.log(ret)); 116 | 117 | } 118 | }); 119 | 120 | // this function gets called when the program 121 | // establishes a connection with the remote BLE radio: 122 | bleSerial.on('connected', function(data){ 123 | console.log("Connected to BLE. Sending a hello message"); 124 | clearTimeout(reconnTimer); 125 | reconnTimer = null; 126 | timerExample(); 127 | //bleSerial.write("Hello BLE!"); 128 | //bleSerial.write([1,2,3,4,5]); 129 | 130 | 131 | //bleSerial.write(new Buffer([6,7,8,9])) 132 | }); 133 | 134 | bleSerial.on('preparing', function(){ 135 | if(reconnTimer == null){ 136 | console.log("setting up retry timer"); 137 | reconnTimer = setTimeout(reConn, 5000); 138 | } 139 | }); 140 | 141 | 142 | // thus function gets called if the radio successfully starts scanning: 143 | bleSerial.on('scanning', function(status){ 144 | console.log("radio status: " + status); 145 | }) 146 | 147 | async function timerExample() { 148 | //console.log('Before I/O callbacks'); 149 | await setImmediatePromise(); 150 | console.log('Connection ready.'); 151 | console.log('1) singleshot 2) continous 3) query. 4) Get MAM data'); 152 | //bleSerial.write(new Uint8Array([0x31,0x10,0x01,251,251,252,252,1,0,2,0])); 153 | //sleep.sleep(5); 154 | //bleSerial.write(new Uint8Array([0x31,0x10,0x05,0,0,0,0,0,0,0,0])); 155 | } 156 | 157 | stdin.on('data', function(chunk) { 158 | if(chunk == '1\n') 159 | { 160 | console.log("Single shot"); 161 | bleSerial.write(singleShotTemperature); 162 | } 163 | if(chunk == '2\n') 164 | { 165 | console.log("Continous measurement"); 166 | bleSerial.write(continuousTemperature); 167 | } 168 | if(chunk == '3\n') 169 | { 170 | console.log("Query data"); 171 | bleSerial.write(queryTemperature); 172 | } 173 | if(chunk == '4\n') 174 | { 175 | console.log("Asking for MAM"); 176 | bleSerial.write(queryMAM); 177 | } 178 | } 179 | ); 180 | 181 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const IOTA = require('iota.lib.js'); 2 | const CCurl = require('ccurl.interface.js'); 3 | const { 4 | promisify 5 | } = require('util'); 6 | 7 | // not really used as we don't do any TX with value changes. 8 | const MWM = 15; 9 | let seed = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUVWXYZ9'; 10 | let targetAddress = '99999999999999999999999999999999999999999999999999999999999999999RUUVI9LOVES9IOTA'; 11 | let targetTag = 'ALL9THE9TAGGING9YOULL9NEED9'; 12 | let message = 'HSVKSZBJFAI9OUUXZSAYVPHENMYSMDOTXSVUISVGWN9DVUBYTNXCFQK9AAAWHFIBHLPRHXIXPX9HUCRUCILCKVZGYBOJEHGJFA9YFGIHNS99ILCOOKWV9FVLGVKCMPVPDZFXTKOBGVKXVTDLOVYCEYTTGRXVWBVFKFXHWQGQSQNESOEAMSSVBCOQVCWKEHHONFQKIBEHXYBNYIYBBXFZNBLGVHXPJTPSRB9FSVGBNVHADGGLKLIIARULVV9ALN99QTS9JUGTTFCNCXEGUZIUFWMXGYVK9YDKFVXMHDRNHRINXKKCIELUAGIDFUIANFNMSZQJGDYDZDQDURRLXHLYCDLFBRZYTQDJZUVAWXKWHGJHDUHETGNDSP9ABBIU9PAGZMLJKNCXTCZSQJXRBCEJ9PQPFLYKLUMEUGNOOTUFLABBBAPEWTWKTAMLMARRLSYRCWSYZRITTRLLLBP9XTRCFMJYYIZSZEVSXTVBFLAOENMPPKWZOUEBIORBVIWXVCTNKRYJMAXTKKMUR9IJDWEVHUBUJMQZIMAFSGZAIGHWHMOOLLINHNVJSIAEDUAO9ZZRABQ9AFRMEE9GLXHSMZIVZIZSSPHTYDKBFAMCWOPOEMFBJOJBPOVQCMUFPXHKQKQXPJKDTK9SK9LNGWYHCEZTBZWQDRCS9XKYHNXWSPHLEQSP9EODYIVQUJROCJWCPVDYJLZUGENRCUGKCLKALLQNGEVCGGNYZKHSZXADXABVRKJBGLHE9KRBSHODGRWQEGJZDL9OTITSAOUJSOGQYJRNIBCYWVZQTPAKULCGTYYHFPNHANGUR9IFY9SOKLMFWYZFEWZOEUXSU9JLXNWZ9ZPOGBQVWRBUQZVOAADABGWYLGSVIKEJBVARTCOUDOBFBFHSY9WNRYBHLGCAQKNZQNDYQMKOGECWIUVWIZ9ON9VFCLMODZELBZQGHLHWZRMDZXROMRWVAXUKCKVFU9AVTLKROICXLDBSPLCJGMXXTXTWLNIBQEQXWTNLABO9EWESSKZCAEQONSABZOCQJOYANPRVXBVYYUUNWAEHGRITYVZPDEMPQKRIRBQMHYHWXQXTXIUFPRJJRIORNUPFIIKVM9QOQVTLGXIRATSYXELMUAJNLLPMPCVSGJEEONRROUWWBBXC9XIHCOOMHYJHPYVXBRKAWB9KNZDUS9HEFLFSSWPPMFKROKJTXVFFLYJZRSJLCHYCDPEPNHDP9TBZGOPRKDLTNZRALWLIWKH9MSRVIFWLTDMNICQRW9HIQPQBG9WZZLCDOZYIDUSEIPEUGJ9ARCVNQZFVQRRUVPMQYQELADHDQFMBTRXDARMGHOQIJMGKJKGNMZAIGCTIP9VWLVOQVZHWDCOXOWLJHWKMELANENMMLYKL9Y9CI9QAOHHJSZBLAAIOPGQVPXLH9AZUUIWSMMNORKBNDSJVBCQLNMQN9E9QKAWIQUCFTVUEJKQKYDFXJZXGKQJXFD9XZUZZDSNVGJBYXCSWHDDDFIEHUXW9F9XQMOV9TVAPYHPLRNOBNWSIPJ9OLFZTAQEHXVAOYOVPBHYTMRNKVHDFZPAFRJEBZUXDPKSKJCBKLRYEWQUJSDJWEX9UJRRFHKE9AHBBNTTFIIIBHRFJVOMOEGB9VWZED9WADAPKFEAFVV99CAHRXD9RXRJDAULFRTKJLLTB9KRLCOM99BTBKDXMXRJOZSYXLSXDQQDEZ9NPCBJDVHARHHJCPGZTMJAV9PJSAEX9YILZBKUVAVNGFRWETNNFMRJYFXSOAOT9KDXTHAWABGZLWYLZVGABLSWUQGLAVWOFUAVQNAGLQWLGXCUSYXTWWCFWDHERSNXGFHKOEXWMBXBYASSBZGNVBOOPAWYBLDQMBXVBVARTDQPYCZLKWIVVJFLVINRDIIKLGEDWSLMOVLSYGDWZIAYRUPKJATMWBTJUADLJUJXI9XVXF9VXWGIIMEIESHZSCGUNAZBJFUXYJQ9KMBZVGJCOWOXGMTA9V9HI9FXILRKYQIFIGAGGCMYAQU9WKIHSOKKRFMWQZBGHHX9UARCSZJGLNGNMRNVBYMGXVRCSLRKMBWIWJVVWAHKAFQPJWOOMKQDOIKONZXKPZ9FXPNZUVT9ZVIQCBRECOQRZJPPYWQAPEWNVMSS9BPPOXCSOZFGP9NNRLQWEJWBKRXRDJAUGUCLZIVYYIPEH9YHR9VGNLFLTJQVYWXHVFKFFPANVMMKNUNUUFDLAVPQNNSGFGKID9CUQVMWWPBAWN9SPSTFDGUSYSCWTNCMNVPPJFITVKTAIQNHWPOKXCTJGTMPPFFBUIQIHPSOYPPZXLUKKCSGFQLRJLR9GOZIALKBIJOLTKDOTBHUSGMYM9WRPBUK9GIIJKWNTJLPDAXZYCKGLCRLRSVHTYYJNHOQEUVRFDRNJISJEEPAJANACSFPDOHGVNCSSGXAAHS9CYDYQBZOQZCFDOHBFDEVGAIF'; 13 | 14 | // sample MAM payload. 15 | 16 | // construct iota.lib.js instance 17 | let iota = new IOTA({ 18 | 'host': 'http://service.iotasupport.com', 19 | 'port': 14265 20 | }); 21 | 22 | const PCCurl = promisify(CCurl); 23 | const PprepareTransfers = promisify(iota.api.prepareTransfers); 24 | const PgetTransactionsToApprove = async depth => { 25 | return new Promise((resolve, reject) => { 26 | iota.api.getTransactionsToApprove(depth, function(err, suc) { 27 | if (err != undefined) { 28 | reject(err); 29 | } else { 30 | resolve(suc); 31 | } 32 | }); 33 | }); 34 | }; 35 | 36 | const PbroadcastTransactions = async trytes => { 37 | return new Promise((resolve, reject) => { 38 | iota.api.broadcastTransactions(trytes, function(err, suc) { 39 | if (err != undefined) { 40 | reject(err); 41 | } else { 42 | resolve(suc); 43 | } 44 | }); 45 | }); 46 | }; 47 | 48 | PprepareTransfers(seed, [{ 49 | address: targetAddress, 50 | value: 0, 51 | message: message, 52 | tag: targetTag 53 | }]).then(transactions => { 54 | return PgetTransactionsToApprove(5).then(toApprove => { 55 | return PCCurl(toApprove.trunkTransaction, toApprove.branchTransaction, MWM, transactions); 56 | }); 57 | }).then(bundle => PbroadcastTransactions(bundle)) 58 | .then(ret => console.log(ret)); 59 | -------------------------------------------------------------------------------- /iota-mam/mam.js: -------------------------------------------------------------------------------- 1 | const MAM = require('./iota-mam'); 2 | const mam_create = MAM.cwrap('mam_create', 'string', ['string','string','number','number','number','number','number','number']); 3 | const mam_parse = MAM.cwrap('mam_parse', 'string', ['string', 'string', 'number']); 4 | 5 | module.exports = { 6 | 'mam_create': mam_create, 7 | 'mam_parse': mam_parse 8 | }; 9 | 10 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "abbrev": { 6 | "version": "1.1.1", 7 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 8 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" 9 | }, 10 | "ajv": { 11 | "version": "4.11.8", 12 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", 13 | "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", 14 | "requires": { 15 | "co": "4.6.0", 16 | "json-stable-stringify": "1.0.1" 17 | } 18 | }, 19 | "ansi-regex": { 20 | "version": "2.1.1", 21 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 22 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 23 | }, 24 | "aproba": { 25 | "version": "1.2.0", 26 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", 27 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" 28 | }, 29 | "are-we-there-yet": { 30 | "version": "1.1.4", 31 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", 32 | "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", 33 | "requires": { 34 | "delegates": "1.0.0", 35 | "readable-stream": "2.3.3" 36 | } 37 | }, 38 | "asn1": { 39 | "version": "0.2.3", 40 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", 41 | "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" 42 | }, 43 | "assert-plus": { 44 | "version": "0.2.0", 45 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", 46 | "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" 47 | }, 48 | "async": { 49 | "version": "2.6.0", 50 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", 51 | "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", 52 | "requires": { 53 | "lodash": "4.17.5" 54 | } 55 | }, 56 | "asynckit": { 57 | "version": "0.4.0", 58 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 59 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 60 | }, 61 | "aws-sign2": { 62 | "version": "0.6.0", 63 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", 64 | "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" 65 | }, 66 | "aws4": { 67 | "version": "1.6.0", 68 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", 69 | "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" 70 | }, 71 | "balanced-match": { 72 | "version": "1.0.0", 73 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 74 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 75 | }, 76 | "bcrypt-pbkdf": { 77 | "version": "1.0.1", 78 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", 79 | "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", 80 | "requires": { 81 | "tweetnacl": "0.14.5" 82 | } 83 | }, 84 | "bignumber.js": { 85 | "version": "4.1.0", 86 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", 87 | "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==" 88 | }, 89 | "bindings": { 90 | "version": "1.2.1", 91 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", 92 | "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" 93 | }, 94 | "block-stream": { 95 | "version": "0.0.9", 96 | "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", 97 | "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", 98 | "requires": { 99 | "inherits": "2.0.3" 100 | } 101 | }, 102 | "bluetooth-hci-socket": { 103 | "version": "0.5.1", 104 | "resolved": "https://registry.npmjs.org/bluetooth-hci-socket/-/bluetooth-hci-socket-0.5.1.tgz", 105 | "integrity": "sha1-774hUk/Bz10/rl1RNl1WHUq77Qs=", 106 | "requires": { 107 | "debug": "2.2.0", 108 | "nan": "2.6.2", 109 | "usb": "1.3.1" 110 | } 111 | }, 112 | "boom": { 113 | "version": "2.10.1", 114 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", 115 | "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", 116 | "requires": { 117 | "hoek": "2.16.3" 118 | } 119 | }, 120 | "bplist-parser": { 121 | "version": "0.0.6", 122 | "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.0.6.tgz", 123 | "integrity": "sha1-ONo0cYF9+dRKs4kuJ3B7u9daEbk=" 124 | }, 125 | "brace-expansion": { 126 | "version": "1.1.8", 127 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 128 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 129 | "requires": { 130 | "balanced-match": "1.0.0", 131 | "concat-map": "0.0.1" 132 | } 133 | }, 134 | "caseless": { 135 | "version": "0.12.0", 136 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 137 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 138 | }, 139 | "ccurl.interface.js": { 140 | "version": "0.0.6", 141 | "resolved": "https://registry.npmjs.org/ccurl.interface.js/-/ccurl.interface.js-0.0.6.tgz", 142 | "integrity": "sha1-tvSTVjve9YI0n8mrABTCdxiuM4I=", 143 | "requires": { 144 | "ffi": "2.2.0", 145 | "iota.lib.js": "0.4.7" 146 | }, 147 | "dependencies": { 148 | "iota.lib.js": { 149 | "version": "0.4.7", 150 | "resolved": "https://registry.npmjs.org/iota.lib.js/-/iota.lib.js-0.4.7.tgz", 151 | "integrity": "sha1-wq8aeIa4sOI5pLVLXKqd0jnC1+s=", 152 | "requires": { 153 | "async": "2.6.0", 154 | "bignumber.js": "4.1.0", 155 | "crypto-js": "3.1.9-1", 156 | "xmlhttprequest": "1.8.0" 157 | } 158 | } 159 | } 160 | }, 161 | "co": { 162 | "version": "4.6.0", 163 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 164 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 165 | }, 166 | "code-point-at": { 167 | "version": "1.1.0", 168 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 169 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" 170 | }, 171 | "combined-stream": { 172 | "version": "1.0.5", 173 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", 174 | "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", 175 | "requires": { 176 | "delayed-stream": "1.0.0" 177 | } 178 | }, 179 | "concat-map": { 180 | "version": "0.0.1", 181 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 182 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 183 | }, 184 | "console-control-strings": { 185 | "version": "1.1.0", 186 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 187 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" 188 | }, 189 | "core-util-is": { 190 | "version": "1.0.2", 191 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 192 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 193 | }, 194 | "cryptiles": { 195 | "version": "2.0.5", 196 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", 197 | "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", 198 | "requires": { 199 | "boom": "2.10.1" 200 | } 201 | }, 202 | "crypto-js": { 203 | "version": "3.1.9-1", 204 | "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz", 205 | "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg=" 206 | }, 207 | "dashdash": { 208 | "version": "1.14.1", 209 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 210 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 211 | "requires": { 212 | "assert-plus": "1.0.0" 213 | }, 214 | "dependencies": { 215 | "assert-plus": { 216 | "version": "1.0.0", 217 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 218 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 219 | } 220 | } 221 | }, 222 | "debug": { 223 | "version": "2.2.0", 224 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 225 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 226 | "requires": { 227 | "ms": "0.7.1" 228 | } 229 | }, 230 | "deep-extend": { 231 | "version": "0.4.2", 232 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", 233 | "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" 234 | }, 235 | "delayed-stream": { 236 | "version": "1.0.0", 237 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 238 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 239 | }, 240 | "delegates": { 241 | "version": "1.0.0", 242 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 243 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" 244 | }, 245 | "detect-libc": { 246 | "version": "1.0.3", 247 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 248 | "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" 249 | }, 250 | "ecc-jsbn": { 251 | "version": "0.1.1", 252 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", 253 | "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", 254 | "requires": { 255 | "jsbn": "0.1.1" 256 | } 257 | }, 258 | "extend": { 259 | "version": "3.0.1", 260 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 261 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" 262 | }, 263 | "extsprintf": { 264 | "version": "1.3.0", 265 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 266 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 267 | }, 268 | "ffi": { 269 | "version": "2.2.0", 270 | "resolved": "https://registry.npmjs.org/ffi/-/ffi-2.2.0.tgz", 271 | "integrity": "sha1-vxiwRmain3EiftVoldVDCvRwQvo=", 272 | "requires": { 273 | "bindings": "1.2.1", 274 | "debug": "2.2.0", 275 | "nan": "2.6.2", 276 | "ref": "1.3.5", 277 | "ref-struct": "1.1.0" 278 | } 279 | }, 280 | "forever-agent": { 281 | "version": "0.6.1", 282 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 283 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 284 | }, 285 | "form-data": { 286 | "version": "2.1.4", 287 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", 288 | "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", 289 | "requires": { 290 | "asynckit": "0.4.0", 291 | "combined-stream": "1.0.5", 292 | "mime-types": "2.1.17" 293 | } 294 | }, 295 | "fs.realpath": { 296 | "version": "1.0.0", 297 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 298 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 299 | }, 300 | "fstream": { 301 | "version": "1.0.11", 302 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", 303 | "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", 304 | "requires": { 305 | "graceful-fs": "4.1.11", 306 | "inherits": "2.0.3", 307 | "mkdirp": "0.5.1", 308 | "rimraf": "2.6.2" 309 | } 310 | }, 311 | "fstream-ignore": { 312 | "version": "1.0.5", 313 | "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", 314 | "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", 315 | "requires": { 316 | "fstream": "1.0.11", 317 | "inherits": "2.0.3", 318 | "minimatch": "3.0.4" 319 | } 320 | }, 321 | "gauge": { 322 | "version": "2.7.4", 323 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", 324 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", 325 | "requires": { 326 | "aproba": "1.2.0", 327 | "console-control-strings": "1.1.0", 328 | "has-unicode": "2.0.1", 329 | "object-assign": "4.1.1", 330 | "signal-exit": "3.0.2", 331 | "string-width": "1.0.2", 332 | "strip-ansi": "3.0.1", 333 | "wide-align": "1.1.2" 334 | } 335 | }, 336 | "getpass": { 337 | "version": "0.1.7", 338 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 339 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 340 | "requires": { 341 | "assert-plus": "1.0.0" 342 | }, 343 | "dependencies": { 344 | "assert-plus": { 345 | "version": "1.0.0", 346 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 347 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 348 | } 349 | } 350 | }, 351 | "glob": { 352 | "version": "7.1.2", 353 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 354 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 355 | "requires": { 356 | "fs.realpath": "1.0.0", 357 | "inflight": "1.0.6", 358 | "inherits": "2.0.3", 359 | "minimatch": "3.0.4", 360 | "once": "1.4.0", 361 | "path-is-absolute": "1.0.1" 362 | } 363 | }, 364 | "graceful-fs": { 365 | "version": "4.1.11", 366 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 367 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" 368 | }, 369 | "har-schema": { 370 | "version": "1.0.5", 371 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", 372 | "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" 373 | }, 374 | "har-validator": { 375 | "version": "4.2.1", 376 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", 377 | "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", 378 | "requires": { 379 | "ajv": "4.11.8", 380 | "har-schema": "1.0.5" 381 | } 382 | }, 383 | "has-unicode": { 384 | "version": "2.0.1", 385 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 386 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" 387 | }, 388 | "hawk": { 389 | "version": "3.1.3", 390 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", 391 | "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", 392 | "requires": { 393 | "boom": "2.10.1", 394 | "cryptiles": "2.0.5", 395 | "hoek": "2.16.3", 396 | "sntp": "1.0.9" 397 | } 398 | }, 399 | "hoek": { 400 | "version": "2.16.3", 401 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", 402 | "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" 403 | }, 404 | "http-signature": { 405 | "version": "1.1.1", 406 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", 407 | "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", 408 | "requires": { 409 | "assert-plus": "0.2.0", 410 | "jsprim": "1.4.1", 411 | "sshpk": "1.13.1" 412 | } 413 | }, 414 | "inflight": { 415 | "version": "1.0.6", 416 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 417 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 418 | "requires": { 419 | "once": "1.4.0", 420 | "wrappy": "1.0.2" 421 | } 422 | }, 423 | "inherits": { 424 | "version": "2.0.3", 425 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 426 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 427 | }, 428 | "ini": { 429 | "version": "1.3.5", 430 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", 431 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" 432 | }, 433 | "iota.lib.js": { 434 | "version": "file:iota.lib.js", 435 | "requires": { 436 | "async": "2.6.0", 437 | "crypto-js": "3.1.9-1", 438 | "xmlhttprequest": "1.8.0" 439 | } 440 | }, 441 | "is-fullwidth-code-point": { 442 | "version": "1.0.0", 443 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 444 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 445 | "requires": { 446 | "number-is-nan": "1.0.1" 447 | } 448 | }, 449 | "is-typedarray": { 450 | "version": "1.0.0", 451 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 452 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 453 | }, 454 | "isarray": { 455 | "version": "1.0.0", 456 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 457 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 458 | }, 459 | "isstream": { 460 | "version": "0.1.2", 461 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 462 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 463 | }, 464 | "jsbn": { 465 | "version": "0.1.1", 466 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 467 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 468 | }, 469 | "json-schema": { 470 | "version": "0.2.3", 471 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 472 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 473 | }, 474 | "json-stable-stringify": { 475 | "version": "1.0.1", 476 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 477 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 478 | "requires": { 479 | "jsonify": "0.0.0" 480 | } 481 | }, 482 | "json-stringify-safe": { 483 | "version": "5.0.1", 484 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 485 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 486 | }, 487 | "jsonify": { 488 | "version": "0.0.0", 489 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 490 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" 491 | }, 492 | "jsprim": { 493 | "version": "1.4.1", 494 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 495 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 496 | "requires": { 497 | "assert-plus": "1.0.0", 498 | "extsprintf": "1.3.0", 499 | "json-schema": "0.2.3", 500 | "verror": "1.10.0" 501 | }, 502 | "dependencies": { 503 | "assert-plus": { 504 | "version": "1.0.0", 505 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 506 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 507 | } 508 | } 509 | }, 510 | "lodash": { 511 | "version": "4.17.5", 512 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", 513 | "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" 514 | }, 515 | "mime-db": { 516 | "version": "1.30.0", 517 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 518 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" 519 | }, 520 | "mime-types": { 521 | "version": "2.1.17", 522 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 523 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 524 | "requires": { 525 | "mime-db": "1.30.0" 526 | } 527 | }, 528 | "minimatch": { 529 | "version": "3.0.4", 530 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 531 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 532 | "requires": { 533 | "brace-expansion": "1.1.8" 534 | } 535 | }, 536 | "minimist": { 537 | "version": "0.0.8", 538 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 539 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 540 | }, 541 | "mkdirp": { 542 | "version": "0.5.1", 543 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 544 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 545 | "requires": { 546 | "minimist": "0.0.8" 547 | } 548 | }, 549 | "ms": { 550 | "version": "0.7.1", 551 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 552 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" 553 | }, 554 | "nan": { 555 | "version": "2.6.2", 556 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", 557 | "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=" 558 | }, 559 | "noble": { 560 | "version": "1.9.0", 561 | "resolved": "https://registry.npmjs.org/noble/-/noble-1.9.0.tgz", 562 | "integrity": "sha1-3MuUIO4rFVoFHE7DNoz/BYgmiWI=", 563 | "requires": { 564 | "bluetooth-hci-socket": "0.5.1", 565 | "bplist-parser": "0.0.6", 566 | "debug": "2.2.0", 567 | "xpc-connection": "0.1.4" 568 | } 569 | }, 570 | "node-pre-gyp": { 571 | "version": "0.6.39", 572 | "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz", 573 | "integrity": "sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==", 574 | "requires": { 575 | "detect-libc": "1.0.3", 576 | "hawk": "3.1.3", 577 | "mkdirp": "0.5.1", 578 | "nopt": "4.0.1", 579 | "npmlog": "4.1.2", 580 | "rc": "1.2.5", 581 | "request": "2.81.0", 582 | "rimraf": "2.6.2", 583 | "semver": "5.5.0", 584 | "tar": "2.2.1", 585 | "tar-pack": "3.4.1" 586 | } 587 | }, 588 | "nopt": { 589 | "version": "4.0.1", 590 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", 591 | "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", 592 | "requires": { 593 | "abbrev": "1.1.1", 594 | "osenv": "0.1.4" 595 | } 596 | }, 597 | "npmlog": { 598 | "version": "4.1.2", 599 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", 600 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", 601 | "requires": { 602 | "are-we-there-yet": "1.1.4", 603 | "console-control-strings": "1.1.0", 604 | "gauge": "2.7.4", 605 | "set-blocking": "2.0.0" 606 | } 607 | }, 608 | "number-is-nan": { 609 | "version": "1.0.1", 610 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 611 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 612 | }, 613 | "oauth-sign": { 614 | "version": "0.8.2", 615 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 616 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" 617 | }, 618 | "object-assign": { 619 | "version": "4.1.1", 620 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 621 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 622 | }, 623 | "once": { 624 | "version": "1.4.0", 625 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 626 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 627 | "requires": { 628 | "wrappy": "1.0.2" 629 | } 630 | }, 631 | "os-homedir": { 632 | "version": "1.0.2", 633 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 634 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" 635 | }, 636 | "os-tmpdir": { 637 | "version": "1.0.2", 638 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 639 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 640 | }, 641 | "osenv": { 642 | "version": "0.1.4", 643 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", 644 | "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", 645 | "requires": { 646 | "os-homedir": "1.0.2", 647 | "os-tmpdir": "1.0.2" 648 | } 649 | }, 650 | "path-is-absolute": { 651 | "version": "1.0.1", 652 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 653 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 654 | }, 655 | "performance-now": { 656 | "version": "0.2.0", 657 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", 658 | "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" 659 | }, 660 | "process-nextick-args": { 661 | "version": "1.0.7", 662 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 663 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 664 | }, 665 | "punycode": { 666 | "version": "1.4.1", 667 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 668 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 669 | }, 670 | "qs": { 671 | "version": "6.4.0", 672 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", 673 | "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" 674 | }, 675 | "rc": { 676 | "version": "1.2.5", 677 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.5.tgz", 678 | "integrity": "sha1-J1zWh/bjs2zHVrqibf7oCnkDAf0=", 679 | "requires": { 680 | "deep-extend": "0.4.2", 681 | "ini": "1.3.5", 682 | "minimist": "1.2.0", 683 | "strip-json-comments": "2.0.1" 684 | }, 685 | "dependencies": { 686 | "minimist": { 687 | "version": "1.2.0", 688 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 689 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 690 | } 691 | } 692 | }, 693 | "readable-stream": { 694 | "version": "2.3.3", 695 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 696 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 697 | "requires": { 698 | "core-util-is": "1.0.2", 699 | "inherits": "2.0.3", 700 | "isarray": "1.0.0", 701 | "process-nextick-args": "1.0.7", 702 | "safe-buffer": "5.1.1", 703 | "string_decoder": "1.0.3", 704 | "util-deprecate": "1.0.2" 705 | } 706 | }, 707 | "ref": { 708 | "version": "1.3.5", 709 | "resolved": "https://registry.npmjs.org/ref/-/ref-1.3.5.tgz", 710 | "integrity": "sha512-2cBCniTtxcGUjDpvFfVpw323a83/0RLSGJJY5l5lcomZWhYpU2cuLdsvYqMixvsdLJ9+sTdzEkju8J8ZHDM2nA==", 711 | "requires": { 712 | "bindings": "1.2.1", 713 | "debug": "2.2.0", 714 | "nan": "2.6.2" 715 | } 716 | }, 717 | "ref-struct": { 718 | "version": "1.1.0", 719 | "resolved": "https://registry.npmjs.org/ref-struct/-/ref-struct-1.1.0.tgz", 720 | "integrity": "sha1-XV7mWtQc78Olxf60BYcmHkee3BM=", 721 | "requires": { 722 | "debug": "2.2.0", 723 | "ref": "1.3.5" 724 | } 725 | }, 726 | "request": { 727 | "version": "2.81.0", 728 | "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", 729 | "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", 730 | "requires": { 731 | "aws-sign2": "0.6.0", 732 | "aws4": "1.6.0", 733 | "caseless": "0.12.0", 734 | "combined-stream": "1.0.5", 735 | "extend": "3.0.1", 736 | "forever-agent": "0.6.1", 737 | "form-data": "2.1.4", 738 | "har-validator": "4.2.1", 739 | "hawk": "3.1.3", 740 | "http-signature": "1.1.1", 741 | "is-typedarray": "1.0.0", 742 | "isstream": "0.1.2", 743 | "json-stringify-safe": "5.0.1", 744 | "mime-types": "2.1.17", 745 | "oauth-sign": "0.8.2", 746 | "performance-now": "0.2.0", 747 | "qs": "6.4.0", 748 | "safe-buffer": "5.1.1", 749 | "stringstream": "0.0.5", 750 | "tough-cookie": "2.3.3", 751 | "tunnel-agent": "0.6.0", 752 | "uuid": "3.2.1" 753 | } 754 | }, 755 | "rimraf": { 756 | "version": "2.6.2", 757 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 758 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 759 | "requires": { 760 | "glob": "7.1.2" 761 | } 762 | }, 763 | "safe-buffer": { 764 | "version": "5.1.1", 765 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 766 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 767 | }, 768 | "semver": { 769 | "version": "5.5.0", 770 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", 771 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" 772 | }, 773 | "set-blocking": { 774 | "version": "2.0.0", 775 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 776 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" 777 | }, 778 | "signal-exit": { 779 | "version": "3.0.2", 780 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 781 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 782 | }, 783 | "sleep": { 784 | "version": "5.1.1", 785 | "resolved": "https://registry.npmjs.org/sleep/-/sleep-5.1.1.tgz", 786 | "integrity": "sha1-h4+h1E0I7rDyb7IBjvhinrGjq5Q=", 787 | "requires": { 788 | "nan": "2.6.2" 789 | } 790 | }, 791 | "sntp": { 792 | "version": "1.0.9", 793 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", 794 | "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", 795 | "requires": { 796 | "hoek": "2.16.3" 797 | } 798 | }, 799 | "sshpk": { 800 | "version": "1.13.1", 801 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", 802 | "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", 803 | "requires": { 804 | "asn1": "0.2.3", 805 | "assert-plus": "1.0.0", 806 | "bcrypt-pbkdf": "1.0.1", 807 | "dashdash": "1.14.1", 808 | "ecc-jsbn": "0.1.1", 809 | "getpass": "0.1.7", 810 | "jsbn": "0.1.1", 811 | "tweetnacl": "0.14.5" 812 | }, 813 | "dependencies": { 814 | "assert-plus": { 815 | "version": "1.0.0", 816 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 817 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 818 | } 819 | } 820 | }, 821 | "string-width": { 822 | "version": "1.0.2", 823 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 824 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 825 | "requires": { 826 | "code-point-at": "1.1.0", 827 | "is-fullwidth-code-point": "1.0.0", 828 | "strip-ansi": "3.0.1" 829 | } 830 | }, 831 | "string_decoder": { 832 | "version": "1.0.3", 833 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 834 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 835 | "requires": { 836 | "safe-buffer": "5.1.1" 837 | } 838 | }, 839 | "stringstream": { 840 | "version": "0.0.5", 841 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", 842 | "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" 843 | }, 844 | "strip-ansi": { 845 | "version": "3.0.1", 846 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 847 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 848 | "requires": { 849 | "ansi-regex": "2.1.1" 850 | } 851 | }, 852 | "strip-json-comments": { 853 | "version": "2.0.1", 854 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 855 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" 856 | }, 857 | "tar": { 858 | "version": "2.2.1", 859 | "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", 860 | "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", 861 | "requires": { 862 | "block-stream": "0.0.9", 863 | "fstream": "1.0.11", 864 | "inherits": "2.0.3" 865 | } 866 | }, 867 | "tar-pack": { 868 | "version": "3.4.1", 869 | "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.1.tgz", 870 | "integrity": "sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg==", 871 | "requires": { 872 | "debug": "2.2.0", 873 | "fstream": "1.0.11", 874 | "fstream-ignore": "1.0.5", 875 | "once": "1.4.0", 876 | "readable-stream": "2.3.3", 877 | "rimraf": "2.6.2", 878 | "tar": "2.2.1", 879 | "uid-number": "0.0.6" 880 | } 881 | }, 882 | "tough-cookie": { 883 | "version": "2.3.3", 884 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", 885 | "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", 886 | "requires": { 887 | "punycode": "1.4.1" 888 | } 889 | }, 890 | "tunnel-agent": { 891 | "version": "0.6.0", 892 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 893 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 894 | "requires": { 895 | "safe-buffer": "5.1.1" 896 | } 897 | }, 898 | "tweetnacl": { 899 | "version": "0.14.5", 900 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 901 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 902 | }, 903 | "uid-number": { 904 | "version": "0.0.6", 905 | "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", 906 | "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" 907 | }, 908 | "usb": { 909 | "version": "1.3.1", 910 | "resolved": "https://registry.npmjs.org/usb/-/usb-1.3.1.tgz", 911 | "integrity": "sha1-tfjDYKU78o9cn7wS1kx/YeQ0arc=", 912 | "requires": { 913 | "nan": "2.8.0", 914 | "node-pre-gyp": "0.6.39" 915 | }, 916 | "dependencies": { 917 | "nan": { 918 | "version": "2.8.0", 919 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", 920 | "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=" 921 | } 922 | } 923 | }, 924 | "util-deprecate": { 925 | "version": "1.0.2", 926 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 927 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 928 | }, 929 | "uuid": { 930 | "version": "3.2.1", 931 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", 932 | "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" 933 | }, 934 | "verror": { 935 | "version": "1.10.0", 936 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 937 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 938 | "requires": { 939 | "assert-plus": "1.0.0", 940 | "core-util-is": "1.0.2", 941 | "extsprintf": "1.3.0" 942 | }, 943 | "dependencies": { 944 | "assert-plus": { 945 | "version": "1.0.0", 946 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 947 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 948 | } 949 | } 950 | }, 951 | "wide-align": { 952 | "version": "1.1.2", 953 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", 954 | "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", 955 | "requires": { 956 | "string-width": "1.0.2" 957 | } 958 | }, 959 | "wrappy": { 960 | "version": "1.0.2", 961 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 962 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 963 | }, 964 | "xmlhttprequest": { 965 | "version": "1.8.0", 966 | "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", 967 | "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" 968 | }, 969 | "xpc-connection": { 970 | "version": "0.1.4", 971 | "resolved": "https://registry.npmjs.org/xpc-connection/-/xpc-connection-0.1.4.tgz", 972 | "integrity": "sha1-3Nf6oq7Gt6bhjMXdrQQvejTHcVY=", 973 | "optional": true, 974 | "requires": { 975 | "nan": "2.6.2" 976 | } 977 | } 978 | } 979 | } 980 | -------------------------------------------------------------------------------- /raspberrypi-bin/libccurl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ojousima/ruuvi-nodejs/9c4fb510f86b236e7fe8badc6bb0d37990c0f32c/raspberrypi-bin/libccurl.so -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # NOTICE 2 | As of right now, changes in FFI interface prevent ccurl.interface.js from compiling in NodeJS 9+ 3 | Please use NodeJS 8.9.4 4 | 5 | # Usage 6 | Program searches for RuuviTag which has Nordic UART service enabled 7 | and automatically connects to first RuuviTag it finds. 8 | Please update the RuuviTag with [MAM-firmware](https://lab.ruuvi.com/distribution-packages/frankfurt_demo_dfu.zip). 9 | 10 | Sometimes there is issue with Bluetooth stack, and you'll need to run 11 | `sudo hciconfig hci0 reset`. Replace the HCI interface number if applicable. 12 | 13 | A simple command line interface is given. 14 | User is given option to setup temperature sensor for a single-shot measurement, 15 | continous measurement (once per second) and querying temperature in plain text. 16 | User can also send a MAM query, which will trigger reading environmental data 17 | and soon the environmental data is sent from RuuviTag with MAM coding. 18 | 19 | The example program publishes MAM data to tangle to fixed address defined in example.js. 20 | 21 | You can observe the state of RuuviTag by RED LED, if the led is on or blinking there is activity 22 | going on. 23 | 24 | After installing, run node example.js 25 | 26 | # Dependencies 27 | ## NodeJS, npm 28 | NOTE: This modifies your global NodeJS and NPM versions. 29 | Update NodeJS to 8.9.4 with instructions found at 30 | https://askubuntu.com/questions/426750/how-can-i-update-my-nodejs-to-the-latest-version . i.e. 31 | ``` 32 | sudo npm cache clean -f 33 | sudo npm install -g n 34 | sudo n 8.9.4 35 | sudo ln -sf /usr/local/n/versions/node/8.9.4/bin/node /usr/bin/node 36 | curl -0 -L https://npmjs.com/install.sh | sudo sh 37 | ``` 38 | 39 | This repository is tested on nodejs 8.9.4, check your version with `node --version` 40 | 41 | ## Noble 42 | [Noble repositry](https://github.com/sandeepmistry/noble) 43 | `npm install noble` 44 | `sudo setcap cap_net_raw+eip $(eval readlink -f \`which node\`)` 45 | 46 | ## iota.lib.js, ruuvi.endpoints.js ccurl.interface.js 47 | `git submodule update --init --recursive` 48 | 49 | `npm install iota.lib.js` 50 | 51 | `npm install ccurl.interface.js` 52 | 53 | `cp raspberrypi-bin/libbcurl.so node_modules/ccurl.interface.js` 54 | 55 | ## Sleep 56 | `npm install sleep` 57 | 58 | ## ccurl 59 | Install ccurl according to instructions published on [NPM](https://www.npmjs.com/package/ccurl.interface.js#https://github.com/iotaledger/ccurl). 60 | For your convenience binaries are provided for Raspberry Pi and 64-bit debian. 61 | 62 | # Licensing 63 | * Ruuvi / Ojousima: BSD-3 64 | * iota libs: MIT 65 | * BLE-UART: Unknown, please refer to [source](https://github.com/tigoe/BluetoothLE-Examples/issues/7) 66 | * Noble: MIT 67 | 68 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var noble = require('noble'); 2 | var async = require('async'); 3 | 4 | var peripheralName = process.argv[2].toLowerCase(); 5 | 6 | noble.on('stateChange', function(state) { 7 | if (state === 'poweredOn') { 8 | noble.startScanning(); 9 | } else { 10 | noble.stopScanning(); 11 | } 12 | }); 13 | 14 | noble.on('discover', function(peripheral) { 15 | if (peripheral.advertisement.localName && peripheral.advertisement.localName.toLowerCase() === peripheralName) { 16 | noble.stopScanning(); 17 | 18 | console.log('peripheral with ID ' + peripheral.id + ' found'); 19 | var advertisement = peripheral.advertisement; 20 | 21 | var localName = advertisement.localName; 22 | var txPowerLevel = advertisement.txPowerLevel; 23 | var manufacturerData = advertisement.manufacturerData; 24 | var serviceData = advertisement.serviceData; 25 | var serviceUuids = advertisement.serviceUuids; 26 | 27 | if (localName) { 28 | console.log(' Local Name = ' + localName); 29 | } 30 | 31 | if (txPowerLevel) { 32 | console.log(' TX Power Level = ' + txPowerLevel); 33 | } 34 | 35 | if (manufacturerData) { 36 | console.log(' Manufacturer Data = ' + manufacturerData.toString('hex')); 37 | } 38 | 39 | if (serviceData) { 40 | console.log(' Service Data = ' + serviceData); 41 | } 42 | 43 | if (serviceUuids) { 44 | console.log(' Service UUIDs = ' + serviceUuids); 45 | } 46 | 47 | console.log(); 48 | 49 | explore(peripheral); 50 | } 51 | }); 52 | 53 | function explore(peripheral) { 54 | console.log('services and characteristics:'); 55 | 56 | peripheral.on('disconnect', function() { 57 | process.exit(0); 58 | }); 59 | 60 | peripheral.connect(function(error) { 61 | peripheral.discoverServices([], function(error, services) { 62 | var serviceIndex = 0; 63 | 64 | async.whilst( 65 | function () { 66 | return (serviceIndex < services.length); 67 | }, 68 | function(callback) { 69 | var service = services[serviceIndex]; 70 | var serviceInfo = service.uuid; 71 | 72 | if (service.name) { 73 | serviceInfo += ' (' + service.name + ')'; 74 | } 75 | console.log(serviceInfo); 76 | 77 | service.discoverCharacteristics([], function(error, characteristics) { 78 | var characteristicIndex = 0; 79 | 80 | async.whilst( 81 | function () { 82 | return (characteristicIndex < characteristics.length); 83 | }, 84 | function(callback) { 85 | var characteristic = characteristics[characteristicIndex]; 86 | var characteristicInfo = ' ' + characteristic.uuid; 87 | 88 | if (characteristic.name) { 89 | characteristicInfo += ' (' + characteristic.name + ')'; 90 | } 91 | 92 | async.series([ 93 | function(callback) { 94 | characteristic.discoverDescriptors(function(error, descriptors) { 95 | async.detect( 96 | descriptors, 97 | function(descriptor, callback) { 98 | return callback(descriptor.uuid === '2901'); 99 | }, 100 | function(userDescriptionDescriptor){ 101 | if (userDescriptionDescriptor) { 102 | userDescriptionDescriptor.readValue(function(error, data) { 103 | if (data) { 104 | characteristicInfo += ' (' + data.toString() + ')'; 105 | } 106 | callback(); 107 | }); 108 | } else { 109 | callback(); 110 | } 111 | } 112 | ); 113 | }); 114 | }, 115 | function(callback) { 116 | characteristicInfo += '\n properties ' + characteristic.properties.join(', '); 117 | 118 | if (characteristic.properties.indexOf('read') !== -1) { 119 | characteristic.read(function(error, data) { 120 | if (data) { 121 | var string = data.toString('ascii'); 122 | 123 | characteristicInfo += '\n value ' + data.toString('hex') + ' | \'' + string + '\''; 124 | } 125 | callback(); 126 | }); 127 | } else { 128 | callback(); 129 | } 130 | }, 131 | function() { 132 | console.log(characteristicInfo); 133 | characteristicIndex++; 134 | callback(); 135 | } 136 | ]); 137 | }, 138 | function(error) { 139 | serviceIndex++; 140 | callback(); 141 | } 142 | ); 143 | }); 144 | }, 145 | function (err) { 146 | peripheral.disconnect(); 147 | } 148 | ); 149 | }); 150 | }); 151 | }var peripheralIdOrAddress = process.argv[2].toLowerCase(); 152 | 153 | --------------------------------------------------------------------------------