mirror of
https://gitlab.com/wirelos/sprocket-lib.git
synced 2025-12-14 20:56:38 +01:00
Resolve "OTA"
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
tools/node_modules
|
||||
@@ -7,5 +7,9 @@ A sprocket is a device that has a single purpose, for example a PIR sensor node
|
||||
# Useful commands
|
||||
```sh
|
||||
# erase flash
|
||||
esptool --port /dev/ttyUSB0 erase_flash
|
||||
esptool --port /dev/ttyUSB0 erase_flash
|
||||
|
||||
# OTA
|
||||
~/.platformio/packages/tool-espotapy/espota.py -i <espIP> -p 8266 -a <authPW> -f .pioenvs/ota/firmware.bin
|
||||
|
||||
```
|
||||
@@ -8,8 +8,8 @@
|
||||
; Please visit documentation for the other options and examples
|
||||
; http://docs.platformio.org/page/projectconf.html
|
||||
|
||||
;[platformio]
|
||||
;env_default = mesh
|
||||
[platformio]
|
||||
env_default = mesh
|
||||
|
||||
[common]
|
||||
framework = arduino
|
||||
@@ -21,19 +21,16 @@ lib_deps =
|
||||
Hash
|
||||
ESPAsyncTCP
|
||||
TaskScheduler
|
||||
SPIFFS
|
||||
|
||||
;[env:build]
|
||||
;src_filter = +<*> -<examples/>
|
||||
;#platform = https://github.com/platformio/platform-espressif8266.git#feature/stage
|
||||
;#platform = https://github.com/platformio/platform-espressif8266.git
|
||||
;#platform = espressif8266@~1.6.0
|
||||
;platform = ${common.platform}
|
||||
;board = ${common.board}
|
||||
;upload_speed = ${common.upload_speed}
|
||||
;monitor_baud = ${common.monitor_baud}
|
||||
;framework = ${common.framework}
|
||||
;lib_deps = ${common.lib_deps}
|
||||
|
||||
;build_flags = -DLED_PIN=2 -g
|
||||
;upload_port = /dev/ttyUSB0
|
||||
;upload_port = 192.168.1.168
|
||||
@@ -67,3 +64,15 @@ framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
painlessMesh
|
||||
PubSubClient
|
||||
|
||||
[env:ota]
|
||||
src_filter = +<*> +<*/plugins/*> -<examples/> +<examples/ota/>
|
||||
platform = espressif8266
|
||||
board = esp12e
|
||||
upload_speed = ${common.upload_speed}
|
||||
upload_flags = --auth=f4ncy
|
||||
monitor_baud = ${common.monitor_baud}
|
||||
framework = ${common.framework}
|
||||
lib_deps = ${common.lib_deps}
|
||||
https://gitlab.com/wirelos/painlessMesh.git#feature/ota
|
||||
ArduinoOTA
|
||||
@@ -15,15 +15,18 @@ Network* MeshNet::init(){
|
||||
mesh.onChangedConnections(bind(&MeshNet::changedConnectionCallback, this));
|
||||
mesh.onNodeTimeAdjusted(bind(&MeshNet::nodeTimeAdjustedCallback, this, _1));
|
||||
|
||||
connectStation();
|
||||
|
||||
return this;
|
||||
}
|
||||
Network* MeshNet::connectStation() {
|
||||
if(config.stationMode){
|
||||
Serial.println("connect station");
|
||||
mesh.stationManual(config.stationSSID, config.stationPassword);
|
||||
mesh.setHostname(config.hostname);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void MeshNet::sendTo(uint32_t target, String msg){
|
||||
mesh.sendSingle(target, msg);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#ifndef __MESHNET_H__
|
||||
#define __MESHNET_H__
|
||||
|
||||
#ifdef ESP32
|
||||
#include <WiFi.h>
|
||||
#elif defined(ESP8266)
|
||||
#include <ESP8266WiFi.h>
|
||||
#endif // ESP32
|
||||
|
||||
#include <painlessMesh.h>
|
||||
#include <WiFiClient.h>
|
||||
#include "Network.h"
|
||||
@@ -8,6 +14,7 @@
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
|
||||
// FIXME non-mesh config should have it's own struct
|
||||
struct MeshConfig {
|
||||
int stationMode;
|
||||
int channel;
|
||||
@@ -27,14 +34,18 @@ class MeshNet : public Network {
|
||||
|
||||
MeshNet(MeshConfig cfg);
|
||||
Network* init();
|
||||
Network* connectStation();
|
||||
|
||||
void update(); // only needed when no scheduler was passed to mesh.init
|
||||
void update();
|
||||
void newConnectionCallback(uint32_t nodeId);
|
||||
void changedConnectionCallback();
|
||||
void nodeTimeAdjustedCallback(int32_t offset);
|
||||
void broadcast(String msg);
|
||||
void sendTo(uint32_t target, String msg);
|
||||
void onReceive(std::function<void(uint32_t from, String &msg)>);
|
||||
int isConnected(){
|
||||
return WiFi.status() == WL_CONNECTED;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -14,6 +14,8 @@ class Network {
|
||||
virtual Network* init() { return this; };
|
||||
virtual Network* init(Scheduler* s) { scheduler = s; return init(); };
|
||||
virtual Network* connect() { return this; };
|
||||
virtual Network* connectStation() { return this; };
|
||||
virtual int isConnected(){ return 0; };
|
||||
virtual void update() {};
|
||||
virtual void broadcast(String msg){};
|
||||
virtual void sendTo(uint32_t target, String msg) {};
|
||||
|
||||
74
src/OtaTcpPlugin.cpp
Normal file
74
src/OtaTcpPlugin.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef __OTA_CLASSIC_H__
|
||||
#define __OTA_CLASSIC_H__
|
||||
|
||||
#include "TaskSchedulerDeclarations.h"
|
||||
#include "ArduinoOTA.h"
|
||||
#include "MeshNet.h"
|
||||
#include "Plugin.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
|
||||
struct OtaConfig {
|
||||
int port;
|
||||
const char* password;
|
||||
};
|
||||
|
||||
// TODO rename to OtaTcpPlugin
|
||||
class OtaTcpPlugin : public Plugin {
|
||||
private:
|
||||
OtaConfig config;
|
||||
Task otaTask;
|
||||
public:
|
||||
OtaTcpPlugin(OtaConfig cfg){
|
||||
config = cfg;
|
||||
}
|
||||
void enable(Scheduler* userScheduler, Network* network){
|
||||
scheduler = userScheduler;
|
||||
|
||||
// connect to network
|
||||
if(!network->isConnected()){
|
||||
// TODO when config is refactored, cast is not necessary anymore
|
||||
static_cast<MeshNet*>(network)->config.stationMode = 1;
|
||||
network->connectStation();
|
||||
// TODO set service message to mesh to announce station IP
|
||||
}
|
||||
// setup task
|
||||
otaTask.set(TASK_MILLISECOND * 100, TASK_FOREVER, [](){
|
||||
ArduinoOTA.handle();
|
||||
});
|
||||
scheduler->addTask(otaTask);
|
||||
|
||||
// configure OTA
|
||||
ArduinoOTA.setPort(config.port);
|
||||
//ArduinoOTA.setHostname(HOSTNAME);
|
||||
if(strlen(config.password) > 0){
|
||||
ArduinoOTA.setPassword(config.password);
|
||||
}
|
||||
// setup callbacks
|
||||
ArduinoOTA.onStart([]() {
|
||||
Serial.println("OTA: Start");
|
||||
});
|
||||
ArduinoOTA.onEnd([]() {
|
||||
Serial.println("OTA: End");
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("OTA: Progress: %u%%\r", (progress / (total / 100)));
|
||||
});
|
||||
ArduinoOTA.onError([](ota_error_t error) {
|
||||
Serial.printf("OTA: Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("OTA: Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("OTA: Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("OTA: Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("OTA: Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("OTA: End Failed");
|
||||
});
|
||||
ArduinoOTA.begin();
|
||||
otaTask.enable();
|
||||
}
|
||||
void disable(){
|
||||
otaTask.disable();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
15
src/Plugin.h
Normal file
15
src/Plugin.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef __SPROCKET_PLUGIN__
|
||||
#define __SPROCKET_PLUGIN__
|
||||
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <Network.h>
|
||||
|
||||
class Plugin {
|
||||
protected:
|
||||
Scheduler* scheduler;
|
||||
public:
|
||||
virtual void enable(Scheduler*, Network*);
|
||||
virtual void disable();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
#include <TaskSchedulerDeclarations.h>
|
||||
#include <Arduino.h>
|
||||
#include <FS.h>
|
||||
#include "FS.h"
|
||||
#ifdef ESP32
|
||||
#include "SPIFFS.h"
|
||||
#endif
|
||||
#include "Network.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -31,6 +34,7 @@ class Sprocket {
|
||||
virtual Sprocket* activate();
|
||||
virtual Sprocket* activate(Scheduler*) { return this; }
|
||||
virtual Sprocket* activate(Scheduler*, Network*) { return this; }
|
||||
virtual Sprocket* enable() { return this; };
|
||||
// TODO bind onMessage to network->onReceive
|
||||
//virtual void onMessage(uint32_t from, String &msg) {};
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define STATION_SSID "Th1ngs4P"
|
||||
#define STATION_PASSWORD "th3r31sn0sp00n"
|
||||
#define HOSTNAME "mesh-node"
|
||||
#define MESH_DEBUG_TYPES ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE
|
||||
#define MESH_DEBUG_TYPES ERROR | CONNECTION | COMMUNICATION
|
||||
//ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,7 @@
|
||||
#define STATION_MODE 1
|
||||
#define WIFI_CHANNEL 11
|
||||
#define MESH_PORT 5555
|
||||
#define MESH_PREFIX "WirelosContraption"
|
||||
#define MESH_PREFIX "whateverYouLike"
|
||||
#define MESH_PASSWORD "somethingSneaky"
|
||||
#define STATION_SSID "Th1ngs4P"
|
||||
#define STATION_PASSWORD "th3r31sn0sp00n"
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
// Bridge config
|
||||
#define MQTT_CLIENT_NAME HOSTNAME
|
||||
#define MQTT_BROKER "iot.eclipse.org"
|
||||
#define MQTT_BROKER "citadel.lan"
|
||||
#define MQTT_PORT 1883
|
||||
#define MQTT_TOPIC_ROOT "mesh"
|
||||
|
||||
|
||||
40
src/examples/ota/SprocketOTA.cpp
Normal file
40
src/examples/ota/SprocketOTA.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef __MESH_APP__
|
||||
#define __MESH_APP__
|
||||
|
||||
#define DEBUG_ESP_OTA
|
||||
#include <painlessMesh.h>
|
||||
#include <Sprocket.h>
|
||||
#include <MeshNet.h>
|
||||
#include <OtaTcpPlugin.cpp>
|
||||
#include "config.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
|
||||
class SprocketOTA : public Sprocket {
|
||||
public:
|
||||
MeshNet* net;
|
||||
OtaTcpPlugin* ota;
|
||||
|
||||
SprocketOTA(SprocketConfig cfg, OtaConfig otaCfg) : Sprocket(cfg) {
|
||||
ota = new OtaTcpPlugin(otaCfg);
|
||||
}
|
||||
|
||||
Sprocket* activate(Scheduler* scheduler, Network* network) {
|
||||
net = static_cast<MeshNet*>(network);
|
||||
net->onReceive(bind(&SprocketOTA::dispatch,this, _1, _2));
|
||||
ota->enable(scheduler, network);
|
||||
return this;
|
||||
} using Sprocket::activate;
|
||||
|
||||
void dispatch( uint32_t from, String &msg ) {
|
||||
Serial.printf("Sprocket: received from %u msg=%s\n", from, msg.c_str());
|
||||
}
|
||||
|
||||
void loop() {
|
||||
net->update();
|
||||
scheduler.execute();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
27
src/examples/ota/config.h
Normal file
27
src/examples/ota/config.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef __OTA_NODE__CONFIG__
|
||||
#define __OTA_NODE__CONFIG__
|
||||
|
||||
// Scheduler config
|
||||
#define _TASK_SLEEP_ON_IDLE_RUN
|
||||
#define _TASK_STD_FUNCTION
|
||||
|
||||
// Chip config
|
||||
#define SERIAL_BAUD_RATE 115200
|
||||
#define STARTUP_DELAY 3000
|
||||
|
||||
// Mesh config
|
||||
#define STATION_MODE 1 // must be 1 => connected to a normal network to receive update
|
||||
#define WIFI_CHANNEL 11
|
||||
#define MESH_PORT 5555
|
||||
#define MESH_PREFIX "whateverYouLike"
|
||||
#define MESH_PASSWORD "somethingSneaky"
|
||||
#define STATION_SSID "Th1ngs4P"
|
||||
#define STATION_PASSWORD "th3r31sn0sp00n"
|
||||
#define HOSTNAME "ota-node"
|
||||
#define MESH_DEBUG_TYPES ERROR | STARTUP | CONNECTION
|
||||
|
||||
// OTA config
|
||||
#define OTA_PORT 8266
|
||||
#define OTA_PASSWORD "f4ncy"
|
||||
|
||||
#endif
|
||||
25
src/examples/ota/main.cpp
Normal file
25
src/examples/ota/main.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <ArduinoOTA.h>
|
||||
#include "config.h"
|
||||
#include "MeshNet.h"
|
||||
#include "SprocketOTA.cpp"
|
||||
|
||||
MeshNet net({
|
||||
STATION_MODE, WIFI_CHANNEL,
|
||||
MESH_PORT, MESH_PREFIX, MESH_PASSWORD,
|
||||
STATION_SSID, STATION_PASSWORD, HOSTNAME,
|
||||
MESH_DEBUG_TYPES
|
||||
});
|
||||
|
||||
SprocketOTA sprocket(
|
||||
{ STARTUP_DELAY, SERIAL_BAUD_RATE },
|
||||
{OTA_PORT, OTA_PASSWORD}
|
||||
);
|
||||
|
||||
void setup() {
|
||||
sprocket.join(net);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
sprocket.loop();
|
||||
yield();
|
||||
}
|
||||
116
tools/ota.js
Normal file
116
tools/ota.js
Normal file
@@ -0,0 +1,116 @@
|
||||
// Mesh msg type = 7
|
||||
// OTA paket types: START = 0, DATA = 1, END = 3
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const mqtt = require('mqtt');
|
||||
|
||||
let filePath = '../.pioenvs/mesh/firmware.bin';
|
||||
let broker = 'mqtt://192.168.1.2:1883';
|
||||
|
||||
const readFile = filePath => new Promise((resolve, reject) => {
|
||||
fs.readFile(filePath, (err, data) => {
|
||||
if (err) reject(err);
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
const checksumFile = (hashName, path) => new Promise((resolve, reject) => {
|
||||
let hash = crypto.createHash(hashName);
|
||||
let stream = fs.createReadStream(path);
|
||||
stream.on('error', err => reject(err));
|
||||
stream.on('data', chunk => hash.update(chunk));
|
||||
stream.on('end', () => resolve(hash.digest('hex')));
|
||||
});
|
||||
|
||||
const upload = async path => {
|
||||
let content = await readFile(path);
|
||||
let md5 = await checksumFile('MD5', path);
|
||||
let b64Content = content.toString('base64');
|
||||
console.log(`MD5 Hash: ${md5}`);
|
||||
//console.log(b64Content);
|
||||
//mqttClient(md5, b64Content);
|
||||
};
|
||||
|
||||
const initializeUpdateMessage = (fromNode, toNode, md5Hash) => {
|
||||
return {
|
||||
dest: toNode,
|
||||
from: fromNode,
|
||||
type: 7,
|
||||
msg: {
|
||||
type: 0,
|
||||
md5: md5Hash
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const firmwareUpdateMessage = (fromNode, toNode, firmware) => {
|
||||
return {
|
||||
dest: toNode,
|
||||
from: fromNode,
|
||||
type: 7,
|
||||
msg: {
|
||||
type: 1,
|
||||
data: firmware,
|
||||
length: firmware.length
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mqttClient = (md5, data) => {
|
||||
|
||||
var client = mqtt.connect(broker);
|
||||
let target = 3895627464;
|
||||
// button thingy=> dest: "757307466",
|
||||
let initMsg = {
|
||||
dest: target,
|
||||
from: 1,
|
||||
type: 7,
|
||||
msg: {
|
||||
type: 0,
|
||||
md5: md5
|
||||
}
|
||||
};
|
||||
let dataMsg = {
|
||||
dest: target,
|
||||
from: 1,
|
||||
type: 7,
|
||||
msg: {
|
||||
type: 1,
|
||||
data: data,
|
||||
length: data.length
|
||||
}
|
||||
};
|
||||
let sm = {
|
||||
OTA_INIT: {
|
||||
FAILED: console.log,
|
||||
DONE: OTA_DATA.WRITE
|
||||
},
|
||||
OTA_DATA: {
|
||||
WRITE: console.log,
|
||||
DONE: OTA_FIN.RESTART,
|
||||
FAILED: console.log
|
||||
},
|
||||
OTA_FIN: {
|
||||
RESTART: console.log
|
||||
}
|
||||
};
|
||||
|
||||
client.on('connect', function () {
|
||||
client.subscribe('/up/wirelos/gateway');
|
||||
client.publish('/down/wirelos', JSON.stringify(initMsg));
|
||||
})
|
||||
|
||||
client.on('message', function (topic, message) {
|
||||
// message is Buffer
|
||||
console.log(message.toString());
|
||||
let obj = JSON.parse(message.toString());
|
||||
sm[obj.type][obj.state](obj);
|
||||
//if(JSON.parse(message.toString()).type == 'OTA_INIT'){
|
||||
// client.publish('/down/wirelos', JSON.stringify(dataMsg));
|
||||
//}
|
||||
client.end();
|
||||
})
|
||||
return client;
|
||||
};
|
||||
|
||||
upload(filePath);
|
||||
488
tools/package-lock.json
generated
Normal file
488
tools/package-lock.json
generated
Normal file
@@ -0,0 +1,488 @@
|
||||
{
|
||||
"name": "tools",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"async-limiter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
|
||||
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"bl": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||
"requires": {
|
||||
"readable-stream": "2.3.6",
|
||||
"safe-buffer": "5.1.2"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"requires": {
|
||||
"balanced-match": "1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
|
||||
"integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ=="
|
||||
},
|
||||
"callback-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callback-stream/-/callback-stream-1.1.0.tgz",
|
||||
"integrity": "sha1-RwGlEmbwbgbqpx/BcjOCLYdfSQg=",
|
||||
"requires": {
|
||||
"inherits": "2.0.3",
|
||||
"readable-stream": "2.3.6"
|
||||
}
|
||||
},
|
||||
"commist": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/commist/-/commist-1.0.0.tgz",
|
||||
"integrity": "sha1-wMNSUBz29S6RJOPvicmAbiAi6+8=",
|
||||
"requires": {
|
||||
"leven": "1.0.2",
|
||||
"minimist": "1.2.0"
|
||||
}
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"requires": {
|
||||
"buffer-from": "1.1.0",
|
||||
"inherits": "2.0.3",
|
||||
"readable-stream": "2.3.6",
|
||||
"typedarray": "0.0.6"
|
||||
}
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"duplexify": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz",
|
||||
"integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==",
|
||||
"requires": {
|
||||
"end-of-stream": "1.4.1",
|
||||
"inherits": "2.0.3",
|
||||
"readable-stream": "2.3.6",
|
||||
"stream-shift": "1.0.0"
|
||||
}
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
||||
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
|
||||
"requires": {
|
||||
"once": "1.4.0"
|
||||
}
|
||||
},
|
||||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
"inflight": "1.0.6",
|
||||
"inherits": "2.0.3",
|
||||
"minimatch": "3.0.4",
|
||||
"once": "1.4.0",
|
||||
"path-is-absolute": "1.0.1"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
|
||||
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
|
||||
"requires": {
|
||||
"is-glob": "3.1.0",
|
||||
"path-dirname": "1.0.2"
|
||||
}
|
||||
},
|
||||
"glob-stream": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
|
||||
"integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=",
|
||||
"requires": {
|
||||
"extend": "3.0.2",
|
||||
"glob": "7.1.2",
|
||||
"glob-parent": "3.1.0",
|
||||
"is-negated-glob": "1.0.0",
|
||||
"ordered-read-streams": "1.0.1",
|
||||
"pumpify": "1.5.1",
|
||||
"readable-stream": "2.3.6",
|
||||
"remove-trailing-separator": "1.1.0",
|
||||
"to-absolute-glob": "2.0.2",
|
||||
"unique-stream": "2.2.1"
|
||||
}
|
||||
},
|
||||
"help-me": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/help-me/-/help-me-1.1.0.tgz",
|
||||
"integrity": "sha1-jy1QjQYAtKRW2i8IZVbn5cBWo8Y=",
|
||||
"requires": {
|
||||
"callback-stream": "1.1.0",
|
||||
"glob-stream": "6.1.0",
|
||||
"through2": "2.0.3",
|
||||
"xtend": "4.0.1"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"requires": {
|
||||
"once": "1.4.0",
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"is-absolute": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
|
||||
"integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
|
||||
"requires": {
|
||||
"is-relative": "1.0.0",
|
||||
"is-windows": "1.0.2"
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
|
||||
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
|
||||
"requires": {
|
||||
"is-extglob": "2.1.1"
|
||||
}
|
||||
},
|
||||
"is-negated-glob": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
|
||||
"integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI="
|
||||
},
|
||||
"is-relative": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
|
||||
"integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
|
||||
"requires": {
|
||||
"is-unc-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"is-unc-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
|
||||
"integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
|
||||
"requires": {
|
||||
"unc-path-regex": "0.1.2"
|
||||
}
|
||||
},
|
||||
"is-windows": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
|
||||
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"json-stable-stringify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
|
||||
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
|
||||
"requires": {
|
||||
"jsonify": "0.0.0"
|
||||
}
|
||||
},
|
||||
"jsonify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
|
||||
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
|
||||
},
|
||||
"leven": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz",
|
||||
"integrity": "sha1-kUS27ryl8dBoAWnxpncNzqYLdcM="
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"requires": {
|
||||
"brace-expansion": "1.1.11"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||
},
|
||||
"mqtt": {
|
||||
"version": "2.18.3",
|
||||
"resolved": "https://registry.npmjs.org/mqtt/-/mqtt-2.18.3.tgz",
|
||||
"integrity": "sha512-BXCUugFgA6FOWJGxhvUWtVLOdt6hYTmiMGPksEyKuuF1FQ0ji7UJBJ/0kVRMUtUWCAtPGnt4mZZZgJpzNLcuQg==",
|
||||
"requires": {
|
||||
"commist": "1.0.0",
|
||||
"concat-stream": "1.6.2",
|
||||
"end-of-stream": "1.4.1",
|
||||
"help-me": "1.1.0",
|
||||
"inherits": "2.0.3",
|
||||
"minimist": "1.2.0",
|
||||
"mqtt-packet": "5.6.0",
|
||||
"pump": "3.0.0",
|
||||
"readable-stream": "2.3.6",
|
||||
"reinterval": "1.1.0",
|
||||
"split2": "2.2.0",
|
||||
"websocket-stream": "5.1.2",
|
||||
"xtend": "4.0.1"
|
||||
}
|
||||
},
|
||||
"mqtt-packet": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-5.6.0.tgz",
|
||||
"integrity": "sha512-QECe2ivqcR1LRsPobRsjenEKAC3i1a5gmm+jNKJLrsiq9PaSQ18LlKFuxvhGxWkvGEPadWv6rKd31O4ICqS1Xw==",
|
||||
"requires": {
|
||||
"bl": "1.2.2",
|
||||
"inherits": "2.0.3",
|
||||
"process-nextick-args": "2.0.0",
|
||||
"safe-buffer": "5.1.2"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"requires": {
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"ordered-read-streams": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
|
||||
"integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=",
|
||||
"requires": {
|
||||
"readable-stream": "2.3.6"
|
||||
}
|
||||
},
|
||||
"path-dirname": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
|
||||
"integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
|
||||
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
|
||||
},
|
||||
"pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"requires": {
|
||||
"end-of-stream": "1.4.1",
|
||||
"once": "1.4.0"
|
||||
}
|
||||
},
|
||||
"pumpify": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
|
||||
"integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
|
||||
"requires": {
|
||||
"duplexify": "3.6.0",
|
||||
"inherits": "2.0.3",
|
||||
"pump": "2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"pump": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
|
||||
"integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
|
||||
"requires": {
|
||||
"end-of-stream": "1.4.1",
|
||||
"once": "1.4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"requires": {
|
||||
"core-util-is": "1.0.2",
|
||||
"inherits": "2.0.3",
|
||||
"isarray": "1.0.0",
|
||||
"process-nextick-args": "2.0.0",
|
||||
"safe-buffer": "5.1.2",
|
||||
"string_decoder": "1.1.1",
|
||||
"util-deprecate": "1.0.2"
|
||||
}
|
||||
},
|
||||
"reinterval": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz",
|
||||
"integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc="
|
||||
},
|
||||
"remove-trailing-separator": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||
},
|
||||
"split2": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz",
|
||||
"integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==",
|
||||
"requires": {
|
||||
"through2": "2.0.3"
|
||||
}
|
||||
},
|
||||
"stream-shift": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
|
||||
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.2"
|
||||
}
|
||||
},
|
||||
"through2": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
|
||||
"integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
|
||||
"requires": {
|
||||
"readable-stream": "2.3.6",
|
||||
"xtend": "4.0.1"
|
||||
}
|
||||
},
|
||||
"through2-filter": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz",
|
||||
"integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=",
|
||||
"requires": {
|
||||
"through2": "2.0.3",
|
||||
"xtend": "4.0.1"
|
||||
}
|
||||
},
|
||||
"to-absolute-glob": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
|
||||
"integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
|
||||
"requires": {
|
||||
"is-absolute": "1.0.0",
|
||||
"is-negated-glob": "1.0.0"
|
||||
}
|
||||
},
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||
},
|
||||
"ultron": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
|
||||
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
|
||||
},
|
||||
"unc-path-regex": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
|
||||
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo="
|
||||
},
|
||||
"unique-stream": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz",
|
||||
"integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=",
|
||||
"requires": {
|
||||
"json-stable-stringify": "1.0.1",
|
||||
"through2-filter": "2.0.0"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"websocket-stream": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-5.1.2.tgz",
|
||||
"integrity": "sha512-lchLOk435iDWs0jNuL+hiU14i3ERSrMA0IKSiJh7z6X/i4XNsutBZrtqu2CPOZuA4G/zabiqVAos0vW+S7GEVw==",
|
||||
"requires": {
|
||||
"duplexify": "3.6.0",
|
||||
"inherits": "2.0.3",
|
||||
"readable-stream": "2.3.6",
|
||||
"safe-buffer": "5.1.2",
|
||||
"ws": "3.3.3",
|
||||
"xtend": "4.0.1"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"ws": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
|
||||
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
|
||||
"requires": {
|
||||
"async-limiter": "1.0.0",
|
||||
"safe-buffer": "5.1.2",
|
||||
"ultron": "1.1.1"
|
||||
}
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
|
||||
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
|
||||
}
|
||||
}
|
||||
}
|
||||
13
tools/package.json
Normal file
13
tools/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "tools",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mqtt": "^2.18.3"
|
||||
}
|
||||
}
|
||||
45
tools/tcp_example.js
Normal file
45
tools/tcp_example.js
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
In the node.js intro tutorial (http://nodejs.org/), they show a basic tcp
|
||||
server, but for some reason omit a client connecting to it. I added an
|
||||
example at the bottom.
|
||||
Save the following server in example.js:
|
||||
*/
|
||||
|
||||
var net = require('net');
|
||||
|
||||
var server = net.createServer(function(socket) {
|
||||
socket.write('Echo server\r\n');
|
||||
socket.pipe(socket);
|
||||
});
|
||||
|
||||
server.listen(1337, '127.0.0.1');
|
||||
|
||||
/*
|
||||
And connect with a tcp client from the command line using netcat, the *nix
|
||||
utility for reading and writing across tcp/udp network connections. I've only
|
||||
used it for debugging myself.
|
||||
$ netcat 127.0.0.1 1337
|
||||
You should see:
|
||||
> Echo server
|
||||
*/
|
||||
|
||||
/* Or use this example tcp client written in node.js. (Originated with
|
||||
example code from
|
||||
http://www.hacksparrow.com/tcp-socket-programming-in-node-js.html.) */
|
||||
|
||||
var net = require('net');
|
||||
|
||||
var client = new net.Socket();
|
||||
client.connect(1337, '127.0.0.1', function() {
|
||||
console.log('Connected');
|
||||
client.write('Hello, server! Love, Client.');
|
||||
});
|
||||
|
||||
client.on('data', function(data) {
|
||||
console.log('Received: ' + data);
|
||||
client.destroy(); // kill client after server's response
|
||||
});
|
||||
|
||||
client.on('close', function() {
|
||||
console.log('Connection closed');
|
||||
});
|
||||
Reference in New Issue
Block a user