master
shaun feakes 2018-08-20 18:52:36 -05:00
parent 696bb2a15b
commit ad48fba62f
16 changed files with 71 additions and 24 deletions

View File

@ -138,6 +138,8 @@ sprinklerd/zone/1/set 1
sprinklerd/zone/zall/set 1 // Cycle all zones using default runtimes.
sprinklerd/24hdelay/set 1
sprinklerd/calendar/set 1
sprinklerd/chanceofrain/set 29 // % chance of rain for today
sprinklerd/raintotal/set 0.3 // Set rain total in inches.
```

View File

@ -255,6 +255,7 @@ void readCfg(char *inifile)
_sdconfig_.dzidx_24hdelay = ini_getl("SPRINKLERD", "DZIDX_24HDELAY", 0, inifile);
_sdconfig_.dzidx_allzones = ini_getl("SPRINKLERD", "DZIDX_ALL_ZONES", 0, inifile);
_sdconfig_.dzidx_status = ini_getl("SPRINKLERD", "DZIDX_STATUS", 0, inifile);
_sdconfig_.dzidx_rainsensor = ini_getl("SPRINKLERD", "DZIDX_RAINSENSOR", 0, inifile);
logMessage (LOG_INFO, "Name = %s\n", _sdconfig_.name);
logMessage (LOG_INFO, "Port = %s\n", _sdconfig_.socket_port);

View File

@ -70,6 +70,7 @@ struct sprinklerdcfg {
int dzidx_24hdelay;
int dzidx_allzones;
int dzidx_status;
int dzidx_rainsensor;
bool enableMQTTdz;
bool enableMQTTaq;
int zones;

View File

@ -7,6 +7,7 @@
#
darkskyAPI='0123456789abcdef9876543210fedcba'
location='42.3601,-71.0589'
probabilityOver=1.0 # Don't set delay from this script, use the SprinklerD config to decide if to set delay
sprinklerdEnableDelay="http://localhost/?type=option&option=24hdelay&state=reset"
sprinklerdProbability="http://localhost/?type=sensor&sensor=chanceofrain&value="
@ -18,7 +19,7 @@ command -v curl >/dev/null 2>&1 || { echoerr "curl is not installed. Aborting!"
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; }
probability=$(curl -s "https://api.darksky.net/forecast/"$darkskyAPI"/"$location | jq '.["daily"].data[0].precipProbability' 2>/dev/null)
darkskyJSON=$(curl -s "https://api.darksky.net/forecast/"$darkskyAPI"/"$location)
if [ $? -ne 0 ]; then
echoerr "Error reading DarkSkys URL, please check!"
@ -26,6 +27,15 @@ if [ $? -ne 0 ]; then
exit 1;
fi
probability=$(echo $darkskyJSON | jq '.["daily"].data[0].precipProbability' )
#if [ $? -ne 0 ]; then
if [ "$probability" == "null" ]; then
echoerr "Error reading DarkSkys JSON, please check!"
exit 1;
fi
echomsg -n "Probability of rain today is "`echo "$probability * 100" | bc`"%"
curl -s "$sprinklerdProbability`echo \"$probability * 100\" | bc`" > /dev/null

BIN
extras/sprinklerd.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
extras/sprinklerd_48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -226,7 +226,7 @@ int build_dz_status_message_JSON(char* buffer, int size, int idx, int nvalue, ch
return strlen(buffer);
}
bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, char *svalue) {
bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, char *svalue, const char *svalue_str) {
int i = 0;
int found = 0;
@ -252,7 +252,8 @@ bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, ch
found++;
}
}
} else if (strncmp("\"svalue1\"", (char *)&str[i], 9) == 0) {
//} else if (strncmp("\"svalue1\"", (char *)&str[i], 9) == 0) {
} else if (strncmp(svalue_str, (char *)&str[i], 9) == 0) {
i = i + 9;
for (; str[i] != ',' && str[i] != '\0'; i++) {
if (str[i] == ':') {

View File

@ -11,7 +11,8 @@
#define JSON_MQTT_MSG_SIZE 50
bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, char *svalue);
//bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, char *svalue);
bool parseJSONmqttrequest(const char *str, size_t len, int *idx, int *nvalue, char *svalue, const char *svalue_str);
int build_dz_mqtt_status_JSON(char* buffer, int size, int idx, int nvalue, float tvalue);
int build_dz_status_message_JSON(char* buffer, int size, int idx, int nvalue, char *svalue);
int build_sprinkler_JSON(char* buffer, int size);

View File

@ -124,7 +124,7 @@ bool check_dz_cache(int idx, int value) {
}
return false;
}
/*
void urldecode(char *dst, const char *src)
{
char a, b;
@ -161,7 +161,7 @@ void urldecode(char *dst, const char *src)
}
*dst++ = '\0';
}
*/
// Need to update network interface.
char *generate_mqtt_id(char *buf, int len) {
extern char *__progname; // glibc populates this
@ -317,6 +317,7 @@ void broadcast_sprinklerdstate(struct mg_connection *nc)
struct mg_connection *c;
static char mqtt_topic[250];
static char mqtt_msg[50];
static char last_state_msg[50];
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)
@ -359,8 +360,11 @@ void broadcast_sprinklerdstate(struct mg_connection *nc)
}
if (_sdconfig_.dzidx_status > 0) {
int value =sprinklerdstatus(mqtt_msg, 50);
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);
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);
}
}
}
}
@ -606,7 +610,7 @@ void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_messa
int i;
char svalue[DZ_SVALUE_LEN];
if (parseJSONmqttrequest(msg->payload.p, msg->payload.len, &idx, &nvalue, svalue)) {
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) {
@ -622,6 +626,9 @@ void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_messa
} 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++)
{
@ -648,8 +655,7 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
char *pt3 = NULL;
char *pt4 = NULL;
// NSF change 10 to strlen(_sdconfig_.mqtt_topic)+1 **** BUT TEST.***
for (i=10; i < msg->topic.len; i++) {
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];
@ -680,6 +686,8 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
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 ) {
@ -691,6 +699,8 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
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) {
@ -710,6 +720,14 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "cycleallzones", 13) == 0 && strncmp(pt3, "set", 3) == 0 ) {
zc_zone(zcALL, 0, status, 0);
logMessage(LOG_DEBUG, "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_DEBUG, "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_DEBUG, "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) {

Binary file not shown.

View File

@ -18,6 +18,7 @@ LOG_LEVEL = NOTICE
#DZIDX_CALENDAR = 197
#DZIDX_24HDELAY = 198
#DZIDX_ALL_ZONES = 199
#DZIDX_RAINSENSOR = 48
# Options for the below ZONE and GPIO configuration
#

View File

@ -8,16 +8,17 @@ CACHE = /var/cache/sprinklerd.cache
LOG_LEVEL = NOTICE
# mqtt stuff
#MQTT_ADDRESS = trident:1883
MQTT_ADDRESS = trident:1883
#MQTT_USER = someusername
#MQTT_PASSWD = somepassword
#MQT_TOPIC = sprinklerd
#MQTT_DZ_PUB_TOPIC = domoticz/in
#MQTT_DZ_SUB_TOPIC = domoticz/out
MQT_TOPIC = sd_test
MQTT_DZ_PUB_TOPIC = domoticz/in
MQTT_DZ_SUB_TOPIC = domoticz/out
#DZIDX_CALENDAR = 197
#DZIDX_24HDELAY = 198
#DZIDX_ALL_ZONES = 199
DZIDX_CALENDAR = 197
DZIDX_24HDELAY = 198
DZIDX_ALL_ZONES = 199
DZIDX_RAINSENSOR = 48
# Options for the below ZONE and GPIO configuration
#

View File

@ -26,15 +26,21 @@ bool setTodayChanceOfRain(int percent)
bool setTodayRainTotal(float rain)
{
_sdconfig_.todayRainTotal = rain;
if (_sdconfig_.todayRainTotal == rain)
return true;
_sdconfig_.todayRainTotal = rain;
logMessage(LOG_DEBUG, "Today's rain total = %f\n",_sdconfig_.todayRainTotal);
time_t now;
time(&now);
if (_sdconfig_.precipInchDelay2day > 0 && _sdconfig_.todayRainTotal >= _sdconfig_.precipInchDelay2day) {
time_t now;
time(&now);
reset_delay24h_time(now + (DELAY24H_SEC * 2) ); // today + 2 days in seconds
} else if (_sdconfig_.precipInchDelay1day > 0 && _sdconfig_.todayRainTotal >= _sdconfig_.precipInchDelay1day) {
enable_delay24h(true);
//enable_delay24h(true);
reset_delay24h_time(now + DELAY24H_SEC);
}
return true;

View File

@ -328,7 +328,11 @@ int str2int(const char* str, int len)
}
// NSF come back and do this correctly
float str2float(const char* str, int len)
{
return (float)strtod(str, NULL);
}

View File

@ -18,6 +18,7 @@ void logMessage(int level, char *format, ...);
int count_characters(const char *str, char character);
void run_external(char *command, int state);
int str2int(const char* str, int len);
float str2float(const char* str, int len);
//void readCfg (char *cfgFile);
int text2elevel(char* level);
char *elevel2text(int level);

View File

@ -186,7 +186,7 @@
*/
}
function addHeadIcon(rel) {
var image = 'data:image/png;base64,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';
var image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJgAAACYCAMAAAAvHNATAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAABdUExURSLQQaPgq8PixOft54bll0Cu3mFhYf///wAAAAaX1Eyw2sXV2PP19Im8zpbAzo7knN3j5NHa3Nff4L7R1fr7+1my1cfW2WG01aqqqnJycsHBwWxsbGm01I2NjWa000nzYgoAAAL5SURBVHja7dlte4IgFAZgLMGZVVpWVmv//2fOKtUZ4NGdkO16zrexHXZfvIMi8jQEYIABBhhggAEGGGCAAQYYYIABBhgnbLlaLFZL/2CpjMuQqXewRXyPhW+wrXzA5NYz2C5+xg4t9sfHmL+z0tt1bIqVf5kkfC1BrY0AW8k4lisuF7U2QaqJT0aurRe2rBYolt6k19YLS6olPeGA0Wv7uzB648+TZO6wK6nDNd3fpts+dTb4iRP8UDXFwdlyQVoSc1kNHpk7W2ApsY7rWHu1V+4b2HEqWLbLjKcxw4lMm8IMW0sZS/nSXUdLixlSeGGfj0EuP+lj7OuZ8vVO2LqafN0GMM9KYworrP73saSuY+YURljW+i8ZbeW3pfDBds1I0twftXulPcVFi/Gl8I4xzhTOWcmawrmOWcLJOjZqGXey8o/b+FzslV7dxG1RXJQ2TsW0sJP6MIQ6TQkrjK5SVkwIu3xY4jQhTNlgCjBPYbpTzTAY5Q1hMGyrPQcOgRHfEHpg3ZfepDo5J2NhiebsbXtP1sO6b+OmuwYdpqvB+gKvh3W/JphuZ3SYrgbrNwst7OX7i+k+S4dp3hDsX3mE9dKx63kBoMM0Ndi/i/2uxehb0pGlxchjjL6J84wx8qykH3uYZqV5HTvoDoovKKUu3UOPbiUcvo4ZV/4tacdUQ2tg3yuHwN60Vw46YyiGSv817NqFXT2BZZ0mU5knsOj8Q6bOkS+wKG8aTWV55A+sNQEUU4WAAQYYYIAB9rt9nGcHZ4RF17tMXaO3wILurwN6yam55Abj6rHAws5fByG9JC2bTKVDs9olNlg4a/84C4Wgl5zVY4ANy2pKrDARti5Y8zJbDCgpijFZdYkdJjbNTxtxD3JJno/Jqkt6YE3XB+Ej3VVJD6zu+tkz21lJH+zZ9fM621VJL+zR9RvRCicl/bBb1wdhO91JST+s7PrZj2w3JQTYNAEYYIAB9q9hk8Z7bkncARhggAEGGGCAAQYYYIABBhhggAFWxjcZXFfjMfI84gAAAABJRU5ErkJggg==';
var link = document.createElement('link');
link.rel = rel;
link.type= 'image/png';