2016-10-28 18:04:30 +02:00
|
|
|
#ifndef CONFIG_DISABLE_MQTT
|
2016-04-08 01:03:57 +02:00
|
|
|
#include <stdarg.h>
|
2016-09-16 11:42:33 +02:00
|
|
|
#include "utils.h"
|
2016-04-14 01:15:42 +02:00
|
|
|
#include "MQTT.h"
|
|
|
|
|
2016-12-14 00:08:47 +01:00
|
|
|
#define MAX_PIN 15
|
2016-12-13 22:31:14 +01:00
|
|
|
#define MAX_GPIO_OBSERVED (MAXSUBSCRIPTIONS*2)
|
2016-03-14 01:47:43 +01:00
|
|
|
Adafruit_MQTT_Client *mqtt;
|
2016-06-18 02:24:00 +02:00
|
|
|
Adafruit_MQTT_Publish *mqtt_ip;
|
2016-09-28 13:45:01 +02:00
|
|
|
Adafruit_MQTT_Publish *mqttGpio[MAXSUBSCRIPTIONS] = {};
|
2016-09-28 14:08:43 +02:00
|
|
|
Adafruit_MQTT_Publish *mqttPwm[MAXSUBSCRIPTIONS] = {};
|
2016-12-13 22:31:14 +01:00
|
|
|
Adafruit_MQTT_Publish *mqttGpioObserved[MAX_GPIO_OBSERVED] = {};
|
2016-12-14 00:08:47 +01:00
|
|
|
gpioInfo mqttIRQ[MAX_PIN + 1] = {};
|
2016-03-14 01:47:43 +01:00
|
|
|
|
2016-06-01 00:49:42 +02:00
|
|
|
#define FEED_MAX_SIZE 96
|
2016-03-21 00:56:27 +01:00
|
|
|
|
2016-04-01 00:14:12 +02:00
|
|
|
bool isMqttConfigured = false;
|
2016-09-15 22:43:00 +02:00
|
|
|
bool useMqtts = false;
|
2016-04-01 00:14:12 +02:00
|
|
|
|
2016-04-14 01:15:42 +02:00
|
|
|
|
2020-03-09 22:38:43 +01:00
|
|
|
int MqttSetup(const char *server, const char *user, const char *passwd, int port, const char *hostname) {
|
2016-09-15 22:43:00 +02:00
|
|
|
useMqtts = (port == 8883);
|
2016-04-14 01:15:42 +02:00
|
|
|
isMqttConfigured = server[0] != '\0';
|
2016-03-25 01:08:48 +01:00
|
|
|
|
2019-05-14 23:44:46 +02:00
|
|
|
if (!isMqttConfigured)
|
2016-04-14 01:15:42 +02:00
|
|
|
return 0;
|
2016-03-25 01:08:48 +01:00
|
|
|
|
2016-09-28 23:19:12 +02:00
|
|
|
#ifndef CONFIG_DISABLE_SSL
|
2019-05-14 23:44:46 +02:00
|
|
|
if (useMqtts)
|
2016-09-15 22:43:00 +02:00
|
|
|
mqtt = new Adafruit_MQTT_Client(new WiFiClientSecure(), server, port, user, passwd);
|
|
|
|
else
|
2016-09-28 23:19:12 +02:00
|
|
|
#endif
|
2016-09-15 22:43:00 +02:00
|
|
|
mqtt = new Adafruit_MQTT_Client(new WiFiClient(), server, port, user, passwd);
|
2016-09-27 23:51:01 +02:00
|
|
|
|
2020-03-09 22:38:43 +01:00
|
|
|
mqtt_ip = MqttCreatePublisher(0, 1, IP_FEED_FORMAT, user, hostname);
|
2016-04-01 00:14:12 +02:00
|
|
|
|
2019-05-14 23:44:46 +02:00
|
|
|
if (NB_ELEMENTS(gpioControlled) + NB_ELEMENTS(pwmControlled) > MAXSUBSCRIPTIONS) {
|
|
|
|
SKETCH_DEBUG_PRINTF("Too much gpio/pwm to control\n Nb gpio %d Nb pwm %d Max is %d",
|
2016-12-13 22:31:14 +01:00
|
|
|
NB_ELEMENTS(gpioControlled), NB_ELEMENTS(pwmControlled), MAXSUBSCRIPTIONS);
|
|
|
|
return -1;
|
|
|
|
}
|
2019-05-14 23:44:46 +02:00
|
|
|
if (NB_ELEMENTS(gpioObserved) > MAX_GPIO_OBSERVED) {
|
2016-12-13 22:31:14 +01:00
|
|
|
SKETCH_DEBUG_PRINTF("Too much gpio observed\n Nb gpio %d Nb is %d",
|
|
|
|
NB_ELEMENTS(gpioObserved), MAX_GPIO_OBSERVED);
|
2016-09-28 14:08:43 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-12-13 22:31:14 +01:00
|
|
|
for (uint i = 0 ; i < NB_ELEMENTS(gpioControlled); i++) {
|
2020-03-09 22:38:43 +01:00
|
|
|
mqtt->subscribe(MqttCreateSubscribe(GPIO_SET_FEED_FORMAT, user, hostname, gpioControlled[i]));
|
|
|
|
mqttGpio[i] = MqttCreatePublisher(0, 0, GPIO_FEED_FORMAT, user, hostname, gpioControlled[i]);
|
2016-03-22 20:01:05 +01:00
|
|
|
}
|
2016-09-28 14:08:43 +02:00
|
|
|
|
2016-12-13 22:31:14 +01:00
|
|
|
for (uint i = 0 ; i < NB_ELEMENTS(gpioObserved) && i < MAX_GPIO_OBSERVED ; i++) {
|
2020-03-09 22:38:43 +01:00
|
|
|
mqttGpioObserved[i] = MqttCreatePublisher(0, 0, GPIO_FEED_FORMAT, user, hostname, gpioObserved[i]);
|
2016-12-14 00:08:47 +01:00
|
|
|
new HIB(gpioObserved[i], HIGH, MqttNofityIRQ , MqttNofityIRQ, NULL );
|
2016-12-13 22:31:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (uint i = 0 ; i < NB_ELEMENTS(pwmControlled); i++) {
|
2020-03-09 22:38:43 +01:00
|
|
|
mqtt->subscribe(MqttCreateSubscribe(PWM_SET_FEED_FORMAT, user, hostname, pwmControlled[i]));
|
|
|
|
mqttPwm[i] = MqttCreatePublisher(0, 0, PWM_FEED_FORMAT, user, hostname, pwmControlled[i]);
|
2016-09-28 14:08:43 +02:00
|
|
|
}
|
2016-12-13 22:31:14 +01:00
|
|
|
|
2016-03-14 01:47:43 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-14 23:44:46 +02:00
|
|
|
Adafruit_MQTT_Publish *MqttCreatePublisher( uint8_t qos, uint8_t retain, const char *fmt, ...) {
|
2016-04-14 01:15:42 +02:00
|
|
|
char buf[FEED_MAX_SIZE];
|
2016-04-08 01:03:57 +02:00
|
|
|
va_list args;
|
|
|
|
va_start (args, fmt);
|
|
|
|
vsnprintf(buf, sizeof(buf), (const char *)fmt, args);
|
|
|
|
va_end(args);
|
2017-03-06 23:30:21 +01:00
|
|
|
return new Adafruit_MQTT_Publish(mqtt, strdup(buf), qos, retain);
|
2016-04-08 01:03:57 +02:00
|
|
|
}
|
|
|
|
|
2019-05-14 23:44:46 +02:00
|
|
|
|
|
|
|
int MqttBatchPublish(std::vector<struct mqttInfo> tab, ...) {
|
2019-06-04 23:18:17 +02:00
|
|
|
if (MqttConnect()) {
|
2019-05-14 23:44:46 +02:00
|
|
|
SKETCH_DEBUG_PRINTLN("cannot connect to mqtt");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (auto info : tab) {
|
|
|
|
char buf[FEED_MAX_SIZE];
|
|
|
|
va_list args;
|
|
|
|
va_start (args, tab);
|
|
|
|
vsnprintf(buf, sizeof(buf), (const char *)info.topic, args);
|
|
|
|
va_end(args);
|
2020-02-28 23:40:35 +01:00
|
|
|
// SKETCH_DEBUG_PRINTF("publishing %f for %s\n", info.value, buf);
|
2019-05-14 23:44:46 +02:00
|
|
|
Adafruit_MQTT_Publish client(mqtt, buf, info.qos, info.retain);
|
|
|
|
if (!client.publish(info.value))
|
|
|
|
SKETCH_DEBUG_PRINTLN("Fail :(");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Adafruit_MQTT_Subscribe *MqttCreateSubscribe(const char *fmt, ...) {
|
2016-09-27 23:44:52 +02:00
|
|
|
char buf[FEED_MAX_SIZE];
|
|
|
|
va_list args;
|
|
|
|
va_start (args, fmt);
|
|
|
|
vsnprintf(buf, sizeof(buf), (const char *)fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
return new Adafruit_MQTT_Subscribe(mqtt, strdup(buf));
|
2016-04-01 00:14:12 +02:00
|
|
|
}
|
2016-04-10 01:59:37 +02:00
|
|
|
|
2016-03-24 14:54:55 +01:00
|
|
|
int MqttIsConnected() {
|
2016-12-13 22:31:14 +01:00
|
|
|
return (isMqttConfigured && (mode == BOOTMODE_NORMAL)) ? mqtt->connected() : 0;
|
2016-03-14 18:05:14 +01:00
|
|
|
}
|
|
|
|
|
2016-03-11 01:31:03 +01:00
|
|
|
// Function to connect and reconnect as necessary to the MQTT server.
|
|
|
|
// Should be called in the loop function and it will take care if connecting.
|
2016-03-24 14:54:55 +01:00
|
|
|
int MqttConnect() {
|
2016-03-11 01:31:03 +01:00
|
|
|
int8_t ret;
|
|
|
|
|
2016-12-13 22:31:14 +01:00
|
|
|
if (!isMqttConfigured || mode != BOOTMODE_NORMAL)
|
2016-04-10 01:59:37 +02:00
|
|
|
return -1;
|
|
|
|
|
2016-03-11 01:31:03 +01:00
|
|
|
// Stop if already connected.
|
2016-03-14 01:47:43 +01:00
|
|
|
if (mqtt->connected()) {
|
2016-03-11 01:31:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t retries = 3;
|
2016-03-14 01:47:43 +01:00
|
|
|
while ((ret = mqtt->connect()) != 0) { // connect will return 0 for connected
|
2016-03-26 15:07:15 +01:00
|
|
|
SKETCH_DEBUG_PRINTLN(mqtt->connectErrorString(ret));
|
|
|
|
SKETCH_DEBUG_PRINTLN("Retrying MQTT connection ...");
|
2016-03-14 01:47:43 +01:00
|
|
|
mqtt->disconnect();
|
2016-03-11 01:31:03 +01:00
|
|
|
delay(100); // wait
|
|
|
|
retries--;
|
|
|
|
if (retries == 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2016-03-22 20:01:05 +01:00
|
|
|
|
2019-05-14 23:44:46 +02:00
|
|
|
template<typename T> int MqttPublish(Adafruit_MQTT_Publish *publisher, T value) {
|
2016-11-20 00:23:16 +01:00
|
|
|
if (MqttConnect() == 0) {
|
2016-11-16 16:59:17 +01:00
|
|
|
publisher->publish(value);
|
|
|
|
return 0;
|
2016-03-22 20:01:05 +01:00
|
|
|
}
|
2016-11-16 16:59:17 +01:00
|
|
|
return -1;
|
2016-03-22 20:01:05 +01:00
|
|
|
}
|
|
|
|
|
2016-11-16 16:59:17 +01:00
|
|
|
int MqttPublishIP(const String &ip) {
|
|
|
|
return MqttPublish(mqtt_ip, ip.c_str());
|
|
|
|
}
|
|
|
|
|
2016-09-28 14:08:43 +02:00
|
|
|
int getGpioFromSubscription(Adafruit_MQTT_Subscribe *subscription, const char *pattern) {
|
|
|
|
char *temp = strstr(subscription->topic, pattern);
|
2016-03-25 01:08:48 +01:00
|
|
|
if (!temp)
|
2016-03-22 20:01:05 +01:00
|
|
|
return -1;
|
2016-09-28 14:08:43 +02:00
|
|
|
String gpioStr(temp + strlen(pattern));
|
2016-03-22 20:01:05 +01:00
|
|
|
int idx = gpioStr.indexOf("/");
|
2016-03-23 00:34:50 +01:00
|
|
|
int gpio = gpioStr.substring(0, idx).toInt();
|
|
|
|
|
|
|
|
if (gpio >= 0 && gpio < 32 )
|
2016-03-22 20:01:05 +01:00
|
|
|
return gpio;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-05-14 23:44:46 +02:00
|
|
|
void MqttNofityIRQ(uint8_t gpio, int value) {
|
2016-12-14 00:08:47 +01:00
|
|
|
mqttIRQ[gpio].updated = 1;
|
|
|
|
mqttIRQ[gpio].value = value;
|
|
|
|
}
|
|
|
|
|
2019-05-14 23:44:46 +02:00
|
|
|
void MqttNofity(int gpio, int value) {
|
2016-12-13 22:31:14 +01:00
|
|
|
if (MqttIsConnected()) {
|
|
|
|
int watchIdx = findIndex(gpio, gpioControlled);
|
|
|
|
if (watchIdx >= 0 ) {
|
|
|
|
mqttGpio[watchIdx]->publish(value);
|
|
|
|
} else {
|
|
|
|
watchIdx = findIndex(gpio, gpioObserved);
|
|
|
|
if (watchIdx >= 0 )
|
|
|
|
mqttGpioObserved[watchIdx]->publish(value);
|
|
|
|
}
|
2016-09-28 14:08:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-28 00:21:12 +02:00
|
|
|
void MqttChangeGpioValue(int gpio, int value) {
|
|
|
|
pinMode(gpio, OUTPUT);
|
|
|
|
digitalWrite(gpio, value);
|
|
|
|
MqttNofity(gpio, value);
|
|
|
|
}
|
|
|
|
|
2016-09-28 14:08:43 +02:00
|
|
|
void MqttChangePWMValue(int gpio, int value) {
|
|
|
|
analogWrite(gpio, value);
|
2016-10-28 00:21:12 +02:00
|
|
|
MqttNofity(gpio, value);
|
2016-03-22 20:01:05 +01:00
|
|
|
}
|
|
|
|
|
2016-12-14 00:08:47 +01:00
|
|
|
void MqttCheckIRQ() {
|
|
|
|
for (uint i = 0 ; i < NB_ELEMENTS(mqttIRQ); i++) {
|
2019-05-14 23:44:46 +02:00
|
|
|
if (mqttIRQ[i].updated == 1) {
|
2016-12-14 00:08:47 +01:00
|
|
|
mqttIRQ[i].updated = 0;
|
|
|
|
MqttNofity(i, mqttIRQ[i].value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-09-10 22:48:37 +02:00
|
|
|
void MqttCheckSubscription()
|
|
|
|
{
|
|
|
|
if (mqtt->getSubscriptionCount() == 0)
|
|
|
|
return;
|
2016-03-24 14:54:55 +01:00
|
|
|
if (MqttConnect() == 0) {
|
2016-03-22 20:01:05 +01:00
|
|
|
Adafruit_MQTT_Subscribe *subscription;
|
2016-04-10 00:37:41 +02:00
|
|
|
while ((subscription = mqtt->readSubscription(0))) {
|
2016-09-28 14:08:43 +02:00
|
|
|
int gpio = getGpioFromSubscription(subscription, "/gpio/");
|
2016-12-09 22:55:12 +01:00
|
|
|
if (gpio > 0 && findIndex(gpio, gpioControlled) >= 0) {
|
2016-09-28 14:08:43 +02:00
|
|
|
SKETCH_DEBUG_PRINTF("Got Subscription for GPIO %d\n", gpio);
|
2022-09-10 22:48:37 +02:00
|
|
|
char *value = (char *)subscription->lastread;
|
2016-09-28 00:29:54 +02:00
|
|
|
SKETCH_DEBUG_PRINTF("Receive data: %s\n", value);
|
2016-03-24 14:54:55 +01:00
|
|
|
MqttChangeGpioValue(gpio, atoi(value));
|
2016-03-22 20:01:05 +01:00
|
|
|
}
|
2016-09-28 14:08:43 +02:00
|
|
|
|
|
|
|
gpio = getGpioFromSubscription(subscription, "/pwm/");
|
2016-12-13 22:31:14 +01:00
|
|
|
if (gpio > 0 && findIndex(gpio, pwmControlled) >= 0) {
|
2016-09-28 14:08:43 +02:00
|
|
|
SKETCH_DEBUG_PRINTF("Got Subscription for PWM %d\n", gpio);
|
2022-09-10 22:48:37 +02:00
|
|
|
char *value = (char *)subscription->lastread;
|
2016-09-28 14:08:43 +02:00
|
|
|
SKETCH_DEBUG_PRINTF("Receive data: %s\n", value);
|
|
|
|
MqttChangePWMValue(gpio, atoi(value));
|
|
|
|
}
|
2016-03-22 20:01:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-28 18:04:30 +02:00
|
|
|
#endif
|