[PubSubClient] Update to latest lib version

This commit is contained in:
TD-er
2025-07-19 00:05:53 +02:00
parent 3e30a1f0a3
commit ae4c97caf6
21 changed files with 825 additions and 343 deletions
+77
View File
@@ -0,0 +1,77 @@
<!-- HTML header for doxygen 1.14.0-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<!--BEGIN PROJECT_ICON-->
<link rel="icon" href="$relpath^$projecticon" type="image/x-icon" />
<!--END PROJECT_ICON-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<!--BEGIN FULL_SIDEBAR-->
<script type="text/javascript">var page_layout=1;</script>
<!--END FULL_SIDEBAR-->
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
<!--BEGIN COPY_CLIPBOARD-->
<script type="text/javascript" src="$relpath^clipboard.js"></script>
<!--END COPY_CLIPBOARD-->
$treeview
$search
$mathjax
$darkmode
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
</head>
<body>
<!--BEGIN FULL_SIDEBAR-->
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
<!--END FULL_SIDEBAR-->
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"$logosize/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign">
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber">&#160;$projectnumber</span></div><!--END PROJECT_NUMBER-->
<!--BEGIN PROJECT_BRIEF-->
<div id="projectbrief">$projectbrief</div>
<script>
function htmlDecode(input) {
var doc = new DOMParser().parseFromString(input, "text/html");
return doc.documentElement.textContent;
}
document.getElementById("projectbrief").innerHTML = htmlDecode("$projectbrief");
</script>
<!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<!--BEGIN !FULL_SIDEBAR-->
<td>$searchbox</td>
<!--END !FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
<!--BEGIN SEARCHENGINE-->
<!--BEGIN FULL_SIDEBAR-->
<tr><td colspan="2">$searchbox</td></tr>
<!--END FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
# Update the Doxyfile PROJECT_NUMBER with the version from library.properties
# Exit immediately if a command exits with a non-zero status.
set -e
# Make sure we are inside the github workspace
cd $GITHUB_WORKSPACE
version=`grep "version=" library.properties | cut -d "=" -f 2-`
echo "Update current version in Doxyfile: $version"
sed -i "s/PROJECT_NUMBER.*/PROJECT_NUMBER = \"v$version\"/" Doxyfile
+4
View File
@@ -3,6 +3,10 @@ name: build
on:
push:
branches: [ "master" ]
paths:
- 'examples/**'
- 'src/**'
- 'tests/**'
pull_request:
branches: [ "master" ]
+65
View File
@@ -0,0 +1,65 @@
# This workflow generates Doxygen API documentation and deploys it to GitHub Pages.
# I didn't manage to build a Jekyll site and deploy the content to GitHub Pages.
# So now I use a static index.html file in the gh-pages branch.
# It runs on pushes to the master branch and can also be triggered manually.
name: Generate Doxygen API and deploy content to GitHub Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: write
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Single deploy job since we're just deploying
deploy:
if: github.repository == 'hmueller01/pubsubclient3'
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Update Doxyfile PROJECT_NUMBER
run: bash .github/doxygen-update-version.sh
- name: Doxygenize
#uses: langroodi/doxygenize@v1.7.1 # waiting for update ...
uses: langroodi/doxygenize@6e920681c5d838e9a1b5cd273b814d1e4023b63d
#uses: hmueller01/doxygenize@update-alpine-linux+patches
with:
# Doxygen configuration file path
doxygenconf: ./Doxyfile
# Generated HTML documents output folder
htmloutput: ./site/api
# GitHub Pages branch name
ghpagesbranch: gh-pages
# GitHub Pages directory path
ghpagesdir: ./site/api
# - name: List site contents
# run: |
# find ./site
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
#path: '.' # Upload entire repository
path: './site'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
+1
View File
@@ -3,3 +3,4 @@ tests/bin
.piolibdeps
.clang_complete
.gcc-flags.json
site/api
+39
View File
@@ -0,0 +1,39 @@
# Minimal Doxyfile for Doxygen 1.13.2
# Project related configuration options
PROJECT_NAME = "PubSubClient3"
PROJECT_NUMBER = "automatically updated by doxygen-update-version.sh"
PROJECT_BRIEF = "Located at <a href='https://github.com/hmueller01/pubsubclient3'>GitHub</a>"
OUTPUT_DIRECTORY = ./site
INPUT = ./src
RECURSIVE = YES
# Build related configuration options
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXCLUDE_SYMBOLS = CHECK_STRING_LENGTH
# HTML output
GENERATE_HTML = YES
HTML_OUTPUT = api
HTML_COLORSTYLE = AUTO_LIGHT
HTML_HEADER = .github/doxygen-header.html
# LaTeX output (disable if not needed)
GENERATE_LATEX = NO
# Source code browsing
SOURCE_BROWSER = YES
# Warnings
WARNINGS = YES
# Dot/Graphviz support (disable if not needed)
HAVE_DOT = NO
# File patterns (optional, default covers most C/C++ files)
FILE_PATTERNS = *.h *.cpp *.c *.hpp
# Language
OUTPUT_LANGUAGE = English
+9 -2
View File
@@ -24,12 +24,19 @@ I appreciate every contribution to this library.
The library comes with a number of example sketches. See File > Examples > PubSubClient
within the Arduino application.
Full API documentation is available here: https://pubsubclient.knolleary.net
Full API documentation is available here: https://hmueller01.github.io/pubsubclient3/api
## Limitations
- The client is based on the [MQTT Version 3.1.1 specification](https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html) with some limitations.
- It can only publish QoS 0 messages. It can subscribe at QoS 0 or QoS 1.
- It can publish at QoS 0, 1 or 2.
**WARNING:** No retransmission is supported to keep the library as much memory friendly as possible.
Note: Without retransmission support, the publish QoS is only meaningful when the broker sends your
message to a subscriber, supposing that the subscriber subscribes with a QoS greater then or equal to
the publish QoS. Consider that MQTT runs over TCP, so retransmission isn't really required in most cases, especially when publishing to the broker.
- It can subscribe at QoS 0 or QoS 1.
- The maximum message size, including header, is **256 bytes** by default. This
is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h` or can be changed
by calling `PubSubClient::setBufferSize(size)`.
@@ -16,7 +16,7 @@ byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
void callback(char* topic, uint8_t* payload, size_t length) {
void callback(char* topic, uint8_t* payload, size_t plength) {
// handle message arrived
}
@@ -21,11 +21,11 @@ byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
void callback(char* topic, uint8_t* payload, size_t length) {
void callback(char* topic, uint8_t* payload, size_t plength) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (size_t i = 0; i < length; i++) {
for (size_t i = 0; i < plength; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
@@ -66,11 +66,11 @@ void setup_wifi() {
Serial.println(WiFi.localIP());
}
void callback(char* topic, uint8_t* payload, size_t length) {
void callback(char* topic, uint8_t* payload, size_t plength) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (size_t i = 0; i < length; i++) {
for (size_t i = 0; i < plength; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
@@ -69,11 +69,11 @@ void setup_wifi() {
Serial.println(WiFi.localIP());
}
void callback(char* topic, uint8_t* payload, size_t length) {
void callback(char* topic, uint8_t* payload, size_t plength) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (size_t i = 0; i < length; i++) {
for (size_t i = 0; i < plength; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
@@ -23,22 +23,22 @@ IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
// Callback function header
void callback(char* topic, uint8_t* payload, size_t length);
void callback(char* topic, uint8_t* payload, size_t plength);
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);
// Callback function
void callback(char* topic, uint8_t* payload, size_t length) {
void callback(char* topic, uint8_t* payload, size_t plength) {
// In order to republish this payload, a copy must be made
// as the orignal payload buffer will be overwritten whilst
// constructing the PUBLISH packet.
// Allocate the correct amount of memory for the payload copy
byte* p = (byte*)malloc(length);
byte* p = (byte*)malloc(plength);
// Copy the payload to the new buffer
memcpy(p, payload, length);
client.publish("outTopic", p, length);
memcpy(p, payload, plength);
client.publish("outTopic", p, plength);
// Free the memory
free(p);
}
@@ -16,7 +16,7 @@ byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress ip(172, 16, 0, 100);
IPAddress server(172, 16, 0, 2);
void callback(char* topic, uint8_t* payload, size_t length) {
void callback(char* topic, uint8_t* payload, size_t plength) {
// handle message arrived
}
@@ -21,11 +21,11 @@ IPAddress server(172, 16, 0, 2);
SRAM sram(4, SRAM_1024);
void callback(char* topic, uint8_t* payload, size_t length) {
void callback(char* topic, uint8_t* payload, size_t plength) {
sram.seek(1);
// do something with the message
for (size_t i = 0; i < length; i++) {
for (size_t i = 0; i < plength; i++) {
Serial.write(sram.read());
}
Serial.println();
+150 -105
View File
@@ -1,12 +1,28 @@
/*
PubSubClient.cpp - A simple client for MQTT.
Nick O'Leary, Holger Mueller
http://knolleary.net
https://github.com/hmueller01/pubsubclient3
*/
/**
* @file PubSubClient.cpp
* @brief A simple client for MQTT.
* @author Nicholas O'Leary - http://knolleary.net
* @author Holger Mueller - https://github.com/hmueller01/pubsubclient3
* @copyright MIT License 2008-2025
*
* This file is part of the PubSubClient library.
*/
#include "PubSubClient.h"
/**
* @brief Macro to check if a string 's' can be safely added to the MQTT buffer.
*
* If either check fails, the client connection is stopped and the function returns false.
* @param l current length in the buffer
* @param s string to check
*/
#define CHECK_STRING_LENGTH(l, s) \
if ((!s) || (l + 2 + strnlen(s, this->bufferSize) > this->bufferSize)) { \
_client->stop(); \
return false; \
}
PubSubClient::PubSubClient() {
setBufferSize(MQTT_MAX_PACKET_SIZE);
setKeepAlive(MQTT_KEEPALIVE);
@@ -95,20 +111,20 @@ PubSubClient::~PubSubClient() {
}
bool PubSubClient::connect(const char* id) {
return connect(id, nullptr, nullptr, 0, 0, 0, 0, 1);
return connect(id, nullptr, nullptr, nullptr, MQTT_QOS0, false, nullptr, true);
}
bool PubSubClient::connect(const char* id, const char* user, const char* pass) {
return connect(id, user, pass, 0, 0, 0, 0, 1);
return connect(id, user, pass, nullptr, MQTT_QOS0, false, nullptr, true);
}
bool PubSubClient::connect(const char* id, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage) {
return connect(id, nullptr, nullptr, willTopic, willQos, willRetain, willMessage, 1);
return connect(id, nullptr, nullptr, willTopic, willQos, willRetain, willMessage, true);
}
bool PubSubClient::connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain,
const char* willMessage) {
return connect(id, user, pass, willTopic, willQos, willRetain, willMessage, 1);
return connect(id, user, pass, willTopic, willQos, willRetain, willMessage, true);
}
bool PubSubClient::connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain,
@@ -157,20 +173,20 @@ bool PubSubClient::connect(const char* id, const char* user, const char* pass, c
this->buffer[length++] = keepAlive & 0xFF;
CHECK_STRING_LENGTH(length, id)
length = writeString(id, this->buffer, length);
length = writeString(id, this->buffer, length, this->bufferSize);
if (willTopic) {
CHECK_STRING_LENGTH(length, willTopic)
length = writeString(willTopic, this->buffer, length);
length = writeString(willTopic, this->buffer, length, this->bufferSize);
CHECK_STRING_LENGTH(length, willMessage)
length = writeString(willMessage, this->buffer, length);
length = writeString(willMessage, this->buffer, length, this->bufferSize);
}
if (user) {
CHECK_STRING_LENGTH(length, user)
length = writeString(user, this->buffer, length);
length = writeString(user, this->buffer, length, this->bufferSize);
if (pass) {
CHECK_STRING_LENGTH(length, pass)
length = writeString(pass, this->buffer, length);
length = writeString(pass, this->buffer, length, this->bufferSize);
}
}
@@ -314,8 +330,8 @@ size_t PubSubClient::readPacket(uint8_t* hdrLen) {
if (!readByte(this->buffer, &len)) return 0;
skip = (this->buffer[*hdrLen + 1] << 8) + this->buffer[*hdrLen + 2];
start = 2;
if (this->buffer[0] & MQTTQOS1) {
// skip message id
if (MQTT_HDR_GET_QOS(this->buffer[0]) > MQTT_QOS0) {
// skip msgId (packet identifier) for QoS 1 and 2 messages
skip += 2;
}
}
@@ -355,7 +371,7 @@ bool PubSubClient::handlePacket(uint8_t hdrLen, size_t length) {
switch (type) {
case MQTTPUBLISH:
if (callback) {
// MQTT Publish packet: See section 3.3 MQTT v3.1 protocol specification:
// MQTT Publish packet: See section 3.3 MQTT v3.1.1 protocol specification:
// - Header: 1 byte
// - Remaining header length: hdrLen bytes, multibyte field (1 .. MQTT_MAX_HEADER_SIZE - 1)
// - Topic length: 2 bytes (starts at buffer[hdrLen + 1])
@@ -377,7 +393,7 @@ bool PubSubClient::handlePacket(uint8_t hdrLen, size_t length) {
memmove(topic, topic + 1, topicLen); // move topic inside buffer 1 byte to front
topic[topicLen] = '\0'; // end the topic as a 'C' string with \x00
if ((this->buffer[0] & 0x06) == MQTTQOS0) {
if (MQTT_HDR_GET_QOS(this->buffer[0]) == MQTT_QOS0) {
// No msgId for QOS == 0
callback(topic, payload, payloadLen);
} else {
@@ -399,7 +415,37 @@ bool PubSubClient::handlePacket(uint8_t hdrLen, size_t length) {
}
}
break;
case MQTTPUBACK:
// MQTT Publish Acknowledgment (QoS 1 publish received): See section 3.4 MQTT v3.1.1 protocol specification
if (length < 4) {
ERROR_PSC_PRINTF_P("handlePacket(): Received PUBACK packet with length %zu, expected at least 4 bytes\n", length);
return false;
}
// No futher action here, as resending is not supported.
break;
case MQTTPUBREC:
// MQTT Publish Received (QoS 2 publish received, part 1): See section 3.5 MQTT v3.1.1 protocol specification
if (length < 4) {
ERROR_PSC_PRINTF_P("handlePacket(): Received PUBREC packet with length %zu, expected at least 4 bytes\n", length);
return false;
}
// MQTT Publish Release (QoS 2 publish received, part 2): See section 3.6 MQTT v3.1.1 protocol specification
buffer[0] = MQTTPUBREL | 2; // PUBREL with bit 1 set
// bytes 1-3 of PUBREL are the same as of PUBREC
if (_client->write(buffer, 4) == 4) {
lastOutActivity = millis();
}
break;
case MQTTPUBCOMP:
// MQTT Publish Complete (QoS 2 publish received, part 3): See section 3.7 MQTT v3.1.1 protocol specification
if (length < 4) {
ERROR_PSC_PRINTF_P("handlePacket(): Received PUBCOMP packet with length %zu, expected at least 4 bytes\n", length);
return false;
}
// No futher action here, as resending is not supported.
break;
case MQTTPINGREQ:
// MQTT Ping Request: See section 3.12 MQTT v3.1.1 protocol specification
this->buffer[0] = MQTTPINGRESP;
this->buffer[1] = 0;
if (_client->write(this->buffer, 2) == 2) {
@@ -456,19 +502,27 @@ bool PubSubClient::loop() {
}
bool PubSubClient::publish(const char* topic, const char* payload) {
return publish(topic, (const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, false);
return publish(topic, payload, MQTT_QOS0, false);
}
bool PubSubClient::publish(const char* topic, const char* payload, bool retained) {
return publish(topic, (const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, retained);
return publish(topic, payload, MQTT_QOS0, retained);
}
bool PubSubClient::publish(const char* topic, const char* payload, uint8_t qos, bool retained) {
return publish(topic, (const uint8_t*)payload, payload ? strnlen(payload, MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, qos, retained);
}
bool PubSubClient::publish(const char* topic, const uint8_t* payload, size_t plength) {
return publish(topic, payload, plength, false);
return publish(topic, payload, plength, MQTT_QOS0, false);
}
bool PubSubClient::publish(const char* topic, const uint8_t* payload, size_t plength, bool retained) {
if (beginPublish(topic, plength, retained)) {
return publish(topic, payload, plength, MQTT_QOS0, retained);
}
bool PubSubClient::publish(const char* topic, const uint8_t* payload, size_t plength, uint8_t qos, bool retained) {
if (beginPublish(topic, plength, qos, retained)) {
size_t rc = write(payload, plength);
lastOutActivity = millis();
return endPublish() && (rc == plength);
@@ -477,11 +531,19 @@ bool PubSubClient::publish(const char* topic, const uint8_t* payload, size_t ple
}
bool PubSubClient::publish_P(const char* topic, const char* payload, bool retained) {
return publish_P(topic, (const uint8_t*)payload, payload ? strnlen_P(payload, MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, retained);
return publish_P(topic, payload, MQTT_QOS0, retained);
}
bool PubSubClient::publish_P(const char* topic, const char* payload, uint8_t qos, bool retained) {
return publish_P(topic, (const uint8_t*)payload, payload ? strnlen_P(payload, MQTT_MAX_POSSIBLE_PACKET_SIZE) : 0, qos, retained);
}
bool PubSubClient::publish_P(const char* topic, const uint8_t* payload, size_t plength, bool retained) {
if (beginPublish(topic, plength, retained)) {
return publish_P(topic, payload, plength, MQTT_QOS0, retained);
}
bool PubSubClient::publish_P(const char* topic, const uint8_t* payload, size_t plength, uint8_t qos, bool retained) {
if (beginPublish(topic, plength, qos, retained)) {
size_t rc = 0;
for (size_t i = 0; i < plength; i++) {
rc += _client->write((uint8_t)pgm_read_byte_near(payload + i));
@@ -493,14 +555,26 @@ bool PubSubClient::publish_P(const char* topic, const uint8_t* payload, size_t p
}
bool PubSubClient::beginPublish(const char* topic, size_t plength, bool retained) {
return beginPublish(topic, plength, MQTT_QOS0, retained);
}
bool PubSubClient::beginPublish(const char* topic, size_t plength, uint8_t qos, bool retained) {
if (!topic) return false;
if (strlen(topic) == 0) return false; // empty topic is not allowed
if (qos > MQTT_QOS2) { // only valid QoS supported
this->_qos = MQTT_QOS0; // reset QoS to 0, that endPublish() will not send a nextMsgId
ERROR_PSC_PRINTF_P("beginPublish() called with invalid QoS %u\n", qos);
return false;
}
this->_qos = qos; // save the QoS for later endPublish() operation
// check if the header and the topic (including 2 length bytes) fit into the buffer
if (connected() && MQTT_MAX_HEADER_SIZE + strlen(topic) + 2 <= this->bufferSize) {
// first write the topic at the end of the maximal variable header (MQTT_MAX_HEADER_SIZE) to the buffer
size_t topicLen = writeString(topic, this->buffer, MQTT_MAX_HEADER_SIZE) - MQTT_MAX_HEADER_SIZE;
size_t topicLen = writeString(topic, this->buffer, MQTT_MAX_HEADER_SIZE, this->bufferSize) - MQTT_MAX_HEADER_SIZE;
// we now know the length of the topic string (lenght + 2 bytes signalling the length) and can build the variable header information
const uint8_t header = MQTTPUBLISH | (retained ? MQTTRETAINED : 0);
uint8_t hdrLen = buildHeader(header, this->buffer, topicLen + plength);
const uint8_t header = MQTTPUBLISH | MQTT_QOS_GET_HDR(qos) | (retained ? MQTTRETAINED : 0);
const size_t nextMsgLen = (qos) ? 2 : 0; // add 2 bytes for the nextMsgId if QoS > 0
uint8_t hdrLen = buildHeader(header, this->buffer, topicLen + plength + nextMsgLen);
if (hdrLen == 0) return false; // exit here in case of header generation failure
// as the header length is variable, it starts at MQTT_MAX_HEADER_SIZE - hdrLen (see buildHeader() documentation)
size_t rc = _client->write(this->buffer + (MQTT_MAX_HEADER_SIZE - hdrLen), hdrLen + topicLen);
@@ -511,8 +585,19 @@ bool PubSubClient::beginPublish(const char* topic, size_t plength, bool retained
}
bool PubSubClient::endPublish() {
flushBuffer();
return connected();
if (connected()) {
if (this->_qos > MQTT_QOS0) {
// QoS == 1 or 2, send the msgId
uint8_t buf[2];
writeNextMsgId(buf, 0, 2);
size_t rc = _client->write(buf, 2);
lastOutActivity = millis();
return (rc == 2);
}
// QoS == 0, no msgId to send
return true;
}
return false;
}
/**
@@ -550,19 +635,13 @@ uint8_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, size_t length) {
}
size_t PubSubClient::write(uint8_t data) {
const size_t rc = appendBuffer(data);
if (rc != 0) {
lastOutActivity = millis();
}
return rc;
lastOutActivity = millis();
return _client->write(data);
}
size_t PubSubClient::write(const uint8_t* buffer, size_t size) {
const size_t rc = appendBuffer(buffer, size);
if (rc != 0) {
lastOutActivity = millis();
}
return rc;
lastOutActivity = millis();
return _client->write(buffer, size);
}
/**
@@ -605,24 +684,10 @@ bool PubSubClient::write(uint8_t header, uint8_t* buf, size_t length) {
}
/**
* @brief Write an UTF-8 encoded string to the give buffer and position. The string can have a length of 0 to 65535 bytes. The buffer is prefixed with two
* bytes representing the length of the string. See section 1.5.3 of MQTT v3.1.1 protocol specification.
* @note If the string does not fit in the buffer (bufferSize) or is longer than 65535 bytes nothing is written to the buffer and the returned position
* is unchanged.
*
* @param string 'C' string of the data that shall be written in the buffer.
* @param buf Buffer to write the string into.
* @param pos Position in the buffer to write the string.
* @return New position in the buffer (pos + 2 + string length), or pos if a buffer overrun would occur.
*/
size_t PubSubClient::writeString(const char* string, uint8_t* buf, size_t pos) {
return writeString(string, buf, pos, this->bufferSize);
}
/**
* @brief Write an UTF-8 encoded string to the give buffer and position. The string can have a length of 0 to 65535 bytes. The buffer is prefixed with two
* bytes representing the length of the string. See section 1.5.3 of MQTT v3.1.1 protocol specification.
* @note If the string does not fit in the buffer or is longer than 65535 bytes nothing is written to the buffer and the returned position is unchanged.
* @brief Write an UTF-8 encoded string to the give buffer and position. The string can have a length of 0 to 65535 bytes. The buffer is prefixed with
* two bytes representing the length of the string. See section 1.5.3 of MQTT v3.1.1 protocol specification.
* @note If the string does not fit in the buffer or is longer than 65535 bytes nothing is written to the buffer and the returned position is
* unchanged.
*
* @param string 'C' string of the data that shall be written in the buffer.
* @param buf Buffer to write the string into.
@@ -645,61 +710,46 @@ size_t PubSubClient::writeString(const char* string, uint8_t* buf, size_t pos, s
return pos;
}
size_t PubSubClient::appendBuffer(uint8_t data) {
buffer[_bufferWritePos] = data;
++_bufferWritePos;
if (_bufferWritePos >= bufferSize) {
if (flushBuffer() == 0) return 0;
/**
* @brief Write nextMsgId to the give buffer and position.
* @note If the nextMsgId (2 bytes) does not fit in the buffer nothing is written to the buffer and the returned position is unchanged.
*
* @param buf Buffer to write the nextMsgId into.
* @param pos Position in the buffer to write the nextMsgId.
* @param size Maximal size of the buffer.
* @return New position in the buffer (pos + 2), or pos if a buffer overrun would occur.
*/
size_t PubSubClient::writeNextMsgId(uint8_t* buf, size_t pos, size_t size) {
if (pos + 2 <= size) {
nextMsgId = (++nextMsgId == 0) ? 1 : nextMsgId; // increment msgId (must not be 0, so start at 1)
buf[pos++] = (uint8_t)(nextMsgId >> 8);
buf[pos++] = (uint8_t)(nextMsgId & 0xFF);
} else {
ERROR_PSC_PRINTF_P("writeNextMsgId(): buffer (%zu) does not fit into buf (%zu)\n", pos + 2, size);
}
return 1;
}
size_t PubSubClient::appendBuffer(const uint8_t *data, size_t size) {
for (size_t i = 0; i < size; ++i) {
if (appendBuffer(data[i]) == 0) return i;
}
return size;
}
size_t PubSubClient::flushBuffer() {
size_t rc = 0;
if (_bufferWritePos > 0) {
if (connected()) {
rc = _client->write(buffer, _bufferWritePos);
if (rc != 0) {
lastOutActivity = millis();
}
}
_bufferWritePos = 0;
}
return rc;
return pos;
}
bool PubSubClient::subscribe(const char* topic) {
return subscribe(topic, 0);
return subscribe(topic, MQTT_QOS0);
}
bool PubSubClient::subscribe(const char* topic, uint8_t qos) {
if (!topic) return false;
if (qos > 1) return false; // only QoS 0 and 1 supported
if (qos > MQTT_QOS1) return false; // only QoS 0 and 1 supported
size_t topicLen = strnlen(topic, this->bufferSize);
if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2 + 2 + topicLen) {
// Too long: header + nextMsgId (2) + topic length bytes (2) + topicLen
if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2 + 2 + topicLen + 1) {
// Too long: header + nextMsgId (2) + topic length bytes (2) + topicLen + QoS (1)
return false;
}
if (connected()) {
// Leave room in the buffer for header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
this->buffer[length++] = (nextMsgId >> 8);
this->buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, this->buffer, length);
length = writeNextMsgId(buffer, length, this->bufferSize); // buffer size is checked before
length = writeString(topic, this->buffer, length, this->bufferSize);
this->buffer[length++] = qos;
return write(MQTTSUBSCRIBE | MQTTQOS1, this->buffer, length - MQTT_MAX_HEADER_SIZE);
return write(MQTTSUBSCRIBE | MQTT_QOS_GET_HDR(MQTT_QOS1), this->buffer, length - MQTT_MAX_HEADER_SIZE);
}
return false;
}
@@ -714,14 +764,9 @@ bool PubSubClient::unsubscribe(const char* topic) {
}
if (connected()) {
uint16_t length = MQTT_MAX_HEADER_SIZE;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
this->buffer[length++] = (nextMsgId >> 8);
this->buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, this->buffer, length);
return write(MQTTUNSUBSCRIBE | MQTTQOS1, this->buffer, length - MQTT_MAX_HEADER_SIZE);
length = writeNextMsgId(buffer, length, this->bufferSize); // buffer size is checked before
length = writeString(topic, this->buffer, length, this->bufferSize);
return write(MQTTUNSUBSCRIBE | MQTT_QOS_GET_HDR(MQTT_QOS1), this->buffer, length - MQTT_MAX_HEADER_SIZE);
}
return false;
}
+252 -172
View File
@@ -1,9 +1,12 @@
/*
PubSubClient.h - A simple client for MQTT.
Nick O'Leary, Holger Mueller
http://knolleary.net
https://github.com/hmueller01/pubsubclient3
*/
/**
* @file PubSubClient.h
* @brief A simple client for MQTT.
* @author Nicholas O'Leary - http://knolleary.net
* @author Holger Mueller - https://github.com/hmueller01/pubsubclient3
* @copyright MIT License 2008-2025
*
* This file is part of the PubSubClient library.
*/
#ifndef PubSubClient_h
#define PubSubClient_h
@@ -14,20 +17,22 @@
#include "IPAddress.h"
#include "Stream.h"
#define MQTT_VERSION_3_1 3
#define MQTT_VERSION_3_1_1 4
#define MQTT_VERSION_3_1 3 ///< Defines MQTT 3.1 protocol version, see #MQTT_VERSION
#define MQTT_VERSION_3_1_1 4 ///< Defines MQTT 3.1.1 protocol version, see #MQTT_VERSION
//< @note The following #define directives can be used to configure the library.
/**
* @brief Sets the version of the MQTT protocol to use.
* @note Default value is MQTT_VERSION_3_1_1 for MQTT 3.1.1.
* @brief Sets the version of the MQTT protocol to use (3.1 or 3.1.1). [#MQTT_VERSION_3_1, #MQTT_VERSION_3_1_1].
* @note Default value is #MQTT_VERSION_3_1_1 for MQTT 3.1.1.
*/
#ifndef MQTT_VERSION
#define MQTT_VERSION MQTT_VERSION_3_1_1
#endif
// MQTT_MAX_POSSIBLE_PACKET_SIZE : Maximum packet size defined by MQTT protocol.
/**
* @brief Maximum packet size defined by MQTT protocol.
*/
#ifndef MQTT_MAX_POSSIBLE_PACKET_SIZE
#define MQTT_MAX_POSSIBLE_PACKET_SIZE 268435455
#endif
@@ -65,23 +70,32 @@
/**
* @brief Sets the maximum number of bytes passed to the network client in each write call.
* Some hardware has a limit to how much data can be passed to them in one go,
* such as the Arduino Wifi Shield.
* such as the Arduino Wifi Shield e.g. use 80.
* @note Defaults to undefined, which passes the entire packet in each write call.
*/
// #define MQTT_MAX_TRANSFER_SIZE 80
#ifndef MQTT_MAX_TRANSFER_SIZE // just a hack that it gets shown in Doxygen
#define MQTT_MAX_TRANSFER_SIZE 80
#undef MQTT_MAX_TRANSFER_SIZE
#endif
// Possible values for client.state()
#define MQTT_CONNECTION_TIMEOUT -4
#define MQTT_CONNECTION_LOST -3
#define MQTT_CONNECT_FAILED -2
#define MQTT_DISCONNECTED -1
#define MQTT_CONNECTED 0
#define MQTT_CONNECT_BAD_PROTOCOL 1
#define MQTT_CONNECT_BAD_CLIENT_ID 2
#define MQTT_CONNECT_UNAVAILABLE 3
#define MQTT_CONNECT_BAD_CREDENTIALS 4
#define MQTT_CONNECT_UNAUTHORIZED 5
/**
* @defgroup group_state state() result
* @brief These values indicate the current PubSubClient::state() of the client.
* @{
*/
#define MQTT_CONNECTION_TIMEOUT -4 ///< The network connection timed out or server didn't respond within the keepalive time.
#define MQTT_CONNECTION_LOST -3 ///< The network connection was lost/broken.
#define MQTT_CONNECT_FAILED -2 ///< The network connection failed.
#define MQTT_DISCONNECTED -1 ///< The client is disconnected cleanly.
#define MQTT_CONNECTED 0 ///< The client is connected.
#define MQTT_CONNECT_BAD_PROTOCOL 1 ///< The server does not support the requested MQTT version.
#define MQTT_CONNECT_BAD_CLIENT_ID 2 ///< The server rejected the client identifier.
#define MQTT_CONNECT_UNAVAILABLE 3 ///< The server was unable to accept the connection.
#define MQTT_CONNECT_BAD_CREDENTIALS 4 ///< The username or password is not valid.
#define MQTT_CONNECT_UNAUTHORIZED 5 ///< The client is not authorized to connect to the server.
/** @} */
/// \cond
#define MQTTRETAINED 1 // Retained flag in the header
#define MQTTCONNECT 1 << 4 // Client request to connect to Server
#define MQTTCONNACK 2 << 4 // Connect Acknowledgment
@@ -98,31 +112,41 @@
#define MQTTPINGRESP 13 << 4 // PING Response
#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting
#define MQTTRESERVED 15 << 4 // Reserved
/// \endcond
#define MQTTQOS0 (0 << 1)
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
/**
* @defgroup group_qos QoS levels
* @brief Quality of Service (QoS) levels for MQTT messages.
* @{
*/
#define MQTT_QOS0 ((uint8_t)0) ///< Quality of Service 0: At most once
#define MQTT_QOS1 ((uint8_t)1) ///< Quality of Service 1: At least once
#define MQTT_QOS2 ((uint8_t)2) ///< Quality of Service 2: Exactly once
/// \cond
#define MQTT_QOS_GET_HDR(qos) (((qos) & 0x03) << 1) // Get QoS header bits from QoS value
#define MQTT_HDR_GET_QOS(header) (((header) & 0x06 ) >> 1) // Get QoS value from MQTT header
/// \endcond
/** @} */
// Maximum size of fixed header and variable length size header
/// \cond Maximum size of fixed header and variable length size header
#define MQTT_MAX_HEADER_SIZE 5
/// \endcond
#if defined(__has_include) && __has_include(<functional>) && !defined(NOFUNCTIONAL)
#include <functional>
/// \anchor callback
/**
* @brief Define the signature required by any callback function.
* @note The parameters are TOPIC, PAYLOAD, and LENGTH, respectively.
* @param topic The topic of the message.
* @param payload The payload of the message.
* @param plength The length of the payload.
*/
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, size_t)> callback
#if defined(__has_include) && __has_include(<functional>) && !defined(NOFUNCTIONAL)
#include <functional>
#define MQTT_CALLBACK_SIGNATURE std::function<void(char* topic, uint8_t* payload, size_t plength)> callback
#else
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, size_t)
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char* topic, uint8_t* payload, size_t plength)
#endif
#define CHECK_STRING_LENGTH(l, s) \
if ((!s) || (l + 2 + strnlen(s, this->bufferSize) > this->bufferSize)) { \
_client->stop(); \
return false; \
}
/// \cond
#ifdef DEBUG_ESP_PORT
#ifdef DEBUG_PUBSUBCLIENT
#define DEBUG_PSC_PRINTF(fmt, ...) DEBUG_ESP_PORT.printf(("PubSubClient: " fmt), ##__VA_ARGS__)
@@ -143,6 +167,7 @@
#define ERROR_PSC_PRINTF_P(fmt, ...)
#endif
#endif
/// \endcond
/**
* @class PubSubClient
@@ -165,7 +190,7 @@ class PubSubClient : public Print {
uint16_t port{};
Stream* stream{};
int _state{MQTT_DISCONNECTED};
int _bufferWritePos = 0;
uint8_t _qos{MQTT_QOS0};
size_t readPacket(uint8_t* hdrLen);
bool handlePacket(uint8_t hdrLen, size_t len);
@@ -173,37 +198,106 @@ class PubSubClient : public Print {
bool readByte(uint8_t* result, size_t* pos);
uint8_t buildHeader(uint8_t header, uint8_t* buf, size_t length);
bool write(uint8_t header, uint8_t* buf, size_t length);
size_t writeString(const char* string, uint8_t* buf, size_t pos);
size_t writeString(const char* string, uint8_t* buf, size_t pos, size_t size);
// Add to buffer and flush if full (only to be used with beginPublish/endPublish)Add commentMore actions
size_t appendBuffer(uint8_t data);
size_t appendBuffer(const uint8_t *data, size_t size);
size_t flushBuffer();
size_t writeNextMsgId(uint8_t* buf, size_t pos, size_t size);
public:
/**
* @brief Creates an uninitialised client instance.
* @note Before it can be used,
* it must be configured using the property setters setClient and setServer.
* @note Before it can be used, it must be configured using the property setters setClient() and setServer().
*/
PubSubClient();
/**
* @brief Creates a partially initialised client instance.
* @param client The network client to use, for example WiFiClient.
* @note Before it can be used,
* it must be configured with the property setter setServer.
* @note Before it can be used, it must be configured with the property setter setServer().
*/
PubSubClient(Client& client);
/**
* @brief Creates a fully configured client instance.
* @param addr The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(IPAddress addr, uint16_t port, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param addr The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream);
/**
* @brief Creates a fully configured client instance.
* @param addr The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message \ref callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param addr The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message \ref callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream);
/**
* @brief Creates a fully configured client instance.
* @param ip The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(uint8_t* ip, uint16_t port, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param ip The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(uint8_t* ip, uint16_t port, Client& client, Stream& stream);
/**
* @brief Creates a fully configured client instance.
* @param ip The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message \ref callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(uint8_t* ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param ip The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message \ref callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(uint8_t* ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(IPAddress, uint16_t, Client& client);
PubSubClient(const char* domain, uint16_t port, Client& client);
/**
* @brief Creates a fully configured client instance.
@@ -212,104 +306,28 @@ class PubSubClient : public Print {
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(IPAddress, uint16_t, Client& client, Stream&);
PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message callback function.
* @param callback Pointer to a message \ref callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client);
PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message callback function.
* @param callback Pointer to a message \ref callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client, Stream&);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(uint8_t*, uint16_t, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(uint8_t*, uint16_t, Client& client, Stream&);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(uint8_t*, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(uint8_t*, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client, Stream&);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(const char*, uint16_t, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(const char*, uint16_t, Client& client, Stream&);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
*/
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client);
/**
* @brief Creates a fully configured client instance.
* @param domain The address of the server.
* @param port The port to connect to.
* @param callback Pointer to a message callback function.
* Called when a message arrives for a subscription created by this client.
* @param client The network client to use, for example WiFiClient.
* @param stream A stream to write received messages to.
*/
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE, Client& client, Stream&);
PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream);
/**
* @brief Destructor for the PubSubClient class.
@@ -319,7 +337,7 @@ class PubSubClient : public Print {
/**
* @brief Sets the server details.
* @param ip The address of the server.
* @param port The port to connect to.
* @param port The port to connect to.
* @return The client instance, allowing the function to be chained.
*/
PubSubClient& setServer(IPAddress ip, uint16_t port);
@@ -327,22 +345,22 @@ class PubSubClient : public Print {
/**
* @brief Sets the server details.
* @param ip The address of the server.
* @param port The port to connect to.
* @param port The port to connect to.
* @return The client instance, allowing the function to be chained.
*/
PubSubClient& setServer(uint8_t* ip, uint16_t port);
/**
* @brief Sets the server details.
* @param ip The address of the server.
* @param port The port to connect to.
* @param domain The address of the server.
* @param port The port to connect to.
* @return The client instance, allowing the function to be chained.
*/
PubSubClient& setServer(const char* domain, uint16_t port);
/**
* @brief Sets the message callback function.
* @param callback Pointer to a message callback function.
* @param callback Pointer to a message \ref callback function.
* Called when a message arrives for a subscription created by this client.
* @return The client instance, allowing the function to be chained.
*/
@@ -398,7 +416,7 @@ class PubSubClient : public Print {
size_t getBufferSize();
/**
* @brief Connects the client.
* @brief Connects the client using a clean session without username and password.
* @param id The client ID to use when connecting to the server.
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
@@ -406,48 +424,60 @@ class PubSubClient : public Print {
bool connect(const char* id);
/**
* @brief Connects the client.
* @brief Connects the client using a clean session with username and password.
* @param id The client ID to use when connecting to the server.
* @param user The username to use. If NULL, no username or password is used.
* @param pass The password to use. If NULL, no password is used.
* @param user The username to use.
* @param pass The password to use.
* @note If **user** is NULL, no username or password is used.
* @note If **pass** is NULL, no password is used.
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
*/
bool connect(const char* id, const char* user, const char* pass);
/**
* @brief Connects the client.
* @brief Connects the client using a clean session and will.
* @param id The client ID to use when connecting to the server.
* @param willTopic The topic to be used by the will message.
* @param willQos The quality of service to be used by the will message. [0, 1, 2].
* @param willRetain Publish the will message with the retain flag.
* @param willMessage The message to be used by the will message.
* @note If **willTopic** is NULL, no will message is sent.
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
*/
bool connect(const char* id, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage);
/**
* @brief Connects the client.
* @brief Connects the client using a clean session with username, password and will.
* @param id The client ID to use when connecting to the server.
* @param user The username to use. If NULL, no username or password is used.
* @param pass The password to use. If NULL, no password is used.
* @param user The username to use.
* @param pass The password to use.
* @param willTopic The topic to be used by the will message.
* @param willQos The quality of service to be used by the will message. [0, 1, 2].
* @param willRetain Publish the will message with the retain flag.
* @param willMessage The message to be used by the will message.
* @note If **user** is NULL, no username or password is used.
* @note If **pass** is NULL, no password is used.
* @note If **willTopic** is NULL, no will message is sent.
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
*/
bool connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, bool willRetain, const char* willMessage);
/**
* @brief Connects the client.
* @brief Connects the client with all possible parameters (user, password, will and session).
* @param id The client ID to use when connecting to the server.
* @param user The username to use. If NULL, no username or password is used.
* @param pass The password to use. If NULL, no password is used.
* @param user The username to use.
* @param pass The password to use.
* @param willTopic The topic to be used by the will message.
* @param willQos The quality of service to be used by the will message. [0, 1, 2].
* @param willRetain Publish the will message with the retain flag.
* @param cleanSession Connect with a clean session.
* @param willMessage The message to be used by the will message.
* @param cleanSession True to connect with a clean session.
* @note If **user** is NULL, no username or password is used.
* @note If **pass** is NULL, no password is used.
* @note If **willTopic** is NULL, no will message is sent.
* @return true If client succeeded in establishing a connection to the broker.
* false If client failed to establish a connection to the broker.
*/
@@ -460,7 +490,7 @@ class PubSubClient : public Print {
void disconnect();
/**
* @brief Publishes a non retained message to the specified topic.
* @brief Publishes a non retained message to the specified topic using QoS 0.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @return true If the publish succeeded.
@@ -469,7 +499,7 @@ class PubSubClient : public Print {
bool publish(const char* topic, const char* payload);
/**
* @brief Publishes a message to the specified topic.
* @brief Publishes a message to the specified topic using QoS 0.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param retained Publish the message with the retain flag.
@@ -479,7 +509,18 @@ class PubSubClient : public Print {
bool publish(const char* topic, const char* payload, bool retained);
/**
* @brief Publishes a non retained message to the specified topic.
* @brief Publishes a message to the specified topic.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish(const char* topic, const char* payload, uint8_t qos, bool retained);
/**
* @brief Publishes a non retained message to the specified topic using QoS 0.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param plength The length of the payload.
@@ -489,7 +530,7 @@ class PubSubClient : public Print {
bool publish(const char* topic, const uint8_t* payload, size_t plength);
/**
* @brief Publishes a message to the specified topic.
* @brief Publishes a message to the specified topic using QoS 0.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param plength The length of the payload.
@@ -500,7 +541,19 @@ class PubSubClient : public Print {
bool publish(const char* topic, const uint8_t* payload, size_t plength, bool retained);
/**
* @brief Publishes a message stored in PROGMEM to the specified topic.
* @brief Publishes a message to the specified topic.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param plength The length of the payload.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish(const char* topic, const uint8_t* payload, size_t plength, uint8_t qos, bool retained);
/**
* @brief Publishes a message stored in PROGMEM to the specified topic using QoS 0.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param retained Publish the message with the retain flag.
@@ -513,6 +566,17 @@ class PubSubClient : public Print {
* @brief Publishes a message stored in PROGMEM to the specified topic.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish_P(const char* topic, const char* payload, uint8_t qos, bool retained);
/**
* @brief Publishes a message stored in PROGMEM to the specified topic using QoS 0.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param plength The length of the payload.
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
@@ -521,7 +585,19 @@ class PubSubClient : public Print {
bool publish_P(const char* topic, const uint8_t* payload, size_t plength, bool retained);
/**
* @brief Start to publish a message.
* @brief Publishes a message stored in PROGMEM to the specified topic.
* @param topic The topic to publish to.
* @param payload The message to publish.
* @param plength The length of the payload.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool publish_P(const char* topic, const uint8_t* payload, size_t plength, uint8_t qos, bool retained);
/**
* @brief Start to publish a message using QoS 0.
* This API:
* beginPublish(...)
* one or more calls to write(...)
@@ -536,6 +612,23 @@ class PubSubClient : public Print {
*/
bool beginPublish(const char* topic, size_t plength, bool retained);
/**
* @brief Start to publish a message.
* This API:
* beginPublish(...)
* one or more calls to write(...)
* endPublish()
* Allows for arbitrarily large payloads to be sent without them having to be copied into
* a new buffer and held in memory at one time.
* @param topic The topic to publish to.
* @param plength The length of the payload.
* @param qos The quality of service (\ref group_qos) to publish at. [0, 1, 2].
* @param retained Publish the message with the retain flag.
* @return true If the publish succeeded.
* false If the publish failed, either connection lost or message too large.
*/
bool beginPublish(const char* topic, size_t plength, uint8_t qos, bool retained);
/**
* @brief Finish sending a message that was started with a call to beginPublish.
* @return true If the publish succeeded.
@@ -545,17 +638,13 @@ class PubSubClient : public Print {
/**
* @brief Writes a single byte as a component of a publish started with a call to beginPublish.
* For performance reasons, this will be appended to the internal buffer,
* which will be flushed when full or on a call to endPublish().
* @param byte A byte to write to the publish payload.
* @param data A byte to write to the publish payload.
* @return The number of bytes written.
*/
virtual size_t write(uint8_t);
virtual size_t write(uint8_t data);
/**
* @brief Writes an array of bytes as a component of a publish started with a call to beginPublish.
* For performance reasons, this will be appended to the internal buffer,
* which will be flushed when full or on a call to endPublish().
* @param buffer The bytes to write.
* @param size The length of the payload to be sent.
* @return The number of bytes written.
@@ -563,7 +652,7 @@ class PubSubClient : public Print {
virtual size_t write(const uint8_t* buffer, size_t size);
/**
* @brief Subscribes to messages published to the specified topic.
* @brief Subscribes to messages published to the specified topic using QoS 0.
* @param topic The topic to subscribe to.
* @return true If sending the subscribe succeeded.
* false If sending the subscribe failed, either connection lost or message too large.
@@ -605,16 +694,7 @@ class PubSubClient : public Print {
* @brief Returns the current state of the client.
* If a connection attempt fails, this can be used to get more information about the failure.
* @note All of the values have corresponding constants defined in PubSubClient.h.
* @return -4 : MQTT_CONNECTION_TIMEOUT - The server didn't respond within the keepalive time.
* -3 : MQTT_CONNECTION_LOST - The network connection was broken.
* -2 : MQTT_CONNECT_FAILED - The network connection failed.
* -1 : MQTT_DISCONNECTED - The client is disconnected cleanly.
* 0 : MQTT_CONNECTED - The client is connected.
* 1 : MQTT_CONNECT_BAD_PROTOCOL - The server doesn't support the requested version of MQTT.
* 2 : MQTT_CONNECT_BAD_CLIENT_ID - The server rejected the client identifier.
* 3 : MQTT_CONNECT_UNAVAILABLE - The server was unable to accept the connection.
* 4 : MQTT_CONNECT_BAD_CREDENTIALS - The username/password were rejected.
* 5 : MQTT_CONNECT_UNAUTHORIZED - The client was not authorized to connect.
* @return See \ref group_state
*/
int state();
};
+2 -2
View File
@@ -7,7 +7,7 @@
byte server[] = {172, 16, 0, 2};
// function declarations
void callback(char* topic, uint8_t* payload, size_t length);
void callback(char* topic, uint8_t* payload, size_t plength);
int test_connect_fails_no_network();
int test_connect_fails_on_no_response();
int test_connect_properly_formatted();
@@ -23,7 +23,7 @@ int test_connect_with_will_username_password();
int test_connect_disconnect_connect();
int test_connect_custom_keepalive();
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t length) {
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t plength) {
// handle message arrived
}
@@ -9,14 +9,14 @@
byte server[] = {172, 16, 0, 2};
// function declarations
void callback(char* topic, uint8_t* payload, size_t length);
void callback(char* topic, uint8_t* payload, size_t plength);
int test_keepalive_pings_idle();
int test_keepalive_pings_with_outbound_qos0();
int test_keepalive_pings_with_inbound_qos0();
int test_keepalive_no_pings_inbound_qos1();
int test_keepalive_disconnects_hung();
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t length) {
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t plength) {
// handle message arrived
}
@@ -54,7 +54,7 @@ int test_keepalive_pings_idle() {
}
int test_keepalive_pings_with_outbound_qos0() {
IT("keeps a connection alive that only sends qos0 (takes 1 minute)");
IT("keeps a connection alive that only sends QoS 0 (takes 1 minute)");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -90,7 +90,7 @@ int test_keepalive_pings_with_outbound_qos0() {
}
int test_keepalive_pings_with_inbound_qos0() {
IT("keeps a connection alive that only receives qos0 (takes 1 minute)");
IT("keeps a connection alive that only receives QoS 0 (takes 1 minute)");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -123,7 +123,7 @@ int test_keepalive_pings_with_inbound_qos0() {
}
int test_keepalive_no_pings_inbound_qos1() {
IT("does not send pings for connections with inbound qos1 (takes 1 minute)");
IT("does not send pings for connections with inbound QoS 1 (takes 1 minute)");
ShimClient shimClient;
shimClient.setAllowConnect(true);
+180 -25
View File
@@ -7,7 +7,7 @@
byte server[] = {172, 16, 0, 2};
// function declarations
void callback(char* topic, uint8_t* payload, size_t length);
void callback(char* topic, uint8_t* payload, size_t plength);
int test_publish();
int test_publish_bytes();
int test_publish_retained();
@@ -16,8 +16,14 @@ int test_publish_not_connected();
int test_publish_too_long();
int test_publish_P();
int test_publish_P_too_long();
int test_publish_empty_topic();
int test_publish_null_payload();
int test_publish_qos1();
int test_publish_qos2();
int test_publish_P_qos1();
int test_publish_P_qos2();
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t length) {
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t plength) {
// handle message arrived
}
@@ -27,14 +33,14 @@ int test_publish() {
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x30, 0xe, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64};
shimClient.expect(publish, 16);
byte publish[] = {0x30, 0x0e, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 'p', 'a', 'y', 'l', 'o', 'a', 'd'};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", "payload");
IS_TRUE(rc);
@@ -49,18 +55,18 @@ int test_publish_bytes() {
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte payload[] = {0x01, 0x02, 0x03, 0x0, 0x05};
size_t length = 5;
byte payload[] = {0x01, 0x02, 0x03, 0x00, 0x05};
size_t length = sizeof(payload);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x30, 0xc, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1, 0x2, 0x3, 0x0, 0x5};
shimClient.expect(publish, 14);
byte publish[] = {0x30, 0x0c, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x01, 0x02, 0x03, 0x00, 0x05};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", payload, length);
IS_TRUE(rc);
@@ -75,18 +81,18 @@ int test_publish_retained() {
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte payload[] = {0x01, 0x02, 0x03, 0x0, 0x05};
size_t length = 5;
byte payload[] = {0x01, 0x02, 0x03, 0x00, 0x05};
size_t length = sizeof(payload);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x31, 0xc, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1, 0x2, 0x3, 0x0, 0x5};
shimClient.expect(publish, 14);
byte publish[] = {0x31, 0x0c, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x1, 0x2, 0x3, 0x0, 0x5};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", payload, length, true);
IS_TRUE(rc);
@@ -102,14 +108,14 @@ int test_publish_retained_2() {
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x31, 0xc, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 'A', 'B', 'C', 'D', 'E'};
shimClient.expect(publish, 14);
byte publish[] = {0x31, 0x0c, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 'A', 'B', 'C', 'D', 'E'};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", "ABCDE", true);
IS_TRUE(rc);
@@ -165,18 +171,18 @@ int test_publish_P() {
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte payload[] = {0x01, 0x02, 0x03, 0x0, 0x05};
size_t length = 5;
byte payload[] = {0x01, 0x02, 0x03, 0x00, 0x05};
size_t length = sizeof(payload);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x31, 0xc, 0x0, 0x5, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x1, 0x2, 0x3, 0x0, 0x5};
shimClient.expect(publish, 14);
byte publish[] = {0x31, 0x0c, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x01, 0x02, 0x03, 0x00, 0x05};
shimClient.expect(publish, sizeof(publish));
rc = client.publish_P("topic", payload, length, true);
IS_TRUE(rc);
@@ -187,7 +193,7 @@ int test_publish_P() {
}
int test_publish_P_too_long() {
IT("publish using PROGMEM fails when topic are too long");
IT("publish using PROGMEM fails when topic is too long");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -198,7 +204,7 @@ int test_publish_P_too_long() {
char payload[] = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
client.setBufferSize(64);
@@ -213,15 +219,164 @@ int test_publish_P_too_long() {
END_IT
}
int test_publish_empty_topic() {
IT("publish fails when topic is empty");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
rc = client.publish("", "payload");
IS_FALSE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_null_payload() {
IT("publishes with null payload");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x30, 0x07, 0x00, 0x05, 't', 'o', 'p', 'i', 'c'};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", nullptr);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_qos1() {
IT("publishes with QoS 1");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
// Example publish packet for QoS 1 (0x32)
byte publish[] = {0x32, 0x10, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00, 0x02};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", "payload", MQTT_QOS1, false);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_qos2() {
IT("publishes with QoS 2");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, 4);
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
// Example publish packet for QoS 2 (0x34)
byte publish[] = {0x34, 0x10, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 'p', 'a', 'y', 'l', 'o', 'a', 'd', 0x00, 0x02};
shimClient.expect(publish, sizeof(publish));
rc = client.publish("topic", "payload", MQTT_QOS2, false);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_P_qos1() {
IT("publishes using PROGMEM with QoS 1 retained");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte payload[] = {0x01, 0x02, 0x03, 0x04, 0x05};
size_t length = sizeof(payload);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x33, 0x0e, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x02};
shimClient.expect(publish, sizeof(publish));
rc = client.publish_P("topic", payload, length, MQTT_QOS1, true);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int test_publish_P_qos2() {
IT("publishes using PROGMEM with QoS 2 retained");
ShimClient shimClient;
shimClient.setAllowConnect(true);
byte payload[] = {0x01, 0x02, 0x03, 0x04, 0x05};
size_t length = sizeof(payload);
byte connack[] = {0x20, 0x02, 0x00, 0x00};
shimClient.respond(connack, sizeof(connack));
PubSubClient client(server, 1883, callback, shimClient);
bool rc = client.connect("client_test1");
IS_TRUE(rc);
byte publish[] = {0x35, 0x0e, 0x00, 0x05, 't', 'o', 'p', 'i', 'c', 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x02};
shimClient.expect(publish, sizeof(publish));
rc = client.publish_P("topic", payload, length, MQTT_QOS2, true);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
END_IT
}
int main() {
SUITE("Publish");
test_publish();
test_publish_bytes();
test_publish_retained();
test_publish_retained_2();
test_publish_qos1();
test_publish_qos2();
test_publish_null_payload();
test_publish_not_connected();
test_publish_empty_topic();
test_publish_too_long();
test_publish_P();
test_publish_P_qos1();
test_publish_P_qos2();
test_publish_P_too_long();
FINISH
+5 -5
View File
@@ -18,7 +18,7 @@ char lastPayload[1024];
size_t lastLength;
// function declarations
void callback(char* topic, uint8_t* payload, size_t length);
void callback(char* topic, uint8_t* payload, size_t plength);
void reset_callback();
int test_receive_callback();
int test_receive_stream();
@@ -36,12 +36,12 @@ void reset_callback() {
lastLength = 0;
}
void callback(char* topic, uint8_t* payload, size_t length) {
TRACE("Callback received topic=[" << topic << "] length=" << length << "\n")
void callback(char* topic, uint8_t* payload, size_t plength) {
TRACE("Callback received topic=[" << topic << "] plength=" << plength << "\n")
callback_called = true;
strcpy(lastTopic, topic);
memcpy(lastPayload, payload, length);
lastLength = length;
memcpy(lastPayload, payload, plength);
lastLength = plength;
}
int test_receive_callback() {
+12 -12
View File
@@ -7,7 +7,7 @@
byte server[] = {172, 16, 0, 2};
// function declarations
void callback(char* topic, uint8_t* payload, size_t length);
void callback(char* topic, uint8_t* payload, size_t plength);
int test_subscribe_no_qos();
int test_subscribe_qos_1();
int test_subscribe_not_connected();
@@ -16,12 +16,12 @@ int test_subscribe_too_long();
int test_unsubscribe();
int test_unsubscribe_not_connected();
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t length) {
void callback(_UNUSED_ char* topic, _UNUSED_ uint8_t* payload, _UNUSED_ size_t plength) {
// handle message arrived
}
int test_subscribe_no_qos() {
IT("subscribe without qos defaults to 0");
IT("subscribe without QoS (defaults to 0)");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -46,7 +46,7 @@ int test_subscribe_no_qos() {
}
int test_subscribe_qos_1() {
IT("subscribes qos 1");
IT("subscribe with QoS 1");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -62,7 +62,7 @@ int test_subscribe_qos_1() {
byte suback[] = {0x90, 0x3, 0x0, 0x2, 0x1};
shimClient.respond(suback, 5);
rc = client.subscribe("topic", 1);
rc = client.subscribe("topic", MQTT_QOS1);
IS_TRUE(rc);
IS_FALSE(shimClient.error());
@@ -85,7 +85,7 @@ int test_subscribe_not_connected() {
}
int test_subscribe_invalid_qos() {
IT("subscribe fails with invalid qos values");
IT("subscribe fails with invalid QoS values");
ShimClient shimClient;
shimClient.setAllowConnect(true);
@@ -96,7 +96,7 @@ int test_subscribe_invalid_qos() {
bool rc = client.connect("client_test1");
IS_TRUE(rc);
rc = client.subscribe("topic", 2);
rc = client.subscribe("topic", MQTT_QOS2);
IS_FALSE(rc);
rc = client.subscribe("topic", 254);
IS_FALSE(rc);
@@ -119,13 +119,13 @@ int test_subscribe_too_long() {
bool rc = client.connect("client_test1");
IS_TRUE(rc);
// max length should be allowed
// 0 1 2 3 4 5 6 7 8 9 0 1 2
rc = client.subscribe("12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
// max length should be allowed (buffer size - MQTT_MAX_HEADER_SIZE - msgId (2) - topic length bytes (2) - QoS (1) = 118)
// 0 1 2 3 4 5 6 7 8 9 0 1 2
rc = client.subscribe("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678");
IS_TRUE(rc);
// 0 1 2 3 4 5 6 7 8 9 0 1 2
rc = client.subscribe("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");
// 0 1 2 3 4 5 6 7 8 9 0 1 2
rc = client.subscribe("12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
IS_FALSE(rc);
IS_FALSE(shimClient.error());