Merge branch 'arendst/development' into development

This commit is contained in:
reloxx13 2018-10-12 22:55:41 +02:00
commit 1923e58926
104 changed files with 8575 additions and 4362 deletions

View File

@ -93,8 +93,8 @@ The following devices are supported:
- [BlitzWolf BW-SHP2 Smart Socket with Energy Monitoring](https://www.banggood.com/BlitzWolf-BW-SHP2-Smart-WIFI-Socket-EU-Plug-220V-16A-Work-with-Amazon-Alexa-Google-Assistant-p-1292899.html)<img src="https://github.com/arendst/arendst.github.io/blob/master/media/shelly2_small_250a.png" width="250" align="right" />
- [Luani HVIO board](https://luani.de/projekte/esp8266-hvio/)
- [Wemos D1 mini](https://wiki.wemos.cc/products:d1:d1_mini)
- [HuaFan Smart Socket](HuaFan-Smart-Socket)
- [Hyleton-313 Smart Plug](Hyleton-313-Smart-Plug)
- [HuaFan Smart Socket](https://github.com/arendst/Sonoff-Tasmota/wiki/HuaFan-Smart-Socket)
- [Hyleton-313 Smart Plug](https://github.com/arendst/Sonoff-Tasmota/wiki/Hyleton-313-Smart-Plug)
- [Allterco Shelly 1](https://shelly.cloud/shelly1-open-source/)
- [Allterco Shelly 2 with Energy Monitoring](https://shelly.cloud/shelly2/)
- NodeMcu and Ledunia

View File

@ -0,0 +1,7 @@
[Makefile]
indent_style = tab
indent_size = 4
[src/*.h,src/*.cpp,examples/**.ino]
indent_style = space
indent_size = 2

2
lib/arduino-mqtt-2.4.0/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.DS_Store
cmake-build-debug/

View File

@ -0,0 +1,46 @@
language: generic
env:
global:
- IDE_VERSION=1.8.7
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;

View File

@ -0,0 +1,38 @@
# 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/Library/Arduino15/packages/esp32/libraries/WiFi/src
/Users/256dpi/Library/Arduino15/packages/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)
add_executable(arduino-mqtt ${SOURCE_FILES})

View File

@ -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.

View File

@ -0,0 +1,14 @@
all: fmt
fmt:
clang-format -i 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/*

View File

@ -0,0 +1,226 @@
# 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 skip = false);
bool connect(const char clientId[], const char username[], bool skip = false);
bool connect(const char clientId[], const char username[], const char password[], bool skip = false);
```
- If the `skip` option is set to true, the client will skip the network level connection and jump to the MQTT level connection. This option can be used in order to establish and verify TLS connections manually before giving control to the MQTT client.
- 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.

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -0,0 +1,9 @@
name=MQTT
version=2.4.0
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=*

View File

@ -0,0 +1,6 @@
#ifndef MQTT_H
#define MQTT_H
#include "MQTTClient.h"
#endif

View File

@ -0,0 +1,491 @@
#ifndef MQTT_CLIENT_H
#define MQTT_CLIENT_H
#include <Arduino.h>
#include <Client.h>
#include <Stream.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;
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;
}
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 = nullptr;
MQTTClientCallback callback;
lwmqtt_arduino_network_t network = {nullptr};
lwmqtt_arduino_timer_t timer1 = {0};
lwmqtt_arduino_timer_t timer2 = {0};
lwmqtt_client_t client = {0};
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) {
// reset client
memset(&this->client, 0, sizeof(lwmqtt_client_t));
// allocate buffers
this->bufSize = (size_t)bufSize;
this->readBuf = (uint8_t *)malloc((size_t)bufSize + 1);
this->writeBuf = (uint8_t *)malloc((size_t)bufSize);
}
~MQTTClient() {
// free will
this->clearWill();
// free hostname
if (this->hostname != nullptr) {
free((void *)this->hostname);
}
// free buffers
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) {
// return if topic is missing
if (topic == nullptr || strlen(topic) == 0) {
return;
}
// clear existing will
this->clearWill();
// allocate will
this->will = (lwmqtt_will_t *)malloc(sizeof(lwmqtt_will_t));
memset(this->will, 0, sizeof(lwmqtt_will_t));
// set topic
this->will->topic = lwmqtt_string(strdup(topic));
// set payload if available
if (payload != nullptr && strlen(payload) > 0) {
this->will->payload = lwmqtt_string(strdup(payload));
}
// set flags
this->will->retained = retained;
this->will->qos = (lwmqtt_qos_t)qos;
}
void clearWill() {
// return if not set
if (this->will == nullptr) {
return;
}
// free payload if set
if (this->will->payload.len > 0) {
free(this->will->payload.data);
}
// free topic if set
if (this->will->topic.len > 0) {
free(this->will->topic.data);
}
// free will
free(this->will);
this->will = nullptr;
}
void setOptions(int keepAlive, bool cleanSession, int timeout) {
// set new options
this->keepAlive = (uint16_t)keepAlive;
this->cleanSession = cleanSession;
this->timeout = (uint32_t)timeout;
}
bool connect(const char clientId[], bool skip = false) { return this->connect(clientId, nullptr, nullptr); }
bool connect(const char clientId[], const char username[], bool skip = false) { return this->connect(clientId, username, nullptr); }
bool connect(const char clientId[], const char username[], const char password[], bool skip = false) {
// close left open connection if still connected
if (!skip && this->connected()) {
this->close();
}
// save client
this->network.client = this->netClient;
// connect to hostg
if(!skip) {
int ret = this->netClient->connect(this->hostname, (uint16_t)this->port);
if (ret <= 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);
}
}
// connect to broker
this->_lastError = lwmqtt_connect(&this->client, options, this->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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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
._*

View File

@ -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!

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)
#######################################

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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__

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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}

View File

@ -1,6 +1,41 @@
/* 6.2.1.9 20180928
/* 6.2.1.15 20181012
* Fix Color Temperature slider functionality regression from 20180726 (#4037)
* Add auto reload of main web page to some web restarts
*
* 6.2.1.14 20181010
* Rewrite Webserver page handler for easier extension (thx to Adrian Scillato)
* Add support for DS3231 Real Time Clock
* Add support for HX711 Load Cell
* Add command WeightRes 0..3 to control display of decimals for kilogram
*
* 6.2.1.13 20181008
* Change default Mqtt client library from PubSubClient to non-blocking ArduinoMqtt by Joel Gaehwiler
* Add command WebRefresh 1000..10000 to control web page refresh in milliseconds. Default is 2345
*
* 6.2.1.12 20181007
* Fix Shelly1 switchmode 3 and 4 when using pushbutton (#3989)
* Add support for CSL Aplic WDP 303075 Power Socket with Energy Monitoring (#3991, #3996)
*
* 6.2.1.11 20181002
* 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)
* Fix exception when wrong Domoticz JSON message is received (#3963)
*
* 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)
* Fix timer offset -00:00 causing 12:00 hour offset (#3923)
* Add support for OBI Power Socket (#1988, #3944)
* Add support for Teckin Power Socket with Energy Monitoring (#3950)
*
* 6.2.1.9 20180928
* Add Apparent Power and Reactive Power to Energy Monitoring devices (#251)
* Add RF Receiver control to module MagicHome to be used on Arilux LC10 (#3792)
* Fix I2CScan invalid JSON error message (#3925)
* Fix invalid configuration restores and decode_config.py crc error when savedata = 0 (#3918)
*
* 6.2.1.8 20180926
* Change status JSON message providing more switch and retain information

View File

@ -46,6 +46,7 @@
#define D_JSON_COMMAND "Command"
#define D_JSON_CONNECT_FAILED "Connect failed"
#define D_JSON_COREVERSION "Core"
#define D_JSON_COUNT "Count"
#define D_JSON_COUNTER "Counter"
#define D_JSON_CURRENT "Current" // As in Voltage and Current
#define D_JSON_DATA "Data"
@ -137,6 +138,7 @@
#define D_JSON_VCC "Vcc"
#define D_JSON_VERSION "Version"
#define D_JSON_VOLTAGE "Voltage"
#define D_JSON_WEIGHT "Weight"
#define D_JSON_WIFI "Wifi"
#define D_JSON_WRONG "Wrong"
#define D_JSON_WRONG_PARAMETERS "Wrong parameters"
@ -187,6 +189,7 @@
#define D_CMND_FREQUENCY_RESOLUTION "FreqRes"
#define D_CMND_CURRENT_RESOLUTION "AmpRes"
#define D_CMND_ENERGY_RESOLUTION "EnergyRes"
#define D_CMND_WEIGHT_RESOLUTION "WeightRes"
#define D_CMND_MODULE "Module"
#define D_CMND_MODULES "Modules"
#define D_CMND_GPIO "GPIO"
@ -277,6 +280,7 @@
#define D_JSON_WITH_IP_ADDRESS "with IP address"
#define D_CMND_WEBPASSWORD "WebPassword"
#define D_CMND_WEBLOG "WebLog"
#define D_CMND_WEBREFRESH "WebRefresh"
#define D_CMND_WEBSEND "WebSend"
#define D_CMND_EMULATION "Emulation"
@ -317,6 +321,7 @@
#define D_CMND_LEDTABLE "LedTable"
#define D_CMND_FADE "Fade"
#define D_CMND_PIXELS "Pixels"
#define D_CMND_RGBWWTABLE "RGBWWTable"
#define D_CMND_ROTATION "Rotation"
#define D_CMND_SCHEME "Scheme"
#define D_CMND_SPEED "Speed"
@ -534,7 +539,6 @@ const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION;
const char S_CONFIGURE_MODULE[] PROGMEM = D_CONFIGURE_MODULE;
const char S_CONFIGURE_WIFI[] PROGMEM = D_CONFIGURE_WIFI;
const char S_NO_NETWORKS_FOUND[] PROGMEM = D_NO_NETWORKS_FOUND;
const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT;
const char S_CONFIGURE_LOGGING[] PROGMEM = D_CONFIGURE_LOGGING;
const char S_CONFIGURE_OTHER[] PROGMEM = D_CONFIGURE_OTHER;
const char S_SAVE_CONFIGURATION[] PROGMEM = D_SAVE_CONFIGURATION;

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV мощност"
#define D_VERSION "Версия"
#define D_VOLTAGE "Напрежение"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Топла"
#define D_WEB_SERVER "Уеб сървър"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Жироскоп - ос Y"
#define D_GZ_AXIS "Жироскоп - ос Z"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "Няма"
#define D_SENSOR_DHT11 "DHT11"
@ -496,12 +503,15 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOOHM "kΩ"
#define D_UNIT_KILOWATTHOUR "kWh"

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
* Updated until v6.1.1c
* Updated until v6.2.1.14
\*********************************************************************/
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -124,9 +124,9 @@
#define D_PORT "Port"
#define D_POWER_FACTOR "Účiník"
#define D_POWERUSAGE "Příkon"
#define D_POWERUSAGE_ACTIVE "Active Power"
#define D_POWERUSAGE_APPARENT "Apparent Power"
#define D_POWERUSAGE_REACTIVE "Reactive Power"
#define D_POWERUSAGE_ACTIVE "Činný příkon"
#define D_POWERUSAGE_APPARENT "Zdánlivý příkon"
#define D_POWERUSAGE_REACTIVE "Jalový příkon"
#define D_PRESSURE "Tlak"
#define D_PRESSUREATSEALEVEL "Tlak na hladině moře"
#define D_PROGRAM_FLASH_SIZE "Velikost paměti flash"
@ -163,17 +163,18 @@
#define D_USER "Uživatel"
#define D_UTC_TIME "UTC"
#define D_UV_INDEX "UV Index"
#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"
#define D_UV_INDEX_1 "Nízký"
#define D_UV_INDEX_2 "Střední"
#define D_UV_INDEX_3 "Vysoký"
#define D_UV_INDEX_4 "Nebezpečný"
#define D_UV_INDEX_5 "Popál1/2"
#define D_UV_INDEX_6 "Popál3"
#define D_UV_INDEX_7 "MimoRozsah"
#define D_UV_LEVEL "úroveň UV"
#define D_UV_POWER "UV Power"
#define D_VERSION "Verze"
#define D_VOLTAGE "Napětí"
#define D_WEIGHT "Hmotnost"
#define D_WARMLIGHT "Teplé světlo"
#define D_WEB_SERVER "Web Server"
@ -332,10 +333,10 @@
#define D_UPLOAD_ERR_7 "Nahrávání přerušeno"
#define D_UPLOAD_ERR_8 "Špatný soubor"
#define D_UPLOAD_ERR_9 "Soubor je příliš velký"
#define D_UPLOAD_ERR_10 "Failed to init RF chip"
#define D_UPLOAD_ERR_11 "Failed to erase RF chip"
#define D_UPLOAD_ERR_12 "Failed to write to RF chip"
#define D_UPLOAD_ERR_13 "Failed to decode RF firmware"
#define D_UPLOAD_ERR_10 "Chyba inicializace RF chipu"
#define D_UPLOAD_ERR_11 "Chyba smazání RF chipu"
#define D_UPLOAD_ERR_12 "Chyba při zápisu do RF chipu"
#define D_UPLOAD_ERR_13 "Chyba dekódování RF firmwaru"
#define D_UPLOAD_ERROR_CODE "Chyba nahrávání"
#define D_ENTER_COMMAND "Vlož příkaz"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro osa-Y"
#define D_GZ_AXIS "Gyro osa-Z"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Odstraňte zátěž"
#define D_HX_CAL_REFERENCE "Vložte referenční zátěž"
#define D_HX_CAL_DONE "Zkalibrováno"
#define D_HX_CAL_FAIL "Chyba kalibrace"
// sonoff_template.h
#define D_SENSOR_NONE "Není"
#define D_SENSOR_DHT11 "DHT11"
@ -496,12 +503,15 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "hod"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"

View File

@ -124,9 +124,9 @@
#define D_PORT "Port"
#define D_POWER_FACTOR "Leistungsfaktor"
#define D_POWERUSAGE "Leistung"
#define D_POWERUSAGE_ACTIVE "Active Power"
#define D_POWERUSAGE_APPARENT "Apparent Power"
#define D_POWERUSAGE_REACTIVE "Reactive Power"
#define D_POWERUSAGE_ACTIVE "Wirkleistung"
#define D_POWERUSAGE_APPARENT "Scheinleistung"
#define D_POWERUSAGE_REACTIVE "Blindleistung"
#define D_PRESSURE "Luftdruck"
#define D_PRESSUREATSEALEVEL "Luftdruck auf Meereshöhe"
#define D_PROGRAM_FLASH_SIZE "Ges. Flash Speicher"
@ -174,6 +174,7 @@
#define D_UV_POWER "UV Intensität"
#define D_VERSION "Version"
#define D_VOLTAGE "Spannung"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "warm"
#define D_WEB_SERVER "Web-Server"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyroskop Y-Achse"
#define D_GZ_AXIS "Gyroskop Z-Achse"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Wägegut entfernen"
#define D_HX_CAL_REFERENCE "Referenzgewicht auflegen"
#define D_HX_CAL_DONE "kalibriert"
#define D_HX_CAL_FAIL "Kalibrierung fehlgeschlagen"
// sonoff_template.h
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Έκδοση"
#define D_VOLTAGE "Τάση"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Ζεστό"
#define D_WEB_SERVER "Web διακομιστής"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "Κανένας"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -28,11 +28,11 @@
* 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
* Updated until v6.2.1.11
\*********************************************************************/
//#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,11 +169,12 @@
#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"
#define D_VOLTAGE "Voltage"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Warm"
#define D_WEB_SERVER "Web Server"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
@ -496,12 +503,16 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"
@ -522,7 +533,6 @@
#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

View File

@ -28,7 +28,7 @@
* Use online command StateText to translate ON, OFF, HOLD and TOGGLE.
* Use online command Prefix to translate cmnd, stat and tele.
*
* Updated until v6.2.0.1
* Updated until v6.2.1.11
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Versión"
#define D_VOLTAGE "Tensión"
#define D_WEIGHT "Peso"
#define D_WARMLIGHT "Cálida"
#define D_WEB_SERVER "Servidor Web"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remover Peso"
#define D_HX_CAL_REFERENCE "Poner Peso de Referencia"
#define D_HX_CAL_DONE "Calibrado"
#define D_HX_CAL_FAIL "Falló Calibración"
// sonoff_template.h
#define D_SENSOR_NONE "Ninguno"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "Puissance UV"
#define D_VERSION "Version"
#define D_VOLTAGE "Tension"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Chaud"
#define D_WEB_SERVER "Serveur web"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Axe-Y"
#define D_GZ_AXIS "Gyro Axe-Z"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "Aucun"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kΩ"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

563
sonoff/language/he-HE.h Normal file
View File

@ -0,0 +1,563 @@
/*
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_WEIGHT "Weight"
#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"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// 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"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#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_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_

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Verzió"
#define D_VOLTAGE "Feszültség"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Meleg"
#define D_WEB_SERVER "Web Szerver"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "Nincs"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "ó"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Versione"
#define D_VOLTAGE "Tensione"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Calda"
#define D_WEB_SERVER "Web Server"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "Nessuno"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Versie"
#define D_VOLTAGE "Spanning"
#define D_WEIGHT "Gewicht"
#define D_WARMLIGHT "Warm"
#define D_WEB_SERVER "Webserver"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Verwijder gewicht"
#define D_HX_CAL_REFERENCE "Plaats ijkgewicht"
#define D_HX_CAL_DONE "Ge-ijkt"
#define D_HX_CAL_FAIL "Ijken is mislukt"
// sonoff_template.h
#define D_SENSOR_NONE "Geen"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "h"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Wersja"
#define D_VOLTAGE "Napięcie"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Nagrzanie"
#define D_WEB_SERVER "Web Server"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "Brak"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Godz"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Versão"
#define D_VOLTAGE "Voltagem"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Luz quente"
#define D_WEB_SERVER "Servidor WEB"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "Nenhum"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "H"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Versão"
#define D_VOLTAGE "Voltagem"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Luz Quente"
#define D_WEB_SERVER "servidor WEB"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "Nenhum"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Версия"
#define D_VOLTAGE "Напряжение"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Тепло"
#define D_WEB_SERVER "Web сервер"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "-нет-"
#define D_SENSOR_DHT11 "DHT11"
@ -496,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "А"
@ -503,6 +512,7 @@
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_HOUR "Ч"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "кОм"
#define D_UNIT_KILOWATTHOUR "кВт"
#define D_UNIT_LUX "лк"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Versiyon"
#define D_VOLTAGE "Voltaj"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Sıcak"
#define D_WEB_SERVER "Web Sunucusu"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
@ -483,7 +490,6 @@
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
#define D_SENSOR_SDS0X1 "SDS0X1"
#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx"
#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx"
#define D_SENSOR_SBR_RX "SerBr Rx"
@ -497,12 +503,15 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "A"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HOUR "Hr"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "kOhm"
#define D_UNIT_KILOWATTHOUR "kWh"
#define D_UNIT_LUX "lx"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "Версія"
#define D_VOLTAGE "Напруга"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "Тепло"
#define D_WEB_SERVER "Web сервер"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "-відсутньо-"
#define D_SENSOR_DHT11 "DHT11"
@ -483,7 +490,6 @@
#define D_SENSOR_SPI_DC "SPI DC"
#define D_SENSOR_BACKLIGHT "BkLight"
#define D_SENSOR_PMS5003 "PMS5003"
#define D_SENSOR_SDS0X1 "SDS0X1"
#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx"
#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx"
#define D_SENSOR_SBR_RX "SerBr Rx"
@ -497,6 +503,8 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "А"
@ -504,6 +512,7 @@
#define D_UNIT_HERTZ "Гц"
#define D_UNIT_HOUR "Г"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "кОм"
#define D_UNIT_KILOWATTHOUR "кВт"
#define D_UNIT_LUX "лк"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "版本"
#define D_VOLTAGE "电压"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "暖"
#define D_WEB_SERVER "Web Server"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "无"
#define D_SENSOR_DHT11 "DHT11"
@ -496,12 +503,15 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "安"
#define D_UNIT_CENTIMETER "厘米"
#define D_UNIT_HOUR "时"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "千欧"
#define D_UNIT_KILOWATTHOUR "千瓦时"
#define D_UNIT_LUX "勒克斯"

View File

@ -174,6 +174,7 @@
#define D_UV_POWER "UV Power"
#define D_VERSION "版本"
#define D_VOLTAGE "電壓"
#define D_WEIGHT "Weight"
#define D_WARMLIGHT "暖"
#define D_WEB_SERVER "Web Server"
@ -455,6 +456,12 @@
#define D_GY_AXIS "Gyro Y-Axis"
#define D_GZ_AXIS "Gyro Z-Axis"
// xsns_34_hx711.ino
#define D_HX_CAL_REMOVE "Remove weigth"
#define D_HX_CAL_REFERENCE "Load reference weigth"
#define D_HX_CAL_DONE "Calibrated"
#define D_HX_CAL_FAIL "Calibration failed"
// sonoff_template.h
#define D_SENSOR_NONE "None"
#define D_SENSOR_DHT11 "DHT11"
@ -496,13 +503,16 @@
#define D_SENSOR_TM1638_CLK "TM16 CLK"
#define D_SENSOR_TM1638_DIO "TM16 DIO"
#define D_SENSOR_TM1638_STB "TM16 STB"
#define D_SENSOR_HX711_SCK "HX711 SCK"
#define D_SENSOR_HX711_DAT "HX711 DAT"
// Units
#define D_UNIT_AMPERE "安"
#define D_UNIT_CENTIMETER "cm"
#define D_UNIT_HERTZ "Hz"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_HOUR "時"
#define D_UNIT_INCREMENTS "inc"
#define D_UNIT_KILOGRAM "kg"
#define D_UNIT_KILOOHM "千歐"
#define D_UNIT_KILOWATTHOUR "千瓦時"
#define D_UNIT_LUX "勒克斯"

View File

@ -110,8 +110,7 @@ typedef union {
uint32_t spare06 : 1;
uint32_t spare07 : 1;
uint32_t spare08 : 1;
uint32_t spare09 : 1;
uint32_t spare10 : 1;
uint32_t weight_resolution : 2;
uint32_t frequency_resolution : 2;
uint32_t axis_resolution : 2;
uint32_t current_resolution : 2;
@ -321,18 +320,20 @@ struct SYSCFG {
byte free_717[1]; // 717
uint16_t mcp230xx_int_timer; // 718
uint8_t rgbwwTable[5]; // 71A
byte free_71A[174]; // 71A
byte free_71F[93]; // 71F
char custom1[32]; // 77C Custom
char custom2[32]; // 79C Custom
uint16_t weight_item; // 7BC Weight of one item in gram * 10
uint16_t weight_max; // 7BE Total max weight in kilogram
unsigned long weight_reference; // 7C0 Reference weight in gram
unsigned long weight_calibration; // 7C4
unsigned long energy_frequency_calibration; // 7C8
byte free_7CC[2]; // 7CC
uint16_t web_refresh; // 7CC
char mems[MAX_RULE_MEMS][10]; // 7CE
// 800 Full - no more free locations
char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b
// E00 - FFF free locations
} Settings;

View File

@ -624,6 +624,10 @@ void SettingsDefaultSet2()
Settings.button_debounce = KEY_DEBOUNCE_TIME;
Settings.switch_debounce = SWITCH_DEBOUNCE_TIME;
for (byte j = 0; j < 5; j++) {
Settings.rgbwwTable[j] = 255;
}
}
/********************************************************************************************/
@ -827,6 +831,11 @@ void SettingsDelta()
Settings.button_debounce = KEY_DEBOUNCE_TIME;
Settings.switch_debounce = SWITCH_DEBOUNCE_TIME;
}
if (Settings.version < 0x0602010A) {
for (byte j = 0; j < 5; j++) {
Settings.rgbwwTable[j] = 255;
}
}
Settings.version = VERSION;
SettingsSave(1);

View File

@ -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
\*********************************************************************************************/
@ -75,6 +80,10 @@ typedef unsigned long power_t; // Power (Relay) type
//#define PWM_FREQ 1000 // 100..1000 Hz led refresh
//#define PWM_FREQ 910 // 100..1000 Hz led refresh (iTead value)
#define PWM_FREQ 880 // 100..1000 Hz led refresh (BN-SZ01 value)
#define PWM_MAX 4000 // [PWM_MAX] Maximum frequency - Default: 4000
#define PWM_MIN 100 // [PWM_MIN] Minimum frequency - Default: 100
// For Dimmers use double of your mains AC frequecy (100 for 50Hz and 120 for 60Hz)
// For Controlling Servos use 50 and also set PWM_FREQ as 50 (DO NOT USE THESE VALUES FOR DIMMERS)
#define DEFAULT_POWER_DELTA 80 // Power change percentage
#define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power
@ -135,8 +144,9 @@ typedef unsigned long power_t; // Power (Relay) type
#define NEO_GRBW 6 // Neopixel GRBW leds
#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_TASMOTAMQTT 2 // Mqtt TasmotaMqtt library based on esp-mqtt-arduino - soon obsolete
#define MQTT_ESPMQTTARDUINO 3 // Mqtt esp-mqtt-arduino library by Ingo Randolf - obsolete but define is present for debugging purposes
#define MQTT_ARDUINOMQTT 4 // Mqtt arduino-mqtt library by Joel Gaehwiler (https://github.com/256dpi/arduino-mqtt)
// Sunrise and Sunset DawnType
#define DAWN_NORMAL -0.8333
@ -204,7 +214,7 @@ enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MA
enum XsnsFunctions {FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD,
FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR,
FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM};
FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON, FUNC_WEB_ADD_HANDLER};
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };

View File

@ -77,7 +77,7 @@
enum TasmotaCommands {
CMND_BACKLOG, CMND_DELAY, CMND_POWER, CMND_FANSPEED, CMND_STATUS, CMND_STATE, CMND_POWERONSTATE, CMND_PULSETIME,
CMND_BLINKTIME, CMND_BLINKCOUNT, CMND_SENSOR, CMND_SAVEDATA, CMND_SETOPTION, CMND_TEMPERATURE_RESOLUTION, CMND_HUMIDITY_RESOLUTION,
CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_FREQUENCY_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION,
CMND_PRESSURE_RESOLUTION, CMND_POWER_RESOLUTION, CMND_VOLTAGE_RESOLUTION, CMND_FREQUENCY_RESOLUTION, CMND_CURRENT_RESOLUTION, CMND_ENERGY_RESOLUTION, CMND_WEIGHT_RESOLUTION,
CMND_MODULE, CMND_MODULES, CMND_GPIO, CMND_GPIOS, CMND_PWM, CMND_PWMFREQUENCY, CMND_PWMRANGE, CMND_COUNTER, CMND_COUNTERTYPE,
CMND_COUNTERDEBOUNCE, CMND_BUTTONDEBOUNCE, CMND_SWITCHDEBOUNCE, CMND_SLEEP, CMND_UPGRADE, CMND_UPLOAD, CMND_OTAURL, CMND_SERIALLOG, CMND_SYSLOG,
CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME,
@ -87,7 +87,7 @@ enum TasmotaCommands {
const char kTasmotaCommands[] PROGMEM =
D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_FANSPEED "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|"
D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SENSOR "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|"
D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_FREQUENCY_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|"
D_CMND_PRESSURE_RESOLUTION "|" D_CMND_POWER_RESOLUTION "|" D_CMND_VOLTAGE_RESOLUTION "|" D_CMND_FREQUENCY_RESOLUTION "|" D_CMND_CURRENT_RESOLUTION "|" D_CMND_ENERGY_RESOLUTION "|" D_CMND_WEIGHT_RESOLUTION "|"
D_CMND_MODULE "|" D_CMND_MODULES "|" D_CMND_GPIO "|" D_CMND_GPIOS "|" D_CMND_PWM "|" D_CMND_PWMFREQUENCY "|" D_CMND_PWMRANGE "|" D_CMND_COUNTER "|" D_CMND_COUNTERTYPE "|"
D_CMND_COUNTERDEBOUNCE "|" D_CMND_BUTTONDEBOUNCE "|" D_CMND_SWITCHDEBOUNCE "|" D_CMND_SLEEP "|" D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_SYSLOG "|"
D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|"
@ -296,20 +296,23 @@ char* GetStateText(byte state)
/********************************************************************************************/
void SetLatchingRelay(power_t power, uint8_t state)
void SetLatchingRelay(power_t lpower, uint8_t state)
{
power &= 1;
if (2 == state) { // Reset relay
state = 0;
latching_power = power;
latching_relay_pulse = 0;
// power xx00 - toggle REL1 (Off) and REL3 (Off) - device 1 Off, device 2 Off
// power xx01 - toggle REL2 (On) and REL3 (Off) - device 1 On, device 2 Off
// power xx10 - toggle REL1 (Off) and REL4 (On) - device 1 Off, device 2 On
// power xx11 - toggle REL2 (On) and REL4 (On) - device 1 On, device 2 On
if (state && !latching_relay_pulse) { // Set latching relay to power if previous pulse has finished
latching_power = lpower;
latching_relay_pulse = 2; // max 200mS (initiated by stateloop())
}
else if (state && !latching_relay_pulse) { // Set port power to On
latching_power = power;
latching_relay_pulse = 2; // max 200mS (initiated by stateloop())
}
if (pin[GPIO_REL1 +latching_power] < 99) {
digitalWrite(pin[GPIO_REL1 +latching_power], bitRead(rel_inverted, latching_power) ? !state : state);
for (byte i = 0; i < devices_present; i++) {
uint8_t port = (i << 1) + ((latching_power >> i) &1);
if (pin[GPIO_REL1 +port] < 99) {
digitalWrite(pin[GPIO_REL1 +port], bitRead(rel_inverted, port) ? !state : state);
}
}
}
@ -818,6 +821,12 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.energy_resolution);
}
else if (CMND_WEIGHT_RESOLUTION == command_code) {
if ((payload >= 0) && (payload <= 3)) {
Settings.flag2.weight_resolution = payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.flag2.weight_resolution);
}
else if (CMND_MODULE == command_code) {
if ((payload > 0) && (payload <= MAXMODULE)) {
payload--;
@ -911,7 +920,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
}
else if (CMND_PWMFREQUENCY == command_code) {
if ((1 == payload) || ((payload >= 100) && (payload <= 4000))) {
if ((1 == payload) || ((payload >= PWM_MIN) && (payload <= PWM_MAX))) {
Settings.pwm_frequency = (1 == payload) ? PWM_FREQ : payload;
analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
}
@ -2028,7 +2037,12 @@ void Every250mSeconds()
#endif // BE_MINIMAL
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "%s"), mqtt_data);
AddLog(LOG_LEVEL_DEBUG);
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(mqtt_data));
#else
// If using core stage or 2.5.0+ the syntax has changed
ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(EspClient, mqtt_data));
#endif
if (!ota_result) {
#ifndef BE_MINIMAL
int ota_error = ESPhttpUpdate.getLastError();
@ -2303,9 +2317,11 @@ void GpioSwitchPinMode(uint8_t index)
if (pin[GPIO_SWT1 +index] < 99) {
// pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : bitRead(switch_no_pullup, index) ? INPUT : INPUT_PULLUP);
uint8_t no_pullup = 0;
if (bitRead(switch_no_pullup, index)) {
no_pullup = (Settings.switchmode[index] < PUSHBUTTON);
uint8_t no_pullup = bitRead(switch_no_pullup, index);
if (no_pullup) {
if (SHELLY2 == Settings.module) {
no_pullup = (Settings.switchmode[index] < PUSHBUTTON);
}
}
pinMode(pin[GPIO_SWT1 +index], (16 == pin[GPIO_SWT1 +index]) ? INPUT_PULLDOWN_16 : (no_pullup) ? INPUT : INPUT_PULLUP);
}
@ -2453,6 +2469,10 @@ void GpioInit()
if (pin[GPIO_REL1 +i] < 99) {
pinMode(pin[GPIO_REL1 +i], OUTPUT);
devices_present++;
if (EXS_RELAY == Settings.module) {
digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0);
if (i &1) { devices_present--; }
}
}
}
}
@ -2493,10 +2513,6 @@ void GpioInit()
}
}
if (EXS_RELAY == Settings.module) {
SetLatchingRelay(0,2);
SetLatchingRelay(1,2);
}
SetLedPower(Settings.ledstate &8);
XdrvCall(FUNC_PRE_INIT);

View File

@ -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

View File

@ -125,7 +125,9 @@ enum UserSelectablePins {
GPIO_PZEM2_TX, // PZEM-003,014,016,017 Serial interface
GPIO_PZEM2_RX, // PZEM-003,014,016,017 Serial interface
GPIO_MP3_DFR562, // RB-DFR-562, DFPlayer Mini MP3 Player
GPIO_SDS0X1_TX, // Nova Fitness SDS011 Serial interface
GPIO_SDS0X1_TX, // Nova Fitness SDS011 Serial interface
GPIO_HX711_SCK, // HX711 Load Cell clock
GPIO_HX711_DAT, // HX711 Load Cell data
GPIO_SENSOR_END };
// Programmer selectable GPIO functionality offset by user selectable GPIOs
@ -135,9 +137,11 @@ enum ProgramSelectablePins {
GPIO_SPI_MISO, // SPI MISO library fixed pin GPIO12
GPIO_SPI_MOSI, // SPI MOSI library fixed pin GPIO13
GPIO_SPI_CLK, // SPI Clk library fixed pin GPIO14
GPIO_HLW_SEL, // HLW8012 Sel output (Sonoff Pow)
GPIO_HLW_CF1, // HLW8012 CF1 voltage / current (Sonoff Pow)
GPIO_HLW_CF, // HLW8012 CF power (Sonoff Pow)
GPIO_NRG_SEL, // HLW8012/HLJ-01 Sel output (1 = Voltage)
GPIO_NRG_SEL_INV, // HLW8012/HLJ-01 Sel output (0 = Voltage)
GPIO_NRG_CF1, // HLW8012/HLJ-01 CF1 voltage / current
GPIO_HLW_CF, // HLW8012 CF power
GPIO_HJL_CF, // HJL-01/BL0937 CF power
GPIO_ADC0, // ADC
GPIO_DI, // my92x1 PWM input
GPIO_DCKI, // my92x1 CLK input
@ -177,7 +181,8 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_BUTTON "1n|" D_SENSOR_BUTTON "2n|" D_SENSOR_BUTTON "3n|" D_SENSOR_BUTTON "4n|"
D_SENSOR_COUNTER "1n|" D_SENSOR_COUNTER "2n|" D_SENSOR_COUNTER "3n|" D_SENSOR_COUNTER "4n|"
D_SENSOR_PZEM_TX "|" D_SENSOR_PZEM_RX "|"
D_SENSOR_DFR562 "|" D_SENSOR_SDS0X1_TX;
D_SENSOR_DFR562 "|" D_SENSOR_SDS0X1_TX "|"
D_SENSOR_HX711_SCK "|" D_SENSOR_HX711_DAT;
/********************************************************************************************/
@ -232,6 +237,10 @@ enum SupportedModules {
SHELLY2,
PHILIPS,
NEO_COOLCAM,
ESP_SWITCH,
OBI,
TECKIN,
APLIC_WDP303075,
MAXMODULE };
/********************************************************************************************/
@ -334,6 +343,8 @@ const uint8_t kGpioNiceList[GPIO_SENSOR_END] PROGMEM = {
GPIO_TM16CLK, // TM1638 Clock
GPIO_TM16DIO, // TM1638 Data I/O
GPIO_TM16STB, // TM1638 Strobe
GPIO_HX711_SCK, // HX711 Load Cell clock
GPIO_HX711_DAT, // HX711 Load Cell data
GPIO_SBR_TX, // Serial Bridge Serial interface
GPIO_SBR_RX, // Serial Bridge Serial interface
GPIO_MHZ_TXD, // MH-Z19 Serial interface
@ -355,31 +366,31 @@ const uint8_t kGpioNiceList[GPIO_SENSOR_END] PROGMEM = {
};
const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
SONOFF_BASIC,
SONOFF_BASIC, // Sonoff Relay Devices
SONOFF_RF,
SONOFF_TH,
SONOFF_DUAL,
SONOFF_DUAL_R2,
SONOFF_POW,
SONOFF_POW_R2,
SONOFF_S31,
SONOFF_4CH,
SONOFF_4CHPRO,
SONOFF_SV,
SONOFF_DEV,
SONOFF_S2X,
SLAMPHER,
SONOFF_TOUCH,
SONOFF_S31, // Sonoff Socket Relay Devices with Energy Monitoring
SONOFF_S2X, // Sonoff Socket Relay Devices
SONOFF_TOUCH, // Sonoff Switch Devices
SONOFF_T11,
SONOFF_T12,
SONOFF_T13,
SONOFF_SC,
SONOFF_B1,
SONOFF_LED,
SONOFF_LED, // Sonoff Light Devices
SONOFF_BN,
SONOFF_IFAN02,
SONOFF_BRIDGE,
CH1,
SONOFF_B1, // Sonoff Light Bulbs
SLAMPHER,
SONOFF_SC, // Sonoff Environmemtal Sensor
SONOFF_IFAN02, // Sonoff Fan
SONOFF_BRIDGE, // Sonoff Bridge
SONOFF_SV, // Sonoff Development Devices
SONOFF_DEV,
CH1, // Relay Devices
CH4,
MOTOR,
ELECTRODRAGON,
@ -390,9 +401,13 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
WION,
SHELLY1,
SHELLY2,
BLITZWOLF_BWSHP2,
NEO_COOLCAM,
H801,
BLITZWOLF_BWSHP2, // Socket Relay Devices with Energy Monitoring
TECKIN,
APLIC_WDP303075,
NEO_COOLCAM, // Socket Relay Devices
OBI,
ESP_SWITCH, // Switch Devices
H801, // Light Devices
MAGICHOME,
ARILUX_LC01,
ARILUX_LC06,
@ -400,9 +415,9 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
ZENGGE_ZF_WF017,
HUAFAN_SS,
KMC_70011,
AILIGHT,
AILIGHT, // Light Bulbs
PHILIPS,
WITTY,
WITTY, // Development Devices
WEMOS
};
@ -484,10 +499,10 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
{ "Sonoff Pow", // Sonoff Pow (ESP8266 - HLW8012)
GPIO_KEY1, // GPIO00 Button
0, 0, 0, 0,
GPIO_HLW_SEL, // GPIO05 HLW8012 Sel output
GPIO_NRG_SEL, // GPIO05 HLW8012 Sel output (1 = Voltage)
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
GPIO_HLW_CF1, // GPIO13 HLW8012 CF1 voltage / current
GPIO_NRG_CF1, // GPIO13 HLW8012 CF1 voltage / current
GPIO_HLW_CF, // GPIO14 HLW8012 CF power
GPIO_LED1, // GPIO15 Blue Led (0 = On, 1 = Off)
0, 0
@ -598,21 +613,22 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1, // GPIO16 Green/Blue Led (1 = On, 0 = Off)
GPIO_ADC0 // ADC0 A0 Analog input
},
{ "EXS Relay", // Latching relay (ESP8266)
{ "EXS Relay(s)", // ES-Store Latching relay(s) (ESP8266)
// https://ex-store.de/ESP8266-WiFi-Relay-V31
// Module Pin 1 VCC 3V3, Module Pin 6 GND
GPIO_KEY1, // GPIO00 Module Pin 8 - Button (firmware flash)
GPIO_USER, // GPIO01 Module Pin 2 = UART0_TXD
GPIO_USER, // GPIO02 Module Pin 7
GPIO_USER, // GPIO03 Module Pin 3 = UART0_RXD
GPIO_USER, // GPIO04 Module Pin 10
GPIO_USER, // GPIO05 Module Pin 9
// V3.1 Module Pin 1 VCC 3V3, Module Pin 6 GND
// https://ex-store.de/2-Kanal-WiFi-WLan-Relay-V5-Blackline-fuer-Unterputzmontage
GPIO_USER, // GPIO00 V3.1 Module Pin 8 - V5.0 Module Pin 4
GPIO_USER, // GPIO01 UART0_TXD V3.1 Module Pin 2 - V5.0 Module Pin 3
GPIO_USER, // GPIO02 V3.1 Module Pin 7
GPIO_USER, // GPIO03 UART0_RXD V3.1 Module Pin 3
GPIO_USER, // GPIO04 V3.1 Module Pin 10 - V5.0 Module Pin 2
GPIO_USER, // GPIO05 V3.1 Module Pin 9 - V5.0 Module Pin 1
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_REL1, // GPIO12 Relay1 ( 1 = Off)
GPIO_REL2, // GPIO13 Relay1 ( 1 = On)
GPIO_USER, // GPIO14 Module Pin 5
0,
GPIO_USER, // GPIO16 Module Pin 4
GPIO_USER, // GPIO14 V3.1 Module Pin 5 - V5.0 GPIO_REL3_INV Relay2 ( 1 = Off)
GPIO_LED1, // GPIO15 V5.0 LED1
GPIO_USER, // GPIO16 V3.1 Module Pin 4 - V5.0 GPIO_REL4_INV Relay2 ( 1 = On)
0
},
{ "WiOn", // Indoor Tap (ESP8266)
@ -720,8 +736,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_KEY1, // GPIO4 Button
GPIO_REL1_INV, // GPIO5 Relay (0 = On, 1 = Off)
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_HLW_CF1, // GPIO12 HLW8012 CF1 voltage / current
GPIO_HLW_SEL, // GPIO13 HLW8012 Sel output
GPIO_NRG_CF1, // GPIO12 HLW8012 CF1 voltage / current
GPIO_NRG_SEL, // GPIO13 HLW8012 Sel output (1 = Voltage)
GPIO_HLW_CF, // GPIO14 HLW8012 CF power
0, 0, 0
},
@ -855,35 +871,19 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
0, 0, 0, 0, 0, 0, // Flash connection
0, 0, 0, 0, 0
},
/*
{ "MagicHome", // Magic Home (aka Flux-light) (ESP8266)
// https://www.aliexpress.com/item/Magic-Home-Mini-RGB-RGBW-Wifi-Controller-For-Led-Strip-Panel-light-Timing-Function-16million-colors/32686853650.html
0,
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
GPIO_LED1_INV, // GPIO02 Blue onboard LED
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
GPIO_USER, // GPIO04 IR receiver (optional)
GPIO_PWM2, // GPIO05 RGB LED Green
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_PWM3, // GPIO12 RGB LED Blue
GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White)
GPIO_PWM1, // GPIO14 RGB LED Red
0, 0, 0
},
*/
{ "MagicHome", // Magic Home (aka Flux-light) (ESP8266) and Arilux LC10 (ESP8285)
// https://www.aliexpress.com/item/Magic-Home-Mini-RGB-RGBW-Wifi-Controller-For-Led-Strip-Panel-light-Timing-Function-16million-colors/32686853650.html
0,
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
GPIO_LED1_INV, // GPIO02 Blue onboard LED
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
GPIO_ARIRFRCV, // GPIO04 IR or RF receiver (optional)
GPIO_ARIRFRCV, // GPIO04 IR or RF receiver (optional) (Arilux LC10)
GPIO_PWM2, // GPIO05 RGB LED Green
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_PWM3, // GPIO12 RGB LED Blue
GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White as used on Arilux LC10)
GPIO_PWM1, // GPIO14 RGB LED Red
GPIO_LED2_INV, // GPIO15 RF receiver control
GPIO_LED2_INV, // GPIO15 RF receiver control (Arilux LC10)
0, 0
},
{ "Luani HVIO", // ESP8266_HVIO
@ -906,10 +906,10 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
// https://www.amazon.com/KMC-Timing-Monitoring-Network-125V-240V/dp/B06XRX2GTQ
GPIO_KEY1, // GPIO00 Button
0, 0, 0,
GPIO_HLW_CF, // GPIO04 HLW8012 CF
GPIO_HLW_CF1, // GPIO05 HLW8012 CF1
GPIO_HLW_CF, // GPIO04 HLW8012 CF power
GPIO_NRG_CF1, // GPIO05 HLW8012 CF1 voltage / current
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_HLW_SEL, // GPIO12 HLW8012 SEL
GPIO_NRG_SEL, // GPIO12 HLW8012 SEL (1 = Voltage)
GPIO_LED1_INV, // GPIO13 Green Led
GPIO_REL1, // GPIO14 Relay
0, 0, 0
@ -1037,11 +1037,11 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off)
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
0,
GPIO_HLW_CF, // GPIO05 BL0937 or HJL-01 CF power
GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_HLW_SEL, // GPIO12 BL0937 or HJL-01 Sel output
GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage)
GPIO_KEY1, // GPIO13 Button
GPIO_HLW_CF1, // GPIO14 BL0937 or HJL-01 CF1 voltage / current
GPIO_NRG_CF1, // GPIO14 BL0937 or HJL-01 CF1 current / voltage
GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On)
0, 0
},
@ -1077,18 +1077,82 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
{ "Neo Coolcam", // Neo Coolcam (ESP8266)
// https://www.banggood.com/NEO-COOLCAM-WiFi-Mini-Smart-Plug-APP-Remote-Control-Timing-Smart-Socket-EU-Plug-p-1288562.html?cur_warehouse=CN
0, 0, 0, 0,
GPIO_LED1_INV, // GPIO13 Red Led (0 = On, 1 = Off)
GPIO_LED1_INV, // GPIO04 Red Led (0 = On, 1 = Off)
0,
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
GPIO_KEY1, // GPIO13 Button
0, 0, 0, 0
},
{ "ESP Switch", // Michael Haustein 4 channel wall switch (ESP07 = ESP8266)
// Use rules for further actions like - rule on power1#state do publish cmnd/other_device/power %value% endon
GPIO_KEY2, // GPIO00 Button 2
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
GPIO_REL3_INV, // GPIO02 Yellow Led 3 (0 = On, 1 = Off)
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
GPIO_KEY1, // GPIO04 Button 1
GPIO_REL2_INV, // GPIO05 Red Led 2 (0 = On, 1 = Off)
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_REL4_INV, // GPIO12 Blue Led 4 (0 = On, 1 = Off)
GPIO_KEY4, // GPIO13 Button 4
GPIO_KEY3, // GPIO14 Button 3
GPIO_LED1, // GPIO15 Optional sensor
GPIO_REL1_INV, // GPIO16 Green Led 1 (0 = On, 1 = Off)
},
{ "OBI Socket", // OBI socket (ESP8266) - https://www.obi.de/hausfunksteuerung/wifi-stecker-schuko/p/2291706
0, 0, 0, 0,
GPIO_LED1, // GPIO04 LED on top and in switch button
GPIO_REL1, // GPIO05 Relay 1 (0 = Off, 1 = On)
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_LED2, // GPIO12
0, // GPIO13
GPIO_KEY1, // GPIO14 switch button
0, 0, 0
},
{ "Teckin", // https://www.amazon.de/gp/product/B07D5V139R
0,
GPIO_KEY1, // GPIO01 Serial TXD and Button
0,
GPIO_LED2_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off)
GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power
GPIO_NRG_CF1, // GPIO05 BL0937 or HJL-01 CF1 current / voltage
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage)
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On)
0, 0, 0
},
{ "AplicWDP303075", // Aplic WDP 303075 (ESP8285 - HLW8012 Energy Monitoring)
// https://www.amazon.de/dp/B07CNWVNJ2
0, 0, 0,
GPIO_KEY1, // GPIO03 Button
GPIO_HLW_CF, // GPIO04 HLW8012 CF power
GPIO_NRG_CF1, // GPIO05 HLW8012 CF1 current / voltage
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_NRG_SEL_INV, // GPIO12 HLW8012 CF Sel output (0 = Voltage)
GPIO_LED1_INV, // GPIO13 LED (0 = On, 1 = Off)
GPIO_REL1, // GPIO14 Relay SRU 5VDC SDA (0 = Off, 1 = On )
0, 0, 0
}
};
/*
Optionals
{ "MagicHome", // Magic Home (aka Flux-light) (ESP8266)
// https://www.aliexpress.com/item/Magic-Home-Mini-RGB-RGBW-Wifi-Controller-For-Led-Strip-Panel-light-Timing-Function-16million-colors/32686853650.html
0,
GPIO_USER, // GPIO01 Serial RXD and Optional sensor
GPIO_LED1_INV, // GPIO02 Blue onboard LED
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
GPIO_USER, // GPIO04 IR receiver (optional)
GPIO_PWM2, // GPIO05 RGB LED Green
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_PWM3, // GPIO12 RGB LED Blue
GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White)
GPIO_PWM1, // GPIO14 RGB LED Red
0, 0, 0
},
{ "Arilux LC10", // Arilux LC10 (ESP8285), RGBW + RF
// https://github.com/arendst/Sonoff-Tasmota/wiki/MagicHome-with-ESP8285
// https://www.aliexpress.com/item/DC5-24V-Wireless-WIFI-LED-RGB-Controller-RGBW-Controller-IR-RF-Remote-Control-IOS-Android-for/32827253255.html

View File

@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_
#define VERSION 0x06020109
#define VERSION 0x0602010F
#define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends"

View File

@ -677,6 +677,10 @@ boolean GetUsedInModule(byte val, uint8_t *arr)
if (GPIO_TM16CLK == val) { return true; }
if (GPIO_TM16DIO == val) { return true; }
if (GPIO_TM16STB == val) { return true; }
#endif
#ifndef USE_HX711
if (GPIO_HX711_SCK == val) { return true; }
if (GPIO_HX711_DAT == val) { return true; }
#endif
if ((val >= GPIO_REL1) && (val < GPIO_REL1 + MAX_RELAYS)) {
offset = (GPIO_REL1_INV - GPIO_REL1);
@ -876,7 +880,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 +937,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
/*********************************************************************************************/
@ -1144,6 +1151,12 @@ void GetFeatures()
#ifdef USE_PZEM2
feature_sns2 |= 0x00000200; // xnrg_05_pzem2.ino
#endif
#ifdef USE_DS3231
feature_sns2 |= 0x00000400; // xsns_33_ds3231.ino
#endif
#ifdef USE_HX711
feature_sns2 |= 0x00000400; // xsns_34_hx711.ino
#endif
}
@ -1295,13 +1308,13 @@ void WiFiSetSleepMode()
* See https://github.com/arendst/Sonoff-Tasmota/issues/2559
*/
//#ifdef ARDUINO_ESP8266_RELEASE_2_4_1
// Sleep explanation: https://github.com/esp8266/Arduino/blob/3f0c601cfe81439ce17e9bd5d28994a7ed144482/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp#L255
#if defined(ARDUINO_ESP8266_RELEASE_2_4_1) || defined(ARDUINO_ESP8266_RELEASE_2_4_2)
#else // Enabled in 2.3.0, 2.4.0 and stage
if (sleep) {
WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times
} else {
WiFi.setSleepMode(WIFI_MODEM_SLEEP); // Diable sleep (Esp8288/Arduino core and sdk default)
WiFi.setSleepMode(WIFI_MODEM_SLEEP); // Disable sleep (Esp8288/Arduino core and sdk default)
}
#endif
}
@ -1775,27 +1788,35 @@ int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len
void I2cScan(char *devs, unsigned int devs_len)
{
byte error;
byte address;
// Return error codes defined in twi.h and core_esp8266_si2c.c
// I2C_OK 0
// I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover
// I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond slave clock stretch time
// I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by slave/another_master after n bits
// I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master?
byte error = 0;
byte address = 0;
byte any = 0;
char tstr[10];
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_DEVICES_FOUND_AT));
for (address = 1; address <= 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (0 == error) {
snprintf_P(tstr, sizeof(tstr), PSTR(" 0x%2x"), address);
strncat(devs, tstr, devs_len);
any = 1;
snprintf_P(devs, devs_len, PSTR("%s 0x%02x"), devs, address);
}
else if (4 == error) {
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_UNKNOWN_ERROR_AT " 0x%2x\"}"), address);
else if (error != 2) { // Seems to happen anyway using this scan
any = 2;
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x"), error, address);
break;
}
}
if (any) {
strncat(devs, "\"}", devs_len);
} else {
}
else {
snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}"));
}
}

View File

@ -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
//#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 ---------------------------------
@ -302,9 +304,12 @@
// #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code)
// #define USE_PCA9685 // Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code)
// #define USE_PCA9685_ADDR 0x40 // Enable PCA9685 I2C Address to use (Must be within range 0x40 through 0x47 - set according to your wired setup)
// #define USE_PCA9685_FREQ 50 // Define default PWM frequency in Hz to be used (must be within 24 to 1526) - If other value is used, it will rever to 50Hz
// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code)
// #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code)
// #define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code)
// #define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code)
// #define USE_RTC_ADDR 0x68 // Default I2C address 0x68
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
@ -368,6 +373,7 @@
#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code)
//#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code)
#define USE_HX711 // Add support for HX711 load cell (+1k5 code)
#define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+3k code)

View File

@ -1,5 +1,5 @@
/*
xdrv_02_webserver.ino - webserver for Sonoff-Tasmota
xdrv_01_webserver.ino - webserver for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
@ -25,6 +25,8 @@
* Based on source by AlexT (https://github.com/tzapu)
\*********************************************************************************************/
#define HTTP_REFRESH_TIME 2345 // milliseconds
#ifdef USE_RF_FLASH
uint8_t *efm8bb1_update = NULL;
#endif // USE_RF_FLASH
@ -72,15 +74,18 @@ const char HTTP_HEAD[] PROGMEM =
"};"
"x.open('GET','ay'+a,true);"
"x.send();"
"lt=setTimeout(la,2345);"
"lt=setTimeout(la,{a});" // Settings.web_refresh
"}"
"function lb(p){"
"la('?d='+p);"
"}"
"function lc(p){"
"la('?t='+p);"
"la('?t='+p);" // ?t related to WebGetArg("t", tmp, sizeof(tmp));
"}";
const char HTTP_HEAD_RELOAD[] PROGMEM =
"setTimeout(function(){location.href='.';},4000);";
const char HTTP_HEAD_STYLE[] PROGMEM =
"</script>"
@ -147,7 +152,7 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM =
"x.open('GET','ax?c2='+id+o,true);"
"x.send();"
"}"
"lt=setTimeout(l,2345);"
"lt=setTimeout(l,{a});"
"return false;"
"}"
"</script>";
@ -189,27 +194,11 @@ const char HTTP_BTN_MENU1[] PROGMEM =
"<br/><form action='up' method='get'><button>" D_FIRMWARE_UPGRADE "</button></form>"
"<br/><form action='cs' method='get'><button>" D_CONSOLE "</button></form>";
const char HTTP_BTN_RSTRT[] PROGMEM =
"<br/><form action='rb' method='get' onsubmit='return confirm(\"" D_CONFIRM_RESTART "\");'><button class='button bred'>" D_RESTART "</button></form>";
"<br/><form action='.' method='get' onsubmit='return confirm(\"" D_CONFIRM_RESTART "\");'><button name='rstrt' class='button bred'>" D_RESTART "</button></form>";
const char HTTP_BTN_MENU_MODULE[] PROGMEM =
"<br/><form action='md' method='get'><button>" D_CONFIGURE_MODULE "</button></form>";
#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
const char HTTP_BTN_MENU_TIMER[] PROGMEM =
"<br/><form action='tm' method='get'><button>" D_CONFIGURE_TIMER "</button></form>";
#endif // USE_TIMERS and USE_TIMERS_WEB
const char HTTP_BTN_MENU_WIFI[] PROGMEM =
"<br/><form action='w0' method='get'><button>" D_CONFIGURE_WIFI "</button></form>";
const char HTTP_BTN_MENU_MQTT[] PROGMEM =
"<br/><form action='mq' method='get'><button>" D_CONFIGURE_MQTT "</button></form>"
#ifdef USE_DOMOTICZ
"<br/><form action='dm' method='get'><button>" D_CONFIGURE_DOMOTICZ "</button></form>"
#endif // USE_DOMOTICZ
"";
"<br/><form action='md' method='get'><button>" D_CONFIGURE_MODULE "</button></form>"
"<br/><form action='wi' method='get'><button>" D_CONFIGURE_WIFI "</button></form>";
const char HTTP_BTN_MENU4[] PROGMEM =
#ifdef USE_KNX
#ifdef USE_KNX_WEB_MENU
"<br/><form action='kn' method='get'><button>" D_CONFIGURE_KNX "</button></form>"
#endif // USE_KNX_WEB_MENU
#endif // USE_KNX
"<br/><form action='lg' method='get'><button>" D_CONFIGURE_LOGGING "</button></form>"
"<br/><form action='co' method='get'><button>" D_CONFIGURE_OTHER "</button></form>"
"<br/>"
@ -227,34 +216,21 @@ const char HTTP_FORM_LOGIN[] PROGMEM =
const char HTTP_BTN_CONF[] PROGMEM =
"<br/><br/><form action='cn' method='get'><button>" D_CONFIGURATION "</button></form>";
const char HTTP_FORM_MODULE[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MODULE_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='6,1' hidden>"
"<fieldset><legend><b>&nbsp;" D_MODULE_PARAMETERS "&nbsp;</b></legend><form method='get' action='md'>"
"<br/><b>" D_MODULE_TYPE "</b> ({mt)<br/><select id='g99' name='g99'></select><br/>";
const char HTTP_LNK_ITEM[] PROGMEM =
"<div><a href='#p' onclick='c(this)'>{v}</a>&nbsp;({w})&nbsp<span class='q'>{i} {r}%</span></div>";
const char HTTP_LNK_SCAN[] PROGMEM =
"<div><a href='/w1'>" D_SCAN_FOR_WIFI_NETWORKS "</a></div><br/>";
"<div><a href='/wi?scan='>" D_SCAN_FOR_WIFI_NETWORKS "</a></div><br/>";
const char HTTP_FORM_WIFI[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_WIFI_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='1,1' hidden>"
"<fieldset><legend><b>&nbsp;" D_WIFI_PARAMETERS "&nbsp;</b></legend><form method='get' action='wi'>"
"<br/><b>" D_AP1_SSID "</b> (" STA_SSID1 ")<br/><input id='s1' name='s1' placeholder='" STA_SSID1 "' value='{s1'><br/>"
"<br/><b>" D_AP1_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_AP1_PASSWORD "' value='" D_ASTERIX "'><br/>"
"<br/><b>" D_AP2_SSID "</b> (" STA_SSID2 ")<br/><input id='s2' name='s2' placeholder='" STA_SSID2 "' value='{s2'><br/>"
"<br/><b>" D_AP2_PASSWORD "</b><br/><input id='p2' name='p2' type='password' placeholder='" D_AP2_PASSWORD "' value='" D_ASTERIX "'><br/>"
"<br/><b>" D_HOSTNAME "</b> (" WIFI_HOSTNAME ")<br/><input id='h' name='h' placeholder='" WIFI_HOSTNAME" ' value='{h1'><br/>";
const char HTTP_FORM_MQTT[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MQTT_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='2,1' hidden>"
"<br/><b>" D_HOST "</b> (" MQTT_HOST ")<br/><input id='mh' name='mh' placeholder='" MQTT_HOST" ' value='{m1'><br/>"
"<br/><b>" D_PORT "</b> (" STR(MQTT_PORT) ")<br/><input id='ml' name='ml' placeholder='" STR(MQTT_PORT) "' value='{m2'><br/>"
"<br/><b>" D_CLIENT "</b> ({m0)<br/><input id='mc' name='mc' placeholder='" MQTT_CLIENT_ID "' value='{m3'><br/>"
"<br/><b>" D_USER "</b> (" MQTT_USER ")<br/><input id='mu' name='mu' placeholder='" MQTT_USER "' value='{m4'><br/>"
"<br/><b>" D_PASSWORD "</b><br/><input id='mp' name='mp' type='password' placeholder='" MQTT_PASS "' value='{m5'><br/>"
"<br/><b>" D_TOPIC "</b> = %topic% (" MQTT_TOPIC ")<br/><input id='mt' name='mt' placeholder='" MQTT_TOPIC" ' value='{m6'><br/>"
"<br/><b>" D_FULL_TOPIC "</b> (" MQTT_FULLTOPIC ")<br/><input id='mf' name='mf' placeholder='" MQTT_FULLTOPIC" ' value='{m7'><br/>";
const char HTTP_FORM_LOG1[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_LOGGING_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='3,0' hidden>";
"<fieldset><legend><b>&nbsp;" D_LOGGING_PARAMETERS "&nbsp;</b></legend><form method='get' action='lg'>";
const char HTTP_FORM_LOG2[] PROGMEM =
"<br/><b>{b0</b> ({b1)<br/><select id='{b2' name='{b2'>"
"<option{a0value='0'>0 " D_NONE "</option>"
@ -268,8 +244,8 @@ const char HTTP_FORM_LOG3[] PROGMEM =
"<br/><b>" D_SYSLOG_PORT "</b> (" STR(SYS_LOG_PORT) ")<br/><input id='lp' name='lp' placeholder='" STR(SYS_LOG_PORT) "' value='{l3'><br/>"
"<br/><b>" D_TELEMETRY_PERIOD "</b> (" STR(TELE_PERIOD) ")<br/><input id='lt' name='lt' placeholder='" STR(TELE_PERIOD) "' value='{l4'><br/>";
const char HTTP_FORM_OTHER[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_OTHER_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='5,1' hidden>"
"<fieldset><legend><b>&nbsp;" D_OTHER_PARAMETERS "&nbsp;</b></legend><form method='get' action='co'>"
// "<input id='w' name='w' value='5,1' hidden>"
"<br/><b>" D_WEB_ADMIN_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_WEB_ADMIN_PASSWORD "' value='" D_ASTERIX "'><br/>"
"<br/><input style='width:10%;' id='b1' name='b1' type='checkbox'{r1><b>" D_MQTT_ENABLE "</b><br/>";
const char HTTP_FORM_OTHER2[] PROGMEM =
@ -281,7 +257,7 @@ const char HTTP_FORM_OTHER3b[] PROGMEM =
"<br/><input style='width:10%;' id='r{1' name='b2' type='radio' value='{1'{2><b>{3</b>{4"; // Different id only used for labels
#endif // USE_EMULATION
const char HTTP_FORM_END[] PROGMEM =
"<br/><button type='submit' class='button bgrn'>" D_SAVE "</button></form></fieldset>";
"<br/><button name='save' type='submit' class='button bgrn'>" D_SAVE "</button></form></fieldset>";
const char HTTP_FORM_RST[] PROGMEM =
"<div id='f1' name='f1' style='display:block;'>"
"<fieldset><legend><b>&nbsp;" D_RESTORE_CONFIGURATION "&nbsp;</b></legend>";
@ -367,6 +343,7 @@ void ExecuteWebCommand(char* svalue, int source)
void StartWebserver(int type, IPAddress ipweb)
{
if (!Settings.web_refresh) { Settings.web_refresh = HTTP_REFRESH_TIME; }
if (!webserver_state) {
if (!WebServer) {
WebServer = new ESP8266WebServer((HTTP_MANAGER==type) ? 80 : WEB_PORT);
@ -379,47 +356,22 @@ void StartWebserver(int type, IPAddress ipweb)
WebServer->on("/ax", HandleAjaxConsoleRefresh);
WebServer->on("/ay", HandleAjaxStatusRefresh);
WebServer->on("/cm", HandleHttpCommand);
WebServer->on("/rb", HandleRestart);
WebServer->onNotFound(HandleNotFound);
#ifndef BE_MINIMAL
WebServer->on("/cn", HandleConfiguration);
WebServer->on("/md", HandleModuleConfiguration);
#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
WebServer->on("/tm", HandleTimerConfiguration);
#endif // USE_TIMERS and USE_TIMERS_WEB
WebServer->on("/w1", HandleWifiConfigurationWithScan);
WebServer->on("/w0", HandleWifiConfiguration);
if (Settings.flag.mqtt_enabled) {
WebServer->on("/mq", HandleMqttConfiguration);
#ifdef USE_DOMOTICZ
WebServer->on("/dm", HandleDomoticzConfiguration);
#endif // USE_DOMOTICZ
}
#ifdef USE_KNX
#ifdef USE_KNX_WEB_MENU
WebServer->on("/kn", HandleKNXConfiguration);
#endif // USE_KNX_WEB_MENU
#endif // USE_KNX
WebServer->on("/wi", HandleWifiConfiguration);
WebServer->on("/lg", HandleLoggingConfiguration);
WebServer->on("/co", HandleOtherConfiguration);
WebServer->on("/dl", HandleBackupConfiguration);
WebServer->on("/sv", HandleSaveSettings);
WebServer->on("/rs", HandleRestoreConfiguration);
WebServer->on("/rt", HandleResetConfiguration);
WebServer->on("/in", HandleInformation);
#ifdef USE_EMULATION
if (EMUL_WEMO == Settings.flag2.emulation) {
WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
WebServer->on("/eventservice.xml", HandleUpnpService);
WebServer->on("/metainfoservice.xml", HandleUpnpMetaService);
WebServer->on("/setup.xml", HandleUpnpSetupWemo);
}
if (EMUL_HUE == Settings.flag2.emulation) {
WebServer->on("/description.xml", HandleUpnpSetupHue);
}
HueWemoAddHandlers();
#endif // USE_EMULATION
XdrvCall(FUNC_WEB_ADD_HANDLER);
#endif // Not BE_MINIMAL
WebServer->on("/fwlink", HandleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
WebServer->onNotFound(HandleNotFound);
}
reset_web_log_flag = 0;
WebServer->begin(); // Web server start
@ -497,6 +449,7 @@ void ShowPage(String &page, bool auth)
return WebServer->requestAuthentication();
}
page.replace(F("{a}"), String(Settings.web_refresh));
page.replace(F("{ha"), my_module.name);
page.replace(F("{h}"), Settings.friendlyname[0]);
if (HTTP_MANAGER == webserver_state) {
@ -519,6 +472,43 @@ void ShowPage(String &page)
ShowPage(page, true);
}
/*-------------------------------------------------------------------------------------------*/
void WebRestart(uint8_t type)
{
// type 0 = restart
// type 1 = restart after config change
// type 2 = restart after config change with possible ip address change too
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTART);
String page = FPSTR(HTTP_HEAD);
page += FPSTR(HTTP_HEAD_RELOAD);
page += FPSTR(HTTP_HEAD_STYLE);
if (type) {
page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION));
page += F("<div style='text-align:center;'><b>" D_CONFIGURATION_SAVED "</b><br/>");
if (2 == type) {
page += F("<br/>" D_TRYING_TO_CONNECT "<br/>");
}
page += F("</div>");
}
else {
page.replace(F("{v}"), FPSTR(S_RESTART));
}
page += FPSTR(HTTP_MSG_RSTRT);
if (HTTP_MANAGER == webserver_state) {
webserver_state = HTTP_ADMIN;
} else {
page += FPSTR(HTTP_BTN_MAIN);
}
ShowPage(page);
ShowWebSource(SRC_WEBGUI);
restart_flag = 2;
}
/*********************************************************************************************/
void HandleWifiLogin()
@ -536,6 +526,11 @@ void HandleRoot()
if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the page.
if ( WebServer->hasArg("rstrt") ) {
WebRestart(0);
return;
}
if (HTTP_MANAGER == webserver_state) {
#ifndef BE_MINIMAL
if ((Settings.web_password[0] != 0) && !(WebServer->hasArg("USER1")) && !(WebServer->hasArg("PASS1"))) {
@ -608,6 +603,12 @@ void HandleRoot()
page += F("</tr></table>");
}
#ifndef BE_MINIMAL
mqtt_data[0] = '\0';
XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON);
page += String(mqtt_data);
#endif // Not BE_MINIMAL
if (HTTP_ADMIN == webserver_state) {
page += FPSTR(HTTP_BTN_MENU1);
page += FPSTR(HTTP_BTN_RSTRT);
@ -643,7 +644,7 @@ void HandleAjaxStatusRefresh()
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_DIMMER " %s"), tmp);
ExecuteWebCommand(svalue, SRC_WEBGUI);
}
WebGetArg("c", tmp, sizeof(tmp));
WebGetArg("t", tmp, sizeof(tmp));
if (strlen(tmp)) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_COLORTEMPERATURE " %s"), tmp);
ExecuteWebCommand(svalue, SRC_WEBGUI);
@ -693,7 +694,10 @@ boolean HttpUser()
return status;
}
/*-------------------------------------------------------------------------------------------*/
#ifndef BE_MINIMAL
void HandleConfiguration()
{
if (HttpUser()) { return; }
@ -704,29 +708,34 @@ void HandleConfiguration()
page.replace(F("{v}"), FPSTR(S_CONFIGURATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_BTN_MENU_MODULE);
#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
#ifdef USE_RULES
page += FPSTR(HTTP_BTN_MENU_TIMER);
#else
if (devices_present) { page += FPSTR(HTTP_BTN_MENU_TIMER); }
#endif // USE_RULES
#endif // USE_TIMERS and USE_TIMERS_WEB
page += FPSTR(HTTP_BTN_MENU_WIFI);
if (Settings.flag.mqtt_enabled) { page += FPSTR(HTTP_BTN_MENU_MQTT); }
mqtt_data[0] = '\0';
XdrvCall(FUNC_WEB_ADD_BUTTON);
page += String(mqtt_data);
page += FPSTR(HTTP_BTN_MENU4);
page += FPSTR(HTTP_BTN_MAIN);
ShowPage(page);
}
/*-------------------------------------------------------------------------------------------*/
void HandleModuleConfiguration()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
char stemp[20];
uint8_t midx;
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MODULE);
if (WebServer->hasArg("save")) {
ModuleSaveSettings();
WebRestart(1);
return;
}
char stemp[20];
uint8_t midx;
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE));
page += FPSTR(HTTP_SCRIPT_MODULE1);
@ -779,28 +788,66 @@ void HandleModuleConfiguration()
ShowPage(page);
}
void HandleWifiConfigurationWithScan()
void ModuleSaveSettings()
{
HandleWifi(true);
char tmp[100];
char stemp[TOPSZ];
WebGetArg("g99", tmp, sizeof(tmp));
byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp);
Settings.last_module = Settings.module;
Settings.module = new_module;
mytmplt cmodule;
memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule));
String gpios = "";
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (Settings.last_module != new_module) {
Settings.my_gp.io[i] = 0;
} else {
if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) {
snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i);
WebGetArg(stemp, tmp, sizeof(tmp));
Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]);
}
}
}
snprintf_P(stemp, sizeof(stemp), kModules[Settings.module].name);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), stemp, gpios.c_str());
AddLog(LOG_LEVEL_INFO);
}
/*-------------------------------------------------------------------------------------------*/
String htmlEscape(String s)
{
s.replace("&", "&amp;");
s.replace("<", "&lt;");
s.replace(">", "&gt;");
s.replace("\"", "&quot;");
s.replace("'", "&#x27;");
s.replace("/", "&#x2F;");
return s;
}
void HandleWifiConfiguration()
{
HandleWifi(false);
}
void HandleWifi(boolean scan)
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_WIFI);
if (WebServer->hasArg("save")) {
WifiSaveSettings();
WebRestart(2);
return;
}
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_WIFI));
page += FPSTR(HTTP_HEAD_STYLE);
if (scan) {
if (WebServer->hasArg("scan")) {
#ifdef USE_EMULATION
UdpDisconnect();
#endif // USE_EMULATION
@ -854,7 +901,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]);
@ -886,39 +933,46 @@ void HandleWifi(boolean scan)
ShowPage(page, !(HTTP_MANAGER == webserver_state));
}
void HandleMqttConfiguration()
void WifiSaveSettings()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT);
char tmp[100];
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_MQTT);
char str[sizeof(Settings.mqtt_client)];
page.replace(F("{m0"), Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client)));
page.replace(F("{m1"), Settings.mqtt_host);
page.replace(F("{m2"), String(Settings.mqtt_port));
page.replace(F("{m3"), Settings.mqtt_client);
page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user);
page.replace(F("{m5"), (Settings.mqtt_pwd[0] == '\0')?"0":Settings.mqtt_pwd);
page.replace(F("{m6"), Settings.mqtt_topic);
page.replace(F("{m7"), Settings.mqtt_fulltopic);
page += FPSTR(HTTP_FORM_END);
page += FPSTR(HTTP_BTN_CONF);
ShowPage(page);
WebGetArg("h", tmp, sizeof(tmp));
strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname));
if (strstr(Settings.hostname,"%")) {
strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname));
}
WebGetArg("s1", tmp, sizeof(tmp));
strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? STA_SSID1 : tmp, sizeof(Settings.sta_ssid[0]));
WebGetArg("s2", tmp, sizeof(tmp));
strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1]));
WebGetArg("p1", tmp, sizeof(tmp));
strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0]));
WebGetArg("p2", tmp, sizeof(tmp));
strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1]));
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"),
Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]);
AddLog(LOG_LEVEL_INFO);
}
/*-------------------------------------------------------------------------------------------*/
void HandleLoggingConfiguration()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_LOGGING);
if (WebServer->hasArg("save")) {
LoggingSaveSettings();
HandleConfiguration();
return;
}
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_LOGGING));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_LOG1);
for (byte idx = 0; idx < 3; idx++) {
page += FPSTR(HTTP_FORM_LOG2);
@ -958,11 +1012,46 @@ void HandleLoggingConfiguration()
ShowPage(page);
}
void LoggingSaveSettings()
{
char tmp[100];
WebGetArg("ls", tmp, sizeof(tmp));
Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp);
WebGetArg("lw", tmp, sizeof(tmp));
Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp);
WebGetArg("ll", tmp, sizeof(tmp));
Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp);
syslog_level = Settings.syslog_level;
syslog_timer = 0;
WebGetArg("lh", tmp, sizeof(tmp));
strlcpy(Settings.syslog_host, (!strlen(tmp)) ? SYS_LOG_HOST : tmp, sizeof(Settings.syslog_host));
WebGetArg("lp", tmp, sizeof(tmp));
Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp);
WebGetArg("lt", tmp, sizeof(tmp));
Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp);
if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) {
Settings.tele_period = 10; // Do not allow periods < 10 seconds
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"),
Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period);
AddLog(LOG_LEVEL_INFO);
}
/*-------------------------------------------------------------------------------------------*/
void HandleOtherConfiguration()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_OTHER);
if (WebServer->hasArg("save")) {
OtherSaveSettings();
WebRestart(1);
return;
}
char stemp[40];
String page = FPSTR(HTTP_HEAD);
@ -996,6 +1085,32 @@ void HandleOtherConfiguration()
ShowPage(page);
}
void OtherSaveSettings()
{
char tmp[100];
char stemp[TOPSZ];
char stemp2[TOPSZ];
WebGetArg("p1", tmp, sizeof(tmp));
strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password));
Settings.flag.mqtt_enabled = WebServer->hasArg("b1");
#ifdef USE_EMULATION
WebGetArg("b2", tmp, sizeof(tmp));
Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp);
#endif // USE_EMULATION
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation);
for (byte i = 0; i < MAX_FRIENDLYNAMES; i++) {
snprintf_P(stemp, sizeof(stemp), PSTR("a%d"), i +1);
WebGetArg(stemp, tmp, sizeof(tmp));
snprintf_P(stemp2, sizeof(stemp2), PSTR(FRIENDLY_NAME"%d"), i +1);
strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? stemp2 : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i]));
snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]);
}
AddLog(LOG_LEVEL_INFO);
}
/*-------------------------------------------------------------------------------------------*/
void HandleBackupConfiguration()
{
if (HttpUser()) { return; }
@ -1013,6 +1128,10 @@ void HandleBackupConfiguration()
WebServer->sendHeader(F("Content-Disposition"), attachment);
WebServer->send(200, FPSTR(HDR_CTYPE_STREAM), "");
uint16_t cfg_crc = Settings.cfg_crc;
Settings.cfg_crc = GetSettingsCrc(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918)
memcpy(settings_buffer, &Settings, sizeof(Settings));
if (config_xor_on_set) {
for (uint16_t i = 2; i < sizeof(Settings); i++) {
@ -1030,173 +1149,11 @@ void HandleBackupConfiguration()
#endif
SettingsBufferFree();
Settings.cfg_crc = cfg_crc; // Restore crc in case savedata = 0 to make sure settings will be noted as changed
}
void HandleSaveSettings()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
char stemp[TOPSZ];
char stemp2[TOPSZ];
String result = "";
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_SAVE_CONFIGURATION);
char tmp[100];
WebGetArg("w", tmp, sizeof(tmp)); // Returns "5,1" where 5 is config type and 1 is restart flag
char *p = tmp;
uint8_t what = strtol(p, &p, 10);
p++; // Skip comma
uint8_t restart = strtol(p, &p, 10);
switch (what) {
case 1:
WebGetArg("h", tmp, sizeof(tmp));
strlcpy(Settings.hostname, (!strlen(tmp)) ? WIFI_HOSTNAME : tmp, sizeof(Settings.hostname));
if (strstr(Settings.hostname,"%")) {
strlcpy(Settings.hostname, WIFI_HOSTNAME, sizeof(Settings.hostname));
}
WebGetArg("s1", tmp, sizeof(tmp));
strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? STA_SSID1 : tmp, sizeof(Settings.sta_ssid[0]));
WebGetArg("s2", tmp, sizeof(tmp));
strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? STA_SSID2 : tmp, sizeof(Settings.sta_ssid[1]));
// WebGetArg("s1", tmp, sizeof(tmp));
// strlcpy(Settings.sta_ssid[0], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[0]));
// WebGetArg("s2", tmp, sizeof(tmp));
// strlcpy(Settings.sta_ssid[1], (!strlen(tmp)) ? "" : tmp, sizeof(Settings.sta_ssid[1]));
WebGetArg("p1", tmp, sizeof(tmp));
strlcpy(Settings.sta_pwd[0], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[0] : tmp, sizeof(Settings.sta_pwd[0]));
WebGetArg("p2", tmp, sizeof(tmp));
strlcpy(Settings.sta_pwd[1], (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.sta_pwd[1] : tmp, sizeof(Settings.sta_pwd[1]));
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_WIFI D_CMND_HOSTNAME " %s, " D_CMND_SSID "1 %s, " D_CMND_SSID "2 %s"),
Settings.hostname, Settings.sta_ssid[0], Settings.sta_ssid[1]);
AddLog(LOG_LEVEL_INFO);
result += F("<br/>" D_TRYING_TO_CONNECT "<br/>");
break;
case 2:
WebGetArg("mt", tmp, sizeof(tmp));
strlcpy(stemp, (!strlen(tmp)) ? MQTT_TOPIC : tmp, sizeof(stemp));
MakeValidMqtt(0, stemp);
WebGetArg("mf", tmp, sizeof(tmp));
strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2));
MakeValidMqtt(1,stemp2);
if ((strcmp(stemp, Settings.mqtt_topic)) || (strcmp(stemp2, Settings.mqtt_fulltopic))) {
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
MqttPublishPrefixTopic_P(TELE, S_LWT, true); // Offline or remove previous retained topic
}
strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic));
strlcpy(Settings.mqtt_fulltopic, stemp2, sizeof(Settings.mqtt_fulltopic));
WebGetArg("mh", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_host, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_host));
WebGetArg("ml", tmp, sizeof(tmp));
Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp);
WebGetArg("mc", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_client, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp, sizeof(Settings.mqtt_client));
WebGetArg("mu", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user));
WebGetArg("mp", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? MQTT_PASS : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_pwd));
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_MQTTPASSWORD " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"),
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_pwd, Settings.mqtt_topic, Settings.mqtt_fulltopic);
AddLog(LOG_LEVEL_INFO);
break;
case 3:
WebGetArg("ls", tmp, sizeof(tmp));
Settings.seriallog_level = (!strlen(tmp)) ? SERIAL_LOG_LEVEL : atoi(tmp);
WebGetArg("lw", tmp, sizeof(tmp));
Settings.weblog_level = (!strlen(tmp)) ? WEB_LOG_LEVEL : atoi(tmp);
WebGetArg("ll", tmp, sizeof(tmp));
Settings.syslog_level = (!strlen(tmp)) ? SYS_LOG_LEVEL : atoi(tmp);
syslog_level = Settings.syslog_level;
syslog_timer = 0;
WebGetArg("lh", tmp, sizeof(tmp));
strlcpy(Settings.syslog_host, (!strlen(tmp)) ? SYS_LOG_HOST : tmp, sizeof(Settings.syslog_host));
WebGetArg("lp", tmp, sizeof(tmp));
Settings.syslog_port = (!strlen(tmp)) ? SYS_LOG_PORT : atoi(tmp);
WebGetArg("lt", tmp, sizeof(tmp));
Settings.tele_period = (!strlen(tmp)) ? TELE_PERIOD : atoi(tmp);
if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) {
Settings.tele_period = 10; // Do not allow periods < 10 seconds
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_LOG D_CMND_SERIALLOG " %d, " D_CMND_WEBLOG " %d, " D_CMND_SYSLOG " %d, " D_CMND_LOGHOST " %s, " D_CMND_LOGPORT " %d, " D_CMND_TELEPERIOD " %d"),
Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period);
AddLog(LOG_LEVEL_INFO);
break;
#if defined(USE_TIMERS) && defined(USE_TIMERS_WEB)
case 7:
TimerSaveSettings();
break;
#endif // USE_TIMERS and USE_TIMERS_WEB
#ifdef USE_DOMOTICZ
case 4:
DomoticzSaveSettings();
break;
#endif // USE_DOMOTICZ
case 5:
WebGetArg("p1", tmp, sizeof(tmp));
strlcpy(Settings.web_password, (!strlen(tmp)) ? "" : (strchr(tmp,'*')) ? Settings.web_password : tmp, sizeof(Settings.web_password));
Settings.flag.mqtt_enabled = WebServer->hasArg("b1");
#ifdef USE_EMULATION
WebGetArg("b2", tmp, sizeof(tmp));
Settings.flag2.emulation = (!strlen(tmp)) ? 0 : atoi(tmp);
#endif // USE_EMULATION
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_OTHER D_MQTT_ENABLE " %s, " D_CMND_EMULATION " %d, " D_CMND_FRIENDLYNAME), GetStateText(Settings.flag.mqtt_enabled), Settings.flag2.emulation);
for (byte i = 0; i < MAX_FRIENDLYNAMES; i++) {
snprintf_P(stemp, sizeof(stemp), PSTR("a%d"), i +1);
WebGetArg(stemp, tmp, sizeof(tmp));
snprintf_P(stemp2, sizeof(stemp2), PSTR(FRIENDLY_NAME"%d"), i +1);
strlcpy(Settings.friendlyname[i], (!strlen(tmp)) ? (i) ? stemp2 : FRIENDLY_NAME : tmp, sizeof(Settings.friendlyname[i]));
snprintf_P(log_data, sizeof(log_data), PSTR("%s%s %s"), log_data, (i) ? "," : "", Settings.friendlyname[i]);
}
AddLog(LOG_LEVEL_INFO);
break;
case 6:
WebGetArg("g99", tmp, sizeof(tmp));
byte new_module = (!strlen(tmp)) ? MODULE : atoi(tmp);
Settings.last_module = Settings.module;
Settings.module = new_module;
mytmplt cmodule;
memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule));
String gpios = "";
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (Settings.last_module != new_module) {
Settings.my_gp.io[i] = 0;
} else {
if (GPIO_USER == ValidGPIO(i, cmodule.gp.io[i])) {
snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i);
WebGetArg(stemp, tmp, sizeof(tmp));
Settings.my_gp.io[i] = (!strlen(tmp)) ? 0 : atoi(tmp);
gpios += F(", " D_GPIO ); gpios += String(i); gpios += F(" "); gpios += String(Settings.my_gp.io[i]);
}
}
}
snprintf_P(stemp, sizeof(stemp), kModules[Settings.module].name);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MODULE "%s " D_CMND_MODULE "%s"), stemp, gpios.c_str());
AddLog(LOG_LEVEL_INFO);
break;
}
if (restart) {
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION));
page += FPSTR(HTTP_HEAD_STYLE);
page += F("<div style='text-align:center;'><b>" D_CONFIGURATION_SAVED "</b><br/>");
page += result;
page += F("</div>");
page += FPSTR(HTTP_MSG_RSTRT);
if (HTTP_MANAGER == webserver_state) {
webserver_state = HTTP_ADMIN;
} else {
page += FPSTR(HTTP_BTN_MAIN);
}
ShowPage(page);
ShowWebSource(SRC_WEBGUI);
restart_flag = 2;
} else {
HandleConfiguration();
}
}
/*-------------------------------------------------------------------------------------------*/
void HandleResetConfiguration()
{
@ -1238,6 +1195,8 @@ void HandleRestoreConfiguration()
upload_file_type = UPL_SETTINGS;
}
/*-------------------------------------------------------------------------------------------*/
void HandleInformation()
{
if (HttpUser()) { return; }
@ -1355,6 +1314,8 @@ void HandleInformation()
}
#endif // Not BE_MINIMAL
/*-------------------------------------------------------------------------------------------*/
void HandleUpgradeFirmware()
{
if (HttpUser()) { return; }
@ -1648,6 +1609,8 @@ void HandleUploadLoop()
delay(0);
}
/*-------------------------------------------------------------------------------------------*/
void HandlePreflightRequest()
{
WebServer->sendHeader(F("Access-Control-Allow-Origin"), F("*"));
@ -1656,6 +1619,8 @@ void HandlePreflightRequest()
WebServer->send(200, FPSTR(HDR_CTYPE_HTML), "");
}
/*-------------------------------------------------------------------------------------------*/
void HandleHttpCommand()
{
if (HttpUser()) { return; }
@ -1714,6 +1679,8 @@ void HandleHttpCommand()
WebServer->send(200, FPSTR(HDR_CTYPE_JSON), message);
}
/*-------------------------------------------------------------------------------------------*/
void HandleConsole()
{
if (HttpUser()) { return; }
@ -1787,27 +1754,6 @@ void HandleAjaxConsoleRefresh()
WebServer->send(200, FPSTR(HDR_CTYPE_XML), message);
}
void HandleRestart()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_RESTART);
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_RESTART));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_MSG_RSTRT);
if (HTTP_MANAGER == webserver_state) {
webserver_state = HTTP_ADMIN;
} else {
page += FPSTR(HTTP_BTN_MAIN);
}
ShowPage(page);
ShowWebSource(SRC_WEBGUI);
restart_flag = 2;
}
/********************************************************************************************/
void HandleNotFound()
@ -1977,8 +1923,8 @@ int WebSend(char *buffer)
/*********************************************************************************************/
enum WebCommands { CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_WEBSEND, CMND_EMULATION };
const char kWebCommands[] PROGMEM = D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBSEND "|" D_CMND_EMULATION ;
enum WebCommands { CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_WEBREFRESH, CMND_WEBSEND, CMND_EMULATION };
const char kWebCommands[] PROGMEM = D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_EMULATION ;
const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND ;
bool WebCommand()
@ -2011,6 +1957,10 @@ bool WebCommand()
if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_ALL)) { Settings.weblog_level = XdrvMailbox.payload; }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.weblog_level);
}
else if (CMND_WEBREFRESH == command_code) {
if ((XdrvMailbox.payload > 999) && (XdrvMailbox.payload <= 10000)) { Settings.web_refresh = XdrvMailbox.payload; }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.web_refresh);
}
else if (CMND_WEBSEND == command_code) {
if (XdrvMailbox.data_len > 0) {
uint8_t result = WebSend(XdrvMailbox.data);
@ -2036,9 +1986,9 @@ bool WebCommand()
* Interface
\*********************************************************************************************/
#define XDRV_02
#define XDRV_01
boolean Xdrv02(byte function)
boolean Xdrv01(byte function)
{
boolean result = false;

View File

@ -1,5 +1,5 @@
/*
xdrv_01_mqtt.ino - mqtt support for Sonoff-Tasmota
xdrv_02_mqtt.ino - mqtt support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends
@ -23,19 +23,32 @@
// 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)
#if (MQTT_LIBRARY_TYPE == MQTT_ESPMQTTARDUINO) // Obsolete as of v6.2.1.11
#undef MQTT_LIBRARY_TYPE
#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT
#endif
/*
#if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT)
#undef MQTT_LIBRARY_TYPE
#define MQTT_LIBRARY_TYPE MQTT_ARDUINOMQTT // Obsolete in near future
#endif
*/
#ifdef USE_MQTT_TLS
#ifdef MQTT_LIBRARY_TYPE
#if (MQTT_LIBRARY_TYPE == MQTT_TASMOTAMQTT)
#undef MQTT_LIBRARY_TYPE
#endif
#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS
#else
#ifndef MQTT_LIBRARY_TYPE
#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as default
#define MQTT_LIBRARY_TYPE MQTT_PUBSUBCLIENT // Use PubSubClient library as it only supports TLS
#endif
#endif
/*********************************************************************************************/
@ -136,48 +149,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 +480,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 +500,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 +521,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
}
@ -765,18 +782,115 @@ bool MqttCommand()
return serviced;
}
/*********************************************************************************************\
* Presentation
\*********************************************************************************************/
#ifdef USE_WEBSERVER
#define WEB_HANDLE_MQTT "mq"
const char S_CONFIGURE_MQTT[] PROGMEM = D_CONFIGURE_MQTT;
const char HTTP_BTN_MENU_MQTT[] PROGMEM =
"<br/><form action='" WEB_HANDLE_MQTT "' method='get'><button>" D_CONFIGURE_MQTT "</button></form>";
const char HTTP_FORM_MQTT[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MQTT_PARAMETERS "&nbsp;</b></legend><form method='get' action='" WEB_HANDLE_MQTT "'>"
"<br/><b>" D_HOST "</b> (" MQTT_HOST ")<br/><input id='mh' name='mh' placeholder='" MQTT_HOST" ' value='{m1'><br/>"
"<br/><b>" D_PORT "</b> (" STR(MQTT_PORT) ")<br/><input id='ml' name='ml' placeholder='" STR(MQTT_PORT) "' value='{m2'><br/>"
"<br/><b>" D_CLIENT "</b> ({m0)<br/><input id='mc' name='mc' placeholder='" MQTT_CLIENT_ID "' value='{m3'><br/>"
"<br/><b>" D_USER "</b> (" MQTT_USER ")<br/><input id='mu' name='mu' placeholder='" MQTT_USER "' value='{m4'><br/>"
"<br/><b>" D_PASSWORD "</b><br/><input id='mp' name='mp' type='password' placeholder='" MQTT_PASS "' value='{m5'><br/>"
"<br/><b>" D_TOPIC "</b> = %topic% (" MQTT_TOPIC ")<br/><input id='mt' name='mt' placeholder='" MQTT_TOPIC" ' value='{m6'><br/>"
"<br/><b>" D_FULL_TOPIC "</b> (" MQTT_FULLTOPIC ")<br/><input id='mf' name='mf' placeholder='" MQTT_FULLTOPIC" ' value='{m7'><br/>";
void HandleMqttConfiguration()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_MQTT);
if (WebServer->hasArg("save")) {
MqttSaveSettings();
WebRestart(1);
return;
}
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_MQTT));
page += FPSTR(HTTP_HEAD_STYLE);
page += FPSTR(HTTP_FORM_MQTT);
char str[sizeof(Settings.mqtt_client)];
page.replace(F("{m0"), Format(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client)));
page.replace(F("{m1"), Settings.mqtt_host);
page.replace(F("{m2"), String(Settings.mqtt_port));
page.replace(F("{m3"), Settings.mqtt_client);
page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user);
page.replace(F("{m5"), (Settings.mqtt_pwd[0] == '\0')?"0":Settings.mqtt_pwd);
page.replace(F("{m6"), Settings.mqtt_topic);
page.replace(F("{m7"), Settings.mqtt_fulltopic);
page += FPSTR(HTTP_FORM_END);
page += FPSTR(HTTP_BTN_CONF);
ShowPage(page);
}
void MqttSaveSettings()
{
char tmp[100];
char stemp[TOPSZ];
char stemp2[TOPSZ];
WebGetArg("mt", tmp, sizeof(tmp));
strlcpy(stemp, (!strlen(tmp)) ? MQTT_TOPIC : tmp, sizeof(stemp));
MakeValidMqtt(0, stemp);
WebGetArg("mf", tmp, sizeof(tmp));
strlcpy(stemp2, (!strlen(tmp)) ? MQTT_FULLTOPIC : tmp, sizeof(stemp2));
MakeValidMqtt(1,stemp2);
if ((strcmp(stemp, Settings.mqtt_topic)) || (strcmp(stemp2, Settings.mqtt_fulltopic))) {
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
MqttPublishPrefixTopic_P(TELE, S_LWT, true); // Offline or remove previous retained topic
}
strlcpy(Settings.mqtt_topic, stemp, sizeof(Settings.mqtt_topic));
strlcpy(Settings.mqtt_fulltopic, stemp2, sizeof(Settings.mqtt_fulltopic));
WebGetArg("mh", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_host, (!strlen(tmp)) ? MQTT_HOST : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_host));
WebGetArg("ml", tmp, sizeof(tmp));
Settings.mqtt_port = (!strlen(tmp)) ? MQTT_PORT : atoi(tmp);
WebGetArg("mc", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_client, (!strlen(tmp)) ? MQTT_CLIENT_ID : tmp, sizeof(Settings.mqtt_client));
WebGetArg("mu", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_user, (!strlen(tmp)) ? MQTT_USER : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_user));
WebGetArg("mp", tmp, sizeof(tmp));
strlcpy(Settings.mqtt_pwd, (!strlen(tmp)) ? MQTT_PASS : (!strcmp(tmp,"0")) ? "" : tmp, sizeof(Settings.mqtt_pwd));
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CMND_MQTTHOST " %s, " D_CMND_MQTTPORT " %d, " D_CMND_MQTTCLIENT " %s, " D_CMND_MQTTUSER " %s, " D_CMND_MQTTPASSWORD " %s, " D_CMND_TOPIC " %s, " D_CMND_FULLTOPIC " %s"),
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, Settings.mqtt_user, Settings.mqtt_pwd, Settings.mqtt_topic, Settings.mqtt_fulltopic);
AddLog(LOG_LEVEL_INFO);
}
#endif // USE_WEBSERVER
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
#define XDRV_01
#define XDRV_02
boolean Xdrv01(byte function)
boolean Xdrv02(byte function)
{
boolean result = false;
if (Settings.flag.mqtt_enabled) {
switch (function) {
#ifdef USE_WEBSERVER
case FUNC_WEB_ADD_BUTTON:
strncat_P(mqtt_data, HTTP_BTN_MENU_MQTT, sizeof(mqtt_data));
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_MQTT, HandleMqttConfiguration);
break;
#endif // USE_WEBSERVER
case FUNC_LOOP:
MqttLoop();
break;

View File

@ -55,11 +55,11 @@
enum LightCommands {
CMND_COLOR, CMND_COLORTEMPERATURE, CMND_DIMMER, CMND_LED, CMND_LEDTABLE, CMND_FADE,
CMND_PIXELS, CMND_ROTATION, CMND_SCHEME, CMND_SPEED, CMND_WAKEUP, CMND_WAKEUPDURATION,
CMND_PIXELS, CMND_RGBWWTABLE, CMND_ROTATION, CMND_SCHEME, CMND_SPEED, CMND_WAKEUP, CMND_WAKEUPDURATION,
CMND_WIDTH, CMND_CHANNEL, CMND_HSBCOLOR, CMND_UNDOCA };
const char kLightCommands[] PROGMEM =
D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_LED "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|"
D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|"
D_CMND_PIXELS "|" D_CMND_RGBWWTABLE "|" D_CMND_ROTATION "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|"
D_CMND_WIDTH "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR "|UNDOCA" ;
struct LRgbColor {
@ -799,7 +799,8 @@ void LightAnimate()
light_update = 0;
for (byte i = 0; i < light_subtype; i++) {
light_last_color[i] = light_new_color[i];
cur_col[i] = (Settings.light_correction) ? ledTable[light_last_color[i]] : light_last_color[i];
cur_col[i] = light_last_color[i]*Settings.rgbwwTable[i]/255;
cur_col[i] = (Settings.light_correction) ? ledTable[cur_col[i]] : cur_col[i];
if (light_type < LT_PWM6) {
if (pin[GPIO_PWM1 +i] < 99) {
if (cur_col[i] > 0xFC) {
@ -1279,6 +1280,33 @@ boolean LightCommand()
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(Settings.light_correction));
}
else if (CMND_RGBWWTABLE == command_code) {
bool validtable = (XdrvMailbox.data_len > 0);
char scolor[25];
if (validtable) {
uint16_t HSB[3];
if (strstr(XdrvMailbox.data, ",")) { // Command with up to 5 comma separated parameters
for (int i = 0; i < LST_RGBWC; i++) {
char *substr;
if (0 == i) {
substr = strtok(XdrvMailbox.data, ",");
} else {
substr = strtok(NULL, ",");
}
if (substr != NULL) {
Settings.rgbwwTable[i] = atoi(substr);
}
}
}
light_update = 1;
}
scolor[0] = '\0';
for (byte i = 0; i < LST_RGBWC; i++) {
snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", Settings.rgbwwTable[i]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, scolor);
}
else if (CMND_FADE == command_code) {
switch (XdrvMailbox.payload) {
case 0: // Off

View File

@ -19,22 +19,6 @@
#ifdef USE_DOMOTICZ
#ifdef USE_WEBSERVER
const char HTTP_FORM_DOMOTICZ[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_DOMOTICZ_PARAMETERS "&nbsp;</b></legend><form method='post' action='sv'>"
"<input id='w' name='w' value='4,1' hidden>"
"<br/><table>";
const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_IDX " {1</b></td><td style='width:70px'><input id='r{1' name='r{1' placeholder='0' value='{2'></td></tr>"
"<tr><td style='width:260px'><b>" D_DOMOTICZ_KEY_IDX " {1</b></td><td style='width:70px'><input id='k{1' name='k{1' placeholder='0' value='{3'></td></tr>";
const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_SWITCH_IDX " {1</b></td><td style='width:70px'><input id='s{1' name='s{1' placeholder='0' value='{4'></td></tr>";
const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_SENSOR_IDX " {1</b> {2</td><td style='width:70px'><input id='l{1' name='l{1' placeholder='0' value='{5'></td></tr>";
const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_UPDATE_TIMER "</b> (" STR(DOMOTICZ_UPDATE_TIMER) ")</td><td style='width:70px'><input id='ut' name='ut' placeholder='" STR(DOMOTICZ_UPDATE_TIMER) "' value='{6'</td></tr>";
#endif // USE_WEBSERVER
const char DOMOTICZ_MESSAGE[] PROGMEM = "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\",\"Battery\":%d,\"RSSI\":%d}";
enum DomoticzCommands { CMND_IDX, CMND_KEYIDX, CMND_SWITCHIDX, CMND_SENSORIDX, CMND_UPDATETIMER };
@ -150,6 +134,15 @@ void DomoticzMqttSubscribe()
"svalue1" : "0",
"switchType" : "Dimmer",
"unit" : 1
}
* Fail on this one
{
"LastUpdate" : "2018-10-02 20:39:45",
"Name" : "Sfeerverlichting",
"Status" : "Off",
"Timers" : "true",
"Type" : "Group",
"idx" : "2"
}
*/
@ -157,7 +150,7 @@ boolean DomoticzMqttData()
{
char stemp1[10];
unsigned long idx = 0;
int16_t nvalue;
int16_t nvalue = -1;
int16_t found = 0;
domoticz_update_flag = 1;
@ -174,7 +167,9 @@ boolean DomoticzMqttData()
// return 1;
// }
idx = domoticz["idx"];
nvalue = domoticz["nvalue"];
if (domoticz.containsKey("nvalue")) {
nvalue = domoticz["nvalue"];
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DOMOTICZ "idx %d, nvalue %d"), idx, nvalue);
AddLog(LOG_LEVEL_DEBUG_MORE);
@ -198,7 +193,11 @@ boolean DomoticzMqttData()
found = 1;
} else if ((!iscolordimmer && 2 == nvalue) || // gswitch_sSetLevel
(iscolordimmer && 15 == nvalue)) { // Color_SetBrightnessLevel
nvalue = domoticz["svalue1"];
if (domoticz.containsKey("svalue1")) {
nvalue = domoticz["svalue1"];
} else {
return 1;
}
if (light_type && (Settings.light_dimmer == nvalue) && ((power >> i) &1)) {
return 1;
}
@ -371,14 +370,39 @@ void DomoticzSensorPowerEnergy(int power, char *energy)
\*********************************************************************************************/
#ifdef USE_WEBSERVER
#define WEB_HANDLE_DOMOTICZ "dm"
const char S_CONFIGURE_DOMOTICZ[] PROGMEM = D_CONFIGURE_DOMOTICZ;
const char HTTP_BTN_MENU_DOMOTICZ[] PROGMEM =
"<br/><form action='" WEB_HANDLE_DOMOTICZ "' method='get'><button>" D_CONFIGURE_DOMOTICZ "</button></form>";
const char HTTP_FORM_DOMOTICZ[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_DOMOTICZ_PARAMETERS "&nbsp;</b></legend><form method='post' action='" WEB_HANDLE_DOMOTICZ "'>"
"<br/><table>";
const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_IDX " {1</b></td><td style='width:70px'><input id='r{1' name='r{1' placeholder='0' value='{2'></td></tr>"
"<tr><td style='width:260px'><b>" D_DOMOTICZ_KEY_IDX " {1</b></td><td style='width:70px'><input id='k{1' name='k{1' placeholder='0' value='{3'></td></tr>";
const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_SWITCH_IDX " {1</b></td><td style='width:70px'><input id='s{1' name='s{1' placeholder='0' value='{4'></td></tr>";
const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_SENSOR_IDX " {1</b> {2</td><td style='width:70px'><input id='l{1' name='l{1' placeholder='0' value='{5'></td></tr>";
const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_UPDATE_TIMER "</b> (" STR(DOMOTICZ_UPDATE_TIMER) ")</td><td style='width:70px'><input id='ut' name='ut' placeholder='" STR(DOMOTICZ_UPDATE_TIMER) "' value='{6'</td></tr>";
void HandleDomoticzConfiguration()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ);
if (WebServer->hasArg("save")) {
DomoticzSaveSettings();
WebRestart(1);
return;
}
char stemp[32];
String page = FPSTR(HTTP_HEAD);
@ -459,6 +483,14 @@ boolean Xdrv07(byte function)
if (Settings.flag.mqtt_enabled) {
switch (function) {
#ifdef USE_WEBSERVER
case FUNC_WEB_ADD_BUTTON:
strncat_P(mqtt_data, HTTP_BTN_MENU_DOMOTICZ, sizeof(mqtt_data));
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_DOMOTICZ, HandleDomoticzConfiguration);
break;
#endif // USE_WEBSERVER
case FUNC_COMMAND:
result = DomoticzCommand();
break;

View File

@ -194,7 +194,7 @@ void ApplyTimerOffsets(Timer *duskdawn)
// apply offsets, check for over- and underflows
uint16_t timeBuffer;
if ((uint16_t)stored.time > 720) {
if ((uint16_t)stored.time > 719) {
// negative offset, time after 12:00
timeBuffer = (uint16_t)stored.time - 720;
// check for underflow
@ -510,6 +510,14 @@ boolean TimerCommand()
#ifdef USE_WEBSERVER
#ifdef USE_TIMERS_WEB
#define WEB_HANDLE_TIMER "tm"
const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER;
const char HTTP_BTN_MENU_TIMER[] PROGMEM =
"<br/><form action='" WEB_HANDLE_TIMER "' method='get'><button>" D_CONFIGURE_TIMER "</button></form>";
const char HTTP_TIMER_SCRIPT[] PROGMEM =
"var pt=[],ct=99;"
"function qs(s){" // Alias to save code space
@ -639,8 +647,7 @@ const char HTTP_TIMER_STYLE[] PROGMEM =
#endif
"</style>";
const char HTTP_FORM_TIMER[] PROGMEM =
"<fieldset style='min-width:470px;text-align:center;'><legend style='text-align:left;'><b>&nbsp;" D_TIMER_PARAMETERS "&nbsp;</b></legend><form method='post' action='sv'>"
"<input id='w' name='w' value='7,0' hidden>"
"<fieldset style='min-width:470px;text-align:center;'><legend style='text-align:left;'><b>&nbsp;" D_TIMER_PARAMETERS "&nbsp;</b></legend><form method='post' action='" WEB_HANDLE_TIMER "'>"
"<br/><input style='width:5%;' id='e0' name='e0' type='checkbox'{e0><b>" D_TIMER_ENABLE "</b><br/><br/><hr/>"
"<input id='t0' name='t0' value='";
const char HTTP_FORM_TIMER1[] PROGMEM =
@ -672,14 +679,18 @@ const char HTTP_FORM_TIMER1[] PROGMEM =
const char HTTP_FORM_TIMER2[] PROGMEM =
"type='submit' onclick='st();this.form.submit();'";
const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER;
void HandleTimerConfiguration()
{
if (HttpUser()) { return; }
if (!WebAuthenticate()) { return WebServer->requestAuthentication(); }
AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER);
if (WebServer->hasArg("save")) {
TimerSaveSettings();
HandleConfiguration();
return;
}
String page = FPSTR(HTTP_HEAD);
page.replace(F("{v}"), FPSTR(S_CONFIGURE_TIMER));
page += FPSTR(HTTP_TIMER_SCRIPT);
@ -743,6 +754,20 @@ boolean Xdrv09(byte function)
case FUNC_PRE_INIT:
TimerSetRandomWindows();
break;
#ifdef USE_WEBSERVER
#ifdef USE_TIMERS_WEB
case FUNC_WEB_ADD_BUTTON:
#ifdef USE_RULES
strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data));
#else
if (devices_present) { strncat_P(mqtt_data, HTTP_BTN_MENU_TIMER, sizeof(mqtt_data)); }
#endif // USE_RULES
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/" WEB_HANDLE_TIMER, HandleTimerConfiguration);
break;
#endif // USE_TIMERS_WEB
#endif // USE_WEBSERVER
case FUNC_EVERY_SECOND:
TimerEverySecond();
break;

View File

@ -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;

View File

@ -749,6 +749,9 @@ void KnxSensor(byte sensor_type, float value)
#ifdef USE_KNX_WEB_MENU
const char S_CONFIGURE_KNX[] PROGMEM = D_CONFIGURE_KNX;
const char HTTP_BTN_MENU_KNX[] PROGMEM =
"<br/><form action='kn' method='get'><button>" D_CONFIGURE_KNX "</button></form>";
const char HTTP_FORM_KNX[] PROGMEM =
"<fieldset><legend style='text-align:left;'><b>&nbsp;" D_KNX_PARAMETERS "&nbsp;</b></legend><form method='post' action='kn'>"
"<br/><center>"
@ -784,7 +787,6 @@ const char HTTP_FORM_KNX_ADD_BTN[] PROGMEM =
const char HTTP_FORM_KNX_ADD_TABLE_ROW[] PROGMEM =
"<tr><td><b>{optex} -> GAfnum / GAarea / GAfdef </b></td>"
// "<td><button type='submit' name='btn_del_ga' value='{opval}' style='background-color: #eb1e1e;'> " D_DELETE " </button></td></tr>";
"<td><button type='submit' name='btn_del_ga' value='{opval}' class='button bred'> " D_DELETE " </button></td></tr>";
const char HTTP_FORM_KNX3[] PROGMEM =
@ -797,10 +799,8 @@ const char HTTP_FORM_KNX4[] PROGMEM =
const char HTTP_FORM_KNX_ADD_TABLE_ROW2[] PROGMEM =
"<tr><td><b>GAfnum / GAarea / GAfdef -> {optex}</b></td>"
// "<td><button type='submit' name='btn_del_cb' value='{opval}' style='background-color: #eb1e1e;'> " D_DELETE " </button></td></tr>";
"<td><button type='submit' name='btn_del_cb' value='{opval}' class='button bred'> " D_DELETE " </button></td></tr>";
void HandleKNXConfiguration()
{
if (HttpUser()) { return; }
@ -971,7 +971,7 @@ void HandleKNXConfiguration()
}
}
page += F("</table></center></fieldset>");
page += F("<br/><button name='save' type='submit'>" D_SAVE "</button></form></fieldset>");
page += F("<br/><button name='save' type='submit' class='button bgrn'>" D_SAVE "</button></form></fieldset>");
page += FPSTR(HTTP_BTN_CONF);
page.replace( F("</script>"),
@ -1295,6 +1295,16 @@ boolean Xdrv11(byte function)
case FUNC_PRE_INIT:
KNX_INIT();
break;
#ifdef USE_WEBSERVER
#ifdef USE_KNX_WEB_MENU
case FUNC_WEB_ADD_BUTTON:
strncat_P(mqtt_data, HTTP_BTN_MENU_KNX, sizeof(mqtt_data));
break;
case FUNC_WEB_ADD_HANDLER:
WebServer->on("/kn", HandleKNXConfiguration);
break;
#endif // USE_KNX_WEB_MENU
#endif // USE_WEBSERVER
case FUNC_LOOP:
knx.loop(); // Process knx events
break;

View File

@ -50,7 +50,7 @@ const char HASS_DISCOVER_LIGHT_DIMMER[] PROGMEM =
"\"brightness_value_template\":\"{{value_json." D_CMND_DIMMER "}}\"";
const char HASS_DISCOVER_LIGHT_COLOR[] PROGMEM =
"%s,\"rgb_command_topic\":\"%s\"," // cmnd/led2/Color
"%s,\"rgb_command_topic\":\"%s2\"," // cmnd/led2/Color2
"\"rgb_state_topic\":\"%s\"," // stat/led2/RESULT
"\"rgb_value_template\":\"{{value_json." D_CMND_COLOR "}}\"";
// "\"rgb_value_template\":\"{{value_json." D_CMND_COLOR " | join(',')}}\"";

View File

@ -19,6 +19,16 @@
--------------------------------------------------------------------------------------------
Version yyyymmdd Action Description
--------------------------------------------------------------------------------------------
1.0.0.4 20181003 added - MP3Reset command in case that the player do rare things
- and needs a reset, the default volume will be set again too
added - MP3_CMD_RESET_VALUE for the player reset function
cleaned - some comments and added function text header
fixed - missing void's in function calls
added - MP3_CMD_DAC command to switch off/on the dac outputs
tested - works with MP3Device 1 = USB STick, or MP3Device 2 = SD-Card
- after power and/or reset the SD-Card(2) is the default device
- DAC looks working too on a headset. Had no amplifier for test
---
1.0.0.3 20180915 added - select device for SD-Card or USB Stick, default will be SD-Card
tested - works by MP3Device 1 = USB STick, or MP3Device 2 = SD-Card
- after power and/or reset the SD-Card(2) is the default device
@ -61,13 +71,20 @@
TasmotaSerial *MP3Player;
/*********************************************************************************************\
* constants
\*********************************************************************************************/
#define D_CMND_MP3 "MP3"
const char S_JSON_MP3_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_MP3 "%s\":%d}";
const char S_JSON_MP3_COMMAND[] PROGMEM = "{\"" D_CMND_MP3 "%s\"}";
const char kMP3_Commands[] PROGMEM = "Track|Play|Pause|Stop|Volume|EQ|Device";
const char kMP3_Commands[] PROGMEM = "Track|Play|Pause|Stop|Volume|EQ|Device|Reset|DAC";
/*********************************************************************************************\
* enumerationsines
\*********************************************************************************************/
// enumerations
enum MP3_Commands { // commands useable in console or rules
CMND_MP3_TRACK, // MP3Track 001...255
CMND_MP3_PLAY, // MP3Play, after pause or normal start to play
@ -75,9 +92,17 @@ enum MP3_Commands { // commands useable in conso
CMND_MP3_STOP, // MP3Stop, real stop, original version was pause function
CMND_MP3_VOLUME, // MP3Volume 0..100
CMND_MP3_EQ, // MP3EQ 0..5
CMND_MP3_DEVICE }; // sd-card: 02, usb-stick: 01
CMND_MP3_DEVICE, // sd-card: 02, usb-stick: 01
CMND_MP3_RESET, // MP3Reset, a fresh and default restart
CMND_MP3_DAC }; // set dac, 1=off, 0=on, DAC is turned on (0) by default
// defines
/*********************************************************************************************\
* command defines
\*********************************************************************************************/
#define MP3_CMD_RESET_VALUE 0 // mp3 reset command value
// player commands
#define MP3_CMD_TRACK 0x03 // specify playback of a track, e.g. MP3Track 003
#define MP3_CMD_PLAY 0x0d // Play, works as a normal play on a real MP3 Player, starts at 001.mp3 file on the selected device
#define MP3_CMD_PAUSE 0x0e // Pause, was original designed as stop, see data sheet
@ -85,10 +110,14 @@ enum MP3_Commands { // commands useable in conso
#define MP3_CMD_VOLUME 0x06 // specifies the volume and means a console input as 0..100
#define MP3_CMD_EQ 0x07 // specify EQ(0/1/2/3/4/5), 0:Normal, 1:Pop, 2:Rock, 3:Jazz, 4:Classic, 5:Bass
#define MP3_CMD_DEVICE 0x09 // specify playback device, USB=1, SD-Card=2, default is 2 also after reset or power down/up
#define MP3_CMD_RESET 0x0C // send a reset command to start fresh
#define MP3_CMD_DAC 0x1A // activate or deactivate the DAC output for an external amplifier, DAC is turned on by default
/*********************************************************************************************\
* calculate the checksum
* starts with cmd[1] with a length of 6 bytes
\*********************************************************************************************/
// calculate the checksum
// starts with cmd[1] with a length of 6 bytes
//
uint16_t MP3_Checksum(uint8_t *array)
{
uint16_t checksum = 0;
@ -96,43 +125,58 @@ uint16_t MP3_Checksum(uint8_t *array)
checksum += array[i];
}
checksum = checksum^0xffff;
return checksum+1;
return (checksum+1);
}
// init player, define serial tx port
// fixed with 9600 baud
//
void MP3PlayerInit() {
/*********************************************************************************************\
* init player
* define serial tx port fixed with 9600 baud
\*********************************************************************************************/
void MP3PlayerInit(void) {
MP3Player = new TasmotaSerial(-1, pin[GPIO_MP3_DFR562]);
// start serial communication fixed to 9600 baud
if (MP3Player->begin(9600)) {
MP3Player->flush();
delay(1000); // set delay
// volume setting
MP3_CMD(MP3_CMD_VOLUME, MP3_VOLUME); // set volume depending on the entry in the user_config.h
delay(1000);
MP3_CMD(MP3_CMD_RESET, MP3_CMD_RESET_VALUE); // reset the player to defaults
delay(3000);
MP3_CMD(MP3_CMD_VOLUME, MP3_VOLUME); // after reset set volume depending on the entry in the user_config.h
}
return;
}
// create mp3 command payload and send it via serail interface to the MP3 player
// {start byte, version, length, command, feedback, para MSB, para LSB, chks MSB, chks LSB, end byte};
// {cmd[0] , cmd[1] , cmd[2], cmd[3] , cmd[4] , cmd[5] , cmd[6] , cmd[7] , cmd[8] , cmd[9] };
// {0x7e , 0xff , 6 , 0 , 0/1 , 0 , 0 , 0 , 0 , 0xef };
//
/*********************************************************************************************\
* create the MP3 commands payload, and send it via serial interface to the MP3 player
* data length is 6 = 6 bytes [FF 06 09 00 00 00] but not counting the start, end, and verification.
* {start byte, version, length, command, feedback, para MSB, para LSB, chks MSB, chks LSB, end byte};
* {cmd[0] , cmd[1] , cmd[2], cmd[3] , cmd[4] , cmd[5] , cmd[6] , cmd[7] , cmd[8] , cmd[9] };
* {0x7e , 0xff , 6 , 0 , 0/1 , 0 , 0 , 0 , 0 , 0xef };
\*********************************************************************************************/
void MP3_CMD(uint8_t mp3cmd,uint16_t val) {
uint8_t i = 0;
uint8_t cmd[10] = {0x7e,0xff,6,0,0,0,0,0,0,0xef}; // fill array
cmd[3] = mp3cmd; // mp3 command value
//cmd[4] = ; // feedback, yet not use
cmd[4] = 0; // feedback, 1=yes, 0=no, yet not use
cmd[5] = val>>8; // data value, shift 8 byte right
cmd[6] = val; // data value low byte
uint16_t chks = MP3_Checksum(&cmd[1]); // see calculate the checksum, line 62..72
uint16_t chks = MP3_Checksum(&cmd[1]); // see calculate the checksum
cmd[7] = chks>>8; // checksum. shift 8 byte right
cmd[8] = chks; // checksum low byte
MP3Player->write(cmd, sizeof(cmd)); // write mp3 data array to player
delay(1000);
if (mp3cmd == MP3_CMD_RESET) {
MP3_CMD(MP3_CMD_VOLUME, MP3_VOLUME); // after reset set volume depending on the entry in the user_config.h
}
return;
}
// check the MP3 commands
//
boolean MP3PlayerCmd() {
/*********************************************************************************************\
* check the MP3 commands
\*********************************************************************************************/
boolean MP3PlayerCmd(void) {
char command[CMDSZ];
boolean serviced = true;
uint8_t disp_len = strlen(D_CMND_MP3);
@ -145,27 +189,31 @@ boolean MP3PlayerCmd() {
case CMND_MP3_VOLUME:
case CMND_MP3_EQ:
case CMND_MP3_DEVICE:
case CMND_MP3_DAC:
// play a track, set volume, select EQ, sepcify file device
if (XdrvMailbox.data_len > 0) {
if (command_code == CMND_MP3_TRACK) { MP3_CMD(MP3_CMD_TRACK, XdrvMailbox.payload); }
if (command_code == CMND_MP3_VOLUME) { MP3_CMD(MP3_CMD_VOLUME, XdrvMailbox.payload * 30 / 100); }
if (command_code == CMND_MP3_EQ) { MP3_CMD(MP3_CMD_EQ, XdrvMailbox.payload); }
if (command_code == CMND_MP3_DEVICE) { MP3_CMD(MP3_CMD_DEVICE, XdrvMailbox.payload); }
if (command_code == CMND_MP3_DAC) { MP3_CMD(MP3_CMD_DAC, XdrvMailbox.payload); }
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND_NVALUE, command, XdrvMailbox.payload);
break;
case CMND_MP3_PLAY:
case CMND_MP3_PAUSE:
case CMND_MP3_STOP:
case CMND_MP3_RESET:
// play or re-play after pause, pause, stop,
if (command_code == CMND_MP3_PLAY) { MP3_CMD(MP3_CMD_PLAY, 0); }
if (command_code == CMND_MP3_PAUSE) { MP3_CMD(MP3_CMD_PAUSE, 0); }
if (command_code == CMND_MP3_STOP) { MP3_CMD(MP3_CMD_STOP, 0); }
if (command_code == CMND_MP3_RESET) { MP3_CMD(MP3_CMD_RESET, 0); }
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_MP3_COMMAND, command, XdrvMailbox.payload);
break;
default:
// else for Unknown command
serviced = false;
// else for Unknown command
serviced = false;
break;
}
}

View File

@ -26,8 +26,13 @@
#define PCA9685_REG_LED0_ON_L 0x06
#define PCA9685_REG_PRE_SCALE 0xFE
#ifndef USE_PCA9685_FREQ
#define USE_PCA9685_FREQ 50
#endif
uint8_t pca9685_detected = 0;
uint16_t pca9685_freq = 50;
uint16_t pca9685_freq = USE_PCA9685_FREQ;
uint16_t pca9685_pin_pwm_value[16];
void PCA9685_Detect(void)
{
@ -51,9 +56,10 @@ void PCA9685_Detect(void)
void PCA9685_Reset(void)
{
I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, 0x80);
PCA9685_SetPWMfreq(50);
PCA9685_SetPWMfreq(USE_PCA9685_FREQ);
for (uint8_t pin=0;pin<16;pin++) {
PCA9685_SetPWM(pin,0,false);
PCA9685_SetPWM(pin,0,false);
pca9685_pin_pwm_value[pin] = 0;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"RESET\":\"OK\"}}"));
}
@ -63,9 +69,13 @@ void PCA9685_SetPWMfreq(double freq) {
7.3.5 from datasheet
prescale value = round(25000000/(4096*freq))-1;
*/
pca9685_freq=freq;
uint8_t pre_scale_osc = round(25000000/(4096*freq))-1;
if (1526 == freq) pre_scale_osc=0xFF; // force setting for 24hz because rounding causes 1526 to be 254
if (freq > 23 && freq < 1527) {
pca9685_freq=freq;
} else {
pca9685_freq=50;
}
uint8_t pre_scale_osc = round(25000000/(4096*pca9685_freq))-1;
if (1526 == pca9685_freq) pre_scale_osc=0xFF; // force setting for 24hz because rounding causes 1526 to be 254
uint8_t current_mode1 = I2cRead8(USE_PCA9685_ADDR, PCA9685_REG_MODE1); // read current value of MODE1 register
uint8_t sleep_mode1 = (current_mode1&0x7F) | 0x10; // Determine register value to put PCA to sleep
I2cWrite8(USE_PCA9685_ADDR, PCA9685_REG_MODE1, sleep_mode1); // Let's sleep a little
@ -88,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)
@ -107,14 +118,17 @@ bool PCA9685_Command(void)
if (',' == XdrvMailbox.data[ca]) { paramcount++; }
}
UpperCase(XdrvMailbox.data,XdrvMailbox.data);
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));
if ((new_freq >= 24) && (new_freq <= 1526)) {
PCA9685_SetPWMfreq(new_freq);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PWMF\":%i, \"Result\":\"OK\"}}"));
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"PCA9685\":{\"PWMF\":%i, \"Result\":\"OK\"}}"),new_freq);
return serviced;
}
} else { // No parameter was given for setfreq, so we return current setting
@ -151,28 +165,36 @@ bool PCA9685_Command(void)
return serviced;
}
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);
for (uint8_t pin=0;pin<16;pin++) {
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);
if (telemetry) {
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
}
}
boolean Xdrv15(byte function)
{
boolean result = false;
if (i2c_flg) {
switch (function) {
case FUNC_MQTT_DATA:
break;
case FUNC_EVERY_SECOND:
PCA9685_Detect();
break;
case FUNC_EVERY_50_MSECOND:
break;
case FUNC_JSON_APPEND:
if (tele_period == 0) {
PCA9685_OutputTelemetry(true);
}
break;
case FUNC_COMMAND:
if (XDRV_15 == XdrvMailbox.index) {
PCA9685_Command();
}
break;
case FUNC_WEB_APPEND:
break;
default:
break;
}

View File

@ -27,22 +27,21 @@
#define XNRG_01 1
// HLW8012 based (Sonoff Pow, KMC70011, HuaFan)
// Energy model type 0 (GPIO_HLW_CF) - HLW8012 based (Sonoff Pow, KMC70011, HuaFan, AplicWDP303075)
#define HLW_PREF 10000 // 1000.0W
#define HLW_UREF 2200 // 220.0V
#define HLW_IREF 4545 // 4.545A
#define HLW_SEL_VOLTAGE 1
// HJL-01 based (BlitzWolf, Homecube, Gosund)
// Energy model type 1 (GPIO_HJL_CF) - HJL-01/BL0937 based (BlitzWolf, Homecube, Gosund, Teckin)
#define HJL_PREF 1362
#define HJL_UREF 822
#define HJL_IREF 3300
#define HJL_SEL_VOLTAGE 0
#define HLW_POWER_PROBE_TIME 10 // Number of seconds to probe for power before deciding none used
byte hlw_select_ui_flag;
byte hlw_ui_flag = 1;
byte hlw_model_type = 0;
byte hlw_load_off;
byte hlw_cf1_timer;
unsigned long hlw_cf_pulse_length;
@ -120,7 +119,7 @@ void HlwEvery200ms()
if (hlw_cf1_timer >= 8) {
hlw_cf1_timer = 0;
hlw_select_ui_flag = (hlw_select_ui_flag) ? 0 : 1;
digitalWrite(pin[GPIO_HLW_SEL], hlw_select_ui_flag);
digitalWrite(pin[GPIO_NRG_SEL], hlw_select_ui_flag);
if (hlw_cf1_pulse_counter) {
hlw_cf1_pulse_length = hlw_cf1_summed_pulse_length / hlw_cf1_pulse_counter;
@ -177,16 +176,14 @@ void HlwSnsInit()
Settings.energy_current_calibration = HLW_IREF_PULSE;
}
if (BLITZWOLF_BWSHP2 == Settings.module) {
if (hlw_model_type) {
hlw_power_ratio = HJL_PREF;
hlw_voltage_ratio = HJL_UREF;
hlw_current_ratio = HJL_IREF;
hlw_ui_flag = HJL_SEL_VOLTAGE;
} else {
hlw_power_ratio = HLW_PREF;
hlw_voltage_ratio = HLW_UREF;
hlw_current_ratio = HLW_IREF;
hlw_ui_flag = HLW_SEL_VOLTAGE;
}
hlw_cf_pulse_length = 0;
@ -203,10 +200,10 @@ void HlwSnsInit()
hlw_select_ui_flag = 0; // Voltage;
pinMode(pin[GPIO_HLW_SEL], OUTPUT);
digitalWrite(pin[GPIO_HLW_SEL], hlw_select_ui_flag);
pinMode(pin[GPIO_HLW_CF1], INPUT_PULLUP);
attachInterrupt(pin[GPIO_HLW_CF1], HlwCf1Interrupt, FALLING);
pinMode(pin[GPIO_NRG_SEL], OUTPUT);
digitalWrite(pin[GPIO_NRG_SEL], hlw_select_ui_flag);
pinMode(pin[GPIO_NRG_CF1], INPUT_PULLUP);
attachInterrupt(pin[GPIO_NRG_CF1], HlwCf1Interrupt, FALLING);
pinMode(pin[GPIO_HLW_CF], INPUT_PULLUP);
attachInterrupt(pin[GPIO_HLW_CF], HlwCfInterrupt, FALLING);
@ -216,7 +213,21 @@ void HlwSnsInit()
void HlwDrvInit()
{
if (!energy_flg) {
if ((pin[GPIO_HLW_SEL] < 99) && (pin[GPIO_HLW_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)) { // Sonoff Pow or any HLW8012 based device
hlw_model_type = 0;
if (pin[GPIO_HJL_CF] < 99) {
pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF];
pin[GPIO_HJL_CF] = 99;
hlw_model_type = 1;
}
hlw_ui_flag = 1;
if (pin[GPIO_NRG_SEL_INV] < 99) {
pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV];
pin[GPIO_NRG_SEL_INV] = 99;
hlw_ui_flag = 0;
}
if ((pin[GPIO_NRG_SEL] < 99) && (pin[GPIO_NRG_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)) { // HLW8012 or HJL-01 based device
energy_flg = XNRG_01;
}
}

View File

@ -835,4 +835,18 @@ void HandleHueApi(String *path)
else if (path->endsWith("/rules")) HueNotImplemented(path);
else HueGlobalConfig(path);
}
void HueWemoAddHandlers()
{
if (EMUL_WEMO == Settings.flag2.emulation) {
WebServer->on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent);
WebServer->on("/eventservice.xml", HandleUpnpService);
WebServer->on("/metainfoservice.xml", HandleUpnpMetaService);
WebServer->on("/setup.xml", HandleUpnpSetupWemo);
}
if (EMUL_HUE == Settings.flag2.emulation) {
WebServer->on("/description.xml", HandleUpnpSetupHue);
}
}
#endif // USE_WEBSERVER && USE_EMULATION

View File

@ -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 {

View File

@ -31,6 +31,9 @@
Version Date Action Description
--------------------------------------------------------------------------------------------
1.0.0.3 20181006 fixed - missing "" around the UV Index text
- thanks to Lisa she had tested it on here mqtt system.
--
1.0.0.2 20180928 tests - same as in version 1.0.0.1
cleaned - source code
changed - snprintf_P for json and web server output
@ -77,9 +80,9 @@
- show not only the UV Power value in W/m2, possible a @define value to show it as joule value
- add a #define to select how many characters are shown benhind the decimal point for the UV Index
---
1.0.0.0 20180912 started - further development by mike2nl - https://github.com/mike2nl/Sonoff-Tasmota
forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota
base - code base from arendst too
1.0.0.0 20180912 started - further development by mike2nl - https://github.com/mike2nl/Sonoff-Tasmota
forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota
base - code base from arendst too
*/
@ -168,11 +171,11 @@ void Veml6070EverySecond(void)
{
// all = 10..15[ms]
if (11 == (uptime %100)) {
Veml6070ModeCmd(1); // on = 1[ms], wakeup the UV sensor
Veml6070ModeCmd(1); // on = 1[ms], wakeup the UV sensor
Veml6070Detect(); // 1[ms], check for sensor and init with IT time
Veml6070ModeCmd(0); // off = 5[ms], suspend the UV sensor
} else {
Veml6070ModeCmd(1); // 1[ms], wakeup the UV sensor
Veml6070ModeCmd(1); // 1[ms], wakeup the UV sensor
uvlevel = Veml6070ReadUv(); // 1..2[ms], get UV raw values
uvrisk = Veml6070UvRiskLevel(uvlevel); // 0..1[ms], get UV risk level
uvpower = Veml6070UvPower(uvrisk); // 2[ms], get UV power in W/m2
@ -277,10 +280,10 @@ void Veml6070Show(boolean json)
dtostrfd(uvpower, 3, str_uvpower);
if (json) {
#ifdef USE_VEML6070_SHOW_RAW
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_LEVEL "\":%s,\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":%s,\"" D_JSON_UV_POWER "\":%s}"),
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_LEVEL "\":%s,\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"),
mqtt_data, veml6070_name, str_uvlevel, str_uvrisk, str_uvrisk_text, str_uvpower);
#else
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":%s,\"" D_JSON_UV_POWER "\":%s}"),
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_UV_INDEX "\":%s,\"" D_JSON_UV_INDEX_TEXT "\":\"%s\",\"" D_JSON_UV_POWER "\":%s}"),
mqtt_data, veml6070_name, str_uvrisk, str_uvrisk_text, str_uvpower);
#endif // USE_VEML6070_SHOW_RAW
#ifdef USE_DOMOTICZ

View File

@ -39,7 +39,7 @@
* I2C Address: 0x39
\*********************************************************************************************/
#if defined(USE_SHT) || defined(USE_VEML6070)
#if defined(USE_SHT) || defined(USE_VEML6070) || defined(USE_TSL2561)
#warning **** Turned off conflicting drivers SHT and VEML6070 ****
#ifdef USE_SHT
#undef USE_SHT // SHT-Driver blocks gesture sensor
@ -47,6 +47,9 @@
#ifdef USE_VEML6070
#undef USE_VEML6070 // address conflict on the I2C-bus
#endif
#ifdef USE_TSL2561
#undef USE_TSL2561 // possible address conflict on the I2C-bus
#endif
#endif
#define APDS9960_I2C_ADDR 0x39
@ -64,10 +67,11 @@
uint8_t APDS9960addr;
uint8_t APDS9960type = 0;
char APDS9960stype[7];
char APDS9960stype[9];
char currentGesture[6];
uint8_t gesture_mode = 1;
volatile uint8_t recovery_loop_counter = 0; //count number of stateloops to switch the sensor off, if needed
#define APDS9960_LONG_RECOVERY 50 //long pause after sensor overload in loops
#define APDS9960_MAX_GESTURE_CYCLES 50 //how many FIFO-reads are allowed to prevent crash
@ -78,8 +82,7 @@ const char HTTP_APDS_9960_SNS[] PROGMEM = "%s"
"{s}" "Red" "{m}%s{e}"
"{s}" "Green" "{m}%s{e}"
"{s}" "Blue" "{m}%s{e}"
"{s}" "Ambient" "{m}%s{e}"
"{s}" "Illuminance" "{m}%s " D_UNIT_LUX "{e}"
"{s}" "Ambient" "{m}%s " D_UNIT_LUX "{e}"
"{s}" "CCT" "{m}%s " "K" "{e}" // calculated color temperature in Kelvin
"{s}" "Proximity" "{m}%s{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
#endif // USE_WEBSERVER
@ -209,7 +212,7 @@ const char HTTP_APDS_9960_SNS[] PROGMEM = "%s"
#define GWTIME_39_2MS 7
/* Default values */
#define DEFAULT_ATIME 219 // 103ms
#define DEFAULT_ATIME 0xdb // 103ms = 0xdb
#define DEFAULT_WTIME 246 // 27ms
#define DEFAULT_PROX_PPULSE 0x87 // 16us, 8 pulses
#define DEFAULT_GESTURE_PPULSE 0x89 // 16us, 10 pulses ---89
@ -218,7 +221,7 @@ const char HTTP_APDS_9960_SNS[] PROGMEM = "%s"
#define DEFAULT_CONFIG1 0x60 // No 12x wait (WTIME) factor
#define DEFAULT_LDRIVE LED_DRIVE_100MA
#define DEFAULT_PGAIN PGAIN_4X
#define DEFAULT_AGAIN AGAIN_4X
#define DEFAULT_AGAIN AGAIN_4X // we have to divide by the same facot at the end
#define DEFAULT_PILT 0 // Low proximity threshold
#define DEFAULT_PIHT 50 // High proximity threshold
#define DEFAULT_AILT 0xFFFF // Force interrupt for calibration
@ -287,6 +290,7 @@ typedef struct gesture_data_type {
} color_data_type;
color_data_type color_data;
uint8_t APDS9960_aTime = DEFAULT_ATIME;
/*******************************************************************************
@ -360,7 +364,7 @@ void calculateColorTemperature()
/* and 60W incandescent values for a wide range. */
/* Note: Y = Illuminance or lux */
X = (-0.14282F * color_data.r) + (1.54924F * color_data.g) + (-0.95641F * color_data.b);
Y = (-0.32466F * color_data.r) + (1.57837F * color_data.g) + (-0.73191F * color_data.b); // this is Lux
Y = (-0.32466F * color_data.r) + (1.57837F * color_data.g) + (-0.73191F * color_data.b); // this is Lux ... under certain circumstances
Z = (-0.68202F * color_data.r) + (0.77073F * color_data.g) + ( 0.56332F * color_data.b);
/* 2. Calculate the chromaticity co-ordinates */
@ -372,7 +376,6 @@ void calculateColorTemperature()
/* Calculate the final CCT */
color_data.cct = (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F;
color_data.lux = Y; // according to Adafruit code comments this seems to be not a perfect solution
return;
}
@ -1611,7 +1614,7 @@ void readAllColorAndProximityData()
if (I2cReadBuffer(APDS9960_I2C_ADDR, APDS9960_CDATAL, (uint8_t *) &color_data, (uint16_t)9))
{
// not absolutely shure, if this is a correct way to do this, but it is very short
// we fill the struct byte by byte
// we fill the struct byte by byte
}
}
@ -1803,11 +1806,11 @@ void handleGesture() {
break;
case DIR_LEFT:
snprintf_P(log, sizeof(log), PSTR("LEFT"));
snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Left"));
snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Left"));
break;
case DIR_RIGHT:
snprintf_P(log, sizeof(log), PSTR("RIGHT"));
snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Right"));
snprintf_P(currentGesture, sizeof(currentGesture), PSTR("Right"));
break;
default:
if(APDS9960_overload)
@ -1832,6 +1835,41 @@ void handleGesture() {
}
}
void APDS9960_adjustATime(void) // not really used atm
{
//readAllColorAndProximityData();
I2cValidRead16LE(&color_data.a, APDS9960_I2C_ADDR, APDS9960_CDATAL);
//disablePower();
if (color_data.a < (uint16_t)20){
APDS9960_aTime = 0x40;
}
else if (color_data.a < (uint16_t)40){
APDS9960_aTime = 0x80;
}
else if (color_data.a < (uint16_t)50){
APDS9960_aTime = DEFAULT_ATIME;
}
else if (color_data.a < (uint16_t)70){
APDS9960_aTime = 0xc0;
}
if (color_data.a < 200){
APDS9960_aTime = 0xe9;
}
/* if (color_data.a < 10000){
APDS9960_aTime = 0xF0;
}*/
else{
APDS9960_aTime = 0xff;
}
//disableLightSensor();
I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, APDS9960_aTime);
enablePower();
enableLightSensor();
delay(20);
}
void APDS9960_loop()
{
@ -1910,29 +1948,30 @@ void APDS9960_show(boolean json)
char green_chr[10];
char blue_chr[10];
char ambient_chr[10];
char illuminance_chr[10];
char cct_chr[10];
char prox_chr[10];
readAllColorAndProximityData();
sprintf (ambient_chr, "%u", color_data.a);
sprintf (ambient_chr, "%u", color_data.a/4);
sprintf (red_chr, "%u", color_data.r);
sprintf (green_chr, "%u", color_data.g);
sprintf (blue_chr, "%u", color_data.b );
sprintf (prox_chr, "%u", color_data.p );
/* disableLightSensor();
I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, DEFAULT_ATIME); // reset to default
enableLightSensor();*/
calculateColorTemperature(); // and calculate Lux
sprintf (cct_chr, "%u", color_data.cct);
sprintf (illuminance_chr, "%u", color_data.lux);
if (json) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"Red\":%s,\"Green\":%s,\"Blue\":%s,\"Ambient\":%s,\"Illuminance\":%s,\"CCT\":%s,\"Proximity\":%s}"),
mqtt_data, APDS9960stype, red_chr, green_chr, blue_chr, ambient_chr, illuminance_chr, cct_chr, prox_chr);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"Red\":%s,\"Green\":%s,\"Blue\":%s,\"Ambient\":%s,\"CCT\":%s,\"Proximity\":%s}"),
mqtt_data, APDS9960stype, red_chr, green_chr, blue_chr, ambient_chr, cct_chr, prox_chr);
#ifdef USE_WEBSERVER
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_APDS_9960_SNS, mqtt_data, red_chr, green_chr, blue_chr, ambient_chr, illuminance_chr, cct_chr, prox_chr );
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_APDS_9960_SNS, mqtt_data, red_chr, green_chr, blue_chr, ambient_chr, cct_chr, prox_chr );
#endif // USE_WEBSERVER
}
}
@ -1952,6 +1991,7 @@ void APDS9960_show(boolean json)
* Sensor27 | | Show current gesture mode
* Sensor27 | 0 / Off | Disable gesture mode
* Sensor27 | 1 / On | Enable gesture mode
* Sensor27 | 2 / On | Enable gesture mode with half gain
\*********************************************************************************************/
bool APDS9960CommandSensor()
@ -1973,7 +2013,8 @@ bool APDS9960CommandSensor()
enableGestureSensor();
gesture_mode = 1;
}
case 2:
break;
case 2: // gain of 2x , needed for some models
if (APDS9960type) {
setGestureGain(GGAIN_2X);
setProximityGain(PGAIN_2X);
@ -1981,6 +2022,16 @@ bool APDS9960CommandSensor()
enableGestureSensor();
gesture_mode = 1;
}
break;
default:
int temp_aTime = (uint8_t)XdrvMailbox.payload;
if (temp_aTime > 2 && temp_aTime < 256){
disablePower();
I2cWrite8(APDS9960_I2C_ADDR, APDS9960_ATIME, temp_aTime);
enablePower();
enableLightSensor();
}
break;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SENSOR_INDEX_SVALUE, XSNS_27, GetStateText(gesture_mode));

View File

@ -20,7 +20,7 @@
#ifdef USE_I2C
#ifdef USE_CCS811
/*********************************************************************************************\
* SGP30 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2)
* CCS811 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2)
*
* Source: Adafruit
*

Some files were not shown because too many files have changed in this diff Show More