1043 lines
39 KiB
C
1043 lines
39 KiB
C
#include <libgen.h>
|
|
#include <netdb.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <sys/ioctl.h>
|
|
//#include <sys/inotify.h>
|
|
#include <net/if.h>
|
|
|
|
#ifdef USE_WIRINGPI
|
|
#include <wiringPi.h>
|
|
#else
|
|
#include "GPIO_Pi.h"
|
|
#endif
|
|
|
|
#include "mongoose.h"
|
|
#include "utils.h"
|
|
#include "net_services.h"
|
|
#include "config.h"
|
|
#include "json_messages.h"
|
|
#include "zone_ctrl.h"
|
|
#include "sd_cron.h"
|
|
#include "hassio.h"
|
|
|
|
|
|
#define EVENT_SIZE ( sizeof (struct inotify_event) )
|
|
#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
|
|
|
|
|
|
typedef enum {mqttstarting, mqttrunning, mqttstopped, mqttdisabled} mqttstatus;
|
|
static mqttstatus _mqtt_status = mqttstopped;
|
|
struct mg_connection *_mqtt_connection;
|
|
static time_t _mqtt_connected_time;
|
|
|
|
void start_mqtt(struct mg_mgr *mgr);
|
|
|
|
static int is_websocket(const struct mg_connection *nc) {
|
|
return nc->flags & MG_F_IS_WEBSOCKET;
|
|
}
|
|
static int is_mqtt(const struct mg_connection *nc) {
|
|
return nc->flags & MG_F_USER_1;
|
|
}
|
|
static void set_mqtt(struct mg_connection *nc) {
|
|
nc->flags |= MG_F_USER_1;
|
|
}
|
|
// Find the first network interface with valid MAC and put mac address into buffer upto length
|
|
bool mac(char *buf, int len)
|
|
{
|
|
struct ifreq s;
|
|
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
|
struct if_nameindex *if_nidxs, *intf;
|
|
|
|
if_nidxs = if_nameindex();
|
|
if (if_nidxs != NULL)
|
|
{
|
|
for (intf = if_nidxs; intf->if_index != 0 || intf->if_name != NULL; intf++)
|
|
{
|
|
strcpy(s.ifr_name, intf->if_name);
|
|
if (0 == ioctl(fd, SIOCGIFHWADDR, &s))
|
|
{
|
|
int i;
|
|
if ( s.ifr_addr.sa_data[0] == 0 &&
|
|
s.ifr_addr.sa_data[1] == 0 &&
|
|
s.ifr_addr.sa_data[2] == 0 &&
|
|
s.ifr_addr.sa_data[3] == 0 &&
|
|
s.ifr_addr.sa_data[4] == 0 &&
|
|
s.ifr_addr.sa_data[5] == 0 ) {
|
|
continue;
|
|
}
|
|
for (i = 0; i < 6 && i * 2 < len; ++i)
|
|
{
|
|
sprintf(&buf[i * 2], "%02x", (unsigned char)s.ifr_addr.sa_data[i]);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Return true if added or changed value, false if same.
|
|
bool update_dz_cache(int dzidx, int value) {
|
|
int i;
|
|
|
|
for(i=0; i < _sdconfig_.zones + NON_ZONE_DZIDS; i++)
|
|
{
|
|
if (_sdconfig_.dz_cache[i].idx == dzidx) {
|
|
if (_sdconfig_.dz_cache[i].status == value) {
|
|
//logMessage(LOG_DEBUG, "No change dzcache idx=%d %d\n", dzidx, value);
|
|
return false;
|
|
} else {
|
|
_sdconfig_.dz_cache[i].status = value;
|
|
//logMessage(LOG_DEBUG, "Updated dzcache idx=%d %d\n", dzidx, value);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// if we got here, there is no cache value, so create one.
|
|
for(i=0; i < _sdconfig_.zones + NON_ZONE_DZIDS; i++)
|
|
{
|
|
//logMessage(LOG_DEBUG, "dzcache index %d idx=%d %d\n",i, _sdconfig_.dz_cache[i].idx, _sdconfig_.dz_cache[i].status);
|
|
if (_sdconfig_.dz_cache[i].idx == 0) {
|
|
_sdconfig_.dz_cache[i].idx = dzidx;
|
|
_sdconfig_.dz_cache[i].status = value;
|
|
//logMessage(LOG_DEBUG, "Added dzcache idx=%d %d\n", dzidx, value);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
logMessage(LOG_ERR, "didn't find or create dzcache value idx=%d %d\n", dzidx, value);
|
|
return true;
|
|
}
|
|
|
|
bool check_dz_cache(int idx, int value) {
|
|
int i;
|
|
|
|
for(i=0; i < _sdconfig_.zones + NON_ZONE_DZIDS; i++)
|
|
{
|
|
if (_sdconfig_.dz_cache[i].idx == idx) {
|
|
if (_sdconfig_.dz_cache[i].status == value)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
/*
|
|
void urldecode(char *dst, const char *src)
|
|
{
|
|
char a, b;
|
|
while (*src)
|
|
{
|
|
if ((*src == '%') &&
|
|
((a = src[1]) && (b = src[2])) &&
|
|
(isxdigit(a) && isxdigit(b)))
|
|
{
|
|
if (a >= 'a')
|
|
a -= 'a' - 'A';
|
|
if (a >= 'A')
|
|
a -= ('A' - 10);
|
|
else
|
|
a -= '0';
|
|
if (b >= 'a')
|
|
b -= 'a' - 'A';
|
|
if (b >= 'A')
|
|
b -= ('A' - 10);
|
|
else
|
|
b -= '0';
|
|
*dst++ = 16 * a + b;
|
|
src += 3;
|
|
}
|
|
else if (*src == '+')
|
|
{
|
|
*dst++ = ' ';
|
|
src++;
|
|
}
|
|
else
|
|
{
|
|
*dst++ = *src++;
|
|
}
|
|
}
|
|
*dst++ = '\0';
|
|
}
|
|
*/
|
|
// Need to update network interface.
|
|
char *generate_mqtt_id(char *buf, int len) {
|
|
extern char *__progname; // glibc populates this
|
|
int i;
|
|
strncpy(buf, basename(__progname), len);
|
|
i = strlen(buf);
|
|
|
|
if (i < len) {
|
|
buf[i++] = '_';
|
|
// If we can't get MAC to pad mqtt id then use PID
|
|
if (!mac(&buf[i], len - i - 1)) {
|
|
sprintf(&buf[i], "%.*d", (len-i-2), getpid());
|
|
}
|
|
}
|
|
buf[len-1] = '\0';
|
|
|
|
return buf;
|
|
}
|
|
|
|
void send_mqtt_msg(struct mg_connection *nc, char *toppic, char *message)
|
|
{
|
|
static uint16_t msg_id = 0;
|
|
|
|
if (msg_id >= 65535){msg_id=1;}else{msg_id++;}
|
|
|
|
//mg_mqtt_publish(nc, toppic, msg_id, MG_MQTT_QOS(0), message, strlen(message));
|
|
mg_mqtt_publish(nc, toppic, msg_id, MG_MQTT_RETAIN | MG_MQTT_QOS(1), message, strlen(message));
|
|
|
|
logMessage(LOG_DEBUG, "MQTT: Published id=%d: %s %s\n", msg_id, toppic, message);
|
|
}
|
|
|
|
void publish_zone_mqtt(struct mg_connection *nc, struct GPIOcfg *gpiopin) {
|
|
static char mqtt_topic[250];
|
|
static char mqtt_msg[50];
|
|
|
|
if (_sdconfig_.enableMQTTaq == true) {
|
|
// sprintf(mqtt_topic, "%s/%s", _sdconfig_.mqtt_topic, gpiopin->name);
|
|
sprintf(mqtt_topic, "%s/zone%d", _sdconfig_.mqtt_topic, gpiopin->zone);
|
|
sprintf(mqtt_msg, "%s", (digitalRead(gpiopin->pin) == gpiopin->on_state ? MQTT_ON : MQTT_OFF));
|
|
send_mqtt_msg(nc, mqtt_topic, mqtt_msg);
|
|
sprintf(mqtt_topic, "%s/zone%d/duration", _sdconfig_.mqtt_topic, gpiopin->zone);
|
|
sprintf(mqtt_msg, "%d", gpiopin->default_runtime * 60);
|
|
send_mqtt_msg(nc, mqtt_topic, mqtt_msg);
|
|
|
|
sprintf(mqtt_topic, "%s/zone%d/remainingduration", _sdconfig_.mqtt_topic, gpiopin->zone);
|
|
if (_sdconfig_.currentZone.zone == gpiopin->zone && _sdconfig_.currentZone.type != zcNONE) {
|
|
sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft * 60);
|
|
} else {
|
|
sprintf(mqtt_msg, "%d", 0);
|
|
}
|
|
send_mqtt_msg(nc, mqtt_topic, mqtt_msg);
|
|
}
|
|
if (gpiopin->dz_idx > 0 && _sdconfig_.enableMQTTdz == true) {
|
|
if ( update_dz_cache(gpiopin->dz_idx,(digitalRead(gpiopin->pin) == gpiopin->on_state ? DZ_ON : DZ_OFF) ) ) {
|
|
build_dz_mqtt_status_JSON(mqtt_msg, 50, gpiopin->dz_idx, (digitalRead(gpiopin->pin) == gpiopin->on_state ? DZ_ON : DZ_OFF), TEMP_UNKNOWN);
|
|
send_mqtt_msg(nc, _sdconfig_.mqtt_dz_pub_topic, mqtt_msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
int sprinklerdstatus(char *status, int length)
|
|
{
|
|
// Status in this order
|
|
// Zone active and run time
|
|
// 24h delay and end time
|
|
// calendar schedule
|
|
// off
|
|
|
|
if (_sdconfig_.currentZone.type != zcNONE) {
|
|
sprintf(status,"Running: Zone %d - time left %02d:%02d",_sdconfig_.currentZone.zone, _sdconfig_.currentZone.timeleft / 60, _sdconfig_.currentZone.timeleft % 60 );
|
|
return 1;
|
|
} else if (_sdconfig_.delay24h == true) {
|
|
struct tm * timeinfo = localtime (&_sdconfig_.delay24h_time);
|
|
strftime (status,length,"24h delay: end time %a %I:%M%p",timeinfo);
|
|
return 3;
|
|
} else if (_sdconfig_.calendar == true) {
|
|
sprintf(status,"Calendar schedule");
|
|
return 2;
|
|
} else {
|
|
sprintf(status,"OFF");
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void broadcast_zonestate(struct mg_connection *nc, struct GPIOcfg *gpiopin)
|
|
{
|
|
//logMessage(LOG_DEBUG, "broadcast_gpiopinstate()\n");
|
|
//static int mqtt_count=0;
|
|
struct mg_connection *c;
|
|
|
|
check_net_services(nc->mgr);
|
|
|
|
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
|
|
if (is_websocket(c)) {
|
|
//ws_send(c, data);
|
|
logMessage(LOG_ERR, "Hit part of code that's not complete - broadcast_gpiopinstate() - websocket\n");
|
|
} else if (is_mqtt(c)) {
|
|
publish_zone_mqtt(c, gpiopin);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void broadcast_sprinklerdactivestate(struct mg_connection *nc)
|
|
{
|
|
//static int mqtt_count=0;
|
|
//int i;
|
|
struct mg_connection *c;
|
|
static char mqtt_topic[250];
|
|
static char mqtt_msg[50];
|
|
|
|
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
|
|
if (is_mqtt(c)) {
|
|
if (_sdconfig_.currentZone.type==zcNONE) {
|
|
sprintf(mqtt_topic, "%s/active", _sdconfig_.mqtt_topic);
|
|
send_mqtt_msg(c, mqtt_topic, " ");
|
|
sprintf(mqtt_topic, "%s/cycleallzones/remainingduration", _sdconfig_.mqtt_topic);
|
|
send_mqtt_msg(c, mqtt_topic, "0");
|
|
} else {
|
|
sprintf(mqtt_topic, "%s/active", _sdconfig_.mqtt_topic);
|
|
sprintf(mqtt_msg, "Zone %d", _sdconfig_.currentZone.zone );
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
//}
|
|
//sprintf(mqtt_topic, "%s/remainingduration", _sdconfig_.mqtt_topic);
|
|
//sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft );
|
|
//send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
sprintf(mqtt_topic, "%s/status", _sdconfig_.mqtt_topic);
|
|
sprinklerdstatus(mqtt_msg, 50);
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
// Send info specific to zone
|
|
sprintf(mqtt_topic, "%s/zone%d/remainingduration", _sdconfig_.mqtt_topic, _sdconfig_.currentZone.zone);
|
|
sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft );
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
}
|
|
if (_sdconfig_.currentZone.type == zcALL) {
|
|
int i, total=_sdconfig_.currentZone.timeleft;
|
|
for (i=_sdconfig_.currentZone.zone+1; i <= _sdconfig_.zones; i++) {
|
|
total += (_sdconfig_.zonecfg[i].default_runtime * 60);
|
|
}
|
|
sprintf(mqtt_topic, "%s/cycleallzones/remainingduration", _sdconfig_.mqtt_topic);
|
|
sprintf(mqtt_msg, "%d", total );
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
sprintf(mqtt_topic, "%s/zone0/remainingduration", _sdconfig_.mqtt_topic);
|
|
//sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft );
|
|
sprintf(mqtt_msg, "%d", total );
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
} else if (_sdconfig_.currentZone.type != zcNONE) {
|
|
sprintf(mqtt_topic, "%s/zone0/remainingduration", _sdconfig_.mqtt_topic);
|
|
sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft );
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
}
|
|
|
|
if (_sdconfig_.currentZone.type != zcALL) {
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
clearEventZones;
|
|
}
|
|
|
|
int getTodayString(char *buffer, int size) {
|
|
time_t rawtime;
|
|
struct tm * timeinfo;
|
|
time (&rawtime);
|
|
timeinfo = localtime (&rawtime);
|
|
return strftime (buffer,size,"%a %h %d.",timeinfo);
|
|
}
|
|
|
|
void broadcast_sprinklerdstate(struct mg_connection *nc)
|
|
{
|
|
//static int mqtt_count=0;
|
|
int i;
|
|
struct mg_connection *c;
|
|
static char mqtt_topic[250];
|
|
static char mqtt_msg[50];
|
|
static char last_state_msg[50];
|
|
static int publishedTodayRainChance = -1;
|
|
static float publishedTodayRainTotal = -1;
|
|
|
|
for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) {
|
|
// Start from 0 since we publish master valve (just a temp measure)
|
|
for (i=(_sdconfig_.master_valve?0:1); i <= _sdconfig_.zones ; i++)
|
|
{
|
|
if (is_websocket(c)) {
|
|
//ws_send(c, data);
|
|
logMessage(LOG_ERR, "Hit part of code that's not complete - broadcast_gpiopinstate() - websocket\n");
|
|
} else if (is_mqtt(c)) {
|
|
publish_zone_mqtt(c, &_sdconfig_.zonecfg[i]);
|
|
}
|
|
}
|
|
if (is_mqtt(c)) {
|
|
if (_sdconfig_.enableMQTTaq == true) {
|
|
sprintf(mqtt_topic, "%s/calendar", _sdconfig_.mqtt_topic);
|
|
sprintf(mqtt_msg, "%s", (_sdconfig_.calendar?MQTT_ON:MQTT_OFF) );
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
sprintf(mqtt_topic, "%s/24hdelay", _sdconfig_.mqtt_topic);
|
|
sprintf(mqtt_msg, "%s", (_sdconfig_.delay24h?MQTT_ON:MQTT_OFF) );
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
sprintf(mqtt_topic, "%s/cycleallzones", _sdconfig_.mqtt_topic);
|
|
sprintf(mqtt_msg, "%s", (_sdconfig_.currentZone.type==zcALL?MQTT_ON:MQTT_OFF) );
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
sprintf(mqtt_topic, "%s/status", _sdconfig_.mqtt_topic);
|
|
sprinklerdstatus(mqtt_msg, 50);
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
if (publishedTodayRainChance != _sdconfig_.todayRainChance || isEventRainProbability) {
|
|
sprintf(mqtt_topic, "%s/chanceofrain", _sdconfig_.mqtt_topic);
|
|
sprintf(mqtt_msg, "%d",_sdconfig_.todayRainChance);
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
publishedTodayRainChance = _sdconfig_.todayRainChance;
|
|
|
|
getTodayString(mqtt_msg, 50);
|
|
sprintf(mqtt_topic, "%s/chanceofrain/day", _sdconfig_.mqtt_topic);
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
|
|
clearEventRainProbability;
|
|
}
|
|
if (publishedTodayRainTotal != _sdconfig_.todayRainTotal || isEventRainTotal) {
|
|
sprintf(mqtt_topic, "%s/raintotal", _sdconfig_.mqtt_topic);
|
|
sprintf(mqtt_msg, "%.2f",_sdconfig_.todayRainTotal);
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
publishedTodayRainTotal = _sdconfig_.todayRainTotal;
|
|
|
|
getTodayString(mqtt_msg, 50);
|
|
sprintf(mqtt_topic, "%s/raintotal/day", _sdconfig_.mqtt_topic);
|
|
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
|
|
|
|
clearEventRainTotal;
|
|
}
|
|
}
|
|
if (_sdconfig_.enableMQTTdz == true) {
|
|
if (_sdconfig_.dzidx_calendar > 0 && update_dz_cache(_sdconfig_.dzidx_calendar,(_sdconfig_.calendar==true ? DZ_ON : DZ_OFF) )) {
|
|
build_dz_mqtt_status_JSON(mqtt_msg, 50, _sdconfig_.dzidx_calendar, (_sdconfig_.calendar==true ? DZ_ON : DZ_OFF), TEMP_UNKNOWN);
|
|
send_mqtt_msg(c, _sdconfig_.mqtt_dz_pub_topic, mqtt_msg);
|
|
}
|
|
if (_sdconfig_.dzidx_24hdelay > 0 && update_dz_cache(_sdconfig_.dzidx_24hdelay,(_sdconfig_.delay24h==true ? DZ_ON : DZ_OFF) )) {
|
|
build_dz_mqtt_status_JSON(mqtt_msg, 50, _sdconfig_.dzidx_24hdelay, (_sdconfig_.delay24h==true ? DZ_ON : DZ_OFF), TEMP_UNKNOWN);
|
|
send_mqtt_msg(c, _sdconfig_.mqtt_dz_pub_topic, mqtt_msg);
|
|
}
|
|
if (_sdconfig_.dzidx_allzones > 0 && update_dz_cache(_sdconfig_.dzidx_allzones,(_sdconfig_.currentZone.type==zcALL ? DZ_ON : DZ_OFF) )) {
|
|
build_dz_mqtt_status_JSON(mqtt_msg, 50, _sdconfig_.dzidx_allzones, (_sdconfig_.currentZone.type==zcALL ? DZ_ON : DZ_OFF), TEMP_UNKNOWN);
|
|
send_mqtt_msg(c, _sdconfig_.mqtt_dz_pub_topic, mqtt_msg);
|
|
}
|
|
if (_sdconfig_.dzidx_status > 0) {
|
|
int value =sprinklerdstatus(mqtt_msg, 50);
|
|
if (strcmp(last_state_msg, mqtt_msg) != 0) {
|
|
build_dz_status_message_JSON(mqtt_topic, 250, _sdconfig_.dzidx_status, value, mqtt_msg);
|
|
send_mqtt_msg(c, _sdconfig_.mqtt_dz_pub_topic, mqtt_topic);
|
|
strcpy(last_state_msg, mqtt_msg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
clearEventStatus;
|
|
|
|
return;
|
|
}
|
|
|
|
int is_value_ON(char *buf) {
|
|
if (strncasecmp(buf, "on", 3) == 0 || strncmp(buf, "1", 1) == 0)
|
|
return true;
|
|
else if (strncasecmp(buf, "off", 3) == 0 || strncmp(buf, "0", 1) == 0)
|
|
return false;
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool is_value_flip(char *buf) {
|
|
if (strncasecmp(buf, "flip", 4) == 0 || strncasecmp(buf, "toggle", 6) == 0 )
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
//int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, char *buffer, int size, bool *changedOption) {
|
|
int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, char *buffer, int size) {
|
|
static int buflen = 50;
|
|
char buf[buflen];
|
|
//int action = -1;
|
|
//int pin = -1;
|
|
//int status = -1;
|
|
int length = 0;
|
|
//int i;
|
|
int zone;
|
|
int runtime;
|
|
|
|
memset(&buffer[0], 0, size);
|
|
|
|
|
|
/* Need to action the following
|
|
/?type=firstload // Include cal schedule
|
|
/?type=read // no need to include cal schedule
|
|
|
|
// Cfg options
|
|
/?type=option&option=24hdelay&state=off // turn off 24h delay
|
|
/?type=option&option=calendar&state=off // turn off calendar
|
|
|
|
// Calendar
|
|
/?type=calcfg&day=3&zone=&time=07:00 // Use default water zone times
|
|
/?type=calcfg&day=2&zone=1&time=7 // Change water zone time
|
|
/?type=calcfg&day=3&zone=&time= // Delete day schedule
|
|
|
|
// Run options
|
|
/?type=option&option=allz&state=on // Run all zones default times
|
|
/?type=zone&zone=2&state=on&runtime=3 // Run zone 2 for 3 mins (ignore 24h delay & calendar settings)
|
|
/?type=zrtcfg&zone=2&time=10 // change zone 2 default runtime to 10
|
|
/?type=cron&zone=1&runtime=12' // Run zone 1 for 12 mins (calendar & 24hdelay settings overide this request)
|
|
*/
|
|
mg_get_http_var(&http_msg->query_string, "type", buf, buflen);
|
|
logMessage (LOG_DEBUG, "Request type %s\n",buf);
|
|
|
|
if (strcmp(buf, "json") == 0) {
|
|
length = build_advanced_sprinkler_JSON(buffer, size);
|
|
} else if (strcmp(buf, "homebridge") == 0) {
|
|
length = build_homebridge_sprinkler_JSON(buffer, size);
|
|
} else if (strcmp(buf, "firstload") == 0) {
|
|
logMessage(LOG_DEBUG, "WEB REQUEST Firstload %s\n",buf);
|
|
length = build_sprinkler_cal_JSON(buffer, size);
|
|
} else if (strcmp(buf, "read") == 0) {
|
|
logMessage(LOG_DEBUG, "WEB REQUEST read %s\n",buf);
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
} else if (strcmp(buf, "option") == 0) {
|
|
//logMessage(LOG_DEBUG, "WEB REQUEST option %s\n",buf);
|
|
mg_get_http_var(&http_msg->query_string, "option", buf, buflen);
|
|
if (strncasecmp(buf, "calendar", 6) == 0 ) {
|
|
mg_get_http_var(&http_msg->query_string, "state", buf, buflen);
|
|
logMessage(LOG_NOTICE, "WEB request to turn Calendar %s\n",buf);
|
|
logMessage(LOG_NOTICE, "Request | %.*s\n",http_msg->query_string.len,http_msg->query_string.p);
|
|
enable_calendar(is_value_ON(buf));
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
} else if (strncasecmp(buf, "24hdelay", 8) == 0 ) {
|
|
mg_get_http_var(&http_msg->query_string, "state", buf, buflen);
|
|
int val = is_value_ON(buf);
|
|
if (val == true || val == false) {
|
|
enable_delay24h(val);
|
|
} else if (strncasecmp(buf, "reset", 5) == 0) {
|
|
mg_get_http_var(&http_msg->query_string, "time", buf, buflen);
|
|
reset_delay24h_time(atoi(buf));
|
|
}
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
} else if (strncasecmp(buf, "allz", 4) == 0 ) {
|
|
mg_get_http_var(&http_msg->query_string, "state", buf, buflen);
|
|
zc_zone(zcALL, 0, (is_value_ON(buf)?zcON:zcOFF), 0);
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
} else {
|
|
logMessage(LOG_WARNING, "Bad request unknown option\n");
|
|
length = sprintf(buffer, "{ \"error\": \"Bad request unknown option\" }");
|
|
}
|
|
//*changedOption = true;
|
|
setEventStatus;
|
|
//broadcast_sprinklerdstate(nc);
|
|
} else if (strncasecmp(buf, "config", 6) == 0) {
|
|
mg_get_http_var(&http_msg->query_string, "option", buf, buflen);
|
|
if (strncasecmp(buf, "raindelaychance", 15) == 0 )
|
|
{
|
|
mg_get_http_var(&http_msg->query_string, "value", buf, buflen);
|
|
_sdconfig_.precipChanceDelay = atoi(buf);
|
|
}
|
|
else if (strncasecmp(buf, "raindelaytotal1", 15) == 0)
|
|
{
|
|
mg_get_http_var(&http_msg->query_string, "value", buf, buflen);
|
|
_sdconfig_.precipInchDelay1day = atof(buf);
|
|
}
|
|
else if (strncasecmp(buf, "raindelaytotal2", 15) == 0)
|
|
{
|
|
mg_get_http_var(&http_msg->query_string, "value", buf, buflen);
|
|
_sdconfig_.precipInchDelay2day = atof(buf);
|
|
}
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
} else if (strncasecmp(buf, "sensor", 6) == 0) {
|
|
mg_get_http_var(&http_msg->query_string, "sensor", buf, buflen);
|
|
if (strncasecmp(buf, "chanceofrain", 13) == 0) {
|
|
mg_get_http_var(&http_msg->query_string, "value", buf, buflen);
|
|
logMessage(LOG_NOTICE, "API: Chance of rain %d%%\n",atoi(buf));
|
|
setTodayChanceOfRain(atoi(buf));
|
|
} else if (strncasecmp(buf, "raintotal", 9) == 0) {
|
|
mg_get_http_var(&http_msg->query_string, "value", buf, buflen);
|
|
logMessage(LOG_NOTICE, "API: Rain total %.2f\n",atof(buf));
|
|
setTodayRainTotal(atof(buf));
|
|
}
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
} else if (strcmp(buf, "zone") == 0 || strcmp(buf, "cron") == 0) {
|
|
//logMessage(LOG_DEBUG, "WEB REQUEST zone %s\n",buf);
|
|
zcRunType type = zcSINGLE;
|
|
if (strcmp(buf, "cron") == 0)
|
|
type = zcCRON;
|
|
|
|
mg_get_http_var(&http_msg->query_string, "zone", buf, buflen);
|
|
zone = atoi(buf);
|
|
mg_get_http_var(&http_msg->query_string, "runtime", buf, buflen);
|
|
runtime = atoi(buf);
|
|
mg_get_http_var(&http_msg->query_string, "state", buf, buflen);
|
|
//if ( (strncasecmp(buf, "off", 3) == 0 || strncmp(buf, "0", 1) == 0) && zone <= _sdconfig_.zones) {
|
|
if (is_value_ON(buf) == true && zone <= _sdconfig_.zones)
|
|
{
|
|
logMessage(LOG_NOTICE, "API: Turn zone %d on for %d mins\n",zone,runtime);
|
|
zc_zone(type, zone, zcON, runtime);
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
//} else if ( (strncasecmp(buf, "on", 2) == 0 || strncmp(buf, "1", 1) == 0) && zone <= _sdconfig_.zones) {
|
|
} else if ( is_value_ON(buf) == false && zone <= _sdconfig_.zones) {
|
|
logMessage(LOG_NOTICE, "API: Turn zone %d off\n",zone);
|
|
zc_zone(type, zone, zcOFF, runtime);
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
} else if ( is_value_flip(buf) == true && zone <= _sdconfig_.zones) {
|
|
logMessage(LOG_NOTICE, "API: Turn zone %d %s\n",zone, !zc_state(zone)==zcON?"ON":"OFF");
|
|
zc_zone(type, zone, !zc_state(zone), runtime);
|
|
} else {
|
|
if (zone > _sdconfig_.zones) {
|
|
logMessage(LOG_WARNING, "Bad request unknown zone %d\n",zone);
|
|
length = sprintf(buffer, "{ \"error\": \"Bad request unknown zone %d\"}", zone);
|
|
} else {
|
|
logMessage(LOG_WARNING, "Bad request on zone %d, unknown state %s\n",zone, buf);
|
|
length = sprintf(buffer, "{ \"error\": \"Bad request on zone %d, unknown state %s\"}", zone, buf);
|
|
}
|
|
|
|
setEventZones;
|
|
}
|
|
} else if (strcmp(buf, "zrtcfg") == 0) {
|
|
//logMessage(LOG_DEBUG, "WEB REQUEST cfg %s\n",buf);
|
|
mg_get_http_var(&http_msg->query_string, "zone", buf, buflen);
|
|
zone = atoi(buf);
|
|
mg_get_http_var(&http_msg->query_string, "time", buf, buflen);
|
|
runtime = atoi(buf);
|
|
if (zone > 0 && zone <= _sdconfig_.zones && runtime > -1) {
|
|
_sdconfig_.zonecfg[zone].default_runtime = runtime;
|
|
logMessage(LOG_DEBUG, "changed default runtime on zone %d, to %d\n",zone, runtime);
|
|
length = build_sprinkler_JSON(buffer, size);
|
|
zc_update_runtime(zone);
|
|
//*changedOption = true;
|
|
setEventZones;
|
|
} else
|
|
length += sprintf(buffer, "{ \"error\": \"bad request zone %d runtime %d\"}",zone,runtime);
|
|
} else if (strcmp(buf, "calcfg") == 0) {
|
|
mg_get_http_var(&http_msg->query_string, "day", buf, buflen);
|
|
int day = atoi(buf);
|
|
mg_get_http_var(&http_msg->query_string, "zone", buf, buflen);
|
|
zone = atoi(buf);
|
|
mg_get_http_var(&http_msg->query_string, "time", buf, buflen);
|
|
runtime = atoi(buf);
|
|
if (day >= 0 && day <= 6 && zone > 0 && time > 0) { // zone runtime
|
|
if (zone <= _sdconfig_.zones)
|
|
_sdconfig_.cron[day].zruntimes[zone-1] = runtime;
|
|
else
|
|
length = sprintf(buffer, "{ \"error\": \"bad zone calendar config request\"}");
|
|
} else if (day >= 0 && day <= 6 && strlen(buf) > 0) { // add day to schedule
|
|
_sdconfig_.cron[day].hour = str2int(buf, 2);
|
|
_sdconfig_.cron[day].minute = str2int(&buf[3], 2);;
|
|
} else if (day >= 0 && day <= 6) { // remove day from schedule
|
|
_sdconfig_.cron[day].hour = -1;
|
|
_sdconfig_.cron[day].minute = -1;
|
|
} else {
|
|
length = sprintf(buffer, "{ \"error\": \"bad calendar config request\"}");
|
|
}
|
|
time(&_sdconfig_.cron_update);
|
|
length = build_sprinkler_cal_JSON(buffer, size);
|
|
} else {
|
|
length += sprintf(buffer, "{ \"error\": \"unknown request\"}");
|
|
}
|
|
|
|
buffer[length] = '\0';
|
|
//logMessage (LOG_DEBUG, "Web Return %d = '%.*s'\n",length, length, buffer);
|
|
return strlen(buffer);
|
|
}
|
|
|
|
|
|
#define CT_TEXT "Content-Type: text/plain"
|
|
#define CT_JSON "Content-Type: application/json"
|
|
|
|
void action_web_request(struct mg_connection *nc, struct http_message *http_msg){
|
|
int bufsize = 1024 + (200 * _sdconfig_.zones);
|
|
char buf[bufsize];
|
|
char *c_type;
|
|
int size = 0;
|
|
//bool changedOption = false;
|
|
|
|
logMessage(LOG_DEBUG, "action_web_request %.*s %.*s\n",http_msg->uri.len, http_msg->uri.p, http_msg->query_string.len, http_msg->query_string.p);
|
|
|
|
if (http_msg->query_string.len > 0) {
|
|
//size = serve_web_request(nc, http_msg, buf, sizeof(buf));
|
|
//size = serve_web_request(nc, http_msg, buf, bufsize, &changedOption);
|
|
size = serve_web_request(nc, http_msg, buf, bufsize);
|
|
c_type = CT_JSON;
|
|
|
|
if (size <= 0) {
|
|
size = sprintf(buf, "{ \"error\": \"unknown request\"}");
|
|
}
|
|
|
|
mg_send_head(nc, 200, size, c_type);
|
|
mg_send(nc, buf, size);
|
|
//logMessage (LOG_DEBUG, "Web Return %d = '%.*s'\n",size, size, buf);
|
|
|
|
//if (changedOption)
|
|
// _sdconfig_.eventToUpdateHappened = true;
|
|
|
|
return;
|
|
}
|
|
|
|
struct mg_serve_http_opts opts;
|
|
|
|
memset(&opts, 0, sizeof(opts)); // Reset all options to defaults
|
|
opts.document_root = _sdconfig_.docroot; // Serve files from the current directory
|
|
// logMessage (LOG_DEBUG, "Doc root=%s\n",opts.document_root);
|
|
mg_serve_http(nc, http_msg, opts);
|
|
}
|
|
/*
|
|
void action_websocket_request(struct mg_connection *nc, struct websocket_message *wm){
|
|
logMessage(LOG_INFO, "action_websocket_request\n");
|
|
}
|
|
*/
|
|
|
|
void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg) {
|
|
int idx = -1;
|
|
int nvalue = -1;
|
|
int i;
|
|
char svalue[DZ_SVALUE_LEN];
|
|
|
|
if (parseJSONmqttrequest(msg->payload.p, msg->payload.len, &idx, &nvalue, svalue, "\"svalue2\"")) {
|
|
if ( idx <= 0 || check_dz_cache(idx, nvalue))
|
|
return;
|
|
if (idx == _sdconfig_.dzidx_calendar) {
|
|
//_sdconfig_.system=(nvalue==DZ_ON?true:false);
|
|
logMessage(LOG_NOTICE, "Domoticz: topic %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
|
|
logMessage(LOG_NOTICE, "Domoticz request to turn Calendar %s\n",nvalue==DZ_ON?"On":"Off");
|
|
enable_calendar(nvalue==DZ_ON?true:false);
|
|
//_sdconfig_.eventToUpdateHappened = true;
|
|
logMessage(LOG_INFO, "Domoticz MQTT request to turn %s calendar",(nvalue==DZ_ON?"ON":"OFF"));
|
|
} else if (idx == _sdconfig_.dzidx_24hdelay) {
|
|
enable_delay24h((nvalue==DZ_ON?true:false));
|
|
logMessage(LOG_INFO, "Domoticz MQTT request to turn %s 24hDelay",(nvalue==DZ_ON?"ON":"OFF"));
|
|
} else if (idx == _sdconfig_.dzidx_allzones) {
|
|
zc_zone(zcALL, 0, (nvalue==DZ_ON?zcON:zcOFF), 0);
|
|
logMessage(LOG_INFO, "Domoticz MQTT request to turn %s cycle all zones",(nvalue==DZ_ON?"ON":"OFF"));
|
|
} else if (idx == _sdconfig_.dzidx_rainsensor) {
|
|
logMessage(LOG_INFO, "Domoticz MQTT rain sensor update, total %s",svalue);
|
|
setTodayRainTotal(atof(svalue));
|
|
} else {
|
|
for (i=1; i <= _sdconfig_.zones ; i++)
|
|
{
|
|
if ( _sdconfig_.zonecfg[i].dz_idx == idx ) {
|
|
logMessage(LOG_INFO, "Domoticz MQT id %d matched Zone %d %s\n",idx, _sdconfig_.zonecfg[i].zone, _sdconfig_.zonecfg[i].name);
|
|
if ( nvalue == DZ_ON || nvalue == DZ_OFF) {
|
|
zc_zone(zcSINGLE, _sdconfig_.zonecfg[i].zone, (nvalue==DZ_ON?zcON:zcOFF), 0);
|
|
logMessage(LOG_DEBUG, "Domoticz MQT: Turn zone %d %s\n",_sdconfig_.zonecfg[i].zone, nvalue==DZ_ON?"ON":"OFF");
|
|
} else {
|
|
logMessage(LOG_WARNING, "Domoticz MQT id %d, unknown state to set %d\n",idx,nvalue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
|
|
//logMessage(LOG_INFO, "action_mqtt_message\n");
|
|
int i;
|
|
//char *pt1 = (char *)&msg->topic.p[strlen(_sdconfig_.mqtt_topic)+1];
|
|
char *pt2 = NULL;
|
|
char *pt3 = NULL;
|
|
char *pt4 = NULL;
|
|
|
|
for (i=strlen(_sdconfig_.mqtt_topic); i < msg->topic.len; i++) {
|
|
if ( msg->topic.p[i] == '/' ) {
|
|
if (pt2 == NULL) {
|
|
pt2 = (char *)&msg->topic.p[++i];
|
|
} else if (pt3 == NULL) {
|
|
pt3 = (char *)&msg->topic.p[++i];
|
|
} else if (pt4 == NULL) {
|
|
pt4 = (char *)&msg->topic.p[++i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Need to action the following
|
|
1 = on
|
|
|
|
//sprinkler/zone1/set on
|
|
//sprinkler/zone1/duration/set on
|
|
//sprinkler/zone/all/set on
|
|
//sprinkler/24hdelay/set on
|
|
//sprinkler/system/set on
|
|
|
|
*/
|
|
// All topics are on or off / 1 or 0
|
|
zcState status = zcOFF;
|
|
if ( strncasecmp(msg->payload.p, "on", 2) == 0 || strncmp(msg->payload.p, MQTT_ON, 1) == 0) {
|
|
status = zcON;
|
|
}
|
|
|
|
logMessage(LOG_DEBUG, "MQTT: topic %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
|
|
|
|
//logMessage(LOG_DEBUG, "MQTT: pt2 %s\n", pt2);
|
|
|
|
//logMessage(LOG_DEBUG, "MQTT: pt2 %.*s == %s %c\n", 4, pt2, strncmp(pt2, "zone", 4) == 0?"YES":"NO", pt2[4]);
|
|
/*
|
|
if (pt2 != NULL && pt3 != NULL && pt4 != NULL && strncmp(pt2, "zone", 4) == 0 && strncmp(pt4, "set", 3) == 0 ) {
|
|
int zone = atoi(pt3);
|
|
if (zone > 0 && zone <= _sdconfig_.zones) {
|
|
zc_zone(zcSINGLE, zone, status, 0);
|
|
logMessage(LOG_DEBUG, "MQTT: Turn zone %d %s\n",zone, status==zcON?"ON":"OFF");
|
|
} else {
|
|
logMessage(LOG_WARNING, "MQTT: unknown zone %d\n",zone);
|
|
}
|
|
} else*/
|
|
//setTodayRainTotal(atof(svalue));
|
|
|
|
if (pt2 != NULL && pt3 != NULL && pt4 != NULL && strncmp(pt2, "zone", 4) == 0 && strncmp(pt3, "duration", 8) == 0 && strncmp(pt4, "set", 3) == 0 ) {
|
|
int zone = atoi(&pt2[4]);
|
|
if (zone > 0 && zone <= _sdconfig_.zones) {
|
|
int v = str2int(msg->payload.p, msg->payload.len);
|
|
_sdconfig_.zonecfg[zone].default_runtime = v / 60;
|
|
//_sdconfig_.eventToUpdateHappened = true;
|
|
//setEventZones;
|
|
zc_update_runtime(zone);
|
|
logMessage(LOG_DEBUG, "MQTT: Default runtime zone %d is %d\n",zone,_sdconfig_.zonecfg[zone].default_runtime);
|
|
} else {
|
|
logMessage(LOG_DEBUG, "MQTT: BAD Default runtime zone %d is %d\n",zone,_sdconfig_.zonecfg[zone].default_runtime);
|
|
}
|
|
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "24hdelay", 8) == 0 && strncmp(pt3, "set", 3) == 0 ) {
|
|
enable_delay24h(status==zcON?true:false);
|
|
logMessage(LOG_NOTICE, "MQTT: Enable 24 hour delay %s\n",status==zcON?"YES":"NO");
|
|
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "calendar", 6) == 0 && strncmp(pt3, "set", 3) == 0 ) {
|
|
//_sdconfig_.system=status==zcON?true:false;
|
|
logMessage(LOG_DEBUG, "MQTT request to turn Calendar %s\n",status==zcON?"On":"Off");
|
|
enable_calendar(status==zcON?true:false);
|
|
logMessage(LOG_NOTICE, "MQTT: Turning calendar %s\n",status==zcON?"ON":"OFF");
|
|
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "cycleallzones", 13) == 0 && strncmp(pt3, "set", 3) == 0 ) {
|
|
zc_zone(zcALL, 0, status, 0);
|
|
logMessage(LOG_NOTICE, "MQTT: Cycle all zones %s\n",status==zcON?"ON":"OFF");
|
|
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "raintotal", 9) == 0 && strncmp(pt3, "set", 3) == 0 ) {
|
|
float v = str2float(msg->payload.p, msg->payload.len);
|
|
logMessage(LOG_NOTICE, "MQTT: Rain total %.2f\n",v);
|
|
setTodayRainTotal(v);
|
|
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "chanceofrain", 12) == 0 && strncmp(pt3, "set", 3) == 0 ) {
|
|
int v = str2int(msg->payload.p, msg->payload.len);
|
|
logMessage(LOG_NOTICE, "MQTT: Chance of rain %d%%\n",v);
|
|
setTodayChanceOfRain(v);
|
|
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "zone", 4) == 0 && strncmp(pt3, "set", 3) == 0 ) {
|
|
int zone = atoi(&pt2[4]);
|
|
if (zone > 0 && zone <= _sdconfig_.zones) {
|
|
logMessage(LOG_NOTICE, "MQTT: Turn zone %d %s\n",zone, status==zcON?"ON":"OFF");
|
|
zc_zone(zcSINGLE, zone, status, 0);
|
|
} else if (zone == 0 && status == zcOFF && _sdconfig_.currentZone.type != zcNONE) {
|
|
// request to turn off master will turn off any running zone
|
|
logMessage(LOG_DEBUG, "MQTT: Request master valve off, turned zone %d off\n",_sdconfig_.currentZone.zone);
|
|
zc_zone(zcSINGLE, _sdconfig_.currentZone.zone , zcOFF, 0);
|
|
} else if (zone == 0 && status == zcON) {
|
|
// Can't turn on master valve, just re-send current stats.
|
|
//_sdconfig_.eventToUpdateHappened = true;
|
|
setEventZones;
|
|
setEventStatus;
|
|
} else {
|
|
logMessage(LOG_WARNING, "MQTT: unknown zone %d\n",zone);
|
|
}
|
|
} else {
|
|
// No set. nothing for us to do.
|
|
logMessage(LOG_DEBUG, "MQTT: Unknown topic %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void ev_handler(struct mg_connection *nc, int ev, void *p) {
|
|
struct mg_mqtt_message *mqtt_msg;
|
|
struct http_message *http_msg;
|
|
static bool hapublished = false;
|
|
char aq_topic[30];
|
|
//struct websocket_message *ws_msg;
|
|
//static double last_control_time;
|
|
|
|
// struct mg_mqtt_message *msg = (struct mg_mqtt_message *)p;
|
|
(void)nc;
|
|
|
|
// if (ev != MG_EV_POLL) logMessage(LOG_DEBUG, "MQTT handler got event %d\n", ev);
|
|
switch (ev) {
|
|
case MG_EV_CONNECT: {
|
|
set_mqtt(nc);
|
|
//if (_sdconfig_.mqtt_topic != NULL || _sdconfig_.mqtt_dz_sub_topic != NULL) {
|
|
struct mg_send_mqtt_handshake_opts opts;
|
|
memset(&opts, 0, sizeof(opts));
|
|
opts.user_name = _sdconfig_.mqtt_user;
|
|
opts.password = _sdconfig_.mqtt_passwd;
|
|
opts.keep_alive = 5;
|
|
// opts.flags = 0x00;
|
|
// opts.flags |= MG_MQTT_WILL_RETAIN;
|
|
opts.flags |= MG_MQTT_CLEAN_SESSION; // NFS Need to readup on this
|
|
|
|
sprintf(aq_topic, "%s/%s", _sdconfig_.mqtt_topic,MQTT_LWM_TOPIC);
|
|
opts.will_topic = aq_topic;
|
|
opts.will_message = MQTT_OFF;
|
|
|
|
mg_set_protocol_mqtt(nc);
|
|
mg_send_mqtt_handshake_opt(nc, _sdconfig_.mqtt_ID, opts);
|
|
logMessage(LOG_INFO, "Connected to mqtt %s with id of: %s\n", _sdconfig_.mqtt_address, _sdconfig_.mqtt_ID);
|
|
_mqtt_status = mqttrunning;
|
|
_mqtt_connection = nc;
|
|
//}
|
|
//last_control_time = mg_time();
|
|
} break;
|
|
|
|
case MG_EV_MQTT_CONNACK:
|
|
mqtt_msg = (struct mg_mqtt_message *)p;
|
|
if (mqtt_msg->connack_ret_code != MG_EV_MQTT_CONNACK_ACCEPTED) {
|
|
logMessage(LOG_WARNING, "Got mqtt connection error: %d\n", mqtt_msg->connack_ret_code);
|
|
_mqtt_status = mqttstopped;
|
|
_mqtt_connection = NULL;
|
|
break;
|
|
}
|
|
time(&_mqtt_connected_time);
|
|
char gp_topic[30];
|
|
struct mg_mqtt_topic_expression topics[2];
|
|
int qos = 0; // can't be bothered with ack, so set to 0
|
|
snprintf(gp_topic, 29, "%s/#", _sdconfig_.mqtt_topic);
|
|
if (_sdconfig_.enableMQTTaq == true && _sdconfig_.enableMQTTdz == true) {
|
|
topics[0].topic = gp_topic;
|
|
topics[0].qos = qos;
|
|
topics[1].topic = _sdconfig_.mqtt_dz_sub_topic;
|
|
topics[1].qos = qos;
|
|
mg_mqtt_subscribe(nc, topics, 2, 42);
|
|
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", gp_topic);
|
|
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", _sdconfig_.mqtt_dz_sub_topic);
|
|
} else if (_sdconfig_.enableMQTTaq == true) {
|
|
topics[0].topic = gp_topic;
|
|
topics[0].qos = qos;
|
|
mg_mqtt_subscribe(nc, topics, 1, 42);
|
|
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", gp_topic);
|
|
} else if (_sdconfig_.enableMQTTdz == true) {
|
|
topics[0].topic = _sdconfig_.mqtt_dz_sub_topic;
|
|
topics[0].qos = qos;
|
|
mg_mqtt_subscribe(nc, topics, 1, 42);
|
|
logMessage(LOG_INFO, "MQTT: Subscribing to '%s'\n", _sdconfig_.mqtt_dz_sub_topic);
|
|
}
|
|
|
|
if (_sdconfig_.enableMQTTha && hapublished == false) {
|
|
logMessage (LOG_DEBUG, "MQTT: Publishing to Home Assistant\n");
|
|
publish_mqtt_hassio_discover(nc);
|
|
hapublished = true;
|
|
}
|
|
|
|
broadcast_sprinklerdstate(nc);
|
|
break;
|
|
|
|
case MG_EV_MQTT_PUBACK:
|
|
mqtt_msg = (struct mg_mqtt_message *)p;
|
|
logMessage(LOG_DEBUG, "MQTT: Message publishing acknowledged (msg_id: %d)\n", mqtt_msg->message_id);
|
|
break;
|
|
|
|
case MG_EV_MQTT_SUBACK:
|
|
logMessage(LOG_DEBUG, "MQTT: Subscription(s) acknowledged\n");
|
|
sprintf(aq_topic, "%s/%s", _sdconfig_.mqtt_topic,MQTT_LWM_TOPIC);
|
|
send_mqtt_msg(nc, aq_topic ,MQTT_ON);
|
|
break;
|
|
|
|
case MG_EV_WEBSOCKET_HANDSHAKE_DONE:
|
|
// nc->user_data = WS;
|
|
logMessage(LOG_DEBUG, "++ Websocket joined\n");
|
|
break;
|
|
|
|
case MG_EV_CLOSE:
|
|
if (is_websocket(nc)) {
|
|
logMessage(LOG_DEBUG, "-- Websocket left\n");
|
|
} else if (is_mqtt(nc)) {
|
|
logMessage(LOG_WARNING, "MQTT Connection closed\n");
|
|
_mqtt_status = mqttstopped;
|
|
_mqtt_connection = NULL;
|
|
// start_mqtt(nc->mgr);
|
|
}
|
|
break;
|
|
|
|
case MG_EV_HTTP_REQUEST:
|
|
http_msg = (struct http_message *)p;
|
|
action_web_request(nc, http_msg);
|
|
break;
|
|
/*
|
|
case MG_EV_WEBSOCKET_FRAME:
|
|
ws_msg = (struct websocket_message *)p;
|
|
action_websocket_request(nc, ws_msg);
|
|
break;
|
|
*/
|
|
case MG_EV_MQTT_PUBLISH:
|
|
mqtt_msg = (struct mg_mqtt_message *)p;
|
|
|
|
// logMessage(LOG_DEBUG, "MQTT: (msg_id: %d) topic %.*s\n",mqtt_msg->message_id, mqtt_msg->topic.len, mqtt_msg->topic.p);
|
|
{ // BS since mongoose doesn;t seem to adhear to CLEAN_SESSION. Simply ignore messages for the first session.
|
|
time_t now;
|
|
time(&now);
|
|
// logMessage(LOG_DEBUG, "MQTT: time diff = %ld\n", now - _mqtt_connected_time);
|
|
if ((now - _mqtt_connected_time) < 1) {
|
|
logMessage(LOG_DEBUG, "MQTT: received (msg_id: %d), looks like cached message, ignoring\n", mqtt_msg->message_id);
|
|
break;
|
|
}
|
|
}
|
|
if (mqtt_msg->message_id != 0) {
|
|
logMessage(LOG_DEBUG, "MQTT: received (msg_id: %d), looks like my own message, ignoring\n", mqtt_msg->message_id);
|
|
break;
|
|
}
|
|
// action_mqtt_message(nc, mqtt_msg);
|
|
if (_sdconfig_.enableMQTTaq && strncmp(mqtt_msg->topic.p, _sdconfig_.mqtt_topic, strlen(_sdconfig_.mqtt_topic)) == 0) {
|
|
action_mqtt_message(nc, mqtt_msg);
|
|
}
|
|
if (_sdconfig_.enableMQTTdz && strncmp(mqtt_msg->topic.p, _sdconfig_.mqtt_dz_sub_topic, strlen(_sdconfig_.mqtt_dz_sub_topic)) == 0) {
|
|
action_domoticz_mqtt_message(nc, mqtt_msg);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool check_net_services(struct mg_mgr *mgr) {
|
|
|
|
if (_mqtt_status == mqttstopped)
|
|
logMessage (LOG_NOTICE, "MQTT client stopped\n");
|
|
|
|
if (_mqtt_status == mqttstopped && _mqtt_status != mqttdisabled)
|
|
{
|
|
start_mqtt(mgr);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void start_mqtt(struct mg_mgr *mgr) {
|
|
|
|
if (_sdconfig_.enableMQTTaq == false) {
|
|
//if( _sdconfig_.enableMQTTaq == false && _sdconfig_.enableMQTTdz == false ) {
|
|
logMessage (LOG_NOTICE, "MQTT client is disabled, not stating\n");
|
|
_mqtt_status = mqttdisabled;
|
|
return;
|
|
}
|
|
|
|
//generate_mqtt_id(_sdconfig_.mqtt_ID, sizeof(_sdconfig_.mqtt_ID)-1);
|
|
if (strlen(_sdconfig_.mqtt_ID) < 1) {
|
|
//logMessage (LOG_DEBUG, "MQTTaq %d | MQTTdz %d\n", _sdconfig_.enableMQTTaq, _sdconfig_.enableMQTTdz);
|
|
generate_mqtt_id(_sdconfig_.mqtt_ID, MQTT_ID_LEN-1);
|
|
logMessage (LOG_DEBUG, "MQTTaq %d | MQTTdz %d | MQTTha %d\n", _sdconfig_.enableMQTTaq, _sdconfig_.enableMQTTdz, _sdconfig_.enableMQTTha);
|
|
}
|
|
|
|
logMessage (LOG_NOTICE, "Starting MQTT client to %s\n", _sdconfig_.mqtt_address);
|
|
if (mg_connect(mgr, _sdconfig_.mqtt_address, ev_handler) == NULL) {
|
|
logMessage (LOG_ERR, "Failed to create MQTT listener to %s\n", _sdconfig_.mqtt_address);
|
|
} else {
|
|
/* NSF NEED TO PASS GPIO STATE HERE
|
|
int i;
|
|
for (i=0; i < TOTAL_BUTTONS; i++) {
|
|
_last_mqtt_aqualinkdata.aqualinkleds[i].state = LED_S_UNKNOWN;
|
|
}
|
|
*/
|
|
_mqtt_status = mqttstarting;
|
|
}
|
|
}
|
|
|
|
bool start_net_services(struct mg_mgr *mgr) {
|
|
//static struct mg_serve_http_opts s_http_server_opts;
|
|
struct mg_connection *nc;
|
|
|
|
mg_mgr_init(mgr, NULL);
|
|
logMessage (LOG_NOTICE, "Starting web server on port %s\n", _sdconfig_.socket_port);
|
|
nc = mg_bind(mgr, _sdconfig_.socket_port, ev_handler);
|
|
if (nc == NULL) {
|
|
logMessage (LOG_ERR, "Failed to create listener\n");
|
|
return false;
|
|
}
|
|
|
|
// Set up HTTP server parameters
|
|
mg_set_protocol_http_websocket(nc);
|
|
|
|
// Start MQTT
|
|
start_mqtt(mgr);
|
|
|
|
|
|
|
|
return true;
|
|
}
|