thermferm/devices.c

Sat, 16 May 2015 17:39:30 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 16 May 2015 17:39:30 +0200
changeset 362
c92651a54969
parent 354
5ff387f4d6b7
child 392
034746506c3d
permissions
-rw-r--r--

Made the client-server protocol more robust. When a change to a unit is made using the web interface, the main process is stopped during the update. Splitted the PID in two PID's, one for heating and one for cooling. Adjusted the web edit scrreen for this, but there are still rough edges. Replaced the PID code, maybe this one works better for our purpose. The simulator air temperature changes on the simulator heater and cooler, but it is not realistic at all. This is a development version, do not use in production. The version is 0.3.0

/*****************************************************************************
 * Copyright (C) 2014..2015
 *   
 * Michiel Broek <mbroek at mbse dot eu>
 *
 * This file is part of the mbsePi-apps
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * mbsePi-apps is distributed in the hope that it will be useful, 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.
 * 
 * You should have received a copy of the GNU General Public License
 * along with thermferm; see the file COPYING.  If not, write to the Free
 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *****************************************************************************/

#include "thermferm.h"
#include "devices.h"
#include "rc-switch.h"
#include "panel.h"
#include "xutil.h"


extern int		debug;
extern sys_config	Config;
extern int		my_shutdown;

#ifdef USE_SIMULATOR

extern int	SIMcooling;
extern int	SIMheating;

#endif

#ifdef HAVE_WIRINGPI_H

#define MAXTIMINGS 100

int             dht11_pin = -1;
int             dht11_temperature = -1;
int             dht11_humidity = -1;
int             dht11_valid = FALSE;
time_t		dht11_last = (time_t)0;


static uint8_t sizecvt(const int read_value) {
    /* 
     * digitalRead() and friends from wiringpi are defined as returning a value
     *            < 256. However, they are returned as int() types. This is a safety function 
     */
    if (read_value > 255 || read_value < 0) {
	syslog(LOG_NOTICE, "invalid data from wiringPi library");
    }
	                      
    return (uint8_t)read_value;
}



/*
 * DHT11 sensor read.
 */
void dht11Read(void) {
    int         	tries = 5;
    unsigned short	got_correct_data = 0;

    if (dht11_pin == -1)
	return;

    while (tries && !got_correct_data) {
	uint8_t	laststate = HIGH;
	uint8_t	counter = 0;
	uint8_t	j = 0, i = 0;
	int	dht11_dat[5] = {0,0,0,0,0};

	/*
	 * Select output mode to send the start signal.
	 */
	pinMode(dht11_pin, OUTPUT);                 
	digitalWrite(dht11_pin, HIGH);
	usleep(1000);

	/*
	 * Low for at least 18 milliseconds
	 */
	digitalWrite(dht11_pin, LOW);
	usleep(20000);
	digitalWrite(dht11_pin, HIGH);
	pinMode(dht11_pin, INPUT);

	/*
	 * Detect change and read data
	 */
	for (i=0; i<MAXTIMINGS; i++) {
	    counter = 0;
	    delayMicroseconds(10);
	    while (sizecvt(digitalRead(dht11_pin)) == laststate) {
		counter++;
		delayMicroseconds(1);
		if (counter == 255) {
		    break;
		}
	    }
	    laststate = sizecvt(digitalRead(dht11_pin));

	    if (counter == 255) 
		break;

	    /*
	     * ignore first 3 transitions
	     */
	    if ((i >= 4) && (i%2 == 0)) {

		// shove each bit into the storage bytes
		dht11_dat[(int)((double)j/8)] <<= 1;
		if (counter > 16)
		    dht11_dat[(int)((double)j/8)] |= 1;
		j++;
	    }
	}

	/*
	 * If there is no sensor, j = 0
	 */
	if ((counter == 255) && (j == 0)) {
	    if (dht11_temperature != -1) {
		syslog(LOG_NOTICE, "dht11 sensor disappeared");
	    } else {
		syslog(LOG_NOTICE, "dht11 sensor not present");
	    }
	    dht11_temperature = -1;
	    dht11_humidity = -1;
	    dht11_valid = FALSE;
	    return;
	} 

	/*
	 * check we read 40 bits (8bit x 5 ) + verify checksum in the last byte
	 * print it out if data is good
	 */
	if ((j >= 40) && (dht11_dat[4] == ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF))) {
		got_correct_data = 1;

		int h = dht11_dat[0] + dht11_dat[1];
		int t = (dht11_dat[2] & 0x7F) + dht11_dat[3];

		if ((dht11_dat[2] & 0x80) != 0) 
		    t *= -1;

		dht11_temperature = t;
		dht11_humidity = h;
		dht11_valid = TRUE;
	} else {
		tries--;
		if (tries == 0)
		    syslog(LOG_NOTICE, "dht11 data checksum was wrong 5 times");
		usleep(100000);
	}
    }
}

#endif


int read_w1(char *address, char *file)
{
    char	*addr = NULL;
    int		fn = -1, rc = -1, retries = 5;
    uint8_t	val;

    addr = xstrcpy((char *)"/sys/bus/w1/devices/");
    addr = xstrcat(addr, address);
    addr = xstrcat(addr, (char *)"/");
    addr = xstrcat(addr, file);

    if ((fn = open(addr, O_RDONLY)) >= 0) {

    	if ((lseek(fn, 0L, SEEK_SET)) == 0) {

	    while (retries--) {
    	    	if ((read(fn, &val, 1)) == 1) {
		    rc = (int)val;
		    goto leave;
//    	    	} else {
//	    	    syslog(LOG_NOTICE, "read_w1() read %s try=%d: %s", addr, retries, strerror(errno));
    	    	}
	    }
	    syslog(LOG_NOTICE, "read_w1() read %s fatal: %s", addr, strerror(errno));

	} else {
	    syslog(LOG_NOTICE, "read_w1() lseek %s: %s", addr, strerror(errno));
	}
    	
    } else {
	syslog(LOG_NOTICE, "read_w1() open %s: %s", addr, strerror(errno));
    }

leave:
    if (fn != -1) {
	if ((close(fn)) == -1) {
	    syslog(LOG_NOTICE, "read_w1() close %s: %s", addr, strerror(errno));
	}
    }

    free(addr);
    return rc;
}



int write_w1(char *address, char *file, uint8_t val)
{
    char	*addr = NULL;
    int		fn = -1, rc = -1, retries = 5;

    addr = xstrcpy((char *)"/sys/bus/w1/devices/");
    addr = xstrcat(addr, address);
    addr = xstrcat(addr, (char *)"/");
    addr = xstrcat(addr, file);

    if ((fn = open(addr, O_WRONLY)) >= 0) {

	if ((lseek(fn, 0L, SEEK_SET)) == 0) {

	    while (retries--) {
	    	if ((write(fn, &val, 1)) == 1) {
		    rc = 0;
		    goto leave;
//	    	} else {
//		    syslog(LOG_NOTICE, "write_w1() write %s try=%d: %s", addr, retries, strerror(errno));
	    	}
	    }
	    syslog(LOG_NOTICE, "write_w1() write %s fatal: %s", addr, strerror(errno));

	} else {
	    syslog(LOG_NOTICE, "write_w1() lseek %s: %s", addr, strerror(errno));
	}

    } else {
	syslog(LOG_NOTICE, "write_w1() open %s: %s", addr, strerror(errno));
    }

leave:
    if (fn != -1) {
	if ((close(fn)) == -1) {
	    syslog(LOG_NOTICE, "write_w1() close %s: %s", addr, strerror(errno));
	}
    }

    free(addr);
    return rc;
}



int device_out(char *uuid, int value)
{
    devices_list	*device;
    time_t		now, my_timestamp;
    int			rc, my_value, test_value;
#ifdef HAVE_WIRINGPI_H
    int			i;
    char		buf[40];
#endif

    if (uuid == NULL)
	return 0;

    now = time(NULL);

#ifdef HAVE_WIRINGPI_H
    piLock(LOCK_DEVICES);
#endif

    for (device = Config.devices; device; device = device->next) {
	if (! strcmp(uuid, device->uuid)) {
	    /*
	     * Execute command if different then the old value. But also
	     * every 2 minutes because commands can have temporary
	     * disconnects, or have radio problems.
	     */
	    my_timestamp = device->timestamp;
	    my_value = device->value;

	    if ((device->type == DEVTYPE_W1) && (device->direction == DEVDIR_OUT_BIN)) {
		test_value = (value == 0) ? 0 : 1;
	    } else {
		test_value = value;
	    }

	    if ((test_value != my_value) || (((int)now - (int)my_timestamp) >= 120)) {

#ifdef HAVE_WIRINGPI_H
		rc = 0;
		if ((device->type == DEVTYPE_RC433) && (device->gpiopin != -1) && (device->present == DEVPRESENT_YES)) {
		    snprintf(buf, 39, "%s,%d", device->address, value ? 1:0);
		    for (i = 0; i < strlen(buf); i++)
			if (buf[i] == '-')
			    buf[i] = ',';
		    piUnlock(LOCK_DEVICES);
	    	    enableTransmit(device->gpiopin);	    
		    rc = toggleSwitch(buf);
		    disableTransmit();
		    piLock(LOCK_DEVICES);
		    syslog(LOG_NOTICE, "RC433 command %s rc=%d", buf, rc);
		    if (debug)
			fprintf(stdout, "RC433 command %s rc=%d\n", buf, rc);
                    device->value = value;
		    device->timestamp = time(NULL);
		    piUnlock(LOCK_DEVICES);
		    return rc;
	        }

		if ((device->type == DEVTYPE_GPIO) && (device->gpiopin != -1) && (device->present == DEVPRESENT_YES)) {

		}
#endif
		if ((device->type == DEVTYPE_W1) && (device->direction == DEVDIR_OUT_BIN) && (device->present == DEVPRESENT_YES)) {
		    if (strncmp(device->address, (char *)"3a", 2) == 0) {
			/*
			 * DS2413. First read state so that we can preserve the state of
			 * the "other" PIO channel. To make things a bit more complicated
			 * the bits in the state register differ from the output register.
			 */
			uint8_t	state, output;

			if ((rc = read_w1(device->address, (char *)"state")) >= 0) {
			    state = (unsigned int)rc;
			    output = (state & 0x01) + ((state & 0x04) >> 1);

			    if (device->subdevice == 0) {
				output = (output & 0xfe);
				output |= (value == 0) ? 0x01 : 0x00;
			    } else if (device->subdevice == 1) {
				output = (output & 0xfd);
				output |= (value == 0) ? 0x02 : 0x00;
			    } else {
				output = 0xff;
			    }

			    if ((write_w1(device->address, (char *)"output", output)) == 0) {
			    	syslog(LOG_NOTICE, "DS2413 PIO%c value=%d (%s)", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1, device->comment);
			    	if (debug)
				    fprintf(stdout, "DS2413 PIO%c value=%d (%s)\n", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1, device->comment);
				device->value = (value == 0) ? 0 : 1;
				device->timestamp = time(NULL);
			    }
			}
		    }
		}

#ifdef USE_SIMULATOR
		if ((device->type == DEVTYPE_SIM) && (device->direction == DEVDIR_OUT_BIN) && (device->present == DEVPRESENT_YES)) {
		    if ((strcmp((char *)"SimCooler", device->address) == 0) || (strcmp((char *)"SimHeater", device->address) == 0)) {
			if (value != device->value) {
			    syslog(LOG_NOTICE, "SIM %s value=%d", device->address, value);
			    if (debug)
			    	fprintf(stdout, "SIM %s value=%d\n", device->address, value);
			}
			device->value = value;
			device->timestamp = time(NULL);
			if (strcmp((char *)"SimCooler", device->address) == 0)
			    SIMcooling = value;
			if (strcmp((char *)"SimHeater", device->address) == 0)
			    SIMheating = value;
		    }
		}
#endif
	    } else {
#ifdef HAVE_WIRINGPI_H
		piUnlock(LOCK_DEVICES);
#endif
		return 0;
	    }
	}
    }
#ifdef HAVE_WIRINGPI_H
    piUnlock(LOCK_DEVICES);
#endif

    return 0;
}	   



/*
 * Auto detect hotplugged or known to be present devices
 */
int devices_detect(void)
{
    struct dirent	*de;
    DIR			*fd;
    devices_list	*device, *ndev;
    int			found, subdevices, ival, i, rc = 0;
    char		buf[40];
    uuid_t		uu;
#ifdef HAVE_WIRINGPI_H
    int			pin;
#endif

    /*
     * Scan for 1-wire devices
     */
    if ((fd = opendir((char *)"/sys/bus/w1/devices"))) {
	while ((de = readdir(fd))) {
	    if (de->d_name[0] != '.') {
		found = FALSE;
		for (device = Config.devices; device; device = device->next) {
		    if (strcmp(device->address,de->d_name) == 0) {
			found = TRUE;
			break;
		    }
		}

		if (found == FALSE) {
		    strncpy(buf, de->d_name, 2);
		    buf[2] = '\0';
		    sscanf(buf, "%02x", &ival);
		    syslog(LOG_NOTICE, "Scan 1-wire %02x %d", ival, ival);
		    subdevices = 1;
		    if (strcmp(buf, (char *)"29") == 0)
			subdevices = 8;
		    if (strcmp(buf, (char *)"3a") == 0)
			subdevices = 2;
		    for (i = 0; i < subdevices; i++) {
			ndev = (devices_list *)malloc(sizeof(devices_list));
			ndev->next = NULL;
			ndev->version = 1;
			ndev->uuid = malloc(37);
			uuid_generate(uu);
			uuid_unparse(uu, ndev->uuid);
			ndev->type = DEVTYPE_W1;
			ndev->direction = DEVDIR_UNDEF;
			if (strcmp(buf, (char *)"10") == 0) {
			    ndev->direction = DEVDIR_IN_ANALOG;
			    ndev->description = xstrcpy((char *)"DS18S20 Digital thermometer");
			} else if (strcmp(buf, (char *)"22") == 0) {
			    ndev->direction = DEVDIR_IN_ANALOG;
			    ndev->description = xstrcpy((char *)"DS1820 Digital thermometer");
			} else if (strcmp(buf, (char *)"28") == 0) {
			    ndev->direction = DEVDIR_IN_ANALOG;
			    ndev->description = xstrcpy((char *)"DS18B20 Digital thermometer");
			} else if (strcmp(buf, (char *)"29") == 0) {
			    ndev->description = xstrcpy((char *)"DS2408 8 Channel addressable switch/LCD");
			    ndev->direction = DEVDIR_IN_BIN;
			} else if (strcmp(buf, (char *)"3a") == 0) {
			    ndev->description = xstrcpy((char *)"DS2413 Dual channel addressable switch");
			    ndev->direction = DEVDIR_IN_BIN;
			} else if (strcmp(buf, (char *)"3b") == 0) {
			    ndev->direction = DEVDIR_IN_ANALOG;
			    ndev->description = xstrcpy((char *)"DS1825 Digital thermometer");
			} else if (strcmp(buf, (char *)"42") == 0) {
			    ndev->direction = DEVDIR_IN_ANALOG;
			    ndev->description = xstrcpy((char *)"DS28EA00 Digital thermometer");
			} else if (strcmp(buf, (char *)"w1") == 0) {
			    ndev->description = xstrcpy((char *)"Master System device");
			} else {
			    ndev->description = xstrcpy((char *)"Unknown device family ");
			    ndev->description = xstrcat(ndev->description, buf);
			}
			ndev->value = ndev->offset = ndev->inuse = 0;
			ndev->present = DEVPRESENT_YES;
			ndev->address = xstrcpy(de->d_name);
			ndev->subdevice = i;
			ndev->gpiopin = -1;
			ndev->comment = xstrcpy((char *)"Auto detected device");
			ndev->timestamp = time(NULL);

			if (Config.devices == NULL) {
			    Config.devices = ndev;
			} else {
			    for (device = Config.devices; device; device = device->next) {
				if (device->next == NULL) {
				    device->next = ndev;
				    break;
				}
			    }
			}
			rc++;
		    }
		}
	    }
	}
	closedir(fd);
    }

#ifdef HAVE_WIRINGPI_H
    if (piBoardRev() == 2) {
	/*
	 * Support rev B and newer boards only
	 */
	found = FALSE;
	for (device = Config.devices; device; device = device->next) {
	    if (device->type == DEVTYPE_GPIO) {
		found = TRUE;
		break;
	    }
	}

    	if (found == FALSE) {
	    /*
	     * There were no GPIO devices found.
	     */
	    subdevices = 12;
	    pin = 0;
	    for (i = 0; i < subdevices; i++) {
	    	if (i == 8)
		    pin = 17;

	    	ndev = (devices_list *)malloc(sizeof(devices_list));
	    	ndev->next = NULL;
	    	ndev->version = 1;
	    	ndev->uuid = malloc(37);
	    	uuid_generate(uu);
	    	uuid_unparse(uu, ndev->uuid);
	    	ndev->type = DEVTYPE_GPIO;
	    	ndev->value = digitalRead(pin);
	    	ndev->present = DEVPRESENT_YES;
	    	ndev->address = xstrcpy((char *)"GPIO");
	    	snprintf(buf, 39, "Raspberry GPIO %d", i);
	    	ndev->description = xstrcpy(buf);
	    	ndev->subdevice = i;
	    	ndev->gpiopin = pin;
	    	ndev->timestamp = time(NULL);
		if (i == PANEL_LED) {
		    ndev->direction = DEVDIR_OUT_BIN;
		    ndev->inuse = 1;
		    ndev->comment = xstrcpy((char *)"Frontpanel LED");
		} else if (i == PANEL_ENTER) {
		    ndev->direction = DEVDIR_IN_BIN;
		    ndev->inuse = 1;
		    ndev->comment = xstrcpy((char *)"Frontpanel Enter key");
		} else if (i == PANEL_DOWN) {
		    ndev->direction = DEVDIR_IN_BIN;
		    ndev->inuse = 1;
		    ndev->comment = xstrcpy((char *)"Frontpanel Down key");
		} else if (i == PANEL_UP) {
		    ndev->direction = DEVDIR_IN_BIN;
		    ndev->inuse = 1;
		    ndev->comment = xstrcpy((char *)"Frontpanel Up key");
		} else if (i == 7) {
		    ndev->direction = DEVDIR_INTERN;
		    ndev->inuse = 1;
		    ndev->comment = xstrcpy((char *)"1-Wire bus");
	    	} else {
		    ndev->direction = DEVDIR_IN_BIN;
		    ndev->inuse = 0;
		    ndev->comment = xstrcpy((char *)"Raspberry GPIO");
	    	}
	    	pin++;

	    	if (Config.devices == NULL) {
		    Config.devices = ndev;
	    	} else {
		    for (device = Config.devices; device; device = device->next) {
		        if (device->next == NULL) {
			    device->next = ndev;
			    break;
		    	}
		    }
	    	}
	    	rc++;
	    }
	}
    }
#endif

#ifdef USE_SIMULATOR
    found = FALSE;
    for (device = Config.devices; device; device = device->next) {
	if (device->type == DEVTYPE_SIM) {
	    found = TRUE;
	    break;
	}
    }

    if (found == FALSE) {
	subdevices = 5;
	for (i = 0; i < subdevices; i++) {
	    ndev = (devices_list *)malloc(sizeof(devices_list));
	    ndev->next = NULL;
	    ndev->version = 1;
	    ndev->uuid = malloc(37);
	    uuid_generate(uu);
	    uuid_unparse(uu, ndev->uuid);
	    ndev->type = DEVTYPE_SIM;
	    ndev->value = ndev->offset = 0;
	    ndev->present = DEVPRESENT_YES;
	    ndev->subdevice = i;
	    ndev->gpiopin = -1;
	    ndev->comment = xstrcpy((char *)"Auto detected device");
	    ndev->timestamp = time(NULL);
	    ndev->inuse = 0;
	    switch (i) {
		case 0:	ndev->direction = DEVDIR_IN_ANALOG;
			ndev->address = xstrcpy((char *)"SimRoomTemp");
			ndev->description = xstrcpy((char *)"Simulated room temperature");
			break;
		case 1:	ndev->direction = DEVDIR_IN_ANALOG;
			ndev->address = xstrcpy((char *)"SimAirTemp");
			ndev->description = xstrcpy((char *)"Simulated air temperature");
			break;
		case 2:	ndev->direction = DEVDIR_IN_ANALOG;
			ndev->address = xstrcpy((char *)"SimBeerTemp");
			ndev->description = xstrcpy((char *)"Simulated beer temperature");
			break;
		case 3:	ndev->direction = DEVDIR_OUT_ANALOG;
			ndev->address = xstrcpy((char *)"SimHeater");
			ndev->description = xstrcpy((char *)"Simulated heater");
			break;
		case 4:	ndev->direction = DEVDIR_OUT_ANALOG;
			ndev->address = xstrcpy((char *)"SimCooler");
			ndev->description = xstrcpy((char *)"Simulated cooler");
			break;
	    }

	    if (Config.devices == NULL) {
		Config.devices = ndev;
	    } else {
		for (device = Config.devices; device; device = device->next) {
		    if (device->next == NULL) {
			device->next = ndev;
			break;
		    }
		}
	    }
	    rc++;
	}
    }
#endif

    return rc;
}



#ifdef HAVE_WIRINGPI_H
PI_THREAD (my_devices_loop)
#else
void *my_devices_loop(void *threadid)
#endif
{
    devices_list	*device;
#ifdef USE_SIMULATOR
    simulator_list	*simulator;
#endif
    char		*addr = NULL, line[60], *p = NULL;
    FILE		*fp;
    int			temp, rc;
#ifdef HAVE_WIRINGPI_H
    time_t		now;
#endif

    syslog(LOG_NOTICE, "Thread my_devices_loop started");

#ifdef HAVE_WIRINGPI_H
    if ((rc = piHiPri(10)))
    	syslog(LOG_NOTICE, "my_devices_loop: piHiPri(10) rc=%d", rc);
#endif

    /*
     * Loop forever until the external shutdown variable is set.
     */
    for (;;) {

    	/*
    	 * Process all devices.
    	 */
    	for (device = Config.devices; device; device = device->next) {

	    if (my_shutdown)
		break;

	    switch (device->type) {
		case DEVTYPE_W1:
			/*
			 * Only tested with DS18B20 but from the kernel source this
			 * should work with all 1-wire thermometer sensors.
			 */
			if ((strncmp(device->address, (char *)"10", 2) == 0) ||
			    (strncmp(device->address, (char *)"22", 2) == 0) ||
			    (strncmp(device->address, (char *)"28", 2) == 0) ||
			    (strncmp(device->address, (char *)"3b", 2) == 0) ||
			    (strncmp(device->address, (char *)"42", 2) == 0)) {
			    addr = xstrcpy((char *)"/sys/bus/w1/devices/");
			    addr = xstrcat(addr, device->address);
			    addr = xstrcat(addr, (char *)"/w1_slave");
			    if ((fp = fopen(addr, "r"))) {
				if (device->present != DEVPRESENT_YES) {
				     syslog(LOG_NOTICE, "sensor %s is back", device->address);
#ifdef HAVE_WIRINGPI_H
				     piLock(LOCK_DEVICES);
#endif
				     device->present = DEVPRESENT_YES;
#ifdef HAVE_WIRINGPI_H
				     piUnlock(LOCK_DEVICES);
#endif
				}
				/*
				 * The output looks like:
				 * 72 01 4b 46 7f ff 0e 10 57 : crc=57 YES
				 * 72 01 4b 46 7f ff 0e 10 57 t=23125
				 */
				fgets(line, 50, fp);
				line[strlen(line)-1] = '\0';
				if ((line[36] == 'Y') && (line[37] == 'E')) {
				    /* CRC is Ok, continue */
				    fgets(line, 50, fp);
				    line[strlen(line)-1] = '\0';
				    strtok(line, (char *)"=");
				    p = strtok(NULL, (char *)"=");
				    rc = sscanf(p, "%d", &temp);
#ifdef HAVE_WIRINGPI_H
				    piLock(LOCK_DEVICES);
#endif
				    if ((rc == 1) && (device->value != temp)) {
					device->value = temp;
				    	device->timestamp = time(NULL);
				    }
#ifdef HAVE_WIRINGPI_H
				    piUnlock(LOCK_DEVICES);
#endif
				} else {
				    syslog(LOG_NOTICE, "sensor %s CRC error", device->address);
#ifdef HAVE_WIRINGPI_H
				    piLock(LOCK_DEVICES);                
#endif
				    device->present = DEVPRESENT_ERROR;
#ifdef HAVE_WIRINGPI_H
				    piUnlock(LOCK_DEVICES);              
#endif
				}
				fclose(fp);
			    } else {
				if (device->present != DEVPRESENT_NO) {
				    syslog(LOG_NOTICE, "sensor %s is missing", device->address);
#ifdef HAVE_WIRINGPI_H
				    piLock(LOCK_DEVICES);                
#endif
				    device->present = DEVPRESENT_NO;
#ifdef HAVE_WIRINGPI_H          
				    piUnlock(LOCK_DEVICES);              
#endif
				}
			    }
			    free(addr);
			    addr = NULL;
			} /* if temperature sensor */
			/*
			 * DS2408 8 Channel addressable switch
			 */
			if (strncmp(device->address, (char *)"29", 2) == 0) {
			    /*
			     * Always read current state and set these bits
			     * in the subdevices value. We do this even with
			     * the output bits, they should match.
			     */
			    addr = xstrcpy((char *)"/sys/bus/w1/devices/");
			    addr = xstrcat(addr, device->address);
			    addr = xstrcat(addr, (char *)"/state");
			    if ((fp = fopen(addr, "r"))) {
				if (device->present != DEVPRESENT_YES) {
				    syslog(LOG_NOTICE, "DS2408 %s is back", device->address);
#ifdef HAVE_WIRINGPI_H
				    piLock(LOCK_DEVICES);
#endif
				    device->present = DEVPRESENT_YES;
#ifdef HAVE_WIRINGPI_H
				    piUnlock(LOCK_DEVICES);
#endif
				}

				fclose(fp);
			    } else {
				if (device->present != DEVPRESENT_NO) {
				    syslog(LOG_NOTICE, "DS2408 %s is missing", device->address);
#ifdef HAVE_WIRINGPI_H
				    piLock(LOCK_DEVICES);
#endif
				    device->present = DEVPRESENT_NO;
#ifdef HAVE_WIRINGPI_H          
				    piUnlock(LOCK_DEVICES);
#endif
				}
			    }
			    free(addr);
			    addr = NULL;
			}
			/*
			 * DS2413 Dual channel addressable switch
			 */
			if (strncmp(device->address, (char *)"3a", 2) == 0) {
			    addr = xstrcpy((char *)"/sys/bus/w1/devices/");
			    addr = xstrcat(addr, device->address);
			    addr = xstrcat(addr, (char *)"/state");

			    if ((access(addr, R_OK)) == 0) {
				if (device->present != DEVPRESENT_YES) {
				    syslog(LOG_NOTICE, "DS2413 %s is back", device->address);
#ifdef HAVE_WIRINGPI_H
				    piLock(LOCK_DEVICES);
#endif
				    device->present = DEVPRESENT_YES;
#ifdef HAVE_WIRINGPI_H
				    piUnlock(LOCK_DEVICES);
#endif
				}
				if ((rc = read_w1(device->address, (char *)"state")) >= 0) {
#ifdef HAVE_WIRINGPI_H
				    piLock(LOCK_DEVICES);
#endif
				    /*
				     * Read PIOA or PIOB pin state bits
				     */
				    if (device->subdevice == 0)
					device->value = (rc & 0x01) ? 0 : 1;
				    else if (device->subdevice == 1)
					device->value = (rc & 0x04) ? 0 : 1;
				    device->timestamp = time(NULL);
#ifdef HAVE_WIRINGPI_H
				    piUnlock(LOCK_DEVICES);
#endif
				}
			    } else {
				if (device->present != DEVPRESENT_NO) {
				    syslog(LOG_NOTICE, "DS2413 %s is missing", device->address);
#ifdef HAVE_WIRINGPI_H
				    piLock(LOCK_DEVICES);
#endif
				    device->present = DEVPRESENT_NO;
#ifdef HAVE_WIRINGPI_H          
				    piUnlock(LOCK_DEVICES);
#endif
				}
			    }
			    free(addr);
			    addr = NULL;
			}

			break;

#ifdef HAVE_WIRINGPI_H
		case DEVTYPE_DHT:
			/*
			 * Make sure we don't read the sensor withing 2 seconds.
			 */
			now = time(NULL);
			if ((int)(now - dht11_last) > 2) {
			    dht11_pin = device->gpiopin;
			    dht11Read();
			    dht11_last = now;
			}
			if (device->subdevice == 0) {
			    piLock(LOCK_DEVICES);
			    if (dht11_valid) {
				device->value = dht11_temperature * 1000;
				device->timestamp = time(NULL);
				device->present = DEVPRESENT_YES;
			    } else {
				device->present = DEVPRESENT_ERROR;
			    }
			    piUnlock(LOCK_DEVICES);
			} else if (device->subdevice == 1) {
			    piLock(LOCK_DEVICES);
			    if (dht11_valid) {
				device->value = dht11_humidity * 1000;
				device->timestamp = time(NULL);
				device->present = DEVPRESENT_YES;
			    } else {
				device->present = DEVPRESENT_ERROR;
			    }
			    piUnlock(LOCK_DEVICES);
			}
			break;
#endif
#ifdef USE_SIMULATOR
		case DEVTYPE_SIM:
#ifdef HAVE_WIRINGPI_H
			piLock(LOCK_DEVICES);
#endif
			if (Config.simulators) {
			    simulator = Config.simulators;
			    if (device->subdevice == 0) {
			    	device->value = (int)(simulator->room_temperature * 1000);
			    	device->timestamp = time(NULL);
			    } else if (device->subdevice == 1) {
			    	device->value = (int)(simulator->air_temperature * 1000);
			    	device->timestamp = time(NULL);
			    } else if (device->subdevice == 2) {
			    	device->value = (int)(simulator->beer_temperature * 1000);
			    	device->timestamp = time(NULL);
			    }
			}
#ifdef HAVE_WIRINGPI_H
			piUnlock(LOCK_DEVICES);
#endif
			break;
#endif
		default:
			break;
	    }

	    /*
	     * Delay a bit after procesing a device.
	     */
	    usleep(10000);
	}
	/*
	 * Delay a bit after all devices
	 */
	usleep(100000);
    }

    syslog(LOG_NOTICE, "Thread my_devices_loop stopped");
    return 0;
}


mercurial