MQTT support in lvgl simulator

This commit is contained in:
KlausMu 2024-03-18 20:20:59 +01:00
parent 73caf51198
commit 665b6908e1
29 changed files with 4673 additions and 52 deletions

View file

@ -52,6 +52,6 @@ jobs:
working-directory: ./Platformio
run: pio run -e esp32
- name: Build PlatformIO env:windows_linux_64bit
- name: Build PlatformIO env:linux_64bit
working-directory: ./Platformio
run: pio run -e windows_linux_64bit
run: pio run -e linux_64bit

View file

@ -52,12 +52,12 @@ jobs:
working-directory: ./Platformio
run: pio run -e esp32
- name: Build PlatformIO env:windows_linux_64bit
- name: Build PlatformIO env:windows_64bit
if: ${{matrix.sys == 'mingw64'}}
working-directory: ./Platformio
run: pio run -e windows_linux_64bit
run: pio run -e windows_64bit
- name: Build PlatformIO env:windows_linux_32bit
- name: Build PlatformIO env:windows_32bit
if: ${{matrix.sys == 'mingw32'}}
working-directory: ./Platformio
run: pio run -e windows_linux_32bit
run: pio run -e windows_32bit

View file

@ -46,9 +46,9 @@ uint8_t IR_VCC_GPIO = 25; // IR receiver power
bool irReceiverEnabled = false;
tShowNewIRmessage_cb thisShowNewIRmessage_cb = NULL;
void set_showNewIRmessage_cb_HAL(tShowNewIRmessage_cb pShowNewIRmessage_cb) {
thisShowNewIRmessage_cb = pShowNewIRmessage_cb;
tAnnounceNewIRmessage_cb thisAnnounceNewIRmessage_cb = NULL;
void set_announceNewIRmessage_cb_HAL(tAnnounceNewIRmessage_cb pAnnounceNewIRmessage_cb) {
thisAnnounceNewIRmessage_cb = pAnnounceNewIRmessage_cb;
}
// The Serial connection baud rate.
@ -190,8 +190,8 @@ void infraredReceiver_loop_HAL() {
message += typeToString((&results)->decode_type, (&results)->repeat);
message += " ";
message += resultToHexidecimal(&results);
if (thisShowNewIRmessage_cb != NULL) {
thisShowNewIRmessage_cb(std::string(message.c_str()));
if (thisAnnounceNewIRmessage_cb != NULL) {
thisAnnounceNewIRmessage_cb(std::string(message.c_str()));
}
yield(); // Feed the WDT (again)

View file

@ -12,5 +12,5 @@ void infraredReceiver_loop_HAL(void);
bool get_irReceiverEnabled_HAL();
void set_irReceiverEnabled_HAL(bool aIrReceiverEnabled);
typedef void (*tShowNewIRmessage_cb)(std::string message);
void set_showNewIRmessage_cb_HAL(tShowNewIRmessage_cb pShowNewIRmessage_cb);
typedef void (*tAnnounceNewIRmessage_cb)(std::string message);
void set_announceNewIRmessage_cb_HAL(tAnnounceNewIRmessage_cb pAnnounceNewIRmessage_cb);

View file

@ -8,9 +8,14 @@ WiFiClient espClient;
PubSubClient mqttClient(espClient);
bool isWifiConnected = false;
showWiFiconnected_cb thisShowWiFiconnected_cb = NULL;
void set_showWiFiconnected_cb_HAL(showWiFiconnected_cb pShowWiFiconnected_cb) {
thisShowWiFiconnected_cb = pShowWiFiconnected_cb;
tAnnounceWiFiconnected_cb thisAnnounceWiFiconnected_cb = NULL;
void set_announceWiFiconnected_cb_HAL(tAnnounceWiFiconnected_cb pAnnounceWiFiconnected_cb) {
thisAnnounceWiFiconnected_cb = pAnnounceWiFiconnected_cb;
}
tAnnounceSubscribedTopics_cb thisAnnounceSubscribedTopics_cb = NULL;
void set_announceSubscribedTopics_cb_HAL(tAnnounceSubscribedTopics_cb pAnnounceSubscribedTopics_cb) {
thisAnnounceSubscribedTopics_cb = pAnnounceSubscribedTopics_cb;
}
bool getIsWifiConnected_HAL() {
@ -30,12 +35,12 @@ void WiFiEvent(WiFiEvent_t event){
// Set status bar icon based on WiFi status
if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP || event == ARDUINO_EVENT_WIFI_STA_GOT_IP6) {
isWifiConnected = true;
thisShowWiFiconnected_cb(true);
thisAnnounceWiFiconnected_cb(true);
Serial.printf("WiFi connected, IP address: %s\r\n", WiFi.localIP().toString().c_str());
} else if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) {
isWifiConnected = false;
thisShowWiFiconnected_cb(false);
thisAnnounceWiFiconnected_cb(false);
// automatically try to reconnect
Serial.printf("WiFi got disconnected. Will try to reconnect.\r\n");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
@ -44,7 +49,7 @@ void WiFiEvent(WiFiEvent_t event){
// e.g. ARDUINO_EVENT_WIFI_STA_CONNECTED or many others
// connected is not enough, will wait for IP
isWifiConnected = false;
thisShowWiFiconnected_cb(false);
thisAnnounceWiFiconnected_cb(false);
}
}
@ -57,6 +62,29 @@ void init_mqtt_HAL(void) {
WiFi.setSleep(true);
}
std::string subscribeTopicOMOTEtest = "OMOTE/test";
void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived
std::string topicReceived(topic);
std::string strPayload(reinterpret_cast<const char *>(payload), length);
if (topicReceived == subscribeTopicOMOTEtest) {
Serial.printf("MQTT: received topic %s with payload %s\r\n", subscribeTopicOMOTEtest.c_str(), strPayload.c_str());
}
thisAnnounceSubscribedTopics_cb(topicReceived, strPayload);
}
void mqtt_subscribeTopics() {
mqttClient.setCallback(&callback);
mqttClient.subscribe(subscribeTopicOMOTEtest.c_str());
Serial.printf(" Successfully subscribed to MQTT topic %s\r\n", subscribeTopicOMOTEtest.c_str());
}
bool checkMQTTconnection() {
if (WiFi.isConnected()) {
@ -64,10 +92,17 @@ bool checkMQTTconnection() {
return true;
} else {
// try to connect to mqtt server
mqttClient.setBufferSize(512); // default is 256
//mqttClient.setKeepAlive(15); // default is 15 Client will send MQTTPINGREQ to keep connection alive
//mqttClient.setSocketTimeout(15); // default is 15 This determines how long the client will wait for incoming data when it expects data to arrive - for example, whilst it is in the middle of reading an MQTT packet.
mqttClient.setServer(MQTT_SERVER, MQTT_SERVER_PORT); // MQTT initialization
if (mqttClient.connect(MQTT_CLIENTNAME, MQTT_USER, MQTT_PASS)) {
std::string mqttClientName = std::string(MQTT_CLIENTNAME) + "_esp32_" + std::string(WiFi.macAddress().c_str());
if (mqttClient.connect(mqttClientName.c_str(), MQTT_USER, MQTT_PASS)) {
Serial.printf(" Successfully connected to MQTT broker\r\n");
mqtt_subscribeTopics();
} else {
Serial.printf(" MQTT connection failed (but WiFi is available). Will try later ...\r\n");
@ -75,11 +110,29 @@ bool checkMQTTconnection() {
return mqttClient.connected();
}
} else {
Serial.printf(" No connection to MQTT server, because WiFi ist not connected.\r\n");
// Serial.printf(" No connection to MQTT server, because WiFi ist not connected.\r\n");
return false;
}
}
unsigned long reconnectInterval = 100;
// in order to do reconnect immediately ...
unsigned long lastReconnectAttempt = millis() - reconnectInterval - 1;
void mqtt_loop_HAL() {
if (!mqttClient.connected()) {
unsigned long currentMillis = millis();
if ((currentMillis - lastReconnectAttempt) > reconnectInterval) {
lastReconnectAttempt = currentMillis;
// Attempt to reconnect
checkMQTTconnection();
}
}
if (mqttClient.connected()) {
mqttClient.loop();
}
}
bool publishMQTTMessage_HAL(const char *topic, const char *payload){
if (checkMQTTconnection()) {

View file

@ -4,11 +4,13 @@
void init_mqtt_HAL(void);
bool getIsWifiConnected_HAL();
void mqtt_loop_HAL();
bool publishMQTTMessage_HAL(const char *topic, const char *payload);
void wifiStop_HAL();
typedef void (*showWiFiconnected_cb)(bool connected);
void set_showWiFiconnected_cb_HAL(showWiFiconnected_cb pShowWiFiconnected_cb);
typedef void (*tAnnounceWiFiconnected_cb)(bool connected);
void set_announceWiFiconnected_cb_HAL(tAnnounceWiFiconnected_cb pAnnounceWiFiconnected_cb);
typedef void (*tAnnounceSubscribedTopics_cb)(std::string topic, std::string payload);
void set_announceSubscribedTopics_cb_HAL(tAnnounceSubscribedTopics_cb pAnnounceSubscribedTopics_cb);
#endif

View file

@ -19,4 +19,4 @@ void set_irReceiverEnabled_HAL(bool aIrReceiverEnabled) {
irReceiverEnabled = aIrReceiverEnabled;
}
void set_showNewIRmessage_cb_HAL(tShowNewIRmessage_cb pShowNewIRmessage_cb) {}
void set_announceNewIRmessage_cb_HAL(tAnnounceNewIRmessage_cb pAnnounceNewIRmessage_cb) {}

View file

@ -9,5 +9,5 @@ void infraredReceiver_loop_HAL(void);
bool get_irReceiverEnabled_HAL();
void set_irReceiverEnabled_HAL(bool aIrReceiverEnabled);
typedef void (*tShowNewIRmessage_cb)(std::string message);
void set_showNewIRmessage_cb_HAL(tShowNewIRmessage_cb pShowNewIRmessage_cb);
typedef void (*tAnnounceNewIRmessage_cb)(std::string message);
void set_announceNewIRmessage_cb_HAL(tAnnounceNewIRmessage_cb pAnnounceNewIRmessage_cb);

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Liam Bindle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,106 @@
<p align="right">
<a href="https://github.com/LiamBindle/MQTT-C/stargazers"><img src="https://img.shields.io/github/stars/LiamBindle/MQTT-C.svg?style=social&label=Star" style="margin-left:5em"></a>
<a href="https://github.com/LiamBindle/MQTT-C/network/members"><img src="https://img.shields.io/github/forks/LiamBindle/MQTT-C.svg?style=social&label=Fork"></a>
</p>
<p align="center">
<img width="70%" src="docs/mqtt-c-logo.png"><br>
<a href="https://liambindle.ca/MQTT-C"><img src="https://img.shields.io/badge/docs-passing-brightgreen.svg"></a>
<a href="https://github.com/LiamBindle/MQTT-C/issues"><img src="https://img.shields.io/badge/Maintained%3F-yes-green.svg"></a>
<a href="https://GitHub.com/LiamBindle/MQTT-C/issues/"><img src="https://img.shields.io/github/issues/LiamBindle/MQTT-C.svg"></a>
<a href="https://github.com/LiamBindle/MQTT-C/issues"><img src="https://img.shields.io/github/issues-closed/LiamBindle/MQTT-C.svg"></a>
<a href="https://github.com/LiamBindle/MQTT-C/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
</p>
MQTT-C is an [MQTT v3.1.1](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html)
client written in C. MQTT is a lightweight publisher-subscriber-based messaging protocol that is
commonly used in IoT and networking applications where high-latency and low data-rate links
are expected. The purpose of MQTT-C is to provide a **portable** MQTT client, **written in C**,
for embedded systems and PC's alike. MQTT-C does this by providing a transparent Platform
Abstraction Layer (PAL) which makes porting to new platforms easy. MQTT-C is completely
thread-safe but can also run perfectly fine on single-threaded systems making MQTT-C
well-suited for embedded systems and microcontrollers. Finally, MQTT-C is small; there are only
two source files totalling less than 2000 lines.
#### A note from the author
It's been great to hear about all the places MQTT-C is being used! Please don't hesitate
to get in touch with me or submit issues on GitHub!
## Getting Started
To use MQTT-C you first instantiate a `struct mqtt_client` and initialize it by calling
@ref mqtt_init.
```c
struct mqtt_client client; /* instantiate the client */
mqtt_init(&client, ...); /* initialize the client */
```
Once your client is initialized you need to connect to an MQTT broker.
```c
mqtt_connect(&client, ...); /* send a connection request to the broker. */
```
At this point the client is ready to use! For example, we can subscribe to a topic like so:
```c
/* subscribe to "toaster/temperature" with a max QoS level of 0 */
mqtt_subscribe(&client, "toaster/temperature", 0);
```
And we can publish to a topic like so:
```c
/* publish coffee temperature with a QoS level of 1 */
int temperature = 67;
mqtt_publish(&client, "coffee/temperature", &temperature, sizeof(int), MQTT_PUBLISH_QOS_1);
```
Those are the basics! From here the [examples](https://github.com/LiamBindle/MQTT-C/tree/master/examples) and [API documentation](https://liambindle.ca/MQTT-C/group__api.html) are good places to get started.
## Building
There are **only two source files** that need to be built, `mqtt.c` and `mqtt_pal.c`.
These files are ANSI C (C89) compatible, and should compile with any C compiler.
Then, simply <code>\#include <mqtt.h></code>.
Alternatively, you can build MQTT-C with CMake or the provided Makefile. These are provided for convenience.
## Documentation
Pre-built documentation can be found here: [https://liambindle.ca/MQTT-C](https://liambindle.ca/MQTT-C). Be sure to check out the [examples](https://github.com/LiamBindle/MQTT-C/tree/master/examples) too.
The @ref api documentation contains all the documentation application programmers should need.
The @ref pal documentation contains everything you should need to port MQTT-C to a new platform,
and the other modules contain documentation for MQTT-C developers.
## Testing and Building the Tests
The MQTT-C unit tests use the [cmocka unit testing framework](https://cmocka.org/).
Therefore, [cmocka](https://cmocka.org/) *must* be installed on your machine to build and run
the unit tests. For convenience, a simple `"makefile"` is included to build the unit tests and
examples on UNIX-like machines. The unit tests and examples can be built as follows:
```bash
$ make all
```
The unit tests and examples will be built in the `"bin/"` directory. The unit tests can be run
like so:
```bash
$ ./bin/tests [address [port]]
```
Note that the \c address and \c port arguments are both optional to specify the location of the
MQTT broker that is to be used for the tests. If no \c address is given then the
[Mosquitto MQTT Test Server](https://test.mosquitto.org/) will be used. If no \c port is given,
port 1883 will be used.
## Portability
MQTT-C provides a transparent platform abstraction layer (PAL) in `mqtt_pal.h` and `mqtt_pal.c`.
These files declare and implement the types and calls that MQTT-C requires. Refer to
@ref pal for the complete documentation of the PAL.
## Contributing
Please feel free to submit issues and pull-requests [here](https://github.com/LiamBindle/MQTT-C).
When submitting a pull-request please ensure you have *fully documented* your changes and
added the appropriate unit tests.
## License
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). See the
`"LICENSE"` file for more details.
## Authors
MQTT-C was initially developed as a CMPT 434 (Winter Term, 2018) final project at the University of
Saskatchewan by:
- **Liam Bindle**
- **Demilade Adeoye**

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,203 @@
#if !defined(__MQTT_PAL_H__)
#define __MQTT_PAL_H__
/*
MIT License
Copyright(c) 2018 Liam Bindle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#if defined(__cplusplus)
extern "C" {
#endif
/**
* @file
* @brief Includes/supports the types/calls required by the MQTT-C client.
*
* @note This is the \em only file included in mqtt.h, and mqtt.c. It is therefore
* responsible for including/supporting all the required types and calls.
*
* @defgroup pal Platform abstraction layer
* @brief Documentation of the types and calls required to port MQTT-C to a new platform.
*
* mqtt_pal.h is the \em only header file included in mqtt.c. Therefore, to port MQTT-C to a
* new platform the following types, functions, constants, and macros must be defined in
* mqtt_pal.h:
* - Types:
* - \c size_t, \c ssize_t
* - \c uint8_t, \c uint16_t, \c uint32_t
* - \c va_list
* - \c mqtt_pal_time_t : return type of \c MQTT_PAL_TIME()
* - \c mqtt_pal_mutex_t : type of the argument that is passed to \c MQTT_PAL_MUTEX_LOCK and
* \c MQTT_PAL_MUTEX_RELEASE
* - Functions:
* - \c memcpy, \c strlen
* - \c va_start, \c va_arg, \c va_end
* - Constants:
* - \c INT_MIN
*
* Additionally, three macro's are required:
* - \c MQTT_PAL_HTONS(s) : host-to-network endian conversion for uint16_t.
* - \c MQTT_PAL_NTOHS(s) : network-to-host endian conversion for uint16_t.
* - \c MQTT_PAL_TIME() : returns [type: \c mqtt_pal_time_t] current time in seconds.
* - \c MQTT_PAL_MUTEX_LOCK(mtx_pointer) : macro that locks the mutex pointed to by \c mtx_pointer.
* - \c MQTT_PAL_MUTEX_RELEASE(mtx_pointer) : macro that unlocks the mutex pointed to by
* \c mtx_pointer.
*
* Lastly, \ref mqtt_pal_sendall and \ref mqtt_pal_recvall, must be implemented in mqtt_pal.c
* for sending and receiving data using the platforms socket calls.
*/
/* UNIX-like platform support */
#if defined(__unix__) || defined(__APPLE__) || defined(__NuttX__)
#include <limits.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <arpa/inet.h>
#include <pthread.h>
#define MQTT_PAL_HTONS(s) htons(s)
#define MQTT_PAL_NTOHS(s) ntohs(s)
#define MQTT_PAL_TIME() time(NULL)
typedef time_t mqtt_pal_time_t;
typedef pthread_mutex_t mqtt_pal_mutex_t;
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) pthread_mutex_init(mtx_ptr, NULL)
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) pthread_mutex_lock(mtx_ptr)
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) pthread_mutex_unlock(mtx_ptr)
#if !defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
#if defined(MQTT_USE_MBEDTLS)
struct mbedtls_ssl_context;
typedef struct mbedtls_ssl_context *mqtt_pal_socket_handle;
#elif defined(MQTT_USE_WOLFSSL)
#include <wolfssl/ssl.h>
typedef WOLFSSL* mqtt_pal_socket_handle;
#elif defined(MQTT_USE_BIO)
#include <openssl/bio.h>
typedef BIO* mqtt_pal_socket_handle;
#elif defined(MQTT_USE_BEARSSL)
#include <bearssl.h>
typedef struct _bearssl_context {
br_ssl_client_context sc;
br_x509_minimal_context xc;
br_sslio_context ioc;
size_t ta_count;
br_x509_trust_anchor *anchOut;
int fd;
int (*low_read)(void *read_context, unsigned char *buf, size_t len);
int (*low_write)(void *write_context, const unsigned char *buf, size_t len);
} bearssl_context;
typedef bearssl_context* mqtt_pal_socket_handle;
#else
typedef int mqtt_pal_socket_handle;
#endif
#endif
#elif defined(_MSC_VER) || defined(WIN32)
#include <limits.h>
#include <winsock2.h>
#include <windows.h>
#include <time.h>
#include <stdint.h>
// original from MQTT-C
// typedef SSIZE_T ssize_t;
// changed for usage in OMOTE
#if defined(WIN64)
typedef SSIZE_T ssize_t;
#endif
#define MQTT_PAL_HTONS(s) htons(s)
#define MQTT_PAL_NTOHS(s) ntohs(s)
#define MQTT_PAL_TIME() time(NULL)
typedef time_t mqtt_pal_time_t;
typedef CRITICAL_SECTION mqtt_pal_mutex_t;
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) InitializeCriticalSection(mtx_ptr)
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) EnterCriticalSection(mtx_ptr)
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) LeaveCriticalSection(mtx_ptr)
#if !defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
#if defined(MQTT_USE_BIO)
#include <openssl/bio.h>
typedef BIO* mqtt_pal_socket_handle;
#else
typedef SOCKET mqtt_pal_socket_handle;
#endif
#endif
#endif
/**
* @brief Sends all the bytes in a buffer.
* @ingroup pal
*
* @param[in] fd The file-descriptor (or handle) of the socket.
* @param[in] buf A pointer to the first byte in the buffer to send.
* @param[in] len The number of bytes to send (starting at \p buf).
* @param[in] flags Flags which are passed to the underlying socket.
*
* @returns The number of bytes sent if successful, an \ref MQTTErrors otherwise.
*
* Note about the error handling:
* - On an error, if some bytes have been processed already,
* this function should return the number of bytes successfully
* processed. (partial success)
* - Otherwise, if the error is an equivalent of EAGAIN, return 0.
* - Otherwise, return MQTT_ERROR_SOCKET_ERROR.
*/
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags);
/**
* @brief Non-blocking receive all the byte available.
* @ingroup pal
*
* @param[in] fd The file-descriptor (or handle) of the socket.
* @param[in] buf A pointer to the receive buffer.
* @param[in] bufsz The max number of bytes that can be put into \p buf.
* @param[in] flags Flags which are passed to the underlying socket.
*
* @returns The number of bytes received if successful, an \ref MQTTErrors otherwise.
*
* Note about the error handling:
* - On an error, if some bytes have been processed already,
* this function should return the number of bytes successfully
* processed. (partial success)
* - Otherwise, if the error is an equivalent of EAGAIN, return 0.
* - Otherwise, return MQTT_ERROR_SOCKET_ERROR.
*/
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags);
#if defined(__cplusplus)
}
#endif
#endif

View file

@ -0,0 +1,103 @@
#if !defined(__POSIX_SOCKET_TEMPLATE_H__)
#define __POSIX_SOCKET_TEMPLATE_H__
#include <stdio.h>
#include <sys/types.h>
#if !defined(WIN32)
#include <sys/socket.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#else
#include <ws2tcpip.h>
#endif
#if defined(__VMS)
#include <ioctl.h>
#endif
#include <fcntl.h>
/*
A template for opening a non-blocking POSIX socket.
*/
int open_nb_socket(const char* addr, const char* port);
int open_nb_socket(const char* addr, const char* port, char *MACaddress) {
struct addrinfo hints = {0};
hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* Must be TCP */
int sockfd = -1;
int rv;
struct addrinfo *p, *servinfo;
/* get address information */
rv = getaddrinfo(addr, port, &hints, &servinfo);
if(rv != 0) {
fprintf(stderr, "Failed to open socket (getaddrinfo): %s\r\n", gai_strerror(rv));
return -1;
}
/* open the first possible socket */
for(p = servinfo; p != NULL; p = p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd == -1) continue;
/* connect to server */
rv = connect(sockfd, p->ai_addr, p->ai_addrlen);
if(rv == -1) {
close(sockfd);
sockfd = -1;
continue;
}
#if !defined(WIN32)
// get MAC address
struct ifreq s;
ioctl(sockfd, SIOCGIFHWADDR, &s);
char buffer[6*3];
int i;
for (i = 0; i < 6; ++i) {
sprintf(&buffer[i*3], "%02x:", (unsigned char) s.ifr_addr.sa_data[i]);
//printf(" %02x", (unsigned char) s.ifr_addr.sa_data[i]);
}
//printf("\r\n");
buffer[17] = '\0';
std::string strMACaddress = std::string(buffer, 18);
strMACaddress.copy(MACaddress, 18);
// printf(" MAC address from posix_sockets %s\r\n", strMACaddress.c_str());
#endif
break;
}
/* free servinfo */
freeaddrinfo(servinfo);
/* make non-blocking */
#if !defined(WIN32)
if (sockfd != -1) fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
#else
if (sockfd != INVALID_SOCKET) {
// original from MQTT-C
// int iMode = 1;
// changed for usage in OMOTE
u_long iMode = 1;
ioctlsocket(sockfd, FIONBIO, &iMode);
}
#endif
#if defined(__VMS)
/*
OpenVMS only partially implements fcntl. It works on file descriptors
but silently fails on socket descriptors. So we need to fall back on
to the older ioctl system to set non-blocking IO
*/
int on = 1;
if (sockfd != -1) ioctl(sockfd, FIONBIO, &on);
#endif
/* return the new socket fd */
return sockfd;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,440 @@
/*
MIT License
Copyright(c) 2018 Liam Bindle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <mqtt.h>
/**
* @file
* @brief Implements @ref mqtt_pal_sendall and @ref mqtt_pal_recvall and
* any platform-specific helpers you'd like.
* @cond Doxygen_Suppress
*/
#if defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
/*
* In case of MQTT_USE_CUSTOM_SOCKET_HANDLE, a pal implemantation is
* provided by the user.
*/
/* Note: Some toolchains complain on an object without symbols */
int _mqtt_pal_dummy;
#else /* defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) */
#if defined(MQTT_USE_MBEDTLS)
#include <mbedtls/ssl.h>
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
enum MQTTErrors error = 0;
size_t sent = 0;
while(sent < len) {
int rv = mbedtls_ssl_write(fd, (const unsigned char*)buf + sent, len - sent);
if (rv < 0) {
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
rv == MBEDTLS_ERR_SSL_WANT_WRITE
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
#endif
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
#endif
) {
/* should call mbedtls_ssl_write later again */
break;
}
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
/*
* Note: rv can be 0 here eg. when mbedtls just flushed
* the previous incomplete record.
*
* Note: we never send an empty TLS record.
*/
sent += (size_t) rv;
}
if (sent == 0) {
return error;
}
return (ssize_t)sent;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
const void *const start = buf;
enum MQTTErrors error = 0;
int rv;
do {
rv = mbedtls_ssl_read(fd, (unsigned char*)buf, bufsz);
if (rv == 0) {
/*
* Note: mbedtls_ssl_read returns 0 when the underlying
* transport was closed without CloseNotify.
*
* Raise an error to trigger a reconnect.
*/
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
if (rv < 0) {
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
rv == MBEDTLS_ERR_SSL_WANT_WRITE
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
#endif
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
#endif
) {
/* should call mbedtls_ssl_read later again */
break;
}
/* Note: MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY is handled here. */
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
buf = (char*)buf + rv;
bufsz -= (unsigned long)rv;
} while (bufsz > 0);
if (buf == start) {
return error;
}
return (const char *)buf - (const char*)start;
}
#elif defined(MQTT_USE_WOLFSSL)
#include <wolfssl/ssl.h>
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
size_t sent = 0;
while (sent < len) {
int tmp = wolfSSL_write(fd, buf + sent, (int)(len - sent));
if (tmp <= 0) {
tmp = wolfSSL_get_error(fd, tmp);
if (tmp == WOLFSSL_ERROR_WANT_READ || tmp == WOLFSSL_ERROR_WANT_WRITE) {
break;
}
return MQTT_ERROR_SOCKET_ERROR;
}
sent += (size_t)tmp;
}
return (ssize_t)sent;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
const void* const start = buf;
int tmp;
do {
tmp = wolfSSL_read(fd, buf, (int)bufsz);
if (tmp <= 0) {
tmp = wolfSSL_get_error(fd, tmp);
if (tmp == WOLFSSL_ERROR_WANT_READ || tmp == WOLFSSL_ERROR_WANT_WRITE) {
break;
}
return MQTT_ERROR_SOCKET_ERROR;
}
buf = (char*)buf + tmp;
bufsz -= tmp;
} while (tmp > 0 && bufsz > 0);
return (ssize_t)(buf - start);
}
#elif defined(MQTT_USE_BEARSSL)
#include <bearssl.h>
#include <memory.h>
static int do_rec_data(mqtt_pal_socket_handle fd, unsigned int status) {
ssize_t rc;
uint8_t *buffer;
size_t length;
int err;
err = br_ssl_engine_last_error(&fd->sc.eng);
if (err != BR_ERR_OK) {
return MQTT_ERROR_SOCKET_ERROR;
}
if ((status & BR_SSL_SENDREC) == BR_SSL_SENDREC) {
buffer = br_ssl_engine_sendrec_buf(&fd->sc.eng, &length);
if (length > 0) {
if ((rc = fd->low_write(&fd->fd, buffer, length)) < 0) {
return MQTT_ERROR_SOCKET_ERROR;
}
br_ssl_engine_sendrec_ack(&fd->sc.eng, rc);
}
}
else if ((status & BR_SSL_RECVREC) == BR_SSL_RECVREC) {
buffer = br_ssl_engine_recvrec_buf(&fd->sc.eng, &length);
if (length > 0) {
if ((rc = fd->low_read(&fd->fd, buffer, length)) < 0) {
return MQTT_ERROR_SOCKET_ERROR;
}
br_ssl_engine_recvrec_ack(&fd->sc.eng, rc);
}
}
else if ((status && BR_SSL_CLOSED) == BR_SSL_CLOSED) {
return MQTT_ERROR_SOCKET_ERROR;
}
return MQTT_OK;
}
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
int rc = MQTT_OK;
uint8_t *buffer;
size_t length;
size_t remaining_bytes = len;
const uint8_t *walker = buf;
unsigned int status;
while (remaining_bytes > 0) {
if (rc == MQTT_ERROR_SOCKET_ERROR) {
return rc;
}
status = br_ssl_engine_current_state(&fd->sc.eng);
if ((status & BR_SSL_CLOSED) != 0) {
return MQTT_ERROR_SOCKET_ERROR;
}
if ((status & (BR_SSL_RECVREC | BR_SSL_SENDREC)) != 0) {
rc = do_rec_data(fd, status);
if (rc != MQTT_OK) {
return rc;
}
status = br_ssl_engine_current_state(&fd->sc.eng);
}
if ((status & BR_SSL_SENDAPP) == BR_SSL_SENDAPP) {
buffer = br_ssl_engine_sendapp_buf(&fd->sc.eng, &length);
if (length > 0) {
size_t write = length >= remaining_bytes? remaining_bytes : length;
memcpy(buffer, walker, write);
remaining_bytes -= write;
walker += write;
br_ssl_engine_sendapp_ack(&fd->sc.eng, write);
br_ssl_engine_flush(&fd->sc.eng, 0);
}
}
}
return len;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
int rc = MQTT_OK;
uint8_t *buffer;
size_t length;
size_t remaining_bytes = bufsz;
uint8_t *walker = buf;
unsigned int status;
if (rc == MQTT_ERROR_SOCKET_ERROR) {
return rc;
}
status = br_ssl_engine_current_state(&fd->sc.eng);
if ((status & (BR_SSL_RECVREC | BR_SSL_SENDREC)) != 0) {
rc = do_rec_data(fd, status);
if (rc != MQTT_OK) {
return rc;
}
status = br_ssl_engine_current_state(&fd->sc.eng);
}
if ((status & BR_SSL_RECVAPP) == BR_SSL_RECVAPP) {
buffer = br_ssl_engine_recvapp_buf(&fd->sc.eng, &length);
if (length > 0) {
size_t write = length >= remaining_bytes? remaining_bytes : length;
memcpy(walker, buffer, write);
remaining_bytes -= write;
walker += write;
br_ssl_engine_recvapp_ack(&fd->sc.eng, write);
}
}
return bufsz - remaining_bytes;
}
#elif defined(MQTT_USE_BIO)
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
size_t sent = 0;
while(sent < len) {
int tmp = BIO_write(fd, (const char*)buf + sent, (int)(len - sent));
if (tmp > 0) {
sent += (size_t) tmp;
} else if (tmp <= 0 && !BIO_should_retry(fd)) {
return MQTT_ERROR_SOCKET_ERROR;
}
}
return (ssize_t)sent;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
const char* const start = (const char*)buf;
char* bufptr = (char*)buf;
int rv;
do {
rv = BIO_read(fd, bufptr, (int)bufsz);
if (rv > 0) {
/* successfully read bytes from the socket */
bufptr += rv;
bufsz -= (unsigned long)rv;
} else if (!BIO_should_retry(fd)) {
/* an error occurred that wasn't "nothing to read". */
return MQTT_ERROR_SOCKET_ERROR;
}
} while (!BIO_should_read(fd) && bufsz > 0);
return (ssize_t)(bufptr - start);
}
#elif defined(__unix__) || defined(__APPLE__) || defined(__NuttX__)
#include <errno.h>
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
enum MQTTErrors error = 0;
size_t sent = 0;
while(sent < len) {
ssize_t rv = send(fd, (const char*)buf + sent, len - sent, flags);
if (rv < 0) {
if (errno == EAGAIN) {
/* should call send later again */
break;
}
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
if (rv == 0) {
/* is this possible? maybe OS bug. */
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
sent += (size_t) rv;
}
if (sent == 0) {
return error;
}
return (ssize_t)sent;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
const void *const start = buf;
enum MQTTErrors error = 0;
ssize_t rv;
do {
rv = recv(fd, buf, bufsz, flags);
if (rv == 0) {
/*
* recv returns 0 when the socket is (half) closed by the peer.
*
* Raise an error to trigger a reconnect.
*/
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
if (rv < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
/* should call recv later again */
break;
}
/* an error occurred that wasn't "nothing to read". */
error = MQTT_ERROR_SOCKET_ERROR;
break;
}
buf = (char*)buf + rv;
bufsz -= (unsigned long)rv;
} while (bufsz > 0);
if (buf == start) {
return error;
}
return (char*)buf - (const char*)start;
}
#elif defined(_MSC_VER) || defined(WIN32)
#include <errno.h>
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
size_t sent = 0;
while(sent < len) {
ssize_t tmp = send(fd, (char*)buf + sent, len - sent, flags);
if (tmp < 1) {
return MQTT_ERROR_SOCKET_ERROR;
}
sent += (size_t) tmp;
}
return sent;
}
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
const char *const start = buf;
ssize_t rv;
do {
rv = recv(fd, buf, bufsz, flags);
if (rv > 0) {
/* successfully read bytes from the socket */
buf = (char*)buf + rv;
bufsz -= rv;
} else if (rv < 0) {
int err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) {
/* an error occurred that wasn't "nothing to read". */
return MQTT_ERROR_SOCKET_ERROR;
}
}
} while (rv > 0 && bufsz > 0);
return (ssize_t)((char*)buf - start);
}
#else
#error No PAL!
#endif
#endif /* defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) */
/** @endcond */

View file

@ -1,18 +1,198 @@
#include <string>
#include "mqtt_hal_windows_linux.h"
#include "secrets.h"
#if (ENABLE_WIFI_AND_MQTT == 1)
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
// example is mainly taken from .pio/libdeps/windows_linux_64bit/MQTT-C/tests.c, TEST__api__publish_subscribe__single
#if !defined(WIN32)
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#else
#include <ws2tcpip.h>
/* Some shortcuts to call winapi in a posix-like way */
#define close(sock) closesocket(sock)
#define usleep(usec) Sleep((usec) / 1000)
#endif
#include "lib/MQTT-C/include/mqtt.h"
#include "lib/MQTT-C/include/posix_sockets.h"
int sockfd = -1;
uint8_t sendmem1[1024], sendmem2[1024];
uint8_t recvmem1[1024], recvmem2[1024];
struct mqtt_client mqttClient;
std::string uniqueClientSuffix = "";
int state = 0;
tAnnounceWiFiconnected_cb thisAnnounceWiFiconnected_cb = NULL;
void set_announceWiFiconnected_cb_HAL(tAnnounceWiFiconnected_cb pAnnounceWiFiconnected_cb) {
thisAnnounceWiFiconnected_cb = pAnnounceWiFiconnected_cb;
}
tAnnounceSubscribedTopics_cb thisAnnounceSubscribedTopics_cb = NULL;
void set_announceSubscribedTopics_cb_HAL(tAnnounceSubscribedTopics_cb pAnnounceSubscribedTopics_cb) {
thisAnnounceSubscribedTopics_cb = pAnnounceSubscribedTopics_cb;
}
bool getIsWifiConnected_HAL() {
return (sockfd != -1);
}
void publish_callback(void** state, struct mqtt_response_publish *publish) {
**(int**)state += 1;
printf("message nr %d received\r\n", **(int**)state);
std::string topic((const char*) (publish->topic_name), publish->topic_name_size);
std::string payload((const char*) (publish->application_message), publish->application_message_size);
printf("Received a PUBLISH(topic=%s, DUP=%d, QOS=%d, RETAIN=%d, pid=%d) from the broker. Data='%s'\r\n",
topic.c_str(), publish->dup_flag, publish->qos_level, publish->retain_flag, publish->packet_id,
payload.c_str()
);
thisAnnounceSubscribedTopics_cb(topic, payload);
}
void mqtt_subscribeTopics() {
mqtt_subscribe(&mqttClient, "OMOTE/test", 2);
}
void reconnect_mqtt(struct mqtt_client *mqttClient, void**) {
printf("MQTT: will reconnect ...\r\n");
mqtt_reinit(mqttClient, sockfd, sendmem1, sizeof(sendmem1), recvmem1, sizeof(recvmem1));
std::string mqttClientName = std::string(MQTT_CLIENTNAME) + uniqueClientSuffix;
// client_id, will_topic, will_message, will_message_size, user_name, password, connect_flags, keep_alive
mqtt_connect(mqttClient, mqttClientName.c_str(), NULL, NULL, 0, MQTT_USER, MQTT_PASS, 0, 30);
if (mqttClient->error != MQTT_OK) {
printf("MQTT: connect error: %s\r\n", mqtt_error_str(mqttClient->error));
// sockfd = -1;
// return;
}
}
#if !defined(WIN32)
std::string getMACaddress() {
struct ifreq s;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
strcpy(s.ifr_name, "eth0");
if (0 == ioctl(fd, SIOCGIFHWADDR, &s)) {
char buffer[6*3];
int i;
for (i = 0; i < 6; ++i) {
sprintf(&buffer[i*3], "%02x:", (unsigned char) s.ifr_addr.sa_data[i]);
// printf(" %02x", (unsigned char) s.ifr_addr.sa_data[i]);
}
//printf("\r\n");
std::string MACaddress = std::string(buffer, 17);
printf(" result in MACaddress(): %s\r\n", MACaddress.c_str());
return MACaddress;
}
return "";
}
#endif
void init_mqtt_HAL(void) {
#if defined(WIN32)
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
printf("Failed to init sockets: %i\r\n", iResult);
return; // return iResult;
}
#endif
char MACaddress[6*3];
sockfd = open_nb_socket(MQTT_SERVER, std::to_string(MQTT_SERVER_PORT).c_str(), MACaddress);
if (sockfd == -1) {
printf("MQTT: Failed to open socket\r\n");
return;
}
#if !defined(WIN32)
// MAC address is not the best. You cannot start more than one instance like that, otherwise the MQTT broker will only keep the last connection.
// printf("MQTT: received MAC address from posix_sockets.h is %s\r\n", MACaddress);
// uniqueClientSuffix = std::string(MACaddress, 18);
// simply use a random number
srand(time(NULL)); // Initialization, should only be called once.
int r = rand(); // Returns a pseudo-random integer between 0 and RAND_MAX.
uniqueClientSuffix = "_linux_" + std::to_string(r);
#else
srand(time(NULL)); // Initialization, should only be called once.
int r = rand(); // Returns a pseudo-random integer between 0 and RAND_MAX.
uniqueClientSuffix = "_windows_" + std::to_string(r);
#endif
// printf("MQTT: MAC address from getMACaddress() in mqtt_hal_windows_linux.cpp is %s\r\n", getMACaddress().c_str());
// printf("MQTT: will init ...\r\n");
// mqtt_init(&mqttClient, sockfd, sendmem1, sizeof(sendmem1), recvmem1, sizeof(recvmem1), publish_callback);
printf("MQTT: will init with reconnect ...\r\n");
mqtt_init_reconnect(&mqttClient, reconnect_mqtt, NULL, publish_callback);
reconnect_mqtt(&mqttClient, NULL);
mqttClient.publish_response_callback_state = &state;
mqtt_subscribeTopics();
thisAnnounceWiFiconnected_cb(true);
}
void mqtt_loop_HAL() {
if (sockfd != -1) {
mqtt_sync(&mqttClient);
}
}
bool publishMQTTMessage_HAL(const char *topic, const char *payload) {
if (sockfd == -1) {
init_mqtt_HAL();
}
mqtt_publish(&mqttClient, topic, payload, strlen(payload), MQTT_PUBLISH_QOS_0);
if (mqttClient.error != MQTT_OK) {
printf("MQTT: publish error %s\r\n", mqtt_error_str(mqttClient.error));
sockfd = -1;
return false;
}
return true;
}
void init_mqtt_HAL(void) {}
void wifiStop_HAL() {
/* disconnect */
if (sockfd != -1) {
mqtt_disconnect(&mqttClient);
mqtt_sync(&mqttClient);
}
#if defined(WIN32)
WSACleanup();
#endif
bool publishMQTTMessage_HAL(const char *topic, const char *payload){
return false;
}
void wifiStop_HAL() {}
void set_showWiFiconnected_cb_HAL(showWiFiconnected_cb pShowWiFiconnected_cb) {}
#endif

View file

@ -4,10 +4,13 @@
void init_mqtt_HAL(void);
bool getIsWifiConnected_HAL();
void mqtt_loop_HAL();
bool publishMQTTMessage_HAL(const char *topic, const char *payload);
void wifiStop_HAL();
typedef void (*showWiFiconnected_cb)(bool connected);
void set_showWiFiconnected_cb_HAL(showWiFiconnected_cb pShowWiFiconnected_cb);
typedef void (*tAnnounceWiFiconnected_cb)(bool connected);
void set_announceWiFiconnected_cb_HAL(tAnnounceWiFiconnected_cb pAnnounceWiFiconnected_cb);
typedef void (*tAnnounceSubscribedTopics_cb)(std::string topic, std::string payload);
void set_announceSubscribedTopics_cb_HAL(tAnnounceSubscribedTopics_cb pAnnounceSubscribedTopics_cb);
#endif

View file

@ -143,8 +143,8 @@ build_src_filter =
+<../hardware/ESP32/*>
;+<../hardware/ESP32/lib/ESP32-BLE-Keyboard/*>
; use this if you have a 64 bit compiler (Ubuntu, WSL2, Windows with MSYS2 MINGW64)
[env:windows_linux_64bit]
; use this if you are using Ubuntu or WSL2 (64 bit compiler)
[env:linux_64bit]
platform = native@^1.2.1
lib_deps =
${env.lib_deps}
@ -169,20 +169,29 @@ build_flags =
-D SDL_ZOOM=2
;-- hardware abstraction, needed to find hardwareLayer.h ------------------
-I hardware
-I hardware/windows_linux/lib/MQTT-C/include
build_src_filter =
+<*>
+<../hardware/windows_linux/*>
; use this if you have a 32 bit compiler (Windows MSYS2 MINGW32)
[env:windows_linux_32bit]
extends = env:windows_linux_64bit
; use this if you are using Windows MSYS2 MINGW64 (64 bit compiler)
[env:windows_64bit]
extends = env:linux_64bit
build_flags =
${env:linux_64bit.build_flags}
; winsock
-l ws2_32
; use this if you are using Windows MSYS2 MINGW32 (32 bit compiler)
[env:windows_32bit]
extends = env:windows_64bit
build_unflags =
${env:windows_linux_64bit.build_unflags}
${env:windows_64bit.build_unflags}
;-- lvgl ------------------------------------------------------------------
-D LV_MEM_CUSTOM=0
-D LV_MEM_SIZE="(64U * 1024U)"
build_flags =
${env:windows_linux_64bit.build_flags}
${env:windows_64bit.build_flags}
;-- lvgl ------------------------------------------------------------------
; 32 bit needs exact the same lvgl memory as on ESP32
-D LV_MEM_CUSTOM=0

View file

@ -7,6 +7,10 @@
#include "applicationInternal/scenes/sceneHandler.h"
#include "applicationInternal/hardware/hardwarePresenter.h"
#include "devices/misc/device_specialCommands.h"
// show WiFi status
#include "applicationInternal/gui/guiBase.h"
// show received IR and MQTT messages
#include "guis/gui_irReceiver.h"
uint16_t KEYBOARD_DUMMY_UP ; //"Keyboard_dummy_up"
uint16_t KEYBOARD_DUMMY_DOWN ; //"Keyboard_dummy_down"
@ -250,3 +254,29 @@ void executeCommand(uint16_t command, std::string additionalPayload) {
Serial.printf("executeCommand: internal error, command not registered\r\n");
}
}
void receiveNewIRmessage_cb(std::string message) {
showNewIRmessage(message);
}
#if (ENABLE_WIFI_AND_MQTT == 1)
void receiveWiFiConnected_cb(bool connected) {
// show status in header
showWiFiConnected(connected);
if (connected) {
// Here you could add sending a MQTT message. This message could be recognized by your home automation software.
// When receiving this message, your home automation software could send the states of the smart home devices known to OMOTE.
// With that, OMOTE could show on startup the correct status of the smart home devices.
//
// Remark: in your home automation software, maybe add a short delay (e.g. 100-200 ms) between receiving this message and sending out the status of the smart home devices.
// WiFi connection could be already available, but MQTT connection could be not completely ready. Just try what works for you.
// executeCommand(TRIGGER_UPDATE_OF_OMOTE_SMART_HOME_DEVICES);
}
}
void receiveMQTTmessage_cb(std::string topic, std::string payload) {
showMQTTmessage(topic, payload);
}
#endif

View file

@ -116,3 +116,10 @@ void get_uniqueCommandID(uint16_t *command);
void register_keyboardCommands();
commandData makeCommandData(commandHandlers a, std::list<std::string> b);
void executeCommand(uint16_t command, std::string additionalPayload = "");
void receiveNewIRmessage_cb(std::string message);
#if (ENABLE_WIFI_AND_MQTT == 1)
// used as callbacks from hardware
void receiveWiFiConnected_cb(bool connected);
void receiveMQTTmessage_cb(std::string topic, std::string payload);
#endif

View file

@ -291,7 +291,7 @@ void setActiveTab(uint32_t index, lv_anim_enable_t anim_en) {
}
}
void showWiFiConnected_cb(bool connected) {
void showWiFiConnected(bool connected) {
if (connected) {
if (WifiLabel != NULL) {lv_label_set_text(WifiLabel, LV_SYMBOL_WIFI);}
} else {

View file

@ -33,5 +33,5 @@ void tabview_tab_changed_event_cb(lv_event_t* e);
void setActiveTab(uint32_t index, lv_anim_enable_t anim_en);
// used by memoryUsage.cpp
void showMemoryUsageBar(bool showBar);
// used as callback from hardware
void showWiFiConnected_cb(bool connected);
// used by commandHandler to show WiFi status
void showWiFiConnected(bool connected);

View file

@ -3,6 +3,8 @@
#include "applicationInternal/hardware/hardwarePresenter.h"
// for registering the callback to show received IR messages
#include "guis/gui_irReceiver.h"
// for registering the callback to receive MQTT messages
#include "../commandHandler.h"
// for registering the callback to show WiFi status
#include "applicationInternal/gui/guiBase.h"
@ -111,9 +113,9 @@ bool get_irReceiverEnabled() {
}
void set_irReceiverEnabled(bool aIrReceiverEnabled) {
if (aIrReceiverEnabled) {
set_showNewIRmessage_cb_HAL(&showNewIRmessage_cb);
set_announceNewIRmessage_cb_HAL(&receiveNewIRmessage_cb);
} else {
set_showNewIRmessage_cb_HAL(NULL);
set_announceNewIRmessage_cb_HAL(NULL);
}
set_irReceiverEnabled_HAL(aIrReceiverEnabled);
}
@ -169,13 +171,17 @@ void init_lvgl_hardware() {
// --- WiFi / MQTT ------------------------------------------------------------
#if (ENABLE_WIFI_AND_MQTT == 1)
void init_mqtt(void) {
set_showWiFiconnected_cb_HAL(&showWiFiConnected_cb);
set_announceWiFiconnected_cb_HAL(&receiveWiFiConnected_cb);
set_announceSubscribedTopics_cb_HAL(receiveMQTTmessage_cb);
init_mqtt_HAL();
}
// used by "commandHandler.cpp", "sleep.cpp"
bool getIsWifiConnected() {
return getIsWifiConnected_HAL();
}
void mqtt_loop() {
mqtt_loop_HAL();
}
bool publishMQTTMessage(const char *topic, const char *payload) {
return publishMQTTMessage_HAL(topic, payload);
}

View file

@ -108,6 +108,7 @@ void init_lvgl_hardware();
void init_mqtt(void);
// used by "commandHandler.cpp", "sleep.cpp"
bool getIsWifiConnected();
void mqtt_loop();
bool publishMQTTMessage(const char *topic, const char *payload);
void wifiStop();
#endif

View file

@ -3,11 +3,15 @@
uint16_t COMMAND_UNKNOWN ;
uint16_t MY_SPECIAL_COMMAND; //"My_special_command";
// uint16_t TRIGGER_UPDATE_OF_OMOTE_SMART_HOME_DEVICES;
void register_specialCommands() {
get_uniqueCommandID(&COMMAND_UNKNOWN);
// command to trigger your home automation software to send the states of the smart home devices known to OMOTE
// register_command(&TRIGGER_UPDATE_OF_OMOTE_SMART_HOME_DEVICES, makeCommandData(MQTT, {"put_here_your_topic_to_trigger_update_of_omote_smart_home_devices", "PRESS"}));
// put SPECIAL commands here if you want
register_command(&MY_SPECIAL_COMMAND , makeCommandData(SPECIAL, {""}));
register_command(&MY_SPECIAL_COMMAND, makeCommandData(SPECIAL, {""}));
}

View file

@ -4,5 +4,6 @@
extern uint16_t COMMAND_UNKNOWN;
extern uint16_t MY_SPECIAL_COMMAND;
// extern uint16_t TRIGGER_UPDATE_OF_OMOTE_SMART_HOME_DEVICES;
void register_specialCommands();

View file

@ -16,6 +16,20 @@ int messagePos = 0;
int messageCount = 0;
bool tabIsInMemory = false;
lv_obj_t* objMQTTmessageReceivedTopic;
lv_obj_t* objMQTTmessageReceivedPayload;
void showMQTTmessage(std::string topic, std::string payload) {
if (!tabIsInMemory) {return;}
if (objMQTTmessageReceivedTopic != NULL) {
lv_label_set_text(objMQTTmessageReceivedTopic, topic.c_str());
}
if (objMQTTmessageReceivedPayload != NULL) {
lv_label_set_text(objMQTTmessageReceivedPayload, payload.c_str());
}
}
void printReceivedMessages(bool clearMessages = false) {
if (!tabIsInMemory) {return;}
@ -44,7 +58,7 @@ void printReceivedMessages(bool clearMessages = false) {
}
}
void showNewIRmessage_cb(std::string message) {
void showNewIRmessage(std::string message) {
setLastActivityTimestamp(); // Reset the sleep timer when a IR message is received
// Serial.printf(" new IR message received: %s\r\n", message.c_str());
@ -130,6 +144,23 @@ void create_tab_content_irReceiver(lv_obj_t* tab) {
printReceivedMessages(true);
}
// Show MQTT messages we subscribed to ------------------------------------------------------
menuLabel = lv_label_create(tab);
lv_label_set_text(menuLabel, "MQTT messages arrived");
lv_obj_t* menuBox = lv_obj_create(tab);
lv_obj_set_size(menuBox, lv_pct(100), 46);
lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN);
lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN);
objMQTTmessageReceivedTopic = lv_label_create(menuBox);
lv_label_set_text(objMQTTmessageReceivedTopic, "");
lv_obj_set_style_text_font(objMQTTmessageReceivedTopic, &lv_font_montserrat_10, LV_PART_MAIN);
lv_obj_align(objMQTTmessageReceivedTopic, LV_ALIGN_TOP_LEFT, 0, -4);
objMQTTmessageReceivedPayload = lv_label_create(menuBox);
lv_label_set_text(objMQTTmessageReceivedPayload, "");
lv_obj_set_style_text_font(objMQTTmessageReceivedPayload, &lv_font_montserrat_10, LV_PART_MAIN);
lv_obj_align(objMQTTmessageReceivedPayload, LV_ALIGN_TOP_LEFT, 0, 8);
}
void notify_tab_before_delete_irReceiver(void) {

View file

@ -6,4 +6,6 @@
const char * const tabName_irReceiver = "IR Receiver";
void register_gui_irReceiver(void);
void showNewIRmessage_cb(std::string);
// used by commandHandler to show WiFi status
void showNewIRmessage(std::string);
void showMQTTmessage(std::string topic, std::string payload);

View file

@ -138,6 +138,10 @@ void loop(unsigned long *pIMUTaskTimer, unsigned long *pUpdateStatusTimer) {
}
// update LVGL UI
gui_loop();
// call mqtt loop to receive mqtt messages, if you are subscribed to some topics
#if (ENABLE_WIFI_AND_MQTT == 1)
mqtt_loop();
#endif
// --- every 100 ms -------------------------------------------------------------------
// Refresh IMU data (motion detection) every 100 ms
@ -146,6 +150,7 @@ void loop(unsigned long *pIMUTaskTimer, unsigned long *pUpdateStatusTimer) {
*pIMUTaskTimer = millis();
check_activity();
}
// --- every 1000 ms ------------------------------------------------------------------