Adafruit_MQTT_Library/Adafruit_MQTT.h

330 lines
12 KiB
C
Raw Normal View History

2015-06-11 00:38:34 +02:00
// The MIT License (MIT)
//
// Copyright (c) 2015 Adafruit Industries
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
2020-06-25 15:56:46 +02:00
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
2015-06-11 00:38:34 +02:00
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
2015-06-01 00:38:33 +02:00
#ifndef _ADAFRUIT_MQTT_H_
#define _ADAFRUIT_MQTT_H_
#include "Arduino.h"
2016-01-05 08:11:27 +01:00
#if defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_STM32_FEATHER)
#define strncpy_P(dest, src, len) strncpy((dest), (src), (len))
#define strncasecmp_P(f1, f2, len) strncasecmp((f1), (f2), (len))
2015-06-01 00:38:33 +02:00
#endif
#define ADAFRUIT_MQTT_VERSION_MAJOR 0
2016-12-29 22:09:07 +01:00
#define ADAFRUIT_MQTT_VERSION_MINOR 17
#define ADAFRUIT_MQTT_VERSION_PATCH 0
// Uncomment/comment to turn on/off debug output messages.
2016-08-10 03:37:07 +02:00
//#define MQTT_DEBUG
2016-07-08 21:21:47 +02:00
// Uncomment/comment to turn on/off error output messages.
#define MQTT_ERROR
// Set where debug messages will be printed.
#define DEBUG_PRINTER Serial
// If using something like Zero or Due, change the above to SerialUSB
// Define actual debug output functions when necessary.
#ifdef MQTT_DEBUG
2020-06-25 15:56:46 +02:00
#define DEBUG_PRINT(...) \
{ DEBUG_PRINTER.print(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) \
{ DEBUG_PRINTER.println(__VA_ARGS__); }
#define DEBUG_PRINTBUFFER(buffer, len) \
{ printBuffer(buffer, len); }
#else
2020-06-25 15:56:46 +02:00
#define DEBUG_PRINT(...) \
{}
#define DEBUG_PRINTLN(...) \
{}
#define DEBUG_PRINTBUFFER(buffer, len) \
{}
#endif
#ifdef MQTT_ERROR
2020-06-25 15:56:46 +02:00
#define ERROR_PRINT(...) \
{ DEBUG_PRINTER.print(__VA_ARGS__); }
#define ERROR_PRINTLN(...) \
{ DEBUG_PRINTER.println(__VA_ARGS__); }
#define ERROR_PRINTBUFFER(buffer, len) \
{ printBuffer(buffer, len); }
#else
2020-06-25 15:56:46 +02:00
#define ERROR_PRINT(...) \
{}
#define ERROR_PRINTLN(...) \
{}
#define ERROR_PRINTBUFFER(buffer, len) \
{}
#endif
2015-10-21 05:51:03 +02:00
// Use 3 (MQTT 3.0) or 4 (MQTT 3.1.1)
#define MQTT_PROTOCOL_LEVEL 4
2015-06-01 00:38:33 +02:00
2020-06-25 15:56:46 +02:00
#define MQTT_CTRL_CONNECT 0x1
#define MQTT_CTRL_CONNECTACK 0x2
#define MQTT_CTRL_PUBLISH 0x3
#define MQTT_CTRL_PUBACK 0x4
#define MQTT_CTRL_PUBREC 0x5
#define MQTT_CTRL_PUBREL 0x6
#define MQTT_CTRL_PUBCOMP 0x7
#define MQTT_CTRL_SUBSCRIBE 0x8
#define MQTT_CTRL_SUBACK 0x9
#define MQTT_CTRL_UNSUBSCRIBE 0xA
2020-06-25 15:56:46 +02:00
#define MQTT_CTRL_UNSUBACK 0xB
#define MQTT_CTRL_PINGREQ 0xC
#define MQTT_CTRL_PINGRESP 0xD
#define MQTT_CTRL_DISCONNECT 0xE
2015-06-01 05:19:13 +02:00
#define MQTT_QOS_1 0x1
#define MQTT_QOS_0 0x0
2015-06-01 00:38:33 +02:00
#define CONNECT_TIMEOUT_MS 6000
2015-06-01 05:19:13 +02:00
#define PUBLISH_TIMEOUT_MS 500
2020-06-25 15:56:46 +02:00
#define PING_TIMEOUT_MS 500
#define SUBACK_TIMEOUT_MS 500
2015-06-01 00:38:33 +02:00
// Adjust as necessary, in seconds. Default to 5 minutes.
#define MQTT_CONN_KEEPALIVE 300
// Largest full packet we're able to send.
// Need to be able to store at least ~90 chars for a connect packet with full
// 23 char client ID.
#define MAXBUFFERSIZE (150)
2015-06-05 18:09:58 +02:00
2020-06-25 15:56:46 +02:00
#define MQTT_CONN_USERNAMEFLAG 0x80
#define MQTT_CONN_PASSWORDFLAG 0x40
#define MQTT_CONN_WILLRETAIN 0x20
#define MQTT_CONN_WILLQOS_1 0x08
#define MQTT_CONN_WILLQOS_2 0x18
#define MQTT_CONN_WILLFLAG 0x04
#define MQTT_CONN_CLEANSESSION 0x02
2015-06-01 00:38:33 +02:00
2015-06-05 18:09:58 +02:00
// how much data we save in a subscription object
// and how many subscriptions we want to be able to track.
2020-06-25 15:56:46 +02:00
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__)
#define MAXSUBSCRIPTIONS 5
#define SUBSCRIPTIONDATALEN 20
#else
2020-06-25 15:56:46 +02:00
#define MAXSUBSCRIPTIONS 15
#define SUBSCRIPTIONDATALEN 100
#endif
2015-06-03 00:33:03 +02:00
2020-06-25 15:56:46 +02:00
class AdafruitIO_MQTT; // forward decl
2020-06-25 15:56:46 +02:00
// Function pointer that returns an int
2016-07-08 23:01:40 +02:00
typedef void (*SubscribeCallbackUInt32Type)(uint32_t);
// returns a double
typedef void (*SubscribeCallbackDoubleType)(double);
// returns a chunk of raw data
typedef void (*SubscribeCallbackBufferType)(char *str, uint16_t len);
// returns an io data wrapper instance
2020-06-25 15:56:46 +02:00
typedef void (AdafruitIO_MQTT::*SubscribeCallbackIOType)(char *str,
uint16_t len);
2015-06-03 00:33:03 +02:00
extern void printBuffer(uint8_t *buffer, uint16_t len);
2015-06-03 00:33:03 +02:00
2020-06-25 15:56:46 +02:00
class Adafruit_MQTT_Subscribe; // forward decl
2015-06-01 00:38:33 +02:00
class Adafruit_MQTT {
2020-06-25 15:56:46 +02:00
public:
Adafruit_MQTT(const char *server, uint16_t port, const char *cid,
const char *user, const char *pass);
Adafruit_MQTT(const char *server, uint16_t port, const char *user = "",
const char *pass = "");
virtual ~Adafruit_MQTT() {}
// Connect to the MQTT server. Returns 0 on success, otherwise an error code
// that indicates something went wrong:
// -1 = Error connecting to server
// 1 = Wrong protocol
// 2 = ID rejected
// 3 = Server unavailable
// 4 = Bad username or password
// 5 = Not authenticated
// 6 = Failed to subscribe
// Use connectErrorString() to get a printable string version of the
// error.
int8_t connect();
int8_t connect(const char *user, const char *pass);
// Return a printable string version of the error code returned by
// connect(). This returns a __FlashStringHelper*, which points to a
// string stored in flash, but can be directly passed to e.g.
// Serial.println without any further processing.
2020-06-25 15:56:46 +02:00
const __FlashStringHelper *connectErrorString(int8_t code);
// Sends MQTT disconnect packet and calls disconnectServer()
bool disconnect();
// Return true if connected to the MQTT server, otherwise false.
2020-06-25 15:56:46 +02:00
virtual bool connected() = 0; // Subclasses need to fill this in!
2015-10-05 15:25:07 +02:00
// Set MQTT last will topic, payload, QOS, and retain. This needs
// to be called before connect() because it is sent as part of the
// connect control packet.
2020-06-25 15:56:46 +02:00
bool will(const char *topic, const char *payload, uint8_t qos = 0,
uint8_t retain = 0);
2015-10-05 15:25:07 +02:00
2021-05-18 22:41:26 +02:00
// Sets the KeepAlive Interval, in seconds.
bool setKeepAliveInterval(uint16_t keepAlive);
// Publish a message to a topic using the specified QoS level. Returns true
// if the message was published, false otherwise.
2020-02-24 07:11:43 +01:00
bool publish(const char *topic, const char *payload, uint8_t qos = 0);
2020-06-25 15:56:46 +02:00
bool publish(const char *topic, uint8_t *payload, uint16_t bLen,
uint8_t qos = 0);
// Add a subscription to receive messages for a topic. Returns true if the
// subscription could be added or was already present, false otherwise.
// Must be called before connect(), subscribing after the connection
// is made is not currently supported.
bool subscribe(Adafruit_MQTT_Subscribe *sub);
2015-10-05 15:26:06 +02:00
// Unsubscribe from a previously subscribed MQTT topic.
bool unsubscribe(Adafruit_MQTT_Subscribe *sub);
// Check if any subscriptions have new messages. Will return a reference to
2020-06-25 15:56:46 +02:00
// an Adafruit_MQTT_Subscribe object which has a new message. Should be
// called in the sketch's loop function to ensure new messages are recevied.
// Note that subscribe should be called first for each topic that receives
// messages!
Adafruit_MQTT_Subscribe *readSubscription(int16_t timeout = 0);
2020-11-06 16:20:52 +01:00
// Handle any data coming in for subscriptions and fires them off to the
// appropriate callback
Adafruit_MQTT_Subscribe *handleSubscriptionPacket(uint16_t len);
2016-07-08 23:01:40 +02:00
void processPackets(int16_t timeout);
2015-10-05 16:38:09 +02:00
// Ping the server to ensure the connection is still alive.
bool ping(uint8_t n = 1);
2020-06-25 15:56:46 +02:00
protected:
// Interface that subclasses need to implement:
2015-06-01 05:19:13 +02:00
// Connect to the server and return true if successful, false otherwise.
virtual bool connectServer() = 0;
2015-06-01 05:56:27 +02:00
2020-06-25 15:56:46 +02:00
// Disconnect from the MQTT server. Returns true if disconnected, false
// otherwise.
virtual bool disconnectServer() = 0; // Subclasses need to fill this in!
// Send data to the server specified by the buffer and length of data.
virtual bool sendPacket(uint8_t *buffer, uint16_t len) = 0;
2015-06-03 00:33:03 +02:00
// Read MQTT packet from the server. Will read up to maxlen bytes and store
// the data in the provided buffer. Waits up to the specified timeout (in
2020-06-25 15:56:46 +02:00
// milliseconds) for data to be available.
virtual uint16_t readPacket(uint8_t *buffer, uint16_t maxlen,
int16_t timeout) = 0;
2015-06-03 00:33:03 +02:00
// Read a full packet, keeping note of the correct length
uint16_t readFullPacket(uint8_t *buffer, uint16_t maxsize, uint16_t timeout);
// Properly process packets until you get to one you want
2020-06-25 15:56:46 +02:00
uint16_t processPacketsUntil(uint8_t *buffer, uint8_t waitforpackettype,
uint16_t timeout);
// Shared state that subclasses can use:
const char *servername;
2015-06-01 00:38:33 +02:00
int16_t portnum;
const char *clientid;
const char *username;
const char *password;
const char *will_topic;
const char *will_payload;
uint8_t will_qos;
uint8_t will_retain;
2021-05-18 22:54:01 +02:00
uint16_t keepAliveInterval; // MQTT KeepAlive time interval, in seconds
2020-06-25 15:56:46 +02:00
uint8_t buffer[MAXBUFFERSIZE]; // one buffer, used for all incoming/outgoing
2015-10-21 06:05:46 +02:00
uint16_t packet_id_counter;
2015-06-01 00:38:33 +02:00
2020-06-25 15:56:46 +02:00
private:
2015-06-03 00:33:03 +02:00
Adafruit_MQTT_Subscribe *subscriptions[MAXSUBSCRIPTIONS];
2020-06-25 15:56:46 +02:00
void flushIncoming(uint16_t timeout);
// Functions to generate MQTT packets.
uint8_t connectPacket(uint8_t *packet);
uint8_t disconnectPacket(uint8_t *packet);
2020-06-25 15:56:46 +02:00
uint16_t publishPacket(uint8_t *packet, const char *topic, uint8_t *payload,
uint16_t bLen, uint8_t qos, uint16_t maxPacketLen = 0);
uint8_t subscribePacket(uint8_t *packet, const char *topic, uint8_t qos);
2015-10-05 15:27:31 +02:00
uint8_t unsubscribePacket(uint8_t *packet, const char *topic);
uint8_t pingPacket(uint8_t *packet);
uint8_t pubackPacket(uint8_t *packet, uint16_t packetid);
2015-06-01 00:38:33 +02:00
};
class Adafruit_MQTT_Publish {
2020-06-25 15:56:46 +02:00
public:
Adafruit_MQTT_Publish(Adafruit_MQTT *mqttserver, const char *feed,
uint8_t qos = 0);
2015-06-01 00:38:33 +02:00
bool publish(const char *s);
2020-06-25 15:56:46 +02:00
bool publish(
double f,
uint8_t precision =
2); // Precision controls the minimum number of digits after decimal.
// This might be ignored and a higher precision value sent.
2015-06-01 00:38:33 +02:00
bool publish(int32_t i);
2015-06-01 05:19:13 +02:00
bool publish(uint32_t i);
bool publish(uint8_t *b, uint16_t bLen);
2015-06-01 00:38:33 +02:00
private:
Adafruit_MQTT *mqtt;
const char *topic;
2015-06-01 05:19:13 +02:00
uint8_t qos;
2015-06-01 00:38:33 +02:00
};
class Adafruit_MQTT_Subscribe {
2020-06-25 15:56:46 +02:00
public:
Adafruit_MQTT_Subscribe(Adafruit_MQTT *mqttserver, const char *feedname,
uint8_t q = 0);
2016-07-08 23:01:40 +02:00
void setCallback(SubscribeCallbackUInt32Type callb);
void setCallback(SubscribeCallbackDoubleType callb);
void setCallback(SubscribeCallbackBufferType callb);
2016-12-29 22:09:07 +01:00
void setCallback(AdafruitIO_MQTT *io, SubscribeCallbackIOType callb);
void removeCallback(void);
2015-06-01 00:38:33 +02:00
2015-06-03 00:33:03 +02:00
const char *topic;
uint8_t qos;
uint8_t lastread[SUBSCRIPTIONDATALEN];
// Number valid bytes in lastread. Limited to SUBSCRIPTIONDATALEN-1 to
// ensure nul terminating lastread.
2016-07-08 23:01:40 +02:00
uint16_t datalen;
SubscribeCallbackUInt32Type callback_uint32t;
SubscribeCallbackDoubleType callback_double;
SubscribeCallbackBufferType callback_buffer;
2020-06-25 15:56:46 +02:00
SubscribeCallbackIOType callback_io;
2016-07-08 23:01:40 +02:00
2016-12-29 22:09:07 +01:00
AdafruitIO_MQTT *io_mqtt;
2016-07-29 21:06:54 +02:00
2021-05-23 20:52:35 +02:00
bool new_message;
2020-06-25 15:56:46 +02:00
private:
2015-06-03 00:33:03 +02:00
Adafruit_MQTT *mqtt;
2015-06-01 00:38:33 +02:00
};
#endif