update to support all Pi versions

master
shaun feakes 2018-07-07 13:14:15 -05:00
parent fdb9e4369d
commit 3a97e993a3
8 changed files with 266 additions and 26 deletions

View File

@ -143,6 +143,41 @@ int build_advanced_sprinkler_JSON(char* buffer, int size)
return strlen(buffer);
}
int build_homebridge_sprinkler_JSON(char* buffer, int size)
{
int i;
memset(&buffer[0], 0, size);
int length = 0;
length += sprintf(buffer+length, "{ \"title\" : \"%s\", ", _sdconfig_.name);
length += sprintf(buffer+length, " \"devices\": [");
for (i=0; i <= _sdconfig_.zones ; i++)
{
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);
}
length += sprintf(buffer+length, "{\"type\" : \"zone\", \"zone\": %d, \"name\": \"Cycle all zones\", \"state\": \"%s\", \"duration\": 0, \"id\" : \"cycleallzones\" },",
_sdconfig_.zones+1,
_sdconfig_.currentZone.type==zcALL?"on":"off");
length += sprintf(buffer+length, "{\"type\" : \"switch\", \"zone\": -1, \"name\": \"24h Rain Delay\", \"state\": \"%s\", \"duration\": 0, \"id\" : \"24hdelay\" },",
_sdconfig_.delay24h?"on":"off");
length += sprintf(buffer+length, "{\"type\" : \"switch\", \"zone\": -1, \"name\": \"Run on calendar schedule\", \"state\": \"%s\", \"duration\": 0, \"id\" : \"calendar\" }",
_sdconfig_.calendar?"on":"off");
length += sprintf(buffer+length, "]}");
buffer[length] = '\0';
return strlen(buffer);
}
int build_dz_mqtt_status_JSON(char* buffer, int size, int idx, int nvalue, float tvalue)
{
memset(&buffer[0], 0, size);

View File

@ -16,7 +16,8 @@ int build_dz_mqtt_status_JSON(char* buffer, int size, int idx, int nvalue, float
int build_dz_status_message_JSON(char* buffer, int size, int idx, int nvalue, char *svalue);
int build_sprinkler_JSON(char* buffer, int size);
int build_sprinkler_cal_JSON(char* buffer, int size);
int build_advanced_sprinkler_JSON(char* buffer, int size);
int build_advanced_sprinkler_JSON(char* buffer, int size);
int build_homebridge_sprinkler_JSON(char* buffer, int size);

View File

@ -199,9 +199,20 @@ void publish_zone_mqtt(struct mg_connection *nc, struct GPIOcfg *gpiopin) {
if (_sdconfig_.enableMQTTaq == true) {
// sprintf(mqtt_topic, "%s/%s", _sdconfig_.mqtt_topic, gpiopin->name);
sprintf(mqtt_topic, "%s/zone/%d", _sdconfig_.mqtt_topic, gpiopin->zone);
sprintf(mqtt_topic, "%s/zone%d", _sdconfig_.mqtt_topic, gpiopin->zone);
sprintf(mqtt_msg, "%s", (digitalRead(gpiopin->pin) == gpiopin->on_state ? MQTT_ON : MQTT_OFF));
send_mqtt_msg(nc, mqtt_topic, mqtt_msg);
sprintf(mqtt_topic, "%s/zone%d/duration", _sdconfig_.mqtt_topic, gpiopin->zone);
sprintf(mqtt_msg, "%d", gpiopin->default_runtime * 60);
send_mqtt_msg(nc, mqtt_topic, mqtt_msg);
sprintf(mqtt_topic, "%s/zone%d/remainingduration", _sdconfig_.mqtt_topic, gpiopin->zone);
if (_sdconfig_.currentZone.zone == gpiopin->zone) {
sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft * 60);
} else {
sprintf(mqtt_msg, "%d", 0);
}
send_mqtt_msg(nc, mqtt_topic, mqtt_msg);
}
if (gpiopin->dz_idx > 0 && _sdconfig_.enableMQTTdz == true) {
if ( update_dz_cache(gpiopin->dz_idx,(digitalRead(gpiopin->pin) == gpiopin->on_state ? DZ_ON : DZ_OFF) ) ) {
@ -269,12 +280,32 @@ void broadcast_sprinklerdactivestate(struct mg_connection *nc)
sprintf(mqtt_topic, "%s/active", _sdconfig_.mqtt_topic);
sprintf(mqtt_msg, "Zone %d", _sdconfig_.currentZone.zone );
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
sprintf(mqtt_topic, "%s/remainingduration", _sdconfig_.mqtt_topic);
sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft );
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
//sprintf(mqtt_topic, "%s/remainingduration", _sdconfig_.mqtt_topic);
//sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft );
//send_mqtt_msg(c, mqtt_topic, mqtt_msg);
sprintf(mqtt_topic, "%s/status", _sdconfig_.mqtt_topic);
sprinklerdstatus(mqtt_msg, 50);
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
// Send info specific to zone
sprintf(mqtt_topic, "%s/zone%d/remainingduration", _sdconfig_.mqtt_topic, _sdconfig_.currentZone.zone);
sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft );
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
if (_sdconfig_.currentZone.type == zcALL) {
int i, total=_sdconfig_.currentZone.timeleft;
for (i=_sdconfig_.currentZone.zone+1; i <= _sdconfig_.zones; i++) {
total += (_sdconfig_.zonecfg[i].default_runtime * 60);
}
sprintf(mqtt_topic, "%s/cycleallzones/remainingduration", _sdconfig_.mqtt_topic);
sprintf(mqtt_msg, "%d", total );
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
sprintf(mqtt_topic, "%s/zone0/remainingduration", _sdconfig_.mqtt_topic);
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
} else if (_sdconfig_.currentZone.type != zcNONE) {
sprintf(mqtt_topic, "%s/zone0/remainingduration", _sdconfig_.mqtt_topic);
sprintf(mqtt_msg, "%d", _sdconfig_.currentZone.timeleft );
send_mqtt_msg(c, mqtt_topic, mqtt_msg);
}
}
}
}
@ -383,7 +414,9 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
logMessage (LOG_DEBUG, "Request type %s\n",buf);
if (strcmp(buf, "json") == 0) {
length = build_advanced_sprinkler_JSON(buffer, size);
length = build_advanced_sprinkler_JSON(buffer, size);
} else if (strcmp(buf, "homebridge") == 0) {
length = build_homebridge_sprinkler_JSON(buffer, size);
} else if (strcmp(buf, "firstload") == 0) {
logMessage(LOG_DEBUG, "WEB REQUEST Firstload %s\n",buf);
length = build_sprinkler_cal_JSON(buffer, size);
@ -396,6 +429,7 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
if (strncasecmp(buf, "calendar", 6) == 0 ) {
mg_get_http_var(&http_msg->query_string, "state", buf, buflen);
logMessage(LOG_NOTICE, "WEB request to turn Calendar %s\n",buf);
logMessage(LOG_NOTICE, "Request | %.*s\n",http_msg->query_string.len,http_msg->query_string.p);
enable_calendar(is_value_ON(buf));
length = build_sprinkler_JSON(buffer, size);
} else if (strncasecmp(buf, "24hdelay", 8) == 0 ) {
@ -456,6 +490,7 @@ int serve_web_request(struct mg_connection *nc, struct http_message *http_msg, c
_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;
} else
length += sprintf(buffer, "{ \"error\": \"bad request zone %d runtime %d\"}",zone,runtime);
} else if (strcmp(buf, "calcfg") == 0) {
@ -547,7 +582,7 @@ void action_domoticz_mqtt_message(struct mg_connection *nc, struct mg_mqtt_messa
return;
if (idx == _sdconfig_.dzidx_calendar) {
//_sdconfig_.system=(nvalue==DZ_ON?true:false);
//logMessage(LOG_NOTICE, "Domoticz: topic %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
logMessage(LOG_NOTICE, "Domoticz: topic %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
logMessage(LOG_NOTICE, "Domoticz request to turn Calendar %s\n",nvalue==DZ_ON?"On":"Off");
enable_calendar(nvalue==DZ_ON?true:false);
//_sdconfig_.eventToUpdateHappened = true;
@ -601,7 +636,8 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
/* Need to action the following
1 = on
//sprinkler/zone/1/set on
//sprinkler/zone1/set on
//sprinkler/zone1/duration/set on
//sprinkler/zone/all/set on
//sprinkler/24hdelay/set on
//sprinkler/system/set on
@ -615,6 +651,8 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
logMessage(LOG_DEBUG, "MQTT: topic %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
//logMessage(LOG_DEBUG, "MQTT: pt2 %.*s == %s %c\n", 4, pt2, strncmp(pt2, "zone", 4) == 0?"YES":"NO", pt2[4]);
/*
if (pt2 != NULL && pt3 != NULL && pt4 != NULL && strncmp(pt2, "zone", 4) == 0 && strncmp(pt4, "set", 3) == 0 ) {
int zone = atoi(pt3);
if (zone > 0 && zone <= _sdconfig_.zones) {
@ -623,6 +661,15 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
} else {
logMessage(LOG_WARNING, "MQTT: unknown zone %d\n",zone);
}
} else*/
if (pt2 != NULL && pt3 != NULL && pt4 != NULL && strncmp(pt2, "zone", 4) == 0 && strncmp(pt3, "duration", 8) == 0 && strncmp(pt4, "set", 3) == 0 ) {
int zone = atoi(&pt2[4]);
if (zone > 0 && zone <= _sdconfig_.zones) {
int v = str2int(msg->payload.p, msg->payload.len);
_sdconfig_.zonecfg[zone].default_runtime = v / 60;
_sdconfig_.eventToUpdateHappened = true;
logMessage(LOG_DEBUG, "MQTT: 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");
@ -634,6 +681,21 @@ void action_mqtt_message(struct mg_connection *nc, struct mg_mqtt_message *msg){
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "cycleallzones", 13) == 0 && strncmp(pt3, "set", 3) == 0 ) {
zc_zone(zcALL, 0, status, 0);
logMessage(LOG_DEBUG, "MQTT: Cycle all zones %s\n",status==zcON?"ON":"OFF");
} else if (pt2 != NULL && pt3 != NULL && strncmp(pt2, "zone", 4) == 0 && strncmp(pt3, "set", 3) == 0 ) {
int zone = atoi(&pt2[4]);
if (zone > 0 && zone <= _sdconfig_.zones) {
zc_zone(zcSINGLE, zone, status, 0);
logMessage(LOG_DEBUG, "MQTT: Turn zone %d %s\n",zone, status==zcON?"ON":"OFF");
} else 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);
} else if (zone == 0 && status == zcON) {
// Can't turn on master valve, just re-send current stats.
_sdconfig_.eventToUpdateHappened = true;
} else {
logMessage(LOG_WARNING, "MQTT: unknown zone %d\n",zone);
}
} else {
logMessage(LOG_DEBUG, "MQTT: Unknown topic %.*s %.*s\n",msg->topic.len, msg->topic.p, msg->payload.len, msg->payload.p);
return;

Binary file not shown.

151
sd_GPIO.c
View File

@ -9,27 +9,102 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include "utils.h"
#include "sd_GPIO.h"
static bool _ever = false;
void gpioDelay (unsigned int howLong);
#ifndef GPIO_SYSFS_MODE
static volatile uint32_t * _gpioReg = MAP_FAILED;
static bool _ever = false;
void gpioDelay (unsigned int howLong) // Microseconds (1000000 = 1 second)
int piBoardId ()
{
struct timespec sleeper, dummy ;
FILE *cpuFd ;
char line [120] ;
char *c ;
unsigned int revision ;
//int bRev, bType, bProc, bMfg, bMem, bWarranty;
int bType;
sleeper.tv_sec = (time_t)(howLong / 1000) ;
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL)
logMessage (LOG_ERR, "piBoardId: Unable to open /proc/cpuinfo") ;
nanosleep (&sleeper, &dummy) ;
while (fgets (line, 120, cpuFd) != NULL)
if (strncmp (line, "Revision", 8) == 0)
break ;
fclose (cpuFd) ;
if (strncmp (line, "Revision", 8) != 0)
logMessage (LOG_ERR, "piBoardId: No \"Revision\" line") ;
// Chomp trailing CR/NL
for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c)
*c = 0 ;
logMessage (LOG_DEBUG, "piBoardId: Revision string: %s\n", line) ;
// Scan to the first character of the revision number
for (c = line ; *c ; ++c)
if (*c == ':')
break ;
if (*c != ':')
logMessage (LOG_ERR, "piBoardId: Unknown \"Revision\" line (no colon)") ;
// Chomp spaces
++c ;
while (isspace (*c))
++c ;
if (!isxdigit (*c))
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 ;
*/
}
return PI_MODEL_UNKNOWN;
}
bool gpioSetup() {
int fd;
unsigned int piGPIObase = 0;
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:
piGPIObase = (GPIO_BASE_P1 + GPIO_OFFSET);
break ;
default:
piGPIObase = (GPIO_BASE_P2 + GPIO_OFFSET);
break ;
}
fd = open("/dev/mem", O_RDWR | O_SYNC);
@ -46,7 +121,7 @@ bool gpioSetup() {
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_SHARED|MAP_LOCKED,
fd,
GPIO_BASE);
piGPIObase);
close(fd);
@ -165,7 +240,35 @@ int pinMode (unsigned pin, unsigned mode)
return true;
}
int getPinMode(unsigned gpio) {
char path[SYSFS_PATH_MAX];
char value_str[SYSFS_READ_MAX];
int fd;
snprintf(path, SYSFS_PATH_MAX, "/sys/class/gpio/gpio%d/direction", gpio);
fd = open(path, O_RDONLY);
if (-1 == fd) {
//fprintf(stderr, "Failed to open gpio direction for writing!\n");
logMessage (LOG_ERR, "Failed to open gpio '%s' for reading!\n",path);
return false;
}
if (-1 == read(fd, value_str, SYSFS_READ_MAX)) {
//fprintf(stderr, "Failed to read value!\n");
logMessage (LOG_ERR, "Failed to read value on '%s'!\n",path);
displayLastSystemError("");
return(-1);
}
close(fd);
if (strcasecmp(value_str, "out")==0)
return OUTPUT;
return INPUT;
}
int digitalRead (unsigned pin)
{
char path[SYSFS_PATH_MAX];
@ -220,6 +323,16 @@ int digitalWrite (unsigned pin, unsigned value)
}
#endif
void gpioDelay (unsigned int howLong) // Microseconds (1000000 = 1 second)
{
struct timespec sleeper, dummy ;
sleeper.tv_sec = (time_t)(howLong / 1000) ;
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
nanosleep (&sleeper, &dummy) ;
}
bool isExported(unsigned pin)
{
char path[SYSFS_PATH_MAX];
@ -459,6 +572,14 @@ 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
#include <stdarg.h>
@ -497,7 +618,7 @@ void displayLastSystemError (const char *on_what)
}
#define PIN 4
#define PIN 17
#define POUT 27
int main(int argc, char *argv[]) {
int repeat = 3;
@ -510,9 +631,9 @@ int main(int argc, char *argv[]) {
pinUnexport(PIN);
pinExport(POUT);
pinExport(PIN);
sleep(1);
*/
sleep(1);
//edgeSetup(POUT, INT_EDGE_BOTH);
if (-1 == pinMode(POUT, OUTPUT) || -1 == pinMode(PIN, INPUT))
@ -523,23 +644,23 @@ int main(int argc, char *argv[]) {
if (pinExport(POUT) != true)
printf("Error exporting pin\n");
/*
if (registerGPIOinterrupt(POUT, INT_EDGE_RISING, (void *)&myCallBack, (void *)&repeat ) != true)
printf("Error registering interupt\n");
if (registerGPIOinterrupt(PIN, INT_EDGE_RISING, (void *)&myCallBack, (void *)&repeat ) != true)
printf("Error registering interupt\n");
*/
do {
printf("I'm writing to GPIO %d (input)\n", digitalRead(PIN), PIN);
printf("Writing %d to GPIO %d\n", repeat % 2, POUT);
if (-1 == digitalWrite(POUT, repeat % 2))
return (3);
printf("I'm reading %d in GPIO %d (input)\n", digitalRead(PIN), PIN);
printf("I'm reading %d in GPIO %d (output)\n", digitalRead(POUT), POUT);
printf("Read %d from GPIO %d (input)\n", digitalRead(PIN), PIN);
printf("Read %d from GPIO %d (output)\n", digitalRead(POUT), POUT);
usleep(500 * 1000);
} while (repeat--);

View File

@ -32,7 +32,10 @@
#define INT_EDGE_BOTH 3
#ifndef GPIO_SYSFS_MODE
#define GPIO_BASE 0x20200000
#define GPIO_BASE_P2 0x3F000000
#define GPIO_BASE_P1 0x20000000
#define GPIO_OFFSET 0x200000
//#define GPIO_BASE 0x20200000
#define GPIO_LEN 0xB4
#define GPSET0 7
@ -48,6 +51,20 @@
#define GPPUD 37
#define GPPUDCLK0 38
#define GPPUDCLK1 39
#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
#endif

View File

@ -340,7 +340,7 @@ void Daemon_Stop (int signum)
}
}
#ifndef USE_WIRINGPI
gpioSetup();
gpioShutdown();
#endif
/*
#ifdef PTHREAD
@ -366,7 +366,7 @@ void intHandler(int signum) {
}
#ifndef USE_WIRINGPI
gpioSetup();
gpioShutdown();
#endif
close(server_sock);

View File

@ -15,6 +15,10 @@ void zc_master(zcState state);
int calc_timeleft() {
if (_sdconfig_.currentZone.zone != -1) {
// See if the duration time changed since we started.
if ( _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);
_sdconfig_.currentZone.timeleft = (_sdconfig_.currentZone.duration * SEC2MIN) - difftime(now, _sdconfig_.currentZone.started_time);