MQTT at least talks to server, works in native and esp32

1.2-legacy
Kevin Hester 2021-04-03 14:54:10 +08:00
rodzic 2acde3333c
commit dcf64dfacd
16 zmienionych plików z 267 dodań i 46 usunięć

Wyświetl plik

@ -15,7 +15,15 @@
<component name="ChangeListManager">
<list default="true" id="58922733-b05b-4b90-9655-b9b18914977a" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/docs/software/TODO.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/software/TODO.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/docs/software/mqtt.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/software/mqtt.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/platformio.ini" beforeDir="false" afterPath="$PROJECT_DIR$/platformio.ini" afterDir="false" />
<change beforePath="$PROJECT_DIR$/proto" beforeDir="false" afterPath="$PROJECT_DIR$/proto" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main.cpp" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.cpp" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/mesh/generated/admin.pb.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/generated/admin.pb.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/mesh/generated/apponly.pb.c" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/generated/apponly.pb.c" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/mesh/generated/apponly.pb.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/generated/apponly.pb.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/mesh/generated/radioconfig.pb.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/generated/radioconfig.pb.h" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -47,6 +55,11 @@
<property name="settings.editor.selected.configurable" value="CMakeSettings" />
</component>
<component name="RunManager" selected="GDB Remote Debug.gdbremote-localhost-2345">
<configuration default="true" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true">
<method v="2">
<option name="CLION.EXTERNAL.BUILD" enabled="true" />
</method>
</configuration>
<configuration default="true" type="CLion_Remote" version="1" remoteCommand="tcp:localhost:2345" symbolFile="" sysroot="">
<debugger kind="GDB" isBundled="true" />
<method v="2" />
@ -60,9 +73,9 @@
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration default="true" type="GradleAppRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true">
<configuration default="true" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true">
<method v="2">
<option name="com.jetbrains.cidr.cpp.gradle.execution.GradleNativeBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration name="PlatformIO Debug" type="platformio" factoryName="PlatformIO Debug" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Debug" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Debug">
@ -98,6 +111,7 @@
<workItem from="1617117632667" duration="307000" />
<workItem from="1617160691713" duration="1016000" />
<workItem from="1617279002260" duration="1626000" />
<workItem from="1617425689081" duration="1896000" />
</task>
<servers />
</component>
@ -129,6 +143,11 @@
<line>37</line>
<option name="timeStamp" value="7" />
</line-breakpoint>
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
<url>file://$USER_HOME$/.platformio/packages/framework-portduino/libraries/WiFi/src/WiFiClient.cpp</url>
<line>49</line>
<option name="timeStamp" value="9" />
</line-breakpoint>
</breakpoints>
</breakpoint-manager>
<watches-manager>

Wyświetl plik

@ -0,0 +1 @@
mosquitto_sub -h test.mosquitto.org -v -t mstat/\# -t mesh/\#

Wyświetl plik

@ -0,0 +1 @@
mosquitto_pub -h test.mosquitto.org -t mstat/FakeNode -m online -d

Wyświetl plik

@ -53,11 +53,22 @@ You probably don't care about this section - skip to the next one.
## MQTT
* DONE have sim provide a fake wifi connection status saying connected
* DONE don't start MQTT if we don't have wifi connected
* mqtt.meshtastic.org should have VERY basic auth at launch (to prevent abuse)
* use MQTT for simulator mesh network
* make a GlobalChat channel as an initial test (with a well known AES128 key), figure out how globally unique IDs work
* Give place in android app for users to select which channel they are sending on (and which channels they are watching)
* attempt reconnect to server if internet connectivity changes
* don't bother contacting server if we don't have any uplink/downlink channels
* test on ESP32
* no need for python gateway to web initially: because both the simulator and ESP32 can talk wifi directly
* if simmesh_name is set in preferences, create the MQTTSimInterface using that as the global channel_id
* figure out how to use MQTT for simulator mesh network, use a special simmesh_name global channel_id? (because this would allow all nodes in simnet_xxx to subscribe only to those packets)
* do initial development inside of portduino
* do as much possible on the device side (so we can eventually just have ESP32 talk directly to server)
* add mqtt_server to radio prefs
* eventually add a MQTTPacket on the ToRadio & FromRadio links
* LATER: an android gateway would be useful
## Multichannel support

Wyświetl plik

@ -12,7 +12,9 @@
- [NODEID](#nodeid)
- [USERID](#userid)
- [CHANNELID](#channelid)
- [PORTID](#portid)
- [Gateway nodes](#gateway-nodes)
- [MQTTSimInterface](#mqttsiminterface)
- [Optional web services](#optional-web-services)
- [Public MQTT broker service](#public-mqtt-broker-service)
- [Riot.im messaging bridge](#riotim-messaging-bridge)
@ -68,17 +70,19 @@ Any gateway-device will contact the MQTT broker.
### Topics
The "mesh/crypt/CHANNELID/NODEID/PORTID" [topic](https://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices/) will be used for messages sent from/to a mesh.
* The "/mesh/crypt/CHANNELID/NODEID/PORTID" [topic](https://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices/) will be used for messages sent from/to a mesh.
Gateway nodes will foward any MeshPacket from a local mesh channel with uplink_enabled. The packet (encapsulated in a ServiceEnvelope) will remain encrypted with the key for the specified channel.
For any channels in the local node with downlink_enabled, the gateway node will forward packets from MQTT to the local mesh. It will do this by subscribing to mesh/crypt/CHANNELID/# and forwarding relevant packets.
For any channels in the gateway node with downlink_enabled, the gateway node will forward packets from MQTT to the local mesh. It will do this by subscribing to mesh/crypt/CHANNELID/# and forwarding relevant packets.
If the channelid 'well known'/public it could be decrypted by a web service (if the web service was provided with the associated channel key), in which case it will be decrypted by a web service and appear at "mesh/clear/CHANNELID/NODEID/PORTID". Note: This is not in the initial deliverable.
FIXME, discuss how text message global mirroring could scale (or not)
FIXME, consider how text message global mirroring could scale (or not)
FIXME, possibly don't global mirror text messages - instead rely on matrix/riot?
FIXME, discuss possible attacks by griefers and how they can be prvented
FIXME, consider possible attacks by griefers and how they can be prvented
* The "/mstat/NODEID" topic contains a simple string showing connection status of nodes. We rely on the MQTT feature for automatically publishing special failrue messages to this topic when the device disconnects.
#### Service Envelope
@ -88,7 +92,7 @@ ServiceEnvelope will include the message, and full information about arrival tim
#### NODEID
The unique ID for a node. A hex string that starts with a ! symbol.
The unique ID for a node. A 8 byte (16 character) hex string that starts with a ! symbol.
#### USERID
@ -96,7 +100,15 @@ A user ID string. This string is either a user ID if known or a nodeid to simply
#### CHANNELID
FIXME, figure out how channelids work
For the time being we simply use the local "channel name" - which is not quite good enough.
FIXME, figure out how channelids work in more detail. They should generally be globally unique, but this is not a requirement. If someone accidentially (or maliciously) sends data using a channel ID they do not 'own' they will still lacking a valid AES256 encryption, so it will be ignored by others.
idea to be pondered: When the user clicks to enable uplink/downlink check the name they entered and 'claim' it on the server?
#### PORTID
Portid is used to descriminated between different packet types which are sent over a channel. As used here it is an integer typically (but not necessarily) chosen from portnums.proto.
### Gateway nodes
@ -107,6 +119,17 @@ Gateway nodes (via code running in the phone) will contain two tables to whiteli
Since multiple gateway nodes might be connected to a single mesh, it is possible that duplicate messages will be published on any particular topic. Therefore subscribers to these topics should
deduplicate if needed by using the packet ID of each message.
### MQTTSimInterface
This is a bit orthogonal from the main MQTT feature set, but a special simulated LoRa interface called MQTTSimInterface uses the
MQTT messaging infrastructure to send "LoRa" packets between simulated nodes running on Linux. This allows us to test radio topologies and code without having to use real hardware.
This service uses the standard mesh/crypt/... topic, but it picks a special CHANNEL_ID. That CHANNEL_ID is typcially of the form "simmesh_xxx".
FIXME: Figure out how to secure the creation and use of well known CHANNEL_IDs.
### Optional web services
#### Public MQTT broker service

Wyświetl plik

@ -9,7 +9,7 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = tbeam
;default_envs = tbeam
;default_envs = tbeam0.7
;default_envs = heltec
;default_envs = tlora-v1
@ -18,7 +18,7 @@ default_envs = tbeam
;default_envs = lora-relay-v1 # nrf board
;default_envs = eink
;default_envs = nrf52840dk-geeksville
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
[common]
; common is not currently used
@ -76,6 +76,7 @@ lib_deps =
Wire ; explicitly needed here because the AXP202 library forgets to add it
SPI
https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
PubSubClient
; Common settings for conventional (non Portduino) Ardino targets
[arduino_base]
@ -202,7 +203,7 @@ build_flags =
-Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7
;-DCFG_DEBUG=3
src_filter =
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<plugins/esp32>
${arduino_base.src_filter} -<esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<plugins/esp32> -<mqtt/>
lib_ignore =
BluetoothOTA
monitor_port = /dev/ttyACM1

2
proto

@ -1 +1 @@
Subproject commit 2aa14392145c38476bf61fea2c43629e1973af6d
Subproject commit 9c16118e59e7318cd8cb92199511c19232939f5f

Wyświetl plik

@ -32,8 +32,9 @@
#include "nimble/BluetoothUtil.h"
#endif
#ifdef PORTDUINO
#if defined(HAS_WIFI) || defined(PORTDUINO)
#include "mesh/wifi/WiFiServerAPI.h"
#include "mqtt/MQTT.h"
#endif
#include "RF95Interface.h"
@ -541,6 +542,10 @@ void setup()
initApiServer();
#endif
#if defined(PORTDUINO) || defined(HAS_WIFI)
mqttInit();
#endif
// Start airtime logger thread.
airTime = new AirTime();

Wyświetl plik

@ -79,7 +79,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
#define AdminMessage_fields &AdminMessage_msg
/* Maximum encoded size of messages (where known) */
#define AdminMessage_size 360
#define AdminMessage_size 397
#ifdef __cplusplus
} /* extern "C" */

Wyświetl plik

@ -6,9 +6,6 @@
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(ServiceEnvelope, ServiceEnvelope, 2)
PB_BIND(ChannelSet, ChannelSet, AUTO)

Wyświetl plik

@ -4,7 +4,6 @@
#ifndef PB_APPONLY_PB_H_INCLUDED
#define PB_APPONLY_PB_H_INCLUDED
#include <pb.h>
#include "mesh.pb.h"
#include "channel.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
@ -16,54 +15,31 @@ typedef struct _ChannelSet {
pb_callback_t settings;
} ChannelSet;
typedef struct _ServiceEnvelope {
bool has_packet;
MeshPacket packet;
pb_callback_t channel_id;
pb_callback_t gateway_id;
} ServiceEnvelope;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define ServiceEnvelope_init_default {false, MeshPacket_init_default, {{NULL}, NULL}, {{NULL}, NULL}}
#define ChannelSet_init_default {{{NULL}, NULL}}
#define ServiceEnvelope_init_zero {false, MeshPacket_init_zero, {{NULL}, NULL}, {{NULL}, NULL}}
#define ChannelSet_init_zero {{{NULL}, NULL}}
/* Field tags (for use in manual encoding/decoding) */
#define ChannelSet_settings_tag 1
#define ServiceEnvelope_packet_tag 1
#define ServiceEnvelope_channel_id_tag 2
#define ServiceEnvelope_gateway_id_tag 3
/* Struct field encoding specification for nanopb */
#define ServiceEnvelope_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, packet, 1) \
X(a, CALLBACK, SINGULAR, STRING, channel_id, 2) \
X(a, CALLBACK, SINGULAR, STRING, gateway_id, 3)
#define ServiceEnvelope_CALLBACK pb_default_field_callback
#define ServiceEnvelope_DEFAULT NULL
#define ServiceEnvelope_packet_MSGTYPE MeshPacket
#define ChannelSet_FIELDLIST(X, a) \
X(a, CALLBACK, REPEATED, MESSAGE, settings, 1)
#define ChannelSet_CALLBACK pb_default_field_callback
#define ChannelSet_DEFAULT NULL
#define ChannelSet_settings_MSGTYPE ChannelSettings
extern const pb_msgdesc_t ServiceEnvelope_msg;
extern const pb_msgdesc_t ChannelSet_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define ServiceEnvelope_fields &ServiceEnvelope_msg
#define ChannelSet_fields &ChannelSet_msg
/* Maximum encoded size of messages (where known) */
/* ServiceEnvelope_size depends on runtime parameters */
/* ChannelSet_size depends on runtime parameters */
#ifdef __cplusplus

Wyświetl plik

@ -0,0 +1,12 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.4 */
#include "mqtt.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(ServiceEnvelope, ServiceEnvelope, AUTO)

Wyświetl plik

@ -0,0 +1,55 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.4 */
#ifndef PB_MQTT_PB_H_INCLUDED
#define PB_MQTT_PB_H_INCLUDED
#include <pb.h>
#include "mesh.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
typedef struct _ServiceEnvelope {
struct _MeshPacket *packet;
char *channel_id;
char *gateway_id;
} ServiceEnvelope;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define ServiceEnvelope_init_default {NULL, NULL, NULL}
#define ServiceEnvelope_init_zero {NULL, NULL, NULL}
/* Field tags (for use in manual encoding/decoding) */
#define ServiceEnvelope_packet_tag 1
#define ServiceEnvelope_channel_id_tag 2
#define ServiceEnvelope_gateway_id_tag 3
/* Struct field encoding specification for nanopb */
#define ServiceEnvelope_FIELDLIST(X, a) \
X(a, POINTER, OPTIONAL, MESSAGE, packet, 1) \
X(a, POINTER, SINGULAR, STRING, channel_id, 2) \
X(a, POINTER, SINGULAR, STRING, gateway_id, 3)
#define ServiceEnvelope_CALLBACK NULL
#define ServiceEnvelope_DEFAULT NULL
#define ServiceEnvelope_packet_MSGTYPE MeshPacket
extern const pb_msgdesc_t ServiceEnvelope_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define ServiceEnvelope_fields &ServiceEnvelope_msg
/* Maximum encoded size of messages (where known) */
/* ServiceEnvelope_size depends on runtime parameters */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

Wyświetl plik

@ -87,6 +87,8 @@ typedef struct _RadioConfig_UserPreferences {
bool fixed_position;
bool serial_disabled;
float frequency_offset;
char mqtt_server[32];
bool mqtt_disabled;
bool factory_reset;
bool debug_log_enabled;
pb_size_t ignore_incoming_count;
@ -152,9 +154,9 @@ extern "C" {
/* Initializer values for message structs */
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0}
/* Field tags (for use in manual encoding/decoding) */
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
@ -181,6 +183,8 @@ extern "C" {
#define RadioConfig_UserPreferences_fixed_position_tag 39
#define RadioConfig_UserPreferences_serial_disabled_tag 40
#define RadioConfig_UserPreferences_frequency_offset_tag 41
#define RadioConfig_UserPreferences_mqtt_server_tag 42
#define RadioConfig_UserPreferences_mqtt_disabled_tag 43
#define RadioConfig_UserPreferences_factory_reset_tag 100
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
#define RadioConfig_UserPreferences_ignore_incoming_tag 103
@ -243,6 +247,8 @@ X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
X(a, STATIC, SINGULAR, BOOL, serial_disabled, 40) \
X(a, STATIC, SINGULAR, FLOAT, frequency_offset, 41) \
X(a, STATIC, SINGULAR, STRING, mqtt_server, 42) \
X(a, STATIC, SINGULAR, BOOL, mqtt_disabled, 43) \
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \
@ -282,8 +288,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
/* Maximum encoded size of messages (where known) */
#define RadioConfig_size 357
#define RadioConfig_UserPreferences_size 354
#define RadioConfig_size 394
#define RadioConfig_UserPreferences_size 391
#ifdef __cplusplus
} /* extern "C" */

76
src/mqtt/MQTT.cpp 100644
Wyświetl plik

@ -0,0 +1,76 @@
#include "MQTT.h"
#include "NodeDB.h"
#include <WiFi.h>
#include <assert.h>
MQTT *mqtt;
String statusTopic = "mstat/";
String packetTopic = "mesh/";
void mqttCallback(char *topic, byte *payload, unsigned int length)
{
DEBUG_MSG("MQTT topic %s\n", topic);
// After parsing ServiceEnvelope
// FIXME - make sure to free both strings and the MeshPacket
}
void mqttInit()
{
// FIXME, for now we require the user to specifically set a MQTT server (till tested)
if (radioConfig.preferences.mqtt_disabled || !*radioConfig.preferences.mqtt_server)
DEBUG_MSG("MQTT disabled...\n");
else if (!WiFi.isConnected())
DEBUG_MSG("WiFi is not connected, can not start MQTT\n");
else
new MQTT();
}
MQTT::MQTT() : pubSub(mqttClient)
{
assert(!mqtt);
mqtt = this;
// pubSub.setServer("devsrv.ezdevice.net", 1883); or 192.168.10.188
const char *serverAddr = "test.mosquitto.org"; // "mqtt.meshtastic.org"; // default hostname
if (*radioConfig.preferences.mqtt_server)
serverAddr = radioConfig.preferences.mqtt_server; // Override the default
pubSub.setServer(serverAddr, 1883);
pubSub.setCallback(mqttCallback);
DEBUG_MSG("Connecting to MQTT server: %s\n", serverAddr);
auto myStatus = (statusTopic + nodeId);
// bool connected = pubSub.connect(nodeId.c_str(), "meshdev", "apes4cats", myStatus.c_str(), 1, true, "offline");
bool connected = pubSub.connect(nodeId.c_str(), myStatus.c_str(), 1, true, "offline");
if (connected) {
DEBUG_MSG("MQTT connected\n");
static char subsStr[64]; /* We keep this static because the mqtt lib
might not be copying it */
// snprintf(subsStr, sizeof(subsStr), "/ezd/todev/%s/#", clientId);
// mqtt.subscribe(subsStr, 1); // we use qos 1 because we don't want to miss messages
/// FIXME, include more information in the status text
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
DEBUG_MSG("published %d\n", ok);
}
}
void MQTT::publish(const MeshPacket *mp, String channelId)
{
// DEBUG_MSG("publish %s = %s\n", suffix.c_str(), payload.c_str());
// pubSub.publish(getTopic(suffix), payload.c_str(), retained);
}
const char *MQTT::getTopic(String suffix, const char *direction)
{
static char buf[128];
// "mesh/crypt/CHANNELID/NODEID/PORTID"
snprintf(buf, sizeof(buf), "mesh/%s/%s/%s", direction, nodeId.c_str(), suffix.c_str());
return buf;
}

38
src/mqtt/MQTT.h 100644
Wyświetl plik

@ -0,0 +1,38 @@
#pragma once
#include "configuration.h"
#include <PubSubClient.h>
#include <WiFiClient.h>
/**
* Our wrapper/singleton for sending/receiving MQTT "udp" packets. This object isolates the MQTT protocol implementation from
* the two components that use it: MQTTPlugin and MQTTSimInterface.
*/
class MQTT
{
/// Our globally unique node ID
String nodeId = "fixmemode";
// supposedly the current version is busted:
// http://www.iotsharing.com/2017/08/how-to-use-esp32-mqtts-with-mqtts-mosquitto-broker-tls-ssl.html
// WiFiClientSecure wifiClient;
WiFiClient mqttClient;
PubSubClient pubSub;
public:
MQTT();
/**
* Publish a packet on the glboal MQTT server.
* @param channelId must be a globally unique channel ID
*/
void publish(const MeshPacket *mp, String channelId);
private:
const char *getTopic(String suffix, const char *direction = "dev");
};
void mqttInit();
extern MQTT *mqtt;