diff --git a/Makefile b/Makefile index 401f5e1..74547aa 100755 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ CFLAGS = $(GCCFLAGS) -I. -I./minIni $(DBG) $(LIBS) -D MG_DISABLE_MD5 -D MG_DISAB # define the C source files -SRCS = sprinkler.c utils.c config.c net_services.c json_messages.c zone_ctrl.c sd_cron.c mongoose.c minIni/minIni.c $(sd_GPIO_C) +SRCS = sprinkler.c utils.c config.c net_services.c json_messages.c zone_ctrl.c sd_cron.c hassio.c mongoose.c minIni/minIni.c $(sd_GPIO_C) # define the C object files # diff --git a/README.md b/README.md index 68f75b3..d1330c8 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,16 @@ Specifically, make sure you configure your MQTT, Pool Equiptment Labels & Domoti ## Included scripts in extras directory. +[sprinklerRainProbability.sh](https://github.com/sfeakes/sprinklerd/blob/master/extras/sprinklerRainProbability.sh) + +Script to check the chance of rain from forecast OpenWeather, WeaterBit, Climacell, WeatherAPI, if it's greater than a configured percentage then enable the 24h rainDelay on SprinklerD. +Simply edit the scrips with your values, and use cron to run it 30mins before your sprinkelrs are due to turn on each day. If the chance of rain is over your configured % it will enable SprinklerD's 24h rain delay, which will stop the sprinklers running that day, and the 24h delay will timeout before the sprinklers are due to run the next day. (or be enabeled again if the chance of rain is high). +You will need to edit this script for your API keys. + +Example cron entry +`0 5 * * * ~/bin/sprinklerRainProbability.sh weatherapi` + + # Configuration with home automation hubs diff --git a/config.c b/config.c index 9fb0839..7e7b355 100644 --- a/config.c +++ b/config.c @@ -232,22 +232,34 @@ void readCfg(char *inifile) ini_gets("SPRINKLERD", "MQTT_ADDRESS", NULL, _sdconfig_.mqtt_address, sizearray(_sdconfig_.mqtt_address), inifile); ini_gets("SPRINKLERD", "MQTT_USER", NULL, _sdconfig_.mqtt_user, sizearray(_sdconfig_.mqtt_user), inifile); ini_gets("SPRINKLERD", "MQTT_PASSWD", NULL, _sdconfig_.mqtt_passwd, sizearray(_sdconfig_.mqtt_passwd), inifile); - + if ( ini_gets("SPRINKLERD", "MQT_TOPIC", NULL, _sdconfig_.mqtt_topic, sizearray(_sdconfig_.mqtt_topic), inifile) > 0 ) _sdconfig_.enableMQTTaq = true; else _sdconfig_.enableMQTTaq = false; + //if ( ini_gets("SPRINKLERD", "MQTT_HA_DIS_TOPIC", NULL, _sdconfig_.mqtt_ha_dis_topic, sizearray(_sdconfig_.mqtt_ha_dis_topic), inifile) > 0 ) if ( ini_gets("SPRINKLERD", "MQTT_DZ_PUB_TOPIC", NULL, _sdconfig_.mqtt_dz_pub_topic, sizearray(_sdconfig_.mqtt_dz_pub_topic), inifile) > 0 && ini_gets("SPRINKLERD", "MQTT_DZ_SUB_TOPIC", NULL, _sdconfig_.mqtt_dz_sub_topic, sizearray(_sdconfig_.mqtt_dz_sub_topic), inifile) > 0) _sdconfig_.enableMQTTdz = true; else _sdconfig_.enableMQTTdz = false; - if (_sdconfig_.enableMQTTdz == true || _sdconfig_.enableMQTTaq == true) { + if ( ini_gets("SPRINKLERD", "MQTT_HA_DIS_TOPIC", NULL, _sdconfig_.mqtt_ha_dis_topic, sizearray(_sdconfig_.mqtt_ha_dis_topic), inifile) > 0 ) + _sdconfig_.enableMQTTha = true; + else + _sdconfig_.enableMQTTha = false; + + + if (_sdconfig_.enableMQTTaq == true ) { logMessage (LOG_DEBUG,"Config mqtt_topic '%s'\n",_sdconfig_.mqtt_topic); - logMessage (LOG_DEBUG,"Config mqtt_dz_pub_topic '%s'\n",_sdconfig_.mqtt_dz_pub_topic); - logMessage (LOG_DEBUG,"Config mqtt_dz_sub_topic '%s'\n",_sdconfig_.mqtt_dz_sub_topic); + if (_sdconfig_.enableMQTTdz == true) { + logMessage (LOG_DEBUG,"Config mqtt_dz_pub_topic '%s'\n",_sdconfig_.mqtt_dz_pub_topic); + logMessage (LOG_DEBUG,"Config mqtt_dz_sub_topic '%s'\n",_sdconfig_.mqtt_dz_sub_topic); + } + if (_sdconfig_.enableMQTTha == true) { + logMessage (LOG_DEBUG,"Config mqtt_ha_dis_topic '%s'\n",_sdconfig_.mqtt_ha_dis_topic); + } } else { logMessage (LOG_DEBUG,"Config mqtt 'disabeled'\n"); } diff --git a/config.h b/config.h index 74f01e9..bd3cb95 100644 --- a/config.h +++ b/config.h @@ -61,12 +61,13 @@ struct sprinklerdcfg { char socket_port[6]; char name[20]; char docroot[512]; - char mqtt_address[20]; + char mqtt_address[128]; char mqtt_user[50]; char mqtt_passwd[50]; char mqtt_topic[50]; - char mqtt_dz_sub_topic[50]; - char mqtt_dz_pub_topic[50]; + char mqtt_dz_sub_topic[128]; + char mqtt_dz_pub_topic[128]; + char mqtt_ha_dis_topic[128]; char mqtt_ID[MQTT_ID_LEN]; int dzidx_calendar; int dzidx_24hdelay; @@ -75,6 +76,7 @@ struct sprinklerdcfg { int dzidx_rainsensor; bool enableMQTTdz; bool enableMQTTaq; + bool enableMQTTha; int zones; int inputs; //int pincfgs; diff --git a/extras/sprinklerRainProbability.sh b/extras/sprinklerRainProbability.sh new file mode 100755 index 0000000..11bbe7e --- /dev/null +++ b/extras/sprinklerRainProbability.sh @@ -0,0 +1,138 @@ +#!/bin/bash +# +# you MUST change at least one of the following API keys, and the lat lng variables. +# openweatherAPI, weatherAPIkey, weatherbitAPIkey, climacellAPIkey +# lat = your latitude +# lon = your longitude +# probabilityOver = Enable rain delay if probability of rain today is grater than this number. +# Range is 0 to 100, so 50 is 50% +# sprinklerdEnableDelay = the URL to SprinklerD +# +# The below are NOT valid, you MUST change them to your information. + +# API Keys from the following are supported +# openweathermap.org weatherapi.com weatherbit.io climacell.co + +openweatherAPIkey='-----' +weatherbitAPIkey='-----' +climacellAPIkey='-----' +weatherAPIkey='-----' + +lat='42.3601' +lon='-71.0589' + +# 101 means don't set rain delay from this script, use the SprinklerD config (webUI) to decide if to set delay +probabilityOver=101 + +# If you are not running this from the same host as SprinklerD, then change localhost in the below. +sprinklerdHost="http://localhost:80" + + + +######################################################################################################################## +# +# Should not need to edit below this line. +# +######################################################################################################################## + + +sprinklerdEnableDelay="$sprinklerdHost/?type=option&option=24hdelay&state=reset" +sprinklerdProbability="$sprinklerdHost/?type=sensor&sensor=chanceofrain&value=" + +openweatherURL="https://api.openweathermap.org/data/2.5/onecall?lat=$lat&lon=$lon&appid=$openweatherAPIkey&exclude=current,minutely,hourly,alerts" +weatherbitURL="https://api.weatherbit.io/v2.0/forecast/daily?key=$weatherbitAPIkey&lat=$lat&lon=$lon" +climacellURL="https://data.climacell.co/v4/timelines?location=$lat%2C$lon&fields=precipitationProbability×teps=1d&units=metric&apikey=$climacellAPIkey" +weatherAPIlURL="http://api.weatherapi.com/v1/forecast.json?key=$weatherAPIkey&q=$lat,$lon&days=1&aqi=no&alerts=no" + +true=0 +false=1 + +echoerr() { printf "%s\n" "$*" >&2; } +echomsg() { if [ -t 1 ]; then echo "$@" 1>&2; fi; } + +function getURL() { + url=$1 + jq=$2 + factor=$3 + + JSON=$(curl -s "$url") + + if [ $? -ne 0 ]; then + echoerr "Error reading URL, '$1' please check!" + echoerr "Maybe you didn't configure your API and location?" + echo 0; + return $false + else + probability=$(echo $JSON | jq "$jq" ) + fi + + probability=$(echo "$probability * $factor / 1" | bc ) + echo $probability + return $true +} + +# Test we have everything installed +command -v curl >/dev/null 2>&1 || { echoerr "curl is not installed. Aborting!"; exit 1; } +command -v jq >/dev/null 2>&1 || { echoerr "jq is not installed. Aborting!"; exit 1; } +command -v bc >/dev/null 2>&1 || { echoerr "bc not installed. Aborting!"; exit 1; } + +pop=-1 + +if [ "$#" -lt 1 ]; then + echomsg "Pass at least one command line parameter (openweather, weatherbit, climacell, weatherapi)" + exit 1; +fi + +for var in "$@" +do + case "$var" in + openweather) + if [ "$openweatherAPIkey" == "-----" ]; then echomsg "missing OpenWeather API key" && continue; fi + if probability=$(getURL "$openweatherURL" '.["daily"][0].pop' "100"); then + echomsg "OpenWeather probability of rain today is $probability%" + pop=$(echo "if($probability>$pop)print $probability else print $pop" | bc -l) + fi + ;; + weatherbit) + if [ "$weatherbitAPIkey" == "-----" ]; then echomsg "missing WeatherBit API key" && continue; fi + if probability=$(getURL "$weatherbitURL" '.data[0].pop' "1"); then + echomsg "WeatherBit probability of rain today is $probability%" + pop=$(echo "if($probability>$pop)print $probability else print $pop" | bc -l) + fi + ;; + climacell) + if [ "$climacellAPIkey" == "-----" ]; then echomsg "missing ClimaCell API key" && continue; fi + if probability=$(getURL "$climacellURL" '.data.timelines[0].intervals[0].values.precipitationProbability' "1"); then + echomsg "ClimaCell probability of rain today is $probability%" + pop=$(echo "if($probability>$pop)print $probability else print $pop" | bc -l) + fi + ;; + weatherapi) + if [ "$weatherAPIkey" == "-----" ]; then echomsg "missing WeatherAPI API key" && continue; fi + if probability=$(getURL "$weatherAPIlURL" '.forecast.forecastday[0].day.daily_chance_of_rain' "1"); then + echomsg "WeatherAPI probability of rain today is $probability%" + pop=$(echo "if($probability>$pop)print $probability else print $pop" | bc -l) + fi + ;; + esac +done + +# Remove all new line, carriage return, tab characters +# from the string, to allow integer comparison +pop="${pop//[$'\t\r\n ']}" + +if [ "$pop" -lt 0 ]; then + echoerr "Error reading Probability, please check!" + exit 1 +fi + +echomsg "Chance of rain $pop%" + +curl -s "$sprinklerdProbability$pop" > /dev/null + +if (( $(echo "$pop > $probabilityOver" | bc -l) )); then + echomsg "Enabeling rain delay" + curl -s "$sprinklerdEnableDelay" > /dev/null +fi + +exit 0 diff --git a/hassio.c b/hassio.c new file mode 100644 index 0000000..644d5e8 --- /dev/null +++ b/hassio.c @@ -0,0 +1,152 @@ + + +#include +#include +#include + + +#include "mongoose.h" +#include "config.h" +#include "net_services.h" +#include "version.h" + +#define HASS_DEVICE "\"identifiers\": " \ + "[\"SprinklerD\"]," \ + " \"sw_version\": \"" SD_VERSION "\"," \ + " \"model\": \"Sprinkler Daemon\"," \ + " \"name\": \"SprinklerD\"," \ + " \"manufacturer\": \"SprinklerD\"," \ + " \"suggested_area\": \"pool\"" + +#define HASS_AVAILABILITY "\"payload_available\" : \"1\"," \ + "\"payload_not_available\" : \"0\"," \ + "\"topic\": \"%s/" MQTT_LWM_TOPIC "\"" + +const char *HASSIO_TEXT_SENSOR_DISCOVER = "{" + "\"device\": {" HASS_DEVICE "}," + "\"availability\": {" HASS_AVAILABILITY "}," + "\"type\": \"sensor\"," + "\"unique_id\": \"%s\"," + "\"name\": \"%s\"," + "\"state_topic\": \"%s/%s\"," + "\"icon\": \"mdi:card-text\"" +"}"; + +const char *HASSIO_SWITCH_DISCOVER = "{" + "\"device\": {" HASS_DEVICE "}," + "\"availability\": {" HASS_AVAILABILITY "}," + "\"type\": \"switch\"," + "\"unique_id\": \"%s\"," + "\"name\": \"%s\"," + "\"state_topic\": \"%s/%s\"," + "\"command_topic\": \"%s/%s/set\"," + "\"payload_on\": \"1\"," + "\"payload_off\": \"0\"," + "\"qos\": 1," + "\"retain\": false" +"}"; + +const char *HASSIO_VALVE_DISCOVER = "{" + "\"device\": {" HASS_DEVICE "}," + "\"availability\": {" HASS_AVAILABILITY "}," + "\"type\": \"valve\"," + "\"device_class\": \"water\"," + "\"unique_id\": \"%s\"," // sprinklerd_zone_1 + "\"name\": \"Zone %d (%s)\"," // 1 island + "\"state_topic\": \"%s/zone%d\"," // 1 + "\"command_topic\": \"%s/zone%d/set\"," // 1 + "\"value_template\": \"{%% set values = { '0':'closed', '1':'open'} %%}{{ values[value] if value in values.keys() else 'closed' }}\"," + "\"payload_open\": \"1\"," + "\"payload_close\": \"0\"," + "\"qos\": 1," + "\"retain\": false" +"}"; + +void publish_mqtt_hassio_discover(struct mg_connection *nc) +{ + char msg[2048]; + char topic[256]; + char id[128]; + int i; + + + sprintf(id,"sprinklerd_status"); + sprintf(topic, "%s/sensor/sprinklerd/%s/config", _sdconfig_.mqtt_ha_dis_topic, id); + sprintf(msg, HASSIO_TEXT_SENSOR_DISCOVER, + _sdconfig_.mqtt_topic, + id, + "Status", + _sdconfig_.mqtt_topic, "status" ); + send_mqtt_msg(nc, topic, msg); + + sprintf(id,"sprinklerd_active_zone"); + sprintf(topic, "%s/sensor/sprinklerd/%s/config", _sdconfig_.mqtt_ha_dis_topic, id); + sprintf(msg, HASSIO_TEXT_SENSOR_DISCOVER, + _sdconfig_.mqtt_topic, + id, + "Active Zone", + _sdconfig_.mqtt_topic, "active" ); + send_mqtt_msg(nc, topic, msg); + + + + sprintf(id,"sprinklerd_calendar"); + sprintf(topic, "%s/switch/sprinklerd/%s/config", _sdconfig_.mqtt_ha_dis_topic, id); + sprintf(msg, HASSIO_SWITCH_DISCOVER, + _sdconfig_.mqtt_topic, + id, + "Calendar Schedule", + _sdconfig_.mqtt_topic, "calendar", + _sdconfig_.mqtt_topic, "calendar" ); + send_mqtt_msg(nc, topic, msg); + + sprintf(id,"sprinklerd_24hdelay"); + sprintf(topic, "%s/switch/sprinklerd/%s/config", _sdconfig_.mqtt_ha_dis_topic, id); + sprintf(msg, HASSIO_SWITCH_DISCOVER, + _sdconfig_.mqtt_topic, + id, + "24 Hour rain delay", + _sdconfig_.mqtt_topic, "24hdelay", + _sdconfig_.mqtt_topic, "24hdelay" ); + send_mqtt_msg(nc, topic, msg); + + sprintf(id,"sprinklerd_cycleallzones"); + sprintf(topic, "%s/switch/sprinklerd/%s/config", _sdconfig_.mqtt_ha_dis_topic, id); + sprintf(msg, HASSIO_SWITCH_DISCOVER, + _sdconfig_.mqtt_topic, + id, + "Cycle All Zones", + _sdconfig_.mqtt_topic, "cycleallzones", + _sdconfig_.mqtt_topic, "cycleallzones" ); + send_mqtt_msg(nc, topic, msg); + + + + + //for (i=(_sdconfig_.master_valve?0:1); i <= _sdconfig_.zones ; i++) + // Don't publish zome0/master valve to ha + for (i=1; i <= _sdconfig_.zones ; i++) + { + sprintf(id,"sprinklerd_zone_%d", _sdconfig_.zonecfg[i].zone); + sprintf(topic, "%s/valve/sprinklerd/%s/config", _sdconfig_.mqtt_ha_dis_topic, id); + sprintf(msg, HASSIO_VALVE_DISCOVER, + _sdconfig_.mqtt_topic, + id, + _sdconfig_.zonecfg[i].zone, + _sdconfig_.zonecfg[i].name, + _sdconfig_.mqtt_topic,_sdconfig_.zonecfg[i].zone, + _sdconfig_.mqtt_topic,_sdconfig_.zonecfg[i].zone + ); + + send_mqtt_msg(nc, topic, msg); +/* + length += sprintf(buffer+length, "{\"type\" : \"zone\", \"zone\": %d, \"name\": \"%s\", \"state\": \"%s\", \"duration\": %d, \"id\" : \"zone%d\" },", + _sdconfig_.zonecfg[i].zone, + _sdconfig_.zonecfg[i].name, + (digitalRead(_sdconfig_.zonecfg[i].pin)==_sdconfig_.zonecfg[i].on_state?"on":"off"), + _sdconfig_.zonecfg[i].default_runtime * 60, + _sdconfig_.zonecfg[i].zone); + */ + } + +} \ No newline at end of file diff --git a/hassio.h b/hassio.h new file mode 100644 index 0000000..edc0e61 --- /dev/null +++ b/hassio.h @@ -0,0 +1,6 @@ +#ifndef HASSIO_H_ +#define HASSIO_H_ + +void publish_mqtt_hassio_discover(struct mg_connection *nc); + +#endif \ No newline at end of file diff --git a/net_services.c b/net_services.c index a6858d1..89b8844 100644 --- a/net_services.c +++ b/net_services.c @@ -19,6 +19,7 @@ #include "json_messages.h" #include "zone_ctrl.h" #include "sd_cron.h" +#include "hassio.h" #define EVENT_SIZE ( sizeof (struct inotify_event) ) @@ -207,7 +208,7 @@ void publish_zone_mqtt(struct mg_connection *nc, struct GPIOcfg *gpiopin) { 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) { + if (_sdconfig_.currentZone.zone == gpiopin->zone && _sdconfig_.currentZone.type != zcNONE) { sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft * 60); } else { sprintf(mqtt_msg, "%d", 0); @@ -277,9 +278,16 @@ void broadcast_sprinklerdactivestate(struct mg_connection *nc) for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) { if (is_mqtt(c)) { - sprintf(mqtt_topic, "%s/active", _sdconfig_.mqtt_topic); - sprintf(mqtt_msg, "Zone %d", _sdconfig_.currentZone.zone ); - send_mqtt_msg(c, mqtt_topic, mqtt_msg); + 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); @@ -290,6 +298,7 @@ void broadcast_sprinklerdactivestate(struct mg_connection *nc) 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++) { @@ -299,6 +308,8 @@ void broadcast_sprinklerdactivestate(struct mg_connection *nc) 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); @@ -306,7 +317,10 @@ void broadcast_sprinklerdactivestate(struct mg_connection *nc) send_mqtt_msg(c, mqtt_topic, mqtt_msg); } - } + if (_sdconfig_.currentZone.type != zcALL) { + + } + } } } @@ -765,6 +779,8 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){ 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; @@ -775,7 +791,7 @@ static void ev_handler(struct mg_connection *nc, int ev, void *p) { switch (ev) { case MG_EV_CONNECT: { set_mqtt(nc); - if (_sdconfig_.mqtt_topic != NULL || _sdconfig_.mqtt_dz_sub_topic != NULL) { + //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; @@ -784,12 +800,17 @@ static void ev_handler(struct mg_connection *nc, int ev, void *p) { // 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; @@ -825,12 +846,25 @@ static void ev_handler(struct mg_connection *nc, int ev, void *p) { 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, "Message publishing acknowledged (msg_id: %d)\n", mqtt_msg->message_id); + 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: @@ -903,8 +937,8 @@ bool check_net_services(struct mg_mgr *mgr) { void start_mqtt(struct mg_mgr *mgr) { - //if (_sdconfig_.enableMQTT == false) { - if( _sdconfig_.enableMQTTaq == false && _sdconfig_.enableMQTTdz == false ) { + 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; @@ -912,9 +946,9 @@ void start_mqtt(struct mg_mgr *mgr) { //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); + //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\n", _sdconfig_.enableMQTTaq, _sdconfig_.enableMQTTdz); + 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); diff --git a/net_services.h b/net_services.h index 98afd93..6506b8f 100644 --- a/net_services.h +++ b/net_services.h @@ -12,6 +12,9 @@ #define MQTT_ON "1" #define MQTT_OFF "0" + +#define MQTT_LWM_TOPIC "Alive" + //enum nsAction{nsNONE = 0, nsGPIO = 1, nsLED = 2, nsLCD = 3}; bool start_net_services(struct mg_mgr *mgr); @@ -21,6 +24,9 @@ void broadcast_sprinklerdactivestate(struct mg_connection *nc); //void broadcast_state(struct mg_connection *nc); //void broadcast_state_error(struct mg_connection *nc, char *msg); bool check_net_services(struct mg_mgr *mgr); + +void send_mqtt_msg(struct mg_connection *nc, char *toppic, char *message); + //void broadcast_polled_devices(struct mg_connection *nc); //void broadcast_polled_devices(struct mg_mgr *mgr); diff --git a/release/sprinklerd b/release/sprinklerd index 2445e51..6f28a3e 100755 Binary files a/release/sprinklerd and b/release/sprinklerd differ diff --git a/release/sprinklerd.conf b/release/sprinklerd.conf index c20cfc1..2066e6d 100644 --- a/release/sprinklerd.conf +++ b/release/sprinklerd.conf @@ -13,6 +13,9 @@ LOG_LEVEL = NOTICE #MQTT_PASSWD = somepassword #MQT_TOPIC = sprinklerd +# If you want to publish to home assistant doscover topics. +#MQTT_HA_DIS_TOPIC = homeassistant + # if you are using domoticz and MQTT uncomment #MQTT_DZ_PUB_TOPIC = domoticz/in #MQTT_DZ_SUB_TOPIC = domoticz/out diff --git a/sprinkler.c b/sprinkler.c index 713d978..bdd92ec 100644 --- a/sprinkler.c +++ b/sprinkler.c @@ -296,6 +296,8 @@ void main_loop () exit(EXIT_FAILURE); } + + i=0; while (true) { @@ -306,12 +308,16 @@ void main_loop () if (zc_check() == true || check_delay24h() == true || _sdconfig_.eventToUpdateHappened) { _sdconfig_.eventToUpdateHappened = false; broadcast_sprinklerdstate(_mgr.active_connections); - } - - if (i >= 20) { + broadcast_sprinklerdactivestate(_mgr.active_connections); + } else if (i > 10 && _sdconfig_.currentZone.type!=zcNONE) { i=0; - if (_sdconfig_.currentZone.type != zcNONE) + broadcast_sprinklerdactivestate(_mgr.active_connections); + } else { + if (i >= 600) { + i=0; + broadcast_sprinklerdstate(_mgr.active_connections); broadcast_sprinklerdactivestate(_mgr.active_connections); + } } //logMessage (LOG_DEBUG, "check_net_services\n"); diff --git a/version.h b/version.h index 2e66468..00ecef1 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ #ifndef SD_VERSION_H #define SD_VERSION_H -#define SD_VERSION "1.2" +#define SD_VERSION "1.3" #endif