basic mqtt plugin

This commit is contained in:
2018-11-15 11:36:19 +01:00
commit accd942c34
10 changed files with 489 additions and 0 deletions

78
.gitignore vendored Normal file
View File

@@ -0,0 +1,78 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# platformio / IDE
.pioenvs
.piolibdeps
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
# build stuff
/data/
dist/
# sprocket stuff
/config/
/firmware
.clang_complete
.gcc-flags.json
.pioenvs
.piolibdeps

38
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,38 @@
image: python:2.7-stretch
# This folder is cached between builds
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
cache:
paths:
- firmware
stages:
- test
- build
before_script:
- "pip install -U platformio"
#firmware-test:
# stage: test
# script: "pio ci --board=esp12e"
# variables: {PLATFORMIO_CI_SRC: "test.cpp"}
firmware-build:
stage: build
image: python:2.7-stretch
script:
- pio run -t clean
- pio run
artifacts:
paths:
- .pioenvs/*/firmware.*
- .pioenvs/*/spiffs.bin
#pack:
# stage: deploy
# script:
# - yarn install
# - yarn pack
# artifacts:
# paths:
# - ./*.tgz

67
.travis.yml Normal file
View File

@@ -0,0 +1,67 @@
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < http://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < http://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < http://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choice one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to by used as a library with examples
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

7
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

6
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"terminal.integrated.env.linux": {
"PATH": "/home/master/.platformio/penv/bin:/home/master/.platformio/penv:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl",
"PLATFORMIO_CALLER": "vscode"
}
}

41
lib/readme.txt Normal file
View File

@@ -0,0 +1,41 @@
This directory is intended for the project specific (private) libraries.
PlatformIO will compile them to static libraries and link to executable file.
The source code of each library should be placed in separate directory, like
"lib/private_lib/[here are source files]".
For example, see how can be organized `Foo` and `Bar` libraries:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) http://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- readme.txt --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
Then in `src/main.c` you should use:
#include <Foo.h>
#include <Bar.h>
// rest H/C/CPP code
PlatformIO will find your libraries automatically, configure preprocessor's
include paths and build them.
More information about PlatformIO Library Dependency Finder
- http://docs.platformio.org/page/librarymanager/ldf.html

30
platformio.ini Normal file
View File

@@ -0,0 +1,30 @@
[platformio]
env_default = basic
[common]
framework = arduino
platform = espressif8266
board = esp12e
upload_speed = 921600
monitor_baud = 115200
lib_deps =
Hash
TaskScheduler
SPIFFS
ArduinoJson
ArduinoOTA
ESPAsyncTCP
ESP8266mDNS
ESP Async WebServer
painlessMesh
https://gitlab.com/wirelos/sprocket-lib.git#develop
[env:basic]
src_filter = +<*> -<examples/> +<examples/basic/>
platform = ${common.platform}
board = ${common.board}
upload_speed = ${common.upload_speed}
monitor_baud = ${common.monitor_baud}
framework = ${common.framework}
lib_deps = ${common.lib_deps}
PubSubClient

150
src/MqttPlugin.cpp Normal file
View File

@@ -0,0 +1,150 @@
#ifndef __MQTT_PLUGIN__
#define __MQTT_PLUGIN__
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STD_FUNCTION
#include <WiFiClient.h>
#include <PubSubClient.h>
#include <Plugin.h>
using namespace std;
using namespace std::placeholders;
struct MqttConfig
{
const char *clientName;
const char *brokerHost;
int brokerPort;
const char *inTopicRoot;
const char *outTopicRoot;
};
class MqttPlugin : public Plugin
{
public:
PubSubClient *client;
WiFiClient wifiClient;
Task connectTask;
Task processTask;
MqttConfig mqttConfig;
vector<String> topics;
MqttPlugin(MqttConfig cfg)
{
mqttConfig = cfg;
//subscribe("mqtt/out", bind(&MqttPlugin::mqttPublish, this, _1));
}
void activate(Scheduler *scheduler)
{
client = new PubSubClient(mqttConfig.brokerHost, mqttConfig.brokerPort, bind(&MqttPlugin::downstreamHandler, this, _1, _2, _3), wifiClient);
enableConnectTask(scheduler);
enableProcessTask(scheduler);
Serial.println("MQTT plugin activated"); // FIXME use PRINT_MSG
}
private:
void enableConnectTask(Scheduler *scheduler)
{
connectTask.set(TASK_SECOND * 5, TASK_FOREVER, bind(&MqttPlugin::connect, this));
scheduler->addTask(connectTask);
connectTask.enable();
}
void enableProcessTask(Scheduler *scheduler)
{
processTask.set(TASK_MILLISECOND * 5, TASK_FOREVER, bind(&MqttPlugin::process, this));
scheduler->addTask(processTask);
processTask.enable();
}
void process()
{
client->loop();
}
void connect()
{
if (!client->connected())
{
Serial.println("MQTT try connect");
if (client->connect(mqttConfig.clientName))
{
Serial.println("MQTT connected");
upstreamHandler("lobby", "join");
// overkill to subscribe to all...?
for (auto const &localSub : mediator->subscriptions)
{
subscribe(localSub.first.c_str(), bind(&MqttPlugin::upstreamHandler, this, localSub.first.c_str(), _1));
client->subscribe(
(String(mqttConfig.inTopicRoot) + String(localSub.first.c_str()))
.c_str());
}
}
}
else
{
publish("local/topic", "Free heap: " + String(ESP.getFreeHeap()));
}
}
void mqttPublish(String msg)
{
client->publish(mqttConfig.outTopicRoot, msg.c_str());
}
void upstreamHandler(String topic, String msg)
{
Serial.println(msg);
// publish message on remote queue
// TODO rootTopic + topic?
client->publish((String(mqttConfig.outTopicRoot) + topic).c_str(), msg.c_str());
}
void downstreamHandler(char *topic, uint8_t *payload, unsigned int length)
{
char *cleanPayload = (char *)malloc(length + 1);
payload[length] = '\0';
memcpy(cleanPayload, payload, length + 1);
String msg = String(cleanPayload);
free(cleanPayload);
Serial.println("MQTT topic " + String(topic));
Serial.println("MQTT msg " + msg);
int topicRootLength = String(mqttConfig.inTopicRoot).length();
String localTopic = String(topic).substring(topicRootLength);
Serial.println("Local topic:" + localTopic);
// publish message to local subscribers on device
publish(localTopic, msg);
}
/* void mqttCallback(char* topic, uint8_t* payload, unsigned int length) {
char* cleanPayload = (char*)malloc(length+1);
payload[length] = '\0';
memcpy(cleanPayload, payload, length+1);
String msg = String(cleanPayload);
free(cleanPayload);
int topicRootLength = String(mqttConfig.topicRoot).length();
String targetStr = String(topic).substring(topicRootLength + 4);
if(targetStr == "gateway"){
if(msg == "getNodes") {
client->publish(MQTT_TOPIC_FROM_GATEWAY, net->mesh.subConnectionJson().c_str());
}
} else if(targetStr == "broadcast") {
net->mesh.sendBroadcast(msg);
} else {
uint32_t target = strtoul(targetStr.c_str(), NULL, 10);
if(net->mesh.isConnected(target)){
net->mesh.sendSingle(target, msg);
} else {
client->publish(MQTT_TOPIC_FROM_GATEWAY, "Client not connected!");
}
}
} */
};
#endif

View File

@@ -0,0 +1,36 @@
#ifndef __DEVICE_CONFIG__
#define __DEVICE_CONFIG__
// Scheduler config
#define _TASK_SLEEP_ON_IDLE_RUN
#define _TASK_STD_FUNCTION
#define _TASK_PRIORITY
// Chip config
#define SPROCKET_TYPE "SPROCKET"
#define SERIAL_BAUD_RATE 115200
#define STARTUP_DELAY 1000
// network config
#define SPROCKET_MODE 1
#define WIFI_CHANNEL 11
#define MESH_PORT 5555
#define AP_SSID "sprocket"
#define AP_PASSWORD "th3r31sn0sp00n"
#define MESH_PREFIX "sprocket-mesh"
#define MESH_PASSWORD "th3r31sn0sp00n"
#define STATION_SSID "MyAP"
#define STATION_PASSWORD "th3r31sn0sp00n"
#define HOSTNAME "sprocket"
#define CONNECT_TIMEOUT 10000
#define MESH_DEBUG_TYPES ERROR | STARTUP | CONNECTION
//#define MESH_DEBUG_TYPES ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE
// WebServer
#define WEB_CONTEXT_PATH "/"
#define WEB_DOC_ROOT "/www"
#define WEB_DEFAULT_FILE "index.html"
#define WEB_PORT 80
#endif

View File

@@ -0,0 +1,36 @@
#include "config.h"
#include "WiFiNet.h"
#include "Sprocket.h"
#include "MqttPlugin.cpp"
WiFiNet *network;
Sprocket *sprocket;
void setup()
{
sprocket = new Sprocket(
{STARTUP_DELAY, SERIAL_BAUD_RATE});
sprocket->subscribe("local/topic", [](String msg){
Serial.println("Received: " + msg);
});
sprocket->addPlugin(
new MqttPlugin({"sprocket", "192.168.1.2", 1883, "wirelos/mqttSprocket-in/", "wirelos/mqttSprocket-out/"}));
network = new WiFiNet(
SPROCKET_MODE,
STATION_SSID,
STATION_PASSWORD,
AP_SSID,
AP_PASSWORD,
HOSTNAME,
CONNECT_TIMEOUT);
network->connect();
sprocket->activate();
}
void loop()
{
sprocket->loop();
yield();
}