Resolve "OTA"

This commit is contained in:
Patrick Balsiger
2018-08-03 11:01:42 +00:00
parent 18ccf6a892
commit dbb4ce9de7
18 changed files with 895 additions and 17 deletions

3
.gitignore vendored
View File

@@ -2,4 +2,5 @@
.piolibdeps .piolibdeps
.vscode/.browse.c_cpp.db* .vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
tools/node_modules

View File

@@ -7,5 +7,9 @@ A sprocket is a device that has a single purpose, for example a PIR sensor node
# Useful commands # Useful commands
```sh ```sh
# erase flash # 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
``` ```

View File

@@ -8,8 +8,8 @@
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; http://docs.platformio.org/page/projectconf.html ; http://docs.platformio.org/page/projectconf.html
;[platformio] [platformio]
;env_default = mesh env_default = mesh
[common] [common]
framework = arduino framework = arduino
@@ -21,19 +21,16 @@ lib_deps =
Hash Hash
ESPAsyncTCP ESPAsyncTCP
TaskScheduler TaskScheduler
SPIFFS
;[env:build] ;[env:build]
;src_filter = +<*> -<examples/> ;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} ;platform = ${common.platform}
;board = ${common.board} ;board = ${common.board}
;upload_speed = ${common.upload_speed} ;upload_speed = ${common.upload_speed}
;monitor_baud = ${common.monitor_baud} ;monitor_baud = ${common.monitor_baud}
;framework = ${common.framework} ;framework = ${common.framework}
;lib_deps = ${common.lib_deps} ;lib_deps = ${common.lib_deps}
;build_flags = -DLED_PIN=2 -g ;build_flags = -DLED_PIN=2 -g
;upload_port = /dev/ttyUSB0 ;upload_port = /dev/ttyUSB0
;upload_port = 192.168.1.168 ;upload_port = 192.168.1.168
@@ -66,4 +63,16 @@ monitor_baud = ${common.monitor_baud}
framework = ${common.framework} framework = ${common.framework}
lib_deps = ${common.lib_deps} lib_deps = ${common.lib_deps}
painlessMesh painlessMesh
PubSubClient 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

View File

@@ -15,15 +15,18 @@ Network* MeshNet::init(){
mesh.onChangedConnections(bind(&MeshNet::changedConnectionCallback, this)); mesh.onChangedConnections(bind(&MeshNet::changedConnectionCallback, this));
mesh.onNodeTimeAdjusted(bind(&MeshNet::nodeTimeAdjustedCallback, this, _1)); mesh.onNodeTimeAdjusted(bind(&MeshNet::nodeTimeAdjustedCallback, this, _1));
connectStation();
return this;
}
Network* MeshNet::connectStation() {
if(config.stationMode){ if(config.stationMode){
Serial.println("connect station"); Serial.println("connect station");
mesh.stationManual(config.stationSSID, config.stationPassword); mesh.stationManual(config.stationSSID, config.stationPassword);
mesh.setHostname(config.hostname); mesh.setHostname(config.hostname);
} }
return this; return this;
} }
void MeshNet::sendTo(uint32_t target, String msg){ void MeshNet::sendTo(uint32_t target, String msg){
mesh.sendSingle(target, msg); mesh.sendSingle(target, msg);
} }

View File

@@ -1,6 +1,12 @@
#ifndef __MESHNET_H__ #ifndef __MESHNET_H__
#define __MESHNET_H__ #define __MESHNET_H__
#ifdef ESP32
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#endif // ESP32
#include <painlessMesh.h> #include <painlessMesh.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include "Network.h" #include "Network.h"
@@ -8,6 +14,7 @@
using namespace std; using namespace std;
using namespace std::placeholders; using namespace std::placeholders;
// FIXME non-mesh config should have it's own struct
struct MeshConfig { struct MeshConfig {
int stationMode; int stationMode;
int channel; int channel;
@@ -27,14 +34,18 @@ class MeshNet : public Network {
MeshNet(MeshConfig cfg); MeshNet(MeshConfig cfg);
Network* init(); Network* init();
Network* connectStation();
void update(); // only needed when no scheduler was passed to mesh.init
void update();
void newConnectionCallback(uint32_t nodeId); void newConnectionCallback(uint32_t nodeId);
void changedConnectionCallback(); void changedConnectionCallback();
void nodeTimeAdjustedCallback(int32_t offset); void nodeTimeAdjustedCallback(int32_t offset);
void broadcast(String msg); void broadcast(String msg);
void sendTo(uint32_t target, String msg); void sendTo(uint32_t target, String msg);
void onReceive(std::function<void(uint32_t from, String &msg)>); void onReceive(std::function<void(uint32_t from, String &msg)>);
int isConnected(){
return WiFi.status() == WL_CONNECTED;
}
}; };
#endif #endif

View File

@@ -14,6 +14,8 @@ class Network {
virtual Network* init() { return this; }; virtual Network* init() { return this; };
virtual Network* init(Scheduler* s) { scheduler = s; return init(); }; virtual Network* init(Scheduler* s) { scheduler = s; return init(); };
virtual Network* connect() { return this; }; virtual Network* connect() { return this; };
virtual Network* connectStation() { return this; };
virtual int isConnected(){ return 0; };
virtual void update() {}; virtual void update() {};
virtual void broadcast(String msg){}; virtual void broadcast(String msg){};
virtual void sendTo(uint32_t target, String msg) {}; virtual void sendTo(uint32_t target, String msg) {};

74
src/OtaTcpPlugin.cpp Normal file
View 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
View 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

View File

@@ -3,7 +3,10 @@
#include <TaskSchedulerDeclarations.h> #include <TaskSchedulerDeclarations.h>
#include <Arduino.h> #include <Arduino.h>
#include <FS.h> #include "FS.h"
#ifdef ESP32
#include "SPIFFS.h"
#endif
#include "Network.h" #include "Network.h"
using namespace std; using namespace std;
@@ -31,6 +34,7 @@ class Sprocket {
virtual Sprocket* activate(); virtual Sprocket* activate();
virtual Sprocket* activate(Scheduler*) { return this; } virtual Sprocket* activate(Scheduler*) { return this; }
virtual Sprocket* activate(Scheduler*, Network*) { return this; } virtual Sprocket* activate(Scheduler*, Network*) { return this; }
virtual Sprocket* enable() { return this; };
// TODO bind onMessage to network->onReceive // TODO bind onMessage to network->onReceive
//virtual void onMessage(uint32_t from, String &msg) {}; //virtual void onMessage(uint32_t from, String &msg) {};
}; };

View File

@@ -18,6 +18,7 @@
#define STATION_SSID "Th1ngs4P" #define STATION_SSID "Th1ngs4P"
#define STATION_PASSWORD "th3r31sn0sp00n" #define STATION_PASSWORD "th3r31sn0sp00n"
#define HOSTNAME "mesh-node" #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 #endif

View File

@@ -13,7 +13,7 @@
#define STATION_MODE 1 #define STATION_MODE 1
#define WIFI_CHANNEL 11 #define WIFI_CHANNEL 11
#define MESH_PORT 5555 #define MESH_PORT 5555
#define MESH_PREFIX "WirelosContraption" #define MESH_PREFIX "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky" #define MESH_PASSWORD "somethingSneaky"
#define STATION_SSID "Th1ngs4P" #define STATION_SSID "Th1ngs4P"
#define STATION_PASSWORD "th3r31sn0sp00n" #define STATION_PASSWORD "th3r31sn0sp00n"
@@ -22,7 +22,7 @@
// Bridge config // Bridge config
#define MQTT_CLIENT_NAME HOSTNAME #define MQTT_CLIENT_NAME HOSTNAME
#define MQTT_BROKER "iot.eclipse.org" #define MQTT_BROKER "citadel.lan"
#define MQTT_PORT 1883 #define MQTT_PORT 1883
#define MQTT_TOPIC_ROOT "mesh" #define MQTT_TOPIC_ROOT "mesh"

View 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
View 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
View 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
View 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
View 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
View 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
View 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');
});