mirror of https://github.com/arendst/Tasmota.git
Merge branch 'arendst/development' into development
This commit is contained in:
commit
4fd9b5b4b5
|
@ -0,0 +1,6 @@
|
|||
Make sure these boxes are checked before submitting your issue - Thank you!
|
||||
|
||||
- [ ] What hardware you are using
|
||||
- [ ] Provide the output of command ``status 0``
|
||||
- [ ] If you have a stack dump decode it: https://github.com/esp8266/Arduino/blob/master/doc/Troubleshooting/stack_dump.rst
|
||||
- [ ] For better debug messages: https://github.com/esp8266/Arduino/blob/master/doc/Troubleshooting/debugging.rst
|
|
@ -0,0 +1,28 @@
|
|||
# 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
|
||||
._*
|
|
@ -0,0 +1,8 @@
|
|||
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
|
|
@ -0,0 +1,102 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
#include <ESP8266WiFi.h>
|
||||
#include <TasmotaMqtt.h>
|
||||
|
||||
// This needs testing
|
||||
|
||||
void myDataCb(char* topic, uint8_t* data, unsigned int data_len);
|
||||
void myPublishedCb();
|
||||
void myDisconnectedCb();
|
||||
void myConnectedCb();
|
||||
|
||||
#define CLIENT_ID "client3"
|
||||
#define TOPIC "/client1/value"
|
||||
|
||||
// create MQTT
|
||||
TasmotaMqtt myMqtt();
|
||||
|
||||
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");
|
||||
|
||||
myMqtt.InitConnection("192.168.0.1", 1883);
|
||||
myMqtt.InitClient(CLIENT_ID, "", "");
|
||||
myMqtt.InitLWT("/lwt", "offline");
|
||||
|
||||
// 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(char* topic, uint8_t* data, unsigned int data_len)
|
||||
{
|
||||
Serial.print(topic);
|
||||
Serial.print(": ");
|
||||
Serial.println(data);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Test
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
TasmotaMqtt.h KEYWORD1
|
||||
TasmotaMqtt KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
InitConnection KEYWORD2
|
||||
InitClient KEYWORD2
|
||||
InitLWT KEYWORD2
|
||||
|
||||
Connect KEYWORD2
|
||||
Disconnect KEYWORD2
|
||||
Connected KEYWORD2
|
||||
|
||||
Publish KEYWORD2
|
||||
Subscribe KEYWORD2
|
||||
|
||||
#general
|
||||
OnConnected KEYWORD2
|
||||
OnDisconnected KEYWORD2
|
||||
OnData KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
name=TasmotaMqtt
|
||||
version=1.0.0
|
||||
author=Theo Arends
|
||||
maintainer=Theo Arends <theo@arends.com>
|
||||
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 Original code for contiki: https://github.com/esar/contiki-mqtt
|
||||
category=Communication
|
||||
url=
|
||||
architectures=esp8266
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
TasmotaMqtt.cpp - Wrapper for mqtt for esp8266 by Tuan PM for Tasmota
|
||||
|
||||
Copyright (C) 2018 Theo Arends and Ingo Randolf
|
||||
|
||||
This library 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/>.
|
||||
*/
|
||||
|
||||
#include "TasmotaMqtt.h"
|
||||
|
||||
#include "user_interface.h"
|
||||
#include "osapi.h"
|
||||
#include "os_type.h"
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Prerequisite
|
||||
*
|
||||
* Copy .c and .h files from https://github.com/tuanpmt/esp_mqtt folder mqtt to folder mqtt
|
||||
* - Replace BOOL with bool
|
||||
* - Remove variables certificate and private_key from file mqtt.c
|
||||
* - Add file user_config.h with default defines for
|
||||
* MQTT_BUF_SIZE 256, MQTT_RECONNECT_TIMEOUT 5, QUEUE_BUFFER_SIZE 2048 and PROTOCOL_NAMEv311
|
||||
\*********************************************************************************************/
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Mqtt internal callbacks
|
||||
\*********************************************************************************************/
|
||||
|
||||
static void mqttConnectedCb(uint32_t *args)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
TasmotaMqtt* _this = (TasmotaMqtt*)client->user_data;
|
||||
if (_this && _this->onMqttConnectedCb) _this->onMqttConnectedCb();
|
||||
}
|
||||
|
||||
static void mqttDisconnectedCb(uint32_t *args)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
TasmotaMqtt* _this = (TasmotaMqtt*)client->user_data;
|
||||
if (_this && _this->onMqttDisconnectedCb) _this->onMqttDisconnectedCb();
|
||||
}
|
||||
|
||||
static void mqttPublishedCb(uint32_t *args)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
TasmotaMqtt* _this = (TasmotaMqtt*)client->user_data;
|
||||
if (_this && _this->onMqttPublishedCb) _this->onMqttPublishedCb();
|
||||
}
|
||||
|
||||
static void mqttTimeoutCb(uint32_t *args)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
TasmotaMqtt* _this = (TasmotaMqtt*)client->user_data;
|
||||
if (_this && _this->onMqttTimeoutCb) _this->onMqttTimeoutCb();
|
||||
}
|
||||
|
||||
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;
|
||||
TasmotaMqtt* _this = (TasmotaMqtt*)client->user_data;
|
||||
if (_this) _this->_onMqttDataCb(topic, topic_len, data, data_len);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* TasmotaMqtt class implementation
|
||||
\*********************************************************************************************/
|
||||
|
||||
TasmotaMqtt::TasmotaMqtt() :
|
||||
onMqttConnectedCb(0),
|
||||
onMqttDisconnectedCb(0),
|
||||
onMqttPublishedCb(0),
|
||||
onMqttTimeoutCb(0),
|
||||
onMqttDataCb(0)
|
||||
{
|
||||
}
|
||||
|
||||
TasmotaMqtt::~TasmotaMqtt()
|
||||
{
|
||||
MQTT_DeleteClient(&mqttClient);
|
||||
}
|
||||
|
||||
void TasmotaMqtt::InitConnection(const char* host, uint32_t port, uint8_t security)
|
||||
{
|
||||
MQTT_InitConnection(&mqttClient, (uint8_t*)host, port, security);
|
||||
|
||||
// set user data
|
||||
mqttClient.user_data = (void*)this;
|
||||
|
||||
MQTT_OnConnected(&mqttClient, mqttConnectedCb);
|
||||
MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
|
||||
MQTT_OnPublished(&mqttClient, mqttPublishedCb);
|
||||
MQTT_OnTimeout(&mqttClient, mqttTimeoutCb);
|
||||
MQTT_OnData(&mqttClient, mqttDataCb);
|
||||
}
|
||||
|
||||
void TasmotaMqtt::InitClient(const char* client_id, const char* client_user, const char* client_pass, uint32_t keep_alive_time, uint8_t clean_session)
|
||||
{
|
||||
MQTT_InitClient(&mqttClient, (uint8_t*)client_id, (uint8_t*)client_user, (uint8_t*)client_pass, keep_alive_time, clean_session);
|
||||
}
|
||||
|
||||
void TasmotaMqtt::DeleteClient()
|
||||
{
|
||||
MQTT_DeleteClient(&mqttClient);
|
||||
}
|
||||
|
||||
void TasmotaMqtt::InitLWT(const char* will_topic, const char* will_msg, uint8_t will_qos, bool will_retain)
|
||||
{
|
||||
MQTT_InitLWT(&mqttClient, (uint8_t*)will_topic, (uint8_t*)will_msg, will_qos, (uint8_t)will_retain);
|
||||
}
|
||||
|
||||
void TasmotaMqtt::OnConnected( void (*function)(void) )
|
||||
{
|
||||
onMqttConnectedCb = function;
|
||||
}
|
||||
|
||||
void TasmotaMqtt::OnDisconnected( void (*function)(void) )
|
||||
{
|
||||
onMqttDisconnectedCb = function;
|
||||
}
|
||||
|
||||
void TasmotaMqtt::OnPublished( void (*function)(void) )
|
||||
{
|
||||
onMqttPublishedCb = function;
|
||||
}
|
||||
|
||||
void TasmotaMqtt::OnTimeout( void (*function)(void) )
|
||||
{
|
||||
onMqttTimeoutCb = function;
|
||||
}
|
||||
|
||||
void TasmotaMqtt::OnData( void (*function)(char*, uint8_t*, unsigned int) )
|
||||
{
|
||||
onMqttDataCb = function;
|
||||
}
|
||||
|
||||
bool TasmotaMqtt::Subscribe(const char* topic, uint8_t qos)
|
||||
{
|
||||
return MQTT_Subscribe(&mqttClient, (char*)topic, qos);
|
||||
}
|
||||
|
||||
bool TasmotaMqtt::Unsubscribe(const char* topic)
|
||||
{
|
||||
return MQTT_UnSubscribe(&mqttClient, (char*)topic);
|
||||
}
|
||||
|
||||
void TasmotaMqtt::Connect()
|
||||
{
|
||||
MQTT_Connect(&mqttClient);
|
||||
}
|
||||
|
||||
void TasmotaMqtt::Connect(const char* client_id, const char* client_user, const char* client_pass, const char* will_topic, const char* will_msg, uint8_t will_qos, bool will_retain)
|
||||
{
|
||||
MQTT_InitClient(&mqttClient, (uint8_t*)client_id, (uint8_t*)client_user, (uint8_t*)client_pass, MQTT_KEEPALIVE, 1);
|
||||
MQTT_InitLWT(&mqttClient, (uint8_t*)will_topic, (uint8_t*)will_msg, will_qos, (uint8_t)will_retain);
|
||||
MQTT_Connect(&mqttClient);
|
||||
}
|
||||
|
||||
void TasmotaMqtt::Disconnect()
|
||||
{
|
||||
MQTT_Disconnect(&mqttClient);
|
||||
}
|
||||
|
||||
bool TasmotaMqtt::Publish(const char* topic, const char* data, int data_length, int qos, bool retain)
|
||||
{
|
||||
return MQTT_Publish(&mqttClient, topic, data, data_length, qos, (int)retain);
|
||||
}
|
||||
|
||||
bool TasmotaMqtt::Connected()
|
||||
{
|
||||
return (mqttClient.connState > TCP_CONNECTED);
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void TasmotaMqtt::_onMqttDataCb(const char* topic, uint32_t topic_len, const char* data, uint32_t data_len)
|
||||
{
|
||||
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;
|
||||
onMqttDataCb((char*)topic_copy, (byte*)data, data_len);
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
TasmotaMqtt.h - Wrapper for mqtt for esp8266 by Tuan PM for Tasmota
|
||||
|
||||
Copyright (C) 2018 Theo Arends and Ingo Randolf
|
||||
|
||||
This library 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 TasmotaMqtt_h
|
||||
#define TasmotaMqtt_h
|
||||
/*********************************************************************************************\
|
||||
* TasmotaMqtt supports currently only non-TLS MQTT
|
||||
*
|
||||
* Adapted from esp-mqtt-arduino by Ingo Randolf (https://github.com/i-n-g-o/esp-mqtt-arduino)
|
||||
\*********************************************************************************************/
|
||||
|
||||
#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"
|
||||
}
|
||||
|
||||
// MQTT_KEEPALIVE : keepAlive interval in Seconds
|
||||
#ifndef MQTT_KEEPALIVE
|
||||
#define MQTT_KEEPALIVE 15
|
||||
#endif
|
||||
|
||||
class TasmotaMqtt {
|
||||
public:
|
||||
TasmotaMqtt();
|
||||
~TasmotaMqtt();
|
||||
|
||||
void InitConnection(const char* host, uint32_t port, uint8_t security = 0);
|
||||
void InitClient(const char* client_id, const char* client_user, const char* client_pass, uint32_t keep_alive_time = MQTT_KEEPALIVE, uint8_t clean_session = 1);
|
||||
void DeleteClient();
|
||||
void InitLWT(const char* will_topic, const char* will_msg, uint8_t will_qos = 0, bool will_retain = false);
|
||||
|
||||
void OnConnected( void (*)(void) );
|
||||
void OnDisconnected( void (*)(void) );
|
||||
void OnPublished( void (*)(void) );
|
||||
void OnTimeout( void (*)(void) );
|
||||
void OnData( void (*)(char*, uint8_t*, unsigned int) );
|
||||
|
||||
bool Subscribe(const char* topic, uint8_t qos = 0);
|
||||
bool Unsubscribe(const char* topic);
|
||||
|
||||
void Connect();
|
||||
void Connect(const char* client_id, const char* client_user, const char* client_pass, const char* will_topic, const char* will_msg, uint8_t will_qos = 0, bool will_retain = false);
|
||||
void Disconnect();
|
||||
|
||||
bool Publish(const char* topic, const char* data, int data_length, int qos = 0, bool retain = false);
|
||||
|
||||
bool Connected();
|
||||
|
||||
int State() { return mqttClient.connState; };
|
||||
|
||||
void (*onMqttConnectedCb)(void);
|
||||
void (*onMqttDisconnectedCb)(void);
|
||||
void (*onMqttPublishedCb)(void);
|
||||
void (*onMqttTimeoutCb)(void);
|
||||
void (*onMqttDataCb) (char*, uint8_t*, unsigned int);
|
||||
|
||||
// internal callback
|
||||
void _onMqttDataCb(const char*, uint32_t, const char*, uint32_t);
|
||||
|
||||
private:
|
||||
MQTT_Client mqttClient;
|
||||
};
|
||||
|
||||
#endif // TasmotaMqtt_h
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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_ */
|
|
@ -0,0 +1,997 @@
|
|||
/* mqtt.c
|
||||
* Protocol: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
|
||||
*
|
||||
* 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 "user_interface.h"
|
||||
#include "osapi.h"
|
||||
#include "espconn.h"
|
||||
#include "os_type.h"
|
||||
#include "mem.h"
|
||||
#include "mqtt_msg.h"
|
||||
#include "debug.h"
|
||||
#include "user_config.h"
|
||||
#include "mqtt.h"
|
||||
#include "queue.h"
|
||||
|
||||
#define MQTT_TASK_PRIO 2
|
||||
#define MQTT_TASK_QUEUE_SIZE 1
|
||||
#define MQTT_SEND_TIMOUT 5
|
||||
|
||||
#ifndef MQTT_SSL_SIZE
|
||||
#define MQTT_SSL_SIZE 5120
|
||||
#endif
|
||||
|
||||
#ifndef QUEUE_BUFFER_SIZE
|
||||
#define QUEUE_BUFFER_SIZE 2048
|
||||
#endif
|
||||
|
||||
/*
|
||||
unsigned char *default_certificate;
|
||||
unsigned int default_certificate_len = 0;
|
||||
unsigned char *default_private_key;
|
||||
unsigned int default_private_key_len = 0;
|
||||
*/
|
||||
|
||||
os_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE];
|
||||
|
||||
#ifdef PROTOCOL_NAMEv311
|
||||
LOCAL uint8_t zero_len_id[2] = { 0, 0 };
|
||||
#endif
|
||||
|
||||
LOCAL void ICACHE_FLASH_ATTR
|
||||
mqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
|
||||
{
|
||||
struct espconn *pConn = (struct espconn *)arg;
|
||||
MQTT_Client* client = (MQTT_Client *)pConn->reverse;
|
||||
|
||||
|
||||
if (ipaddr == NULL)
|
||||
{
|
||||
MQTT_INFO("DNS: Found, but got no ip, try to reconnect\r\n");
|
||||
client->connState = TCP_RECONNECT_REQ;
|
||||
return;
|
||||
}
|
||||
|
||||
MQTT_INFO("DNS: found ip %d.%d.%d.%d\n",
|
||||
*((uint8 *) &ipaddr->addr),
|
||||
*((uint8 *) &ipaddr->addr + 1),
|
||||
*((uint8 *) &ipaddr->addr + 2),
|
||||
*((uint8 *) &ipaddr->addr + 3));
|
||||
|
||||
if (client->ip.addr == 0 && ipaddr->addr != 0)
|
||||
{
|
||||
os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);
|
||||
if (client->security) {
|
||||
#ifdef MQTT_SSL_ENABLE
|
||||
espconn_secure_set_size(ESPCONN_CLIENT, MQTT_SSL_SIZE);
|
||||
espconn_secure_connect(client->pCon);
|
||||
#else
|
||||
MQTT_INFO("TCP: Do not support SSL\r\n");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
espconn_connect(client->pCon);
|
||||
}
|
||||
|
||||
client->connState = TCP_CONNECTING;
|
||||
MQTT_INFO("TCP: connecting...\r\n");
|
||||
}
|
||||
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LOCAL void ICACHE_FLASH_ATTR
|
||||
deliver_publish(MQTT_Client* client, uint8_t* message, int length)
|
||||
{
|
||||
mqtt_event_data_t event_data;
|
||||
|
||||
event_data.topic_length = length;
|
||||
event_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length);
|
||||
event_data.data_length = length;
|
||||
event_data.data = mqtt_get_publish_data(message, &event_data.data_length);
|
||||
|
||||
if (client->dataCb)
|
||||
client->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length);
|
||||
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_send_keepalive(MQTT_Client *client)
|
||||
{
|
||||
MQTT_INFO("\r\nMQTT: Send keepalive packet to %s:%d!\r\n", client->host, client->port);
|
||||
client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);
|
||||
client->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ;
|
||||
client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
|
||||
client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
|
||||
|
||||
|
||||
client->sendTimeout = MQTT_SEND_TIMOUT;
|
||||
MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
|
||||
err_t result = ESPCONN_OK;
|
||||
if (client->security) {
|
||||
#ifdef MQTT_SSL_ENABLE
|
||||
result = espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
|
||||
#else
|
||||
MQTT_INFO("TCP: Do not support SSL\r\n");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
result = espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
|
||||
}
|
||||
|
||||
client->mqtt_state.outbound_message = NULL;
|
||||
if (ESPCONN_OK == result) {
|
||||
client->keepAliveTick = 0;
|
||||
client->connState = MQTT_DATA;
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
}
|
||||
else {
|
||||
client->connState = TCP_RECONNECT_DISCONNECTING;
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete tcp client and free all memory
|
||||
* @param mqttClient: The mqtt client which contain TCP client
|
||||
* @retval None
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_tcpclient_delete(MQTT_Client *mqttClient)
|
||||
{
|
||||
if (mqttClient->pCon != NULL) {
|
||||
MQTT_INFO("TCP: Free memory\r\n");
|
||||
// Force abort connections
|
||||
espconn_abort(mqttClient->pCon);
|
||||
// Delete connections
|
||||
espconn_delete(mqttClient->pCon);
|
||||
|
||||
if (mqttClient->pCon->proto.tcp) {
|
||||
os_free(mqttClient->pCon->proto.tcp);
|
||||
mqttClient->pCon->proto.tcp = NULL;
|
||||
}
|
||||
os_free(mqttClient->pCon);
|
||||
mqttClient->pCon = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete MQTT client and free all memory
|
||||
* @param mqttClient: The mqtt client
|
||||
* @retval None
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_client_delete(MQTT_Client *mqttClient)
|
||||
{
|
||||
if (mqttClient == NULL)
|
||||
return;
|
||||
|
||||
if (mqttClient->pCon != NULL) {
|
||||
mqtt_tcpclient_delete(mqttClient);
|
||||
}
|
||||
|
||||
if (mqttClient->host != NULL) {
|
||||
os_free(mqttClient->host);
|
||||
mqttClient->host = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->user_data != NULL) {
|
||||
os_free(mqttClient->user_data);
|
||||
mqttClient->user_data = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->mqtt_state.in_buffer != NULL) {
|
||||
os_free(mqttClient->mqtt_state.in_buffer);
|
||||
mqttClient->mqtt_state.in_buffer = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->mqtt_state.out_buffer != NULL) {
|
||||
os_free(mqttClient->mqtt_state.out_buffer);
|
||||
mqttClient->mqtt_state.out_buffer = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->mqtt_state.outbound_message != NULL) {
|
||||
if (mqttClient->mqtt_state.outbound_message->data != NULL)
|
||||
{
|
||||
os_free(mqttClient->mqtt_state.outbound_message->data);
|
||||
mqttClient->mqtt_state.outbound_message->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mqttClient->mqtt_state.mqtt_connection.buffer != NULL) {
|
||||
// Already freed but not NULL
|
||||
mqttClient->mqtt_state.mqtt_connection.buffer = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->connect_info.client_id != NULL) {
|
||||
#ifdef PROTOCOL_NAMEv311
|
||||
/* Don't attempt to free if it's the zero_len array */
|
||||
if ( ((uint8_t*)mqttClient->connect_info.client_id) != zero_len_id )
|
||||
os_free(mqttClient->connect_info.client_id);
|
||||
#else
|
||||
os_free(mqttClient->connect_info.client_id);
|
||||
#endif
|
||||
mqttClient->connect_info.client_id = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->connect_info.username != NULL) {
|
||||
os_free(mqttClient->connect_info.username);
|
||||
mqttClient->connect_info.username = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->connect_info.password != NULL) {
|
||||
os_free(mqttClient->connect_info.password);
|
||||
mqttClient->connect_info.password = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->connect_info.will_topic != NULL) {
|
||||
os_free(mqttClient->connect_info.will_topic);
|
||||
mqttClient->connect_info.will_topic = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->connect_info.will_message != NULL) {
|
||||
os_free(mqttClient->connect_info.will_message);
|
||||
mqttClient->connect_info.will_message = NULL;
|
||||
}
|
||||
|
||||
if (mqttClient->msgQueue.buf != NULL) {
|
||||
os_free(mqttClient->msgQueue.buf);
|
||||
mqttClient->msgQueue.buf = NULL;
|
||||
}
|
||||
|
||||
// Initialize state
|
||||
mqttClient->connState = WIFI_INIT;
|
||||
// Clear callback functions to avoid abnormal callback
|
||||
mqttClient->connectedCb = NULL;
|
||||
mqttClient->disconnectedCb = NULL;
|
||||
mqttClient->publishedCb = NULL;
|
||||
mqttClient->timeoutCb = NULL;
|
||||
mqttClient->dataCb = NULL;
|
||||
|
||||
MQTT_INFO("MQTT: client already deleted\r\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Client received callback function.
|
||||
* @param arg: contain the ip link information
|
||||
* @param pdata: received data
|
||||
* @param len: the lenght of received data
|
||||
* @retval None
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len)
|
||||
{
|
||||
uint8_t msg_type;
|
||||
uint8_t msg_qos;
|
||||
uint16_t msg_id;
|
||||
uint8_t msg_conn_ret;
|
||||
|
||||
struct espconn *pCon = (struct espconn*)arg;
|
||||
MQTT_Client *client = (MQTT_Client *)pCon->reverse;
|
||||
|
||||
READPACKET:
|
||||
MQTT_INFO("TCP: data received %d bytes\r\n", len);
|
||||
// MQTT_INFO("STATE: %d\r\n", client->connState);
|
||||
if (len < MQTT_BUF_SIZE && len > 0) {
|
||||
os_memcpy(client->mqtt_state.in_buffer, pdata, len);
|
||||
|
||||
msg_type = mqtt_get_type(client->mqtt_state.in_buffer);
|
||||
msg_qos = mqtt_get_qos(client->mqtt_state.in_buffer);
|
||||
msg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length);
|
||||
switch (client->connState) {
|
||||
case MQTT_CONNECT_SENDING:
|
||||
if (msg_type == MQTT_MSG_TYPE_CONNACK) {
|
||||
if (client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT) {
|
||||
MQTT_INFO("MQTT: Invalid packet\r\n");
|
||||
if (client->security) {
|
||||
#ifdef MQTT_SSL_ENABLE
|
||||
espconn_secure_disconnect(client->pCon);
|
||||
#else
|
||||
MQTT_INFO("TCP: Do not support SSL\r\n");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
espconn_disconnect(client->pCon);
|
||||
}
|
||||
} else {
|
||||
msg_conn_ret = mqtt_get_connect_return_code(client->mqtt_state.in_buffer);
|
||||
switch (msg_conn_ret) {
|
||||
case CONNECTION_ACCEPTED:
|
||||
MQTT_INFO("MQTT: Connected to %s:%d\r\n", client->host, client->port);
|
||||
client->connState = MQTT_DATA;
|
||||
if (client->connectedCb)
|
||||
client->connectedCb((uint32_t*)client);
|
||||
break;
|
||||
case CONNECTION_REFUSE_PROTOCOL:
|
||||
case CONNECTION_REFUSE_SERVER_UNAVAILABLE:
|
||||
case CONNECTION_REFUSE_BAD_USERNAME:
|
||||
case CONNECTION_REFUSE_NOT_AUTHORIZED:
|
||||
MQTT_INFO("MQTT: Connection refuse, reason code: %d\r\n", msg_conn_ret);
|
||||
default:
|
||||
if (client->security) {
|
||||
#ifdef MQTT_SSL_ENABLE
|
||||
espconn_secure_disconnect(client->pCon);
|
||||
#else
|
||||
MQTT_INFO("TCP: Do not support SSL\r\n");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
espconn_disconnect(client->pCon);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case MQTT_DATA:
|
||||
case MQTT_KEEPALIVE_SEND:
|
||||
client->mqtt_state.message_length_read = len;
|
||||
client->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
|
||||
|
||||
|
||||
switch (msg_type)
|
||||
{
|
||||
|
||||
case MQTT_MSG_TYPE_SUBACK:
|
||||
if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)
|
||||
MQTT_INFO("MQTT: Subscribe successful\r\n");
|
||||
break;
|
||||
case MQTT_MSG_TYPE_UNSUBACK:
|
||||
if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)
|
||||
MQTT_INFO("MQTT: UnSubscribe successful\r\n");
|
||||
break;
|
||||
case MQTT_MSG_TYPE_PUBLISH:
|
||||
if (msg_qos == 1)
|
||||
client->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id);
|
||||
else if (msg_qos == 2)
|
||||
client->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id);
|
||||
if (msg_qos == 1 || msg_qos == 2) {
|
||||
MQTT_INFO("MQTT: Queue response QoS: %d\r\n", msg_qos);
|
||||
if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
|
||||
MQTT_INFO("MQTT: Queue full\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
deliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);
|
||||
break;
|
||||
case MQTT_MSG_TYPE_PUBACK:
|
||||
if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) {
|
||||
MQTT_INFO("MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\r\n");
|
||||
}
|
||||
|
||||
break;
|
||||
case MQTT_MSG_TYPE_PUBREC:
|
||||
client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id);
|
||||
if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
|
||||
MQTT_INFO("MQTT: Queue full\r\n");
|
||||
}
|
||||
break;
|
||||
case MQTT_MSG_TYPE_PUBREL:
|
||||
client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id);
|
||||
if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
|
||||
MQTT_INFO("MQTT: Queue full\r\n");
|
||||
}
|
||||
break;
|
||||
case MQTT_MSG_TYPE_PUBCOMP:
|
||||
if (client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id) {
|
||||
MQTT_INFO("MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\r\n");
|
||||
}
|
||||
break;
|
||||
case MQTT_MSG_TYPE_PINGREQ:
|
||||
client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection);
|
||||
if (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
|
||||
MQTT_INFO("MQTT: Queue full\r\n");
|
||||
}
|
||||
break;
|
||||
case MQTT_MSG_TYPE_PINGRESP:
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
// NOTE: this is done down here and not in the switch case above
|
||||
// because the PSOCK_READBUF_LEN() won't work inside a switch
|
||||
// statement due to the way protothreads resume.
|
||||
if (msg_type == MQTT_MSG_TYPE_PUBLISH)
|
||||
{
|
||||
len = client->mqtt_state.message_length_read;
|
||||
|
||||
if (client->mqtt_state.message_length < client->mqtt_state.message_length_read)
|
||||
{
|
||||
//client->connState = MQTT_PUBLISH_RECV;
|
||||
//Not Implement yet
|
||||
len -= client->mqtt_state.message_length;
|
||||
pdata += client->mqtt_state.message_length;
|
||||
|
||||
MQTT_INFO("Get another published message\r\n");
|
||||
goto READPACKET;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
MQTT_INFO("ERROR: Message too long\r\n");
|
||||
}
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Client send over callback function.
|
||||
* @param arg: contain the ip link information
|
||||
* @retval None
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_tcpclient_sent_cb(void *arg)
|
||||
{
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
MQTT_Client* client = (MQTT_Client *)pCon->reverse;
|
||||
MQTT_INFO("TCP: Sent\r\n");
|
||||
client->sendTimeout = 0;
|
||||
client->keepAliveTick = 0;
|
||||
|
||||
if ((client->connState == MQTT_DATA || client->connState == MQTT_KEEPALIVE_SEND)
|
||||
&& client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH) {
|
||||
if (client->publishedCb)
|
||||
client->publishedCb((uint32_t*)client);
|
||||
}
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR mqtt_timer(void *arg)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)arg;
|
||||
|
||||
if (client->connState == MQTT_DATA) {
|
||||
client->keepAliveTick ++;
|
||||
if (client->keepAliveTick > (client->mqtt_state.connect_info->keepalive / 2)) {
|
||||
client->connState = MQTT_KEEPALIVE_SEND;
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
}
|
||||
|
||||
} else if (client->connState == TCP_RECONNECT_REQ) {
|
||||
client->reconnectTick ++;
|
||||
if (client->reconnectTick > MQTT_RECONNECT_TIMEOUT) {
|
||||
client->reconnectTick = 0;
|
||||
client->connState = TCP_RECONNECT;
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
if (client->timeoutCb)
|
||||
client->timeoutCb((uint32_t*)client);
|
||||
}
|
||||
}
|
||||
if (client->sendTimeout > 0)
|
||||
client->sendTimeout --;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_tcpclient_discon_cb(void *arg)
|
||||
{
|
||||
|
||||
struct espconn *pespconn = (struct espconn *)arg;
|
||||
MQTT_Client* client = (MQTT_Client *)pespconn->reverse;
|
||||
MQTT_INFO("TCP: Disconnected callback\r\n");
|
||||
if (TCP_DISCONNECTING == client->connState) {
|
||||
client->connState = TCP_DISCONNECTED;
|
||||
}
|
||||
else if (MQTT_DELETING == client->connState) {
|
||||
client->connState = MQTT_DELETED;
|
||||
}
|
||||
else {
|
||||
client->connState = TCP_RECONNECT_REQ;
|
||||
}
|
||||
if (client->disconnectedCb)
|
||||
client->disconnectedCb((uint32_t*)client);
|
||||
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Tcp client connect success callback function.
|
||||
* @param arg: contain the ip link information
|
||||
* @retval None
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_tcpclient_connect_cb(void *arg)
|
||||
{
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
MQTT_Client* client = (MQTT_Client *)pCon->reverse;
|
||||
|
||||
espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb);
|
||||
espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);////////
|
||||
espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);///////
|
||||
MQTT_INFO("MQTT: Connected to broker %s:%d\r\n", client->host, client->port);
|
||||
|
||||
mqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length);
|
||||
client->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info);
|
||||
client->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);
|
||||
client->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
|
||||
|
||||
|
||||
client->sendTimeout = MQTT_SEND_TIMOUT;
|
||||
MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
|
||||
if (client->security) {
|
||||
#ifdef MQTT_SSL_ENABLE
|
||||
espconn_secure_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
|
||||
#else
|
||||
MQTT_INFO("TCP: Do not support SSL\r\n");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
espconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);
|
||||
}
|
||||
|
||||
client->mqtt_state.outbound_message = NULL;
|
||||
client->connState = MQTT_CONNECT_SENDING;
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tcp client connect repeat callback function.
|
||||
* @param arg: contain the ip link information
|
||||
* @retval None
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_tcpclient_recon_cb(void *arg, sint8 errType)
|
||||
{
|
||||
struct espconn *pCon = (struct espconn *)arg;
|
||||
MQTT_Client* client = (MQTT_Client *)pCon->reverse;
|
||||
|
||||
MQTT_INFO("TCP: Reconnect to %s:%d\r\n", client->host, client->port);
|
||||
|
||||
client->connState = TCP_RECONNECT_REQ;
|
||||
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MQTT publish function.
|
||||
* @param client: MQTT_Client reference
|
||||
* @param topic: string topic will publish to
|
||||
* @param data: buffer data send point to
|
||||
* @param data_length: length of data
|
||||
* @param qos: qos
|
||||
* @param retain: retain
|
||||
* @retval TRUE if success queue
|
||||
*/
|
||||
bool ICACHE_FLASH_ATTR
|
||||
MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain)
|
||||
{
|
||||
uint8_t dataBuffer[MQTT_BUF_SIZE];
|
||||
uint16_t dataLen;
|
||||
client->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection,
|
||||
topic, data, data_length,
|
||||
qos, retain,
|
||||
&client->mqtt_state.pending_msg_id);
|
||||
if (client->mqtt_state.outbound_message->length == 0) {
|
||||
MQTT_INFO("MQTT: Queuing publish failed\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
MQTT_INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size);
|
||||
while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
|
||||
MQTT_INFO("MQTT: Queue full\r\n");
|
||||
if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
|
||||
MQTT_INFO("MQTT: Serious buffer error\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MQTT subscibe function.
|
||||
* @param client: MQTT_Client reference
|
||||
* @param topic: string topic will subscribe
|
||||
* @param qos: qos
|
||||
* @retval TRUE if success queue
|
||||
*/
|
||||
bool ICACHE_FLASH_ATTR
|
||||
MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos)
|
||||
{
|
||||
uint8_t dataBuffer[MQTT_BUF_SIZE];
|
||||
uint16_t dataLen;
|
||||
|
||||
client->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection,
|
||||
topic, qos,
|
||||
&client->mqtt_state.pending_msg_id);
|
||||
MQTT_INFO("MQTT: queue subscribe, topic\"%s\", id: %d\r\n", topic, client->mqtt_state.pending_msg_id);
|
||||
while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
|
||||
MQTT_INFO("MQTT: Queue full\r\n");
|
||||
if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
|
||||
MQTT_INFO("MQTT: Serious buffer error\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MQTT un-subscibe function.
|
||||
* @param client: MQTT_Client reference
|
||||
* @param topic: String topic will un-subscribe
|
||||
* @retval TRUE if success queue
|
||||
*/
|
||||
bool ICACHE_FLASH_ATTR
|
||||
MQTT_UnSubscribe(MQTT_Client *client, char* topic)
|
||||
{
|
||||
uint8_t dataBuffer[MQTT_BUF_SIZE];
|
||||
uint16_t dataLen;
|
||||
client->mqtt_state.outbound_message = mqtt_msg_unsubscribe(&client->mqtt_state.mqtt_connection,
|
||||
topic,
|
||||
&client->mqtt_state.pending_msg_id);
|
||||
MQTT_INFO("MQTT: queue un-subscribe, topic\"%s\", id: %d\r\n", topic, client->mqtt_state.pending_msg_id);
|
||||
while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
|
||||
MQTT_INFO("MQTT: Queue full\r\n");
|
||||
if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
|
||||
MQTT_INFO("MQTT: Serious buffer error\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MQTT ping function.
|
||||
* @param client: MQTT_Client reference
|
||||
* @retval TRUE if success queue
|
||||
*/
|
||||
bool ICACHE_FLASH_ATTR
|
||||
MQTT_Ping(MQTT_Client *client)
|
||||
{
|
||||
uint8_t dataBuffer[MQTT_BUF_SIZE];
|
||||
uint16_t dataLen;
|
||||
client->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);
|
||||
if (client->mqtt_state.outbound_message->length == 0) {
|
||||
MQTT_INFO("MQTT: Queuing publish failed\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
MQTT_INFO("MQTT: queuing publish, length: %d, queue size(%d/%d)\r\n", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size);
|
||||
while (QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1) {
|
||||
MQTT_INFO("MQTT: Queue full\r\n");
|
||||
if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {
|
||||
MQTT_INFO("MQTT: Serious buffer error\r\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_Task(os_event_t *e)
|
||||
{
|
||||
MQTT_Client* client = (MQTT_Client*)e->par;
|
||||
uint8_t dataBuffer[MQTT_BUF_SIZE];
|
||||
uint16_t dataLen;
|
||||
if (e->par == 0)
|
||||
return;
|
||||
switch (client->connState) {
|
||||
|
||||
case TCP_RECONNECT_REQ:
|
||||
break;
|
||||
case TCP_RECONNECT:
|
||||
mqtt_tcpclient_delete(client);
|
||||
MQTT_Connect(client);
|
||||
MQTT_INFO("TCP: Reconnect to: %s:%d\r\n", client->host, client->port);
|
||||
client->connState = TCP_CONNECTING;
|
||||
break;
|
||||
case MQTT_DELETING:
|
||||
case TCP_DISCONNECTING:
|
||||
case TCP_RECONNECT_DISCONNECTING:
|
||||
if (client->security) {
|
||||
#ifdef MQTT_SSL_ENABLE
|
||||
espconn_secure_disconnect(client->pCon);
|
||||
#else
|
||||
MQTT_INFO("TCP: Do not support SSL\r\n");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
espconn_disconnect(client->pCon);
|
||||
}
|
||||
break;
|
||||
case TCP_DISCONNECTED:
|
||||
MQTT_INFO("MQTT: Disconnected\r\n");
|
||||
mqtt_tcpclient_delete(client);
|
||||
break;
|
||||
case MQTT_DELETED:
|
||||
MQTT_INFO("MQTT: Deleted client\r\n");
|
||||
mqtt_client_delete(client);
|
||||
break;
|
||||
case MQTT_KEEPALIVE_SEND:
|
||||
mqtt_send_keepalive(client);
|
||||
break;
|
||||
case MQTT_DATA:
|
||||
if (QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) {
|
||||
break;
|
||||
}
|
||||
if (QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0) {
|
||||
client->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer);
|
||||
client->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen);
|
||||
|
||||
|
||||
client->sendTimeout = MQTT_SEND_TIMOUT;
|
||||
MQTT_INFO("MQTT: Sending, type: %d, id: %04X\r\n", client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);
|
||||
client->keepAliveTick = 0;
|
||||
if (client->security) {
|
||||
#ifdef MQTT_SSL_ENABLE
|
||||
espconn_secure_send(client->pCon, dataBuffer, dataLen);
|
||||
#else
|
||||
MQTT_INFO("TCP: Do not support SSL\r\n");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
espconn_send(client->pCon, dataBuffer, dataLen);
|
||||
}
|
||||
|
||||
client->mqtt_state.outbound_message = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MQTT initialization connection function
|
||||
* @param client: MQTT_Client reference
|
||||
* @param host: Domain or IP string
|
||||
* @param port: Port to connect
|
||||
* @param security: 1 for ssl, 0 for none
|
||||
* @retval None
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32_t port, uint8_t security)
|
||||
{
|
||||
uint32_t temp;
|
||||
MQTT_INFO("MQTT:InitConnection\r\n");
|
||||
os_memset(mqttClient, 0, sizeof(MQTT_Client));
|
||||
temp = os_strlen(host);
|
||||
mqttClient->host = (uint8_t*)os_zalloc(temp + 1);
|
||||
os_strcpy(mqttClient->host, host);
|
||||
mqttClient->host[temp] = 0;
|
||||
mqttClient->port = port;
|
||||
mqttClient->security = security;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MQTT initialization mqtt client function
|
||||
* @param client: MQTT_Client reference
|
||||
* @param clientid: MQTT client id
|
||||
* @param client_user:MQTT client user
|
||||
* @param client_pass:MQTT client password
|
||||
* @param client_pass:MQTT keep alive timer, in second
|
||||
* @retval None
|
||||
*/
|
||||
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)
|
||||
{
|
||||
uint32_t temp;
|
||||
MQTT_INFO("MQTT:InitClient\r\n");
|
||||
|
||||
os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t));
|
||||
|
||||
if ( !client_id )
|
||||
{
|
||||
/* Should be allowed by broker, but clean session flag must be set. */
|
||||
#ifdef PROTOCOL_NAMEv311
|
||||
if (cleanSession)
|
||||
{
|
||||
mqttClient->connect_info.client_id = zero_len_id;
|
||||
} else {
|
||||
MQTT_INFO("cleanSession must be set to use 0 length client_id\r\n");
|
||||
return false;
|
||||
}
|
||||
/* Not supported. Return. */
|
||||
#else
|
||||
MQTT_INFO("Client ID required for MQTT < 3.1.1!\r\n");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* If connect_info's client_id is still NULL and we get here, we can *
|
||||
* assume the passed client_id is non-NULL. */
|
||||
if ( !(mqttClient->connect_info.client_id) )
|
||||
{
|
||||
temp = os_strlen(client_id);
|
||||
mqttClient->connect_info.client_id = (uint8_t*)os_zalloc(temp + 1);
|
||||
os_strcpy(mqttClient->connect_info.client_id, client_id);
|
||||
mqttClient->connect_info.client_id[temp] = 0;
|
||||
}
|
||||
|
||||
if (client_user)
|
||||
{
|
||||
temp = os_strlen(client_user);
|
||||
mqttClient->connect_info.username = (uint8_t*)os_zalloc(temp + 1);
|
||||
os_strcpy(mqttClient->connect_info.username, client_user);
|
||||
mqttClient->connect_info.username[temp] = 0;
|
||||
}
|
||||
|
||||
if (client_pass)
|
||||
{
|
||||
temp = os_strlen(client_pass);
|
||||
mqttClient->connect_info.password = (uint8_t*)os_zalloc(temp + 1);
|
||||
os_strcpy(mqttClient->connect_info.password, client_pass);
|
||||
mqttClient->connect_info.password[temp] = 0;
|
||||
}
|
||||
|
||||
|
||||
mqttClient->connect_info.keepalive = keepAliveTime;
|
||||
mqttClient->connect_info.clean_session = cleanSession;
|
||||
|
||||
mqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
|
||||
mqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE;
|
||||
mqttClient->mqtt_state.out_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);
|
||||
mqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE;
|
||||
mqttClient->mqtt_state.connect_info = &mqttClient->connect_info;
|
||||
|
||||
mqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length);
|
||||
|
||||
QUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE);
|
||||
|
||||
system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE);
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
|
||||
return true;
|
||||
}
|
||||
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)
|
||||
{
|
||||
uint32_t temp;
|
||||
temp = os_strlen(will_topic);
|
||||
mqttClient->connect_info.will_topic = (uint8_t*)os_zalloc(temp + 1);
|
||||
os_strcpy(mqttClient->connect_info.will_topic, will_topic);
|
||||
mqttClient->connect_info.will_topic[temp] = 0;
|
||||
|
||||
temp = os_strlen(will_msg);
|
||||
mqttClient->connect_info.will_message = (uint8_t*)os_zalloc(temp + 1);
|
||||
os_strcpy(mqttClient->connect_info.will_message, will_msg);
|
||||
mqttClient->connect_info.will_message[temp] = 0;
|
||||
|
||||
|
||||
mqttClient->connect_info.will_qos = will_qos;
|
||||
mqttClient->connect_info.will_retain = will_retain;
|
||||
}
|
||||
/**
|
||||
* @brief Begin connect to MQTT broker
|
||||
* @param client: MQTT_Client reference
|
||||
* @retval None
|
||||
*/
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_Connect(MQTT_Client *mqttClient)
|
||||
{
|
||||
if (mqttClient->pCon) {
|
||||
// Clean up the old connection forcefully - using MQTT_Disconnect
|
||||
// does not actually release the old connection until the
|
||||
// disconnection callback is invoked.
|
||||
mqtt_tcpclient_delete(mqttClient);
|
||||
}
|
||||
mqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
|
||||
mqttClient->pCon->type = ESPCONN_TCP;
|
||||
mqttClient->pCon->state = ESPCONN_NONE;
|
||||
mqttClient->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
|
||||
mqttClient->pCon->proto.tcp->local_port = espconn_port();
|
||||
mqttClient->pCon->proto.tcp->remote_port = mqttClient->port;
|
||||
mqttClient->pCon->reverse = mqttClient;
|
||||
espconn_regist_connectcb(mqttClient->pCon, mqtt_tcpclient_connect_cb);
|
||||
espconn_regist_reconcb(mqttClient->pCon, mqtt_tcpclient_recon_cb);
|
||||
|
||||
mqttClient->keepAliveTick = 0;
|
||||
mqttClient->reconnectTick = 0;
|
||||
|
||||
|
||||
os_timer_disarm(&mqttClient->mqttTimer);
|
||||
os_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient);
|
||||
os_timer_arm(&mqttClient->mqttTimer, 1000, 1);
|
||||
|
||||
if (UTILS_StrToIP(mqttClient->host, &mqttClient->pCon->proto.tcp->remote_ip)) {
|
||||
MQTT_INFO("TCP: Connect to ip %s:%d\r\n", mqttClient->host, mqttClient->port);
|
||||
if (mqttClient->security)
|
||||
{
|
||||
#ifdef MQTT_SSL_ENABLE
|
||||
espconn_secure_set_size(ESPCONN_CLIENT, MQTT_SSL_SIZE);
|
||||
espconn_secure_connect(mqttClient->pCon);
|
||||
#else
|
||||
MQTT_INFO("TCP: Do not support SSL\r\n");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
espconn_connect(mqttClient->pCon);
|
||||
}
|
||||
}
|
||||
else {
|
||||
MQTT_INFO("TCP: Connect to domain %s:%d\r\n", mqttClient->host, mqttClient->port);
|
||||
espconn_gethostbyname(mqttClient->pCon, mqttClient->host, &mqttClient->ip, mqtt_dns_found);
|
||||
}
|
||||
mqttClient->connState = TCP_CONNECTING;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_Disconnect(MQTT_Client *mqttClient)
|
||||
{
|
||||
mqttClient->connState = TCP_DISCONNECTING;
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
|
||||
os_timer_disarm(&mqttClient->mqttTimer);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_DeleteClient(MQTT_Client *mqttClient)
|
||||
{
|
||||
if (NULL == mqttClient)
|
||||
return;
|
||||
|
||||
mqttClient->connState = MQTT_DELETED;
|
||||
// if(TCP_DISCONNECTED == mqttClient->connState) {
|
||||
// mqttClient->connState = MQTT_DELETED;
|
||||
// } else if(MQTT_DELETED != mqttClient->connState) {
|
||||
// mqttClient->connState = MQTT_DELETING;
|
||||
// }
|
||||
|
||||
system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);
|
||||
os_timer_disarm(&mqttClient->mqttTimer);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb)
|
||||
{
|
||||
mqttClient->connectedCb = connectedCb;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb)
|
||||
{
|
||||
mqttClient->disconnectedCb = disconnectedCb;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb)
|
||||
{
|
||||
mqttClient->dataCb = dataCb;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb)
|
||||
{
|
||||
mqttClient->publishedCb = publishedCb;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
MQTT_OnTimeout(MQTT_Client *mqttClient, MqttCallback timeoutCb)
|
||||
{
|
||||
mqttClient->timeoutCb = timeoutCb;
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/* 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 "user_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_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_ */
|
|
@ -0,0 +1,487 @@
|
|||
/*
|
||||
* 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 "user_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);
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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 */
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/* 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;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* 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_ */
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* \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;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#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
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* \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
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef __MQTT_CONFIG_H__
|
||||
#define __MQTT_CONFIG_H__
|
||||
|
||||
//#define MQTT_SSL_ENABLE
|
||||
|
||||
#define MQTT_RECONNECT_TIMEOUT 5 /*second*/
|
||||
|
||||
//#define MQTT_BUF_SIZE 1024
|
||||
#define MQTT_BUF_SIZE 512
|
||||
#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__
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#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
|
|
@ -0,0 +1,28 @@
|
|||
# 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
|
||||
._*
|
|
@ -0,0 +1,15 @@
|
|||
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!
|
|
@ -0,0 +1,102 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#######################################
|
||||
# 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)
|
||||
#######################################
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
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
|
|
@ -0,0 +1,269 @@
|
|||
/*//-------------------------------------------------------------------------------
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*//-------------------------------------------------------------------------------
|
||||
* 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
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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
|
@ -0,0 +1,152 @@
|
|||
/* 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_ */
|
|
@ -0,0 +1,19 @@
|
|||
#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__
|
|
@ -0,0 +1,487 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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 */
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/* 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;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* 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_ */
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* \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;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#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
|
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* \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
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#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
|
|
@ -21,6 +21,7 @@ src_dir = sonoff
|
|||
;env_default = sonoff-IT
|
||||
;env_default = sonoff-NL
|
||||
;env_default = sonoff-PL
|
||||
;env_default = sonoff-PT
|
||||
;env_default = sonoff-RU
|
||||
;env_default = sonoff-CN
|
||||
|
||||
|
@ -122,6 +123,8 @@ extra_scripts = pio/strip-floats.py
|
|||
monitor_baud = 115200
|
||||
|
||||
[env:sonoff-HU]
|
||||
;platform = espressif8266@1.5.0 ; v2.3.0
|
||||
;platform = espressif8266@1.6.0 ; v2.4.0
|
||||
platform = espressif8266
|
||||
framework = arduino
|
||||
board = esp01_1m
|
||||
|
@ -175,6 +178,20 @@ extra_scripts = pio/strip-floats.py
|
|||
; *** Serial Monitor options
|
||||
monitor_baud = 115200
|
||||
|
||||
[env:sonoff-PT]
|
||||
;platform = espressif8266@1.5.0 ; v2.3.0
|
||||
;platform = espressif8266@1.6.0 ; v2.4.0
|
||||
platform = espressif8266
|
||||
framework = arduino
|
||||
board = esp01_1m
|
||||
board_flash_mode = dout
|
||||
build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMY_LANGUAGE=pt-PT
|
||||
lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON
|
||||
extra_scripts = pio/strip-floats.py
|
||||
|
||||
; *** Serial Monitor options
|
||||
monitor_baud = 115200
|
||||
|
||||
[env:sonoff-RU]
|
||||
;platform = espressif8266@1.5.0 ; v2.3.0
|
||||
;platform = espressif8266@1.6.0 ; v2.4.0
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/* 5.12.0d
|
||||
* Prep for optional MQTT drivers by separating mqtt code from sonoff.ino to file xdrv_00_mqtt.ino
|
||||
* Add support for optional MQTT drivers to be selected in user_config.h (#1992)
|
||||
* Add Portuguese language file
|
||||
* Add compiler check for stable lwIP version v1.4 (#1940)
|
||||
* Add diacritics to Polish language file (#2005)
|
||||
* Add Hungarian language file (#2024)
|
||||
* Add support for Nova Fitness SDS011 and possibly SDS021 particle concentration sensor (#2070)
|
||||
* Fix MQTT TLS fingerprint validation (#2033)
|
||||
*
|
||||
* 5.12.0c
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "Háttérvil"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
|
|
|
@ -0,0 +1,458 @@
|
|||
/*
|
||||
pt-PT.h - localization for Portuguese - Portugal for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2018 Theo Arends and Paulo Paiva
|
||||
|
||||
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_PT_PT_H_
|
||||
#define _LANGUAGE_PT_PT_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.
|
||||
*
|
||||
\*********************************************************************/
|
||||
|
||||
//#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
|
||||
|
||||
// "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 "DomSegTerQuaQuiSexSab"
|
||||
#define D_MONTH3LIST "JanFevMarAbrMaiJunJulAgoSepOutNovDez"
|
||||
|
||||
// Non JSON decimal separator
|
||||
#define D_DECIMAL_SEPARATOR "."
|
||||
|
||||
// Common
|
||||
#define D_ADMIN "Admin"
|
||||
#define D_AIR_QUALITY "Qualidade do Ar"
|
||||
#define D_AP "AP" // Ponto de Acesso
|
||||
#define D_AS "como"
|
||||
#define D_AUTO "AUTO"
|
||||
#define D_BLINK "Piscar"
|
||||
#define D_BLINKOFF "Piscar desligado"
|
||||
#define D_BOOT_COUNT "Contagem de Inicialização"
|
||||
#define D_BRIGHTLIGHT "Brilho"
|
||||
#define D_BUTTON "Botão"
|
||||
#define D_BY "por" // Write by me
|
||||
#define D_BYTES "Bytes"
|
||||
#define D_CELSIUS "Celsius"
|
||||
#define D_CO2 "Dioxido de Carbono"
|
||||
#define D_CODE "Código" // Button code
|
||||
#define D_COLDLIGHT "Luz Fria"
|
||||
#define D_COMMAND "Comando"
|
||||
#define D_CONNECTED "Ligado"
|
||||
#define D_COUNT "Contagem"
|
||||
#define D_COUNTER "Contador"
|
||||
#define D_CURRENT "Corrente" // As in Voltage and Current
|
||||
#define D_DATA "Dados"
|
||||
#define D_DARKLIGHT "Luz Escura"
|
||||
#define D_DEBUG "Depurar"
|
||||
#define D_DISABLED "Disabilitado"
|
||||
#define D_DNS_SERVER "Servidor DNS"
|
||||
#define D_DONE "Concluído"
|
||||
#define D_DST_TIME "DST"
|
||||
#define D_EMULATION "Emulação"
|
||||
#define D_ENABLED "Habilitado"
|
||||
#define D_ERASE "Apagar"
|
||||
#define D_ERROR "Erro"
|
||||
#define D_FAHRENHEIT "Fahrenheit"
|
||||
#define D_FAILED "Falha"
|
||||
#define D_FALLBACK "Retornar"
|
||||
#define D_FALLBACK_TOPIC "Tópico para retornar"
|
||||
#define D_FALSE "Falso"
|
||||
#define D_FILE "Ficheiro"
|
||||
#define D_FREE_MEMORY "Memoria Livre"
|
||||
#define D_GAS "Gás"
|
||||
#define D_GATEWAY "Gateway"
|
||||
#define D_GROUP "Grupo"
|
||||
#define D_HOST "Anfitrião"
|
||||
#define D_HOSTNAME "Nome Anfitrião"
|
||||
#define D_HUMIDITY "Humidade"
|
||||
#define D_ILLUMINANCE "Luminâcia"
|
||||
#define D_IMMEDIATE "Immediato" // Button immediate
|
||||
#define D_INDEX "Indíce"
|
||||
#define D_INFO "Info"
|
||||
#define D_INITIALIZED "Inicializado"
|
||||
#define D_IP_ADDRESS "Endereço IP"
|
||||
#define D_LIGHT "Luz"
|
||||
#define D_LWT "LWT"
|
||||
#define D_MODULE "Módulo"
|
||||
#define D_MQTT "MQTT"
|
||||
#define D_MULTI_PRESS "multi-pressão"
|
||||
#define D_NOISE "Ruído"
|
||||
#define D_NONE "Nenhum"
|
||||
#define D_OFF "Off"
|
||||
#define D_OFFLINE "Desconetado"
|
||||
#define D_OK "Ok"
|
||||
#define D_ON "On"
|
||||
#define D_ONLINE "Conetado"
|
||||
#define D_PASSWORD "Palavra Chave"
|
||||
#define D_PORT "Porta"
|
||||
#define D_POWER_FACTOR "Factor de Potência"
|
||||
#define D_POWERUSAGE "Potência"
|
||||
#define D_PRESSURE "Pressão"
|
||||
#define D_PRESSUREATSEALEVEL "Pressão ao nível do Mar"
|
||||
#define D_PROGRAM_FLASH_SIZE "Tamanho do Programa na Flash"
|
||||
#define D_PROGRAM_SIZE "Tamanho do Programa"
|
||||
#define D_PROJECT "Projeto"
|
||||
#define D_RECEIVED "Recebido"
|
||||
#define D_RESTART "Reiniciar"
|
||||
#define D_RESTARTING "A reiniciar"
|
||||
#define D_RESTART_REASON "Razão do reinicio"
|
||||
#define D_RESTORE "Restauro"
|
||||
#define D_RETAINED "Manter"
|
||||
#define D_SAVE "Salvar"
|
||||
#define D_SENSOR "Sensor"
|
||||
#define D_SSID "SSId"
|
||||
#define D_START "Início"
|
||||
#define D_STD_TIME "STD"
|
||||
#define D_STOP "Parar"
|
||||
#define D_SUBNET_MASK "Mascara sub rede"
|
||||
#define D_SUBSCRIBE_TO "Subescrever para"
|
||||
#define D_SUCCESSFUL "Successo"
|
||||
#define D_TEMPERATURE "Temperatura"
|
||||
#define D_TO "para"
|
||||
#define D_TOGGLE "Pressionar"
|
||||
#define D_TOPIC "Tópico"
|
||||
#define D_TRANSMIT "Transmitir"
|
||||
#define D_TRUE "Verdadeiro"
|
||||
#define D_UPGRADE "Atualizar"
|
||||
#define D_UPLOAD "Enviar"
|
||||
#define D_UPTIME "Tempo de Atividade"
|
||||
#define D_USER "Utilizador"
|
||||
#define D_UTC_TIME "UTC"
|
||||
#define D_UV_LEVEL "Nível UV"
|
||||
#define D_VERSION "Versão"
|
||||
#define D_VOLTAGE "Voltagem"
|
||||
#define D_WARMLIGHT "Luz Quente"
|
||||
#define D_WEB_SERVER "servidor WEB"
|
||||
|
||||
// sonoff.ino
|
||||
#define D_WARNING_MINIMAL_VERSION "AVISO esta versão não supporta configurações persistentes"
|
||||
#define D_LEVEL_10 "nível 1-0"
|
||||
#define D_LEVEL_01 "nível 0-1"
|
||||
#define D_SERIAL_LOGGING_DISABLED "Registro em serie desabilitado"
|
||||
#define D_SYSLOG_LOGGING_REENABLED "Registro do Syslog reativado"
|
||||
|
||||
#define D_SET_BAUDRATE_TO "Ajuste da velocidade para"
|
||||
#define D_RECEIVED_TOPIC "Topico Recebido"
|
||||
#define D_DATA_SIZE "Tamanho de dados"
|
||||
#define D_ANALOG_INPUT "Entrada Analógica"
|
||||
|
||||
#define D_FINGERPRINT "Verifique a impressão digital TLS..."
|
||||
#define D_TLS_CONNECT_FAILED_TO "TLS não conseguiu ligar"
|
||||
#define D_RETRY_IN "Tentativa em"
|
||||
#define D_VERIFIED "Verificado"
|
||||
#define D_INSECURE "Ligação insegura devido à impressão digital inválida"
|
||||
#define D_CONNECT_FAILED_TO "A ligação falhou ao"
|
||||
|
||||
// support.ino
|
||||
#define D_OSWATCH "osWatch"
|
||||
#define D_BLOCKED_LOOP "Loop Bloqueado"
|
||||
#define D_WPS_FAILED_WITH_STATUS "WPSconfig Falha de estado"
|
||||
#define D_ACTIVE_FOR_3_MINUTES "ativo por 3 minutes"
|
||||
#define D_FAILED_TO_START "Falha ao iníciar"
|
||||
#define D_PATCH_ISSUE_2186 "Questão 2186"
|
||||
#define D_CONNECTING_TO_AP "Ligando ao AP"
|
||||
#define D_IN_MODE "em modo"
|
||||
#define D_CONNECT_FAILED_NO_IP_ADDRESS "A ligação falhou porque nenhum endereço IP foi recebido"
|
||||
#define D_CONNECT_FAILED_AP_NOT_REACHED "A ligação falhou porque o AP não pode ser alcançado"
|
||||
#define D_CONNECT_FAILED_WRONG_PASSWORD "A ligação falhou porque a palavra chave está incorreta"
|
||||
#define D_CONNECT_FAILED_AP_TIMEOUT "A ligação falhou porque o tempo excedeu"
|
||||
#define D_ATTEMPTING_CONNECTION "A ligar..."
|
||||
#define D_CHECKING_CONNECTION "A verificar ligação..."
|
||||
#define D_QUERY_DONE "Consulta finalizada. Serviço MQTT não encontrado"
|
||||
#define D_MQTT_SERVICE_FOUND "Serviço MQTT encontrado em"
|
||||
#define D_FOUND_AT "encontrado em"
|
||||
#define D_SYSLOG_HOST_NOT_FOUND "Syslog anfitrião não encontrado"
|
||||
|
||||
// settings.ino
|
||||
#define D_SAVED_TO_FLASH_AT "Guardado na flash em"
|
||||
#define D_LOADED_FROM_FLASH_AT "Lido da flash em"
|
||||
#define D_USE_DEFAULTS "Usar predefinições"
|
||||
#define D_ERASED_SECTOR "Apagar setores"
|
||||
|
||||
// webserver.ino
|
||||
#define D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "MINIMO firmware - Atualizar Por favor"
|
||||
#define D_WEBSERVER_ACTIVE_ON "Servidor WEB ativo em"
|
||||
#define D_WITH_IP_ADDRESS "com o endereço IP"
|
||||
#define D_WEBSERVER_STOPPED "Servitor WEB parou"
|
||||
#define D_FILE_NOT_FOUND "Ficheiro não encontrado"
|
||||
#define D_REDIRECTED "Redirecionado para o portal ativo"
|
||||
#define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager configura o Ponto de Acesso e mantem a Estação"
|
||||
#define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager configura o Ponto de Acesso"
|
||||
#define D_TRYING_TO_CONNECT "A tentar ligar o dispositivo à rede"
|
||||
|
||||
#define D_RESTART_IN "Reinicia em"
|
||||
#define D_SECONDS "segundos"
|
||||
#define D_DEVICE_WILL_RESTART "O dispositivo irá reiniciar dentro de alguns segundos"
|
||||
#define D_BUTTON_TOGGLE "Pressionar"
|
||||
#define D_CONFIGURATION "Configuração"
|
||||
#define D_INFORMATION "Informação"
|
||||
#define D_FIRMWARE_UPGRADE "Atualização de Firmware"
|
||||
#define D_CONSOLE "Consola"
|
||||
#define D_CONFIRM_RESTART "Confirmar o reinicio"
|
||||
|
||||
#define D_CONFIGURE_MODULE "Configurar Módulo"
|
||||
#define D_CONFIGURE_WIFI "Configurar WiFi"
|
||||
#define D_CONFIGURE_MQTT "Configurar MQTT"
|
||||
#define D_CONFIGURE_DOMOTICZ "Configurar Domoticz"
|
||||
#define D_CONFIGURE_LOGGING "Configurar Logging"
|
||||
#define D_CONFIGURE_OTHER "Configurar outras opções"
|
||||
#define D_CONFIRM_RESET_CONFIGURATION "Apagar configuração Confirmar"
|
||||
#define D_RESET_CONFIGURATION "Apagar configuração"
|
||||
#define D_BACKUP_CONFIGURATION "Guardar configuração"
|
||||
#define D_RESTORE_CONFIGURATION "Repor configuração"
|
||||
#define D_MAIN_MENU "Menu Principal"
|
||||
|
||||
#define D_MODULE_PARAMETERS "Parametros do Módulo"
|
||||
#define D_MODULE_TYPE "Tipo de Módulo"
|
||||
#define D_GPIO "GPIO"
|
||||
#define D_SERIAL_IN "Serial Entrada"
|
||||
#define D_SERIAL_OUT "Serial Saída"
|
||||
|
||||
#define D_WIFI_PARAMETERS "Parametros Wifi"
|
||||
#define D_SCAN_FOR_WIFI_NETWORKS "Em busca de redes wifi"
|
||||
#define D_SCAN_DONE "Busca finalizada"
|
||||
#define D_NO_NETWORKS_FOUND "Sem redes"
|
||||
#define D_REFRESH_TO_SCAN_AGAIN "Nova busca"
|
||||
#define D_DUPLICATE_ACCESSPOINT "Ponto de Acesso duplicado"
|
||||
#define D_SKIPPING_LOW_QUALITY "Ignorado devido a baixa qualidade do sinal"
|
||||
#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 Palavra Chave"
|
||||
#define D_AP2_SSID "AP2 SSId"
|
||||
#define D_AP2_PASSWORD "AP2 Palavra Chave"
|
||||
|
||||
#define D_MQTT_PARAMETERS "Parametros MQTT"
|
||||
#define D_CLIENT "Cliente"
|
||||
#define D_FULL_TOPIC "Tópico completo"
|
||||
|
||||
#define D_LOGGING_PARAMETERS "Parametros Logging"
|
||||
#define D_SERIAL_LOG_LEVEL "Nível de registro serial"
|
||||
#define D_WEB_LOG_LEVEL "Nível de registro WEB"
|
||||
#define D_SYS_LOG_LEVEL "Nível de registro Syslog"
|
||||
#define D_MORE_DEBUG "Depurar mais"
|
||||
#define D_SYSLOG_HOST "Syslog anfitrião"
|
||||
#define D_SYSLOG_PORT "Porta Syslog"
|
||||
#define D_TELEMETRY_PERIOD "Periodo de Telemetria"
|
||||
|
||||
#define D_OTHER_PARAMETERS "Outros parametros"
|
||||
#define D_WEB_ADMIN_PASSWORD "Palavra Chave de WEB Admin"
|
||||
#define D_MQTT_ENABLE "MQTT habilitado"
|
||||
#define D_FRIENDLY_NAME "Nome amigável"
|
||||
#define D_BELKIN_WEMO "Belkin WeMo"
|
||||
#define D_HUE_BRIDGE "Hue Bridge"
|
||||
#define D_SINGLE_DEVICE "dispositivo único"
|
||||
#define D_MULTI_DEVICE "multiplos dispositivos"
|
||||
|
||||
#define D_SAVE_CONFIGURATION "Salvar configuração"
|
||||
#define D_CONFIGURATION_SAVED "Configuração guardada"
|
||||
#define D_CONFIGURATION_RESET "Reinicialização da configuração"
|
||||
|
||||
#define D_PROGRAM_VERSION "Versão do Programa"
|
||||
#define D_BUILD_DATE_AND_TIME "Data e Hora da construção"
|
||||
#define D_CORE_AND_SDK_VERSION "Versão Core/SDK"
|
||||
#define D_FLASH_WRITE_COUNT "contagem de gravação flash"
|
||||
#define D_MAC_ADDRESS "Endereço MAC"
|
||||
#define D_MQTT_HOST "MQTT Servidor"
|
||||
#define D_MQTT_PORT "MQTT Porta"
|
||||
#define D_MQTT_CLIENT "MQTT Cliente"
|
||||
#define D_MQTT_USER "MQTT Utilizador"
|
||||
#define D_MQTT_TOPIC "MQTT Tópico"
|
||||
#define D_MQTT_GROUP_TOPIC "MQTT Tópico Grupo"
|
||||
#define D_MQTT_FULL_TOPIC "MQTT Tópico Completo"
|
||||
#define D_MDNS_DISCOVERY "Descobrir mDNS"
|
||||
#define D_MDNS_ADVERTISE "Anunciar mDNS"
|
||||
#define D_ESP_CHIP_ID "ESP Chip Id"
|
||||
#define D_FLASH_CHIP_ID "Flash Chip Id"
|
||||
#define D_FLASH_CHIP_SIZE "Flash Size"
|
||||
#define D_FREE_PROGRAM_SPACE "Espaço Livre Programa"
|
||||
|
||||
#define D_UPGRADE_BY_WEBSERVER "Atualizar pelo servidor WEB"
|
||||
#define D_OTA_URL "OTA Url"
|
||||
#define D_START_UPGRADE "Iniciar atualização"
|
||||
#define D_UPGRADE_BY_FILE_UPLOAD "Atualização por envio de ficheiro"
|
||||
#define D_UPLOAD_STARTED "Início do envio"
|
||||
#define D_UPGRADE_STARTED "Atualização Iniciada"
|
||||
#define D_UPLOAD_DONE "Atualização Finalizada"
|
||||
#define D_UPLOAD_ERR_1 "Nenhum ficheiro selecionado"
|
||||
#define D_UPLOAD_ERR_2 "Nao existe espaço disponível"
|
||||
#define D_UPLOAD_ERR_3 "Byte mágico não é 0xE9"
|
||||
#define D_UPLOAD_ERR_4 "O tamanho do programa e maior do que o tamanho real da flash"
|
||||
#define D_UPLOAD_ERR_5 "Envio buffer miscompare"
|
||||
#define D_UPLOAD_ERR_6 "Falha no envio. Hablitar logging 3"
|
||||
#define D_UPLOAD_ERR_7 "Envio cancelado"
|
||||
#define D_UPLOAD_ERR_8 "Ficheiro inválido"
|
||||
#define D_UPLOAD_ERR_9 "Ficheiro demasiado grande"
|
||||
#define D_UPLOAD_ERROR_CODE "Código de erro do envio"
|
||||
|
||||
#define D_ENTER_COMMAND "Inserir comando"
|
||||
#define D_ENABLE_WEBLOG_FOR_RESPONSE "Habilitar weblog 2 se resposta esperada"
|
||||
#define D_NEED_USER_AND_PASSWORD "Necessário user=<nome utilizador>&password=<palavra chave>"
|
||||
|
||||
// xdrv_wemohue.ino
|
||||
#define D_MULTICAST_DISABLED "Multicast desabilitado"
|
||||
#define D_MULTICAST_REJOINED "Multicast (re)ingressou"
|
||||
#define D_MULTICAST_JOIN_FAILED "Multicast falha no reingresso"
|
||||
#define D_FAILED_TO_SEND_RESPONSE "Falha no envio de reposta"
|
||||
|
||||
#define D_WEMO "WeMo"
|
||||
#define D_WEMO_BASIC_EVENT "WeMo evento básico"
|
||||
#define D_WEMO_EVENT_SERVICE "WeMo evento de serviço"
|
||||
#define D_WEMO_META_SERVICE "WeMo serviço meta"
|
||||
#define D_WEMO_SETUP "WeMo configuração"
|
||||
#define D_RESPONSE_SENT "Rsposta enviada"
|
||||
|
||||
#define D_HUE "Hue"
|
||||
#define D_HUE_BRIDGE_SETUP "Hue setup"
|
||||
#define D_HUE_API_NOT_IMPLEMENTED "Hue API nao implementada"
|
||||
#define D_HUE_API "Hue API"
|
||||
#define D_HUE_POST_ARGS "Hue POST args"
|
||||
#define D_3_RESPONSE_PACKETS_SENT "3 pacotes de resposta enviados"
|
||||
|
||||
// xdrv_05_domoticz.ino
|
||||
#define D_DOMOTICZ_PARAMETERS "Parametros Domoticz"
|
||||
#define D_DOMOTICZ_IDX "Idx"
|
||||
#define D_DOMOTICZ_KEY_IDX "Chave idx"
|
||||
#define D_DOMOTICZ_SWITCH_IDX "Interruptor 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 "Potência,Energia"
|
||||
#define D_DOMOTICZ_ILLUMINANCE "Luminâcia"
|
||||
#define D_DOMOTICZ_COUNT "Contagem"
|
||||
#define D_DOMOTICZ_VOLTAGE "Voltagem"
|
||||
#define D_DOMOTICZ_CURRENT "Corrente"
|
||||
#define D_DOMOTICZ_AIRQUALITY "Qualidade do Ar"
|
||||
#define D_DOMOTICZ_UPDATE_TIMER "Tempo de atualização"
|
||||
|
||||
// xdrv_03_energy.ino
|
||||
#define D_ENERGY_TODAY "Consumo energético de hoje"
|
||||
#define D_ENERGY_YESTERDAY "Consumo energético de ontem"
|
||||
#define D_ENERGY_TOTAL "Consumo total de energial"
|
||||
|
||||
// xsns_05_ds18b20.ino
|
||||
#define D_SENSOR_BUSY "Sensor ocupado"
|
||||
#define D_SENSOR_CRC_ERROR "Erro Sensor CRC"
|
||||
#define D_SENSORS_FOUND "Sensors encontrados"
|
||||
|
||||
// xsns_06_dht.ino
|
||||
#define D_TIMEOUT_WAITING_FOR "Fim do tempo de espera"
|
||||
#define D_START_SIGNAL_LOW "Sinal de início baixo"
|
||||
#define D_START_SIGNAL_HIGH "Sinal de início elevado"
|
||||
#define D_PULSE "pulse"
|
||||
#define D_CHECKSUM_FAILURE "Falha Checksum"
|
||||
|
||||
// xsns_07_sht1x.ino
|
||||
#define D_SENSOR_DID_NOT_ACK_COMMAND "Sensor não aceitou o comando ACK"
|
||||
#define D_SHT1X_FOUND "SHT1X encontrado"
|
||||
|
||||
// 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 "Partículas"
|
||||
|
||||
// sonoff_template.h
|
||||
#define D_SENSOR_NONE "Nenhum"
|
||||
#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_IRSEND "IRsend"
|
||||
#define D_SENSOR_SWITCH "Interruptor" // Suffix "1"
|
||||
#define D_SENSOR_BUTTON "Botão" // Suffix "1"
|
||||
#define D_SENSOR_RELAY "Relé" // Suffix "1i"
|
||||
#define D_SENSOR_LED "Led" // Suffix "1i"
|
||||
#define D_SENSOR_PWM "PWM" // Suffix "1"
|
||||
#define D_SENSOR_COUNTER "Contador" // 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 "Luz negra"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "A"
|
||||
#define D_UNIT_HOUR "Hr"
|
||||
#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_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_VOLT "V"
|
||||
#define D_UNIT_WATT "W"
|
||||
#define D_UNIT_WATTHOUR "Wh"
|
||||
|
||||
// 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_PT_PT_H_
|
|
@ -408,6 +408,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "А"
|
||||
|
|
|
@ -407,6 +407,7 @@
|
|||
#define D_SENSOR_SPI_DC "SPI DC"
|
||||
#define D_SENSOR_BACKLIGHT "BkLight"
|
||||
#define D_SENSOR_PMS5003 "PMS5003"
|
||||
#define D_SENSOR_SDS0X1 "SDS0X1"
|
||||
|
||||
// Units
|
||||
#define D_UNIT_AMPERE "安"
|
||||
|
|
|
@ -221,9 +221,7 @@ char* GetMqttClient(char* output, const char* input, int size)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!digits) {
|
||||
strlcpy(output, input, size);
|
||||
}
|
||||
if (!digits) strlcpy(output, input, size);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -270,17 +268,13 @@ void GetTopic_P(char *stopic, byte prefix, char *topic, const char* subtopic)
|
|||
}
|
||||
fulltopic.replace(F("#"), "");
|
||||
fulltopic.replace(F("//"), "/");
|
||||
if (!fulltopic.endsWith("/")) {
|
||||
fulltopic += "/";
|
||||
}
|
||||
if (!fulltopic.endsWith("/")) fulltopic += "/";
|
||||
snprintf_P(stopic, TOPSZ, PSTR("%s%s"), fulltopic.c_str(), romram);
|
||||
}
|
||||
|
||||
char* GetStateText(byte state)
|
||||
{
|
||||
if (state > 3) {
|
||||
state = 1;
|
||||
}
|
||||
if (state > 3) state = 1;
|
||||
return Settings.state_text[state];
|
||||
}
|
||||
|
||||
|
@ -315,9 +309,7 @@ void SetDevicePower(power_t rpower)
|
|||
power_t mask = 1;
|
||||
uint8_t count = 0;
|
||||
for (byte i = 0; i < devices_present; i++) {
|
||||
if (rpower & mask) {
|
||||
count++;
|
||||
}
|
||||
if (rpower & mask) count++;
|
||||
mask <<= 1;
|
||||
}
|
||||
if (count > 1) {
|
||||
|
@ -352,9 +344,7 @@ void SetDevicePower(power_t rpower)
|
|||
|
||||
void SetLedPower(uint8_t state)
|
||||
{
|
||||
if (state) {
|
||||
state = 1;
|
||||
}
|
||||
if (state) state = 1;
|
||||
digitalWrite(pin[GPIO_LED1], (bitRead(led_inverted, 0)) ? !state : state);
|
||||
}
|
||||
|
||||
|
@ -392,9 +382,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
|
||||
strncpy(topicBuf, topic, sizeof(topicBuf));
|
||||
for (i = 0; i < data_len; i++) {
|
||||
if (!isspace(data[i])) {
|
||||
break;
|
||||
}
|
||||
if (!isspace(data[i])) break;
|
||||
}
|
||||
data_len -= i;
|
||||
memcpy(dataBuf, data +i, sizeof(dataBuf));
|
||||
|
@ -419,9 +407,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
while (isdigit(type[i-1])) {
|
||||
i--;
|
||||
}
|
||||
if (i < strlen(type)) {
|
||||
index = atoi(type +i);
|
||||
}
|
||||
if (i < strlen(type)) index = atoi(type +i);
|
||||
type[i] = '\0';
|
||||
}
|
||||
|
||||
|
@ -431,13 +417,9 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
|
||||
if (type != NULL) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}"));
|
||||
if (Settings.ledstate &0x02) {
|
||||
blinks++;
|
||||
}
|
||||
if (Settings.ledstate &0x02) blinks++;
|
||||
|
||||
if (!strcmp(dataBuf,"?")) {
|
||||
data_len = 0;
|
||||
}
|
||||
if (!strcmp(dataBuf,"?")) data_len = 0;
|
||||
int16_t payload = -99; // No payload
|
||||
uint16_t payload16 = 0;
|
||||
long lnum = strtol(dataBuf, &p, 10);
|
||||
|
@ -489,23 +471,17 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
}
|
||||
}
|
||||
else if (CMND_DELAY == command_code) {
|
||||
if ((payload >= MIN_BACKLOG_DELAY) && (payload <= 3600)) {
|
||||
backlog_delay = payload;
|
||||
}
|
||||
if ((payload >= MIN_BACKLOG_DELAY) && (payload <= 3600)) backlog_delay = payload;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, backlog_delay);
|
||||
}
|
||||
else if ((CMND_POWER == command_code) && (index > 0) && (index <= devices_present)) {
|
||||
if ((payload < 0) || (payload > 4)) {
|
||||
payload = 9;
|
||||
}
|
||||
if ((payload < 0) || (payload > 4)) payload = 9;
|
||||
ExecuteCommandPower(index, payload);
|
||||
fallback_topic_flag = 0;
|
||||
return;
|
||||
}
|
||||
else if (CMND_STATUS == command_code) {
|
||||
if ((payload < 0) || (payload > MAX_STATUS)) {
|
||||
payload = 99;
|
||||
}
|
||||
if ((payload < 0) || (payload > MAX_STATUS)) payload = 99;
|
||||
PublishStatus(payload);
|
||||
fallback_topic_flag = 0;
|
||||
return;
|
||||
|
@ -542,18 +518,14 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
else if (CMND_BLINKTIME == command_code) {
|
||||
if ((payload > 2) && (payload <= 3600)) {
|
||||
Settings.blinktime = payload;
|
||||
if (blink_timer) {
|
||||
blink_timer = Settings.blinktime;
|
||||
}
|
||||
if (blink_timer) blink_timer = Settings.blinktime;
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.blinktime);
|
||||
}
|
||||
else if (CMND_BLINKCOUNT == command_code) {
|
||||
if (data_len > 0) {
|
||||
Settings.blinkcount = payload16; // 0 - 65535
|
||||
if (blink_counter) {
|
||||
blink_counter = Settings.blinkcount *2;
|
||||
}
|
||||
if (blink_counter) blink_counter = Settings.blinkcount *2;
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.blinkcount);
|
||||
}
|
||||
|
@ -569,15 +541,15 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, (Settings.save_data > 1) ? stemp1 : GetStateText(Settings.save_data));
|
||||
}
|
||||
else if (CMND_SENSOR == command_code) {
|
||||
XdrvMailbox.topic = command;
|
||||
XdrvMailbox.index = index;
|
||||
XdrvMailbox.payload = payload;
|
||||
XdrvMailbox.data_len = data_len;
|
||||
XdrvMailbox.payload16 = payload16;
|
||||
XdrvMailbox.payload = payload;
|
||||
XdrvMailbox.grpflg = grpflg;
|
||||
XdrvMailbox.topic = command;
|
||||
XdrvMailbox.data = dataBuf;
|
||||
XsnsCall(FUNC_COMMAND);
|
||||
// if (!XsnsCall(FUNC_COMMAND)) {
|
||||
// type = NULL;
|
||||
// }
|
||||
// if (!XsnsCall(FUNC_COMMAND)) type = NULL;
|
||||
}
|
||||
else if ((CMND_SETOPTION == command_code) && ((index <= 21) || ((index > 31) && (index <= P_MAX_PARAM8 + 31)))) {
|
||||
if (index <= 31) {
|
||||
|
@ -632,9 +604,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (ptype) {
|
||||
snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), Settings.param[index]);
|
||||
}
|
||||
if (ptype) snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), Settings.param[index]);
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, (ptype) ? index +32 : index, (ptype) ? stemp1 : GetStateText(bitRead(Settings.flag.data, index)));
|
||||
}
|
||||
else if (CMND_TEMPERATURE_RESOLUTION == command_code) {
|
||||
|
@ -729,9 +699,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
byte jsflg = 0;
|
||||
for (byte i = 0; i < MAX_GPIO_PIN; i++) {
|
||||
if (GPIO_USER == cmodule.gp.io[i]) {
|
||||
if (jsflg) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
|
||||
}
|
||||
if (jsflg) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
|
||||
jsflg = 1;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_GPIO "%d\":\"%d (%s)\""),
|
||||
mqtt_data, i, Settings.my_gp.io[i], GetTextIndexed(stemp1, sizeof(stemp1), Settings.my_gp.io[i], kSensorNames));
|
||||
|
@ -769,7 +737,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_PWM "\":{"));
|
||||
bool first = true;
|
||||
for (byte i = 0; i < MAX_PWMS; i++) {
|
||||
if(pin[GPIO_PWM1 + i] < 99) {
|
||||
if (pin[GPIO_PWM1 + i] < 99) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_PWM "%d\":%d"), mqtt_data, first ? "" : ",", i+1, Settings.pwm_value[i]);
|
||||
first = false;
|
||||
}
|
||||
|
@ -818,9 +786,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
}
|
||||
else if (CMND_SLEEP == command_code) {
|
||||
if ((payload >= 0) && (payload < 251)) {
|
||||
if ((!Settings.sleep && payload) || (Settings.sleep && !payload)) {
|
||||
restart_flag = 2;
|
||||
}
|
||||
if ((!Settings.sleep && payload) || (Settings.sleep && !payload)) restart_flag = 2;
|
||||
Settings.sleep = payload;
|
||||
sleep = payload;
|
||||
}
|
||||
|
@ -867,9 +833,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.syslog_host);
|
||||
}
|
||||
else if (CMND_LOGPORT == command_code) {
|
||||
if (payload16 > 0) {
|
||||
Settings.syslog_port = (1 == payload16) ? SYS_LOG_PORT : payload16;
|
||||
}
|
||||
if (payload16 > 0) Settings.syslog_port = (1 == payload16) ? SYS_LOG_PORT : payload16;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.syslog_port);
|
||||
}
|
||||
else if ((CMND_IPADDRESS == command_code) && (index > 0) && (index <= 4)) {
|
||||
|
@ -884,9 +848,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
if ((data_len > 0) && (data_len < sizeof(Settings.ntp_server[0]))) {
|
||||
strlcpy(Settings.ntp_server[index -1], (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? (1==index)?NTP_SERVER1:(2==index)?NTP_SERVER2:NTP_SERVER3 : dataBuf, sizeof(Settings.ntp_server[0]));
|
||||
for (i = 0; i < strlen(Settings.ntp_server[index -1]); i++) {
|
||||
if (Settings.ntp_server[index -1][i] == ',') {
|
||||
Settings.ntp_server[index -1][i] = '.';
|
||||
}
|
||||
if (Settings.ntp_server[index -1][i] == ',') Settings.ntp_server[index -1][i] = '.';
|
||||
}
|
||||
restart_flag = 2;
|
||||
}
|
||||
|
@ -959,16 +921,12 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, index, Settings.friendlyname[index -1]);
|
||||
}
|
||||
else if ((CMND_SWITCHMODE == command_code) && (index > 0) && (index <= MAX_SWITCHES)) {
|
||||
if ((payload >= 0) && (payload < MAX_SWITCH_OPTION)) {
|
||||
Settings.switchmode[index -1] = payload;
|
||||
}
|
||||
if ((payload >= 0) && (payload < MAX_SWITCH_OPTION)) Settings.switchmode[index -1] = payload;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, index, Settings.switchmode[index-1]);
|
||||
}
|
||||
#ifdef USE_WEBSERVER
|
||||
else if (CMND_WEBSERVER == command_code) {
|
||||
if ((payload >= 0) && (payload <= 2)) {
|
||||
Settings.webserver = payload;
|
||||
}
|
||||
if ((payload >= 0) && (payload <= 2)) Settings.webserver = payload;
|
||||
if (Settings.webserver) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_WEBSERVER "\":\"" D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %s\"}"),
|
||||
(2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str());
|
||||
|
@ -983,9 +941,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.web_password);
|
||||
}
|
||||
else if (CMND_WEBLOG == command_code) {
|
||||
if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) {
|
||||
Settings.weblog_level = payload;
|
||||
}
|
||||
if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) Settings.weblog_level = payload;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.weblog_level);
|
||||
}
|
||||
#ifdef USE_EMULATION
|
||||
|
@ -1001,9 +957,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
else if (CMND_TELEPERIOD == command_code) {
|
||||
if ((payload >= 0) && (payload < 3601)) {
|
||||
Settings.tele_period = (1 == payload) ? TELE_PERIOD : payload;
|
||||
if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) {
|
||||
Settings.tele_period = 10; // Do not allow periods < 10 seconds
|
||||
}
|
||||
if ((Settings.tele_period > 0) && (Settings.tele_period < 10)) Settings.tele_period = 10; // Do not allow periods < 10 seconds
|
||||
tele_period = Settings.tele_period;
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_UNIT, command, Settings.tele_period, (Settings.flag.value_units) ? " " D_UNIT_SECOND : "");
|
||||
|
@ -1038,15 +992,11 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
}
|
||||
}
|
||||
else if (CMND_TIMEZONE == command_code) {
|
||||
if ((data_len > 0) && (((payload >= -13) && (payload <= 13)) || (99 == payload))) {
|
||||
Settings.timezone = payload;
|
||||
}
|
||||
if ((data_len > 0) && (((payload >= -13) && (payload <= 13)) || (99 == payload))) Settings.timezone = payload;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.timezone);
|
||||
}
|
||||
else if (CMND_ALTITUDE == command_code) {
|
||||
if ((data_len > 0) && ((payload >= -30000) && (payload <= 30000))) {
|
||||
Settings.altitude = payload;
|
||||
}
|
||||
if ((data_len > 0) && ((payload >= -30000) && (payload <= 30000))) Settings.altitude = payload;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.altitude);
|
||||
}
|
||||
else if (CMND_LEDPOWER == command_code) {
|
||||
|
@ -1069,9 +1019,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
else if (CMND_LEDSTATE ==command_code) {
|
||||
if ((payload >= 0) && (payload < MAX_LED_OPTION)) {
|
||||
Settings.ledstate = payload;
|
||||
if (!Settings.ledstate) {
|
||||
SetLedPower(0);
|
||||
}
|
||||
if (!Settings.ledstate) SetLedPower(0);
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.ledstate);
|
||||
}
|
||||
|
@ -1084,17 +1032,12 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
I2cScan(mqtt_data, sizeof(mqtt_data));
|
||||
}
|
||||
#endif // USE_I2C
|
||||
// else if (Settings.flag.mqtt_enabled && MqttCommand(grpflg, type, index, dataBuf, data_len, payload, payload16)) {
|
||||
// Serviced
|
||||
// }
|
||||
else if (XdrvCommand(grpflg, type, index, dataBuf, data_len, payload, payload16)) {
|
||||
// Serviced
|
||||
}
|
||||
#ifdef DEBUG_THEO
|
||||
else if (CMND_EXCEPTION == command_code) {
|
||||
if (data_len > 0) {
|
||||
ExceptionTest(payload);
|
||||
}
|
||||
if (data_len > 0) ExceptionTest(payload);
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
|
||||
}
|
||||
#endif // DEBUG_THEO
|
||||
|
@ -1108,9 +1051,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
|
|||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_UNKNOWN "\"}"));
|
||||
type = (char*)topicBuf;
|
||||
}
|
||||
if (mqtt_data[0] != '\0') {
|
||||
MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
|
||||
}
|
||||
if (mqtt_data[0] != '\0') MqttPublishPrefixTopic_P(RESULT_OR_STAT, type);
|
||||
fallback_topic_flag = 0;
|
||||
}
|
||||
|
||||
|
@ -1132,9 +1073,7 @@ boolean send_button_power(byte key, byte device, byte state)
|
|||
|
||||
char *key_topic = (key) ? Settings.switch_topic : Settings.button_topic;
|
||||
if (Settings.flag.mqtt_enabled && MqttIsConnected() && (strlen(key_topic) != 0) && strcmp(key_topic, "0")) {
|
||||
if (!key && (device > devices_present)) {
|
||||
device = 1;
|
||||
}
|
||||
if (!key && (device > devices_present)) device = 1;
|
||||
GetTopic_P(stopic, CMND, key_topic, GetPowerDevice(scommand, device, sizeof(scommand), key));
|
||||
if (9 == state) {
|
||||
mqtt_data[0] = '\0';
|
||||
|
@ -1173,12 +1112,8 @@ void ExecuteCommandPower(byte device, byte state)
|
|||
state &= 1;
|
||||
publish_power = 0;
|
||||
}
|
||||
if ((device < 1) || (device > devices_present)) {
|
||||
device = 1;
|
||||
}
|
||||
if (device <= MAX_PULSETIMERS) {
|
||||
pulse_timer[(device -1)] = 0;
|
||||
}
|
||||
if ((device < 1) || (device > devices_present)) device = 1;
|
||||
if (device <= MAX_PULSETIMERS) pulse_timer[(device -1)] = 0;
|
||||
power_t mask = 1 << (device -1);
|
||||
if (state <= POWER_TOGGLE) {
|
||||
if ((blink_mask & mask)) {
|
||||
|
@ -1189,9 +1124,7 @@ void ExecuteCommandPower(byte device, byte state)
|
|||
interlock_mutex = 1;
|
||||
for (byte i = 0; i < devices_present; i++) {
|
||||
power_t imask = 1 << i;
|
||||
if ((power & imask) && (mask != imask)) {
|
||||
ExecuteCommandPower(i +1, POWER_OFF);
|
||||
}
|
||||
if ((power & imask) && (mask != imask)) ExecuteCommandPower(i +1, POWER_OFF);
|
||||
}
|
||||
interlock_mutex = 0;
|
||||
}
|
||||
|
@ -1229,14 +1162,10 @@ void ExecuteCommandPower(byte device, byte state)
|
|||
byte flag = (blink_mask & mask);
|
||||
blink_mask &= (POWER_MASK ^ mask); // Clear device mask
|
||||
MqttPublishPowerBlinkState(device);
|
||||
if (flag) {
|
||||
ExecuteCommandPower(device, (blink_powersave >> (device -1))&1); // Restore state
|
||||
}
|
||||
if (flag) ExecuteCommandPower(device, (blink_powersave >> (device -1))&1); // Restore state
|
||||
return;
|
||||
}
|
||||
if (publish_power) {
|
||||
MqttPublishPowerState(device);
|
||||
}
|
||||
if (publish_power) MqttPublishPowerState(device);
|
||||
}
|
||||
|
||||
void StopAllPowerBlink()
|
||||
|
@ -1263,9 +1192,7 @@ void ExecuteCommand(char *cmnd)
|
|||
token = strtok(cmnd, " ");
|
||||
if (token != NULL) {
|
||||
start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble
|
||||
if (start) {
|
||||
token = start +1;
|
||||
}
|
||||
if (start) token = start +1;
|
||||
}
|
||||
snprintf_P(stopic, sizeof(stopic), PSTR("/%s"), (token == NULL) ? "" : token);
|
||||
token = strtok(NULL, "");
|
||||
|
@ -1279,16 +1206,10 @@ void PublishStatus(uint8_t payload)
|
|||
uint8_t option = 1;
|
||||
|
||||
// Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX
|
||||
if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) {
|
||||
option++;
|
||||
}
|
||||
if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) option++;
|
||||
|
||||
if ((!Settings.flag.mqtt_enabled) && (6 == payload)) {
|
||||
payload = 99;
|
||||
}
|
||||
if (!energy_flg && (9 == payload)) {
|
||||
payload = 99;
|
||||
}
|
||||
if ((!Settings.flag.mqtt_enabled) && (6 == payload)) payload = 99;
|
||||
if (!energy_flg && (9 == payload)) payload = 99;
|
||||
|
||||
if ((0 == payload) || (99 == payload)) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":\"%s\",\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"),
|
||||
|
@ -1328,8 +1249,8 @@ void PublishStatus(uint8_t payload)
|
|||
}
|
||||
|
||||
if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"),
|
||||
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS6_MQTT "\":{\"" D_CMND_MQTTHOST "\":\"%s\",\"" D_CMND_MQTTPORT "\":%d,\"" D_CMND_MQTTCLIENT D_JSON_MASK "\":\"%s\",\"" D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"MqttType\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"),
|
||||
Settings.mqtt_host, Settings.mqtt_port, Settings.mqtt_client, mqtt_client, Settings.mqtt_user, MqttLibraryType(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE);
|
||||
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "6"));
|
||||
}
|
||||
|
||||
|
@ -1406,9 +1327,7 @@ boolean MqttShowSensor()
|
|||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
|
||||
|
||||
if (json_data_available) {
|
||||
XdrvCall(FUNC_SHOW_SENSOR);
|
||||
}
|
||||
if (json_data_available) XdrvCall(FUNC_SHOW_SENSOR);
|
||||
return json_data_available;
|
||||
}
|
||||
|
||||
|
@ -1418,14 +1337,10 @@ void PerformEverySecond()
|
|||
{
|
||||
uptime++;
|
||||
|
||||
if (blockgpio0) {
|
||||
blockgpio0--;
|
||||
}
|
||||
if (blockgpio0) blockgpio0--;
|
||||
|
||||
for (byte i = 0; i < MAX_PULSETIMERS; i++) {
|
||||
if (pulse_timer[i] > 111) {
|
||||
pulse_timer[i]--;
|
||||
}
|
||||
if (pulse_timer[i] > 111) pulse_timer[i]--;
|
||||
}
|
||||
|
||||
if (seriallog_timer) {
|
||||
|
@ -1470,10 +1385,7 @@ void PerformEverySecond()
|
|||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE));
|
||||
|
||||
mqtt_data[0] = '\0';
|
||||
if (MqttShowSensor()) {
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
|
||||
}
|
||||
|
||||
if (MqttShowSensor()) MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1485,9 +1397,7 @@ void PerformEverySecond()
|
|||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"" D_JSON_UPTIME "\":\"%s\"}"), GetDateAndTime(DT_LOCAL).c_str(), GetDateAndTime(DT_UPTIME).c_str());
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_UPTIME));
|
||||
}
|
||||
if ((3 == RtcTime.minute) && !latest_uptime_flag) {
|
||||
latest_uptime_flag = true;
|
||||
}
|
||||
if ((3 == RtcTime.minute) && !latest_uptime_flag) latest_uptime_flag = true;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
@ -1525,9 +1435,7 @@ void ButtonHandler()
|
|||
|
||||
if (button_present) {
|
||||
if (SONOFF_4CHPRO == Settings.module) {
|
||||
if (holdbutton[button_index]) {
|
||||
holdbutton[button_index]--;
|
||||
}
|
||||
if (holdbutton[button_index]) holdbutton[button_index]--;
|
||||
|
||||
boolean button_pressed = false;
|
||||
if ((PRESSED == button) && (NOT_PRESSED == lastbutton[button_index])) {
|
||||
|
@ -1539,9 +1447,7 @@ void ButtonHandler()
|
|||
if ((NOT_PRESSED == button) && (PRESSED == lastbutton[button_index])) {
|
||||
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1);
|
||||
AddLog(LOG_LEVEL_DEBUG);
|
||||
if (!holdbutton[button_index]) { // Do not allow within 1 second
|
||||
button_pressed = true;
|
||||
}
|
||||
if (!holdbutton[button_index]) button_pressed = true; // Do not allow within 1 second
|
||||
}
|
||||
if (button_pressed) {
|
||||
if (!send_button_power(0, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set
|
||||
|
@ -1733,15 +1639,11 @@ void StateLoop()
|
|||
|
||||
if (!(state % (STATES/10))) {
|
||||
|
||||
if (mqtt_cmnd_publish) {
|
||||
mqtt_cmnd_publish--; // Clean up
|
||||
}
|
||||
if (mqtt_cmnd_publish) mqtt_cmnd_publish--; // Clean up
|
||||
|
||||
if (latching_relay_pulse) {
|
||||
latching_relay_pulse--;
|
||||
if (!latching_relay_pulse) {
|
||||
SetLatchingRelay(0, 0);
|
||||
}
|
||||
if (!latching_relay_pulse) SetLatchingRelay(0, 0);
|
||||
}
|
||||
|
||||
for (byte i = 0; i < MAX_PULSETIMERS; i++) {
|
||||
|
@ -1770,9 +1672,7 @@ void StateLoop()
|
|||
}
|
||||
|
||||
// Backlog
|
||||
if (backlog_delay) {
|
||||
backlog_delay--;
|
||||
}
|
||||
if (backlog_delay) backlog_delay--;
|
||||
if ((backlog_pointer != backlog_index) && !backlog_delay && !backlog_mutex) {
|
||||
backlog_mutex = 1;
|
||||
ExecuteCommand((char*)backlog[backlog_pointer].c_str());
|
||||
|
@ -1813,9 +1713,7 @@ void StateLoop()
|
|||
}
|
||||
if (!blinkstate) {
|
||||
blinks--;
|
||||
if (200 == blinks) {
|
||||
blinks = 0;
|
||||
}
|
||||
if (200 == blinks) blinks = 0;
|
||||
}
|
||||
} else {
|
||||
if (Settings.ledstate &1) {
|
||||
|
@ -1845,9 +1743,7 @@ void StateLoop()
|
|||
}
|
||||
if (ota_state_flag <= 0) {
|
||||
#ifdef USE_WEBSERVER
|
||||
if (Settings.webserver) {
|
||||
StopWebserver();
|
||||
}
|
||||
if (Settings.webserver) StopWebserver();
|
||||
#endif // USE_WEBSERVER
|
||||
#ifdef USE_ARILUX_RF
|
||||
AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine
|
||||
|
@ -1861,9 +1757,7 @@ void StateLoop()
|
|||
if (RtcSettings.ota_loader) {
|
||||
char *pch = strrchr(mqtt_data, '-'); // Change from filename-DE.bin into filename-minimal.bin
|
||||
char *ech = strrchr(mqtt_data, '.'); // Change from filename.bin into filename-minimal.bin
|
||||
if (!pch) {
|
||||
pch = ech;
|
||||
}
|
||||
if (!pch) pch = ech;
|
||||
if (pch) {
|
||||
mqtt_data[pch - mqtt_data] = '\0';
|
||||
char *ech = strrchr(Settings.ota_url, '.'); // Change from filename.bin into filename-minimal.bin
|
||||
|
@ -1901,9 +1795,7 @@ void StateLoop()
|
|||
}
|
||||
break;
|
||||
case (STATES/10)*4:
|
||||
if (MidnightNow()) {
|
||||
CounterSaveState();
|
||||
}
|
||||
if (MidnightNow()) CounterSaveState();
|
||||
if (save_data_counter && (backlog_pointer == backlog_index)) {
|
||||
save_data_counter--;
|
||||
if (save_data_counter <= 0) {
|
||||
|
@ -1948,6 +1840,9 @@ void StateLoop()
|
|||
WifiCheck(wifi_state_flag);
|
||||
wifi_state_flag = WIFI_RESTART;
|
||||
break;
|
||||
case (STATES/10)*8:
|
||||
if (WL_CONNECTED == WiFi.status()) MqttCheck();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2100,14 +1995,10 @@ void GpioInit()
|
|||
}
|
||||
#endif // USE_DHT
|
||||
}
|
||||
if (mpin) {
|
||||
pin[mpin] = i;
|
||||
}
|
||||
if (mpin) pin[mpin] = i;
|
||||
}
|
||||
|
||||
if (2 == pin[GPIO_TXD]) {
|
||||
Serial.set_tx(2);
|
||||
}
|
||||
if (2 == pin[GPIO_TXD]) Serial.set_tx(2);
|
||||
|
||||
analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h)
|
||||
analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
|
||||
|
@ -2116,9 +2007,7 @@ void GpioInit()
|
|||
spi_flg = ((((pin[GPIO_SPI_CS] < 99) && (pin[GPIO_SPI_CS] > 14)) || (pin[GPIO_SPI_CS] < 12)) || (((pin[GPIO_SPI_DC] < 99) && (pin[GPIO_SPI_DC] > 14)) || (pin[GPIO_SPI_DC] < 12)));
|
||||
if (spi_flg) {
|
||||
for (byte i = 0; i < GPIO_MAX; i++) {
|
||||
if ((pin[i] >= 12) && (pin[i] <=14)) {
|
||||
pin[i] = 99;
|
||||
}
|
||||
if ((pin[i] >= 12) && (pin[i] <=14)) pin[i] = 99;
|
||||
}
|
||||
my_module.gp.io[12] = GPIO_SPI_MISO;
|
||||
pin[GPIO_SPI_MISO] = 12;
|
||||
|
@ -2131,9 +2020,7 @@ void GpioInit()
|
|||
|
||||
#ifdef USE_I2C
|
||||
i2c_flg = ((pin[GPIO_I2C_SCL] < 99) && (pin[GPIO_I2C_SDA] < 99));
|
||||
if (i2c_flg) {
|
||||
Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]);
|
||||
}
|
||||
if (i2c_flg) Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]);
|
||||
#endif // USE_I2C
|
||||
|
||||
devices_present = 1;
|
||||
|
@ -2141,9 +2028,7 @@ void GpioInit()
|
|||
light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0
|
||||
if (Settings.flag.pwm_control) {
|
||||
for (byte i = 0; i < MAX_PWMS; i++) {
|
||||
if (pin[GPIO_PWM1 +i] < 99) {
|
||||
light_type++; // Use Dimmer/Color control for all PWM as SetOption15 = 1
|
||||
}
|
||||
if (pin[GPIO_PWM1 +i] < 99) light_type++; // Use Dimmer/Color control for all PWM as SetOption15 = 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2176,9 +2061,7 @@ void GpioInit()
|
|||
light_type = LT_RGBWC;
|
||||
}
|
||||
else {
|
||||
if (!light_type) {
|
||||
devices_present = 0;
|
||||
}
|
||||
if (!light_type) devices_present = 0;
|
||||
for (byte i = 0; i < MAX_RELAYS; i++) {
|
||||
if (pin[GPIO_REL1 +i] < 99) {
|
||||
pinMode(pin[GPIO_REL1 +i], OUTPUT);
|
||||
|
@ -2287,9 +2170,7 @@ void setup()
|
|||
}
|
||||
WifiConnect();
|
||||
|
||||
if (MOTOR == Settings.module) {
|
||||
Settings.poweronstate = POWER_ALL_ON; // Needs always on else in limbo!
|
||||
}
|
||||
if (MOTOR == Settings.module) Settings.poweronstate = POWER_ALL_ON; // Needs always on else in limbo!
|
||||
if (POWER_ALL_ALWAYS_ON == Settings.poweronstate) {
|
||||
SetDevicePower(1);
|
||||
} else {
|
||||
|
|
|
@ -61,6 +61,7 @@ void WifiWpsStatusCallback(wps_cb_status status);
|
|||
#define CO2_HIGH 1200 // Above this CO2 value show red light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
|
||||
#endif
|
||||
#define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code)
|
||||
#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code)
|
||||
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
|
||||
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram)
|
||||
#define USE_IR_HVAC // Support for HVAC system using IR (+2k code)
|
||||
|
@ -170,4 +171,4 @@ void WifiWpsStatusCallback(wps_cb_status status);
|
|||
#define ARDUINO_ESP8266_RELEASE "STAGE"
|
||||
#endif
|
||||
|
||||
#endif // _SONOFF_POST_H_
|
||||
#endif // _SONOFF_POST_H_
|
||||
|
|
|
@ -88,6 +88,7 @@ enum UserSelectablePins {
|
|||
GPIO_SPI_DC, // SPI Data Direction
|
||||
GPIO_BACKLIGHT, // Display backlight control
|
||||
GPIO_PMS5003, // Plantower PMS5003 Serial interface
|
||||
GPIO_SDS0X1, // Nova Fitness SDS011 Serial interface
|
||||
GPIO_SENSOR_END };
|
||||
|
||||
// Programmer selectable GPIO functionality offset by user selectable GPIOs
|
||||
|
@ -129,7 +130,7 @@ const char kSensorNames[] PROGMEM =
|
|||
D_SENSOR_PZEM_TX "|" D_SENSOR_PZEM_RX "|"
|
||||
D_SENSOR_SAIR_TX "|" D_SENSOR_SAIR_RX "|"
|
||||
D_SENSOR_SPI_CS "|" D_SENSOR_SPI_DC "|" D_SENSOR_BACKLIGHT "|"
|
||||
D_SENSOR_PMS5003;
|
||||
D_SENSOR_PMS5003 "|" D_SENSOR_SDS0X1;
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
//#define MY_LANGUAGE it-IT // Italian in Italy
|
||||
//#define MY_LANGUAGE nl-NL // Dutch in the Netherlands
|
||||
//#define MY_LANGUAGE pl-PL // Polish in Poland
|
||||
//#define MY_LANGUAGE pt-PT // Portuguese in Portugal
|
||||
//#define MY_LANGUAGE ru-RU // Russian in Russia
|
||||
//#define MY_LANGUAGE zh-CN // Chinese (Simplified) in China
|
||||
|
||||
|
@ -71,13 +72,23 @@
|
|||
// -- Ota -----------------------------------------
|
||||
#define OTA_URL "http://sonoff.maddox.co.uk/tasmota/sonoff.ino.bin" // [OtaUrl]
|
||||
|
||||
/*********************************************************************************************\
|
||||
* 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 1 // Use PubSubClient library
|
||||
// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support
|
||||
//#define MQTT_LIBRARY_TYPE 2 // 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 3 // Use (patched) esp-mqtt-arduino library (+4k8 code, +4k mem) - non-TLS only
|
||||
|
||||
// -- MQTT ----------------------------------------
|
||||
#define MQTT_USE 1 // [SetOption3] Select default MQTT use (0 = Off, 1 = On)
|
||||
|
||||
// !!! TLS uses a LOT OF MEMORY (20k) so be careful to enable other options at the same time !!!
|
||||
//#define USE_MQTT_TLS // EXPERIMENTAL Use TLS for MQTT connection (+53k code, +15k mem) - Disable by //
|
||||
//#define USE_MQTT_TLS // Use TLS for MQTT connection (+53k code, +15k mem) - Disable by //
|
||||
// Needs Fingerprint, TLS Port, UserId and Password
|
||||
#ifdef USE_MQTT_TLS
|
||||
// #define MQTT_HOST "m20.cloudmqtt.com" // [MqttHost]
|
||||
#define MQTT_HOST "" // [MqttHost]
|
||||
#define MQTT_FINGERPRINT "A5 02 FF 13 99 9F 8B 39 8E F1 83 4F 11 23 65 0B 32 36 FC 07" // [MqttFingerprint]
|
||||
#define MQTT_PORT 20123 // [MqttPort] MQTT TLS port
|
||||
|
@ -204,6 +215,7 @@
|
|||
#define CO2_LOW 800 // Below this CO2 value show green light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
|
||||
#define CO2_HIGH 1200 // Above this CO2 value show red light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
|
||||
#define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code)
|
||||
#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code)
|
||||
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
|
||||
|
||||
// -- Low level interface devices -----------------
|
||||
|
|
|
@ -18,17 +18,25 @@
|
|||
*/
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Select only ONE of the defines below - Not supported yet
|
||||
* Select ONE of possible MQTT libraries below
|
||||
\*********************************************************************************************/
|
||||
|
||||
// Default MQTT driver for both non-TLS and TLS connections. Blocks network if MQTT server is unavailable.
|
||||
#define USE_MQTT_CLIENT 1 // Use PubSubClient library
|
||||
//#define MQTT_LIBRARY_TYPE 1 // Use PubSubClient library
|
||||
// Alternative MQTT driver does not block network when MQTT server is unavailable. No TLS support
|
||||
//#define MQTT_LIBRARY_TYPE 2 // 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 3 // Use (patched) esp-mqtt-arduino library (+4k8 code, +4k mem) - non-TLS only
|
||||
|
||||
// Replaces PubSubClient solving network hangs when MQTT server is unavailable. No TLS support
|
||||
//#define USE_MQTT_CLIENT 2 // Use (patched) esp-mqtt-arduino library (+4k8 code) - non-TLS only
|
||||
|
||||
// Only TLS support. Unstable due to lack of memory
|
||||
//#define USE_MQTT_CLIENT 3 // Use ESP8266MQTTClient library (+52k code, +15k mem) - TLS only and unstable
|
||||
#ifdef USE_MQTT_TLS
|
||||
#ifdef MQTT_LIBRARY_TYPE
|
||||
#undef MQTT_LIBRARY_TYPE
|
||||
#endif
|
||||
#define MQTT_LIBRARY_TYPE 1 // Use PubSubClient library as it only supports TLS
|
||||
#else
|
||||
#ifndef MQTT_LIBRARY_TYPE
|
||||
#define MQTT_LIBRARY_TYPE 1 // Use PubSubClient library as default
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
|
@ -41,8 +49,9 @@ const char kMqttCommands[] PROGMEM =
|
|||
D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|" D_CMND_FULLTOPIC "|" D_CMND_PREFIX "|" D_CMND_GROUPTOPIC "|" D_CMND_TOPIC "|"
|
||||
D_CMND_BUTTONTOPIC "|" D_CMND_SWITCHTOPIC "|" D_CMND_BUTTONRETAIN "|" D_CMND_SWITCHRETAIN "|" D_CMND_POWERRETAIN "|" D_CMND_SENSORRETAIN ;
|
||||
|
||||
uint8_t mqtt_retry_counter = 0; // MQTT connection retry counter
|
||||
uint8_t mqtt_connection_flag = 2; // MQTT connection messages flag
|
||||
uint8_t mqtt_retry_counter = 1; // MQTT connection retry counter
|
||||
uint8_t mqtt_initial_connection_state = 2; // MQTT connection messages state
|
||||
bool mqtt_connected = false; // MQTT virtual connection status
|
||||
|
||||
/*********************************************************************************************\
|
||||
* MQTT driver specific code need to provide the following functions:
|
||||
|
@ -51,11 +60,10 @@ uint8_t mqtt_connection_flag = 2; // MQTT connection messages flag
|
|||
* void MqttDisconnect()
|
||||
* void MqttSubscribeLib(char *topic)
|
||||
* bool MqttPublishLib(const char* topic, boolean retained)
|
||||
* void MqttCheckConnection()
|
||||
* void MqttLoop()
|
||||
\*********************************************************************************************/
|
||||
|
||||
#if (1 == USE_MQTT_CLIENT) /*****************************************************************/
|
||||
#if (1 == MQTT_LIBRARY_TYPE) /*****************************************************************/
|
||||
|
||||
#include <PubSubClient.h>
|
||||
|
||||
|
@ -87,38 +95,53 @@ bool MqttPublishLib(const char* topic, boolean retained)
|
|||
return MqttClient.publish(topic, mqtt_data, retained);
|
||||
}
|
||||
|
||||
void MqttCheckConnection()
|
||||
{
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
if (!MqttIsConnected()) {
|
||||
if (!mqtt_retry_counter) {
|
||||
MqttReconnect();
|
||||
} else {
|
||||
mqtt_retry_counter--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!mqtt_retry_counter) {
|
||||
MqttReconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MqttLoop()
|
||||
{
|
||||
MqttClient.loop();
|
||||
}
|
||||
|
||||
#elif (2 == USE_MQTT_CLIENT) /***************************************************************/
|
||||
#elif (2 == MQTT_LIBRARY_TYPE) /*****************************************************************/
|
||||
|
||||
#include <TasmotaMqtt.h>
|
||||
TasmotaMqtt MqttClient;
|
||||
|
||||
bool MqttIsConnected()
|
||||
{
|
||||
return mqtt_connected;
|
||||
}
|
||||
|
||||
void MqttDisconnect()
|
||||
{
|
||||
MqttClient.Disconnect();
|
||||
}
|
||||
|
||||
void MqttDisconnectedCb()
|
||||
{
|
||||
MqttDisconnected(MqttClient.State()); // status codes are documented in file mqtt.h as tConnState
|
||||
}
|
||||
|
||||
void MqttSubscribeLib(char *topic)
|
||||
{
|
||||
MqttClient.Subscribe(topic, 0);
|
||||
}
|
||||
|
||||
bool MqttPublishLib(const char* topic, boolean retained)
|
||||
{
|
||||
return MqttClient.Publish(topic, mqtt_data, strlen(mqtt_data), 0, retained);
|
||||
}
|
||||
|
||||
void MqttLoop()
|
||||
{
|
||||
}
|
||||
|
||||
#elif (3 == MQTT_LIBRARY_TYPE) /***************************************************************/
|
||||
|
||||
#include <MQTT.h>
|
||||
MQTT *MqttClient = NULL;
|
||||
|
||||
bool MqttIsConnected()
|
||||
{
|
||||
bool result = false;
|
||||
if (MqttClient) result = (MqttClient->isConnected() && !mqtt_retry_counter);
|
||||
return result;
|
||||
return mqtt_connected;
|
||||
}
|
||||
|
||||
void MqttDisconnect()
|
||||
|
@ -126,17 +149,19 @@ void MqttDisconnect()
|
|||
if (MqttClient) MqttClient->disconnect();
|
||||
}
|
||||
|
||||
void MqttMyDataCb(const char* topic, uint32_t topic_len, const char *data, uint32_t data_len)
|
||||
void MqttDisconnectedCb()
|
||||
{
|
||||
char topicCpy[topic_len];
|
||||
memcpy(topicCpy, topic, topic_len);
|
||||
topicCpy[topic_len] = 0;
|
||||
MqttDataHandler((char*)topicCpy, (byte*)data, data_len);
|
||||
MqttDisconnected(MqttClient->getState()); // status codes are documented in file mqtt.h as tConnState
|
||||
}
|
||||
|
||||
void MqttMyNoneCb()
|
||||
void MqttMyDataCb(const char* topic, uint32_t topic_len, const char* data, uint32_t data_len)
|
||||
{
|
||||
// Do nothing
|
||||
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);
|
||||
}
|
||||
|
||||
void MqttSubscribeLib(char *topic)
|
||||
|
@ -149,74 +174,19 @@ bool MqttPublishLib(const char* topic, boolean retained)
|
|||
return MqttClient->publish(topic, mqtt_data, strlen(mqtt_data), 0, retained);
|
||||
}
|
||||
|
||||
void MqttCheckConnection()
|
||||
{
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
if (!MqttIsConnected()) {
|
||||
if (!mqtt_retry_counter) {
|
||||
MqttReconnect();
|
||||
} else {
|
||||
mqtt_retry_counter--;
|
||||
}
|
||||
}
|
||||
MqttReconnect();
|
||||
} else {
|
||||
if (!mqtt_retry_counter) {
|
||||
MqttReconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MqttLoop()
|
||||
{
|
||||
// No action
|
||||
}
|
||||
|
||||
#elif (3 == USE_MQTT_CLIENT) /***************************************************************/
|
||||
|
||||
#include <ESP8266MQTTClient.h>
|
||||
MQTTClient MqttClient;
|
||||
|
||||
bool MqttIsConnected()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void MqttDisconnect()
|
||||
{
|
||||
// No action
|
||||
}
|
||||
|
||||
void MqttSubscribeLib(char *topic)
|
||||
{
|
||||
MqttClient.subscribe(topic, 0);
|
||||
}
|
||||
|
||||
bool MqttPublishLib(const char* topic, boolean retained)
|
||||
{
|
||||
return MqttClient.publish(topic, mqtt_data, 0, retained);
|
||||
}
|
||||
|
||||
void MqttCheckConnection()
|
||||
{
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
MqttReconnect();
|
||||
} else {
|
||||
if (!mqtt_retry_counter) {
|
||||
MqttReconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MqttLoop()
|
||||
{
|
||||
MqttClient.handle();
|
||||
}
|
||||
|
||||
#endif // USE_MQTT_CLIENT
|
||||
#endif // MQTT_LIBRARY_TYPE
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
int MqttLibraryType()
|
||||
{
|
||||
return (int)MQTT_LIBRARY_TYPE;
|
||||
}
|
||||
|
||||
void MqttRetryCounter(uint8_t value)
|
||||
{
|
||||
mqtt_retry_counter = value;
|
||||
|
@ -238,10 +208,12 @@ void MqttPublishDirect(const char* topic, boolean retained)
|
|||
snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_RESULT));
|
||||
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
if (MqttPublishLib(topic, retained)) {
|
||||
snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_MQTT));
|
||||
if (retained) {
|
||||
snprintf_P(sretained, sizeof(sretained), PSTR(" (" D_RETAINED ")"));
|
||||
if (MqttIsConnected()) {
|
||||
if (MqttPublishLib(topic, retained)) {
|
||||
snprintf_P(slog_type, sizeof(slog_type), PSTR(D_LOG_MQTT));
|
||||
if (retained) {
|
||||
snprintf_P(sretained, sizeof(sretained), PSTR(" (" D_RETAINED ")"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -336,11 +308,28 @@ void MqttPublishPowerBlinkState(byte device)
|
|||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void MqttDisconnected(int state)
|
||||
{
|
||||
mqtt_connected = false;
|
||||
mqtt_retry_counter = Settings.mqtt_retry;
|
||||
|
||||
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d, rc %d. " D_RETRY_IN " %d " D_UNIT_SECOND),
|
||||
Settings.mqtt_host, Settings.mqtt_port, state, mqtt_retry_counter);
|
||||
AddLog(LOG_LEVEL_INFO);
|
||||
}
|
||||
|
||||
void MqttConnected()
|
||||
{
|
||||
char stopic[TOPSZ];
|
||||
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED));
|
||||
mqtt_connected = true;
|
||||
mqtt_retry_counter = 0;
|
||||
|
||||
GetTopic_P(stopic, TELE, mqtt_topic, S_LWT);
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_ONLINE));
|
||||
MqttPublish(stopic, true);
|
||||
|
||||
// Satisfy iobroker (#299)
|
||||
mqtt_data[0] = '\0';
|
||||
|
@ -360,7 +349,7 @@ void MqttConnected()
|
|||
XdrvCall(FUNC_MQTT_SUBSCRIBE);
|
||||
}
|
||||
|
||||
if (mqtt_connection_flag) {
|
||||
if (mqtt_initial_connection_state) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_MODULE "\":\"%s\",\"" D_JSON_VERSION "\":\"%s\",\"" D_JSON_FALLBACKTOPIC "\":\"%s\",\"" D_CMND_GROUPTOPIC "\":\"%s\"}"),
|
||||
my_module.name, my_version, mqtt_client, Settings.mqtt_grptopic);
|
||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "1"));
|
||||
|
@ -381,48 +370,49 @@ void MqttConnected()
|
|||
|
||||
XdrvCall(FUNC_MQTT_INIT);
|
||||
}
|
||||
mqtt_connection_flag = 0;
|
||||
mqtt_initial_connection_state = 0;
|
||||
}
|
||||
|
||||
#ifdef USE_MQTT_TLS
|
||||
boolean MqttCheckTls()
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_FINGERPRINT));
|
||||
if (!EspClient.connect(Settings.mqtt_host, Settings.mqtt_port)) {
|
||||
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_TLS_CONNECT_FAILED_TO " %s:%d. " D_RETRY_IN " %d " D_UNIT_SECOND),
|
||||
Settings.mqtt_host, Settings.mqtt_port, mqtt_retry_counter);
|
||||
AddLog(LOG_LEVEL_DEBUG);
|
||||
} else if (!EspClient.verify(Settings.mqtt_fingerprint, Settings.mqtt_host)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_INSECURE));
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED));
|
||||
result = true;
|
||||
}
|
||||
EspClient.stop();
|
||||
yield();
|
||||
return result;
|
||||
}
|
||||
#endif // USE_MQTT_TLS
|
||||
|
||||
void MqttReconnect()
|
||||
{
|
||||
char stopic[TOPSZ];
|
||||
|
||||
mqtt_retry_counter = Settings.mqtt_retry;
|
||||
|
||||
if (!Settings.flag.mqtt_enabled) {
|
||||
MqttConnected();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_EMULATION
|
||||
UdpDisconnect();
|
||||
#endif // USE_EMULATION
|
||||
if (mqtt_connection_flag > 1) { // Executed once just after power on and wifi is connected - Initial TLS check
|
||||
#ifdef USE_MQTT_TLS
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_FINGERPRINT));
|
||||
if (!EspClient.connect(Settings.mqtt_host, Settings.mqtt_port)) {
|
||||
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_TLS_CONNECT_FAILED_TO " %s:%d. " D_RETRY_IN " %d " D_UNIT_SECOND),
|
||||
Settings.mqtt_host, Settings.mqtt_port, mqtt_retry_counter);
|
||||
AddLog(LOG_LEVEL_DEBUG);
|
||||
EspClient.stop();
|
||||
return;
|
||||
}
|
||||
if (EspClient.verify(Settings.mqtt_fingerprint, Settings.mqtt_host)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_VERIFIED));
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_INSECURE));
|
||||
EspClient.stop();
|
||||
return;
|
||||
}
|
||||
EspClient.stop();
|
||||
yield();
|
||||
#endif // USE_MQTT_TLS
|
||||
mqtt_connection_flag = 1;
|
||||
// mqtt_retry_counter = 1;
|
||||
// return;
|
||||
}
|
||||
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_ATTEMPTING_CONNECTION));
|
||||
|
||||
mqtt_connected = false;
|
||||
mqtt_retry_counter = Settings.mqtt_retry;
|
||||
|
||||
#ifndef USE_MQTT_TLS
|
||||
#ifdef USE_DISCOVERY
|
||||
#ifdef MQTT_HOST_DISCOVERY
|
||||
|
@ -441,63 +431,57 @@ void MqttReconnect()
|
|||
GetTopic_P(stopic, TELE, mqtt_topic, S_LWT);
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_OFFLINE);
|
||||
|
||||
#if (1 == USE_MQTT_CLIENT)
|
||||
if (2 == mqtt_initial_connection_state) { // Executed once just after power on and wifi is connected
|
||||
#ifdef USE_MQTT_TLS
|
||||
if (!MqttCheckTls()) return;
|
||||
#endif // USE_MQTT_TLS
|
||||
|
||||
#if (2 == MQTT_LIBRARY_TYPE)
|
||||
MqttClient.InitConnection(Settings.mqtt_host, Settings.mqtt_port);
|
||||
MqttClient.InitClient(mqtt_client, mqtt_user, mqtt_pwd, MQTT_KEEPALIVE);
|
||||
MqttClient.InitLWT(stopic, mqtt_data, 1, true);
|
||||
MqttClient.OnConnected(MqttConnected);
|
||||
MqttClient.OnDisconnected(MqttDisconnectedCb);
|
||||
MqttClient.OnData(MqttDataHandler);
|
||||
#elif (3 == MQTT_LIBRARY_TYPE)
|
||||
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);
|
||||
#endif
|
||||
|
||||
mqtt_initial_connection_state = 1;
|
||||
}
|
||||
|
||||
#if (1 == MQTT_LIBRARY_TYPE)
|
||||
MqttClient.setCallback(MqttDataHandler);
|
||||
MqttClient.setServer(Settings.mqtt_host, Settings.mqtt_port);
|
||||
if (MqttClient.connect(mqtt_client, mqtt_user, mqtt_pwd, stopic, 1, true, mqtt_data)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED));
|
||||
mqtt_retry_counter = 0;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_ONLINE));
|
||||
MqttPublish(stopic, true);
|
||||
MqttConnected();
|
||||
} else {
|
||||
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d, rc %d. " D_RETRY_IN " %d " D_UNIT_SECOND),
|
||||
Settings.mqtt_host, Settings.mqtt_port, MqttClient.state(), mqtt_retry_counter); //status codes are documented here http://pubsubclient.knolleary.net/api.html#state
|
||||
AddLog(LOG_LEVEL_INFO);
|
||||
}
|
||||
#elif (2 == USE_MQTT_CLIENT)
|
||||
if (!MqttClient) {
|
||||
MqttClient = new MQTT(mqtt_client, Settings.mqtt_host, Settings.mqtt_port, stopic, 1, true, mqtt_data);
|
||||
// MqttClient->onConnected(MqttMyNoneCb);
|
||||
// MqttClient->onDisconnected(MqttMyNoneCb);
|
||||
// MqttClient->onPublished(MqttMyNoneCb);
|
||||
MqttClient->onData(MqttMyDataCb);
|
||||
MqttClient->setUserPwd(mqtt_user, mqtt_pwd);
|
||||
MqttDisconnected(MqttClient.state()); // status codes are documented here http://pubsubclient.knolleary.net/api.html#state
|
||||
}
|
||||
#elif (2 == MQTT_LIBRARY_TYPE)
|
||||
MqttClient.Connect();
|
||||
#elif (3 == MQTT_LIBRARY_TYPE)
|
||||
MqttClient->connect();
|
||||
uint16_t mqtt_timeout = 50;
|
||||
while (!MqttClient->isConnected() && mqtt_timeout--) delay(1);
|
||||
if (MqttClient->isConnected()) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED));
|
||||
mqtt_retry_counter = 0;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_ONLINE));
|
||||
MqttPublish(stopic, true);
|
||||
MqttConnected();
|
||||
} else {
|
||||
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d. " D_RETRY_IN " %d " D_UNIT_SECOND),
|
||||
Settings.mqtt_host, Settings.mqtt_port, mqtt_retry_counter);
|
||||
AddLog(LOG_LEVEL_INFO);
|
||||
}
|
||||
#elif (3 == USE_MQTT_CLIENT)
|
||||
//topic, data, data is continuing
|
||||
MqttClient.onData([](String topic, String data, bool cont) {
|
||||
MqttDataHandler((char*)topic.c_str(), (byte*)data.c_str(), strlen(data.c_str()));
|
||||
});
|
||||
char uri[200];
|
||||
snprintf_P(uri, sizeof(uri), PSTR("mqtt://%s:%s@%s:%d#%s"), mqtt_user, mqtt_pwd, Settings.mqtt_host, Settings.mqtt_port, mqtt_client);
|
||||
#endif // MQTT_LIBRARY_TYPE
|
||||
}
|
||||
|
||||
if (MqttClient.begin(String(uri), {.lwtTopic = stopic, .lwtMsg = mqtt_data, .lwtQos = 1, .lwtRetain = 1}, MQTT_KEEPALIVE, true)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, S_LOG_MQTT, PSTR(D_CONNECTED));
|
||||
mqtt_retry_counter = 0;
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(D_ONLINE));
|
||||
MqttPublish(stopic, true);
|
||||
MqttConnected();
|
||||
void MqttCheck()
|
||||
{
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
if (!MqttIsConnected()) {
|
||||
if (!mqtt_retry_counter) {
|
||||
MqttReconnect();
|
||||
} else {
|
||||
mqtt_retry_counter--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_MQTT D_CONNECT_FAILED_TO " %s:%d. " D_RETRY_IN " %d " D_UNIT_SECOND),
|
||||
Settings.mqtt_host, Settings.mqtt_port, mqtt_retry_counter); //status codes are documented here http://pubsubclient.knolleary.net/api.html#state
|
||||
AddLog(LOG_LEVEL_INFO);
|
||||
if (mqtt_initial_connection_state) MqttReconnect();
|
||||
}
|
||||
#endif // USE_MQTT_CLIENT
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
@ -543,9 +527,7 @@ bool MqttCommand()
|
|||
else if ((CMND_STATETEXT == command_code) && (index > 0) && (index <= 4)) {
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.state_text[0]))) {
|
||||
for(i = 0; i <= data_len; i++) {
|
||||
if (dataBuf[i] == ' ') {
|
||||
dataBuf[i] = '_';
|
||||
}
|
||||
if (dataBuf[i] == ' ') dataBuf[i] = '_';
|
||||
}
|
||||
strlcpy(Settings.state_text[index -1], dataBuf, sizeof(Settings.state_text[0]));
|
||||
}
|
||||
|
@ -584,9 +566,7 @@ bool MqttCommand()
|
|||
else if (CMND_FULLTOPIC == command_code) {
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_fulltopic))) {
|
||||
MakeValidMqtt(1, dataBuf);
|
||||
if (!strcmp(dataBuf, mqtt_client)) {
|
||||
payload = 1;
|
||||
}
|
||||
if (!strcmp(dataBuf, mqtt_client)) payload = 1;
|
||||
strlcpy(stemp1, (1 == payload) ? MQTT_FULLTOPIC : dataBuf, sizeof(stemp1));
|
||||
if (strcmp(stemp1, Settings.mqtt_fulltopic)) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
|
||||
|
@ -609,9 +589,7 @@ bool MqttCommand()
|
|||
else if (CMND_GROUPTOPIC == command_code) {
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_grptopic))) {
|
||||
MakeValidMqtt(0, dataBuf);
|
||||
if (!strcmp(dataBuf, mqtt_client)) {
|
||||
payload = 1;
|
||||
}
|
||||
if (!strcmp(dataBuf, mqtt_client)) payload = 1;
|
||||
strlcpy(Settings.mqtt_grptopic, (1 == payload) ? MQTT_GRPTOPIC : dataBuf, sizeof(Settings.mqtt_grptopic));
|
||||
restart_flag = 2;
|
||||
}
|
||||
|
@ -620,9 +598,7 @@ bool MqttCommand()
|
|||
else if ((CMND_TOPIC == command_code) && !grpflg) {
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.mqtt_topic))) {
|
||||
MakeValidMqtt(0, dataBuf);
|
||||
if (!strcmp(dataBuf, mqtt_client)) {
|
||||
payload = 1;
|
||||
}
|
||||
if (!strcmp(dataBuf, mqtt_client)) payload = 1;
|
||||
strlcpy(stemp1, (1 == payload) ? MQTT_TOPIC : dataBuf, sizeof(stemp1));
|
||||
if (strcmp(stemp1, Settings.mqtt_topic)) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), (Settings.flag.mqtt_offline) ? S_OFFLINE : "");
|
||||
|
@ -636,9 +612,7 @@ bool MqttCommand()
|
|||
else if ((CMND_BUTTONTOPIC == command_code) && !grpflg) {
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.button_topic))) {
|
||||
MakeValidMqtt(0, dataBuf);
|
||||
if (!strcmp(dataBuf, mqtt_client)) {
|
||||
payload = 1;
|
||||
}
|
||||
if (!strcmp(dataBuf, mqtt_client)) payload = 1;
|
||||
strlcpy(Settings.button_topic, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? mqtt_topic : dataBuf, sizeof(Settings.button_topic));
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.button_topic);
|
||||
|
@ -646,9 +620,7 @@ bool MqttCommand()
|
|||
else if (CMND_SWITCHTOPIC == command_code) {
|
||||
if ((data_len > 0) && (data_len < sizeof(Settings.switch_topic))) {
|
||||
MakeValidMqtt(0, dataBuf);
|
||||
if (!strcmp(dataBuf, mqtt_client)) {
|
||||
payload = 1;
|
||||
}
|
||||
if (!strcmp(dataBuf, mqtt_client)) payload = 1;
|
||||
strlcpy(Settings.switch_topic, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? mqtt_topic : dataBuf, sizeof(Settings.switch_topic));
|
||||
}
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.switch_topic);
|
||||
|
@ -715,16 +687,15 @@ boolean Xdrv00(byte function)
|
|||
{
|
||||
boolean result = false;
|
||||
|
||||
switch (function) {
|
||||
case FUNC_LOOP:
|
||||
if (Settings.flag.mqtt_enabled) MqttLoop();
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
if (WL_CONNECTED == WiFi.status()) MqttCheckConnection();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
if (Settings.flag.mqtt_enabled) result = MqttCommand();
|
||||
break;
|
||||
if (Settings.flag.mqtt_enabled) {
|
||||
switch (function) {
|
||||
case FUNC_LOOP:
|
||||
MqttLoop();
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = MqttCommand();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -179,6 +179,7 @@ boolean XdrvMqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t
|
|||
* Function call to all xdrv
|
||||
*
|
||||
* FUNC_INIT
|
||||
* FUNC_LOOP
|
||||
* FUNC_MQTT_SUBSCRIBE
|
||||
* FUNC_MQTT_INIT
|
||||
* return FUNC_MQTT_DATA
|
||||
|
@ -195,9 +196,7 @@ boolean XdrvCall(byte Function)
|
|||
|
||||
for (byte x = 0; x < xdrv_present; x++) {
|
||||
result = xdrv_func_ptr[x](Function);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
if (result) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
xsns_20_novasds.ino - Nova SDS011/SDS021 particle concentration sensor support for Sonoff-Tasmota
|
||||
|
||||
Copyright (C) 2018 Theo Arends
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifdef USE_NOVA_SDS
|
||||
/*********************************************************************************************\
|
||||
* Nova Fitness SDS011 (and possibly SDS021) particle concentration sensor
|
||||
* For background information see http://aqicn.org/sensor/sds011/
|
||||
\*********************************************************************************************/
|
||||
|
||||
#include <TasmotaSerial.h>
|
||||
|
||||
TasmotaSerial *NovaSdsSerial;
|
||||
|
||||
uint8_t novasds_type = 1;
|
||||
uint8_t novasds_valid = 0;
|
||||
|
||||
struct sds011data {
|
||||
uint16_t pm100;
|
||||
uint16_t pm25;
|
||||
} novasds_data;
|
||||
|
||||
bool NovaSdsReadData()
|
||||
{
|
||||
if (! NovaSdsSerial->available()) return false;
|
||||
|
||||
while ((NovaSdsSerial->peek() != 0xAA) && NovaSdsSerial->available()) {
|
||||
NovaSdsSerial->read();
|
||||
}
|
||||
|
||||
byte d[8] = { 0 };
|
||||
NovaSdsSerial->read(); // skip 0xAA
|
||||
NovaSdsSerial->readBytes(d, 8);
|
||||
NovaSdsSerial->flush();
|
||||
|
||||
AddLogSerial(LOG_LEVEL_DEBUG_MORE, d, 8);
|
||||
|
||||
if (d[7] == ((d[1] + d[2] + d[3] + d[4] + d[5] + d[6]) & 0xFF)) {
|
||||
novasds_data.pm25 = (d[1] + 256 * d[2]);
|
||||
novasds_data.pm100 = (d[3] + 256 * d[4]);
|
||||
} else {
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR("SDS: " D_CHECKSUM_FAILURE));
|
||||
return false;
|
||||
}
|
||||
|
||||
novasds_valid = 10;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void NovaSdsSecond() // Every second
|
||||
{
|
||||
if (NovaSdsReadData()) {
|
||||
novasds_valid = 10;
|
||||
} else {
|
||||
if (novasds_valid) {
|
||||
novasds_valid--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void NovaSdsInit()
|
||||
{
|
||||
novasds_type = 0;
|
||||
|
||||
if (pin[GPIO_SDS0X1] < 99) {
|
||||
NovaSdsSerial = new TasmotaSerial(pin[GPIO_SDS0X1], -1);
|
||||
if (NovaSdsSerial->begin()) {
|
||||
novasds_type = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
const char HTTP_SDS0X1_SNS[] PROGMEM = "%s"
|
||||
"{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"
|
||||
"{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
void NovaSdsShow(boolean json)
|
||||
{
|
||||
if (novasds_valid) {
|
||||
if (json) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SDS0X1\":{\"PM2.5\":%d,\"PM10\":%d}"), mqtt_data, novasds_data.pm25, novasds_data.pm100);
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SDS0X1_SNS, mqtt_data, novasds_data.pm25/10, novasds_data.pm100/10);
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XSNS_20
|
||||
|
||||
boolean Xsns20(byte function)
|
||||
{
|
||||
boolean result = false;
|
||||
|
||||
if (novasds_type) {
|
||||
switch (function) {
|
||||
case FUNC_INIT:
|
||||
NovaSdsInit();
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
NovaSdsSecond();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
NovaSdsShow(1);
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_APPEND:
|
||||
NovaSdsShow(0);
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_NOVA_SDS
|
|
@ -206,9 +206,7 @@ boolean XsnsCall(byte Function)
|
|||
|
||||
for (byte x = 0; x < xsns_present; x++) {
|
||||
result = xsns_func_ptr[x](Function);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
if (result) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
Loading…
Reference in New Issue