mirror of https://github.com/arendst/Tasmota.git
commit
6794029416
10
README.md
10
README.md
|
@ -21,6 +21,16 @@ See [RELEASENOTES.md](https://github.com/arendst/Sonoff-Tasmota/blob/development
|
|||
|
||||
The development codebase is checked hourly for changes and if new commits have been merged and compile successfuly they will be posted at http://thehackbox.org/tasmota/ (this web address can be used for OTA too). It is important to note that these are based on the current development codebase and it is not recommended to flash it to devices used in production or which are hard to reach in the event that you need to manually flash the device if OTA failed. The last compiled commit number is also posted on the same page along with the current build status (if a firmware rebuild is in progress).
|
||||
|
||||
The current development codebase also stages a new experimental MQTT library that is not enabled by default. This may be enabled by commenting out:
|
||||
|
||||
#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT
|
||||
|
||||
and uncommenting:
|
||||
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT
|
||||
|
||||
For those interested in pre-compiled binaries based on this proposed MQTT library these may be downloaded from http://thehackbox.org/mqtt/ (This URL is also OTA friendly) but please do not under any circumstances use binaries from this link on devices used for day to day purposes as the testing of this newly proposed library still needs to follow its course of testing and possible debugging - Only use it on devices that you would normally use for testing purposes as to not inconvenience yourself when having to revert back to previous firmware versions by cable upload.
|
||||
|
||||
### Disclaimer
|
||||
:warning: **DANGER OF ELECTROCUTION** :warning:
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[src/*.h,src/*.cpp,examples/**.ino]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -0,0 +1,2 @@
|
|||
.DS_Store
|
||||
cmake-build-debug/
|
|
@ -0,0 +1,46 @@
|
|||
language: generic
|
||||
env:
|
||||
global:
|
||||
- IDE_VERSION=1.8.5
|
||||
matrix:
|
||||
- EXAMPLE="AdafruitHuzzahESP8266" BOARD="esp8266:esp8266:huzzah:FlashSize=4M3M,CpuFrequency=80"
|
||||
- EXAMPLE="AdafruitHuzzahESP8266Secure" BOARD="esp8266:esp8266:huzzah:FlashSize=4M3M,CpuFrequency=80"
|
||||
- EXAMPLE="ArduinoEthernetShield" BOARD="arduino:avr:uno"
|
||||
- EXAMPLE="ArduinoMKRGSM1400" BOARD="arduino:samd:mkrgsm1400"
|
||||
- EXAMPLE="ArduinoMKRGSM1400Secure" BOARD="arduino:samd:mkrgsm1400"
|
||||
- EXAMPLE="ArduinoWiFi101Secure" BOARD="arduino:avr:uno"
|
||||
- EXAMPLE="ArduinoWiFiShield" BOARD="arduino:avr:uno"
|
||||
- EXAMPLE="ArduinoYun" BOARD="arduino:avr:yun"
|
||||
- EXAMPLE="ArduinoYunSecure" BOARD="arduino:avr:yun"
|
||||
- EXAMPLE="ESP32DevelopmentBoard" BOARD="espressif:esp32:esp32:FlashFreq=80"
|
||||
- EXAMPLE="ESP32DevelopmentBoardSecure" BOARD="espressif:esp32:esp32:FlashFreq=80"
|
||||
before_install:
|
||||
- /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
|
||||
- sleep 3
|
||||
- export DISPLAY=:1.0
|
||||
- wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz
|
||||
- tar xf arduino-$IDE_VERSION-linux64.tar.xz
|
||||
- mv arduino-$IDE_VERSION ~/arduino-ide
|
||||
- export PATH=$PATH:~/arduino-ide
|
||||
- if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
|
||||
arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --install-boards esp8266:esp8266;
|
||||
arduino --pref "boardsmanager.additional.urls=" --save-prefs;
|
||||
fi
|
||||
- if [[ "$BOARD" =~ "espressif:esp32:" ]]; then
|
||||
mkdir -p ~/Arduino/hardware/espressif &&
|
||||
cd ~/Arduino/hardware/espressif &&
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 &&
|
||||
cd esp32/tools/ &&
|
||||
python get.py &&
|
||||
cd $TRAVIS_BUILD_DIR;
|
||||
fi
|
||||
- if [[ "$BOARD" =~ "arduino:samd:mkrgsm1400" ]]; then
|
||||
arduino --install-boards arduino:samd;
|
||||
arduino --install-library MKRGSM;
|
||||
fi
|
||||
- arduino --install-library WiFi101
|
||||
install:
|
||||
- mkdir -p ~/Arduino/libraries
|
||||
- ln -s $PWD ~/Arduino/libraries/.
|
||||
script:
|
||||
- arduino --verbose-build --verify --board $BOARD $PWD/examples/$EXAMPLE/$EXAMPLE.ino;
|
|
@ -0,0 +1,40 @@
|
|||
# Uncompilable CMake File to enable project editing with CLion IDE
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.4)
|
||||
project(arduino-mqtt)
|
||||
|
||||
include_directories(
|
||||
/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/
|
||||
/Users/256dpi/Development/Arduino/libraries/Ethernet/src
|
||||
/Users/256dpi/Development/Arduino/libraries/WiFi101/src
|
||||
/Users/256dpi/Development/Arduino/libraries/MKRGSM/src
|
||||
/Applications/Arduino.app/Contents/Java/libraries/Bridge/src
|
||||
/Users/256dpi/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266WiFi/src
|
||||
/Users/256dpi/Development/Arduino/hardware/espressif/esp32/libraries/WiFi/src
|
||||
/Users/256dpi/Development/Arduino/hardware/espressif/esp32/libraries/WiFiClientSecure/src
|
||||
src/)
|
||||
|
||||
include_directories(src/)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
|
||||
set(SOURCE_FILES
|
||||
examples/AdafruitHuzzahESP8266/AdafruitHuzzahESP8266.ino
|
||||
examples/AdafruitHuzzahESP8266Secure/AdafruitHuzzahESP8266Secure.ino
|
||||
examples/ArduinoEthernetShield/ArduinoEthernetShield.ino
|
||||
examples/ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino
|
||||
examples/ArduinoMKRGSM1400Secure/ArduinoMKRGSM1400Secure.ino
|
||||
examples/ArduinoWiFi101/ArduinoWiFi101.ino
|
||||
examples/ArduinoWiFi101Secure/ArduinoWiFi101Secure.ino
|
||||
examples/ArduinoWiFiShield/ArduinoWiFiShield.ino
|
||||
examples/ArduinoYun/ArduinoYun.ino
|
||||
examples/ArduinoYunSecure/ArduinoYunSecure.ino
|
||||
examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino
|
||||
examples/ESP32DevelopmentBoardSecure/ESP32DevelopmentBoardSecure.ino
|
||||
src/lwmqtt
|
||||
src/MQTT.h
|
||||
src/MQTTClient.h
|
||||
src/system.cpp
|
||||
src/system.h)
|
||||
|
||||
add_executable(arduino-mqtt ${SOURCE_FILES})
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Joël Gähwiler
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
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.
|
|
@ -0,0 +1,14 @@
|
|||
all: fmt
|
||||
|
||||
fmt:
|
||||
clang-format -i src/*.cpp src/*.h -style="{BasedOnStyle: Google, ColumnLimit: 120}"
|
||||
|
||||
update:
|
||||
rm -rf ./lwmqtt
|
||||
git clone --branch v0.6.2 https://github.com/256dpi/lwmqtt.git ./lwmqtt
|
||||
mkdir -p ./src/lwmqtt
|
||||
cp -r ./lwmqtt/src/*.c ./src/lwmqtt/
|
||||
cp -r ./lwmqtt/src/*.h ./src/lwmqtt/
|
||||
cp -r ./lwmqtt/include/*.h ./src/lwmqtt/
|
||||
rm -rf ./lwmqtt
|
||||
sed -i '' "s/<lwmqtt.h>/\"lwmqtt.h\"/g" ./src/lwmqtt/*
|
|
@ -0,0 +1,225 @@
|
|||
# arduino-mqtt
|
||||
|
||||
[![Build Status](https://travis-ci.org/256dpi/arduino-mqtt.svg?branch=master)](https://travis-ci.org/256dpi/arduino-mqtt)
|
||||
[![GitHub release](https://img.shields.io/github/release/256dpi/arduino-mqtt.svg)](https://github.com/256dpi/arduino-mqtt/releases)
|
||||
|
||||
This library bundles the [lwmqtt](https://github.com/256dpi/lwmqtt) MQTT 3.1.1 client and adds a thin wrapper to get an Arduino like API.
|
||||
|
||||
Download the latest version from the [release](https://github.com/256dpi/arduino-mqtt/releases) section. Or even better use the builtin Library Manager in the Arduino IDE and search for "MQTT".
|
||||
|
||||
The library is also available on [PlatformIO](https://platformio.org/lib/show/617/MQTT). You can install it by running: `pio lib install "MQTT"`.
|
||||
|
||||
## Compatibility
|
||||
|
||||
The following examples show how you can use the library with various Arduino compatible hardware:
|
||||
|
||||
- [Arduino Yun & Yun-Shield](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoYun/ArduinoYun.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoYunSecure/ArduinoYunSecure.ino))
|
||||
- [Arduino Ethernet Shield](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoEthernetShield/ArduinoEthernetShield.ino)
|
||||
- [Arduino WiFi Shield](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoWiFiShield/ArduinoWiFiShield.ino)
|
||||
- [Adafruit HUZZAH ESP8266](https://github.com/256dpi/arduino-mqtt/blob/master/examples/AdafruitHuzzahESP8266/AdafruitHuzzahESP8266.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/AdafruitHuzzahESP8266Secure/AdafruitHuzzahESP8266Secure.ino))
|
||||
- [Arduino/Genuino WiFi101 Shield](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoWiFi101/ArduinoWiFi101.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoWiFi101Secure/ArduinoWiFi101Secure.ino))
|
||||
- [Arduino MKR GSM 1400](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoMKRGSM1400/ArduinoMKRGSM1400.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ArduinoMKRGSM1400Secure/ArduinoMKRGSM1400Secure.ino))
|
||||
- [ESP32 Development Board](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ESP32DevelopmentBoard/ESP32DevelopmentBoard.ino) ([Secure](https://github.com/256dpi/arduino-mqtt/blob/master/examples/ESP32DevelopmentBoardSecure/ESP32DevelopmentBoardSecure.ino))
|
||||
|
||||
Other shields and boards should also work if they provide a [Client](https://www.arduino.cc/en/Reference/ClientConstructor) based network implementation.
|
||||
|
||||
## Notes
|
||||
|
||||
- The maximum size for packets being published and received is set by default to 128 bytes. To change the buffer sizes, you need to use `MQTTClient client(256)` instead of just `MQTTClient client` on the top of your sketch. The passed value denotes the read and write buffer size.
|
||||
|
||||
- On the ESP8266 it has been reported that an additional `delay(10);` after `client.loop();` fixes many stability issues with WiFi connections.
|
||||
|
||||
- To use the library with shiftr.io, you need to provide the token key (username) and token secret (password) as the second and third argument to `client.connect(name, key, secret)`.
|
||||
|
||||
## Example
|
||||
|
||||
The following example uses an Arduino MKR1000 to connect to shiftr.io. You can check on your device after a successful connection here: https://shiftr.io/try.
|
||||
|
||||
```c++
|
||||
#include <SPI.h>
|
||||
#include <WiFi101.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char ssid[] = "ssid";
|
||||
const char pass[] = "pass";
|
||||
|
||||
WiFiClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, pass);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
client.begin("broker.shiftr.io", net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
Initialize the object using the hostname of the broker, the brokers port (default: `1883`) and the underlying Client class for network transport:
|
||||
|
||||
```c++
|
||||
void begin(const char hostname[], Client &client);
|
||||
void begin(const char hostname[], int port, Client &client);
|
||||
```
|
||||
|
||||
- Specify port `8883` when using secure clients for encrypted connections.
|
||||
- Local domain names (e.g. `Computer.local` on OSX) are not supported by Arduino. You need to set the IP address directly.
|
||||
|
||||
The hostname and port can also be changed after calling `begin()`:
|
||||
|
||||
```c++
|
||||
void setHost(const char hostname[]);
|
||||
void setHost(const char hostname[], int port);
|
||||
```
|
||||
|
||||
Set a will message (last testament) that gets registered on the broker after connecting. `setWill()` has to be called before calling `connect()`:
|
||||
|
||||
```c++
|
||||
void setWill(const char topic[]);
|
||||
void setWill(const char topic[], const char payload[]);
|
||||
void setWill(const char topic[], const char payload[], bool retained, int qos);
|
||||
void clearWill();
|
||||
```
|
||||
|
||||
Register a callback to receive messages:
|
||||
|
||||
```c++
|
||||
void onMessage(MQTTClientCallbackSimple);
|
||||
// Callback signature: void messageReceived(String &topic, String &payload) {}
|
||||
|
||||
void onMessageAdvanced(MQTTClientCallbackAdvanced);
|
||||
// Callback signature: void messageReceived(MQTTClient *client, char topic[], char payload[], int payload_length) {}
|
||||
```
|
||||
|
||||
- The set callback is mostly called during a call to `loop()` but may also be called during a call to `subscribe()`, `unsubscribe()` or `publish() // QoS > 0` if messages have been received before receiving the required acknowledgement. Therefore, it is strongly recommended to not call `subscribe()`, `unsubscribe()` or `publish() // QoS > 0` directly in the callback.
|
||||
|
||||
Set more advanced options:
|
||||
|
||||
```c++
|
||||
void setOptions(int keepAlive, bool cleanSession, int timeout);
|
||||
```
|
||||
|
||||
- The `keepAlive` option controls the keep alive interval in seconds (default: 10).
|
||||
- The `cleanSession` option controls the session retention on the broker side (default: true).
|
||||
- The `timeout` option controls the default timeout for all commands in milliseconds (default: 1000).
|
||||
|
||||
Connect to broker using the supplied client id and an optional username and password:
|
||||
|
||||
```c++
|
||||
bool connect(const char clientId[]);
|
||||
bool connect(const char clientId[], const char username[]);
|
||||
bool connect(const char clientId[], const char username[], const char password[]);
|
||||
```
|
||||
|
||||
- This functions returns a boolean that indicates if the connection has been established successfully.
|
||||
|
||||
Publishes a message to the broker with an optional payload:
|
||||
|
||||
```c++
|
||||
bool publish(const String &topic);
|
||||
bool publish(const char topic[]);
|
||||
bool publish(const String &topic, const String &payload);
|
||||
bool publish(const String &topic, const String &payload, bool retained, int qos);
|
||||
bool publish(const char topic[], const String &payload);
|
||||
bool publish(const char topic[], const String &payload, bool retained, int qos);
|
||||
bool publish(const char topic[], const char payload[]);
|
||||
bool publish(const char topic[], const char payload[], bool retained, int qos);
|
||||
bool publish(const char topic[], const char payload[], int length);
|
||||
bool publish(const char topic[], const char payload[], int length, bool retained, int qos);
|
||||
```
|
||||
|
||||
Subscribe to a topic:
|
||||
|
||||
```c++
|
||||
bool subscribe(const String &topic);
|
||||
bool subscribe(const String &topic, int qos);
|
||||
bool subscribe(const char topic[]);
|
||||
bool subscribe(const char topic[], int qos);
|
||||
```
|
||||
|
||||
Unsubscribe from a topic:
|
||||
|
||||
```c++
|
||||
bool unsubscribe(const String &topic);
|
||||
bool unsubscribe(const char topic[]);
|
||||
```
|
||||
|
||||
Sends and receives packets:
|
||||
|
||||
```c++
|
||||
bool loop();
|
||||
```
|
||||
|
||||
- This function should be called in every `loop`.
|
||||
|
||||
Check if the client is currently connected:
|
||||
|
||||
```c++
|
||||
bool connected();
|
||||
```
|
||||
|
||||
Access low-level information for debugging:
|
||||
|
||||
```c++
|
||||
lwmqtt_err_t lastError();
|
||||
lwmqtt_return_code_t returnCode();
|
||||
```
|
||||
|
||||
- The error codes can be found [here](https://github.com/256dpi/lwmqtt/blob/master/include/lwmqtt.h#L11).
|
||||
- The return codes can be found [here](https://github.com/256dpi/lwmqtt/blob/master/include/lwmqtt.h#L243).
|
||||
|
||||
Disconnect from the broker:
|
||||
|
||||
```c++
|
||||
bool disconnect();
|
||||
```
|
||||
|
||||
## Release Management
|
||||
|
||||
- Update version in `library.properties`.
|
||||
- Create release on GitHub.
|
|
@ -0,0 +1,69 @@
|
|||
// This example uses an Adafruit Huzzah ESP8266
|
||||
// to connect to shiftr.io.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Joël Gähwiler
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char ssid[] = "ssid";
|
||||
const char pass[] = "pass";
|
||||
|
||||
WiFiClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, pass);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
client.begin("broker.shiftr.io", net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
delay(10); // <- fixes some issues with WiFi stability
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// This example uses an Adafruit Huzzah ESP8266
|
||||
// to connect to shiftr.io.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Joël Gähwiler
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char ssid[] = "ssid";
|
||||
const char pass[] = "pass";
|
||||
|
||||
WiFiClientSecure net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, pass);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
//
|
||||
// MQTT brokers usually use port 8883 for secure connections.
|
||||
client.begin("broker.shiftr.io", 8883, net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
delay(10); // <- fixes some issues with WiFi stability
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// This example uses an Arduino Uno together with
|
||||
// an Ethernet Shield to connect to shiftr.io.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Joël Gähwiler
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <Ethernet.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
byte ip[] = {192, 168, 1, 177}; // <- change to match your network
|
||||
|
||||
EthernetClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("connecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Ethernet.begin(mac, ip);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
client.begin("broker.shiftr.io", net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// This example uses an Arduino MKR GSM 1400 board
|
||||
// to connect to shiftr.io.
|
||||
//
|
||||
// IMPORTANT: This example uses the new MKRGSM library.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Sandeep Mistry
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <MKRGSM.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char pin[] = "";
|
||||
const char apn[] = "apn";
|
||||
const char login[] = "login";
|
||||
const char password[] = "password";
|
||||
|
||||
GSMClient net;
|
||||
GPRS gprs;
|
||||
GSM gsmAccess;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
// connection state
|
||||
bool connected = false;
|
||||
|
||||
Serial.print("connecting to cellular network ...");
|
||||
|
||||
// After starting the modem with gsmAccess.begin()
|
||||
// attach to the GPRS network with the APN, login and password
|
||||
while (!connected) {
|
||||
if ((gsmAccess.begin(pin) == GSM_READY) &&
|
||||
(gprs.attachGPRS(apn, login, password) == GPRS_READY)) {
|
||||
connected = true;
|
||||
} else {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
client.begin("broker.shiftr.io", net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// This example uses an Arduino MKR GSM 1400 board
|
||||
// to securely connect to shiftr.io.
|
||||
//
|
||||
// IMPORTANT: This example uses the new MKRGSM library.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Sandeep Mistry
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <MKRGSM.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char pin[] = "";
|
||||
const char apn[] = "apn";
|
||||
const char login[] = "login";
|
||||
const char password[] = "password";
|
||||
|
||||
GSMSSLClient net;
|
||||
GPRS gprs;
|
||||
GSM gsmAccess;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
// connection state
|
||||
bool connected = false;
|
||||
|
||||
Serial.print("connecting to cellular network ...");
|
||||
|
||||
// After starting the modem with gsmAccess.begin()
|
||||
// attach to the GPRS network with the APN, login and password
|
||||
while (!connected) {
|
||||
if ((gsmAccess.begin(pin) == GSM_READY) &&
|
||||
(gprs.attachGPRS(apn, login, password) == GPRS_READY)) {
|
||||
connected = true;
|
||||
} else {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
//
|
||||
// MQTT brokers usually use port 8883 for secure connections.
|
||||
client.begin("broker.shiftr.io", 8883, net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// This example uses an Arduino/Genuino Zero together with
|
||||
// a WiFi101 Shield or a MKR1000 to connect to shiftr.io.
|
||||
//
|
||||
// IMPORTANT: This example uses the new WiFi101 library.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Gilberto Conti
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <WiFi101.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char ssid[] = "ssid";
|
||||
const char pass[] = "pass";
|
||||
|
||||
WiFiClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, pass);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
client.begin("broker.shiftr.io", net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// This example uses an Arduino/Genuino Zero together with
|
||||
// a WiFi101 Shield or a MKR1000 to connect to shiftr.io.
|
||||
//
|
||||
// IMPORTANT: This example uses the new WiFi101 library.
|
||||
//
|
||||
// IMPORTANT: You need to install/update the SSL certificates first:
|
||||
// https://github.com/arduino-libraries/WiFi101-FirmwareUpdater#to-update-ssl-certificates
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Gilberto Conti
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <WiFi101.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char ssid[] = "ssid";
|
||||
const char pass[] = "pass";
|
||||
|
||||
WiFiSSLClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, pass);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
//
|
||||
// MQTT brokers usually use port 8883 for secure connections.
|
||||
client.begin("broker.shiftr.io", 8883, net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// This example uses an Arduino Uno together with
|
||||
// a WiFi Shield to connect to shiftr.io.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Joël Gähwiler
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char ssid[] = "ssid";
|
||||
const char pass[] = "pass";
|
||||
|
||||
WiFiClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, pass);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
client.begin("broker.shiftr.io", net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// This example uses an Arduino Yun or a Yun-Shield
|
||||
// and the MQTTClient to connect to shiftr.io.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Joël Gähwiler
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <Bridge.h>
|
||||
#include <BridgeClient.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
BridgeClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("connecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Bridge.begin();
|
||||
Serial.begin(115200);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
client.begin("broker.shiftr.io", net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// This example uses an Arduino Yun or a Yun-Shield
|
||||
// and the MQTTClient to connect to shiftr.io.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Joël Gähwiler
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <Bridge.h>
|
||||
#include <BridgeSSLClient.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
BridgeSSLClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("connecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Bridge.begin();
|
||||
Serial.begin(115200);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
//
|
||||
// MQTT brokers usually use port 8883 for secure connections.
|
||||
client.begin("broker.shiftr.io", 8883, net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// This example uses an ESP32 Development Board
|
||||
// to connect to shiftr.io.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Joël Gähwiler
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char ssid[] = "ssid";
|
||||
const char pass[] = "pass";
|
||||
|
||||
WiFiClient net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, pass);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
client.begin("broker.shiftr.io", net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
delay(10); // <- fixes some issues with WiFi stability
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// This example uses an ESP32 Development Board
|
||||
// to connect to shiftr.io.
|
||||
//
|
||||
// You can check on your device after a successful
|
||||
// connection here: https://shiftr.io/try.
|
||||
//
|
||||
// by Joël Gähwiler
|
||||
// https://github.com/256dpi/arduino-mqtt
|
||||
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
const char ssid[] = "ssid";
|
||||
const char pass[] = "pass";
|
||||
|
||||
WiFiClientSecure net;
|
||||
MQTTClient client;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
void connect() {
|
||||
Serial.print("checking wifi...");
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("\nconnecting...");
|
||||
while (!client.connect("arduino", "try", "try")) {
|
||||
Serial.print(".");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.println("\nconnected!");
|
||||
|
||||
client.subscribe("/hello");
|
||||
// client.unsubscribe("/hello");
|
||||
}
|
||||
|
||||
void messageReceived(String &topic, String &payload) {
|
||||
Serial.println("incoming: " + topic + " - " + payload);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid, pass);
|
||||
|
||||
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
|
||||
// You need to set the IP address directly.
|
||||
//
|
||||
// MQTT brokers usually use port 8883 for secure connections.
|
||||
client.begin("broker.shiftr.io", 8883, net);
|
||||
client.onMessage(messageReceived);
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
client.loop();
|
||||
delay(10); // <- fixes some issues with WiFi stability
|
||||
|
||||
if (!client.connected()) {
|
||||
connect();
|
||||
}
|
||||
|
||||
// publish a message roughly every second.
|
||||
if (millis() - lastMillis > 1000) {
|
||||
lastMillis = millis();
|
||||
client.publish("/hello", "world");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
name=MQTT
|
||||
version=2.3.3
|
||||
author=Joel Gaehwiler <joel.gaehwiler@gmail.com>
|
||||
maintainer=Joel Gaehwiler <joel.gaehwiler@gmail.com>
|
||||
sentence=MQTT library for Arduino
|
||||
paragraph=This library bundles the lwmqtt client and adds a thin wrapper to get an Arduino like API.
|
||||
category=Communication
|
||||
url=https://github.com/256dpi/arduino-mqtt
|
||||
architectures=*
|
|
@ -0,0 +1,386 @@
|
|||
#ifndef MQTT_CLIENT_H
|
||||
#define MQTT_CLIENT_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Client.h>
|
||||
#include <Stream.h>
|
||||
|
||||
#include "system.h"
|
||||
|
||||
class MQTTClient;
|
||||
|
||||
typedef void (*MQTTClientCallbackSimple)(String &topic, String &payload);
|
||||
typedef void (*MQTTClientCallbackAdvanced)(MQTTClient *client, char topic[], char bytes[], int length);
|
||||
|
||||
typedef struct {
|
||||
MQTTClient *client = nullptr;
|
||||
MQTTClientCallbackSimple simple = nullptr;
|
||||
MQTTClientCallbackAdvanced advanced = nullptr;
|
||||
} MQTTClientCallback;
|
||||
|
||||
static void MQTTClientHandler(lwmqtt_client_t * /*client*/, void *ref, lwmqtt_string_t topic,
|
||||
lwmqtt_message_t message) {
|
||||
// get callback
|
||||
auto cb = (MQTTClientCallback *)ref;
|
||||
|
||||
// null terminate topic
|
||||
char terminated_topic[topic.len + 1];
|
||||
memcpy(terminated_topic, topic.data, topic.len);
|
||||
terminated_topic[topic.len] = '\0';
|
||||
|
||||
// null terminate payload if available
|
||||
if (message.payload != nullptr) {
|
||||
message.payload[message.payload_len] = '\0';
|
||||
}
|
||||
|
||||
// call the advanced callback and return if available
|
||||
if (cb->advanced != nullptr) {
|
||||
cb->advanced(cb->client, terminated_topic, (char *)message.payload, (int)message.payload_len);
|
||||
return;
|
||||
}
|
||||
|
||||
// return if simple callback is not set
|
||||
if (cb->simple == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create topic string
|
||||
String str_topic = String(terminated_topic);
|
||||
|
||||
// create payload string
|
||||
String str_payload;
|
||||
if (message.payload != nullptr) {
|
||||
str_payload = String((const char *)message.payload);
|
||||
}
|
||||
|
||||
// call simple callback
|
||||
cb->simple(str_topic, str_payload);
|
||||
}
|
||||
|
||||
class MQTTClient {
|
||||
private:
|
||||
size_t bufSize = 0;
|
||||
uint8_t *readBuf = nullptr;
|
||||
uint8_t *writeBuf = nullptr;
|
||||
|
||||
uint16_t keepAlive = 10;
|
||||
bool cleanSession = true;
|
||||
uint32_t timeout = 1000;
|
||||
|
||||
Client *netClient = nullptr;
|
||||
const char *hostname = nullptr;
|
||||
int port = 0;
|
||||
lwmqtt_will_t will = lwmqtt_default_will;
|
||||
bool hasWill = false;
|
||||
MQTTClientCallback callback;
|
||||
|
||||
lwmqtt_arduino_network_t network = {nullptr};
|
||||
lwmqtt_arduino_timer_t timer1 = {0};
|
||||
lwmqtt_arduino_timer_t timer2 = {0};
|
||||
lwmqtt_client_t client;
|
||||
|
||||
bool _connected = false;
|
||||
lwmqtt_return_code_t _returnCode = (lwmqtt_return_code_t)0;
|
||||
lwmqtt_err_t _lastError = (lwmqtt_err_t)0;
|
||||
|
||||
public:
|
||||
explicit MQTTClient(int bufSize = 128) {
|
||||
memset(&client, 0, sizeof(client));
|
||||
this->bufSize = (size_t)bufSize;
|
||||
this->readBuf = (uint8_t *)malloc((size_t)bufSize + 1);
|
||||
this->writeBuf = (uint8_t *)malloc((size_t)bufSize);
|
||||
}
|
||||
|
||||
~MQTTClient() {
|
||||
free(this->readBuf);
|
||||
free(this->writeBuf);
|
||||
}
|
||||
|
||||
void begin(const char hostname[], Client &client) { this->begin(hostname, 1883, client); }
|
||||
|
||||
void begin(const char hostname[], int port, Client &client) {
|
||||
// set hostname and port
|
||||
this->setHost(hostname, port);
|
||||
|
||||
// set client
|
||||
this->netClient = &client;
|
||||
|
||||
// initialize client
|
||||
lwmqtt_init(&this->client, this->writeBuf, this->bufSize, this->readBuf, this->bufSize);
|
||||
|
||||
// set timers
|
||||
lwmqtt_set_timers(&this->client, &this->timer1, &this->timer2, lwmqtt_arduino_timer_set, lwmqtt_arduino_timer_get);
|
||||
|
||||
// set network
|
||||
lwmqtt_set_network(&this->client, &this->network, lwmqtt_arduino_network_read, lwmqtt_arduino_network_write);
|
||||
|
||||
// set callback
|
||||
lwmqtt_set_callback(&this->client, (void *)&this->callback, MQTTClientHandler);
|
||||
}
|
||||
|
||||
void onMessage(MQTTClientCallbackSimple cb) {
|
||||
// set callback
|
||||
this->callback.client = this;
|
||||
this->callback.simple = cb;
|
||||
this->callback.advanced = nullptr;
|
||||
}
|
||||
|
||||
void onMessageAdvanced(MQTTClientCallbackAdvanced cb) {
|
||||
// set callback
|
||||
this->callback.client = this;
|
||||
this->callback.simple = nullptr;
|
||||
this->callback.advanced = cb;
|
||||
}
|
||||
|
||||
void setHost(const char hostname[]) { this->setHost(hostname, 1883); }
|
||||
|
||||
void setHost(const char hostname[], int port) {
|
||||
// free hostname if set
|
||||
if(this->hostname != nullptr) {
|
||||
free((void *)this->hostname);
|
||||
}
|
||||
|
||||
// set hostname and port
|
||||
this->hostname = strdup(hostname);
|
||||
this->port = port;
|
||||
}
|
||||
|
||||
void setWill(const char topic[]) { this->setWill(topic, ""); }
|
||||
|
||||
void setWill(const char topic[], const char payload[]) { this->setWill(topic, payload, false, 0); }
|
||||
|
||||
void setWill(const char topic[], const char payload[], bool retained, int qos) {
|
||||
this->hasWill = true;
|
||||
this->will.topic = lwmqtt_string(topic);
|
||||
this->will.payload = lwmqtt_string(payload);
|
||||
this->will.retained = retained;
|
||||
this->will.qos = (lwmqtt_qos_t)qos;
|
||||
}
|
||||
|
||||
void clearWill() { this->hasWill = false; }
|
||||
|
||||
void setOptions(int keepAlive, bool cleanSession, int timeout) {
|
||||
this->keepAlive = (uint16_t)keepAlive;
|
||||
this->cleanSession = cleanSession;
|
||||
this->timeout = (uint32_t)timeout;
|
||||
}
|
||||
|
||||
bool connect(const char clientId[]) { return this->connect(clientId, nullptr, nullptr); }
|
||||
|
||||
bool connect(const char clientId[], const char username[]) { return this->connect(clientId, username, nullptr); }
|
||||
|
||||
bool connect(const char clientId[], const char username[], const char password[]) {
|
||||
// close left open connection if still connected
|
||||
if (this->connected()) {
|
||||
this->close();
|
||||
}
|
||||
|
||||
// save client
|
||||
this->network.client = this->netClient;
|
||||
|
||||
// connect to host
|
||||
if (this->netClient->connect(this->hostname, (uint16_t)this->port) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// prepare options
|
||||
lwmqtt_options_t options = lwmqtt_default_options;
|
||||
options.keep_alive = this->keepAlive;
|
||||
options.clean_session = this->cleanSession;
|
||||
options.client_id = lwmqtt_string(clientId);
|
||||
|
||||
// set username and password if available
|
||||
if (username != nullptr) {
|
||||
options.username = lwmqtt_string(username);
|
||||
|
||||
if (password != nullptr) {
|
||||
options.password = lwmqtt_string(password);
|
||||
}
|
||||
}
|
||||
|
||||
// prepare will reference
|
||||
lwmqtt_will_t *will = nullptr;
|
||||
if (this->hasWill) {
|
||||
will = &this->will;
|
||||
}
|
||||
|
||||
// connect to broker
|
||||
this->_lastError = lwmqtt_connect(&this->client, options, will, &this->_returnCode, this->timeout);
|
||||
if (this->_lastError != LWMQTT_SUCCESS) {
|
||||
// close connection
|
||||
this->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// set flag
|
||||
this->_connected = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool publish(const String &topic) { return this->publish(topic.c_str(), ""); }
|
||||
|
||||
bool publish(const char topic[]) { return this->publish(topic, ""); }
|
||||
|
||||
bool publish(const String &topic, const String &payload) { return this->publish(topic.c_str(), payload.c_str()); }
|
||||
|
||||
bool publish(const String &topic, const String &payload, bool retained, int qos) {
|
||||
return this->publish(topic.c_str(), payload.c_str(), retained, qos);
|
||||
}
|
||||
|
||||
bool publish(const char topic[], const String &payload) { return this->publish(topic, payload.c_str()); }
|
||||
|
||||
bool publish(const char topic[], const String &payload, bool retained, int qos) {
|
||||
return this->publish(topic, payload.c_str(), retained, qos);
|
||||
}
|
||||
|
||||
bool publish(const char topic[], const char payload[]) {
|
||||
return this->publish(topic, (char *)payload, (int)strlen(payload));
|
||||
}
|
||||
|
||||
bool publish(const char topic[], const char payload[], bool retained, int qos) {
|
||||
return this->publish(topic, (char *)payload, (int)strlen(payload), retained, qos);
|
||||
}
|
||||
|
||||
bool publish(const char topic[], const char payload[], int length) {
|
||||
return this->publish(topic, payload, length, false, 0);
|
||||
}
|
||||
|
||||
bool publish(const char topic[], const char payload[], int length, bool retained, int qos) {
|
||||
// return immediately if not connected
|
||||
if (!this->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// prepare message
|
||||
lwmqtt_message_t message = lwmqtt_default_message;
|
||||
message.payload = (uint8_t *)payload;
|
||||
message.payload_len = (size_t)length;
|
||||
message.retained = retained;
|
||||
message.qos = lwmqtt_qos_t(qos);
|
||||
|
||||
// publish message
|
||||
this->_lastError = lwmqtt_publish(&this->client, lwmqtt_string(topic), message, this->timeout);
|
||||
if (this->_lastError != LWMQTT_SUCCESS) {
|
||||
// close connection
|
||||
this->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subscribe(const String &topic) { return this->subscribe(topic.c_str()); }
|
||||
|
||||
bool subscribe(const String &topic, int qos) { return this->subscribe(topic.c_str(), qos); }
|
||||
|
||||
bool subscribe(const char topic[]) { return this->subscribe(topic, 0); }
|
||||
|
||||
bool subscribe(const char topic[], int qos) {
|
||||
// return immediately if not connected
|
||||
if (!this->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// subscribe to topic
|
||||
this->_lastError = lwmqtt_subscribe_one(&this->client, lwmqtt_string(topic), (lwmqtt_qos_t)qos, this->timeout);
|
||||
if (this->_lastError != LWMQTT_SUCCESS) {
|
||||
// close connection
|
||||
this->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool unsubscribe(const String &topic) { return this->unsubscribe(topic.c_str()); }
|
||||
|
||||
bool unsubscribe(const char topic[]) {
|
||||
// return immediately if not connected
|
||||
if (!this->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// unsubscribe from topic
|
||||
this->_lastError = lwmqtt_unsubscribe_one(&this->client, lwmqtt_string(topic), this->timeout);
|
||||
if (this->_lastError != LWMQTT_SUCCESS) {
|
||||
// close connection
|
||||
this->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loop() {
|
||||
// return immediately if not connected
|
||||
if (!this->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get available bytes on the network
|
||||
auto available = (size_t)this->netClient->available();
|
||||
|
||||
// yield if data is available
|
||||
if (available > 0) {
|
||||
this->_lastError = lwmqtt_yield(&this->client, available, this->timeout);
|
||||
if (this->_lastError != LWMQTT_SUCCESS) {
|
||||
// close connection
|
||||
this->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// keep the connection alive
|
||||
this->_lastError = lwmqtt_keep_alive(&this->client, this->timeout);
|
||||
if (this->_lastError != LWMQTT_SUCCESS) {
|
||||
// close connection
|
||||
this->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool connected() {
|
||||
// a client is connected if the network is connected, a client is available and
|
||||
// the connection has been properly initiated
|
||||
return this->netClient != nullptr && this->netClient->connected() == 1 && this->_connected;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lastError() { return this->_lastError; }
|
||||
|
||||
lwmqtt_return_code_t returnCode() { return this->_returnCode; }
|
||||
|
||||
bool disconnect() {
|
||||
// return immediately if not connected anymore
|
||||
if (!this->connected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// cleanly disconnect
|
||||
this->_lastError = lwmqtt_disconnect(&this->client, this->timeout);
|
||||
|
||||
// close
|
||||
this->close();
|
||||
|
||||
return this->_lastError == LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
private:
|
||||
void close() {
|
||||
// set flag
|
||||
this->_connected = false;
|
||||
|
||||
// close network
|
||||
this->netClient->stop();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef MQTT_H
|
||||
#define MQTT_H
|
||||
|
||||
#include "MQTTClient.h"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,618 @@
|
|||
#include "packet.h"
|
||||
|
||||
void lwmqtt_init(lwmqtt_client_t *client, uint8_t *write_buf, size_t write_buf_size, uint8_t *read_buf,
|
||||
size_t read_buf_size) {
|
||||
client->last_packet_id = 1;
|
||||
client->keep_alive_interval = 0;
|
||||
client->pong_pending = false;
|
||||
|
||||
client->write_buf = write_buf;
|
||||
client->write_buf_size = write_buf_size;
|
||||
client->read_buf = read_buf;
|
||||
client->read_buf_size = read_buf_size;
|
||||
|
||||
client->callback = NULL;
|
||||
client->callback_ref = NULL;
|
||||
|
||||
client->network = NULL;
|
||||
client->network_read = NULL;
|
||||
client->network_write = NULL;
|
||||
|
||||
client->keep_alive_timer = NULL;
|
||||
client->command_timer = NULL;
|
||||
client->timer_set = NULL;
|
||||
client->timer_get = NULL;
|
||||
}
|
||||
|
||||
void lwmqtt_set_network(lwmqtt_client_t *client, void *ref, lwmqtt_network_read_t read, lwmqtt_network_write_t write) {
|
||||
client->network = ref;
|
||||
client->network_read = read;
|
||||
client->network_write = write;
|
||||
}
|
||||
|
||||
void lwmqtt_set_timers(lwmqtt_client_t *client, void *keep_alive_timer, void *command_timer, lwmqtt_timer_set_t set,
|
||||
lwmqtt_timer_get_t get) {
|
||||
client->keep_alive_timer = keep_alive_timer;
|
||||
client->command_timer = command_timer;
|
||||
client->timer_set = set;
|
||||
client->timer_get = get;
|
||||
|
||||
client->timer_set(client->keep_alive_timer, 0);
|
||||
client->timer_set(client->command_timer, 0);
|
||||
}
|
||||
|
||||
void lwmqtt_set_callback(lwmqtt_client_t *client, void *ref, lwmqtt_callback_t cb) {
|
||||
client->callback_ref = ref;
|
||||
client->callback = cb;
|
||||
}
|
||||
|
||||
static uint16_t lwmqtt_get_next_packet_id(lwmqtt_client_t *client) {
|
||||
// check overflow
|
||||
if (client->last_packet_id == 65535) {
|
||||
client->last_packet_id = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// increment packet id
|
||||
client->last_packet_id++;
|
||||
|
||||
return client->last_packet_id;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_read_from_network(lwmqtt_client_t *client, size_t offset, size_t len) {
|
||||
// check read buffer capacity
|
||||
if (client->read_buf_size < offset + len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// prepare counter
|
||||
size_t read = 0;
|
||||
|
||||
// read while data is missing
|
||||
while (read < len) {
|
||||
// check remaining time
|
||||
int32_t remaining_time = client->timer_get(client->command_timer);
|
||||
if (remaining_time <= 0) {
|
||||
return LWMQTT_NETWORK_TIMEOUT;
|
||||
}
|
||||
|
||||
// read
|
||||
size_t partial_read = 0;
|
||||
lwmqtt_err_t err = client->network_read(client->network, client->read_buf + offset + read, len - read,
|
||||
&partial_read, (uint32_t)remaining_time);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// increment counter
|
||||
read += partial_read;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_write_to_network(lwmqtt_client_t *client, size_t offset, size_t len) {
|
||||
// prepare counter
|
||||
size_t written = 0;
|
||||
|
||||
// write while data is left
|
||||
while (written < len) {
|
||||
// check remaining time
|
||||
int32_t remaining_time = client->timer_get(client->command_timer);
|
||||
if (remaining_time <= 0) {
|
||||
return LWMQTT_NETWORK_TIMEOUT;
|
||||
}
|
||||
|
||||
// write
|
||||
size_t partial_write = 0;
|
||||
lwmqtt_err_t err = client->network_write(client->network, client->write_buf + offset + written, len - written,
|
||||
&partial_write, (uint32_t)remaining_time);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// increment counter
|
||||
written += partial_write;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_read_packet_in_buffer(lwmqtt_client_t *client, size_t *read,
|
||||
lwmqtt_packet_type_t *packet_type) {
|
||||
// preset packet type
|
||||
*packet_type = LWMQTT_NO_PACKET;
|
||||
|
||||
// read or wait for header byte
|
||||
lwmqtt_err_t err = lwmqtt_read_from_network(client, 0, 1);
|
||||
if (err == LWMQTT_NETWORK_TIMEOUT) {
|
||||
// this is ok as no data has been read at all
|
||||
return LWMQTT_SUCCESS;
|
||||
} else if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// detect packet type
|
||||
err = lwmqtt_detect_packet_type(client->read_buf, 1, packet_type);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// prepare variables
|
||||
size_t len = 0;
|
||||
uint32_t rem_len = 0;
|
||||
|
||||
do {
|
||||
// adjust len
|
||||
len++;
|
||||
|
||||
// read next byte
|
||||
err = lwmqtt_read_from_network(client, len, 1);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// attempt to detect remaining length
|
||||
err = lwmqtt_detect_remaining_length(client->read_buf + 1, len, &rem_len);
|
||||
} while (err == LWMQTT_BUFFER_TOO_SHORT);
|
||||
|
||||
// check final error
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// read the rest of the buffer if needed
|
||||
if (rem_len > 0) {
|
||||
err = lwmqtt_read_from_network(client, 1 + len, rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// adjust counter
|
||||
*read += 1 + len + rem_len;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_send_packet_in_buffer(lwmqtt_client_t *client, size_t length) {
|
||||
// write to network
|
||||
lwmqtt_err_t err = lwmqtt_write_to_network(client, 0, length);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// reset keep alive timer
|
||||
client->timer_set(client->keep_alive_timer, client->keep_alive_interval);
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_cycle(lwmqtt_client_t *client, size_t *read, lwmqtt_packet_type_t *packet_type) {
|
||||
// read next packet from the network
|
||||
lwmqtt_err_t err = lwmqtt_read_packet_in_buffer(client, read, packet_type);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (*packet_type == LWMQTT_NO_PACKET) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
switch (*packet_type) {
|
||||
// handle publish packets
|
||||
case LWMQTT_PUBLISH_PACKET: {
|
||||
// decode publish packet
|
||||
bool dup;
|
||||
uint16_t packet_id;
|
||||
lwmqtt_string_t topic;
|
||||
lwmqtt_message_t msg;
|
||||
err = lwmqtt_decode_publish(client->read_buf, client->read_buf_size, &dup, &packet_id, &topic, &msg);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// call callback if set
|
||||
if (client->callback != NULL) {
|
||||
client->callback(client, client->callback_ref, topic, msg);
|
||||
}
|
||||
|
||||
// break early on qos zero
|
||||
if (msg.qos == LWMQTT_QOS0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// define ack packet
|
||||
lwmqtt_packet_type_t ack_type = LWMQTT_NO_PACKET;
|
||||
if (msg.qos == LWMQTT_QOS1) {
|
||||
ack_type = LWMQTT_PUBACK_PACKET;
|
||||
} else if (msg.qos == LWMQTT_QOS2) {
|
||||
ack_type = LWMQTT_PUBREC_PACKET;
|
||||
}
|
||||
|
||||
// encode ack packet
|
||||
size_t len;
|
||||
err = lwmqtt_encode_ack(client->write_buf, client->write_buf_size, &len, ack_type, false, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send ack packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// handle pubrec packets
|
||||
case LWMQTT_PUBREC_PACKET: {
|
||||
// decode pubrec packet
|
||||
bool dup;
|
||||
uint16_t packet_id;
|
||||
err = lwmqtt_decode_ack(client->read_buf, client->read_buf_size, LWMQTT_PUBREC_PACKET, &dup, &packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// encode pubrel packet
|
||||
size_t len;
|
||||
err = lwmqtt_encode_ack(client->write_buf, client->write_buf_size, &len, LWMQTT_PUBREL_PACKET, 0, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send pubrel packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// handle pubrel packets
|
||||
case LWMQTT_PUBREL_PACKET: {
|
||||
// decode pubrec packet
|
||||
bool dup;
|
||||
uint16_t packet_id;
|
||||
err = lwmqtt_decode_ack(client->read_buf, client->read_buf_size, LWMQTT_PUBREL_PACKET, &dup, &packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// encode pubcomp packet
|
||||
size_t len;
|
||||
err = lwmqtt_encode_ack(client->write_buf, client->write_buf_size, &len, LWMQTT_PUBCOMP_PACKET, 0, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send pubcomp packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// handle pingresp packets
|
||||
case LWMQTT_PINGRESP_PACKET: {
|
||||
// set flag
|
||||
client->pong_pending = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// handle all other packets
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
static lwmqtt_err_t lwmqtt_cycle_until(lwmqtt_client_t *client, lwmqtt_packet_type_t *packet_type, size_t available,
|
||||
lwmqtt_packet_type_t needle) {
|
||||
// prepare counter
|
||||
size_t read = 0;
|
||||
|
||||
// loop until timeout has been reached
|
||||
do {
|
||||
// do one cycle
|
||||
lwmqtt_err_t err = lwmqtt_cycle(client, &read, packet_type);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// return when one packet has been successfully read when no availability has been given
|
||||
if (needle == LWMQTT_NO_PACKET && available == 0) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// otherwise check if needle has been found
|
||||
if (*packet_type == needle) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
} while (client->timer_get(client->command_timer) > 0 && (available == 0 || read < available));
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_yield(lwmqtt_client_t *client, size_t available, uint32_t timeout) {
|
||||
// set command timer
|
||||
client->timer_set(client->command_timer, timeout);
|
||||
|
||||
// cycle until timeout has been reached
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
lwmqtt_err_t err = lwmqtt_cycle_until(client, &packet_type, available, LWMQTT_NO_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_connect(lwmqtt_client_t *client, lwmqtt_options_t options, lwmqtt_will_t *will,
|
||||
lwmqtt_return_code_t *return_code, uint32_t timeout) {
|
||||
// set command timer
|
||||
client->timer_set(client->command_timer, timeout);
|
||||
|
||||
// save keep alive interval (take 75% to be a little earlier than actually needed)
|
||||
client->keep_alive_interval = (uint32_t)(options.keep_alive * 750);
|
||||
|
||||
// set keep alive timer
|
||||
client->timer_set(client->keep_alive_timer, client->keep_alive_interval);
|
||||
|
||||
// reset pong pending flag
|
||||
client->pong_pending = false;
|
||||
|
||||
// initialize return code
|
||||
*return_code = LWMQTT_UNKNOWN_RETURN_CODE;
|
||||
|
||||
// encode connect packet
|
||||
size_t len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_connect(client->write_buf, client->write_buf_size, &len, options, will);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// wait for connack packet
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_CONNACK_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (packet_type != LWMQTT_CONNACK_PACKET) {
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// decode connack packet
|
||||
bool session_present;
|
||||
err = lwmqtt_decode_connack(client->read_buf, client->read_buf_size, &session_present, return_code);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// return error if connection was not accepted
|
||||
if (*return_code != LWMQTT_CONNECTION_ACCEPTED) {
|
||||
return LWMQTT_CONNECTION_DENIED;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_subscribe(lwmqtt_client_t *client, int count, lwmqtt_string_t *topic_filter, lwmqtt_qos_t *qos,
|
||||
uint32_t timeout) {
|
||||
// set command timer
|
||||
client->timer_set(client->command_timer, timeout);
|
||||
|
||||
// encode subscribe packet
|
||||
size_t len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_subscribe(client->write_buf, client->write_buf_size, &len,
|
||||
lwmqtt_get_next_packet_id(client), count, topic_filter, qos);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// wait for suback packet
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_SUBACK_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (packet_type != LWMQTT_SUBACK_PACKET) {
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// decode packet
|
||||
int suback_count = 0;
|
||||
lwmqtt_qos_t granted_qos[count];
|
||||
uint16_t packet_id;
|
||||
err = lwmqtt_decode_suback(client->read_buf, client->read_buf_size, &packet_id, count, &suback_count, granted_qos);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check suback codes
|
||||
for (int i = 0; i < suback_count; i++) {
|
||||
if (granted_qos[i] == LWMQTT_QOS_FAILURE) {
|
||||
return LWMQTT_FAILED_SUBSCRIPTION;
|
||||
}
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_subscribe_one(lwmqtt_client_t *client, lwmqtt_string_t topic_filter, lwmqtt_qos_t qos,
|
||||
uint32_t timeout) {
|
||||
return lwmqtt_subscribe(client, 1, &topic_filter, &qos, timeout);
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_unsubscribe(lwmqtt_client_t *client, int count, lwmqtt_string_t *topic_filter, uint32_t timeout) {
|
||||
// set command timer
|
||||
client->timer_set(client->command_timer, timeout);
|
||||
|
||||
// encode unsubscribe packet
|
||||
size_t len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_unsubscribe(client->write_buf, client->write_buf_size, &len,
|
||||
lwmqtt_get_next_packet_id(client), count, topic_filter);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send unsubscribe packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// wait for unsuback packet
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
err = lwmqtt_cycle_until(client, &packet_type, 0, LWMQTT_UNSUBACK_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (packet_type != LWMQTT_UNSUBACK_PACKET) {
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// decode unsuback packet
|
||||
bool dup;
|
||||
uint16_t packet_id;
|
||||
err = lwmqtt_decode_ack(client->read_buf, client->read_buf_size, LWMQTT_UNSUBACK_PACKET, &dup, &packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_unsubscribe_one(lwmqtt_client_t *client, lwmqtt_string_t topic_filter, uint32_t timeout) {
|
||||
return lwmqtt_unsubscribe(client, 1, &topic_filter, timeout);
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_publish(lwmqtt_client_t *client, lwmqtt_string_t topic, lwmqtt_message_t message,
|
||||
uint32_t timeout) {
|
||||
// set command timer
|
||||
client->timer_set(client->command_timer, timeout);
|
||||
|
||||
// add packet id if at least qos 1
|
||||
uint16_t packet_id = 0;
|
||||
if (message.qos == LWMQTT_QOS1 || message.qos == LWMQTT_QOS2) {
|
||||
packet_id = lwmqtt_get_next_packet_id(client);
|
||||
}
|
||||
|
||||
// encode publish packet
|
||||
size_t len = 0;
|
||||
lwmqtt_err_t err =
|
||||
lwmqtt_encode_publish(client->write_buf, client->write_buf_size, &len, 0, packet_id, topic, message);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// immediately return on qos zero
|
||||
if (message.qos == LWMQTT_QOS0) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// define ack packet
|
||||
lwmqtt_packet_type_t ack_type = LWMQTT_NO_PACKET;
|
||||
if (message.qos == LWMQTT_QOS1) {
|
||||
ack_type = LWMQTT_PUBACK_PACKET;
|
||||
} else if (message.qos == LWMQTT_QOS2) {
|
||||
ack_type = LWMQTT_PUBCOMP_PACKET;
|
||||
}
|
||||
|
||||
// wait for ack packet
|
||||
lwmqtt_packet_type_t packet_type = LWMQTT_NO_PACKET;
|
||||
err = lwmqtt_cycle_until(client, &packet_type, 0, ack_type);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
} else if (packet_type != ack_type) {
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// decode ack packet
|
||||
bool dup;
|
||||
err = lwmqtt_decode_ack(client->read_buf, client->read_buf_size, ack_type, &dup, &packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_disconnect(lwmqtt_client_t *client, uint32_t timeout) {
|
||||
// set command timer
|
||||
client->timer_set(client->command_timer, timeout);
|
||||
|
||||
// encode disconnect packet
|
||||
size_t len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_zero(client->write_buf, client->write_buf_size, &len, LWMQTT_DISCONNECT_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send disconnected packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_keep_alive(lwmqtt_client_t *client, uint32_t timeout) {
|
||||
// set command timer
|
||||
client->timer_set(client->command_timer, timeout);
|
||||
|
||||
// return immediately if keep alive interval is zero
|
||||
if (client->keep_alive_interval == 0) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// return immediately if no ping is due
|
||||
if (client->timer_get(client->keep_alive_timer) > 0) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// a ping is due
|
||||
|
||||
// fail immediately if a pong is already pending
|
||||
if (client->pong_pending) {
|
||||
return LWMQTT_PONG_TIMEOUT;
|
||||
}
|
||||
|
||||
// encode pingreq packet
|
||||
size_t len;
|
||||
lwmqtt_err_t err = lwmqtt_encode_zero(client->write_buf, client->write_buf_size, &len, LWMQTT_PINGREQ_PACKET);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// send packet
|
||||
err = lwmqtt_send_packet_in_buffer(client, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// set flag
|
||||
client->pong_pending = true;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
uint8_t lwmqtt_read_bits(uint8_t byte, int pos, int num) { return (byte & (uint8_t)((~(0xFF << num)) << pos)) >> pos; }
|
||||
|
||||
void lwmqtt_write_bits(uint8_t *byte, uint8_t value, int pos, int num) {
|
||||
*byte = (*byte & ~(uint8_t)((~(0xFF << num)) << pos)) | (value << pos);
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_read_data(uint8_t **buf, const uint8_t *buf_end, uint8_t **data, size_t len) {
|
||||
// check zero length
|
||||
if (len == 0) {
|
||||
*data = NULL;
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// check buffer size
|
||||
if ((size_t)(buf_end - (*buf)) < len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// read data
|
||||
*data = *buf;
|
||||
|
||||
// advance pointer
|
||||
*buf += len;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_write_data(uint8_t **buf, const uint8_t *buf_end, uint8_t *data, size_t len) {
|
||||
// check zero length
|
||||
if (len == 0) {
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
// check buffer size
|
||||
if ((size_t)(buf_end - (*buf)) < len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// write data
|
||||
memcpy(*buf, data, len);
|
||||
|
||||
// advance pointer
|
||||
*buf += len;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_read_num(uint8_t **buf, const uint8_t *buf_end, uint16_t *num) {
|
||||
// check buffer size
|
||||
if ((size_t)(buf_end - (*buf)) < 2) {
|
||||
*num = 0;
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// read two byte integer
|
||||
*num = (uint16_t)256 * (*buf)[0] + (*buf)[1];
|
||||
|
||||
// adjust pointer
|
||||
*buf += 2;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_write_num(uint8_t **buf, const uint8_t *buf_end, uint16_t num) {
|
||||
// check buffer size
|
||||
if ((size_t)(buf_end - (*buf)) < 2) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// write bytes
|
||||
(*buf)[0] = (uint8_t)(num / 256);
|
||||
(*buf)[1] = (uint8_t)(num % 256);
|
||||
|
||||
// adjust pointer
|
||||
*buf += 2;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_read_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t *str) {
|
||||
// read length
|
||||
uint16_t len;
|
||||
lwmqtt_err_t err = lwmqtt_read_num(buf, buf_end, &len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// read data
|
||||
err = lwmqtt_read_data(buf, buf_end, (uint8_t **)&str->data, len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// set length
|
||||
str->len = len;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_write_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t str) {
|
||||
// write string length
|
||||
lwmqtt_err_t err = lwmqtt_write_num(buf, buf_end, str.len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write data
|
||||
err = lwmqtt_write_data(buf, buf_end, (uint8_t *)str.data, str.len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_read_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t *byte) {
|
||||
// check buffer size
|
||||
if ((size_t)(buf_end - (*buf)) < 1) {
|
||||
*byte = 0;
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// read byte
|
||||
*byte = (*buf)[0];
|
||||
|
||||
// adjust pointer
|
||||
*buf += 1;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_write_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t byte) {
|
||||
// check buffer size
|
||||
if ((size_t)(buf_end - (*buf)) < 1) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// write byte
|
||||
(*buf)[0] = byte;
|
||||
|
||||
// adjust pointer
|
||||
*buf += 1;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_varnum_length(uint32_t varnum, int *len) {
|
||||
if (varnum < 128) {
|
||||
*len = 1;
|
||||
return LWMQTT_SUCCESS;
|
||||
} else if (varnum < 16384) {
|
||||
*len = 2;
|
||||
return LWMQTT_SUCCESS;
|
||||
} else if (varnum < 2097151) {
|
||||
*len = 3;
|
||||
return LWMQTT_SUCCESS;
|
||||
} else if (varnum < 268435455) {
|
||||
*len = 4;
|
||||
return LWMQTT_SUCCESS;
|
||||
} else {
|
||||
*len = 0;
|
||||
return LWMQTT_VARNUM_OVERFLOW;
|
||||
}
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_read_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t *varnum) {
|
||||
// prepare last byte
|
||||
uint8_t byte;
|
||||
|
||||
// prepare multiplier
|
||||
uint32_t multiplier = 1;
|
||||
|
||||
// prepare length
|
||||
size_t len = 0;
|
||||
|
||||
// initialize number
|
||||
*varnum = 0;
|
||||
|
||||
// decode variadic number
|
||||
do {
|
||||
// increment length
|
||||
len++;
|
||||
|
||||
// return error if buffer is to small
|
||||
if ((size_t)(buf_end - (*buf)) < len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// return error if the length has overflowed
|
||||
if (len > 4) {
|
||||
return LWMQTT_VARNUM_OVERFLOW;
|
||||
}
|
||||
|
||||
// read byte
|
||||
byte = (*buf)[len - 1];
|
||||
|
||||
// add byte to number
|
||||
*varnum += (byte & 127) * multiplier;
|
||||
|
||||
// increase multiplier
|
||||
multiplier *= 128;
|
||||
} while ((byte & 128) != 0);
|
||||
|
||||
// adjust pointer
|
||||
*buf += len;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_write_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t varnum) {
|
||||
// init len counter
|
||||
size_t len = 0;
|
||||
|
||||
// encode variadic number
|
||||
do {
|
||||
// check overflow
|
||||
if (len == 4) {
|
||||
return LWMQTT_VARNUM_OVERFLOW;
|
||||
}
|
||||
|
||||
// return error if buffer is to small
|
||||
if ((size_t)(buf_end - (*buf)) < len + 1) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// calculate current byte
|
||||
uint8_t byte = (uint8_t)(varnum % 128);
|
||||
|
||||
// change remaining length
|
||||
varnum /= 128;
|
||||
|
||||
// set the top bit of this byte if there are more to encode
|
||||
if (varnum > 0) {
|
||||
byte |= 0x80;
|
||||
}
|
||||
|
||||
// write byte
|
||||
(*buf)[len++] = byte;
|
||||
} while (varnum > 0);
|
||||
|
||||
// adjust pointer
|
||||
*buf += len;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
#ifndef LWMQTT_HELPERS_H
|
||||
#define LWMQTT_HELPERS_H
|
||||
|
||||
#include "lwmqtt.h"
|
||||
|
||||
/**
|
||||
* Reads bits from a byte.
|
||||
*
|
||||
* @param byte - The byte to read from.
|
||||
* @param pos - The position of the first bit.
|
||||
* @param num - The number of bits to read.
|
||||
* @return The read bits as a byte.
|
||||
*/
|
||||
uint8_t lwmqtt_read_bits(uint8_t byte, int pos, int num);
|
||||
|
||||
/**
|
||||
* Write bits to a byte.
|
||||
*
|
||||
* @param byte - The byte to write bits to.
|
||||
* @param value - The bits to write as a byte.
|
||||
* @param pos - The position of the first bit.
|
||||
* @param num - The number of bits to write.
|
||||
*/
|
||||
void lwmqtt_write_bits(uint8_t *byte, uint8_t value, int pos, int num);
|
||||
|
||||
/**
|
||||
* Reads arbitrary data from the specified buffer. The pointer is incremented by bytes read.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param data - Pointer to beginning of data.
|
||||
* @param len - The amount of data to read.
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_read_data(uint8_t **buf, const uint8_t *buf_end, uint8_t **data, size_t len);
|
||||
|
||||
/**
|
||||
* Writes arbitrary data to the specified buffer. The pointer is incremented by the bytes written.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param data - Pointer to the to be written data.
|
||||
* @param len - The amount of data to write.
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_write_data(uint8_t **buf, const uint8_t *buf_end, uint8_t *data, size_t len);
|
||||
|
||||
/**
|
||||
* Reads two byte number from the specified buffer. The pointer is incremented by two.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param num - The read number.
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_read_num(uint8_t **buf, const uint8_t *buf_end, uint16_t *num);
|
||||
|
||||
/**
|
||||
* Writes a two byte number to the specified buffer. The pointer is incremented by two.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param num - The number to write.
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_write_num(uint8_t **buf, const uint8_t *buf_end, uint16_t num);
|
||||
|
||||
/**
|
||||
* Reads a string from the specified buffer into the passed object. The pointer is incremented by the bytes read.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param str - The object into which the data is to be read.
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_read_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t *str);
|
||||
|
||||
/**
|
||||
* Writes a string to the specified buffer. The pointer is incremented by the bytes written.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param str - The string to write.
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_write_string(uint8_t **buf, const uint8_t *buf_end, lwmqtt_string_t str);
|
||||
|
||||
/**
|
||||
* Reads one byte from the buffer. The pointer is incremented by one.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param byte - The read byte.
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_read_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t *byte);
|
||||
|
||||
/**
|
||||
* Writes one byte to the specified buffer. The pointer is incremented by one.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param byte - The byte to write.
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_BUFFER_TOO_SHORT.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_write_byte(uint8_t **buf, const uint8_t *buf_end, uint8_t byte);
|
||||
|
||||
/**
|
||||
* Returns the amount of bytes required by the variable number.
|
||||
*
|
||||
* @param varnum - The number to check.
|
||||
* @param len - The required length;
|
||||
* @return LWMQTT_SUCCESS or LWMQTT_VARNUM_OVERFLOW.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_varnum_length(uint32_t varnum, int *len);
|
||||
|
||||
/**
|
||||
* Reads a variable number from the specified buffer. The pointer is incremented by the bytes read.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param varnum - The read varnum.
|
||||
* @return LWMQTT_SUCCESS, LWMQTT_BUFFER_TOO_SHORT or LWMQTT_VARNUM_OVERFLOW.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_read_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t *varnum);
|
||||
|
||||
/**
|
||||
* Writes a variable number to the specified buffer. The pointer is incremented by the bytes written.
|
||||
*
|
||||
* @param buf - Pointer to the buffer.
|
||||
* @param buf_end - Pointer to the end of the buffer.
|
||||
* @param varnum - The number to write.
|
||||
* @return LWMQTT_SUCCESS, LWMQTT_BUFFER_TOO_SHORT or LWMQTT_VARNUM_OVERFLOW.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_write_varnum(uint8_t **buf, const uint8_t *buf_end, uint32_t varnum);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,381 @@
|
|||
#ifndef LWMQTT_H
|
||||
#define LWMQTT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* The error type used by all exposed APIs.
|
||||
*
|
||||
* If a function returns an error that operates on a connected client (e.g publish, keep_alive, etc.) the caller should
|
||||
* switch into a disconnected state, close and cleanup the current connection and start over by creating a new
|
||||
* connection.
|
||||
*/
|
||||
typedef enum {
|
||||
LWMQTT_SUCCESS = 0,
|
||||
LWMQTT_BUFFER_TOO_SHORT = -1,
|
||||
LWMQTT_VARNUM_OVERFLOW = -2,
|
||||
LWMQTT_NETWORK_FAILED_CONNECT = -3,
|
||||
LWMQTT_NETWORK_TIMEOUT = -4,
|
||||
LWMQTT_NETWORK_FAILED_READ = -5,
|
||||
LWMQTT_NETWORK_FAILED_WRITE = -6,
|
||||
LWMQTT_REMAINING_LENGTH_OVERFLOW = -7,
|
||||
LWMQTT_REMAINING_LENGTH_MISMATCH = -8,
|
||||
LWMQTT_MISSING_OR_WRONG_PACKET = -9,
|
||||
LWMQTT_CONNECTION_DENIED = -10,
|
||||
LWMQTT_FAILED_SUBSCRIPTION = -11,
|
||||
LWMQTT_SUBACK_ARRAY_OVERFLOW = -12,
|
||||
LWMQTT_PONG_TIMEOUT = -13,
|
||||
} lwmqtt_err_t;
|
||||
|
||||
/**
|
||||
* A common string object.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t len;
|
||||
char *data;
|
||||
} lwmqtt_string_t;
|
||||
|
||||
/**
|
||||
* The initializer for string objects.
|
||||
*/
|
||||
#define lwmqtt_default_string \
|
||||
{ 0, NULL }
|
||||
|
||||
/**
|
||||
* Returns a string object for the passed C string.
|
||||
*
|
||||
* @param str - The C string.
|
||||
* @return A string object.
|
||||
*/
|
||||
lwmqtt_string_t lwmqtt_string(const char *str);
|
||||
|
||||
/**
|
||||
* Compares a string object to a C string.
|
||||
*
|
||||
* @param a - The string object to compare.
|
||||
* @param b - The C string to compare.
|
||||
* @return Similarity e.g. strcmp().
|
||||
*/
|
||||
int lwmqtt_strcmp(lwmqtt_string_t a, const char *b);
|
||||
|
||||
/**
|
||||
* The available QOS levels.
|
||||
*/
|
||||
typedef enum { LWMQTT_QOS0 = 0, LWMQTT_QOS1 = 1, LWMQTT_QOS2 = 2, LWMQTT_QOS_FAILURE = 128 } lwmqtt_qos_t;
|
||||
|
||||
/**
|
||||
* The message object used to publish and receive messages.
|
||||
*/
|
||||
typedef struct {
|
||||
lwmqtt_qos_t qos;
|
||||
bool retained;
|
||||
uint8_t *payload;
|
||||
size_t payload_len;
|
||||
} lwmqtt_message_t;
|
||||
|
||||
/**
|
||||
* The initializer for message objects.
|
||||
*/
|
||||
#define lwmqtt_default_message \
|
||||
{ LWMQTT_QOS0, false, NULL, 0 }
|
||||
|
||||
/**
|
||||
* Forward declaration of the client object.
|
||||
*/
|
||||
typedef struct lwmqtt_client_t lwmqtt_client_t;
|
||||
|
||||
/**
|
||||
* The callback used to read from a network object.
|
||||
*
|
||||
* The callbacks is expected to read up to the amount of bytes in to the passed buffer. It should block the specified
|
||||
* timeout and wait for more incoming data.
|
||||
*
|
||||
* @param ref - A custom reference.
|
||||
* @param buf - The buffer.
|
||||
* @param len - The length of the buffer.
|
||||
* @param read - Variable that must be set with the amount of read bytes.
|
||||
* @param timeout - The timeout in milliseconds for the operation.
|
||||
*/
|
||||
typedef lwmqtt_err_t (*lwmqtt_network_read_t)(void *ref, uint8_t *buf, size_t len, size_t *read, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* The callback used to write to a network object.
|
||||
*
|
||||
* The callback is expected to write up to the amount of bytes from the passed buffer. It should wait up to the
|
||||
* specified timeout to write the specified data to the network.
|
||||
*
|
||||
* @param ref - A custom reference.
|
||||
* @param buf - The buffer.
|
||||
* @param len - The length of the buffer.
|
||||
* @param sent - Variable that must be set with the amount of written bytes.
|
||||
* @param timeout - The timeout in milliseconds for the operation.
|
||||
*/
|
||||
typedef lwmqtt_err_t (*lwmqtt_network_write_t)(void *ref, uint8_t *buf, size_t len, size_t *sent, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* The callback used to set a timer.
|
||||
*
|
||||
* @param ref - A custom reference.
|
||||
* @param timeout - The amount of milliseconds until the deadline.
|
||||
*/
|
||||
typedef void (*lwmqtt_timer_set_t)(void *ref, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* The callback used to get a timers value.
|
||||
*
|
||||
* @param - A custom reference.
|
||||
* @return The amount of milliseconds until the deadline. May return negative numbers if the deadline has been reached.
|
||||
*/
|
||||
typedef int32_t (*lwmqtt_timer_get_t)(void *ref);
|
||||
|
||||
/**
|
||||
* The callback used to forward incoming messages.
|
||||
*
|
||||
* Note: The callback is mostly executed because of a call to lwmqtt_yield() that processes incoming messages. However,
|
||||
* it is possible that the callback is also executed during a call to lwmqtt_subscribe(), lwmqtt_publish() or
|
||||
* lwmqtt_unsubscribe() if incoming messages are received between the required acknowledgements. It is therefore not
|
||||
* recommended to call any further lwmqtt methods in the callback as this might result in weird call stacks. The
|
||||
* callback should place the received messages in a queue and dispatch them after the caller has returned.
|
||||
*/
|
||||
typedef void (*lwmqtt_callback_t)(lwmqtt_client_t *client, void *ref, lwmqtt_string_t str, lwmqtt_message_t msg);
|
||||
|
||||
/**
|
||||
* The client object.
|
||||
*/
|
||||
struct lwmqtt_client_t {
|
||||
uint16_t last_packet_id;
|
||||
uint32_t keep_alive_interval;
|
||||
bool pong_pending;
|
||||
|
||||
size_t write_buf_size, read_buf_size;
|
||||
uint8_t *write_buf, *read_buf;
|
||||
|
||||
lwmqtt_callback_t callback;
|
||||
void *callback_ref;
|
||||
|
||||
void *network;
|
||||
lwmqtt_network_read_t network_read;
|
||||
lwmqtt_network_write_t network_write;
|
||||
|
||||
void *keep_alive_timer;
|
||||
void *command_timer;
|
||||
lwmqtt_timer_set_t timer_set;
|
||||
lwmqtt_timer_get_t timer_get;
|
||||
};
|
||||
|
||||
/**
|
||||
* Will initialize the specified client object.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param write_buf - The write buffer.
|
||||
* @param write_buf_size - The write buffer size.
|
||||
* @param read_buf - The read buffer.
|
||||
* @param read_buf_size - The read buffer size.
|
||||
*/
|
||||
void lwmqtt_init(lwmqtt_client_t *client, uint8_t *write_buf, size_t write_buf_size, uint8_t *read_buf,
|
||||
size_t read_buf_size);
|
||||
|
||||
/**
|
||||
* Will set the network reference and callbacks for this client object.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param ref - The reference to the network object.
|
||||
* @param read - The read callback.
|
||||
* @param write - The write callback.
|
||||
*/
|
||||
void lwmqtt_set_network(lwmqtt_client_t *client, void *ref, lwmqtt_network_read_t read, lwmqtt_network_write_t write);
|
||||
|
||||
/**
|
||||
* Will set the timer references and callbacks for this client object.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param keep_alive_timer - The reference to the keep alive timer.
|
||||
* @param command_timer - The reference to the command timer.
|
||||
* @param set - The set callback.
|
||||
* @param get - The get callback.
|
||||
*/
|
||||
void lwmqtt_set_timers(lwmqtt_client_t *client, void *keep_alive_timer, void *command_timer, lwmqtt_timer_set_t set,
|
||||
lwmqtt_timer_get_t get);
|
||||
|
||||
/**
|
||||
* Will set the callback used to receive incoming messages.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param ref - A custom reference that will passed to the callback.
|
||||
* @param cb - The callback to be called.
|
||||
*/
|
||||
void lwmqtt_set_callback(lwmqtt_client_t *client, void *ref, lwmqtt_callback_t cb);
|
||||
|
||||
/**
|
||||
* The object defining the last will of a client.
|
||||
*/
|
||||
typedef struct {
|
||||
lwmqtt_string_t topic;
|
||||
lwmqtt_qos_t qos;
|
||||
bool retained;
|
||||
lwmqtt_string_t payload;
|
||||
} lwmqtt_will_t;
|
||||
|
||||
/**
|
||||
* The default initializer for the will object.
|
||||
*/
|
||||
#define lwmqtt_default_will \
|
||||
{ lwmqtt_default_string, LWMQTT_QOS0, false, lwmqtt_default_string }
|
||||
|
||||
/**
|
||||
* The object containing the connection options for a client.
|
||||
*/
|
||||
typedef struct {
|
||||
lwmqtt_string_t client_id;
|
||||
uint16_t keep_alive;
|
||||
bool clean_session;
|
||||
lwmqtt_string_t username;
|
||||
lwmqtt_string_t password;
|
||||
} lwmqtt_options_t;
|
||||
|
||||
/**
|
||||
* The default initializer for the options object.
|
||||
*/
|
||||
#define lwmqtt_default_options \
|
||||
{ lwmqtt_default_string, 60, true, lwmqtt_default_string, lwmqtt_default_string }
|
||||
|
||||
/**
|
||||
* The available return codes transported by the connack packet.
|
||||
*/
|
||||
typedef enum {
|
||||
LWMQTT_CONNECTION_ACCEPTED = 0,
|
||||
LWMQTT_UNACCEPTABLE_PROTOCOL = 1,
|
||||
LWMQTT_IDENTIFIER_REJECTED = 2,
|
||||
LWMQTT_SERVER_UNAVAILABLE = 3,
|
||||
LWMQTT_BAD_USERNAME_OR_PASSWORD = 4,
|
||||
LWMQTT_NOT_AUTHORIZED = 5,
|
||||
LWMQTT_UNKNOWN_RETURN_CODE = 6
|
||||
} lwmqtt_return_code_t;
|
||||
|
||||
/**
|
||||
* Will send a connect packet and wait for a connack response and set the return code.
|
||||
*
|
||||
* The network object must already be connected to the server. An error is returned if the broker rejects the
|
||||
* connection.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param options - The options object.
|
||||
* @param will - The will object.
|
||||
* @param return_code - The variable that will receive the return code.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_connect(lwmqtt_client_t *client, lwmqtt_options_t options, lwmqtt_will_t *will,
|
||||
lwmqtt_return_code_t *return_code, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Will send a publish packet and wait for all acks to complete.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param topic - The topic.
|
||||
* @param message - The message.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_publish(lwmqtt_client_t *client, lwmqtt_string_t topic, lwmqtt_message_t msg, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Will send a subscribe packet with multiple topic filters plus QOS levels and wait for the suback to complete.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param count - The number of topic filters and QOS levels.
|
||||
* @param topic_filter - The list of topic filters.
|
||||
* @param qos - The list of QOS levels.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_subscribe(lwmqtt_client_t *client, int count, lwmqtt_string_t *topic_filter, lwmqtt_qos_t *qos,
|
||||
uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Will send a subscribe packet with a single topic filter plus QOS level and wait for the suback to complete.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param topic_filter - The topic filter.
|
||||
* @param qos - The QOS level.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_subscribe_one(lwmqtt_client_t *client, lwmqtt_string_t topic_filter, lwmqtt_qos_t qos,
|
||||
uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Will send an unsubscribe packet with multiple topic filters and wait for the unsuback to complete.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param count - The number of topic filters.
|
||||
* @param topic_filter - The topic filter.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_unsubscribe(lwmqtt_client_t *client, int count, lwmqtt_string_t *topic_filter, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Will send an unsubscribe packet with a single topic filter and wait for the unsuback to complete.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param topic_filter - The topic filter.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_unsubscribe_one(lwmqtt_client_t *client, lwmqtt_string_t topic_filter, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Will send a disconnect packet and finish the client.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_disconnect(lwmqtt_client_t *client, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Will yield control to the client and receive incoming packets from the network.
|
||||
*
|
||||
* Single-threaded applications may peek on the network and assess if data is available to read before calling yield and
|
||||
* potentially block until the timeout is reached. Multi-threaded applications may select on the socket and block until
|
||||
* data is available and then yield to the client if data is available. All applications may specify the amount of bytes
|
||||
* available to read in order to constrain the yield to only receive packets that are already in-flight.
|
||||
*
|
||||
* If no availability info is given the yield will return after one packet has been successfully read or the deadline
|
||||
* has been reached but no single bytes has been received.
|
||||
*
|
||||
* Note: The message callback might be called with incoming messages as part of this call.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param available - The available bytes to read.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_yield(lwmqtt_client_t *client, size_t available, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Will yield control to the client to keep the connection alive.
|
||||
*
|
||||
* This functions must be called at a rate slightly lower than 25% of the configured keep alive. If keep alive is zero,
|
||||
* the function must not be called at all.
|
||||
*
|
||||
* @param client - The client object.
|
||||
* @param timeout - The command timeout.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_keep_alive(lwmqtt_client_t *client, uint32_t timeout);
|
||||
|
||||
#endif // LWMQTT_H
|
|
@ -0,0 +1,742 @@
|
|||
#include "packet.h"
|
||||
|
||||
lwmqtt_err_t lwmqtt_detect_packet_type(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t *packet_type) {
|
||||
// set default packet type
|
||||
*packet_type = LWMQTT_NO_PACKET;
|
||||
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// prepare header
|
||||
uint8_t header;
|
||||
|
||||
// read header
|
||||
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// get packet type
|
||||
*packet_type = (lwmqtt_packet_type_t)lwmqtt_read_bits(header, 4, 4);
|
||||
|
||||
// check if packet type is correct and can be received
|
||||
switch (*packet_type) {
|
||||
case LWMQTT_CONNACK_PACKET:
|
||||
case LWMQTT_PUBLISH_PACKET:
|
||||
case LWMQTT_PUBACK_PACKET:
|
||||
case LWMQTT_PUBREC_PACKET:
|
||||
case LWMQTT_PUBREL_PACKET:
|
||||
case LWMQTT_PUBCOMP_PACKET:
|
||||
case LWMQTT_SUBACK_PACKET:
|
||||
case LWMQTT_UNSUBACK_PACKET:
|
||||
case LWMQTT_PINGRESP_PACKET:
|
||||
return LWMQTT_SUCCESS;
|
||||
default:
|
||||
*packet_type = LWMQTT_NO_PACKET;
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_detect_remaining_length(uint8_t *buf, size_t buf_len, uint32_t *rem_len) {
|
||||
// prepare pointer
|
||||
uint8_t *ptr = buf;
|
||||
|
||||
// attempt to decode remaining length
|
||||
lwmqtt_err_t err = lwmqtt_read_varnum(&ptr, buf + buf_len, rem_len);
|
||||
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
||||
*rem_len = 0;
|
||||
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
||||
} else if (err != LWMQTT_SUCCESS) {
|
||||
*rem_len = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_connect(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_options_t options,
|
||||
lwmqtt_will_t *will) {
|
||||
// prepare pointers
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// fixed header is 10
|
||||
uint32_t rem_len = 10;
|
||||
|
||||
// add client id to remaining length
|
||||
rem_len += options.client_id.len + 2;
|
||||
|
||||
// add will if present to remaining length
|
||||
if (will != NULL) {
|
||||
rem_len += will->topic.len + 2 + will->payload.len + 2;
|
||||
}
|
||||
|
||||
// add username if present to remaining length
|
||||
if (options.username.len > 0) {
|
||||
rem_len += options.username.len + 2;
|
||||
|
||||
// add password if present to remaining length
|
||||
if (options.password.len > 0) {
|
||||
rem_len += options.password.len + 2;
|
||||
}
|
||||
}
|
||||
|
||||
// check remaining length length
|
||||
int rem_len_len;
|
||||
lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len);
|
||||
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
||||
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
||||
}
|
||||
|
||||
// prepare header
|
||||
uint8_t header = 0;
|
||||
lwmqtt_write_bits(&header, LWMQTT_CONNECT_PACKET, 4, 4);
|
||||
|
||||
// write header
|
||||
err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write remaining length
|
||||
err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write version string
|
||||
err = lwmqtt_write_string(&buf_ptr, buf_end, lwmqtt_string("MQTT"));
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write version number
|
||||
err = lwmqtt_write_byte(&buf_ptr, buf_end, 4);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// prepare flags
|
||||
uint8_t flags = 0;
|
||||
|
||||
// set clean session
|
||||
lwmqtt_write_bits(&flags, (uint8_t)(options.clean_session), 1, 1);
|
||||
|
||||
// set will flags if present
|
||||
if (will != NULL) {
|
||||
lwmqtt_write_bits(&flags, 1, 2, 1);
|
||||
lwmqtt_write_bits(&flags, will->qos, 3, 2);
|
||||
lwmqtt_write_bits(&flags, (uint8_t)(will->retained), 5, 1);
|
||||
}
|
||||
|
||||
// set username flag if present
|
||||
if (options.username.len > 0) {
|
||||
lwmqtt_write_bits(&flags, 1, 7, 1);
|
||||
|
||||
// set password flag if present
|
||||
if (options.password.len > 0) {
|
||||
lwmqtt_write_bits(&flags, 1, 6, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// write flags
|
||||
err = lwmqtt_write_byte(&buf_ptr, buf_end, flags);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write keep alive
|
||||
err = lwmqtt_write_num(&buf_ptr, buf_end, options.keep_alive);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write client id
|
||||
err = lwmqtt_write_string(&buf_ptr, buf_end, options.client_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write will if present
|
||||
if (will != NULL) {
|
||||
// write topic
|
||||
err = lwmqtt_write_string(&buf_ptr, buf_end, will->topic);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write payload length
|
||||
err = lwmqtt_write_num(&buf_ptr, buf_end, (uint16_t)will->payload.len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write payload
|
||||
err = lwmqtt_write_data(&buf_ptr, buf_end, (uint8_t *)will->payload.data, will->payload.len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// write username if present
|
||||
if (options.username.len > 0) {
|
||||
err = lwmqtt_write_string(&buf_ptr, buf_end, options.username);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// write password if present
|
||||
if (options.username.len > 0 && options.password.len > 0) {
|
||||
err = lwmqtt_write_string(&buf_ptr, buf_end, options.password);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// set written length
|
||||
*len = buf_ptr - buf;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_decode_connack(uint8_t *buf, size_t buf_len, bool *session_present,
|
||||
lwmqtt_return_code_t *return_code) {
|
||||
// prepare pointers
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// read header
|
||||
uint8_t header;
|
||||
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check packet type
|
||||
if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_CONNACK_PACKET) {
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// read remaining length
|
||||
uint32_t rem_len;
|
||||
err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check remaining length
|
||||
if (rem_len != 2) {
|
||||
return LWMQTT_REMAINING_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
// read flags
|
||||
uint8_t flags;
|
||||
err = lwmqtt_read_byte(&buf_ptr, buf_end, &flags);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// read return code
|
||||
uint8_t raw_return_code;
|
||||
err = lwmqtt_read_byte(&buf_ptr, buf_end, &raw_return_code);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// get session present
|
||||
*session_present = lwmqtt_read_bits(flags, 7, 1) == 1;
|
||||
|
||||
// get return code
|
||||
switch (raw_return_code) {
|
||||
case 0:
|
||||
*return_code = LWMQTT_CONNECTION_ACCEPTED;
|
||||
break;
|
||||
case 1:
|
||||
*return_code = LWMQTT_UNACCEPTABLE_PROTOCOL;
|
||||
break;
|
||||
case 2:
|
||||
*return_code = LWMQTT_IDENTIFIER_REJECTED;
|
||||
break;
|
||||
case 3:
|
||||
*return_code = LWMQTT_SERVER_UNAVAILABLE;
|
||||
break;
|
||||
case 4:
|
||||
*return_code = LWMQTT_BAD_USERNAME_OR_PASSWORD;
|
||||
break;
|
||||
case 5:
|
||||
*return_code = LWMQTT_NOT_AUTHORIZED;
|
||||
break;
|
||||
default:
|
||||
*return_code = LWMQTT_UNKNOWN_RETURN_CODE;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_zero(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type) {
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// write header
|
||||
uint8_t header = 0;
|
||||
lwmqtt_write_bits(&header, packet_type, 4, 4);
|
||||
lwmqtt_err_t err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write remaining length
|
||||
err = lwmqtt_write_varnum(&buf_ptr, buf_end, 0);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// set length
|
||||
*len = buf_ptr - buf;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_decode_ack(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t packet_type, bool *dup,
|
||||
uint16_t *packet_id) {
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// read header
|
||||
uint8_t header = 0;
|
||||
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check packet type
|
||||
if (lwmqtt_read_bits(header, 4, 4) != packet_type) {
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// get dup
|
||||
*dup = lwmqtt_read_bits(header, 3, 1) == 1;
|
||||
|
||||
// read remaining length
|
||||
uint32_t rem_len;
|
||||
err = lwmqtt_read_varnum(&buf_ptr, buf + buf_len, &rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check remaining length
|
||||
if (rem_len != 2) {
|
||||
return LWMQTT_REMAINING_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
// read packet id
|
||||
err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_ack(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type, bool dup,
|
||||
uint16_t packet_id) {
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// prepare header
|
||||
uint8_t header = 0;
|
||||
|
||||
// set packet type
|
||||
lwmqtt_write_bits(&header, packet_type, 4, 4);
|
||||
|
||||
// set dup
|
||||
lwmqtt_write_bits(&header, (uint8_t)(dup), 3, 1);
|
||||
|
||||
// set qos
|
||||
lwmqtt_write_bits(&header, (uint8_t)(packet_type == LWMQTT_PUBREL_PACKET ? LWMQTT_QOS1 : LWMQTT_QOS0), 1, 2);
|
||||
|
||||
// write header
|
||||
lwmqtt_err_t err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write remaining length
|
||||
err = lwmqtt_write_varnum(&buf_ptr, buf_end, 2);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write packet id
|
||||
err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// set written length
|
||||
*len = buf_ptr - buf;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_decode_publish(uint8_t *buf, size_t buf_len, bool *dup, uint16_t *packet_id, lwmqtt_string_t *topic,
|
||||
lwmqtt_message_t *msg) {
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// read header
|
||||
uint8_t header;
|
||||
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check packet type
|
||||
if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_PUBLISH_PACKET) {
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// get dup
|
||||
*dup = lwmqtt_read_bits(header, 3, 1) == 1;
|
||||
|
||||
// get retained
|
||||
msg->retained = lwmqtt_read_bits(header, 0, 1) == 1;
|
||||
|
||||
// get qos
|
||||
switch (lwmqtt_read_bits(header, 1, 2)) {
|
||||
case 0:
|
||||
msg->qos = LWMQTT_QOS0;
|
||||
break;
|
||||
case 1:
|
||||
msg->qos = LWMQTT_QOS1;
|
||||
break;
|
||||
case 2:
|
||||
msg->qos = LWMQTT_QOS2;
|
||||
break;
|
||||
default:
|
||||
msg->qos = LWMQTT_QOS0;
|
||||
break;
|
||||
}
|
||||
|
||||
// read remaining length
|
||||
uint32_t rem_len;
|
||||
err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check remaining length (topic length)
|
||||
if (rem_len < 2) {
|
||||
return LWMQTT_REMAINING_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
// check buffer capacity
|
||||
if ((uint32_t)(buf_end - buf_ptr) < rem_len) {
|
||||
return LWMQTT_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
// reset buf end
|
||||
buf_end = buf_ptr + rem_len;
|
||||
|
||||
// read topic
|
||||
err = lwmqtt_read_string(&buf_ptr, buf_end, topic);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// read packet id if qos is at least 1
|
||||
if (msg->qos > 0) {
|
||||
err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
*packet_id = 0;
|
||||
}
|
||||
|
||||
// set payload length
|
||||
msg->payload_len = buf_end - buf_ptr;
|
||||
|
||||
// read payload
|
||||
err = lwmqtt_read_data(&buf_ptr, buf_end, &msg->payload, buf_end - buf_ptr);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_publish(uint8_t *buf, size_t buf_len, size_t *len, bool dup, uint16_t packet_id,
|
||||
lwmqtt_string_t topic, lwmqtt_message_t msg) {
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// calculate remaining length
|
||||
uint32_t rem_len = 2 + topic.len + (uint32_t)msg.payload_len;
|
||||
if (msg.qos > 0) {
|
||||
rem_len += 2;
|
||||
}
|
||||
|
||||
// check remaining length length
|
||||
int rem_len_len;
|
||||
lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len);
|
||||
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
||||
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
||||
}
|
||||
|
||||
// prepare header
|
||||
uint8_t header = 0;
|
||||
|
||||
// set packet type
|
||||
lwmqtt_write_bits(&header, LWMQTT_PUBLISH_PACKET, 4, 4);
|
||||
|
||||
// set dup
|
||||
lwmqtt_write_bits(&header, (uint8_t)(dup), 3, 1);
|
||||
|
||||
// set qos
|
||||
lwmqtt_write_bits(&header, msg.qos, 1, 2);
|
||||
|
||||
// set retained
|
||||
lwmqtt_write_bits(&header, (uint8_t)(msg.retained), 0, 1);
|
||||
|
||||
// write header
|
||||
err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write remaining length
|
||||
err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write topic
|
||||
err = lwmqtt_write_string(&buf_ptr, buf_end, topic);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write packet id if qos is at least 1
|
||||
if (msg.qos > 0) {
|
||||
err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// write payload
|
||||
err = lwmqtt_write_data(&buf_ptr, buf_end, msg.payload, msg.payload_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// set length
|
||||
*len = buf_ptr - buf;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_subscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count,
|
||||
lwmqtt_string_t *topic_filters, lwmqtt_qos_t *qos_levels) {
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// calculate remaining length
|
||||
uint32_t rem_len = 2;
|
||||
for (int i = 0; i < count; i++) {
|
||||
rem_len += 2 + topic_filters[i].len + 1;
|
||||
}
|
||||
|
||||
// check remaining length length
|
||||
int rem_len_len;
|
||||
lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len);
|
||||
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
||||
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
||||
}
|
||||
|
||||
// prepare header
|
||||
uint8_t header = 0;
|
||||
|
||||
// set packet type
|
||||
lwmqtt_write_bits(&header, LWMQTT_SUBSCRIBE_PACKET, 4, 4);
|
||||
|
||||
// set qos
|
||||
lwmqtt_write_bits(&header, LWMQTT_QOS1, 1, 2);
|
||||
|
||||
// write header
|
||||
err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write remaining length
|
||||
err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write packet id
|
||||
err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write all subscriptions
|
||||
for (int i = 0; i < count; i++) {
|
||||
// write topic
|
||||
err = lwmqtt_write_string(&buf_ptr, buf_end, topic_filters[i]);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write qos level
|
||||
err = lwmqtt_write_byte(&buf_ptr, buf_end, (uint8_t)qos_levels[i]);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// set length
|
||||
*len = buf_ptr - buf;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_decode_suback(uint8_t *buf, size_t buf_len, uint16_t *packet_id, int max_count, int *count,
|
||||
lwmqtt_qos_t *granted_qos_levels) {
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// read header
|
||||
uint8_t header;
|
||||
lwmqtt_err_t err = lwmqtt_read_byte(&buf_ptr, buf_end, &header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check packet type
|
||||
if (lwmqtt_read_bits(header, 4, 4) != LWMQTT_SUBACK_PACKET) {
|
||||
return LWMQTT_MISSING_OR_WRONG_PACKET;
|
||||
}
|
||||
|
||||
// read remaining length
|
||||
uint32_t rem_len;
|
||||
err = lwmqtt_read_varnum(&buf_ptr, buf_end, &rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check remaining length (packet id + min. one suback code)
|
||||
if (rem_len < 3) {
|
||||
return LWMQTT_REMAINING_LENGTH_MISMATCH;
|
||||
}
|
||||
|
||||
// read packet id
|
||||
err = lwmqtt_read_num(&buf_ptr, buf_end, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// read all suback codes
|
||||
for (*count = 0; *count < (int)rem_len - 2; (*count)++) {
|
||||
// check max count
|
||||
if (*count > max_count) {
|
||||
return LWMQTT_SUBACK_ARRAY_OVERFLOW;
|
||||
}
|
||||
|
||||
// read qos level
|
||||
uint8_t raw_qos_level;
|
||||
err = lwmqtt_read_byte(&buf_ptr, buf_end, &raw_qos_level);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// set qos level
|
||||
switch (raw_qos_level) {
|
||||
case 0:
|
||||
granted_qos_levels[*count] = LWMQTT_QOS0;
|
||||
break;
|
||||
case 1:
|
||||
granted_qos_levels[*count] = LWMQTT_QOS1;
|
||||
break;
|
||||
case 2:
|
||||
granted_qos_levels[*count] = LWMQTT_QOS2;
|
||||
break;
|
||||
default:
|
||||
granted_qos_levels[*count] = LWMQTT_QOS_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_encode_unsubscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count,
|
||||
lwmqtt_string_t *topic_filters) {
|
||||
// prepare pointer
|
||||
uint8_t *buf_ptr = buf;
|
||||
uint8_t *buf_end = buf + buf_len;
|
||||
|
||||
// calculate remaining length
|
||||
uint32_t rem_len = 2;
|
||||
for (int i = 0; i < count; i++) {
|
||||
rem_len += 2 + topic_filters[i].len;
|
||||
}
|
||||
|
||||
// check remaining length length
|
||||
int rem_len_len;
|
||||
lwmqtt_err_t err = lwmqtt_varnum_length(rem_len, &rem_len_len);
|
||||
if (err == LWMQTT_VARNUM_OVERFLOW) {
|
||||
return LWMQTT_REMAINING_LENGTH_OVERFLOW;
|
||||
}
|
||||
|
||||
// prepare header
|
||||
uint8_t header = 0;
|
||||
|
||||
// set packet type
|
||||
lwmqtt_write_bits(&header, LWMQTT_UNSUBSCRIBE_PACKET, 4, 4);
|
||||
|
||||
// set qos
|
||||
lwmqtt_write_bits(&header, LWMQTT_QOS1, 1, 2);
|
||||
|
||||
// write header
|
||||
err = lwmqtt_write_byte(&buf_ptr, buf_end, header);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write remaining length
|
||||
err = lwmqtt_write_varnum(&buf_ptr, buf_end, rem_len);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write packet id
|
||||
err = lwmqtt_write_num(&buf_ptr, buf_end, packet_id);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// write topics
|
||||
for (int i = 0; i < count; i++) {
|
||||
err = lwmqtt_write_string(&buf_ptr, buf_end, topic_filters[i]);
|
||||
if (err != LWMQTT_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// set length
|
||||
*len = buf_ptr - buf;
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
#ifndef LWMQTT_PACKET_H
|
||||
#define LWMQTT_PACKET_H
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
/**
|
||||
* The available packet types.
|
||||
*/
|
||||
typedef enum {
|
||||
LWMQTT_NO_PACKET = 0,
|
||||
LWMQTT_CONNECT_PACKET = 1,
|
||||
LWMQTT_CONNACK_PACKET,
|
||||
LWMQTT_PUBLISH_PACKET,
|
||||
LWMQTT_PUBACK_PACKET,
|
||||
LWMQTT_PUBREC_PACKET,
|
||||
LWMQTT_PUBREL_PACKET,
|
||||
LWMQTT_PUBCOMP_PACKET,
|
||||
LWMQTT_SUBSCRIBE_PACKET,
|
||||
LWMQTT_SUBACK_PACKET,
|
||||
LWMQTT_UNSUBSCRIBE_PACKET,
|
||||
LWMQTT_UNSUBACK_PACKET,
|
||||
LWMQTT_PINGREQ_PACKET,
|
||||
LWMQTT_PINGRESP_PACKET,
|
||||
LWMQTT_DISCONNECT_PACKET
|
||||
} lwmqtt_packet_type_t;
|
||||
|
||||
/**
|
||||
* Will detect the packet type from the at least one byte long buffer.
|
||||
*
|
||||
* @param buf - The buffer from which the packet type will be detected.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param packet_type - The packet type.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_detect_packet_type(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t *packet_type);
|
||||
|
||||
/**
|
||||
* Will detect the remaining length form the at least on byte long buffer.
|
||||
*
|
||||
* It will return LWMQTT_BUFFER_TOO_SHORT if the buffer is to short and an additional byte should be read from the
|
||||
* network. In case the remaining length is overflowed it will return LWMQTT_REMAINING_LENGTH_OVERFLOW.
|
||||
*
|
||||
* @param buf - The buffer from which the remaining length will be detected.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param rem_len - The detected remaining length.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_detect_remaining_length(uint8_t *buf, size_t buf_len, uint32_t *rem_len);
|
||||
|
||||
/**
|
||||
* Encodes a connect packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param options - The options to be used to build the connect packet.
|
||||
* @param will - The last will and testament.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_connect(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_options_t options,
|
||||
lwmqtt_will_t *will);
|
||||
|
||||
/**
|
||||
* Decodes a connack packet from the supplied buffer.
|
||||
*
|
||||
* @param buf - The raw buffer data.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param session_present - The session present flag.
|
||||
* @param return_code - The return code.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_decode_connack(uint8_t *buf, size_t buf_len, bool *session_present,
|
||||
lwmqtt_return_code_t *return_code);
|
||||
|
||||
/**
|
||||
* Encodes a zero (disconnect, pingreq) packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param packet_type - The packets type.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_zero(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type);
|
||||
|
||||
/**
|
||||
* Decodes an ack (puback, pubrec, pubrel, pubcomp, unsuback) packet from the supplied buffer.
|
||||
*
|
||||
* @param buf - The raw buffer data.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param packet_type - The packet type.
|
||||
* @param dup - The dup flag.
|
||||
* @param packet_id - The packet id.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_decode_ack(uint8_t *buf, size_t buf_len, lwmqtt_packet_type_t packet_type, bool *dup,
|
||||
uint16_t *packet_id);
|
||||
|
||||
/**
|
||||
* Encodes an ack (puback, pubrec, pubrel, pubcomp) packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param packet_type - The packets type.
|
||||
* @param dup - The dup flag.
|
||||
* @param packet_id - The packet id.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_ack(uint8_t *buf, size_t buf_len, size_t *len, lwmqtt_packet_type_t packet_type, bool dup,
|
||||
uint16_t packet_id);
|
||||
|
||||
/**
|
||||
* Decodes a publish packet from the supplied buffer.
|
||||
*
|
||||
* @param buf - The raw buffer data.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param dup - The dup flag.
|
||||
* @param packet_id - The packet id.
|
||||
* @param topic - The topic.
|
||||
* @parma msg - The message.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_decode_publish(uint8_t *buf, size_t buf_len, bool *dup, uint16_t *packet_id, lwmqtt_string_t *topic,
|
||||
lwmqtt_message_t *msg);
|
||||
|
||||
/**
|
||||
* Encodes a publish packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param dup - The dup flag.
|
||||
* @param packet_id - The packet id.
|
||||
* @param topic - The topic.
|
||||
* @param msg - The message.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_publish(uint8_t *buf, size_t buf_len, size_t *len, bool dup, uint16_t packet_id,
|
||||
lwmqtt_string_t topic, lwmqtt_message_t msg);
|
||||
|
||||
/**
|
||||
* Encodes a subscribe packet into the supplied buffer.
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param packet_id - The packet id.
|
||||
* @param count - The number of members in the topic_filters and qos_levels array.
|
||||
* @param topic_filters - The array of topic filter.
|
||||
* @param qos_levels - The array of requested QoS levels.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_subscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count,
|
||||
lwmqtt_string_t *topic_filters, lwmqtt_qos_t *qos_levels);
|
||||
|
||||
/**
|
||||
* Decodes a suback packet from the supplied buffer.
|
||||
*
|
||||
* @param buf - The raw buffer data.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param packet_id - The packet id.
|
||||
* @param max_count - The maximum number of members allowed in the granted_qos_levels array.
|
||||
* @param count - The number of members in the granted_qos_levels array.
|
||||
* @param granted_qos_levels - The granted QoS levels.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_decode_suback(uint8_t *buf, size_t buf_len, uint16_t *packet_id, int max_count, int *count,
|
||||
lwmqtt_qos_t *granted_qos_levels);
|
||||
|
||||
/**
|
||||
* Encodes the supplied unsubscribe data into the supplied buffer, ready for sending
|
||||
*
|
||||
* @param buf - The buffer into which the packet will be encoded.
|
||||
* @param buf_len - The length of the specified buffer.
|
||||
* @param len - The encoded length of the packet.
|
||||
* @param packet_id - The packet id.
|
||||
* @param count - The number of members in the topic_filters array.
|
||||
* @param topic_filters - The array of topic filters.
|
||||
* @return An error value.
|
||||
*/
|
||||
lwmqtt_err_t lwmqtt_encode_unsubscribe(uint8_t *buf, size_t buf_len, size_t *len, uint16_t packet_id, int count,
|
||||
lwmqtt_string_t *topic_filters);
|
||||
|
||||
#endif // LWMQTT_PACKET_H
|
|
@ -0,0 +1,38 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "lwmqtt.h"
|
||||
|
||||
lwmqtt_string_t lwmqtt_string(const char *str) {
|
||||
// check for null
|
||||
if (str == NULL) {
|
||||
return (lwmqtt_string_t){0, NULL};
|
||||
}
|
||||
|
||||
// get length
|
||||
uint16_t len = (uint16_t)strlen(str);
|
||||
|
||||
// check zero length
|
||||
if (len == 0) {
|
||||
return (lwmqtt_string_t){0, NULL};
|
||||
}
|
||||
|
||||
return (lwmqtt_string_t){len, (char *)str};
|
||||
}
|
||||
|
||||
int lwmqtt_strcmp(lwmqtt_string_t a, const char *b) {
|
||||
// get string of b
|
||||
lwmqtt_string_t b_str = lwmqtt_string(b);
|
||||
|
||||
// return if both are zero length
|
||||
if (a.len == 0 && b_str.len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return if lengths are different
|
||||
if (a.len != b_str.len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// compare memory of same length
|
||||
return strncmp(a.data, b_str.data, a.len);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
#include "system.h"
|
||||
|
||||
void lwmqtt_arduino_timer_set(void *ref, uint32_t timeout) {
|
||||
// cast timer reference
|
||||
auto t = (lwmqtt_arduino_timer_t *)ref;
|
||||
|
||||
// set future end time
|
||||
t->end = (uint32_t)(millis() + timeout);
|
||||
}
|
||||
|
||||
int32_t lwmqtt_arduino_timer_get(void *ref) {
|
||||
// cast timer reference
|
||||
auto t = (lwmqtt_arduino_timer_t *)ref;
|
||||
|
||||
// get difference to end time
|
||||
return (int32_t)t->end - (int32_t)millis();
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_arduino_network_read(void *ref, uint8_t *buffer, size_t len, size_t *read, uint32_t timeout) {
|
||||
// cast network reference
|
||||
auto n = (lwmqtt_arduino_network_t *)ref;
|
||||
|
||||
// set timeout
|
||||
n->client->setTimeout(timeout);
|
||||
|
||||
// read bytes
|
||||
*read = n->client->readBytes(buffer, len);
|
||||
if (*read <= 0) {
|
||||
return LWMQTT_NETWORK_FAILED_READ;
|
||||
}
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
||||
|
||||
lwmqtt_err_t lwmqtt_arduino_network_write(void *ref, uint8_t *buffer, size_t len, size_t *sent, uint32_t /*timeout*/) {
|
||||
// cast network reference
|
||||
auto n = (lwmqtt_arduino_network_t *)ref;
|
||||
|
||||
// write bytes
|
||||
*sent = n->client->write(buffer, len);
|
||||
if (*sent <= 0) {
|
||||
return LWMQTT_NETWORK_FAILED_WRITE;
|
||||
};
|
||||
|
||||
return LWMQTT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef LWMQTT_ARDUINO_H
|
||||
#define LWMQTT_ARDUINO_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Client.h>
|
||||
|
||||
extern "C" {
|
||||
#include "lwmqtt/lwmqtt.h"
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t end;
|
||||
} lwmqtt_arduino_timer_t;
|
||||
|
||||
void lwmqtt_arduino_timer_set(void *ref, uint32_t timeout);
|
||||
|
||||
int32_t lwmqtt_arduino_timer_get(void *ref);
|
||||
|
||||
typedef struct {
|
||||
Client *client;
|
||||
} lwmqtt_arduino_network_t;
|
||||
|
||||
lwmqtt_err_t lwmqtt_arduino_network_read(void *ref, uint8_t *buf, size_t len, size_t *read, uint32_t timeout);
|
||||
lwmqtt_err_t lwmqtt_arduino_network_write(void *ref, uint8_t *buf, size_t len, size_t *sent, uint32_t timeout);
|
||||
|
||||
#endif // LWMQTT_ARDUINO_H
|
|
@ -1,28 +0,0 @@
|
|||
# C++ objects and libs
|
||||
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
#*.a
|
||||
*.la
|
||||
*.lai
|
||||
*.so
|
||||
*.dll
|
||||
*.dylib
|
||||
|
||||
#Makefile
|
||||
*-build-*
|
||||
build-*
|
||||
*.autosave
|
||||
|
||||
# .log files (usually created by QtTest - thanks to VestniK)
|
||||
*.log
|
||||
|
||||
|
||||
# Editors temporary files
|
||||
*~
|
||||
|
||||
|
||||
#OSX
|
||||
.DS_Store
|
||||
._*
|
|
@ -1,15 +0,0 @@
|
|||
MQTT
|
||||
====
|
||||
|
||||
A Wrapper around mqtt for Arduino to be used with esp8266 modules.
|
||||
|
||||
It wraps a slightly modified version of mqtt for esp8266 ported by Tuan PM.
|
||||
Original code for esp: https://github.com/tuanpmt/esp_mqtt
|
||||
Original code for contiki: https://github.com/esar/contiki-mqtt
|
||||
|
||||
|
||||
====
|
||||
|
||||
**secure libssl:**
|
||||
|
||||
If you want to use secure communication, please use the `secure`-branch!
|
|
@ -1,102 +0,0 @@
|
|||
#include <ESP8266WiFi.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
void myDataCb(String& topic, String& data);
|
||||
void myPublishedCb();
|
||||
void myDisconnectedCb();
|
||||
void myConnectedCb();
|
||||
|
||||
#define CLIENT_ID "client1"
|
||||
|
||||
// create MQTT object
|
||||
MQTT myMqtt(CLIENT_ID, "192.168.0.1", 1883);
|
||||
|
||||
//
|
||||
const char* ssid = "ssid";
|
||||
const char* password = "ssid_password";
|
||||
|
||||
|
||||
//
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("WiFi connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
Serial.println("Connecting to MQTT server");
|
||||
|
||||
// setup callbacks
|
||||
myMqtt.onConnected(myConnectedCb);
|
||||
myMqtt.onDisconnected(myDisconnectedCb);
|
||||
myMqtt.onPublished(myPublishedCb);
|
||||
myMqtt.onData(myDataCb);
|
||||
|
||||
Serial.println("connect mqtt...");
|
||||
myMqtt.connect();
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
//
|
||||
void loop() {
|
||||
|
||||
int value = analogRead(A0);
|
||||
|
||||
String topic("/");
|
||||
topic += CLIENT_ID;
|
||||
topic += "/value";
|
||||
|
||||
String valueStr(value);
|
||||
|
||||
// publish value to topic
|
||||
boolean result = myMqtt.publish(topic, valueStr);
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void myConnectedCb()
|
||||
{
|
||||
Serial.println("connected to MQTT server");
|
||||
}
|
||||
|
||||
void myDisconnectedCb()
|
||||
{
|
||||
Serial.println("disconnected. try to reconnect...");
|
||||
delay(500);
|
||||
myMqtt.connect();
|
||||
}
|
||||
|
||||
void myPublishedCb()
|
||||
{
|
||||
//Serial.println("published.");
|
||||
}
|
||||
|
||||
void myDataCb(String& topic, String& data)
|
||||
{
|
||||
|
||||
Serial.print(topic);
|
||||
Serial.print(": ");
|
||||
Serial.println(data);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
#include <ESP8266WiFi.h>
|
||||
#include <MQTT.h>
|
||||
|
||||
void myDataCb(String& topic, String& data);
|
||||
void myPublishedCb();
|
||||
void myDisconnectedCb();
|
||||
void myConnectedCb();
|
||||
|
||||
#define CLIENT_ID "client3"
|
||||
#define TOPIC "/client1/value"
|
||||
|
||||
|
||||
// create MQTT
|
||||
MQTT myMqtt(CLIENT_ID, "192.168.0.1", 1883);
|
||||
|
||||
|
||||
const char* ssid = "ssid";
|
||||
const char* password = "ssid_password";
|
||||
|
||||
|
||||
//
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.print("Connecting to ");
|
||||
Serial.println(ssid);
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("WiFi connected");
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
|
||||
Serial.println("Connecting to MQTT server");
|
||||
|
||||
// setup callbacks
|
||||
myMqtt.onConnected(myConnectedCb);
|
||||
myMqtt.onDisconnected(myDisconnectedCb);
|
||||
myMqtt.onPublished(myPublishedCb);
|
||||
myMqtt.onData(myDataCb);
|
||||
|
||||
Serial.println("connect mqtt...");
|
||||
myMqtt.connect();
|
||||
|
||||
Serial.println("subscribe to topic...");
|
||||
myMqtt.subscribe(TOPIC);
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
//
|
||||
void loop() {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void myConnectedCb()
|
||||
{
|
||||
Serial.println("connected to MQTT server");
|
||||
}
|
||||
|
||||
void myDisconnectedCb()
|
||||
{
|
||||
Serial.println("disconnected. try to reconnect...");
|
||||
delay(500);
|
||||
myMqtt.connect();
|
||||
}
|
||||
|
||||
void myPublishedCb()
|
||||
{
|
||||
//Serial.println("published.");
|
||||
}
|
||||
|
||||
void myDataCb(String& topic, String& data)
|
||||
{
|
||||
|
||||
Serial.print(topic);
|
||||
Serial.print(": ");
|
||||
Serial.println(data);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Test
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
MQTT.h KEYWORD1
|
||||
|
||||
MQTT KEYWORD1
|
||||
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
setClientId KEYWORD2
|
||||
setUserPwd KEYWORD2
|
||||
|
||||
connect KEYWORD2
|
||||
disconnect KEYWORD2
|
||||
isConnected KEYWORD2
|
||||
|
||||
publish KEYWORD2
|
||||
subscribe KEYWORD2
|
||||
|
||||
getState KEYWORD2
|
||||
|
||||
#general
|
||||
onConnected KEYWORD2
|
||||
onDisconnected KEYWORD2
|
||||
onPublished KEYWORD2
|
||||
onData KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
name=ESP MQTT
|
||||
version=1.0.1
|
||||
author=Ingo Randolf
|
||||
maintainer=Ingo Randolf
|
||||
sentence=A Wrapper around mqtt for Arduino to be used with esp8266 modules.
|
||||
paragraph=It wraps a slightly modified version of mqtt for esp8266 ported by Tuan PM. Original code for esp: https://github.com/tuanpmt/esp_mqtt (7ec2ef8e1df0422b77348fe1da7885568e0c9d01) Original code for contiki: https://github.com/esar/contiki-mqtt
|
||||
category=Communication
|
||||
url=https://github.com/i-n-g-o/esp-mqtt-arduino
|
||||
architectures=esp8266
|
|
@ -1,269 +0,0 @@
|
|||
/*//-------------------------------------------------------------------------------
|
||||
* MQTT.cpp
|
||||
*
|
||||
* Implementation file for MQTT Wrapper
|
||||
*
|
||||
* Wrapper for Arduino written by Ingo Randolf during
|
||||
* eTextiles Summercamp 2015.
|
||||
*
|
||||
* This library is intended to be used with esp8266 modules.
|
||||
*
|
||||
*
|
||||
* This class wraps a slightly modified version of mqtt
|
||||
* for esp8266 written by Tuan PM.
|
||||
* Original code: https://github.com/tuanpmt/esp_mqtt
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
//-------------------------------------------------------------------------------*/
|
||||
#include "MQTT.h"
|
||||
|
||||
#include "user_interface.h"
|
||||
#include "osapi.h"
|
||||
#include "os_type.h"
|
||||
#include "mqtt/debug.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// mqtt internal callbacks
|
||||
//------------------------------------------------------------------------------------
|
||||
static void mqttConnectedCb(uint32_t *args)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
|
||||
MQTT* _this = (MQTT*)client->user_data;
|
||||
|
||||
if (_this && _this->onMqttConnectedCb) {
|
||||
_this->onMqttConnectedCb();
|
||||
}
|
||||
}
|
||||
|
||||
static void mqttDisconnectedCb(uint32_t *args)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
|
||||
MQTT* _this = (MQTT*)client->user_data;
|
||||
|
||||
if (_this && _this->onMqttDisconnectedCb) {
|
||||
_this->onMqttDisconnectedCb();
|
||||
}
|
||||
}
|
||||
|
||||
static void mqttPublishedCb(uint32_t *args)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
|
||||
MQTT* _this = (MQTT*)client->user_data;
|
||||
|
||||
if (_this && _this->onMqttPublishedCb) {
|
||||
_this->onMqttPublishedCb();
|
||||
}
|
||||
}
|
||||
|
||||
static void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
|
||||
MQTT* _this = (MQTT*)client->user_data;
|
||||
|
||||
if (_this) {
|
||||
|
||||
_this->_onMqttDataCb(topic, topic_len, data, data_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void mqttTimeoutCb(uint32_t *args)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
|
||||
MQTT* _this = (MQTT*)client->user_data;
|
||||
|
||||
// if (_this && _this->onMqttTimeoutCb) {
|
||||
// _this->onMqttTimeoutCb();
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// MQTT class implementation
|
||||
//------------------------------------------------------------------------------------
|
||||
|
||||
//MQTT::MQTT(const char* client_id, const char* host, uint32_t port) :
|
||||
MQTT::MQTT(const char* client_id, const char* host, uint32_t port, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) :
|
||||
onMqttConnectedCb(0)
|
||||
,onMqttDisconnectedCb(0)
|
||||
,onMqttPublishedCb(0)
|
||||
,onMqttDataCb(0)
|
||||
,onMqttDataRawCb(0)
|
||||
{
|
||||
// init connections
|
||||
MQTT_InitConnection(&mqttClient, (uint8_t*)host, port, 0);
|
||||
|
||||
// init client
|
||||
if ( !MQTT_InitClient(&mqttClient, (uint8_t*)client_id, (uint8_t*)"", (uint8_t*)"", 15, 1) ) {
|
||||
MQTT_INFO("Failed to initialize properly. Check MQTT version.\r\n");
|
||||
}
|
||||
|
||||
// init LWT
|
||||
// MQTT_InitLWT(&mqttClient, (uint8_t*)"/lwt", (uint8_t*)"offline", 0, 0);
|
||||
MQTT_InitLWT(&mqttClient, (uint8_t*)willTopic, (uint8_t*)willMessage, willQos, (uint8_t)willRetain);
|
||||
|
||||
// set user data
|
||||
mqttClient.user_data = (void*)this;
|
||||
|
||||
// setup callbacks
|
||||
MQTT_OnConnected(&mqttClient, mqttConnectedCb);
|
||||
MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
|
||||
MQTT_OnPublished(&mqttClient, mqttPublishedCb);
|
||||
MQTT_OnData(&mqttClient, mqttDataCb);
|
||||
|
||||
MQTT_OnTimeout(&mqttClient, mqttTimeoutCb);
|
||||
}
|
||||
|
||||
|
||||
MQTT::~MQTT()
|
||||
{
|
||||
MQTT_DeleteClient(&mqttClient);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
void MQTT::setClientId(const char* client_id)
|
||||
{
|
||||
MQTT_SetUserId(&mqttClient, client_id);
|
||||
}
|
||||
|
||||
void MQTT::setUserPwd(const char* user, const char* pwd)
|
||||
{
|
||||
MQTT_SetUserPwd(&mqttClient, user, pwd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
void MQTT::connect()
|
||||
{
|
||||
MQTT_Connect(&mqttClient);
|
||||
}
|
||||
|
||||
void MQTT::disconnect()
|
||||
{
|
||||
MQTT_Disconnect(&mqttClient);
|
||||
}
|
||||
|
||||
bool MQTT::isConnected()
|
||||
{
|
||||
return (mqttClient.connState >= TCP_CONNECTED);
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
bool MQTT::publish(const char* topic, const char* buf, uint32_t buf_len, int qos, int retain)
|
||||
{
|
||||
return MQTT_Publish(&mqttClient, topic, buf, buf_len, qos, retain);
|
||||
}
|
||||
|
||||
bool MQTT::publish(String& topic, String& data, int qos, int retain)
|
||||
{
|
||||
return publish(topic.c_str(), data.c_str(), data.length(), qos, retain);
|
||||
}
|
||||
|
||||
bool MQTT::publish(String& topic, const char* buf, uint32_t buf_len, int qos, int retain)
|
||||
{
|
||||
return publish(topic.c_str(), buf, buf_len, qos, retain);
|
||||
}
|
||||
|
||||
bool MQTT::publish(const char* topic, String& data, int qos, int retain)
|
||||
{
|
||||
return publish(topic, data.c_str(), data.length(), qos, retain);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
bool MQTT::subscribe(const char* topic, uint8_t qos)
|
||||
{
|
||||
return MQTT_Subscribe(&mqttClient, (char*)topic, qos);
|
||||
}
|
||||
|
||||
bool MQTT::subscribe(const String& topic, uint8_t qos)
|
||||
{
|
||||
return MQTT_Subscribe(&mqttClient, (char*)topic.c_str(), qos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// set user callback functions
|
||||
//-------------------------------------------------------------------------------
|
||||
void MQTT::onConnected( void (*function)(void) )
|
||||
{
|
||||
onMqttConnectedCb = function;
|
||||
}
|
||||
|
||||
void MQTT::onDisconnected( void (*function)(void) )
|
||||
{
|
||||
onMqttDisconnectedCb = function;
|
||||
}
|
||||
|
||||
void MQTT::onPublished( void (*function)(void) )
|
||||
{
|
||||
onMqttPublishedCb = function;
|
||||
}
|
||||
|
||||
void MQTT::onData( void (*function)(String&, String&) )
|
||||
{
|
||||
onMqttDataCb = function;
|
||||
}
|
||||
|
||||
void MQTT::onData( void (*function)(const char*, uint32_t, const char*, uint32_t) )
|
||||
{
|
||||
onMqttDataRawCb = function;
|
||||
}
|
||||
|
||||
|
||||
// internal callback, calling user CB
|
||||
void MQTT::_onMqttDataCb(const char* topic, uint32_t topic_len, const char* buf, uint32_t buf_len)
|
||||
{
|
||||
if (onMqttDataRawCb) {
|
||||
onMqttDataRawCb(topic, topic_len, buf, buf_len);
|
||||
}
|
||||
|
||||
if (onMqttDataCb) {
|
||||
|
||||
char* topicCpy = (char*)malloc(topic_len+1);
|
||||
memcpy(topicCpy, topic, topic_len);
|
||||
topicCpy[topic_len] = 0;
|
||||
// string it
|
||||
String topicStr(topicCpy);
|
||||
|
||||
char* bufCpy = (char*)malloc(buf_len+1);
|
||||
memcpy(bufCpy, buf, buf_len);
|
||||
bufCpy[buf_len] = 0;
|
||||
// string it
|
||||
String bufStr(bufCpy);
|
||||
|
||||
onMqttDataCb(topicStr, bufStr);
|
||||
|
||||
free(topicCpy);
|
||||
free(bufCpy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
/*//-------------------------------------------------------------------------------
|
||||
* MQTT.h
|
||||
*
|
||||
* Header file for MQTT Wrapper
|
||||
*
|
||||
* Wrapper for Arduino written by Ingo Randolf during
|
||||
* eTextiles Summercamp 2015.
|
||||
*
|
||||
* This library is intended to be used with esp8266 modules.
|
||||
*
|
||||
*
|
||||
* This class wraps a slightly modified version of mqtt
|
||||
* for esp8266 written by Tuan PM.
|
||||
* Original code: https://github.com/tuanpmt/esp_mqtt
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
//-------------------------------------------------------------------------------*/
|
||||
#ifndef MQTT_WRAPPER_H
|
||||
#define MQTT_WRAPPER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
extern "C" {
|
||||
#include <stddef.h>
|
||||
#include "mqtt/mqtt.h"
|
||||
}
|
||||
|
||||
class MQTT
|
||||
{
|
||||
public:
|
||||
// MQTT(const char* client_id, const char* host, uint32_t port);
|
||||
MQTT(const char* client_id, const char* host, uint32_t port, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
|
||||
|
||||
~MQTT();
|
||||
|
||||
void setClientId(const char* client_id);
|
||||
void setUserPwd(const char* user, const char* pwd);
|
||||
|
||||
void connect();
|
||||
void disconnect();
|
||||
bool isConnected();
|
||||
|
||||
bool publish(const char* topic, const char* buf, uint32_t buf_len, int qos = 0, int retain = 0);
|
||||
bool publish(String& topic, String& data, int qos = 0, int retain = 0);
|
||||
bool publish(String& topic, const char* buf, uint32_t buf_len, int qos = 0, int retain = 0);
|
||||
bool publish(const char* topic, String& data, int qos = 0, int retain = 0);
|
||||
|
||||
bool subscribe(const char* topic, uint8_t qos = 0);
|
||||
bool subscribe(const String& topic, uint8_t qos = 0);
|
||||
|
||||
int getState() { return mqttClient.connState; };
|
||||
|
||||
// set callbacks
|
||||
void onConnected( void (*)(void) );
|
||||
void onDisconnected( void (*)(void) );
|
||||
void onPublished( void (*)(void) );
|
||||
void onData( void (*)(String&, String&) );
|
||||
void onData( void (*)(const char*, uint32_t, const char*, uint32_t) );
|
||||
|
||||
// user callbacks
|
||||
void (*onMqttConnectedCb)(void);
|
||||
void (*onMqttDisconnectedCb)(void);
|
||||
void (*onMqttPublishedCb)(void);
|
||||
void (*onMqttDataCb) (String&, String&);
|
||||
void (*onMqttDataRawCb) (const char*, uint32_t, const char*, uint32_t);
|
||||
|
||||
// internal callback
|
||||
void _onMqttDataCb(const char*, uint32_t, const char*, uint32_t);
|
||||
|
||||
private:
|
||||
MQTT_Client mqttClient;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* debug.h
|
||||
*
|
||||
* Created on: Dec 4, 2014
|
||||
* Author: Minh
|
||||
*/
|
||||
|
||||
#ifndef USER_DEBUG_H_
|
||||
#define USER_DEBUG_H_
|
||||
|
||||
|
||||
#if defined(MQTT_DEBUG_ON)
|
||||
#define MQTT_INFO( format, ... ) os_printf( format, ## __VA_ARGS__ )
|
||||
#else
|
||||
#define MQTT_INFO( format, ... )
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* USER_DEBUG_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,152 +0,0 @@
|
|||
/* mqtt.h
|
||||
*
|
||||
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef USER_AT_MQTT_H_
|
||||
#define USER_AT_MQTT_H_
|
||||
#include "mqtt_config.h"
|
||||
#include "mqtt_msg.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
#include "queue.h"
|
||||
typedef struct mqtt_event_data_t
|
||||
{
|
||||
uint8_t type;
|
||||
const char* topic;
|
||||
const char* data;
|
||||
uint16_t topic_length;
|
||||
uint16_t data_length;
|
||||
uint16_t data_offset;
|
||||
} mqtt_event_data_t;
|
||||
|
||||
typedef struct mqtt_state_t
|
||||
{
|
||||
uint16_t port;
|
||||
int auto_reconnect;
|
||||
mqtt_connect_info_t* connect_info;
|
||||
uint8_t* in_buffer;
|
||||
uint8_t* out_buffer;
|
||||
int in_buffer_length;
|
||||
int out_buffer_length;
|
||||
uint16_t message_length;
|
||||
uint16_t message_length_read;
|
||||
mqtt_message_t* outbound_message;
|
||||
mqtt_connection_t mqtt_connection;
|
||||
uint16_t pending_msg_id;
|
||||
int pending_msg_type;
|
||||
int pending_publish_qos;
|
||||
} mqtt_state_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_INIT,
|
||||
WIFI_CONNECTING,
|
||||
WIFI_CONNECTING_ERROR,
|
||||
WIFI_CONNECTED,
|
||||
DNS_RESOLVE,
|
||||
TCP_DISCONNECTING,
|
||||
TCP_DISCONNECTED,
|
||||
TCP_RECONNECT_DISCONNECTING,
|
||||
TCP_RECONNECT_REQ,
|
||||
TCP_RECONNECT,
|
||||
TCP_CONNECTING,
|
||||
TCP_CONNECTING_ERROR,
|
||||
TCP_CONNECTED,
|
||||
MQTT_CONNECT_SEND,
|
||||
MQTT_CONNECT_SENDING,
|
||||
MQTT_SUBSCIBE_SEND,
|
||||
MQTT_SUBSCIBE_SENDING,
|
||||
MQTT_DATA,
|
||||
MQTT_KEEPALIVE_SEND,
|
||||
MQTT_PUBLISH_RECV,
|
||||
MQTT_PUBLISHING,
|
||||
MQTT_DELETING,
|
||||
MQTT_DELETED,
|
||||
} tConnState;
|
||||
|
||||
typedef void (*MqttCallback)(uint32_t *args);
|
||||
typedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh);
|
||||
|
||||
typedef struct {
|
||||
struct espconn *pCon;
|
||||
uint8_t security;
|
||||
uint8_t* host;
|
||||
uint32_t port;
|
||||
ip_addr_t ip;
|
||||
mqtt_state_t mqtt_state;
|
||||
mqtt_connect_info_t connect_info;
|
||||
MqttCallback connectedCb;
|
||||
MqttCallback disconnectedCb;
|
||||
MqttCallback publishedCb;
|
||||
MqttCallback timeoutCb;
|
||||
MqttDataCallback dataCb;
|
||||
ETSTimer mqttTimer;
|
||||
uint32_t keepAliveTick;
|
||||
uint32_t reconnectTick;
|
||||
uint32_t sendTimeout;
|
||||
tConnState connState;
|
||||
QUEUE msgQueue;
|
||||
void* user_data;
|
||||
} MQTT_Client;
|
||||
|
||||
#define SEC_NONSSL 0
|
||||
#define SEC_SSL 1
|
||||
|
||||
#define MQTT_FLAG_CONNECTED 1
|
||||
#define MQTT_FLAG_READY 2
|
||||
#define MQTT_FLAG_EXIT 4
|
||||
|
||||
#define MQTT_EVENT_TYPE_NONE 0
|
||||
#define MQTT_EVENT_TYPE_CONNECTED 1
|
||||
#define MQTT_EVENT_TYPE_DISCONNECTED 2
|
||||
#define MQTT_EVENT_TYPE_SUBSCRIBED 3
|
||||
#define MQTT_EVENT_TYPE_UNSUBSCRIBED 4
|
||||
#define MQTT_EVENT_TYPE_PUBLISH 5
|
||||
#define MQTT_EVENT_TYPE_PUBLISHED 6
|
||||
#define MQTT_EVENT_TYPE_EXITED 7
|
||||
#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8
|
||||
|
||||
void ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security);
|
||||
bool ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, uint8_t* client_id, uint8_t* client_user, uint8_t* client_pass, uint32_t keepAliveTime, uint8_t cleanSession);
|
||||
void ICACHE_FLASH_ATTR MQTT_DeleteClient(MQTT_Client *mqttClient);
|
||||
void ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain);
|
||||
|
||||
void ICACHE_FLASH_ATTR MQTT_SetUserId(MQTT_Client *mqttClient, const char* client_id);
|
||||
void ICACHE_FLASH_ATTR MQTT_SetUserPwd(MQTT_Client *mqttClient, const char* user_id, const char* pwd);
|
||||
|
||||
void ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb);
|
||||
void ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb);
|
||||
void ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb);
|
||||
void ICACHE_FLASH_ATTR MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb);
|
||||
void ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb);
|
||||
bool ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos);
|
||||
bool ICACHE_FLASH_ATTR MQTT_UnSubscribe(MQTT_Client *client, char* topic);
|
||||
void ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient);
|
||||
void ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient);
|
||||
bool ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain);
|
||||
|
||||
#endif /* USER_AT_MQTT_H_ */
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef __MQTT_CONFIG_H__
|
||||
#define __MQTT_CONFIG_H__
|
||||
|
||||
//#define MQTT_SSL_ENABLE
|
||||
|
||||
/*DEFAULT CONFIGURATIONS*/
|
||||
|
||||
#define MQTT_BUF_SIZE 1024
|
||||
//#define MQTT_KEEPALIVE 120 /*second*/
|
||||
#define MQTT_KEEPALIVE 15 /*second*/
|
||||
|
||||
#define MQTT_RECONNECT_TIMEOUT 5 /*second*/
|
||||
|
||||
#define QUEUE_BUFFER_SIZE 2048
|
||||
|
||||
//#define PROTOCOL_NAMEv31 /*MQTT version 3.1 compatible with Mosquitto v0.15*/
|
||||
#define PROTOCOL_NAMEv311 /*MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/*/
|
||||
|
||||
#endif // __MQTT_CONFIG_H__
|
|
@ -1,487 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Stephen Robinson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "mqtt_msg.h"
|
||||
#include "mqtt_config.h"
|
||||
#define MQTT_MAX_FIXED_HEADER_SIZE 3
|
||||
|
||||
enum mqtt_connect_flag
|
||||
{
|
||||
MQTT_CONNECT_FLAG_USERNAME = 1 << 7,
|
||||
MQTT_CONNECT_FLAG_PASSWORD = 1 << 6,
|
||||
MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5,
|
||||
MQTT_CONNECT_FLAG_WILL = 1 << 2,
|
||||
MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1
|
||||
};
|
||||
|
||||
struct __attribute((__packed__)) mqtt_connect_variable_header
|
||||
{
|
||||
uint8_t lengthMsb;
|
||||
uint8_t lengthLsb;
|
||||
#if defined(PROTOCOL_NAMEv31)
|
||||
uint8_t magic[6];
|
||||
#elif defined(PROTOCOL_NAMEv311)
|
||||
uint8_t magic[4];
|
||||
#else
|
||||
#error "Please define protocol name"
|
||||
#endif
|
||||
uint8_t version;
|
||||
uint8_t flags;
|
||||
uint8_t keepaliveMsb;
|
||||
uint8_t keepaliveLsb;
|
||||
};
|
||||
|
||||
static int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const char* string, int len)
|
||||
{
|
||||
if (connection->message.length + len + 2 > connection->buffer_length)
|
||||
return -1;
|
||||
|
||||
connection->buffer[connection->message.length++] = len >> 8;
|
||||
connection->buffer[connection->message.length++] = len & 0xff;
|
||||
memcpy(connection->buffer + connection->message.length, string, len);
|
||||
connection->message.length += len;
|
||||
|
||||
return len + 2;
|
||||
}
|
||||
|
||||
static uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connection, uint16_t message_id)
|
||||
{
|
||||
// If message_id is zero then we should assign one, otherwise
|
||||
// we'll use the one supplied by the caller
|
||||
while (message_id == 0)
|
||||
message_id = ++connection->message_id;
|
||||
|
||||
if (connection->message.length + 2 > connection->buffer_length)
|
||||
return 0;
|
||||
|
||||
connection->buffer[connection->message.length++] = message_id >> 8;
|
||||
connection->buffer[connection->message.length++] = message_id & 0xff;
|
||||
|
||||
return message_id;
|
||||
}
|
||||
|
||||
static int ICACHE_FLASH_ATTR init_message(mqtt_connection_t* connection)
|
||||
{
|
||||
connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE;
|
||||
return MQTT_MAX_FIXED_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static mqtt_message_t* ICACHE_FLASH_ATTR fail_message(mqtt_connection_t* connection)
|
||||
{
|
||||
connection->message.data = connection->buffer;
|
||||
connection->message.length = 0;
|
||||
return &connection->message;
|
||||
}
|
||||
|
||||
static mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain)
|
||||
{
|
||||
int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE;
|
||||
|
||||
if (remaining_length > 127)
|
||||
{
|
||||
connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
|
||||
connection->buffer[1] = 0x80 | (remaining_length % 128);
|
||||
connection->buffer[2] = remaining_length / 128;
|
||||
connection->message.length = remaining_length + 3;
|
||||
connection->message.data = connection->buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);
|
||||
connection->buffer[2] = remaining_length;
|
||||
connection->message.length = remaining_length + 2;
|
||||
connection->message.data = connection->buffer + 1;
|
||||
}
|
||||
|
||||
return &connection->message;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length)
|
||||
{
|
||||
memset(connection, 0, sizeof(mqtt_connection_t));
|
||||
connection->buffer = buffer;
|
||||
connection->buffer_length = buffer_length;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length)
|
||||
{
|
||||
int i;
|
||||
int totlen = 0;
|
||||
|
||||
for (i = 1; i < length; ++i)
|
||||
{
|
||||
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
|
||||
if ((buffer[i] & 0x80) == 0)
|
||||
{
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
totlen += i;
|
||||
|
||||
return totlen;
|
||||
}
|
||||
|
||||
const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)
|
||||
{
|
||||
int i;
|
||||
int totlen = 0;
|
||||
int topiclen;
|
||||
|
||||
for (i = 1; i < *length; ++i)
|
||||
{
|
||||
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
|
||||
if ((buffer[i] & 0x80) == 0)
|
||||
{
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
totlen += i;
|
||||
|
||||
if (i + 2 >= *length)
|
||||
return NULL;
|
||||
topiclen = buffer[i++] << 8;
|
||||
topiclen |= buffer[i++];
|
||||
|
||||
if (i + topiclen > *length)
|
||||
return NULL;
|
||||
|
||||
*length = topiclen;
|
||||
return (const char*)(buffer + i);
|
||||
}
|
||||
|
||||
const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)
|
||||
{
|
||||
int i;
|
||||
int totlen = 0;
|
||||
int topiclen;
|
||||
int blength = *length;
|
||||
*length = 0;
|
||||
|
||||
for (i = 1; i < blength; ++i)
|
||||
{
|
||||
totlen += (buffer[i] & 0x7f) << (7 * (i - 1));
|
||||
if ((buffer[i] & 0x80) == 0)
|
||||
{
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
totlen += i;
|
||||
|
||||
if (i + 2 >= blength)
|
||||
return NULL;
|
||||
topiclen = buffer[i++] << 8;
|
||||
topiclen |= buffer[i++];
|
||||
|
||||
if (i + topiclen >= blength)
|
||||
return NULL;
|
||||
|
||||
i += topiclen;
|
||||
|
||||
if (mqtt_get_qos(buffer) > 0)
|
||||
{
|
||||
if (i + 2 >= blength)
|
||||
return NULL;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if (totlen < i)
|
||||
return NULL;
|
||||
|
||||
if (totlen <= blength)
|
||||
*length = totlen - i;
|
||||
else
|
||||
*length = blength - i;
|
||||
return (const char*)(buffer + i);
|
||||
}
|
||||
|
||||
uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length)
|
||||
{
|
||||
if (length < 1)
|
||||
return 0;
|
||||
|
||||
switch (mqtt_get_type(buffer))
|
||||
{
|
||||
case MQTT_MSG_TYPE_PUBLISH:
|
||||
{
|
||||
int i;
|
||||
int topiclen;
|
||||
|
||||
for (i = 1; i < length; ++i)
|
||||
{
|
||||
if ((buffer[i] & 0x80) == 0)
|
||||
{
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 2 >= length)
|
||||
return 0;
|
||||
topiclen = buffer[i++] << 8;
|
||||
topiclen |= buffer[i++];
|
||||
|
||||
if (i + topiclen >= length)
|
||||
return 0;
|
||||
i += topiclen;
|
||||
|
||||
if (mqtt_get_qos(buffer) > 0)
|
||||
{
|
||||
if (i + 2 >= length)
|
||||
return 0;
|
||||
//i += 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (buffer[i] << 8) | buffer[i + 1];
|
||||
}
|
||||
case MQTT_MSG_TYPE_PUBACK:
|
||||
case MQTT_MSG_TYPE_PUBREC:
|
||||
case MQTT_MSG_TYPE_PUBREL:
|
||||
case MQTT_MSG_TYPE_PUBCOMP:
|
||||
case MQTT_MSG_TYPE_SUBACK:
|
||||
case MQTT_MSG_TYPE_UNSUBACK:
|
||||
case MQTT_MSG_TYPE_SUBSCRIBE:
|
||||
{
|
||||
// This requires the remaining length to be encoded in 1 byte,
|
||||
// which it should be.
|
||||
if (length >= 4 && (buffer[1] & 0x80) == 0)
|
||||
return (buffer[2] << 8) | buffer[3];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info)
|
||||
{
|
||||
struct mqtt_connect_variable_header* variable_header;
|
||||
|
||||
init_message(connection);
|
||||
|
||||
if (connection->message.length + sizeof(*variable_header) > connection->buffer_length)
|
||||
return fail_message(connection);
|
||||
variable_header = (void*)(connection->buffer + connection->message.length);
|
||||
connection->message.length += sizeof(*variable_header);
|
||||
|
||||
variable_header->lengthMsb = 0;
|
||||
#if defined(PROTOCOL_NAMEv31)
|
||||
variable_header->lengthLsb = 6;
|
||||
memcpy(variable_header->magic, "MQIsdp", 6);
|
||||
variable_header->version = 3;
|
||||
#elif defined(PROTOCOL_NAMEv311)
|
||||
variable_header->lengthLsb = 4;
|
||||
memcpy(variable_header->magic, "MQTT", 4);
|
||||
variable_header->version = 4;
|
||||
#else
|
||||
#error "Please define protocol name"
|
||||
#endif
|
||||
|
||||
variable_header->flags = 0;
|
||||
variable_header->keepaliveMsb = info->keepalive >> 8;
|
||||
variable_header->keepaliveLsb = info->keepalive & 0xff;
|
||||
|
||||
if (info->clean_session)
|
||||
variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;
|
||||
|
||||
if (info->client_id == NULL)
|
||||
{
|
||||
/* Never allowed */
|
||||
return fail_message(connection);
|
||||
}
|
||||
else if (info->client_id[0] == '\0')
|
||||
{
|
||||
#ifdef PROTOCOL_NAMEv311
|
||||
/* Allowed. Format 0 Length ID */
|
||||
append_string(connection, info->client_id, 2) ;
|
||||
#else
|
||||
/* 0 Length not allowed */
|
||||
return fail_message(connection);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No 0 data and at least 1 long. Good to go. */
|
||||
if(append_string(connection, info->client_id, strlen(info->client_id)) < 0)
|
||||
return fail_message(connection);
|
||||
}
|
||||
|
||||
if (info->will_topic != NULL && info->will_topic[0] != '\0')
|
||||
{
|
||||
if (append_string(connection, info->will_topic, strlen(info->will_topic)) < 0)
|
||||
return fail_message(connection);
|
||||
|
||||
if (append_string(connection, info->will_message, strlen(info->will_message)) < 0)
|
||||
return fail_message(connection);
|
||||
|
||||
variable_header->flags |= MQTT_CONNECT_FLAG_WILL;
|
||||
if (info->will_retain)
|
||||
variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;
|
||||
variable_header->flags |= (info->will_qos & 3) << 3;
|
||||
}
|
||||
|
||||
if (info->username != NULL && info->username[0] != '\0')
|
||||
{
|
||||
if (append_string(connection, info->username, strlen(info->username)) < 0)
|
||||
return fail_message(connection);
|
||||
|
||||
variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;
|
||||
}
|
||||
|
||||
if (info->password != NULL && info->password[0] != '\0')
|
||||
{
|
||||
if (append_string(connection, info->password, strlen(info->password)) < 0)
|
||||
return fail_message(connection);
|
||||
|
||||
variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;
|
||||
}
|
||||
|
||||
return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id)
|
||||
{
|
||||
init_message(connection);
|
||||
|
||||
if (topic == NULL || topic[0] == '\0')
|
||||
return fail_message(connection);
|
||||
|
||||
if (append_string(connection, topic, strlen(topic)) < 0)
|
||||
return fail_message(connection);
|
||||
|
||||
if (qos > 0)
|
||||
{
|
||||
if ((*message_id = append_message_id(connection, 0)) == 0)
|
||||
return fail_message(connection);
|
||||
}
|
||||
else
|
||||
*message_id = 0;
|
||||
|
||||
if (connection->message.length + data_length > connection->buffer_length)
|
||||
return fail_message(connection);
|
||||
memcpy(connection->buffer + connection->message.length, data, data_length);
|
||||
connection->message.length += data_length;
|
||||
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id)
|
||||
{
|
||||
init_message(connection);
|
||||
if (append_message_id(connection, message_id) == 0)
|
||||
return fail_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id)
|
||||
{
|
||||
init_message(connection);
|
||||
if (append_message_id(connection, message_id) == 0)
|
||||
return fail_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id)
|
||||
{
|
||||
init_message(connection);
|
||||
if (append_message_id(connection, message_id) == 0)
|
||||
return fail_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id)
|
||||
{
|
||||
init_message(connection);
|
||||
if (append_message_id(connection, message_id) == 0)
|
||||
return fail_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id)
|
||||
{
|
||||
init_message(connection);
|
||||
|
||||
if (topic == NULL || topic[0] == '\0')
|
||||
return fail_message(connection);
|
||||
|
||||
if ((*message_id = append_message_id(connection, 0)) == 0)
|
||||
return fail_message(connection);
|
||||
|
||||
if (append_string(connection, topic, strlen(topic)) < 0)
|
||||
return fail_message(connection);
|
||||
|
||||
if (connection->message.length + 1 > connection->buffer_length)
|
||||
return fail_message(connection);
|
||||
connection->buffer[connection->message.length++] = qos;
|
||||
|
||||
return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)
|
||||
{
|
||||
init_message(connection);
|
||||
|
||||
if (topic == NULL || topic[0] == '\0')
|
||||
return fail_message(connection);
|
||||
|
||||
if ((*message_id = append_message_id(connection, 0)) == 0)
|
||||
return fail_message(connection);
|
||||
|
||||
if (append_string(connection, topic, strlen(topic)) < 0)
|
||||
return fail_message(connection);
|
||||
|
||||
return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection)
|
||||
{
|
||||
init_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection)
|
||||
{
|
||||
init_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection)
|
||||
{
|
||||
init_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0);
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
/*
|
||||
* File: mqtt_msg.h
|
||||
* Author: Minh Tuan
|
||||
*
|
||||
* Created on July 12, 2014, 1:05 PM
|
||||
*/
|
||||
|
||||
#ifndef MQTT_MSG_H
|
||||
#define MQTT_MSG_H
|
||||
#include "user_config.h"
|
||||
#include "c_types.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014, Stephen Robinson
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
/* 7 6 5 4 3 2 1 0*/
|
||||
/*| --- Message Type---- | DUP Flag | QoS Level | Retain |
|
||||
/* Remaining Length */
|
||||
|
||||
|
||||
enum mqtt_message_type
|
||||
{
|
||||
MQTT_MSG_TYPE_CONNECT = 1,
|
||||
MQTT_MSG_TYPE_CONNACK = 2,
|
||||
MQTT_MSG_TYPE_PUBLISH = 3,
|
||||
MQTT_MSG_TYPE_PUBACK = 4,
|
||||
MQTT_MSG_TYPE_PUBREC = 5,
|
||||
MQTT_MSG_TYPE_PUBREL = 6,
|
||||
MQTT_MSG_TYPE_PUBCOMP = 7,
|
||||
MQTT_MSG_TYPE_SUBSCRIBE = 8,
|
||||
MQTT_MSG_TYPE_SUBACK = 9,
|
||||
MQTT_MSG_TYPE_UNSUBSCRIBE = 10,
|
||||
MQTT_MSG_TYPE_UNSUBACK = 11,
|
||||
MQTT_MSG_TYPE_PINGREQ = 12,
|
||||
MQTT_MSG_TYPE_PINGRESP = 13,
|
||||
MQTT_MSG_TYPE_DISCONNECT = 14
|
||||
};
|
||||
|
||||
enum mqtt_connect_return_code
|
||||
{
|
||||
CONNECTION_ACCEPTED = 0,
|
||||
CONNECTION_REFUSE_PROTOCOL,
|
||||
CONNECTION_REFUSE_ID_REJECTED,
|
||||
CONNECTION_REFUSE_SERVER_UNAVAILABLE,
|
||||
CONNECTION_REFUSE_BAD_USERNAME,
|
||||
CONNECTION_REFUSE_NOT_AUTHORIZED
|
||||
};
|
||||
|
||||
typedef struct mqtt_message
|
||||
{
|
||||
uint8_t* data;
|
||||
uint16_t length;
|
||||
|
||||
} mqtt_message_t;
|
||||
|
||||
typedef struct mqtt_connection
|
||||
{
|
||||
mqtt_message_t message;
|
||||
|
||||
uint16_t message_id;
|
||||
uint8_t* buffer;
|
||||
uint16_t buffer_length;
|
||||
|
||||
} mqtt_connection_t;
|
||||
|
||||
typedef struct mqtt_connect_info
|
||||
{
|
||||
char* client_id;
|
||||
char* username;
|
||||
char* password;
|
||||
char* will_topic;
|
||||
char* will_message;
|
||||
uint32_t keepalive;
|
||||
int will_qos;
|
||||
int will_retain;
|
||||
int clean_session;
|
||||
|
||||
} mqtt_connect_info_t;
|
||||
|
||||
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_connect_return_code(uint8_t* buffer) { return buffer[3]; }
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }
|
||||
|
||||
void ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
|
||||
int ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length);
|
||||
const char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
|
||||
const char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
|
||||
uint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length);
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection);
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MQTT_MSG_H */
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
#include "proto.h"
|
||||
#include "ringbuf.h"
|
||||
I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize)
|
||||
{
|
||||
parser->buf = buf;
|
||||
parser->bufSize = bufSize;
|
||||
parser->dataLen = 0;
|
||||
parser->callback = completeCallback;
|
||||
parser->isEsc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value)
|
||||
{
|
||||
switch (value) {
|
||||
case 0x7D:
|
||||
parser->isEsc = 1;
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
parser->dataLen = 0;
|
||||
parser->isEsc = 0;
|
||||
parser->isBegin = 1;
|
||||
break;
|
||||
|
||||
case 0x7F:
|
||||
if (parser->callback != NULL)
|
||||
parser->callback();
|
||||
parser->isBegin = 0;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (parser->isBegin == 0) break;
|
||||
|
||||
if (parser->isEsc) {
|
||||
value ^= 0x20;
|
||||
parser->isEsc = 0;
|
||||
}
|
||||
|
||||
if (parser->dataLen < parser->bufSize)
|
||||
parser->buf[parser->dataLen++] = value;
|
||||
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len)
|
||||
{
|
||||
while (len--)
|
||||
PROTO_ParseByte(parser, *buf++);
|
||||
|
||||
return 0;
|
||||
}
|
||||
I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, U8 *bufOut, U16* len, U16 maxBufLen)
|
||||
{
|
||||
U8 c;
|
||||
|
||||
PROTO_PARSER proto;
|
||||
PROTO_Init(&proto, NULL, bufOut, maxBufLen);
|
||||
while (RINGBUF_Get(rb, &c) == 0) {
|
||||
if (PROTO_ParseByte(&proto, c) == 0) {
|
||||
*len = proto.dataLen;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize)
|
||||
{
|
||||
U16 i = 2;
|
||||
U16 len = *(U16*) packet;
|
||||
|
||||
if (bufSize < 1) return -1;
|
||||
|
||||
*buf++ = 0x7E;
|
||||
bufSize--;
|
||||
|
||||
while (len--) {
|
||||
switch (*packet) {
|
||||
case 0x7D:
|
||||
case 0x7E:
|
||||
case 0x7F:
|
||||
if (bufSize < 2) return -1;
|
||||
*buf++ = 0x7D;
|
||||
*buf++ = *packet++ ^ 0x20;
|
||||
i += 2;
|
||||
bufSize -= 2;
|
||||
break;
|
||||
default:
|
||||
if (bufSize < 1) return -1;
|
||||
*buf++ = *packet++;
|
||||
i++;
|
||||
bufSize--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bufSize < 1) return -1;
|
||||
*buf++ = 0x7F;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len)
|
||||
{
|
||||
U16 i = 2;
|
||||
if (RINGBUF_Put(rb, 0x7E) == -1) return -1;
|
||||
while (len--) {
|
||||
switch (*packet) {
|
||||
case 0x7D:
|
||||
case 0x7E:
|
||||
case 0x7F:
|
||||
if (RINGBUF_Put(rb, 0x7D) == -1) return -1;
|
||||
if (RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1;
|
||||
i += 2;
|
||||
break;
|
||||
default:
|
||||
if (RINGBUF_Put(rb, *packet++) == -1) return -1;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (RINGBUF_Put(rb, 0x7F) == -1) return -1;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* File: proto.h
|
||||
* Author: ThuHien
|
||||
*
|
||||
* Created on November 23, 2012, 8:57 AM
|
||||
*/
|
||||
|
||||
#ifndef _PROTO_H_
|
||||
#define _PROTO_H_
|
||||
#include <stdlib.h>
|
||||
#include "typedef.h"
|
||||
#include "ringbuf.h"
|
||||
|
||||
typedef void(PROTO_PARSE_CALLBACK)();
|
||||
|
||||
typedef struct {
|
||||
U8 *buf;
|
||||
U16 bufSize;
|
||||
U16 dataLen;
|
||||
U8 isEsc;
|
||||
U8 isBegin;
|
||||
PROTO_PARSE_CALLBACK* callback;
|
||||
} PROTO_PARSER;
|
||||
|
||||
I8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize);
|
||||
I8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len);
|
||||
I16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize);
|
||||
I16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len);
|
||||
I8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value);
|
||||
I16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, U8 *bufOut, U16* len, U16 maxBufLen);
|
||||
#endif
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/* str_queue.c
|
||||
*
|
||||
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "queue.h"
|
||||
|
||||
#include "user_interface.h"
|
||||
#include "osapi.h"
|
||||
#include "os_type.h"
|
||||
#include "mem.h"
|
||||
#include "proto.h"
|
||||
|
||||
uint8_t *last_rb_p_r;
|
||||
uint8_t *last_rb_p_w;
|
||||
uint32_t last_fill_cnt;
|
||||
|
||||
void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize)
|
||||
{
|
||||
queue->buf = (uint8_t*)os_zalloc(bufferSize);
|
||||
RINGBUF_Init(&queue->rb, queue->buf, bufferSize);
|
||||
}
|
||||
int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
last_rb_p_r = queue->rb.p_r;
|
||||
last_rb_p_w = queue->rb.p_w;
|
||||
last_fill_cnt = queue->rb.fill_cnt;
|
||||
|
||||
ret = PROTO_AddRb(&queue->rb, buffer, len);
|
||||
if (ret == -1) {
|
||||
// rolling ring buffer back
|
||||
queue->rb.p_r = last_rb_p_r;
|
||||
queue->rb.p_w = last_rb_p_w;
|
||||
queue->rb.fill_cnt = last_fill_cnt;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen)
|
||||
{
|
||||
|
||||
return PROTO_ParseRb(&queue->rb, buffer, len, maxLen);
|
||||
}
|
||||
|
||||
BOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue)
|
||||
{
|
||||
if (queue->rb.fill_cnt <= 0)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/* str_queue.h --
|
||||
*
|
||||
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef USER_QUEUE_H_
|
||||
#define USER_QUEUE_H_
|
||||
#include "os_type.h"
|
||||
#include "ringbuf.h"
|
||||
typedef struct {
|
||||
uint8_t *buf;
|
||||
RINGBUF rb;
|
||||
} QUEUE;
|
||||
|
||||
void ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize);
|
||||
int32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len);
|
||||
int32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen);
|
||||
bool ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue);
|
||||
#endif /* USER_QUEUE_H_ */
|
|
@ -1,67 +0,0 @@
|
|||
/**
|
||||
* \file
|
||||
* Ring Buffer library
|
||||
*/
|
||||
|
||||
#include "ringbuf.h"
|
||||
|
||||
|
||||
/**
|
||||
* \brief init a RINGBUF object
|
||||
* \param r pointer to a RINGBUF object
|
||||
* \param buf pointer to a byte array
|
||||
* \param size size of buf
|
||||
* \return 0 if successfull, otherwise failed
|
||||
*/
|
||||
I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size)
|
||||
{
|
||||
if (r == NULL || buf == NULL || size < 2) return -1;
|
||||
|
||||
r->p_o = r->p_r = r->p_w = buf;
|
||||
r->fill_cnt = 0;
|
||||
r->size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* \brief put a character into ring buffer
|
||||
* \param r pointer to a ringbuf object
|
||||
* \param c character to be put
|
||||
* \return 0 if successfull, otherwise failed
|
||||
*/
|
||||
I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c)
|
||||
{
|
||||
if (r->fill_cnt >= r->size)return -1; // ring buffer is full, this should be atomic operation
|
||||
|
||||
|
||||
r->fill_cnt++; // increase filled slots count, this should be atomic operation
|
||||
|
||||
|
||||
*r->p_w++ = c; // put character into buffer
|
||||
|
||||
if (r->p_w >= r->p_o + r->size) // rollback if write pointer go pass
|
||||
r->p_w = r->p_o; // the physical boundary
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* \brief get a character from ring buffer
|
||||
* \param r pointer to a ringbuf object
|
||||
* \param c read character
|
||||
* \return 0 if successfull, otherwise failed
|
||||
*/
|
||||
I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c)
|
||||
{
|
||||
if (r->fill_cnt <= 0)return -1; // ring buffer is empty, this should be atomic operation
|
||||
|
||||
|
||||
r->fill_cnt--; // decrease filled slots count
|
||||
|
||||
|
||||
*c = *r->p_r++; // get the character out
|
||||
|
||||
if (r->p_r >= r->p_o + r->size) // rollback if write pointer go pass
|
||||
r->p_r = r->p_o; // the physical boundary
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef _RING_BUF_H_
|
||||
#define _RING_BUF_H_
|
||||
|
||||
#include <os_type.h>
|
||||
#include <stdlib.h>
|
||||
#include "typedef.h"
|
||||
|
||||
typedef struct {
|
||||
U8* p_o; /**< Original pointer */
|
||||
U8* volatile p_r; /**< Read pointer */
|
||||
U8* volatile p_w; /**< Write pointer */
|
||||
volatile I32 fill_cnt; /**< Number of filled slots */
|
||||
I32 size; /**< Buffer size */
|
||||
} RINGBUF;
|
||||
|
||||
I16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size);
|
||||
I16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c);
|
||||
I16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c);
|
||||
#endif
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* \file
|
||||
* Standard Types definition
|
||||
*/
|
||||
|
||||
#ifndef _TYPE_DEF_H_
|
||||
#define _TYPE_DEF_H_
|
||||
|
||||
typedef char I8;
|
||||
typedef unsigned char U8;
|
||||
typedef short I16;
|
||||
typedef unsigned short U16;
|
||||
typedef long I32;
|
||||
typedef unsigned long U32;
|
||||
typedef unsigned long long U64;
|
||||
|
||||
#endif
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Tuan PM
|
||||
* Email: tuanpm@live.com
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str)
|
||||
{
|
||||
uint8_t segs = 0; /* Segment count. */
|
||||
uint8_t chcnt = 0; /* Character count within segment. */
|
||||
uint8_t accum = 0; /* Accumulator for segment. */
|
||||
/* Catch NULL pointer. */
|
||||
if (str == 0)
|
||||
return 0;
|
||||
/* Process every character in string. */
|
||||
|
||||
while (*str != '\0') {
|
||||
/* Segment changeover. */
|
||||
|
||||
if (*str == '.') {
|
||||
/* Must have some digits in segment. */
|
||||
if (chcnt == 0)
|
||||
return 0;
|
||||
/* Limit number of segments. */
|
||||
if (++segs == 4)
|
||||
return 0;
|
||||
/* Reset segment values and restart loop. */
|
||||
chcnt = accum = 0;
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check numeric. */
|
||||
if ((*str < '0') || (*str > '9'))
|
||||
return 0;
|
||||
|
||||
/* Accumulate and check segment. */
|
||||
|
||||
if ((accum = accum * 10 + *str - '0') > 255)
|
||||
return 0;
|
||||
/* Advance other segment specific stuff and continue loop. */
|
||||
|
||||
chcnt++;
|
||||
str++;
|
||||
}
|
||||
|
||||
/* Check enough segments and enough characters in last segment. */
|
||||
|
||||
if (segs != 3)
|
||||
return 0;
|
||||
if (chcnt == 0)
|
||||
return 0;
|
||||
/* Address okay. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip)
|
||||
{
|
||||
|
||||
/* The count of the number of bytes processed. */
|
||||
int i;
|
||||
/* A pointer to the next digit to process. */
|
||||
const char * start;
|
||||
|
||||
start = str;
|
||||
for (i = 0; i < 4; i++) {
|
||||
/* The digit being processed. */
|
||||
char c;
|
||||
/* The value of this byte. */
|
||||
int n = 0;
|
||||
while (1) {
|
||||
c = * start;
|
||||
start++;
|
||||
if (c >= '0' && c <= '9') {
|
||||
n *= 10;
|
||||
n += c - '0';
|
||||
}
|
||||
/* We insist on stopping at "." if we are still parsing
|
||||
the first, second, or third numbers. If we have reached
|
||||
the end of the numbers, we will allow any character. */
|
||||
else if ((i < 3 && c == '.') || i == 3) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (n >= 256) {
|
||||
return 0;
|
||||
}
|
||||
((uint8_t*)ip)[i] = n;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s)
|
||||
{
|
||||
uint32_t value = 0, digit;
|
||||
int8_t c;
|
||||
|
||||
while ((c = *s++)) {
|
||||
if ('0' <= c && c <= '9')
|
||||
digit = c - '0';
|
||||
else if ('A' <= c && c <= 'F')
|
||||
digit = c - 'A' + 10;
|
||||
else if ('a' <= c && c <= 'f')
|
||||
digit = c - 'a' + 10;
|
||||
else break;
|
||||
|
||||
value = (value << 4) | digit;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
#include "c_types.h"
|
||||
|
||||
uint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s);
|
||||
uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip);
|
||||
uint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str);
|
||||
#endif
|
|
@ -25,6 +25,7 @@ env_default = sonoff
|
|||
;env_default = sonoff-ES
|
||||
;env_default = sonoff-FR
|
||||
;env_default = sonoff-GR
|
||||
;env_default = sonoff-HE
|
||||
;env_default = sonoff-HU
|
||||
;env_default = sonoff-IT
|
||||
;env_default = sonoff-NL
|
||||
|
@ -294,6 +295,20 @@ upload_resetmethod = ${common.upload_resetmethod}
|
|||
upload_speed = ${common.upload_speed}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:sonoff-HE]
|
||||
platform = ${common.platform}
|
||||
framework = ${common.framework}
|
||||
board = ${common.board}
|
||||
board_build.flash_mode = ${common.board_build.flash_mode}
|
||||
board_build.f_cpu = ${common.board_build.f_cpu}
|
||||
build_unflags = ${common.build_unflags}
|
||||
build_flags = ${common.build_flags} -DMY_LANGUAGE=he-HE
|
||||
monitor_speed = ${common.monitor_speed}
|
||||
upload_port = ${common.upload_port}
|
||||
upload_resetmethod = ${common.upload_resetmethod}
|
||||
upload_speed = ${common.upload_speed}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:sonoff-HU]
|
||||
platform = ${common.platform}
|
||||
framework = ${common.framework}
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
/* 6.2.1.10 20180930
|
||||
/* 6.2.1.11 20191002
|
||||
* Remove support for MQTT Client based on esp-mqtt-arduino by #define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO
|
||||
* Add support for MQTT Client based on lwmqtt to be selected by #define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT
|
||||
* Change MQTT_ARDUINOMQTT command timeout from 1 to 10 seconds
|
||||
* Add Hebrew language file (#3960)
|
||||
*
|
||||
* 6.2.1.10 20180930
|
||||
* Add command RGBWWTable to support color calibration (#3933)
|
||||
* Add support for Michael Haustein ESP Switch
|
||||
* Add support for EXS Relay V5.0 (#3810)
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
\*********************************************************************/
|
||||
|
||||
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
|
||||
|
||||
// https://www.science.co.il/language/Locale-codes.php
|
||||
#define LANGUAGE_LCID 2057
|
||||
// HTML (ISO 639-1) Language Code
|
||||
#define D_HTML_LANGUAGE "en"
|
||||
|
@ -169,7 +169,7 @@
|
|||
#define D_UV_INDEX_4 "Danger"
|
||||
#define D_UV_INDEX_5 "BurnL1/2"
|
||||
#define D_UV_INDEX_6 "BurnL3"
|
||||
#define D_UV_INDEX_7 "OoR"
|
||||
#define D_UV_INDEX_7 "OoR" // Out of Range
|
||||
#define D_UV_LEVEL "UV Level"
|
||||
#define D_UV_POWER "UV Power"
|
||||
#define D_VERSION "Version"
|
||||
|
|
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
he-HE.h - localization for Hebrew - Israel for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2018 Yuval Mejahez
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _LANGUAGE_HE_HE_H_
|
||||
#define _LANGUAGE_HE_HE_H_
|
||||
|
||||
/*************************** ATTENTION *******************************\
|
||||
*
|
||||
* Due to memory constraints only UTF-8 is supported.
|
||||
* To save code space keep text as short as possible.
|
||||
* Time and Date provided by SDK can not be localized (yet).
|
||||
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
|
||||
* Use online command Prefix to translate cmnd, stat and tele.
|
||||
*
|
||||
* Updated until v5.14.0b
|
||||
\*********************************************************************/
|
||||
|
||||
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
|
||||
|
||||
#define LANGUAGE_LCID 1037
|
||||
// HTML (ISO 639-1) Language Code
|
||||
#define D_HTML_LANGUAGE "he"
|
||||
|
||||
// "2017-03-07T11:08:02" - ISO8601:2004
|
||||
#define D_YEAR_MONTH_SEPARATOR "-"
|
||||
#define D_MONTH_DAY_SEPARATOR "-"
|
||||
#define D_DATE_TIME_SEPARATOR "T"
|
||||
#define D_HOUR_MINUTE_SEPARATOR ":"
|
||||
#define D_MINUTE_SECOND_SEPARATOR ":"
|
||||
|
||||
#define D_DAY3LIST "SunMonTueWedThuFriSat"
|
||||
#define D_MONTH3LIST "JanFebMarAprMayJunJulAugSepOctNovDec"
|
||||
|
||||
// Non JSON decimal separator
|
||||
#define D_DECIMAL_SEPARATOR "."
|
||||
|
||||
// Common
|
||||
#define D_ADMIN "מנהל"
|
||||
#define D_AIR_QUALITY "איכות אוויר"
|
||||
#define D_AP "AP" // Access Point
|
||||
#define D_AS "as"
|
||||
#define D_AUTO "AUTO"
|
||||
#define D_BLINK "מהבהב"
|
||||
#define D_BLINKOFF "כיבוי היבהוב"
|
||||
#define D_BOOT_COUNT "מונה הפעלה מחדש"
|
||||
#define D_BRIGHTLIGHT "בהירות"
|
||||
#define D_BSSID "BSSId"
|
||||
#define D_BUTTON "לחצן"
|
||||
#define D_BY "by" // Written by me
|
||||
#define D_BYTES "בייט"
|
||||
#define D_CELSIUS "צלזיוס"
|
||||
#define D_CHANNEL "ערוץ"
|
||||
#define D_CO2 "Carbon dioxide"
|
||||
#define D_CODE "קוד" // Button code
|
||||
#define D_COLDLIGHT "קור"
|
||||
#define D_COMMAND "פקודה"
|
||||
#define D_CONNECTED "מחובר"
|
||||
#define D_COUNT "סופר"
|
||||
#define D_COUNTER "מונה"
|
||||
#define D_CURRENT "נוכחי" // As in Voltage and Current
|
||||
#define D_DATA "נתונים"
|
||||
#define D_DARKLIGHT "חושך"
|
||||
#define D_DEBUG "באגים"
|
||||
#define D_DISABLED "מבוטל"
|
||||
#define D_DISTANCE "מרחק"
|
||||
#define D_DNS_SERVER "DNS שרת"
|
||||
#define D_DONE "סיים"
|
||||
#define D_DST_TIME "DST"
|
||||
#define D_ECO2 "eCO2"
|
||||
#define D_EMULATION "הדמיה"
|
||||
#define D_ENABLED "מאופשר"
|
||||
#define D_ERASE "מחיקה"
|
||||
#define D_ERROR "שגיאה"
|
||||
#define D_FAHRENHEIT "פרנהייט"
|
||||
#define D_FAILED "נכשל"
|
||||
#define D_FALLBACK "חזרה"
|
||||
#define D_FALLBACK_TOPIC "נושא לחזרה"
|
||||
#define D_FALSE "שגוי"
|
||||
#define D_FILE "קובץ"
|
||||
#define D_FREE_MEMORY "זכרון פנוי"
|
||||
#define D_FREQUENCY "תדר"
|
||||
#define D_GAS "גז"
|
||||
#define D_GATEWAY "שער"
|
||||
#define D_GROUP "קבוצה"
|
||||
#define D_HOST "מארח"
|
||||
#define D_HOSTNAME "שם מארח"
|
||||
#define D_HUMIDITY "לחות"
|
||||
#define D_ILLUMINANCE "רמת חשיפה"
|
||||
#define D_IMMEDIATE "מידי" // Button immediate
|
||||
#define D_INDEX "אינדקס"
|
||||
#define D_INFO "מידע"
|
||||
#define D_INFRARED "אינפרא"
|
||||
#define D_INITIALIZED "מאותחל"
|
||||
#define D_IP_ADDRESS "IP כתובת"
|
||||
#define D_LIGHT "אור"
|
||||
#define D_LWT "LWT"
|
||||
#define D_MODULE "מודול"
|
||||
#define D_MQTT "MQTT"
|
||||
#define D_MULTI_PRESS "multi-press"
|
||||
#define D_NOISE "רעש"
|
||||
#define D_NONE "כלום"
|
||||
#define D_OFF "כבוי"
|
||||
#define D_OFFLINE "מנותק"
|
||||
#define D_OK "אוקיי"
|
||||
#define D_ON "פועל"
|
||||
#define D_ONLINE "מחובר"
|
||||
#define D_PASSWORD "סיסמא"
|
||||
#define D_PORT "פורט"
|
||||
#define D_POWER_FACTOR "גורם כוח"
|
||||
#define D_POWERUSAGE "כוח"
|
||||
#define D_POWERUSAGE_ACTIVE "כוח פעיל"
|
||||
#define D_POWERUSAGE_APPARENT "כוח לכאורה"
|
||||
#define D_POWERUSAGE_REACTIVE "כוח תגובתי"
|
||||
#define D_PRESSURE "לחץ"
|
||||
#define D_PRESSUREATSEALEVEL "לחץ ימי"
|
||||
#define D_PROGRAM_FLASH_SIZE "גודל תוכנית פלאש"
|
||||
#define D_PROGRAM_SIZE "גודל תוכנית"
|
||||
#define D_PROJECT "פרויקט"
|
||||
#define D_RECEIVED "התקבל"
|
||||
#define D_RESTART "איתחול"
|
||||
#define D_RESTARTING "הפעלה מחדש"
|
||||
#define D_RESTART_REASON "סיבת הפעלה מחדש"
|
||||
#define D_RESTORE "שחזור"
|
||||
#define D_RETAINED "שמור"
|
||||
#define D_RULE "חוק"
|
||||
#define D_SAVE "שמירה"
|
||||
#define D_SENSOR "חיישן"
|
||||
#define D_SSID "SSId"
|
||||
#define D_START "התחלה"
|
||||
#define D_STD_TIME "STD"
|
||||
#define D_STOP "עצירה"
|
||||
#define D_SUBNET_MASK "רשת מסכת משנה"
|
||||
#define D_SUBSCRIBE_TO "הרשם ל"
|
||||
#define D_SUCCESSFUL "הצליח"
|
||||
#define D_SUNRISE "זריחה"
|
||||
#define D_SUNSET "שקיעה"
|
||||
#define D_TEMPERATURE "טמפרטורה"
|
||||
#define D_TO "ל"
|
||||
#define D_TOGGLE "מתג"
|
||||
#define D_TOPIC "נושא"
|
||||
#define D_TRANSMIT "עבר"
|
||||
#define D_TRUE "נכון"
|
||||
#define D_TVOC "TVOC"
|
||||
#define D_UPGRADE "שדרוג"
|
||||
#define D_UPLOAD "העלאה"
|
||||
#define D_UPTIME "זמן עליה"
|
||||
#define D_USER "משתמש"
|
||||
#define D_UTC_TIME "UTC"
|
||||
#define D_UV_INDEX "UV אינדקס"
|
||||
#define D_UV_INDEX_1 "Low"
|
||||
#define D_UV_INDEX_2 "Mid"
|
||||
#define D_UV_INDEX_3 "High"
|
||||
#define D_UV_INDEX_4 "Danger"
|
||||
#define D_UV_INDEX_5 "BurnL1/2"
|
||||
#define D_UV_INDEX_6 "BurnL3"
|
||||
#define D_UV_INDEX_7 "OoR" // Out of Range
|
||||
#define D_UV_LEVEL "UV רמת"
|
||||
#define D_UV_POWER "UV Power"
|
||||
#define D_VERSION "גרסה"
|
||||
#define D_VOLTAGE "מתח"
|
||||
#define D_WARMLIGHT "חום"
|
||||
#define D_WEB_SERVER "Web שרת"
|
||||
|
||||
// sonoff.ino
|
||||
#define D_WARNING_MINIMAL_VERSION "WARNING This version does not support persistent settings"
|
||||
#define D_LEVEL_10 "level 1-0"
|
||||
#define D_LEVEL_01 "level 0-1"
|
||||
#define D_SERIAL_LOGGING_DISABLED "Serial logging disabled"
|
||||
#define D_SYSLOG_LOGGING_REENABLED "Syslog logging re-enabled"
|
||||
|
||||
#define D_SET_BAUDRATE_TO "Set Baudrate to"
|
||||
#define D_RECEIVED_TOPIC "Received Topic"
|
||||
#define D_DATA_SIZE "Data Size"
|
||||
#define D_ANALOG_INPUT "אנלוגי"
|
||||
|
||||
// support.ino
|
||||
#define D_OSWATCH "osWatch"
|
||||
#define D_BLOCKED_LOOP "Blocked Loop"
|
||||
#define D_WPS_FAILED_WITH_STATUS "WPSconfig FAILED with status"
|
||||
#define D_ACTIVE_FOR_3_MINUTES "active for 3 minutes"
|
||||
#define D_FAILED_TO_START "failed to start"
|
||||
#define D_PATCH_ISSUE_2186 "Patch issue 2186"
|
||||
#define D_CONNECTING_TO_AP "Connecting to AP"
|
||||
#define D_IN_MODE "in mode"
|
||||
#define D_CONNECT_FAILED_NO_IP_ADDRESS "Connect failed as no IP address received"
|
||||
#define D_CONNECT_FAILED_AP_NOT_REACHED "Connect failed as AP cannot be reached"
|
||||
#define D_CONNECT_FAILED_WRONG_PASSWORD "Connect failed with AP incorrect password"
|
||||
#define D_CONNECT_FAILED_AP_TIMEOUT "Connect failed with AP timeout"
|
||||
#define D_ATTEMPTING_CONNECTION "Attempting connection..."
|
||||
#define D_CHECKING_CONNECTION "Checking connection..."
|
||||
#define D_QUERY_DONE "Query done. MQTT services found"
|
||||
#define D_MQTT_SERVICE_FOUND "MQTT service found on"
|
||||
#define D_FOUND_AT "found at"
|
||||
#define D_SYSLOG_HOST_NOT_FOUND "Syslog Host not found"
|
||||
|
||||
// settings.ino
|
||||
#define D_SAVED_TO_FLASH_AT "Saved to flash at"
|
||||
#define D_LOADED_FROM_FLASH_AT "Loaded from flash at"
|
||||
#define D_USE_DEFAULTS "השתמש בהגדרות ברירת המחדל"
|
||||
#define D_ERASED_SECTOR "סקטור מחוק"
|
||||
|
||||
// xdrv_02_webserver.ino
|
||||
#define D_NOSCRIPT "JavaScript - כדי להשתמש ב קושחה אסמוטה אנא הפעל"
|
||||
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "קושחה מינימלית - בבקשה אנא שדרג"
|
||||
#define D_WEBSERVER_ACTIVE_ON "Web server active on"
|
||||
#define D_WITH_IP_ADDRESS "with IP address"
|
||||
#define D_WEBSERVER_STOPPED "Web server stopped"
|
||||
#define D_FILE_NOT_FOUND "File Not Found"
|
||||
#define D_REDIRECTED "Redirected to captive portal"
|
||||
#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager set AccessPoint and keep Station"
|
||||
#define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager set AccessPoint"
|
||||
#define D_TRYING_TO_CONNECT "מנסה לחבר את ההתקן לרשת"
|
||||
|
||||
#define D_RESTART_IN "הפעלה מחדש תןך"
|
||||
#define D_SECONDS "שניות"
|
||||
#define D_DEVICE_WILL_RESTART "ההתקן יופעל מחדש בעוד מס' שניות"
|
||||
#define D_BUTTON_TOGGLE "מצב"
|
||||
#define D_CONFIGURATION "הגדרות"
|
||||
#define D_INFORMATION "מידע"
|
||||
#define D_FIRMWARE_UPGRADE "שדרוג קושחה"
|
||||
#define D_CONSOLE "קונסול"
|
||||
#define D_CONFIRM_RESTART "אישור הפעלה מחדש"
|
||||
|
||||
#define D_CONFIGURE_MODULE "הגדרות מודול"
|
||||
#define D_CONFIGURE_WIFI "WIFI הגדרות"
|
||||
#define D_CONFIGURE_MQTT "MQTT הגדרות"
|
||||
#define D_CONFIGURE_DOMOTICZ "Domoticz הגדרות"
|
||||
#define D_CONFIGURE_LOGGING "הגדרת לוגים"
|
||||
#define D_CONFIGURE_OTHER "הגדרות שונות"
|
||||
#define D_CONFIRM_RESET_CONFIGURATION "אישור שינוי הגדרות"
|
||||
#define D_RESET_CONFIGURATION "אתחול הגדרות"
|
||||
#define D_BACKUP_CONFIGURATION "גיבוי הגדרות"
|
||||
#define D_RESTORE_CONFIGURATION "שחזור הגדרות"
|
||||
#define D_MAIN_MENU "תפריט ראשי"
|
||||
|
||||
#define D_MODULE_PARAMETERS "מודול פרמטרים"
|
||||
#define D_MODULE_TYPE "סוג מודול"
|
||||
#define D_GPIO " רגל "
|
||||
#define D_SERIAL_IN "כניסת סריאל"
|
||||
#define D_SERIAL_OUT "יציאת סריאל"
|
||||
|
||||
#define D_WIFI_PARAMETERS "Wifi פרמטרים"
|
||||
#define D_SCAN_FOR_WIFI_NETWORKS "סורק עבור רשתות אלחוטיות"
|
||||
#define D_SCAN_DONE "סריקה הושלמה"
|
||||
#define D_NO_NETWORKS_FOUND "לא נמצאו רשתות אלחוטיות"
|
||||
#define D_REFRESH_TO_SCAN_AGAIN "רענן כדי לסרוק שוב"
|
||||
#define D_DUPLICATE_ACCESSPOINT "נקודות גישה משוכפלות"
|
||||
#define D_SKIPPING_LOW_QUALITY "מדלג עקב איכות רשת נמוכה"
|
||||
#define D_RSSI "RSSI"
|
||||
#define D_WEP "WEP"
|
||||
#define D_WPA_PSK "WPA PSK"
|
||||
#define D_WPA2_PSK "WPA2 PSK"
|
||||
#define D_AP1_SSID "AP1 SSId"
|
||||
#define D_AP1_PASSWORD "AP1 Password"
|
||||
#define D_AP2_SSID "AP2 SSId"
|
||||
#define D_AP2_PASSWORD "AP2 Password"
|
||||
|
||||
#define D_MQTT_PARAMETERS "MQTT פרמטרים"
|
||||
#define D_CLIENT "לקוח"
|
||||
#define D_FULL_TOPIC "זיהוי מלא"
|
||||
|
||||
#define D_LOGGING_PARAMETERS "פרמטרי לוגים"
|
||||
#define D_SERIAL_LOG_LEVEL "רמת לוג עבור סריאל"
|
||||
#define D_WEB_LOG_LEVEL "רמת לוג עבור אתר"
|
||||
#define D_SYS_LOG_LEVEL "Syslog רמת לוג עבור שרת"
|
||||
#define D_MORE_DEBUG "מיפוי נוסף"
|
||||
#define D_SYSLOG_HOST "Syslog מארח"
|
||||
#define D_SYSLOG_PORT "Syslog פורט"
|
||||
#define D_TELEMETRY_PERIOD "Telemetry period"
|
||||
|
||||
#define D_OTHER_PARAMETERS "פרמטרים שונים"
|
||||
#define D_WEB_ADMIN_PASSWORD "סיסמת מנהל - אתר"
|
||||
#define D_MQTT_ENABLE "MQTT אפשר"
|
||||
#define D_FRIENDLY_NAME "שם ידידותי"
|
||||
#define D_BELKIN_WEMO "Belkin WeMo"
|
||||
#define D_HUE_BRIDGE "Hue Bridge"
|
||||
#define D_SINGLE_DEVICE "התקן בודד"
|
||||
#define D_MULTI_DEVICE "התקנים"
|
||||
|
||||
#define D_SAVE_CONFIGURATION "שמירת הגדרות"
|
||||
#define D_CONFIGURATION_SAVED "הגדרות נשמרו"
|
||||
#define D_CONFIGURATION_RESET "איפוס הגדרות"
|
||||
|
||||
#define D_PROGRAM_VERSION "גירסת תוכנה"
|
||||
#define D_BUILD_DATE_AND_TIME "Build Date & Time"
|
||||
#define D_CORE_AND_SDK_VERSION "Core/SDK Version"
|
||||
#define D_FLASH_WRITE_COUNT "מונה צריבות"
|
||||
#define D_MAC_ADDRESS "MAC כתובת"
|
||||
#define D_MQTT_HOST "MQTT מארח"
|
||||
#define D_MQTT_PORT "MQTT פורט"
|
||||
#define D_MQTT_CLIENT "MQTT לקוח"
|
||||
#define D_MQTT_USER "MQTT שם משתמש"
|
||||
#define D_MQTT_TOPIC "MQTT נושא"
|
||||
#define D_MQTT_GROUP_TOPIC "MQTT נושא קבוצת"
|
||||
#define D_MQTT_FULL_TOPIC "MQTT נושא מלא"
|
||||
#define D_MDNS_DISCOVERY "mDNS זיהוי"
|
||||
#define D_MDNS_ADVERTISE "mDNS פרסום"
|
||||
#define D_ESP_CHIP_ID "ESP מס' רכיב"
|
||||
#define D_FLASH_CHIP_ID "מס' רכיב פלאש"
|
||||
#define D_FLASH_CHIP_SIZE "גודל זיכרון פלאש"
|
||||
#define D_FREE_PROGRAM_SPACE "מקום פנוי - תוכנה"
|
||||
|
||||
#define D_UPGRADE_BY_WEBSERVER "שדרוג קושחה"
|
||||
#define D_OTA_URL "OTA כתובת"
|
||||
#define D_START_UPGRADE "התחל בשדרוג"
|
||||
#define D_UPGRADE_BY_FILE_UPLOAD "שדרוג דרך קובץ נכשל"
|
||||
#define D_UPLOAD_STARTED "העלאה מתחילה"
|
||||
#define D_UPGRADE_STARTED "שדרוג מתחיל"
|
||||
#define D_UPLOAD_DONE "העלאה הסתיימה"
|
||||
#define D_UPLOAD_ERR_1 "לא נבחר קובץ"
|
||||
#define D_UPLOAD_ERR_2 "אין מספיק מקום"
|
||||
#define D_UPLOAD_ERR_3 "Magic byte is not 0xE9"
|
||||
#define D_UPLOAD_ERR_4 "גודל קובץ השדרוג גדול מנפח האחסון של הפלאש"
|
||||
#define D_UPLOAD_ERR_5 "מאגר העלאה לא תקין"
|
||||
#define D_UPLOAD_ERR_6 "העלאה נכשלה. אפשר רישום 3"
|
||||
#define D_UPLOAD_ERR_7 "ההעלאה בוטלה"
|
||||
#define D_UPLOAD_ERR_8 "קובץ שגוי"
|
||||
#define D_UPLOAD_ERR_9 "קובץ גדול מדי"
|
||||
#define D_UPLOAD_ERR_10 "נכשלה RF הפעלת שבב"
|
||||
#define D_UPLOAD_ERR_11 "נכשלה RF מחיקת שבב"
|
||||
#define D_UPLOAD_ERR_12 "נכשלה RF כתיבת שבב"
|
||||
#define D_UPLOAD_ERR_13 "נכשלה RF קידוד קושחת שבב"
|
||||
#define D_UPLOAD_ERROR_CODE "שגיאת קוד העלאה"
|
||||
|
||||
#define D_ENTER_COMMAND "הקש פקודה"
|
||||
#define D_ENABLE_WEBLOG_FOR_RESPONSE "Enable weblog 2 if response expected"
|
||||
#define D_NEED_USER_AND_PASSWORD "Need user=<username>&password=<password>"
|
||||
|
||||
// xdrv_01_mqtt.ino
|
||||
#define D_FINGERPRINT "Verify TLS fingerprint..."
|
||||
#define D_TLS_CONNECT_FAILED_TO "TLS Connect failed to"
|
||||
#define D_RETRY_IN "Retry in"
|
||||
#define D_VERIFIED "Verified using Fingerprint"
|
||||
#define D_INSECURE "Insecure connection due to invalid Fingerprint"
|
||||
#define D_CONNECT_FAILED_TO "Connect failed to"
|
||||
|
||||
// xplg_wemohue.ino
|
||||
#define D_MULTICAST_DISABLED "Multicast disabled"
|
||||
#define D_MULTICAST_REJOINED "Multicast (re)joined"
|
||||
#define D_MULTICAST_JOIN_FAILED "Multicast join failed"
|
||||
#define D_FAILED_TO_SEND_RESPONSE "Failed to send response"
|
||||
|
||||
#define D_WEMO "WeMo"
|
||||
#define D_WEMO_BASIC_EVENT "WeMo basic event"
|
||||
#define D_WEMO_EVENT_SERVICE "WeMo event service"
|
||||
#define D_WEMO_META_SERVICE "WeMo meta service"
|
||||
#define D_WEMO_SETUP "WeMo setup"
|
||||
#define D_RESPONSE_SENT "Response sent"
|
||||
|
||||
#define D_HUE "Hue"
|
||||
#define D_HUE_BRIDGE_SETUP "Hue setup"
|
||||
#define D_HUE_API_NOT_IMPLEMENTED "Hue API not implemented"
|
||||
#define D_HUE_API "Hue API"
|
||||
#define D_HUE_POST_ARGS "Hue POST args"
|
||||
#define D_3_RESPONSE_PACKETS_SENT "3 response packets sent"
|
||||
|
||||
// xdrv_07_domoticz.ino
|
||||
#define D_DOMOTICZ_PARAMETERS "Domoticz parameters"
|
||||
#define D_DOMOTICZ_IDX "Idx"
|
||||
#define D_DOMOTICZ_KEY_IDX "Key idx"
|
||||
#define D_DOMOTICZ_SWITCH_IDX "Switch idx"
|
||||
#define D_DOMOTICZ_SENSOR_IDX "Sensor idx"
|
||||
#define D_DOMOTICZ_TEMP "Temp"
|
||||
#define D_DOMOTICZ_TEMP_HUM "Temp,Hum"
|
||||
#define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Hum,Baro"
|
||||
#define D_DOMOTICZ_POWER_ENERGY "Power,Energy"
|
||||
#define D_DOMOTICZ_ILLUMINANCE "Illuminance"
|
||||
#define D_DOMOTICZ_COUNT "Count/PM1"
|
||||
#define D_DOMOTICZ_VOLTAGE "Voltage/PM2.5"
|
||||
#define D_DOMOTICZ_CURRENT "Current/PM10"
|
||||
#define D_DOMOTICZ_AIRQUALITY "AirQuality"
|
||||
#define D_DOMOTICZ_UPDATE_TIMER "Update timer"
|
||||
|
||||
// xdrv_09_timers.ino
|
||||
#define D_CONFIGURE_TIMER "הגדרות תזמון"
|
||||
#define D_TIMER_PARAMETERS "פרמטרים עבור תזמון"
|
||||
#define D_TIMER_ENABLE "אפשר תזמון"
|
||||
#define D_TIMER_ARM "חמש"
|
||||
#define D_TIMER_TIME "זמן"
|
||||
#define D_TIMER_DAYS "ימים"
|
||||
#define D_TIMER_REPEAT "חזרות"
|
||||
#define D_TIMER_OUTPUT "פלט"
|
||||
#define D_TIMER_ACTION "פעולה"
|
||||
|
||||
// xdrv_10_knx.ino
|
||||
#define D_CONFIGURE_KNX "Configure KNX"
|
||||
#define D_KNX_PARAMETERS "KNX Parameters"
|
||||
#define D_KNX_GENERAL_CONFIG "General"
|
||||
#define D_KNX_PHYSICAL_ADDRESS "Physical Address"
|
||||
#define D_KNX_PHYSICAL_ADDRESS_NOTE "( Must be unique on the KNX network )"
|
||||
#define D_KNX_ENABLE "Enable KNX"
|
||||
#define D_KNX_GROUP_ADDRESS_TO_WRITE "Data to Send to Group Addresses"
|
||||
#define D_ADD "Add"
|
||||
#define D_DELETE "Delete"
|
||||
#define D_REPLY "Reply"
|
||||
#define D_KNX_GROUP_ADDRESS_TO_READ "Group Addresses to Receive Data from"
|
||||
#define D_LOG_KNX "KNX: "
|
||||
#define D_RECEIVED_FROM "Received from"
|
||||
#define D_KNX_COMMAND_WRITE "Write"
|
||||
#define D_KNX_COMMAND_READ "Read"
|
||||
#define D_KNX_COMMAND_OTHER "Other"
|
||||
#define D_SENT_TO "sent to"
|
||||
#define D_KNX_WARNING "The group address ( 0 / 0 / 0 ) is reserved and can not be used."
|
||||
#define D_KNX_ENHANCEMENT "Communication Enhancement"
|
||||
#define D_KNX_TX_SLOT "KNX TX"
|
||||
#define D_KNX_RX_SLOT "KNX RX"
|
||||
|
||||
// xdrv_03_energy.ino
|
||||
#define D_ENERGY_TODAY "צריכה יומית"
|
||||
#define D_ENERGY_YESTERDAY "צריכה בעבר"
|
||||
#define D_ENERGY_TOTAL "צריכה כללית"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor busy"
|
||||
#define D_SENSOR_CRC_ERROR "Sensor CRC error"
|
||||
#define D_SENSORS_FOUND "Sensors found"
|
||||
|
||||
// xsns_06_dht.ino
|
||||
#define D_TIMEOUT_WAITING_FOR "Timeout waiting for"
|
||||
#define D_START_SIGNAL_LOW "start signal low"
|
||||
#define D_START_SIGNAL_HIGH "start signal high"
|
||||
#define D_PULSE "pulse"
|
||||
#define D_CHECKSUM_FAILURE "Checksum failure"
|
||||
|
||||
// xsns_07_sht1x.ino
|
||||
#define D_SENSOR_DID_NOT_ACK_COMMAND "Sensor did not ACK command"
|
||||
#define D_SHT1X_FOUND "SHT1X found"
|
||||
|
||||
// xsns_18_pms5003.ino
|
||||
#define D_STANDARD_CONCENTRATION "CF-1 PM" // Standard Particle CF-1 Particle Matter
|
||||
#define D_ENVIRONMENTAL_CONCENTRATION "PM" // Environmetal Particle Matter
|
||||
#define D_PARTICALS_BEYOND "Particals"
|
||||
|
||||
// xsns_32_mpu6050.ino
|
||||
#define D_AX_AXIS "Accel. X-Axis"
|
||||
#define D_AY_AXIS "Accel. Y-Axis"
|
||||
#define D_AZ_AXIS "Accel. Z-Axis"
|
||||
#define D_GX_AXIS "Gyro X-Axis"
|
||||
#define D_GY_AXIS "Gyro Y-Axis"
|
||||
#define D_GZ_AXIS "Gyro Z-Axis"
|
||||
|
||||
// sonoff_template.h
|
||||
#define D_SENSOR_NONE "None"
|
||||
#define D_SENSOR_DHT11 "DHT11"
|
||||
#define D_SENSOR_AM2301 "AM2301"
|
||||
#define D_SENSOR_SI7021 "SI7021"
|
||||
#define D_SENSOR_DS18X20 "DS18x20"
|
||||
#define D_SENSOR_I2C_SCL "I2C SCL"
|
||||
#define D_SENSOR_I2C_SDA "I2C SDA"
|
||||
#define D_SENSOR_WS2812 "WS2812"
|
||||
#define D_SENSOR_DFR562 "MP3 Player"
|
||||
#define D_SENSOR_IRSEND "IRsend"
|
||||
#define D_SENSOR_SWITCH "מתג" // Suffix "1"
|
||||
#define D_SENSOR_BUTTON "לחצן" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "ממסר" // Suffix "1i"
|
||||
#define D_SENSOR_LED "לד" // Suffix "1i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "מונה" // Suffix "1"
|
||||
#define D_SENSOR_IRRECV "IRrecv"
|
||||
#define D_SENSOR_MHZ_RX "MHZ Rx"
|
||||
#define D_SENSOR_MHZ_TX "MHZ Tx"
|
||||
#define D_SENSOR_PZEM_RX "PZEM Rx"
|
||||
#define D_SENSOR_PZEM_TX "PZEM Tx"
|
||||
#define D_SENSOR_SAIR_RX "SAir Rx"
|
||||
#define D_SENSOR_SAIR_TX "SAir Tx"
|
||||
#define D_SENSOR_SPI_CS "SPI CS"
|
||||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx"
|
||||
#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx"
|
||||
#define D_SENSOR_SBR_RX "SerBr Rx"
|
||||
#define D_SENSOR_SBR_TX "SerBr Tx"
|
||||
#define D_SENSOR_SR04_TRIG "SR04 Tri"
|
||||
#define D_SENSOR_SR04_ECHO "SR04 Ech"
|
||||
#define D_SENSOR_SDM120_TX "SDM120 Tx"
|
||||
#define D_SENSOR_SDM120_RX "SDM120 Rx"
|
||||
#define D_SENSOR_SDM630_TX "SDM630 Tx"
|
||||
#define D_SENSOR_SDM630_RX "SDM630 Rx"
|
||||
#define D_SENSOR_TM1638_CLK "TM16 CLK"
|
||||
#define D_SENSOR_TM1638_DIO "TM16 DIO"
|
||||
#define D_SENSOR_TM1638_STB "TM16 STB"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
#define D_UNIT_CENTIMETER "cm"
|
||||
#define D_UNIT_HOUR "Hr"
|
||||
#define D_UNIT_INCREMENTS "inc"
|
||||
#define D_UNIT_KILOOHM "kOhm"
|
||||
#define D_UNIT_KILOWATTHOUR "kWh"
|
||||
#define D_UNIT_LUX "lx"
|
||||
#define D_UNIT_MICROGRAM_PER_CUBIC_METER "ug/m3"
|
||||
#define D_UNIT_MICROMETER "um"
|
||||
#define D_UNIT_MICROSECOND "us"
|
||||
#define D_UNIT_MILLIAMPERE "mA"
|
||||
#define D_UNIT_MILLISECOND "ms"
|
||||
#define D_UNIT_MINUTE "Min"
|
||||
#define D_UNIT_PARTS_PER_BILLION "ppb"
|
||||
#define D_UNIT_PARTS_PER_DECILITER "ppd"
|
||||
#define D_UNIT_PARTS_PER_MILLION "ppm"
|
||||
#define D_UNIT_PRESSURE "hPa"
|
||||
#define D_UNIT_SECOND "sec"
|
||||
#define D_UNIT_SECTORS "sectors"
|
||||
#define D_UNIT_VA "VA"
|
||||
#define D_UNIT_VAR "VAr"
|
||||
#define D_UNIT_VOLT "V"
|
||||
#define D_UNIT_WATT "W"
|
||||
#define D_UNIT_WATTHOUR "Wh"
|
||||
#define D_UNIT_HERTZ "Hz"
|
||||
#define D_UNIT_WATT_METER_QUADRAT "W/m²"
|
||||
|
||||
// Log message prefix
|
||||
#define D_LOG_APPLICATION "APP: " // Application
|
||||
#define D_LOG_BRIDGE "BRG: " // Bridge
|
||||
#define D_LOG_CONFIG "CFG: " // Settings
|
||||
#define D_LOG_COMMAND "CMD: " // Command
|
||||
#define D_LOG_DEBUG "DBG: " // Debug
|
||||
#define D_LOG_DHT "DHT: " // DHT sensor
|
||||
#define D_LOG_DOMOTICZ "DOM: " // Domoticz
|
||||
#define D_LOG_DSB "DSB: " // DS18xB20 sensor
|
||||
#define D_LOG_HTTP "HTP: " // HTTP webserver
|
||||
#define D_LOG_I2C "I2C: " // I2C
|
||||
#define D_LOG_IRR "IRR: " // Infra Red Received
|
||||
#define D_LOG_LOG "LOG: " // Logging
|
||||
#define D_LOG_MODULE "MOD: " // Module
|
||||
#define D_LOG_MDNS "DNS: " // mDNS
|
||||
#define D_LOG_MQTT "MQT: " // MQTT
|
||||
#define D_LOG_OTHER "OTH: " // Other
|
||||
#define D_LOG_RESULT "RSL: " // Result
|
||||
#define D_LOG_RFR "RFR: " // RF Received
|
||||
#define D_LOG_SERIAL "SER: " // Serial
|
||||
#define D_LOG_SHT1 "SHT: " // SHT1x sensor
|
||||
#define D_LOG_UPLOAD "UPL: " // Upload
|
||||
#define D_LOG_UPNP "UPP: " // UPnP
|
||||
#define D_LOG_WIFI "WIF: " // Wifi
|
||||
|
||||
#endif // _LANGUAGE_HE_HE_H_
|
|
@ -20,6 +20,11 @@
|
|||
#ifndef _SONOFF_H_
|
||||
#define _SONOFF_H_
|
||||
|
||||
#define USE_DHT // Default DHT11 sensor needs no external library
|
||||
#define USE_ENERGY_SENSOR // Use energy sensors (+14k code)
|
||||
#define USE_HLW8012 // Use energy sensor for Sonoff Pow and WolfBlitz
|
||||
#define USE_CSE7766 // Use energy sensor for Sonoff S31 and Pow R2
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Power Type
|
||||
\*********************************************************************************************/
|
||||
|
@ -136,7 +141,7 @@ typedef unsigned long power_t; // Power (Relay) type
|
|||
|
||||
#define MQTT_PUBSUBCLIENT 1 // Mqtt PubSubClient library
|
||||
#define MQTT_TASMOTAMQTT 2 // Mqtt TasmotaMqtt library based on esp-mqtt-arduino
|
||||
#define MQTT_ESPMQTTARDUINO 3 // Mqtt esp-mqtt-arduino library by Ingo Randolf
|
||||
#define MQTT_ARDUINOMQTT 3 // Mqtt arduino-mqtt library by Joel Gaehwiler (https://github.com/256dpi/arduino-mqtt)
|
||||
|
||||
// Sunrise and Sunset DawnType
|
||||
#define DAWN_NORMAL -0.8333
|
||||
|
|
|
@ -50,11 +50,6 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
|||
#define MODULE SONOFF_BASIC // [Module] Select default model
|
||||
#endif
|
||||
|
||||
#define USE_DHT // Default DHT11 sensor needs no external library
|
||||
#define USE_ENERGY_SENSOR // Use energy sensors (+14k code)
|
||||
#define USE_HLW8012 // Use energy sensor for Sonoff Pow and WolfBlitz
|
||||
#define USE_CSE7766 // Use energy sensor for Sonoff S31 and Pow R2
|
||||
|
||||
/*********************************************************************************************\
|
||||
* [sonoff-sensors.bin]
|
||||
* Provide an image with useful supported sensors enabled
|
||||
|
@ -272,10 +267,13 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
|||
#endif
|
||||
|
||||
#ifndef MQTT_MAX_PACKET_SIZE
|
||||
#define MQTT_MAX_PACKET_SIZE 1000
|
||||
#define MQTT_MAX_PACKET_SIZE 1000 // Bytes
|
||||
#endif
|
||||
#ifndef MQTT_KEEPALIVE
|
||||
#define MQTT_KEEPALIVE 15
|
||||
#define MQTT_KEEPALIVE 15 // Seconds
|
||||
#endif
|
||||
#ifndef MQTT_TIMEOUT
|
||||
#define MQTT_TIMEOUT 10000 // milli seconds
|
||||
#endif
|
||||
|
||||
#ifndef MESSZ
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#ifndef _SONOFF_VERSION_H_
|
||||
#define _SONOFF_VERSION_H_
|
||||
|
||||
#define VERSION 0x0602010A
|
||||
#define VERSION 0x0602010B
|
||||
|
||||
#define D_PROGRAMNAME "Sonoff-Tasmota"
|
||||
#define D_AUTHOR "Theo Arends"
|
||||
|
|
|
@ -876,7 +876,7 @@ void GetFeatures()
|
|||
#if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT)
|
||||
feature_drv1 |= 0x00000800; // xdrv_01_mqtt.ino
|
||||
#endif
|
||||
#if (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO)
|
||||
#if (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) // Obsolete since 6.2.1.11
|
||||
feature_drv1 |= 0x00001000; // xdrv_01_mqtt.ino
|
||||
#endif
|
||||
#ifdef MQTT_HOST_DISCOVERY
|
||||
|
@ -933,6 +933,9 @@ void GetFeatures()
|
|||
#ifdef USE_SMARTCONFIG
|
||||
feature_drv1 |= 0x40000000; // support.ino
|
||||
#endif
|
||||
#if (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT)
|
||||
feature_drv1 |= 0x80000000; // xdrv_01_mqtt.ino
|
||||
#endif
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
|
|
|
@ -196,6 +196,7 @@
|
|||
//#define MY_LANGUAGE en-GB // English in Great Britain. Enabled by Default
|
||||
//#define MY_LANGUAGE es-AR // Spanish in Argentina
|
||||
//#define MY_LANGUAGE fr-FR // French in France
|
||||
//#define MY_LANGUAGE he-HE // Hebrew in Israel
|
||||
//#define MY_LANGUAGE hu-HU // Hungarian in Hungary
|
||||
//#define MY_LANGUAGE it-IT // Italian in Italy
|
||||
//#define MY_LANGUAGE nl-NL // Dutch in the Netherlands
|
||||
|
@ -216,14 +217,14 @@
|
|||
//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+13k code)
|
||||
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* Select ONE of possible three MQTT library types below
|
||||
* Select ONE of possible MQTT library types below
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
// Default MQTT driver for both non-TLS and TLS connections. Blocks network if MQTT server is unavailable.
|
||||
#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library
|
||||
// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 code, +4k mem) - non-TLS only
|
||||
// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO // Use (patched) esp-mqtt-arduino library (+4k8 code, +4k mem) - non-TLS only
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 (core 2.3.0), +14k4 (core 2.4.2 lwip2) code, +4k mem) - non-TLS only
|
||||
// Alternative MQTT driver does not block network when MQTT server is unavailable. TLS should work but needs to be tested.
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Use arduino-mqtt (lwmqtt) library (+3k3 code, +2k mem)
|
||||
|
||||
// -- MQTT ----------------------------------------
|
||||
#define MQTT_TELE_RETAIN 0 // Tele messages may send retain flag (0 = off, 1 = on)
|
||||
|
@ -271,6 +272,7 @@
|
|||
// -- One wire sensors ----------------------------
|
||||
// WARNING: Select none for default one DS18B20 sensor or enable one of the following two options for multiple sensors
|
||||
#define USE_DS18x20 // Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
|
||||
//#define W1_PARASITE_POWER // If using USE_DS18x20 then optimize for parasite powered sensors
|
||||
//#define USE_DS18x20_LEGACY // Optional for more than one DS18x20 sensors with dynamic scan using library OneWire (+1k5 code)
|
||||
|
||||
// -- I2C sensors ---------------------------------
|
||||
|
|
|
@ -23,19 +23,29 @@
|
|||
// Default MQTT driver for both non-TLS and TLS connections. Blocks network if MQTT server is unavailable.
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library
|
||||
// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 code, +4k mem) - non-TLS only
|
||||
// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_ESPMQTTARDUINO // Use (patched) esp-mqtt-arduino library (+4k8 code, +4k mem) - non-TLS only
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_TASMOTAMQTT // Use TasmotaMqtt library (+4k4 (core 2.3.0), +14k4 (core 2.4.2 lwip2) code, +4k mem) - non-TLS only
|
||||
// Alternative MQTT driver does not block network when MQTT server is unavailable. TLS should work but needs to be tested.
|
||||
//#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Use arduino-mqtt (lwmqtt) library (+3k3 code, +2k mem)
|
||||
|
||||
#ifdef USE_MQTT_TLS
|
||||
|
||||
/*
|
||||
#ifdef MQTT_LIBRARY_TYPE
|
||||
#undef MQTT_LIBRARY_TYPE
|
||||
#endif
|
||||
#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS
|
||||
*/
|
||||
#if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT)
|
||||
#undef MQTT_LIBRARY_TYPE
|
||||
#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef MQTT_LIBRARY_TYPE
|
||||
#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as default
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
@ -136,48 +146,48 @@ void MqttLoop()
|
|||
{
|
||||
}
|
||||
|
||||
#elif (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) /*******************************************/
|
||||
#elif (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT) /**********************************************/
|
||||
|
||||
#include <MQTT.h>
|
||||
MQTT *MqttClient = NULL;
|
||||
#include <MQTTClient.h>
|
||||
MQTTClient MqttClient(MQTT_MAX_PACKET_SIZE);
|
||||
|
||||
bool MqttIsConnected()
|
||||
{
|
||||
return mqtt_connected;
|
||||
return MqttClient.connected();
|
||||
}
|
||||
|
||||
void MqttDisconnect()
|
||||
{
|
||||
if (MqttClient) MqttClient->disconnect();
|
||||
MqttClient.disconnect();
|
||||
}
|
||||
|
||||
void MqttDisconnectedCb()
|
||||
/*
|
||||
void MqttMyDataCb(MQTTClient* client, char* topic, char* data, int data_len)
|
||||
//void MqttMyDataCb(MQTTClient *client, char topic[], char data[], int data_len)
|
||||
{
|
||||
MqttDisconnected(MqttClient->getState()); // status codes are documented in file mqtt.h as tConnState
|
||||
// MqttDataHandler((char*)topic, (byte*)data, data_len);
|
||||
}
|
||||
*/
|
||||
|
||||
void MqttMyDataCb(const char* topic, uint32_t topic_len, const char* data, uint32_t data_len)
|
||||
void MqttMyDataCb(String &topic, String &data)
|
||||
{
|
||||
char topic_copy[topic_len +1];
|
||||
|
||||
memcpy(topic_copy, topic, topic_len);
|
||||
topic_copy[topic_len] = 0;
|
||||
if (0 == data_len) data = (const char*)&topic_copy + topic_len;
|
||||
MqttDataHandler((char*)topic_copy, (byte*)data, data_len);
|
||||
MqttDataHandler((char*)topic.c_str(), (byte*)data.c_str(), data.length());
|
||||
}
|
||||
|
||||
void MqttSubscribeLib(char *topic)
|
||||
{
|
||||
MqttClient->subscribe(topic);
|
||||
MqttClient.subscribe(topic, 0);
|
||||
}
|
||||
|
||||
bool MqttPublishLib(const char* topic, boolean retained)
|
||||
{
|
||||
return MqttClient->publish(topic, mqtt_data, strlen(mqtt_data), 0, retained);
|
||||
return MqttClient.publish(topic, mqtt_data, strlen(mqtt_data), retained, 0);
|
||||
}
|
||||
|
||||
void MqttLoop()
|
||||
{
|
||||
MqttClient.loop();
|
||||
// delay(10);
|
||||
}
|
||||
|
||||
#endif // MQTT_LIBRARY_TYPE
|
||||
|
@ -467,6 +477,14 @@ void MqttReconnect()
|
|||
GetTopic_P(stopic, TELE, mqtt_topic, S_LWT);
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_OFFLINE);
|
||||
|
||||
//#ifdef ARDUINO_ESP8266_RELEASE_2_4_1
|
||||
#ifdef USE_MQTT_TLS
|
||||
EspClient = WiFiClientSecure(); // Wifi Secure Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497)
|
||||
#else
|
||||
EspClient = WiFiClient(); // Wifi Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497)
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
if (2 == mqtt_initial_connection_state) { // Executed once just after power on and wifi is connected
|
||||
#ifdef USE_MQTT_TLS
|
||||
if (!MqttCheckTls()) return;
|
||||
|
@ -479,25 +497,17 @@ void MqttReconnect()
|
|||
MqttClient.OnConnected(MqttConnected);
|
||||
MqttClient.OnDisconnected(MqttDisconnectedCb);
|
||||
MqttClient.OnData(MqttDataHandler);
|
||||
#elif (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO)
|
||||
MqttClient = new MQTT(mqtt_client, Settings.mqtt_host, Settings.mqtt_port, stopic, 1, true, mqtt_data);
|
||||
MqttClient->setUserPwd(mqtt_user, mqtt_pwd);
|
||||
MqttClient->onConnected(MqttConnected);
|
||||
MqttClient->onDisconnected(MqttDisconnectedCb);
|
||||
MqttClient->onData(MqttMyDataCb);
|
||||
#elif (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT)
|
||||
MqttClient.begin(Settings.mqtt_host, Settings.mqtt_port, EspClient);
|
||||
MqttClient.setWill(stopic, mqtt_data, true, 1);
|
||||
MqttClient.setOptions(MQTT_KEEPALIVE, true, MQTT_TIMEOUT);
|
||||
// MqttClient.onMessageAdvanced(MqttMyDataCb);
|
||||
MqttClient.onMessage(MqttMyDataCb);
|
||||
#endif
|
||||
|
||||
mqtt_initial_connection_state = 1;
|
||||
}
|
||||
|
||||
//#ifdef ARDUINO_ESP8266_RELEASE_2_4_1
|
||||
#ifdef USE_MQTT_TLS
|
||||
EspClient = WiFiClientSecure(); // Wifi Secure Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497)
|
||||
#else
|
||||
EspClient = WiFiClient(); // Wifi Client reconnect issue 4497 (https://github.com/esp8266/Arduino/issues/4497)
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
#if (MQTT_LIBRARY_TYPE == MQTT_PUBSUBCLIENT)
|
||||
MqttClient.setCallback(MqttDataHandler);
|
||||
MqttClient.setServer(Settings.mqtt_host, Settings.mqtt_port);
|
||||
|
@ -508,8 +518,12 @@ void MqttReconnect()
|
|||
}
|
||||
#elif (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT)
|
||||
MqttClient.Connect();
|
||||
#elif (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO)
|
||||
MqttClient->connect();
|
||||
#elif (MQTT_LIBRARY_TYPE == MQTT_ARDUINOMQTT)
|
||||
if (MqttClient.connect(mqtt_client, mqtt_user, mqtt_pwd)) {
|
||||
MqttConnected();
|
||||
} else {
|
||||
MqttDisconnected(MqttClient.lastError()); // status codes are documented here https://github.com/256dpi/lwmqtt/blob/master/include/lwmqtt.h#L11
|
||||
}
|
||||
#endif // MQTT_LIBRARY_TYPE
|
||||
}
|
||||
|
||||
|
|
|
@ -789,6 +789,17 @@ void HandleWifiConfiguration()
|
|||
HandleWifi(false);
|
||||
}
|
||||
|
||||
String htmlEscape(String s)
|
||||
{
|
||||
s.replace("&", "&");
|
||||
s.replace("<", "<");
|
||||
s.replace(">", ">");
|
||||
s.replace("\"", """);
|
||||
s.replace("'", "'");
|
||||
s.replace("/", "/");
|
||||
return s;
|
||||
}
|
||||
|
||||
void HandleWifi(boolean scan)
|
||||
{
|
||||
if (HttpUser()) { return; }
|
||||
|
@ -854,7 +865,7 @@ void HandleWifi(boolean scan)
|
|||
String item = FPSTR(HTTP_LNK_ITEM);
|
||||
String rssiQ;
|
||||
rssiQ += quality;
|
||||
item.replace(F("{v}"), WiFi.SSID(indices[i]));
|
||||
item.replace(F("{v}"), htmlEscape(WiFi.SSID(indices[i])));
|
||||
item.replace(F("{w}"), String(WiFi.channel(indices[i])));
|
||||
item.replace(F("{r}"), rssiQ);
|
||||
uint8_t auth = WiFi.encryptionType(indices[i]);
|
||||
|
|
|
@ -83,6 +83,7 @@ unsigned long rules_timer[MAX_RULE_TIMERS] = { 0 };
|
|||
uint8_t rules_quota = 0;
|
||||
long rules_new_power = -1;
|
||||
long rules_old_power = -1;
|
||||
long rules_old_dimm = -1;
|
||||
|
||||
uint32_t rules_triggers[MAX_RULE_SETS] = { 0 };
|
||||
uint16_t rules_last_minute = 60;
|
||||
|
@ -398,6 +399,16 @@ void RulesEvery50ms()
|
|||
}
|
||||
rules_old_power = rules_new_power;
|
||||
}
|
||||
else if (rules_old_dimm != Settings.light_dimmer) {
|
||||
if (rules_old_dimm != -1) {
|
||||
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Dimmer\":{\"State\":%d}}"), Settings.light_dimmer);
|
||||
} else {
|
||||
// Boot time DIMMER VALUE
|
||||
snprintf_P(json_event, sizeof(json_event), PSTR("{\"Dimmer\":{\"Boot\":%d}}"), Settings.light_dimmer);
|
||||
}
|
||||
RulesProcessEvent(json_event);
|
||||
rules_old_dimm = Settings.light_dimmer;
|
||||
}
|
||||
else if (event_data[0]) {
|
||||
char *event;
|
||||
char *parameter;
|
||||
|
|
|
@ -98,6 +98,7 @@ void PCA9685_SetPWM(uint8_t pin, uint16_t pwm, bool inverted) {
|
|||
} else {
|
||||
PCA9685_SetPWM_Reg(pin, 0, pwm);
|
||||
}
|
||||
pca9685_pin_pwm_value[pin] = pwm;
|
||||
}
|
||||
|
||||
bool PCA9685_Command(void)
|
||||
|
@ -120,6 +121,8 @@ bool PCA9685_Command(void)
|
|||
|
||||
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"RESET")) { PCA9685_Reset(); return serviced; }
|
||||
|
||||
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"STATUS")) { PCA9685_OutputTelemetry(false); return serviced; }
|
||||
|
||||
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"PWMF")) {
|
||||
if (paramcount > 1) {
|
||||
uint16_t new_freq = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2));
|
||||
|
@ -162,7 +165,7 @@ bool PCA9685_Command(void)
|
|||
return serviced;
|
||||
}
|
||||
|
||||
void PCA9685_OutputTelemetry(void) {
|
||||
void PCA9685_OutputTelemetry(bool telemetry) {
|
||||
if (0 == pca9685_detected) { return; } // We do not do this if the PCA9685 has not been detected
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"PCA9685\": {"), GetDateAndTime(DT_LOCAL).c_str());
|
||||
snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"PWM_FREQ\":%i,"),mqtt_data,pca9685_freq);
|
||||
|
@ -170,7 +173,9 @@ void PCA9685_OutputTelemetry(void) {
|
|||
snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"PWM%i\":%i,"),mqtt_data,pin,pca9685_pin_pwm_value[pin]);
|
||||
}
|
||||
snprintf_P(mqtt_data,sizeof(mqtt_data),PSTR("%s\"END\":1}}"),mqtt_data);
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
|
||||
if (telemetry) {
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
|
||||
}
|
||||
}
|
||||
|
||||
boolean Xdrv15(byte function)
|
||||
|
@ -182,7 +187,7 @@ boolean Xdrv15(byte function)
|
|||
case FUNC_EVERY_SECOND:
|
||||
PCA9685_Detect();
|
||||
if (tele_period == 0) {
|
||||
PCA9685_OutputTelemetry();
|
||||
PCA9685_OutputTelemetry(true);
|
||||
}
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#define HLW_IREF 4545 // 4.545A
|
||||
#define HLW_SEL_VOLTAGE 1
|
||||
|
||||
// HJL-01 based (BlitzWolf, Homecube, Gosund)
|
||||
// HJL-01 based (BlitzWolf, Homecube, Gosund, Teckin)
|
||||
#define HJL_PREF 1362
|
||||
#define HJL_UREF 822
|
||||
#define HJL_IREF 3300
|
||||
|
@ -177,7 +177,7 @@ void HlwSnsInit()
|
|||
Settings.energy_current_calibration = HLW_IREF_PULSE;
|
||||
}
|
||||
|
||||
if (BLITZWOLF_BWSHP2 == Settings.module) {
|
||||
if ((BLITZWOLF_BWSHP2 == Settings.module) || (TECKIN == Settings.module)) {
|
||||
hlw_power_ratio = HJL_PREF;
|
||||
hlw_voltage_ratio = HJL_UREF;
|
||||
hlw_current_ratio = HJL_IREF;
|
||||
|
|
|
@ -49,6 +49,10 @@ struct DS18X20STRUCT {
|
|||
uint8_t ds18x20_sensors = 0;
|
||||
uint8_t ds18x20_pin = 0;
|
||||
char ds18x20_types[12];
|
||||
#ifdef W1_PARASITE_POWER
|
||||
uint8_t ds18x20_sensor_curr = 0;
|
||||
unsigned long w1_power_until = 0;
|
||||
#endif
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Embedded tuned OneWire library
|
||||
|
@ -285,7 +289,14 @@ void Ds18x20Init()
|
|||
void Ds18x20Convert()
|
||||
{
|
||||
OneWireReset();
|
||||
#ifdef W1_PARASITE_POWER
|
||||
// With parasite power address one sensor at a time
|
||||
if (++ds18x20_sensor_curr >= ds18x20_sensors)
|
||||
ds18x20_sensor_curr = 0;
|
||||
OneWireSelect(ds18x20_sensor[ds18x20_sensor_curr].address);
|
||||
#else
|
||||
OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus
|
||||
#endif
|
||||
OneWireWrite(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end
|
||||
// delay(750); // 750ms should be enough for 12bit conv
|
||||
}
|
||||
|
@ -334,6 +345,9 @@ bool Ds18x20Read(uint8_t sensor)
|
|||
OneWireWrite(data[4]); // Configuration Register
|
||||
OneWireSelect(ds18x20_sensor[index].address);
|
||||
OneWireWrite(W1_WRITE_EEPROM); // Save scratchpad to EEPROM
|
||||
#ifdef W1_PARASITE_POWER
|
||||
w1_power_until = millis() + 10; // 10ms specified duration for EEPROM write
|
||||
#endif
|
||||
}
|
||||
temp12 = (data[1] << 8) + data[0];
|
||||
if (temp12 > 2047) {
|
||||
|
@ -374,7 +388,18 @@ void Ds18x20Name(uint8_t sensor)
|
|||
|
||||
void Ds18x20EverySecond()
|
||||
{
|
||||
if (uptime &1) {
|
||||
#ifdef W1_PARASITE_POWER
|
||||
// skip access if there is still an eeprom write ongoing
|
||||
unsigned long now = millis();
|
||||
if (now < w1_power_until)
|
||||
return;
|
||||
#endif
|
||||
if (uptime & 1
|
||||
#ifdef W1_PARASITE_POWER
|
||||
// if more than 1 sensor and only parasite power: convert every cycle
|
||||
|| ds18x20_sensors >= 2
|
||||
#endif
|
||||
) {
|
||||
// 2mS
|
||||
Ds18x20Convert(); // Start conversion, takes up to one second
|
||||
} else {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -105,7 +105,7 @@ a_features = [[
|
|||
"USE_WS2812_DMA","USE_IR_REMOTE","USE_IR_HVAC","USE_IR_RECEIVE",
|
||||
"USE_DOMOTICZ","USE_DISPLAY","USE_HOME_ASSISTANT","USE_SERIAL_BRIDGE",
|
||||
"USE_TIMERS","USE_SUNRISE","USE_TIMERS_WEB","USE_RULES",
|
||||
"USE_KNX","USE_WPS","USE_SMARTCONFIG",""
|
||||
"USE_KNX","USE_WPS","USE_SMARTCONFIG","MQTT_ARDUINOMQTT"
|
||||
],[
|
||||
"USE_CONFIG_OVERRIDE","BE_MINIMAL","USE_SENSORS","USE_CLASSIC",
|
||||
"USE_KNX_NO_EMULATION","USE_DISPLAY_MODES1TO5","USE_DISPLAY_GRAPH","USE_DISPLAY_LCD",
|
||||
|
|
Loading…
Reference in New Issue