Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
|
cb920a03d3 | |
|
e93ad44028 | |
|
53f6e6874c | |
|
3d1e855b39 | |
|
d039eeb972 | |
|
5c3f29e773 | |
|
9648433ef8 | |
|
b6b96e1415 | |
|
1f46cf2b1d |
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 2017 Shaun Feakes - All rights reserved
|
||||
*
|
||||
* You may use redistribute and/or modify this code under the terms of
|
||||
* the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation. For the terms of this license,
|
||||
* see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* You are free to use this software under the terms of the GNU General
|
||||
* Public License, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* https://github.com/sfeakes/GPIO_pi
|
||||
*/
|
||||
|
||||
/********************-> GPIO Pi v1.2 <-********************/
|
||||
|
||||
|
||||
|
||||
#define _GPIO_pi_NAME_ "GPIO Pi"
|
||||
#define _GPIO_pi_VERSION_ "1.2"
|
||||
|
||||
#ifndef _GPIO_pi_H_
|
||||
#define _GPIO_pi_H_
|
||||
|
||||
/* Use sysfs for ALL gpio activity?
|
||||
comment out to use memory where we can
|
||||
*/
|
||||
//#define GPIO_SYSFS_MODE
|
||||
|
||||
|
||||
#include <syslog.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// check number is between 2 and 27
|
||||
#ifndef USE_WIRINGPI
|
||||
#define GPIO_MIN 2
|
||||
#define GPIO_MAX 27
|
||||
#else // WiringPI valid numbers
|
||||
#define GPIO_MIN 0
|
||||
#define GPIO_MAX 30
|
||||
#endif
|
||||
|
||||
#define validGPIO(X) ((X) <= (GPIO_MAX) ? ( ((X) >= (GPIO_MIN) ? (1) : (0)) ) : (0))
|
||||
|
||||
#ifndef USE_WIRINGPI // Don't include anything below this line if using wiringpi.
|
||||
|
||||
#define INPUT 0
|
||||
#define OUTPUT 1
|
||||
#define IO_ALT5 2 // PWM Circuit
|
||||
#define IO_ALT4 3 // SPI Circuit
|
||||
#define IO_ALT0 4 // PCM Audio Circuit (Also I2C)
|
||||
#define IO_ALT1 5 // SMI (Secondary Memory Interface)
|
||||
#define IO_ALT2 6 // Nothing
|
||||
#define IO_ALT3 7 // BSC - SPI Circuit
|
||||
|
||||
|
||||
#define LOW 0
|
||||
#define HIGH 1
|
||||
|
||||
#define INT_EDGE_SETUP 0
|
||||
#define INT_EDGE_FALLING 1
|
||||
#define INT_EDGE_RISING 2
|
||||
#define INT_EDGE_BOTH 3
|
||||
|
||||
#define PUD_OFF 0
|
||||
#define PUD_DOWN 1
|
||||
#define PUD_UP 2
|
||||
|
||||
#define SYSFS_PATH_MAX 35
|
||||
#define SYSFS_READ_MAX 3
|
||||
|
||||
#ifndef GPIO_SYSFS_MODE
|
||||
#define GPIO_BASE_P4 0xFE000000 // Pi 4
|
||||
#define GPIO_BASE_P2 0x3F000000 // Pi 2 & 3
|
||||
#define GPIO_BASE_P1 0x20000000 // Pi 1 & Zero
|
||||
#define GPIO_OFFSET 0x200000
|
||||
|
||||
//#define GPIO_BASE 0x20200000
|
||||
#define GPIO_LEN 0xB4
|
||||
#define GPIO_LEN_P4 0xF1 // Pi 4 has more registers BCM2711
|
||||
|
||||
#define GPSET0 7
|
||||
#define GPSET1 8
|
||||
|
||||
#define GPCLR0 10
|
||||
#define GPCLR1 11
|
||||
|
||||
#define GPLEV0 13
|
||||
#define GPLEV1 14
|
||||
|
||||
#define GPPUD 37
|
||||
#define GPPUDCLK0 38
|
||||
#define GPPUDCLK1 39
|
||||
|
||||
/* Pi4 BCM2711 has different pulls */
|
||||
#define GPPUPPDN0 57
|
||||
#define GPPUPPDN1 58
|
||||
#define GPPUPPDN2 59
|
||||
#define GPPUPPDN3 60
|
||||
|
||||
|
||||
#define PI_MODEL_UNKNOWN -1
|
||||
#define PI_MODEL_A 0
|
||||
#define PI_MODEL_B 1
|
||||
#define PI_MODEL_AP 2
|
||||
#define PI_MODEL_BP 3
|
||||
#define PI_MODEL_2 4
|
||||
#define PI_ALPHA 5
|
||||
#define PI_MODEL_CM 6
|
||||
#define PI_MODEL_07 7
|
||||
#define PI_MODEL_3 8
|
||||
#define PI_MODEL_ZERO 9
|
||||
#define PI_MODEL_CM3 10
|
||||
#define PI_MODEL_ZERO_W 12
|
||||
#define PI_MODEL_3P 13
|
||||
#define PI_MODEL_3AP 14
|
||||
#define PI_MODEL_CM3P 16
|
||||
#define PI_MODEL_4B 17
|
||||
|
||||
#endif
|
||||
|
||||
#define GPIO_ERR_GENERAL -7
|
||||
#define GPIO_NOT_IO_MODE -6
|
||||
#define GPIO_NOT_OUTPUT -5
|
||||
#define GPIO_NOT_EXPORTED -4
|
||||
#define GPIO_ERR_IO -3
|
||||
#define GPIO_ERR_NOT_SETUP -2
|
||||
#define GPIO_ERR_BAD_PIN -1
|
||||
#define GPIO_OK 0
|
||||
|
||||
//#ifndef SYSFS_MODE
|
||||
int pinExport(unsigned int gpio);
|
||||
int pinUnexport(unsigned int gpio);
|
||||
bool isExported(unsigned int gpio);
|
||||
int pinMode(unsigned int gpio, unsigned int mode);
|
||||
int getPinMode(unsigned int gpio);
|
||||
int digitalRead(unsigned int gpio);
|
||||
int digitalWrite(unsigned int gpio, unsigned int level);
|
||||
int setPullUpDown(unsigned int gpio, unsigned int pud);
|
||||
int edgeSetup (unsigned int pin, unsigned int value);
|
||||
bool gpioSetup();
|
||||
void gpioShutdown();
|
||||
int registerGPIOinterrupt(unsigned int gpio, unsigned int mode, void (*function)(void *args), void *args );
|
||||
|
||||
#ifndef GPIO_SYSFS_INTERRUPT
|
||||
int unregisterGPIOinterrupt(unsigned int gpio);
|
||||
#endif
|
||||
|
||||
/*
|
||||
#else
|
||||
bool pinExport(int pin);
|
||||
bool pinUnexport(int pin);
|
||||
bool pinMode (int pin, int mode);
|
||||
int digitalRead (int pin);
|
||||
bool digitalWrite (int pin, int value);
|
||||
#endif
|
||||
*/
|
||||
|
||||
#endif /* WiringPI */
|
||||
#endif /* _GPIO_pi_H_ */
|
28
Makefile
28
Makefile
|
@ -4,7 +4,7 @@ CC = gcc
|
|||
#USE_WIRINGPI := 1
|
||||
|
||||
ifeq ($(USE_WIRINGPI),)
|
||||
sd_GPIO_C := sd_GPIO.c
|
||||
sd_GPIO_C := GPIO_Pi.c
|
||||
else
|
||||
#WPI_LIB := -D USE_WIRINGPI -lwiringPi -lwiringPiDev
|
||||
WPI_LIB := -D USE_WIRINGPI -lwiringPi
|
||||
|
@ -19,15 +19,14 @@ LIBS := $(WPI_LIB) -lm -lpthread
|
|||
$DBG =
|
||||
|
||||
# define any compile-time flags
|
||||
GCCFLAGS = -Wall
|
||||
GCCFLAGS = -Wall -O3
|
||||
#CFLAGS = -Wall -lpthread -lwiringPi -lwiringPiDev -lm -I. -I./minIni
|
||||
CFLAGS = $(GCCFLAGS) -I. -I./minIni $(DBG) $(LIBS) -D MG_DISABLE_MD5 -D MG_DISABLE_HTTP_DIGEST_AUTH -D MG_DISABLE_MD5 -D MG_DISABLE_JSON_RPC
|
||||
#CFLAGS = -Wextra -Wall -g -I./wiringPI
|
||||
|
||||
|
||||
# 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)
|
||||
TSRC = test.c config.c utils.c minIni/minIni.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
|
||||
#
|
||||
|
@ -38,11 +37,11 @@ TSRC = test.c config.c utils.c minIni/minIni.c
|
|||
# with the .o suffix
|
||||
#
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
TOBJ = $(TSRC:.c=.o)
|
||||
|
||||
# define the executable file
|
||||
MAIN = ./release/sprinklerd
|
||||
TEST = ./release/testing
|
||||
GMON = ./release/gpio_monitor
|
||||
GPIO = ./release/gpio
|
||||
|
||||
#
|
||||
# The following part of the makefile is generic; it can be used to
|
||||
|
@ -50,7 +49,14 @@ TEST = ./release/testing
|
|||
# deleting dependencies appended to the file from 'make depend'
|
||||
#
|
||||
|
||||
.PHONY: depend clean
|
||||
.PHONY: depend clean release
|
||||
|
||||
release:
|
||||
sudo docker run -it --mount type=bind,source=./,target=/build aqualinkd-releasebin make armhf
|
||||
$(info Binaries for release have been built)
|
||||
|
||||
armhf: CC = arm-linux-gnueabihf-gcc
|
||||
armhf: $(MAIN)
|
||||
|
||||
all: $(MAIN)
|
||||
@echo: $(MAIN) have been compiled
|
||||
|
@ -58,11 +64,9 @@ all: $(MAIN)
|
|||
$(MAIN): $(OBJS)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
|
||||
|
||||
test: $(TEST)
|
||||
@echo: $(TEST) have been compiled
|
||||
|
||||
$(TEST): $(TOBJ)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -o $(TEST) $(TOBJ) $(LFLAGS) $(LIBS)
|
||||
gpio_tools:
|
||||
$(CC) -o $(GMON) GPIO_Pi.c -lm -lpthread -D GPIO_MONITOR
|
||||
$(CC) -o $(GPIO) GPIO_Pi.c -lm -lpthread -D GPIO_TOOL
|
||||
|
||||
# this is a suffix replacement rule for building .o's from .c's
|
||||
# it uses automatic variables $<: the name of the prerequisite of
|
||||
|
|
19
README.md
19
README.md
|
@ -93,17 +93,30 @@ 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`
|
||||
|
||||
<!--
|
||||
[sprinklerDarkskys.sh](https://github.com/sfeakes/sprinklerd/blob/master/extras/sprinklerDarkskys.sh)
|
||||
Script to check the chance of rain from darkskys forecast API, 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 can also use this script to simply sent the 'chance or rain today' to SprinklerD, and allow SprinklerD to make the decision if to enable rain delay, depending on options configured in the UI.
|
||||
|
||||
[sprinklerOpenWeather.sh](https://github.com/sfeakes/sprinklerd/blob/master/extras/sprinklerOpenWeather.sh)
|
||||
Exactly the same as above (sprinklerDarkskys.sh) but uses OpenWeather forecast API.
|
||||
|
||||
[sprinklerMeteohub.sh](https://github.com/sfeakes/sprinklerd/blob/master/extras/sprinklerMeteohub.sh)
|
||||
Script to pull daily rain total from Hereohub and send it to SprinklerD. SprinklerD will then turn on rain dalys (14h or 48h) depending on rain threshold.
|
||||
Script to pull daily rain total from Meteohub and send it to SprinklerD. SprinklerD will then turn on rain dalys (14h or 48h) depending on rain threshold.
|
||||
|
||||
[sprinklerRainDelay.sh](https://github.com/sfeakes/sprinklerd/blob/master/extras/sprinklerRainDelay.sh)
|
||||
Script to enable extended rain delays. i.e. I have my weatherstation triger this script when it detects rain. The script will cancel any running zones and enable a rain delay. You can use a number on command line parameter to enable long delays, (number represents number of days). So if my rainsensor logs over 5mm rain in any 24h period it will call this script with a 2 day delay, or 3 day delay if over 15mm of rain.
|
||||
|
||||
-->
|
||||
|
||||
# Configuration with home automation hubs
|
||||
|
||||
|
@ -200,6 +213,8 @@ http://sprinklerd.ip.address:port?type=option&option=24hdelay&state=off
|
|||
* // Run options
|
||||
<host>?type=option&option=allz&state=on // Run all zones default times (ignore 24h delay & calendar settings)
|
||||
<host>?type=zone&zone=2&state=on&runtime=3 // Run zone 2 for 3 mins (ignore 24h delay & calendar settings)
|
||||
<host>?type=zone&zone=2&state=off // Turn off zone 2
|
||||
<host>?type=zone&zone=2&state=flip // Flip state of zone 2, Turn off if on, Turn on if off
|
||||
<host>?type=zrtcfg&zone=2&time=10 // change zone 2 default runtime to 10
|
||||
<host>?type=cron&zone=1&runtime=12&state=on' // Run zone 1 for 12 mins (calendar & 24hdelay settings overide this request)
|
||||
|
||||
|
|
115
config.c
115
config.c
|
@ -9,10 +9,11 @@
|
|||
#include <wiringPi.h>
|
||||
#define PIN_CFG_NAME "WPI_PIN"
|
||||
#else
|
||||
#include "sd_GPIO.h"
|
||||
//#include "sd_GPIO.h"
|
||||
#define PIN_CFG_NAME "GPIO_PIN"
|
||||
#endif
|
||||
|
||||
#include "GPIO_Pi.h"
|
||||
#include "minIni.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
|
@ -231,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");
|
||||
}
|
||||
|
@ -307,7 +320,14 @@ void readCfg(char *inifile)
|
|||
//_sdconfig_.zonecfg[i].master_valve = ini_getl(str, "MASTER_VALVE", NO, inifile);
|
||||
_sdconfig_.zonecfg[i].default_runtime = ini_getl(str, "DEFAULT_RUNTIME", 10, inifile);
|
||||
//ini_gets(str, "NAME", NULL, _sdconfig_.zonecfg[idx].name, sizearray(_sdconfig_.zonecfg[idx].name), inifile);
|
||||
ini_gets(str, "NAME", NULL, _sdconfig_.zonecfg[i].name, sizearray(_sdconfig_.zonecfg[i].name), inifile);
|
||||
ini_gets(str, "NAME", NULL, _sdconfig_.zonecfg[i].name, sizearray(_sdconfig_.zonecfg[i].name), inifile);
|
||||
//#ifndef USE_WIRINGPI
|
||||
if ( ! validGPIO(pin) ) {
|
||||
logMessage (LOG_ERR, "GPIO pin %d is not valid, found in ZONE:%d of configuration file %s \n",pin, i, inifile);
|
||||
pin = -1;
|
||||
sprintf(_sdconfig_.zonecfg[i].name, "ERROR");
|
||||
}
|
||||
//#endif
|
||||
/*
|
||||
logMessage (LOG_DEBUG,"Zone Config : %s\n%25s : %d\n%25s : %d\n%25s : %d\n%25s : %d\n%25s : %d\n",
|
||||
_sdconfig_.zonecfg[i].name,
|
||||
|
@ -347,6 +367,89 @@ void readCfg(char *inifile)
|
|||
logMessage (LOG_ERR," no config zones set\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
_sdconfig_.inputs = 0;
|
||||
// Caculate how many inputs we have
|
||||
for (i=1; i <= 24; i++) // 24 = Just some arbutary number (max GPIO without expansion board)
|
||||
{
|
||||
sprintf(str, "INPUT:%d", i);
|
||||
pin = ini_getl(str, PIN_CFG_NAME, -1, inifile);
|
||||
if (pin == -1)
|
||||
break;
|
||||
else
|
||||
_sdconfig_.inputs = i;
|
||||
}
|
||||
|
||||
logMessage (LOG_DEBUG, "Found %d INPUTS\n", _sdconfig_.inputs);
|
||||
|
||||
if ( _sdconfig_.inputs != 0) {
|
||||
// n= _sdconfig_.zones+1;
|
||||
_sdconfig_.inputcfg = malloc((_sdconfig_.inputs + 1) * sizeof(struct GPIOcfg));
|
||||
for (i=0; i < _sdconfig_.inputs; i++)
|
||||
{
|
||||
sprintf(str, "INPUT:%d", i+1);
|
||||
pin = ini_getl(str, PIN_CFG_NAME, -1, inifile);
|
||||
if (! validGPIO(pin) ) {
|
||||
logMessage (LOG_ERR, "GPIO pin %d is not valid, found in INPUT:%d of configuration file %s \n",pin, i+1, inifile);
|
||||
continue;
|
||||
}
|
||||
logMessage (LOG_DEBUG, "INPUT = %d\n", i+1);
|
||||
|
||||
_sdconfig_.inputcfg[i].input_output = INPUT; // Zone is always input
|
||||
_sdconfig_.inputcfg[i].receive_mode = BOTH; // Zone always needs trigger on both (high or low)
|
||||
_sdconfig_.inputcfg[i].zone = i+1;
|
||||
_sdconfig_.inputcfg[i].pin = pin;
|
||||
_sdconfig_.inputcfg[i].on_state = ini_getl(str, "GPIO_ON_STATE", NO, inifile);
|
||||
//_sdconfig_.inputcfg[i].startup_state = !_sdconfig_.inputcfg[i].on_state;
|
||||
//_sdconfig_.inputcfg[i].shutdown_state = !_sdconfig_.inputcfg[i].on_state;
|
||||
|
||||
_sdconfig_.inputcfg[i].set_pull_updown = ini_getl(str, "GPIO_PULL_UPDN", -1, inifile);
|
||||
_sdconfig_.inputcfg[i].dz_idx = ini_getl(str, "DOMOTICZ_IDX", -1, inifile); // Not used at the moment.
|
||||
ini_gets(str, "NAME", NULL, _sdconfig_.inputcfg[i].name, sizearray(_sdconfig_.inputcfg[i].name), inifile);
|
||||
|
||||
_sdconfig_.inputcfg[i].command_on = malloc(COMMAND_SIZE * sizeof(char));
|
||||
_sdconfig_.inputcfg[i].command_off = malloc(COMMAND_SIZE * sizeof(char));
|
||||
ini_gets(str, "COMMAND_ON", NULL, _sdconfig_.inputcfg[i].command_on, COMMAND_SIZE, inifile);
|
||||
ini_gets(str, "COMMAND_OFF", NULL, _sdconfig_.inputcfg[i].command_off, COMMAND_SIZE, inifile);
|
||||
|
||||
logMessage (LOG_DEBUG,"Input Config : %s\n%25s : %d\n%25s : %d\n%25s : %d\n%25s : %d\n",
|
||||
_sdconfig_.inputcfg[i].name,
|
||||
"PIN",_sdconfig_.inputcfg[i].pin,
|
||||
"Set pull up/down", _sdconfig_.inputcfg[i].set_pull_updown,
|
||||
"ON state", _sdconfig_.inputcfg[i].on_state,
|
||||
"Domoticz IDX", _sdconfig_.inputcfg[i].dz_idx);
|
||||
}
|
||||
}
|
||||
|
||||
_sdconfig_.runBeforeCmds = 0;
|
||||
// Caculate how many external command to run
|
||||
for (i=1; i <= 10; i++) // 10 = Just some arbutary number
|
||||
{
|
||||
sprintf(str, "EXTERNAL:%d", i);
|
||||
pin = ini_getl(str, "RUNB4STARTTIME", -1, inifile);
|
||||
if (pin == -1)
|
||||
break;
|
||||
else
|
||||
_sdconfig_.runBeforeCmds = i;
|
||||
}
|
||||
|
||||
if ( _sdconfig_.runBeforeCmds != 0) {
|
||||
// n= _sdconfig_.zones+1;
|
||||
_sdconfig_.runBeforeCmd = malloc((_sdconfig_.runBeforeCmds) * sizeof(struct RunB4CalStart));
|
||||
for (i=0; i < _sdconfig_.runBeforeCmds; i++)
|
||||
{
|
||||
sprintf(str, "EXTERNAL:%d", i+1);
|
||||
_sdconfig_.runBeforeCmd[i].mins = ini_getl(str, "RUNB4STARTTIME", -1, inifile);
|
||||
ini_gets(str, "COMMAND", NULL, _sdconfig_.runBeforeCmd[i].command, sizearray(_sdconfig_.runBeforeCmd[i].command), inifile);
|
||||
//if (_sdconfig_.runBeforeCmd[i].mins <= 0 || _sdconfig_.runBeforeCmd[i].mins > 120) {
|
||||
// logMessage (LOG_ERR, "RUNB4STARTTIME %d is not valid, found in EXTERNAL:%d of configuration file %s \n",_sdconfig_.runBeforeCmd[i].mins, i+1, inifile);
|
||||
// continue;
|
||||
//}
|
||||
logMessage (LOG_DEBUG,"Run external command '%s', %d mins before start time\n",_sdconfig_.runBeforeCmd[i].command, _sdconfig_.runBeforeCmd[i].mins);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
idx=0;
|
||||
pin=-1;
|
||||
|
|
43
config.h
43
config.h
|
@ -24,6 +24,11 @@ struct CALENDARday {
|
|||
int minute;
|
||||
int *zruntimes;
|
||||
};
|
||||
|
||||
struct RunB4CalStart {
|
||||
int mins;
|
||||
char command[256];
|
||||
};
|
||||
/*
|
||||
struct GPIOextra {
|
||||
char command_high[COMMAND_SIZE];
|
||||
|
@ -46,6 +51,8 @@ struct GPIOcfg {
|
|||
//int ignore_requests;
|
||||
int zone;
|
||||
int default_runtime;
|
||||
char *command_on;
|
||||
char *command_off;
|
||||
//bool master_valve;
|
||||
//struct GPIOextra *extra;
|
||||
};
|
||||
|
@ -59,12 +66,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;
|
||||
|
@ -73,7 +81,9 @@ struct sprinklerdcfg {
|
|||
int dzidx_rainsensor;
|
||||
bool enableMQTTdz;
|
||||
bool enableMQTTaq;
|
||||
bool enableMQTTha;
|
||||
int zones;
|
||||
int inputs;
|
||||
//int pincfgs;
|
||||
bool calendar;
|
||||
bool delay24h;
|
||||
|
@ -84,14 +94,18 @@ struct sprinklerdcfg {
|
|||
float precipInchDelay2day;
|
||||
struct DZcache *dz_cache;
|
||||
struct GPIOcfg *zonecfg;
|
||||
struct GPIOcfg *inputcfg;
|
||||
//struct GPIOcfg *gpiocfg;
|
||||
struct CALENDARday cron[7];
|
||||
//time_t cron_update;
|
||||
long cron_update;
|
||||
int log_level;
|
||||
struct szRunning currentZone;
|
||||
struct RunB4CalStart *runBeforeCmd;
|
||||
int runBeforeCmds;
|
||||
char cache_file[512];
|
||||
bool eventToUpdateHappened;
|
||||
//bool eventToUpdateHappened;
|
||||
uint8_t updateEventMask;
|
||||
int todayRainChance;
|
||||
float todayRainTotal;
|
||||
};
|
||||
|
@ -121,5 +135,26 @@ void read_cache();
|
|||
#define ON 0
|
||||
#define OFF 1
|
||||
*/
|
||||
|
||||
#define UPDATE_RAINTOTAL (1 << 0) //
|
||||
#define UPDATE_RAINPROBABILITY (1 << 1) //
|
||||
#define UPDATE_ZONES (1 << 2) //
|
||||
#define UPDATE_STATUS (1 << 3) //
|
||||
|
||||
#define isEventRainTotal ((_sdconfig_.updateEventMask & UPDATE_RAINTOTAL) == UPDATE_RAINTOTAL)
|
||||
#define isEventRainProbability ((_sdconfig_.updateEventMask & UPDATE_RAINPROBABILITY) == UPDATE_RAINPROBABILITY)
|
||||
#define isEventZones ((_sdconfig_.updateEventMask & UPDATE_ZONES) == UPDATE_ZONES)
|
||||
#define isEventStatus ((_sdconfig_.updateEventMask & UPDATE_STATUS) == UPDATE_STATUS)
|
||||
|
||||
#define setEventRainTotal (_sdconfig_.updateEventMask |= UPDATE_RAINTOTAL)
|
||||
#define setEventRainProbability (_sdconfig_.updateEventMask |= UPDATE_RAINPROBABILITY)
|
||||
#define setEventZones (_sdconfig_.updateEventMask |= UPDATE_ZONES)
|
||||
#define setEventStatus (_sdconfig_.updateEventMask |= UPDATE_STATUS)
|
||||
|
||||
#define clearEventRainTotal (_sdconfig_.updateEventMask &= ~UPDATE_RAINTOTAL)
|
||||
#define clearEventRainProbability (_sdconfig_.updateEventMask &= ~UPDATE_RAINPROBABILITY)
|
||||
#define clearEventZones (_sdconfig_.updateEventMask &= ~UPDATE_ZONES)
|
||||
#define clearEventStatus (_sdconfig_.updateEventMask &= ~UPDATE_STATUS)
|
||||
|
||||
#define NO_CHANGE 2
|
||||
#endif /* CONFIG_H_ */
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# darkskyAPI = your DarkSky API key below, it's free to get one
|
||||
# location = your location lat,long
|
||||
# probabilityOver = Enable rain delay if probability of rain today is grater than this number.
|
||||
# Range is 0 to 1, so 0.5 is 50%
|
||||
# sprinklerdEnableDelay = the URL to SprinklerD
|
||||
#
|
||||
#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="
|
||||
|
||||
echoerr() { printf "%s\n" "$*" >&2; }
|
||||
echomsg() { if [ -t 1 ]; then echo "$@" 1>&2; fi; }
|
||||
|
||||
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; }
|
||||
|
||||
darkskyJSON=$(curl -s "https://api.darksky.net/forecast/"$darkskyAPI"/"$location)
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echoerr "Error reading DarkSkys URL, please check!"
|
||||
echoerr "Maybe you didn't configure your API and location?"
|
||||
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
|
||||
|
||||
if (( $(echo "$probability > $probabilityOver" | bc -l) )); then
|
||||
echomsg -n ", enabeling rain delay"
|
||||
curl -s "$sprinklerdEnableDelay" > /dev/null
|
||||
fi
|
||||
|
||||
echomsg ""
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
#
|
||||
# Change the URL's below to point to Meteohub server and SprinklerD server
|
||||
#
|
||||
|
||||
meteohubRainTotal="http://hurricane/meteograph.cgi?text=day1_rain0_total_in"
|
||||
#meteohubRainTotal="http://192.168.144.101/meteograph.cgi?text=last24h_rain0_total_in"
|
||||
#meteohubRainTotal="http://192.168.144.101/meteograph.cgi?text=alltime_rain0_total_in"
|
||||
|
||||
sprinklerdSetRainTotal="http://localhost/?type=sensor&sensor=raintotal&value="
|
||||
|
||||
echoerr() { printf "%s\n" "$*" >&2; }
|
||||
echomsg() { if [ -t 1 ]; then echo "$@" 1>&2; fi; }
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echoerr "curl is not installed. Aborting!"; exit 1; }
|
||||
|
||||
rainTotal=$(curl -s "$meteohubRainTotal")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echoerr "Error reading Metrohub URL, please check!"
|
||||
echoerr "Assuming rain sensor is not responding, not sending rain total to SprinklerD"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
echomsg -n "Rain total is $rainTotal\" at `date`"
|
||||
|
||||
|
||||
curl -s "$sprinklerdSetRainTotal$rainTotal" > /dev/null
|
||||
|
||||
echomsg ""
|
|
@ -0,0 +1,229 @@
|
|||
#!/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.
|
||||
|
||||
#Can use below to track best api for location
|
||||
#https://www.forecastadvisor.com/
|
||||
|
||||
# API Keys from the following are supported
|
||||
# openweathermap.org weatherapi.com weatherbit.io climacell.co
|
||||
|
||||
openweatherAPIkey='-----'
|
||||
weatherbitAPIkey='-----'
|
||||
climacellAPIkey='-----'
|
||||
weatherAPIkey='-----'
|
||||
accuweatherAPI='-----'
|
||||
|
||||
lat='42.3601'
|
||||
lon='-71.0589'
|
||||
zip='11111'
|
||||
|
||||
|
||||
# 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"
|
||||
openmeteoURL="https://api.open-meteo.com/v1/forecast?latitude=$lat&longitude=$lon&daily=precipitation_probability_max&timezone=America%2FChicago&forecast_days=1"
|
||||
accuweatherURL="http://dataservice.accuweather.com/forecasts/v1/daily/1day/$zip?apikey=$accuweatherAPI&details=true"
|
||||
pirateweatherURL="https://api.pirateweather.net/forecast/$pirateweatherAPI/$lat%2C$lon?exclude=minutely%2Chourly%2Calerts"
|
||||
|
||||
|
||||
true=0
|
||||
false=1
|
||||
|
||||
OUT_FIRST=1
|
||||
OUT_MAX=2
|
||||
OUT_MIN=3
|
||||
OUT_AVERAGE=4
|
||||
OUT_PRINT_ONLY=5
|
||||
|
||||
output=$OUT_FIRST
|
||||
|
||||
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
|
||||
|
||||
if ! [[ $probability =~ ^[0-9]+([.][0-9]+)?$ ]]; then
|
||||
echoerr "Did not get a number from probability API result=$probability"
|
||||
return $false
|
||||
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; }
|
||||
|
||||
probArray=()
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echomsg "Pass at least one command line parameter (openweather, weatherbit, climacell, weatherapi, openmeteo, accuweather, pirateweather)"
|
||||
echomsg "if you pass more than 1 of above, can also use one of folowing -max -min -average -first"
|
||||
echomsg "Example:-"
|
||||
echomsg " $0 openweather weatherapi -average"
|
||||
echomsg ""
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
for var in "$@"
|
||||
do
|
||||
case "$var" in
|
||||
-max)
|
||||
output=$OUT_MAX
|
||||
;;
|
||||
-min)
|
||||
output=$OUT_MIN
|
||||
;;
|
||||
-average)
|
||||
output=$OUT_AVERAGE
|
||||
;;
|
||||
-first)
|
||||
output=$OUT_FIRST
|
||||
;;
|
||||
-print)
|
||||
output=$OUT_PRINT_ONLY
|
||||
;;
|
||||
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)
|
||||
probArray+=($probability)
|
||||
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)
|
||||
probArray+=($probability)
|
||||
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%"
|
||||
probArray+=($probability)
|
||||
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%"
|
||||
probArray+=($probability)
|
||||
fi
|
||||
;;
|
||||
openmeteo)
|
||||
if probability=$(getURL "$openmeteoURL" '.daily.precipitation_probability_max[]' "1"); then
|
||||
echomsg "Open Meteo probability of rain today is $probability%"
|
||||
probArray+=($probability)
|
||||
fi
|
||||
;;
|
||||
accuweather)
|
||||
if probability=$(getURL "$accuweatherURL" '.DailyForecasts[0].Day.PrecipitationProbability' "1"); then
|
||||
echomsg "AccuWeather probability of rain today is $probability%"
|
||||
probArray+=($probability)
|
||||
fi
|
||||
;;
|
||||
pirateweather)
|
||||
if probability=$(getURL "$pirateweatherURL" '.daily.data[0].precipProbability' "100"); then
|
||||
echomsg "PirateWeather probability of rain today is $probability%"
|
||||
probArray+=($probability)
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
if [ ${#probArray[@]} -le 0 ]; then
|
||||
echoerr "No rain probability values found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
prop=${probArray[0]}
|
||||
|
||||
case $output in
|
||||
$OUT_PRINT_ONLY)
|
||||
exit 0;
|
||||
;;
|
||||
$OUT_FIRST)
|
||||
prop=${probArray[0]}
|
||||
;;
|
||||
$OUT_MAX)
|
||||
for n in "${probArray[@]}" ; do
|
||||
((n > prop)) && prop=$n
|
||||
done
|
||||
;;
|
||||
$OUT_MIN)
|
||||
for n in "${probArray[@]}" ; do
|
||||
((n < prop)) && prop=$n
|
||||
done
|
||||
;;
|
||||
$OUT_AVERAGE)
|
||||
prop=0
|
||||
for n in "${probArray[@]}" ; do
|
||||
let prop=prop+n
|
||||
done
|
||||
let prop=prop/${#probArray[@]}
|
||||
;;
|
||||
esac
|
||||
|
||||
echomsg "Chance of rain $prop%"
|
||||
|
||||
curl -s "$sprinklerdProbability$prop" > /dev/null
|
||||
|
||||
if (( $(echo "$prop > $probabilityOver" | bc -l) )); then
|
||||
echomsg "Enabeling rain delay"
|
||||
curl -s "$sprinklerdEnableDelay" > /dev/null
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "config.h"
|
||||
#include "net_services.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
|
||||
//#define HASS_EXPIRE ""\"expire_after"\": 300,"
|
||||
#define HASS_EXPIRE ""
|
||||
|
||||
#define HASS_DEVICE "\"identifiers\": " \
|
||||
"[\"SprinklerD\"]," \
|
||||
" \"sw_version\": \"" SD_VERSION "\"," \
|
||||
" \"model\": \"Sprinkler Daemon\"," \
|
||||
" \"name\": \"SprinklerD\"," \
|
||||
" \"manufacturer\": \"SprinklerD\"," \
|
||||
" \"suggested_area\": \"garden\""
|
||||
|
||||
#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_SENSOR_DISCOVER = "{"
|
||||
"\"device\": {" HASS_DEVICE "},"
|
||||
"\"availability\": {" HASS_AVAILABILITY "},"
|
||||
"\"type\": \"sensor\","
|
||||
"\"unique_id\": \"%s\","
|
||||
"\"name\": \"%s\","
|
||||
"\"state_topic\": \"%s/%s\","
|
||||
"\"value_template\": \"{{ value_json }}\","
|
||||
"\"unit_of_measurement\": \"%s\","
|
||||
"\"icon\": \"%s\""
|
||||
"}";
|
||||
|
||||
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\""
|
||||
"}";
|
||||
|
||||
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\""
|
||||
"}";
|
||||
|
||||
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);
|
||||
|
||||
|
||||
sprintf(id,"sprinklerd_rainprobability");
|
||||
sprintf(topic, "%s/sensor/sprinklerd/%s/config", _sdconfig_.mqtt_ha_dis_topic, id);
|
||||
sprintf(msg, HASSIO_SENSOR_DISCOVER,
|
||||
_sdconfig_.mqtt_topic,
|
||||
id,
|
||||
"Todays Rain Probability",
|
||||
_sdconfig_.mqtt_topic, "chanceofrain",
|
||||
"%",
|
||||
"mdi:water-percent" );
|
||||
send_mqtt_msg(nc, topic, msg);
|
||||
|
||||
sprintf(id,"sprinklerd_raintotal");
|
||||
sprintf(topic, "%s/sensor/sprinklerd/%s/config", _sdconfig_.mqtt_ha_dis_topic, id);
|
||||
sprintf(msg, HASSIO_SENSOR_DISCOVER,
|
||||
_sdconfig_.mqtt_topic,
|
||||
id,
|
||||
"Todays Rain Total",
|
||||
_sdconfig_.mqtt_topic, "raintotal",
|
||||
"\\\"",
|
||||
"mdi:weather-hail" );
|
||||
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);
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef HASSIO_H_
|
||||
#define HASSIO_H_
|
||||
|
||||
void publish_mqtt_hassio_discover(struct mg_connection *nc);
|
||||
|
||||
#endif
|
|
@ -6,7 +6,7 @@
|
|||
#ifdef USE_WIRINGPI
|
||||
#include <wiringPi.h>
|
||||
#else
|
||||
#include "sd_GPIO.h"
|
||||
#include "GPIO_Pi.h"
|
||||
#endif
|
||||
|
||||
#include "json_messages.h"
|
||||
|
@ -105,6 +105,7 @@ int build_advanced_sprinkler_JSON(char* buffer, int size)
|
|||
int i, day;
|
||||
memset(&buffer[0], 0, size);
|
||||
int length = 0;
|
||||
bool cal = false;
|
||||
/*
|
||||
length += sprintf(buffer+length, "{ \"title\" : \"%s\",\"calendar\" : \"%s\", \"24hdelay\" : \"%s\", \"allz\" : \"%s\", \"#zones\" : %d, \"24hdelay-offtime\" : %li",
|
||||
_sdconfig_.name,
|
||||
|
@ -146,8 +147,9 @@ int build_advanced_sprinkler_JSON(char* buffer, int size)
|
|||
|
||||
for (day=0; day <= 6; day++) {
|
||||
if (_sdconfig_.cron[day].hour >= 0 && _sdconfig_.cron[day].minute >= 0) {
|
||||
cal = true;
|
||||
length += sprintf(buffer+length, "\"day %d\" : { \"start time\" : \"%.2d:%.2d\", ",day,_sdconfig_.cron[day].hour,_sdconfig_.cron[day].minute);
|
||||
for (i=0; i < _sdconfig_.zones; i ++) {
|
||||
for (i=1; i < _sdconfig_.zones; i ++) {
|
||||
if (_sdconfig_.cron[day].zruntimes[i] >= 0) {
|
||||
length += sprintf(buffer+length, "\"Zone %d\" : %d,",i+1,_sdconfig_.cron[day].zruntimes[i]);
|
||||
//logMessage(LOG_DEBUG, "Zone %d, length %d limit %d\n",i+1,length,size);
|
||||
|
@ -157,8 +159,11 @@ int build_advanced_sprinkler_JSON(char* buffer, int size)
|
|||
length += sprintf(buffer+length, "},");
|
||||
}
|
||||
}
|
||||
length -= 1;
|
||||
if (cal) {
|
||||
length -= 1;
|
||||
}
|
||||
length += sprintf(buffer+length, "}}");
|
||||
|
||||
|
||||
buffer[length] = '\0';
|
||||
return strlen(buffer);
|
||||
|
|
3447
mongoose.c
3447
mongoose.c
File diff suppressed because it is too large
Load Diff
553
mongoose.h
553
mongoose.h
File diff suppressed because it is too large
Load Diff
168
net_services.c
168
net_services.c
|
@ -9,7 +9,7 @@
|
|||
#ifdef USE_WIRINGPI
|
||||
#include <wiringPi.h>
|
||||
#else
|
||||
#include "sd_GPIO.h"
|
||||
#include "GPIO_Pi.h"
|
||||
#endif
|
||||
|
||||
#include "mongoose.h"
|
||||
|
@ -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) )
|
||||
|
@ -190,7 +191,7 @@ void send_mqtt_msg(struct mg_connection *nc, char *toppic, char *message)
|
|||
//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_INFO, "MQTT: Published id=%d: %s %s\n", msg_id, toppic, 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) {
|
||||
|
@ -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,8 +317,21 @@ void broadcast_sprinklerdactivestate(struct mg_connection *nc)
|
|||
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)
|
||||
|
@ -318,10 +342,12 @@ void broadcast_sprinklerdstate(struct mg_connection *nc)
|
|||
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=0; i <= _sdconfig_.zones ; i++)
|
||||
for (i=(_sdconfig_.master_valve?0:1); i <= _sdconfig_.zones ; i++)
|
||||
{
|
||||
if (is_websocket(c)) {
|
||||
//ws_send(c, data);
|
||||
|
@ -344,6 +370,30 @@ void broadcast_sprinklerdstate(struct mg_connection *nc)
|
|||
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) )) {
|
||||
|
@ -369,6 +419,9 @@ void broadcast_sprinklerdstate(struct mg_connection *nc)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearEventStatus;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -381,7 +434,15 @@ int is_value_ON(char *buf) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, char *buffer, int size, bool *changedOption) {
|
||||
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;
|
||||
|
@ -454,11 +515,12 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
|
|||
logMessage(LOG_WARNING, "Bad request unknown option\n");
|
||||
length = sprintf(buffer, "{ \"error\": \"Bad request unknown option\" }");
|
||||
}
|
||||
*changedOption = true;
|
||||
//*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)
|
||||
if (strncasecmp(buf, "raindelaychance", 15) == 0 )
|
||||
{
|
||||
mg_get_http_var(&http_msg->query_string, "value", buf, buflen);
|
||||
_sdconfig_.precipChanceDelay = atoi(buf);
|
||||
|
@ -478,9 +540,11 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
|
|||
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);
|
||||
|
@ -498,12 +562,17 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
|
|||
//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);
|
||||
|
@ -512,6 +581,8 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
|
|||
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);
|
||||
|
@ -519,11 +590,13 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
|
|||
zone = atoi(buf);
|
||||
mg_get_http_var(&http_msg->query_string, "time", buf, buflen);
|
||||
runtime = atoi(buf);
|
||||
if (zone > 0 && zone <= _sdconfig_.zones && runtime > 0) {
|
||||
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);
|
||||
*changedOption = true;
|
||||
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) {
|
||||
|
@ -567,13 +640,14 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
char buf[bufsize];
|
||||
char *c_type;
|
||||
int size = 0;
|
||||
bool changedOption = false;
|
||||
//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, &changedOption);
|
||||
size = serve_web_request(nc, http_msg, buf, bufsize);
|
||||
c_type = CT_JSON;
|
||||
|
||||
if (size <= 0) {
|
||||
|
@ -584,9 +658,8 @@ void action_web_request(struct mg_connection *nc, struct http_message *http_msg)
|
|||
mg_send(nc, buf, size);
|
||||
//logMessage (LOG_DEBUG, "Web Return %d = '%.*s'\n",size, size, buf);
|
||||
|
||||
if (changedOption)
|
||||
_sdconfig_.eventToUpdateHappened = true;
|
||||
//broadcast_sprinklerdstate(nc);
|
||||
//if (changedOption)
|
||||
// _sdconfig_.eventToUpdateHappened = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -706,46 +779,51 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
|
|||
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;
|
||||
//_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_DEBUG, "MQTT: Enable 24 hour delay %s\n",status==zcON?"YES":"NO");
|
||||
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_NOTICE, "MQTT request to turn Calendar %s\n",status==zcON?"On":"Off");
|
||||
logMessage(LOG_DEBUG, "MQTT request to turn Calendar %s\n",status==zcON?"On":"Off");
|
||||
enable_calendar(status==zcON?true:false);
|
||||
logMessage(LOG_DEBUG, "MQTT: Turning calendar %s\n",status==zcON?"ON":"OFF");
|
||||
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_DEBUG, "MQTT: Cycle all zones %s\n",status==zcON?"ON":"OFF");
|
||||
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_DEBUG, "MQTT: Rain total %.2f\n",v);
|
||||
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_DEBUG, "MQTT: Chance of rain %d%%\n",v);
|
||||
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);
|
||||
logMessage(LOG_DEBUG, "MQTT: Turn zone %d %s\n",zone, status==zcON?"ON":"OFF");
|
||||
} else if (zone == 0 && status == zcOFF && _sdconfig_.currentZone.type != zcNONE) {
|
||||
// request to turn off master will turn off any running zone
|
||||
zc_zone(zcSINGLE, _sdconfig_.currentZone.zone , zcOFF, 0);
|
||||
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;
|
||||
//_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;
|
||||
}
|
||||
|
@ -754,6 +832,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;
|
||||
|
||||
|
@ -764,7 +844,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;
|
||||
|
@ -773,12 +853,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;
|
||||
|
||||
|
@ -814,12 +899,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:
|
||||
|
@ -892,8 +990,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;
|
||||
|
@ -901,9 +999,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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,162 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# ROOT=/nas/data/Development/Raspberry/gpiocrtl/test-install
|
||||
#
|
||||
|
||||
|
||||
BUILD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
SERVICE="sprinklerd"
|
||||
|
||||
BIN="sprinklerd"
|
||||
CFG="sprinklerd.conf"
|
||||
SRV="sprinklerd.service"
|
||||
DEF="sprinklerd"
|
||||
MDNS="sprinklerd.service"
|
||||
|
||||
BINLocation="/usr/local/bin"
|
||||
CFGLocation="/etc"
|
||||
SRVLocation="/etc/systemd/system"
|
||||
DEFLocation="/etc/default"
|
||||
WEBLocation="/var/www/sprinklerd/"
|
||||
MDNSLocation="/etc/avahi/services/"
|
||||
|
||||
function check_cron() {
|
||||
|
||||
# Look for cron running with LSB name support
|
||||
if [[ ! $(pgrep -af cron | grep '\-l') ]]; then
|
||||
# look for cron running
|
||||
if [[ ! $(pgrep -af cron) ]]; then
|
||||
# look for cron installed
|
||||
if [[ ! $(command -v cron) ]]; then
|
||||
echo "Can't find cron, please install"
|
||||
else
|
||||
echo "cron is not running, please start cron"
|
||||
fi
|
||||
else
|
||||
# Cron is running, but not with LSB name support
|
||||
if [ ! -d "/etc/cron.d" ] || [ ! -f "/etc/default/cron" ]; then
|
||||
echo "The version of Cron may not support chron.d, if so the calendar schedule will not work"
|
||||
echo "Please check cron for LSB name support before using calendar schedule feature of $SERVICE"
|
||||
else
|
||||
# Check and see if we can add LSB support
|
||||
#if [ -f "/etc/default/cron" ]; then
|
||||
echo ...
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $(mount | grep " / " | grep "(ro,") ]]; then
|
||||
echo "Root filesystem is readonly, can't install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_cron
|
||||
exit 0
|
||||
|
||||
if [ ! -d "/etc/cron.d" ]; then
|
||||
echo "The version of Cron may not support chron.d, if so the calendar schedule will not work"
|
||||
echo "Please check before starting"
|
||||
else
|
||||
if [ -f "/etc/default/cron" ]; then
|
||||
CD=$(cat /etc/default/cron | grep -v ^# | grep "\-l")
|
||||
if [ -z "$CD" ]; then
|
||||
echo "Please enabled cron.d support, if not the calendar will not work"
|
||||
echo "Edit /etc/default/cron and look for the -l option"
|
||||
fi
|
||||
else
|
||||
echo "Please make sure the version if Cron supports chron.d, if not the calendar schedule will not work"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
if [ "$1" == "uninstall" ] || [ "$1" == "-u" ] || [ "$1" == "remove" ]; then
|
||||
systemctl stop $SERVICE > /dev/null 2>&1
|
||||
systemctl disable $SERVICE > /dev/null 2>&1
|
||||
rm -f $BINLocation/$BIN
|
||||
rm -f $SRVLocation/$SRV
|
||||
rm -f $DEFLocation/$DEF
|
||||
rm -f $MDNSLocation/$MDNS
|
||||
rm -rf $WEBLocation
|
||||
if [ -f $CFGLocation/$CFG ]; then
|
||||
cache=$(cat $CFGLocation/$CFG | grep CACHE | cut -d= -f2 | sed -e 's/^[ \t]*//' | sed -e 's/ *$//')
|
||||
rm -f $cache
|
||||
rm -f $CFGLocation/$CFG
|
||||
fi
|
||||
rm -f "/etc/cron.d/sprinklerd"
|
||||
echo "SprinklerD & configuration removed from system"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Check cron.d options
|
||||
if [ ! -d "/etc/cron.d" ]; then
|
||||
echo "The version of Cron may not support chron.d, if so the calendar will not work"
|
||||
echo "Please check before starting"
|
||||
else
|
||||
if [ -f "/etc/default/cron" ]; then
|
||||
CD=$(cat /etc/default/cron | grep -v ^# | grep "\-l")
|
||||
if [ -z "$CD" ]; then
|
||||
echo "Please enabled cron.d support, if not the calendar will not work"
|
||||
echo "Edit /etc/default/cron and look for the -l option"
|
||||
fi
|
||||
else
|
||||
echo "Please make sure the version if Cron supports chron.d, if not the calendar will not work"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Exit if we can't find systemctl
|
||||
command -v systemctl >/dev/null 2>&1 || { echo "This script needs systemd's systemctl manager, Please check path or install manually" >&2; exit 1; }
|
||||
|
||||
# stop service, hide any error, as the service may not be installed yet
|
||||
systemctl stop $SERVICE > /dev/null 2>&1
|
||||
SERVICE_EXISTS=$(echo $?)
|
||||
|
||||
# copy files to locations, but only copy cfg if it doesn;t already exist
|
||||
|
||||
cp $BUILD/$BIN $BINLocation/$BIN
|
||||
cp $BUILD/$SRV $SRVLocation/$SRV
|
||||
|
||||
if [ -f $CFGLocation/$CFG ]; then
|
||||
echo "Config exists, did not copy new config, you may need to edit existing! $CFGLocation/$CFG"
|
||||
else
|
||||
cp $BUILD/$CFG $CFGLocation/$CFG
|
||||
fi
|
||||
|
||||
if [ -f $DEFLocation/$DEF ]; then
|
||||
echo "Defaults exists, did not copy new defaults to $DEFLocation/$DEF"
|
||||
else
|
||||
cp $BUILD/$DEF.defaults $DEFLocation/$DEF
|
||||
fi
|
||||
|
||||
if [ -f $MDNSLocation/$MDNS ]; then
|
||||
echo "Avahi/mDNS defaults exists, did not copy new defaults to $MDNSLocation/$MDNS"
|
||||
else
|
||||
if [ -d "$MDNSLocation" ]; then
|
||||
cp $BUILD/$MDNS.avahi $MDNSLocation/$MDNS
|
||||
else
|
||||
echo "Avahi/mDNS may not be installed, not copying $MDNSLocation/$MDNS"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -d "$WEBLocation" ]; then
|
||||
mkdir -p $WEBLocation
|
||||
fi
|
||||
|
||||
cp -r $BUILD/../web/* $WEBLocation
|
||||
|
||||
systemctl enable $SERVICE
|
||||
systemctl daemon-reload
|
||||
|
||||
if [ $SERVICE_EXISTS -eq 0 ]; then
|
||||
echo "Starting daemon $SERVICE"
|
||||
systemctl start $SERVICE
|
||||
fi
|
||||
|
Binary file not shown.
|
@ -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
|
||||
|
@ -32,7 +35,7 @@ LOG_LEVEL = NOTICE
|
|||
# PUD_UP 2
|
||||
|
||||
#NAME = name of zone
|
||||
#GPIO_PIN = GPIO Pin # This is the GPIO# not the pin#, so (17 = GPIO17 = Pin 11) or another example (5 = GPIO5 = Pin 29)
|
||||
#GPIO_PIN = GPIO # This is the GPIO# not the pin#, so (17 = GPIO17 = Pin 11) or another example (5 = GPIO5 = Pin 29)
|
||||
#WPI_PIN = use instead of GPIO_PIN if compiled with USE_WIRINGPI flag, This is WiringPi Pin#, not Raspberry Pi board pin#
|
||||
#GPIO_PULL_UPDN = setup pull up pull down resistor PUD_OFF|PUD_DOWN|PUD_UP
|
||||
#GPIO_ON_STATE = State GPIO reads when relay for zone is on. HIGH or LOW 1 or 0
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
[SPRINKLERD]
|
||||
PORT=80
|
||||
NAME=My Sprinklers
|
||||
DOCUMENTROOT = /nas/data/Development/Raspberry/SprinklerD/web/
|
||||
CACHE = /var/cache/sprinklerd.cache
|
||||
# The log level. [DEBUG, INFO, NOTICE, WARNING, ERROR]
|
||||
#LOG_LEVEL = DEBUG
|
||||
LOG_LEVEL = NOTICE
|
||||
|
||||
# mqtt stuff
|
||||
MQTT_ADDRESS = trident:1883
|
||||
#MQTT_USER = someusername
|
||||
#MQTT_PASSWD = somepassword
|
||||
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_RAINSENSOR = 48
|
||||
|
||||
# Options for the below ZONE and GPIO configuration
|
||||
#
|
||||
# LOW 0
|
||||
# HIGH 1
|
||||
#
|
||||
# PUD_OFF 0
|
||||
# PUD_DOWN 1
|
||||
# PUD_UP 2
|
||||
|
||||
#NAME = name of zone
|
||||
#GPIO_PIN = GPIO Pin # This is WiringPi Pin#, not Raspberry Pi board pin#.
|
||||
#WPI_PIN = use instead of GPIO_PIN if compiled with USE_WIRINGPI flag
|
||||
#GPIO_PULL_UPDN = setup pull up pull down resistor PUD_OFF|PUD_DOWN|PUD_UP
|
||||
#GPIO_ON_STATE = State GPIO reads when relay for zone is on. HIGH or LOW 1 or 0
|
||||
#DOMOTICZ_IDX = Domoticz IDX 0 or remove entry if you don;t use Domoticz (only if you use domoticz)
|
||||
#MASTER_VALVE = YES=1 NO=0 // turn on with any zone
|
||||
|
||||
# Don't use ZONE:0 for anything other than master valve, if you don't have a master valve simply delete it and start from ZONE:1
|
||||
[ZONE]
|
||||
[ZONE:0]
|
||||
NAME=Master Valve
|
||||
MASTER_VALVE=1
|
||||
GPIO_PIN=17
|
||||
WPI_PIN=0
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
|
||||
[ZONE:1]
|
||||
NAME=Island
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=18
|
||||
WPI_PIN=1
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=200
|
||||
|
||||
[ZONE:2]
|
||||
NAME=Driveway
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=27
|
||||
WPI_PIN=2
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=201
|
||||
|
||||
[ZONE:3]
|
||||
NAME=Diningroom Flowerbeds
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=22
|
||||
WPI_PIN=3
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=202
|
||||
|
||||
[ZONE:4]
|
||||
NAME=Front Flowerbeds
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=23
|
||||
WPI_PIN=4
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=203
|
||||
|
||||
[ZONE:5]
|
||||
NAME=Backgarden Left
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=24
|
||||
WPI_PIN=5
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=204
|
||||
|
||||
[ZONE:6]
|
||||
NAME=Backgarden Right
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=25
|
||||
WPI_PIN=6
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=205
|
||||
|
||||
[ZONE:7]
|
||||
NAME=Garage Flowerbeds
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=5
|
||||
WPI_PIN=21
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=206
|
||||
|
||||
[ZONE:8]
|
||||
NAME=Golfcart path
|
||||
DEFAULT_RUNTIME=10
|
||||
GPIO_PIN=6
|
||||
WPI_PIN=22
|
||||
GPIO_PULL_UPDN=1
|
||||
GPIO_ON_STATE=0
|
||||
DOMOTICZ_IDX=207
|
||||
|
||||
#
|
||||
# This is for future support of sensors, not implimented yet
|
||||
#
|
||||
#PIN
|
||||
#NAME name
|
||||
#PIN_MODE Setup as input or output
|
||||
#PULL_UPDN setup pull up pull down resistor NONE|PUD_OFF|PUD_DOWN|PUD_UP
|
||||
#TRIGGER_EVENT_ON trigger_event on NONE|INT_EDGE_SETUP|INT_EDGE_FALLING|INT_EDGE_RISING|INT_EDGE_BOTH
|
||||
#TRIGGER_EVENT_STATE trigger_event_received_state LOW|HIGH|BOTH
|
||||
#COMMAND triggered_event_runcmd = external command to run
|
||||
#DOMOTICZ_IDX Domoticz IDX
|
||||
|
||||
[GPIO]
|
||||
[GPIO:1]
|
||||
NAME=Rain Sensor
|
||||
GPIO_PIN=4
|
||||
WPI_PIN=7
|
||||
PIN_MODE=0
|
||||
#PULL_UPDN=0
|
||||
TRIGGER_EVENT_ON=3
|
||||
COMMAND_HIGH=/usr/bin/curl -s -o /dev/null 'http://localhost?type=option&option=24hdelay&state=on'
|
||||
COMMAND_LOW=/usr/bin/curl -s -o /dev/null 'http://localhost?type=option&option=24hdelay&state=off'
|
|
@ -15,6 +15,26 @@
|
|||
#include "utils.h"
|
||||
#include "sd_GPIO.h"
|
||||
|
||||
const char *_piModelNames [16] =
|
||||
{
|
||||
"Model A", // 0
|
||||
"Model B", // 1
|
||||
"Model A+", // 2
|
||||
"Model B+", // 3
|
||||
"Pi 2", // 4
|
||||
"Alpha", // 5
|
||||
"CM", // 6
|
||||
"Unknown07", // 07
|
||||
"Pi 3", // 08
|
||||
"Pi Zero", // 09
|
||||
"CM3", // 10
|
||||
"Unknown11", // 11
|
||||
"Pi Zero-W", // 12
|
||||
"Pi 3+", // 13
|
||||
"Unknown New 14", // 14
|
||||
"Unknown New 15", // 15
|
||||
} ;
|
||||
|
||||
static bool _ever = false;
|
||||
void gpioDelay (unsigned int howLong);
|
||||
|
||||
|
@ -68,22 +88,26 @@ int piBoardId ()
|
|||
logMessage (LOG_ERR, "piBoardId: Unknown \"Revision\" line (no hex digit at start of revision)") ;
|
||||
|
||||
revision = (unsigned int)strtol (c, NULL, 16) ; // Hex number with no leading 0x
|
||||
|
||||
|
||||
// Check for new way:
|
||||
|
||||
if ((revision & (1 << 23)) != 0) // New way
|
||||
{/*
|
||||
bRev = (revision & (0x0F << 0)) >> 0 ;*/
|
||||
bType = (revision & (0xFF << 4)) >> 4 ;
|
||||
return bType;
|
||||
/*
|
||||
bProc = (revision & (0x0F << 12)) >> 12 ; // Not used for now.
|
||||
bMfg = (revision & (0x0F << 16)) >> 16 ;
|
||||
bMem = (revision & (0x07 << 20)) >> 20 ;
|
||||
bWarranty = (revision & (0x03 << 24)) != 0 ;
|
||||
*/
|
||||
|
||||
logMessage (LOG_DEBUG, "piBoard Model: %s\n", _piModelNames[bType]) ;
|
||||
|
||||
return bType;
|
||||
}
|
||||
|
||||
logMessage (LOG_ERR, "piBoard Model: UNKNOWN\n");
|
||||
return PI_MODEL_UNKNOWN;
|
||||
}
|
||||
|
||||
|
@ -93,11 +117,15 @@ bool gpioSetup() {
|
|||
|
||||
switch ( piBoardId() )
|
||||
{
|
||||
case PI_MODEL_A: case PI_MODEL_B:
|
||||
case PI_MODEL_AP: case PI_MODEL_BP:
|
||||
case PI_ALPHA: case PI_MODEL_CM:
|
||||
case PI_MODEL_ZERO: case PI_MODEL_ZERO_W:
|
||||
case PI_MODEL_UNKNOWN:
|
||||
case PI_MODEL_A:
|
||||
case PI_MODEL_B:
|
||||
case PI_MODEL_AP:
|
||||
case PI_MODEL_BP:
|
||||
case PI_ALPHA:
|
||||
case PI_MODEL_CM:
|
||||
case PI_MODEL_ZERO:
|
||||
case PI_MODEL_ZERO_W:
|
||||
//case PI_MODEL_UNKNOWN:
|
||||
piGPIObase = (GPIO_BASE_P1 + GPIO_OFFSET);
|
||||
break ;
|
||||
|
||||
|
@ -133,6 +161,9 @@ bool gpioSetup() {
|
|||
int pinMode(unsigned gpio, unsigned mode) {
|
||||
int reg, shift;
|
||||
|
||||
if (! validGPIO(gpio))
|
||||
return -1;
|
||||
|
||||
reg = gpio / 10;
|
||||
shift = (gpio % 10) * 3;
|
||||
|
||||
|
@ -144,6 +175,9 @@ int pinMode(unsigned gpio, unsigned mode) {
|
|||
int getPinMode(unsigned gpio) {
|
||||
int reg, shift;
|
||||
|
||||
if (! validGPIO(gpio))
|
||||
return -1;
|
||||
|
||||
reg = gpio / 10;
|
||||
shift = (gpio % 10) * 3;
|
||||
|
||||
|
@ -153,6 +187,9 @@ int getPinMode(unsigned gpio) {
|
|||
int digitalRead(unsigned gpio) {
|
||||
unsigned bank, bit;
|
||||
|
||||
if (! validGPIO(gpio))
|
||||
return -1;
|
||||
|
||||
bank = gpio >> 5;
|
||||
|
||||
bit = (1 << (gpio & 0x1F));
|
||||
|
@ -166,6 +203,9 @@ int digitalRead(unsigned gpio) {
|
|||
int digitalWrite(unsigned gpio, unsigned level) {
|
||||
unsigned bank, bit;
|
||||
|
||||
if (! validGPIO(gpio))
|
||||
return -1;
|
||||
|
||||
bank = gpio >> 5;
|
||||
|
||||
bit = (1 << (gpio & 0x1F));
|
||||
|
@ -175,13 +215,16 @@ int digitalWrite(unsigned gpio, unsigned level) {
|
|||
else
|
||||
*(_gpioReg + GPSET0 + bank) = bit;
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
int setPullUpDown(unsigned gpio, unsigned pud)
|
||||
{
|
||||
unsigned bank, bit;
|
||||
|
||||
if (! validGPIO(gpio))
|
||||
return -1;
|
||||
|
||||
bank = gpio >> 5;
|
||||
|
||||
bit = (1 << (gpio & 0x1F));
|
||||
|
@ -212,6 +255,9 @@ int pinMode (unsigned pin, unsigned mode)
|
|||
{
|
||||
//static const char s_directions_str[] = "in\0out\0";
|
||||
|
||||
if (! validGPIO(pin))
|
||||
return -1;
|
||||
|
||||
char path[SYSFS_PATH_MAX];
|
||||
int fd;
|
||||
/*
|
||||
|
@ -246,6 +292,9 @@ int getPinMode(unsigned gpio) {
|
|||
char value_str[SYSFS_READ_MAX];
|
||||
int fd;
|
||||
|
||||
if (! validGPIO(gpio))
|
||||
return -1;
|
||||
|
||||
snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/direction", gpio);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (-1 == fd) {
|
||||
|
@ -274,6 +323,9 @@ int digitalRead (unsigned pin)
|
|||
char path[SYSFS_PATH_MAX];
|
||||
char value_str[SYSFS_READ_MAX];
|
||||
int fd;
|
||||
|
||||
if (! validGPIO(pin))
|
||||
return -1;
|
||||
|
||||
snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/value", pin);
|
||||
fd = open(path, O_RDONLY);
|
||||
|
@ -301,6 +353,9 @@ int digitalWrite (unsigned pin, unsigned value)
|
|||
|
||||
char path[SYSFS_PATH_MAX];
|
||||
int fd;
|
||||
|
||||
if (! validGPIO(pin))
|
||||
return -1;
|
||||
|
||||
snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/value", pin);
|
||||
fd = open(path, O_WRONLY);
|
||||
|
@ -353,6 +408,9 @@ bool pinExport(unsigned pin)
|
|||
ssize_t bytes_written;
|
||||
int fd;
|
||||
|
||||
if (! validGPIO(pin))
|
||||
return -1;
|
||||
|
||||
fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
//fprintf(stderr, "Failed to open export for writing!\n");
|
||||
|
@ -372,6 +430,9 @@ bool pinUnexport(unsigned pin)
|
|||
ssize_t bytes_written;
|
||||
int fd;
|
||||
|
||||
if (! validGPIO(pin))
|
||||
return -1;
|
||||
|
||||
fd = open("/sys/class/gpio/unexport", O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
//fprintf(stderr, "Failed to open unexport for writing!\n");
|
||||
|
@ -392,6 +453,9 @@ bool edgeSetup (unsigned pin, unsigned value)
|
|||
char path[SYSFS_PATH_MAX];
|
||||
int fd;
|
||||
|
||||
if (! validGPIO(pin))
|
||||
return -1;
|
||||
|
||||
snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/edge", pin);
|
||||
fd = open(path, O_WRONLY);
|
||||
if (-1 == fd) {
|
||||
|
@ -457,7 +521,7 @@ void gpioShutdown() {
|
|||
|
||||
for (i=0; i< MAX_FDS; i++) {
|
||||
if (_sysFds[i] != -1) {
|
||||
printf("Closing fd\n");
|
||||
//printf("Closing fd %d\n",i);
|
||||
close(_sysFds[i]);
|
||||
_sysFds[i] = -1;
|
||||
} else {
|
||||
|
@ -539,6 +603,10 @@ bool registerGPIOinterrupt(int pin, int mode, void (*function)(void *args), void
|
|||
{
|
||||
pthread_t threadId ;
|
||||
struct threadGPIOinterupt stuff;
|
||||
|
||||
if (! validGPIO(pin))
|
||||
return false;
|
||||
|
||||
// Check it's exported
|
||||
if (! isExported(pin))
|
||||
pinExport(pin);
|
||||
|
@ -570,33 +638,22 @@ bool registerGPIOinterrupt(int pin, int mode, void (*function)(void *args), void
|
|||
}
|
||||
|
||||
|
||||
//#define TEST_HARNESS
|
||||
|
||||
#define GPIO_OFF 0x00005000 /* Offset from IO_START to the GPIO reg's. */
|
||||
|
||||
/* IO_START and IO_BASE are defined in hardware.h */
|
||||
|
||||
#define GPIO_START (IO_START_2 + GPIO_OFF) /* Physical addr of the GPIO reg. */
|
||||
#define GPIO_BASE_NEW (IO_BASE_2 + GPIO_OFF) /* Virtual addr of the GPIO reg. */
|
||||
|
||||
|
||||
#ifdef TEST_HARNESS
|
||||
#if defined(TEST_HARNESS) || defined(GPIO_MONITOR) || defined(GPIO_RW)
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
void *myCallBack(void * args) {
|
||||
printf("Ping\n");
|
||||
//struct threadGPIOinterupt *stuff = (struct threadGPIOinterupt *) args;
|
||||
//printf("Pin is %d\n",stuff->pin);
|
||||
}
|
||||
int _log_level = LOG_DEBUG;
|
||||
|
||||
void logMessage(int level, char *format, ...)
|
||||
{
|
||||
//if (_debuglog_ == false && level == LOG_DEBUG)
|
||||
// return;
|
||||
if (level > _log_level)
|
||||
return;
|
||||
|
||||
char buffer[256];
|
||||
va_list args;
|
||||
|
@ -618,9 +675,134 @@ void displayLastSystemError (const char *on_what)
|
|||
|
||||
}
|
||||
|
||||
#endif //TEST_HARNESS || GPIO_MONITOR
|
||||
|
||||
#ifdef GPIO_RW
|
||||
|
||||
void errorParms()
|
||||
{
|
||||
printf("Missing Parameters:-\n\t[read|write] pin <value>\n\tgpio write 17 1\n");
|
||||
exit(1);
|
||||
}
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
bool isWrite=false;
|
||||
int pin = 0;
|
||||
int value = 0;
|
||||
|
||||
_log_level = LOG_ERR;
|
||||
|
||||
if (argc < 3) {
|
||||
errorParms();
|
||||
}
|
||||
|
||||
if (strcmp (argv[1], "read") == 0)
|
||||
{
|
||||
isWrite = false;
|
||||
} else if (strcmp (argv[1], "write") == 0) {
|
||||
isWrite = true;
|
||||
if (argc < 4)
|
||||
errorParms();
|
||||
} else {
|
||||
errorParms();
|
||||
}
|
||||
|
||||
pin = atoi(argv[2]);
|
||||
|
||||
if (! gpioSetup()) {
|
||||
logMessage (LOG_ERR, "Failed to setup GPIO\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isWrite) {
|
||||
value = atoi(argv[3]);
|
||||
int pmode = getPinMode(pin);
|
||||
pinMode (pin, OUTPUT);
|
||||
digitalWrite(pin, value);
|
||||
//if (pmode != OUTPUT)
|
||||
// pinMode (pin, pmode);
|
||||
}
|
||||
|
||||
printf ("%d\n", digitalRead(pin));
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GPIO_MONITOR
|
||||
|
||||
bool FOREVER = true;
|
||||
|
||||
void intHandler(int signum) {
|
||||
static int called=0;
|
||||
logMessage (LOG_INFO, "Stopping! - signel(%d)\n",signum);
|
||||
gpioShutdown();
|
||||
FOREVER = false;
|
||||
called++;
|
||||
if (called > 3)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void event_trigger (int pin)
|
||||
{
|
||||
printf("Pin %d triggered, state=%d\n",pin,digitalRead(pin));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
int i;
|
||||
|
||||
if (! gpioSetup()) {
|
||||
logMessage (LOG_ERR, "Failed to setup GPIO\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
signal(SIGINT, intHandler);
|
||||
signal(SIGTERM, intHandler);
|
||||
signal(SIGSEGV, intHandler);
|
||||
|
||||
for (i=GPIO_MIN; i <= GPIO_MAX; i++) {
|
||||
printf ("Pin %d is %d\n", i, digitalRead(i));
|
||||
if (registerGPIOinterrupt (i, INT_EDGE_BOTH, (void *)&event_trigger, (void *)i) != true)
|
||||
{
|
||||
displayLastSystemError ("Unable to set interrupt handler for specified pin, exiting");
|
||||
gpioShutdown();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
while(FOREVER) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif //GPIO_MONITOR
|
||||
|
||||
//#define TEST_HARNESS
|
||||
|
||||
#ifdef TEST_HARNESS
|
||||
|
||||
#define GPIO_OFF 0x00005000 /* Offset from IO_START to the GPIO reg's. */
|
||||
|
||||
/* IO_START and IO_BASE are defined in hardware.h */
|
||||
|
||||
#define GPIO_START (IO_START_2 + GPIO_OFF) /* Physical addr of the GPIO reg. */
|
||||
#define GPIO_BASE_NEW (IO_BASE_2 + GPIO_OFF) /* Virtual addr of the GPIO reg. */
|
||||
|
||||
|
||||
void *myCallBack(void * args) {
|
||||
printf("Ping\n");
|
||||
//struct threadGPIOinterupt *stuff = (struct threadGPIOinterupt *) args;
|
||||
//printf("Pin is %d\n",stuff->pin);
|
||||
}
|
||||
|
||||
#define PIN 17
|
||||
#define POUT 27
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
int repeat = 3;
|
||||
|
||||
// if (-1 == GPIOExport(POUT) || -1 == GPIOExport(PIN))
|
|
@ -11,6 +11,19 @@
|
|||
#include <syslog.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// check number is between 2 and 27
|
||||
#ifndef USE_WIRINGPI
|
||||
#define GPIO_MIN 2
|
||||
#define GPIO_MAX 27
|
||||
#else // WiringPI valid numbers
|
||||
#define GPIO_MIN 0
|
||||
#define GPIO_MAX 30
|
||||
#endif
|
||||
|
||||
#define validGPIO(X) ((X) <= (GPIO_MAX) ? ( ((X) >= (GPIO_MIN) ? (1) : (0)) ) : (0))
|
||||
|
||||
#ifndef USE_WIRINGPI // Don't include anything below this line if using wiringpi.
|
||||
|
||||
#define INPUT 0
|
||||
#define OUTPUT 1
|
||||
|
||||
|
@ -65,10 +78,10 @@
|
|||
#define PI_MODEL_ZERO 9
|
||||
#define PI_MODEL_CM3 10
|
||||
#define PI_MODEL_ZERO_W 12
|
||||
#define PI_MODEL_3P 13
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//#ifndef SYSFS_MODE
|
||||
bool pinExport(unsigned pin);
|
||||
bool pinUnexport(unsigned pin);
|
||||
|
@ -91,4 +104,5 @@ bool digitalWrite (int pin, int value);
|
|||
#endif
|
||||
*/
|
||||
|
||||
#endif /* WiringPI */
|
||||
#endif /* _SD_GPIO_H_ */
|
50
sd_cron.c
50
sd_cron.c
|
@ -15,10 +15,14 @@ bool setTodayChanceOfRain(int percent)
|
|||
{
|
||||
logMessage(LOG_DEBUG, "Set today's chance of rain = %d\n",percent);
|
||||
if (percent <= 100 && percent >= 0) {
|
||||
//_sdconfig_.eventToUpdateHappened = true;
|
||||
setEventRainProbability;
|
||||
_sdconfig_.todayRainChance = percent;
|
||||
if (_sdconfig_.precipChanceDelay > 0 && _sdconfig_.todayRainChance >= _sdconfig_.precipChanceDelay) {
|
||||
//enable_delay24h(true);
|
||||
reset_delay24h_time(0); // will add 24hours or reset
|
||||
reset_delay24h_time(0); // will add 24hours or turn on and set delay to 24hours
|
||||
} else {
|
||||
enable_delay24h(false); // Turn off rain delay
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -28,10 +32,12 @@ bool setTodayChanceOfRain(int percent)
|
|||
|
||||
bool setTodayRainTotal(float rain)
|
||||
{
|
||||
if (_sdconfig_.todayRainTotal == rain)
|
||||
if (_sdconfig_.todayRainTotal == rain && rain != 0)
|
||||
return true;
|
||||
|
||||
_sdconfig_.todayRainTotal = rain;
|
||||
|
||||
_sdconfig_.todayRainTotal = rain;
|
||||
//_sdconfig_.eventToUpdateHappened = true;
|
||||
setEventRainTotal;
|
||||
|
||||
logMessage(LOG_DEBUG, "Today's rain total = %f\n",_sdconfig_.todayRainTotal);
|
||||
|
||||
|
@ -64,7 +70,8 @@ bool check_delay24h()
|
|||
void enable_calendar(bool state)
|
||||
{
|
||||
if (_sdconfig_.calendar != state) {
|
||||
_sdconfig_.eventToUpdateHappened = true;
|
||||
//_sdconfig_.eventToUpdateHappened = true;
|
||||
setEventStatus;
|
||||
_sdconfig_.calendar = state;
|
||||
logMessage(LOG_NOTICE, "Turning %s calendar\n",state==true?"on":"off");
|
||||
} else {
|
||||
|
@ -75,7 +82,8 @@ void enable_calendar(bool state)
|
|||
void enable_delay24h(bool state)
|
||||
{
|
||||
if (_sdconfig_.delay24h != state) {
|
||||
_sdconfig_.eventToUpdateHappened = true;
|
||||
//_sdconfig_.eventToUpdateHappened = true;
|
||||
setEventStatus;
|
||||
|
||||
_sdconfig_.delay24h = state;
|
||||
if (state) {
|
||||
|
@ -96,7 +104,8 @@ void enable_delay24h(bool state)
|
|||
void reset_delay24h_time(unsigned long dtime)
|
||||
{
|
||||
if (_sdconfig_.delay24h != true) {
|
||||
_sdconfig_.eventToUpdateHappened = true;
|
||||
//_sdconfig_.eventToUpdateHappened = true;
|
||||
setEventStatus;
|
||||
}
|
||||
|
||||
time_t now;
|
||||
|
@ -136,6 +145,7 @@ void write_cron() {
|
|||
int hour;
|
||||
int day;
|
||||
int zone;
|
||||
int rb4i;
|
||||
|
||||
bool fs = remount_root_ro(false);
|
||||
|
||||
|
@ -155,7 +165,8 @@ void write_cron() {
|
|||
hour = _sdconfig_.cron[day].hour;
|
||||
for (zone=0; zone < _sdconfig_.zones; zone ++) {
|
||||
if (_sdconfig_.cron[day].zruntimes[zone] > 0) {
|
||||
fprintf(fp, "%d %d * * %d root /usr/bin/curl -s -o /dev/null 'localhost?type=cron&zone=%d&runtime=%d&state=on'\n",min,hour,day,zone+1,_sdconfig_.cron[day].zruntimes[zone]);
|
||||
fprintf(fp, "%d %d * * %d root /usr/bin/curl -s -o /dev/null 'localhost:%s?type=cron&zone=%d&runtime=%d&state=on'\n",min,hour,day,_sdconfig_.socket_port,zone+1,_sdconfig_.cron[day].zruntimes[zone]);
|
||||
//fprintf(fp, "%d %d * * %d root /usr/bin/curl -s -o /dev/null 'localhost?type=cron&zone=%d&runtime=%d&state=on'\n",min,hour,day,zone+1,_sdconfig_.cron[day].zruntimes[zone]);
|
||||
min = min + _sdconfig_.cron[day].zruntimes[zone];
|
||||
// NSF Check if to incrument hour.
|
||||
if (min >= 60) {
|
||||
|
@ -169,9 +180,28 @@ void write_cron() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (rb4i=0; rb4i<_sdconfig_.runBeforeCmds; rb4i++) {
|
||||
if (_sdconfig_.cron[day].minute < _sdconfig_.runBeforeCmd[rb4i].mins) {
|
||||
fprintf(fp, "%d %d * * %d root %s\n",
|
||||
(60 - (_sdconfig_.runBeforeCmd[rb4i].mins - _sdconfig_.cron[day].minute)),
|
||||
(_sdconfig_.cron[day].hour - 1),
|
||||
day,
|
||||
_sdconfig_.runBeforeCmd[rb4i].command);
|
||||
} else {
|
||||
fprintf(fp, "%d %d * * %d root %s\n",
|
||||
(_sdconfig_.cron[day].minute - _sdconfig_.runBeforeCmd[rb4i].mins),
|
||||
_sdconfig_.cron[day].hour,
|
||||
day,
|
||||
_sdconfig_.runBeforeCmd[rb4i].command);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(fp, "0 0 * * * root /usr/bin/curl -s -o /dev/null 'localhost?type=sensor&sensor=chanceofrain&value=0'\n");
|
||||
fprintf(fp, "0 0 * * * root /usr/bin/curl -s -o /dev/null 'localhost?type=sensor&sensor=raintotal&value=0'\n");
|
||||
|
||||
|
||||
|
||||
fprintf(fp, "0 0 * * * root /usr/bin/curl -s -o /dev/null 'localhost:%s?type=sensor&sensor=chanceofrain&value=0'\n",_sdconfig_.socket_port);
|
||||
fprintf(fp, "0 0 * * * root /usr/bin/curl -s -o /dev/null 'localhost:%s?type=sensor&sensor=raintotal&value=0'\n",_sdconfig_.socket_port);
|
||||
fprintf(fp, "#***** AUTO GENERATED DO NOT EDIT *****\n");
|
||||
fclose(fp);
|
||||
|
||||
|
|
165
sprinkler.c
165
sprinkler.c
|
@ -10,10 +10,12 @@
|
|||
#ifdef USE_WIRINGPI
|
||||
#define WIRINGPI_CODES 1
|
||||
#include <wiringPi.h>
|
||||
#else
|
||||
#include "sd_GPIO.h"
|
||||
//#else
|
||||
// #include "sd_GPIO.h"
|
||||
#endif
|
||||
|
||||
#include "GPIO_Pi.h"
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
@ -39,31 +41,31 @@ void intHandler(int signum);
|
|||
//extern _sdconfig_;
|
||||
#ifdef USE_WIRINGPI
|
||||
/* BS functions due to limitations in wiringpi of not supporting a pointer in callback event */
|
||||
// Let's hope no one wants mroe than 24 zones
|
||||
void event_trigger_0 (void) { event_trigger (&_sdconfig_.zonecfg[0]) ; }
|
||||
void event_trigger_1 (void) { event_trigger (&_sdconfig_.zonecfg[1]) ; }
|
||||
void event_trigger_2 (void) { event_trigger (&_sdconfig_.zonecfg[2]) ; }
|
||||
void event_trigger_3 (void) { event_trigger (&_sdconfig_.zonecfg[3]) ; }
|
||||
void event_trigger_4 (void) { event_trigger (&_sdconfig_.zonecfg[4]) ; }
|
||||
void event_trigger_5 (void) { event_trigger (&_sdconfig_.zonecfg[5]) ; }
|
||||
void event_trigger_6 (void) { event_trigger (&_sdconfig_.zonecfg[6]) ; }
|
||||
void event_trigger_7 (void) { event_trigger (&_sdconfig_.zonecfg[7]) ; }
|
||||
void event_trigger_8 (void) { event_trigger (&_sdconfig_.zonecfg[8]) ; }
|
||||
void event_trigger_9 (void) { event_trigger (&_sdconfig_.zonecfg[9]) ; }
|
||||
void event_trigger_10 (void) { event_trigger (&_sdconfig_.zonecfg[10]) ; }
|
||||
void event_trigger_11 (void) { event_trigger (&_sdconfig_.zonecfg[11]) ; }
|
||||
void event_trigger_12 (void) { event_trigger (&_sdconfig_.zonecfg[12]) ; }
|
||||
void event_trigger_13 (void) { event_trigger (&_sdconfig_.zonecfg[13]) ; }
|
||||
void event_trigger_14 (void) { event_trigger (&_sdconfig_.zonecfg[14]) ; }
|
||||
void event_trigger_15 (void) { event_trigger (&_sdconfig_.zonecfg[15]) ; }
|
||||
void event_trigger_16 (void) { event_trigger (&_sdconfig_.zonecfg[16]) ; }
|
||||
void event_trigger_17 (void) { event_trigger (&_sdconfig_.zonecfg[17]) ; }
|
||||
void event_trigger_18 (void) { event_trigger (&_sdconfig_.zonecfg[18]) ; }
|
||||
void event_trigger_19 (void) { event_trigger (&_sdconfig_.zonecfg[19]) ; }
|
||||
void event_trigger_20 (void) { event_trigger (&_sdconfig_.zonecfg[20]) ; }
|
||||
void event_trigger_21 (void) { event_trigger (&_sdconfig_.zonecfg[21]) ; }
|
||||
void event_trigger_22 (void) { event_trigger (&_sdconfig_.zonecfg[22]) ; }
|
||||
void event_trigger_23 (void) { event_trigger (&_sdconfig_.zonecfg[23]) ; }
|
||||
// Let's hope no one wants mroe than 24 inputs
|
||||
void event_trigger_0 (void) { event_trigger (&_sdconfig_.inputcfg[0]) ; }
|
||||
void event_trigger_1 (void) { event_trigger (&_sdconfig_.inputcfg[1]) ; }
|
||||
void event_trigger_2 (void) { event_trigger (&_sdconfig_.inputcfg[2]) ; }
|
||||
void event_trigger_3 (void) { event_trigger (&_sdconfig_.inputcfg[3]) ; }
|
||||
void event_trigger_4 (void) { event_trigger (&_sdconfig_.inputcfg[4]) ; }
|
||||
void event_trigger_5 (void) { event_trigger (&_sdconfig_.inputcfg[5]) ; }
|
||||
void event_trigger_6 (void) { event_trigger (&_sdconfig_.inputcfg[6]) ; }
|
||||
void event_trigger_7 (void) { event_trigger (&_sdconfig_.inputcfg[7]) ; }
|
||||
void event_trigger_8 (void) { event_trigger (&_sdconfig_.inputcfg[8]) ; }
|
||||
void event_trigger_9 (void) { event_trigger (&_sdconfig_.inputcfg[9]) ; }
|
||||
void event_trigger_10 (void) { event_trigger (&_sdconfig_.inputcfg[10]) ; }
|
||||
void event_trigger_11 (void) { event_trigger (&_sdconfig_.inputcfg[11]) ; }
|
||||
void event_trigger_12 (void) { event_trigger (&_sdconfig_.inputcfg[12]) ; }
|
||||
void event_trigger_13 (void) { event_trigger (&_sdconfig_.inputcfg[13]) ; }
|
||||
void event_trigger_14 (void) { event_trigger (&_sdconfig_.inputcfg[14]) ; }
|
||||
void event_trigger_15 (void) { event_trigger (&_sdconfig_.inputcfg[15]) ; }
|
||||
void event_trigger_16 (void) { event_trigger (&_sdconfig_.inputcfg[16]) ; }
|
||||
void event_trigger_17 (void) { event_trigger (&_sdconfig_.inputcfg[17]) ; }
|
||||
void event_trigger_18 (void) { event_trigger (&_sdconfig_.inputcfg[18]) ; }
|
||||
void event_trigger_19 (void) { event_trigger (&_sdconfig_.inputcfg[19]) ; }
|
||||
void event_trigger_20 (void) { event_trigger (&_sdconfig_.inputcfg[20]) ; }
|
||||
void event_trigger_21 (void) { event_trigger (&_sdconfig_.inputcfg[21]) ; }
|
||||
void event_trigger_22 (void) { event_trigger (&_sdconfig_.inputcfg[22]) ; }
|
||||
void event_trigger_23 (void) { event_trigger (&_sdconfig_.inputcfg[23]) ; }
|
||||
|
||||
|
||||
typedef void (*FunctionCallback)();
|
||||
|
@ -139,14 +141,15 @@ int main (int argc, char *argv[])
|
|||
else
|
||||
_sdconfig_.log_level = LOG_INFO;
|
||||
|
||||
readCfg(cfg);
|
||||
|
||||
logMessage(LOG_NOTICE,"Starting %s version %s\n",argv[0],SD_VERSION);
|
||||
|
||||
readCfg(cfg);
|
||||
|
||||
_sdconfig_.calendar = true;
|
||||
_sdconfig_.currentZone.type = zcNONE;
|
||||
_sdconfig_.cron_update = 0;
|
||||
_sdconfig_.eventToUpdateHappened = false;
|
||||
//_sdconfig_.eventToUpdateHappened = false;
|
||||
_sdconfig_.updateEventMask = 0;
|
||||
read_cron();
|
||||
read_cache();
|
||||
|
||||
|
@ -250,6 +253,10 @@ void main_loop ()
|
|||
logMessage(LOG_DEBUG, "Setting up GPIO\n");
|
||||
|
||||
gpioSetup();
|
||||
if (! gpioSetup()) {
|
||||
logMessage(LOG_ERR, "Failed to setup GPIO\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i=(_sdconfig_.master_valve?0:1); i <= _sdconfig_.zones ; i++)
|
||||
{
|
||||
|
@ -264,27 +271,23 @@ void main_loop ()
|
|||
pinMode (_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].input_output);
|
||||
if ( _sdconfig_.zonecfg[i].startup_state != -1)
|
||||
digitalWrite(_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].startup_state);
|
||||
/*
|
||||
// We actually don't need to register a interupt handeler for outputs. But we will for inputs, so leave this here for future use.
|
||||
if (registerGPIOinterrupt (_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].receive_mode, (void *)&event_trigger, (void *)&_sdconfig_.zonecfg[i]) != true)
|
||||
|
||||
logMessage (LOG_DEBUG, "Set GPIO %d to %s\n", _sdconfig_.zonecfg[i].pin,(_sdconfig_.zonecfg[i].input_output==OUTPUT?"OUTPUT":"INPUT") );
|
||||
|
||||
}
|
||||
|
||||
for (i=0; i < _sdconfig_.inputs ; i++)
|
||||
{
|
||||
logMessage (LOG_DEBUG, "Setting up Input %d\n", i);
|
||||
pinMode (_sdconfig_.inputcfg[i].pin, _sdconfig_.inputcfg[i].input_output);
|
||||
if (registerGPIOinterrupt (_sdconfig_.inputcfg[i].pin, _sdconfig_.inputcfg[i].receive_mode, (void *)&event_trigger, (void *)&_sdconfig_.inputcfg[i]) != true)
|
||||
{
|
||||
displayLastSystemError ("Unable to set interrupt handler for specified pin, exiting");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
*/
|
||||
logMessage (LOG_DEBUG, "Set GPIO %d to %s\n", _sdconfig_.zonecfg[i].pin,(_sdconfig_.zonecfg[i].input_output==OUTPUT?"OUTPUT":"INPUT") );
|
||||
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
for (i=0; i < _sdconfig_.pinscfgs ; i++)
|
||||
{
|
||||
if ( _sdconfig_.zonecfg[i].startup_state == 0 || _sdconfig_.zonecfg[i].startup_state == 1 ) {
|
||||
logMessage (LOG_DEBUG, "Setting pin %d to state %d\n", _sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].startup_state);
|
||||
digitalWrite(_sdconfig_.zonecfg[i].pin, _sdconfig_.zonecfg[i].startup_state);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
logMessage (LOG_DEBUG, "GPIO setup complete\n");
|
||||
|
||||
logMessage (LOG_DEBUG, "Starting HTTPD\n");
|
||||
|
@ -294,22 +297,28 @@ void main_loop ()
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
i=0;
|
||||
while (true)
|
||||
{
|
||||
//logMessage (LOG_DEBUG, "mg_mgr_poll\n");
|
||||
mg_mgr_poll(&_mgr, 500);
|
||||
|
||||
//logMessage (LOG_DEBUG, "updateEventMask=%d\n",_sdconfig_.updateEventMask);
|
||||
check_cron();
|
||||
if (zc_check() == true || check_delay24h() == true || _sdconfig_.eventToUpdateHappened) {
|
||||
_sdconfig_.eventToUpdateHappened = false;
|
||||
if (zc_check() == true || check_delay24h() == true || _sdconfig_.updateEventMask != 0) {
|
||||
//_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");
|
||||
|
@ -385,56 +394,34 @@ void event_trigger (struct GPIOcfg *gpiopin)
|
|||
//int out_state_toset;
|
||||
int in_state_read;
|
||||
time_t rawtime;
|
||||
struct tm * timeinfo;
|
||||
char timebuffer[20];
|
||||
//struct tm * timeinfo;
|
||||
//char timebuffer[20];
|
||||
//bool changed=false;
|
||||
time (&rawtime);
|
||||
timeinfo = localtime (&rawtime);
|
||||
strftime (timebuffer,20,"%T",timeinfo);
|
||||
//timeinfo = localtime (&rawtime);
|
||||
//strftime (timebuffer,20,"%T",timeinfo);
|
||||
|
||||
|
||||
//printf("Received trigger %d - at %s - last trigger %d\n",digitalRead (gpioconfig->pin), timebuffer, gpioconfig->last_event_state);
|
||||
|
||||
logMessage (LOG_DEBUG,"%s Received input change on pin %d - START\n",timebuffer, gpiopin->pin);
|
||||
logMessage (LOG_INFO,"Received input change on pin %d\n", gpiopin->pin);
|
||||
|
||||
if ( (rawtime - gpiopin->last_event_time) < 1 && gpiopin->input_output == INPUT)
|
||||
{
|
||||
logMessage (LOG_DEBUG," ignoring, time between triggers too short (%d-%d)=%d\n",rawtime, gpiopin->last_event_time, (rawtime - gpiopin->last_event_time));
|
||||
logMessage (LOG_DEBUG,"Ignoring input event on pin %d, time between triggers too short (%d-%d)=%d\n",gpiopin->pin,rawtime, gpiopin->last_event_time, (rawtime - gpiopin->last_event_time));
|
||||
return;
|
||||
}
|
||||
gpiopin->last_event_time = rawtime;
|
||||
//logMessage (LOG_DEBUG,"Diff between last event %d (%d, %d)\n",rawtime - gpioconfig->last_event_time, rawtime, gpioconfig->last_event_time);
|
||||
|
||||
/* Handle button pressed interrupts */
|
||||
|
||||
|
||||
in_state_read = digitalRead (gpiopin->pin);
|
||||
//logMessage (LOG_DEBUG, " Init pin state %d, previous state %d\n", in_state_read, gpiopin->last_event_state);
|
||||
|
||||
//if ( gpioconfig->receive_state == BOTH || in_state_read == gpioconfig->receive_state)
|
||||
//{
|
||||
|
||||
gpiopin->last_event_state = in_state_read;
|
||||
|
||||
if ( in_state_read == gpiopin->on_state && strlen(gpiopin->command_on) > 0)
|
||||
run_external(gpiopin->command_on);
|
||||
else if ( in_state_read == !gpiopin->on_state && strlen(gpiopin->command_off) > 0)
|
||||
run_external(gpiopin->command_off);
|
||||
|
||||
/*
|
||||
if (gpiopin->ext_cmd != NULL && strlen(gpiopin->ext_cmd) > 0) {
|
||||
//logMessage (LOG_DEBUG, "command '%s'\n", gpioconfig->ext_cmd);
|
||||
run_external(gpiopin->ext_cmd, in_state_read);
|
||||
}
|
||||
*/
|
||||
//sleep(1);
|
||||
//} else {
|
||||
// logMessage (LOG_DEBUG," ignoring, reseived state does not match cfg\n");
|
||||
// return;
|
||||
//if (_mgr.active_connections != NULL) {
|
||||
// _sdconfig_.eventToUpdateHappened = true;
|
||||
//}
|
||||
|
||||
// Sleep for 1 second just to limit duplicte events
|
||||
//sleep(1);
|
||||
|
||||
logMessage (LOG_DEBUG,"%s Receive input change on pin %d - END\n",timebuffer, gpiopin->pin);
|
||||
//if (changed ==true )
|
||||
if (_mgr.active_connections != NULL) {
|
||||
_sdconfig_.eventToUpdateHappened = true;
|
||||
//broadcast_zonestate(_mgr.active_connections, gpiopin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
10
utils.c
10
utils.c
|
@ -114,7 +114,7 @@ void logMessage(int level, char *format, ...)
|
|||
//if (_debuglog_ == false && level == LOG_DEBUG)
|
||||
// return;
|
||||
|
||||
char buffer[MXPRNT];
|
||||
char buffer[MXPRNT+1];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
strncpy(buffer, " ", 8);
|
||||
|
@ -301,13 +301,11 @@ char * replace(char const * const original, char const * const pattern, char con
|
|||
}
|
||||
}
|
||||
|
||||
void run_external(char *command, int state)
|
||||
void run_external(char *command)
|
||||
{
|
||||
|
||||
char *cmd = replace(command, "%STATE%", (state==1?"1":"0"));
|
||||
system(cmd);
|
||||
logMessage (LOG_DEBUG, "Ran command '%s'\n", cmd);
|
||||
free(cmd);
|
||||
system(command);
|
||||
logMessage (LOG_DEBUG, "Ran command '%s'\n", command);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
2
utils.h
2
utils.h
|
@ -16,7 +16,7 @@ void daemonise ( char *pidFile, void (*main_function)(void) );
|
|||
void displayLastSystemError (const char *on_what);
|
||||
void logMessage(int level, char *format, ...);
|
||||
int count_characters(const char *str, char character);
|
||||
void run_external(char *command, int state);
|
||||
void run_external(char *command);
|
||||
int str2int(const char* str, int len);
|
||||
float str2float(const char* str, int len);
|
||||
//void readCfg (char *cfgFile);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef SD_VERSION_H
|
||||
#define SD_VERSION_H
|
||||
|
||||
#define SD_VERSION "1.0d"
|
||||
#define SD_VERSION "1.4.1"
|
||||
|
||||
#endif
|
||||
|
|
177
zone_ctrl.c
177
zone_ctrl.c
|
@ -1,8 +1,7 @@
|
|||
|
||||
#ifdef USE_WIRINGPI
|
||||
#include <wiringPi.h>
|
||||
#else
|
||||
#include "sd_GPIO.h"
|
||||
#include "GPIO_Pi.h"
|
||||
#endif
|
||||
|
||||
#include "zone_ctrl.h"
|
||||
|
@ -16,8 +15,8 @@ void zc_master(zcState state);
|
|||
int calc_timeleft() {
|
||||
if (_sdconfig_.currentZone.zone != -1) {
|
||||
// See if the duration time changed since we started, on was not a cron request.
|
||||
if ( _sdconfig_.currentZone.type != zcCRON && _sdconfig_.currentZone.duration != _sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime)
|
||||
_sdconfig_.currentZone.duration=_sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime;
|
||||
//if ( _sdconfig_.currentZone.type != zcCRON && _sdconfig_.currentZone.duration != _sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime)
|
||||
// _sdconfig_.currentZone.duration=_sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime;
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
@ -31,6 +30,55 @@ int calc_timeleft() {
|
|||
return _sdconfig_.currentZone.timeleft;
|
||||
}
|
||||
|
||||
zcState zc_state(int zone) {
|
||||
if (zone > 0 && zone <= _sdconfig_.zones) {
|
||||
return (digitalRead(_sdconfig_.zonecfg[zone].pin) == _sdconfig_.zonecfg[zone].on_state ? zcON : zcOFF);
|
||||
} else {
|
||||
return zcOFF; // If invalid zone just return off, maybe change to NULL
|
||||
}
|
||||
}
|
||||
|
||||
int start_next_zone(int startz) {
|
||||
|
||||
int zone = startz+1;
|
||||
|
||||
setEventZones;
|
||||
|
||||
while( _sdconfig_.zonecfg[zone].default_runtime <= 0 || !validGPIO( _sdconfig_.zonecfg[zone].pin) ) {
|
||||
//logMessage (LOG_INFO, "Run Zone, skipping zone %d due to runtime of %d\n",zone,_sdconfig_.zonecfg[zone].default_runtime);
|
||||
logMessage (LOG_INFO, "Run Zone, skipping zone %d due to %s\n",zone,_sdconfig_.zonecfg[zone].default_runtime<=0?" runtime of 0":" bad GPIO pin#");
|
||||
zone++;
|
||||
if (zone > _sdconfig_.zones) { // No more zones left to run, turn everything off
|
||||
_sdconfig_.currentZone.type=zcNONE;
|
||||
_sdconfig_.currentZone.zone=-1;
|
||||
_sdconfig_.currentZone.timeleft = 0;
|
||||
zc_master(zcOFF);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( zc_start(zone) == true) {
|
||||
_sdconfig_.currentZone.zone=zone;
|
||||
zc_master(zcON);
|
||||
time(&_sdconfig_.currentZone.started_time);
|
||||
_sdconfig_.currentZone.duration=_sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime;
|
||||
calc_timeleft();
|
||||
|
||||
} else {
|
||||
logMessage (LOG_ERR, "Run Zone, failed to start zone %d, check GPIO\n",zone);
|
||||
return start_next_zone(zone);
|
||||
}
|
||||
|
||||
return zone;
|
||||
}
|
||||
|
||||
void zc_update_runtime(int zone) {
|
||||
if (zone > 0 && zone < _sdconfig_.zones && zone == _sdconfig_.currentZone.zone) {
|
||||
_sdconfig_.currentZone.duration=_sdconfig_.zonecfg[zone].default_runtime;
|
||||
}
|
||||
setEventZones;
|
||||
}
|
||||
|
||||
bool zc_check() {
|
||||
// check what's running, and if time now is greater than duration Stop if grater
|
||||
// Move onto next zone if (all) runtype
|
||||
|
@ -47,11 +95,7 @@ bool zc_check() {
|
|||
if (calc_timeleft() <= 0){
|
||||
if (_sdconfig_.currentZone.type==zcALL && _sdconfig_.currentZone.zone < _sdconfig_.zones) {
|
||||
zc_stop(_sdconfig_.currentZone.zone);
|
||||
_sdconfig_.currentZone.zone++;
|
||||
zc_start(_sdconfig_.currentZone.zone);
|
||||
time(&_sdconfig_.currentZone.started_time);
|
||||
_sdconfig_.currentZone.duration=_sdconfig_.zonecfg[_sdconfig_.currentZone.zone].default_runtime;
|
||||
calc_timeleft();
|
||||
start_next_zone(_sdconfig_.currentZone.zone);
|
||||
} else {
|
||||
zc_master(zcOFF);
|
||||
zc_stop(_sdconfig_.currentZone.zone);
|
||||
|
@ -118,13 +162,9 @@ bool zc_zone(zcRunType type, int zone, zcState state, int length) {
|
|||
}
|
||||
_sdconfig_.currentZone.type=zcNONE;
|
||||
if (state == zcON) {
|
||||
zc_start(1);
|
||||
zc_master(zcON);
|
||||
_sdconfig_.currentZone.zone=1;
|
||||
time(&_sdconfig_.currentZone.started_time);
|
||||
_sdconfig_.currentZone.duration=_sdconfig_.zonecfg[1].default_runtime;
|
||||
_sdconfig_.currentZone.type=zcALL;
|
||||
calc_timeleft();
|
||||
if ( start_next_zone(0) != -1 ) { // Pass 0 as start_next_zone will incrument zone
|
||||
_sdconfig_.currentZone.type=zcALL;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -135,31 +175,35 @@ bool zc_zone(zcRunType type, int zone, zcState state, int length) {
|
|||
logMessage (LOG_DEBUG, "Use default time of %d\n",length);
|
||||
}
|
||||
|
||||
// NSF need to Check the array is valid
|
||||
//if ( _sdconfig_.zonecfg[zone] == NULL) {
|
||||
// return false;
|
||||
//}
|
||||
|
||||
if (state == zcON) {
|
||||
for (i=1; i <= _sdconfig_.zones ; i++)
|
||||
{
|
||||
if ( _sdconfig_.zonecfg[i].on_state == digitalRead (_sdconfig_.zonecfg[i].pin)) {
|
||||
if (zone == i) {
|
||||
logMessage (LOG_DEBUG, "Request to turn zone %d on. Zone %d is already on, ignoring!\n",zone,zone);
|
||||
return false;
|
||||
if ( length > 0) {
|
||||
for (i=1; i <= _sdconfig_.zones ; i++)
|
||||
{
|
||||
if ( _sdconfig_.zonecfg[i].on_state == digitalRead (_sdconfig_.zonecfg[i].pin)) {
|
||||
if (zone == i) {
|
||||
logMessage (LOG_DEBUG, "Request to turn zone %d on. Zone %d is already on, ignoring!\n",zone,zone);
|
||||
return false;
|
||||
}
|
||||
zc_stop(i);
|
||||
}
|
||||
zc_stop(i);
|
||||
}
|
||||
}
|
||||
zc_start(zone);
|
||||
zc_master(zcON);
|
||||
_sdconfig_.currentZone.type=type;
|
||||
_sdconfig_.currentZone.zone=zone;
|
||||
_sdconfig_.currentZone.duration=length;
|
||||
logMessage (LOG_DEBUG, "set runtime to %d and %d\n",length,_sdconfig_.currentZone.duration);
|
||||
time(&_sdconfig_.currentZone.started_time);
|
||||
calc_timeleft();
|
||||
return true;
|
||||
if ( zc_start(zone) == true) {
|
||||
zc_master(zcON);
|
||||
_sdconfig_.currentZone.type=type;
|
||||
_sdconfig_.currentZone.zone=zone;
|
||||
_sdconfig_.currentZone.duration=length;
|
||||
logMessage (LOG_DEBUG, "set runtime to %d and %d\n",length,_sdconfig_.currentZone.duration);
|
||||
time(&_sdconfig_.currentZone.started_time);
|
||||
calc_timeleft();
|
||||
return true;
|
||||
} else {
|
||||
logMessage (LOG_ERR, "Request to turn on zone %d failed, check GPIO\n",zone);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
logMessage (LOG_WARNING, "Request to turn zone %d on. Ignored due to runtime being %d\n",zone,length);
|
||||
return false;
|
||||
}
|
||||
} else if (state == zcOFF) {
|
||||
if (_sdconfig_.currentZone.type == zcALL) { // If all zones, and told to turn off current, run next zone
|
||||
_sdconfig_.currentZone.started_time = _sdconfig_.currentZone.started_time - (_sdconfig_.currentZone.duration * SEC2MIN) - 1;
|
||||
|
@ -175,38 +219,63 @@ bool zc_zone(zcRunType type, int zone, zcState state, int length) {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool zc_start(/*zcRunType type,*/ int zone) {
|
||||
// check anything on, turn off
|
||||
|
||||
// Turn on master valve if we have one
|
||||
// turn on zone
|
||||
int rtn = false;
|
||||
// Check if zone is already on
|
||||
if ( _sdconfig_.zonecfg[zone].on_state == digitalRead (_sdconfig_.zonecfg[zone].pin)) {
|
||||
logMessage (LOG_DEBUG, "Request to turn zone %d on. Zone %d is already on, ignoring!\n",zone,zone);
|
||||
return false;
|
||||
}
|
||||
logMessage (LOG_NOTICE, "Turning on Zone %d\n",zone);
|
||||
#ifndef USE_WIRINGPI
|
||||
//int rtn = digitalWrite(_sdconfig_.zonecfg[zone].pin, _sdconfig_.zonecfg[zone].on_state );
|
||||
//logMessage (LOG_NOTICE, "digitalWrite return %d\n",rtn);
|
||||
if (digitalWrite(_sdconfig_.zonecfg[zone].pin, _sdconfig_.zonecfg[zone].on_state ) == GPIO_OK )
|
||||
rtn = true;
|
||||
else
|
||||
rtn = false;
|
||||
#else
|
||||
digitalWrite(_sdconfig_.zonecfg[zone].pin, _sdconfig_.zonecfg[zone].on_state );
|
||||
_sdconfig_.eventToUpdateHappened = true;
|
||||
// store what's running
|
||||
int rtn = true;
|
||||
#endif
|
||||
//_sdconfig_.eventToUpdateHappened = true;
|
||||
setEventZones;
|
||||
|
||||
return true;
|
||||
return rtn;
|
||||
// store what's running
|
||||
//if (rtn == true)
|
||||
// return true;
|
||||
//else
|
||||
// return false;
|
||||
}
|
||||
|
||||
bool zc_stop(/*zcRunType type,*/ int zone) {
|
||||
|
||||
// Turn on master valve if we have one
|
||||
|
||||
int rtn = false;
|
||||
// Check if zone is alreay off
|
||||
if ( _sdconfig_.zonecfg[zone].on_state != digitalRead (_sdconfig_.zonecfg[zone].pin)) {
|
||||
logMessage (LOG_DEBUG, "Request to turn zone %d off. Zone %d is already off, ignoring!\n",zone,zone);
|
||||
return false;
|
||||
}
|
||||
logMessage (LOG_NOTICE, "Turning off Zone %d\n",zone);
|
||||
#ifndef USE_WIRINGPI
|
||||
//int rtn = digitalWrite(_sdconfig_.zonecfg[zone].pin, !_sdconfig_.zonecfg[zone].on_state );
|
||||
if (digitalWrite(_sdconfig_.zonecfg[zone].pin, !_sdconfig_.zonecfg[zone].on_state ) == GPIO_OK )
|
||||
rtn = true;
|
||||
else
|
||||
rtn = false;
|
||||
#else
|
||||
digitalWrite(_sdconfig_.zonecfg[zone].pin, !_sdconfig_.zonecfg[zone].on_state );
|
||||
_sdconfig_.eventToUpdateHappened = true;
|
||||
//_sdconfig_.zonecfg[zone]
|
||||
// turn off zone
|
||||
int rtn = true;
|
||||
#endif
|
||||
//_sdconfig_.eventToUpdateHappened = true;
|
||||
setEventZones;
|
||||
|
||||
// delete what's running
|
||||
|
||||
return true;
|
||||
return rtn;
|
||||
/*
|
||||
if (rtn == true)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -22,5 +22,6 @@ struct szRunning {
|
|||
bool zc_check();
|
||||
bool zc_zone(zcRunType type, int zone, zcState state, int length);
|
||||
void zc_rain_delay_enabeled();
|
||||
|
||||
zcState zc_state(int zone);
|
||||
void zc_update_runtime(int zone);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue