Example #1
0
static int acurite_txr_callback(bitbuffer_t *bitbuf) {
    int browlen;
    uint8_t *bb;
    float tempc, tempf, wind_dird, rainfall = 0.0, wind_speedmph;
    uint8_t humidity, sensor_status, repeat_no, message_type;
    char channel, *wind_dirstr = "";
    uint16_t sensor_id;
    int wind_speed, raincounter;


    local_time_str(0, time_str);

    if (debug_output > 1) {
        fprintf(stderr,"acurite_txr\n");
        bitbuffer_print(bitbuf);
    }

    for (uint16_t brow = 0; brow < bitbuf->num_rows; ++brow) {
	browlen = (bitbuf->bits_per_row[brow] + 7)/8;
	bb = bitbuf->bb[brow];

	if (debug_output > 1)
	    fprintf(stderr,"acurite_txr: row %d bits %d, bytes %d \n", brow, bitbuf->bits_per_row[brow], browlen);

	if (bitbuf->bits_per_row[brow] < ACURITE_TXR_BITLEN ||
	    bitbuf->bits_per_row[brow] > ACURITE_5N1_BITLEN + 1) {
	    if (debug_output > 1 && bitbuf->bits_per_row[brow] > 16)
		fprintf(stderr,"acurite_txr: skipping wrong len\n");
	    continue;
	}

	// There will be 1 extra false zero bit added by the demod.
	// this forces an extra zero byte to be added
	if (bb[browlen - 1] == 0)
	    browlen--;

	if (!acurite_crc(bb,browlen - 1)) {
	    if (debug_output) {
		fprintf(stderr, "%s Acurite bad checksum:", time_str);
		for (uint8_t i = 0; i < browlen; i++)
		    fprintf(stderr," 0x%02x",bb[i]);
		fprintf(stderr,"\n");
	    }
	    continue;
	}

	if (debug_output) {
	    fprintf(stderr, "acurite_txr Parity: ");
	    for (uint8_t i = 0; i < browlen; i++) {
		fprintf(stderr,"%d",byteParity(bb[i]));
	    }
	    fprintf(stderr,"\n");
	}


	// tower sensor messages are 7 bytes.
	// @todo - see if there is a type in the message that
	// can be used instead of length to determine type
	if (browlen == ACURITE_TXR_BITLEN / 8) {
	    channel = acurite_getChannel(bb[0]);
	    sensor_id = acurite_txr_getSensorId(bb[0],bb[1]);
	    sensor_status = bb[2]; // @todo, uses parity? & 0x07f
	    humidity = acurite_getHumidity(bb[3]);
	    tempc = acurite_txr_getTemp(bb[4], bb[5]);
	    tempf = celsius2fahrenheit(tempc);

	    printf("%s Acurite tower sensor 0x%04X Ch %c: %3.1F C %3.1F F %d %% RH\n",
		   time_str, sensor_id, channel, tempc, tempf, humidity);

	    // currently 0x44 seens to be a normal status and/or type
	    // for tower sensors.  Battery OK/Normal == 0x40
	    if (sensor_status != 0x44)
		printf("%s Acurite tower sensor 0x%04X Ch %c, Status %02X\n",
		       time_str, sensor_id, channel, sensor_status);

	}

	// The 5-n-1 weather sensor messages are 8 bytes.
	if (browlen == ACURITE_5N1_BITLEN / 8) {
	    channel = acurite_getChannel(bb[0]);
	    sensor_id = acurite_5n1_getSensorId(bb[0],bb[1]);
	    repeat_no = acurite_5n1_getMessageCaught(bb[0]);
	    message_type = bb[2] & 0x3f;


	    if (message_type == 0x31) {
		// Wind speed, wind direction, and rain fall
	        wind_speed = acurite_getWindSpeed(bb[3], bb[4]);
		wind_speedmph = kmph2mph(wind_speed);
		wind_dird = acurite_5n1_winddirections[bb[4] & 0x0f];
		wind_dirstr = acurite_5n1_winddirection_str[bb[4] & 0x0f];
		raincounter = acurite_getRainfallCounter(bb[5], bb[6]);
		if (acurite_raincounter > 0) {
		    // track rainfall difference after first run
		    rainfall = ( raincounter - acurite_raincounter ) * 0.01;
		    if (raincounter < acurite_raincounter) {
			printf("%s Acurite 5n1 sensor 0x%04X Ch %c, rain counter reset or wrapped around (old %d, new %d)\n",
			       time_str, sensor_id, channel, acurite_raincounter, raincounter);
			acurite_raincounter = raincounter;
		    }
		} else {
		    // capture starting counter
		    acurite_raincounter = raincounter;
		    printf("%s Acurite 5n1 sensor 0x%04X Ch %c, Total rain fall since last reset: %0.2f\n",
			   time_str, sensor_id, channel, raincounter * 0.01);
		}

		printf("%s Acurite 5n1 sensor 0x%04X Ch %c, Msg %02x, Wind %d kmph / %0.1f mph %0.1f° %s (%d), rain gauge %0.2f in.\n",
		       time_str, sensor_id, channel, message_type,
		       wind_speed, wind_speedmph,
		       wind_dird, wind_dirstr, bb[4] & 0x0f, rainfall);

	    } else if (message_type == 0x38) {
		// Wind speed, temperature and humidity
		wind_speed = acurite_getWindSpeed(bb[3], bb[4]);
		wind_speedmph = kmph2mph((float) wind_speed);
		tempf = acurite_getTemp(bb[4], bb[5]);
		tempc = fahrenheit2celsius(tempf);
		humidity = acurite_getHumidity(bb[6]);

		printf("%s Acurite 5n1 sensor 0x%04X Ch %c, Msg %02x, Wind %d kmph / %0.1f mph, %3.1F C %3.1F F %d %% RH\n",
		       time_str, sensor_id, channel, message_type,
		       wind_speed, wind_speedmph, tempc, tempf, humidity);
	    } else {
		printf("%s Acurite 5n1 sensor 0x%04X Ch %c, Status %02X, Unknown message type 0x%02x\n",
			time_str, sensor_id, channel, bb[3], message_type);
	    }
	}
    }

    return 0;
}
Example #2
0
/*
 * This callback handles several Acurite devices that use a very
 * similar RF encoding and data format:
 *:
 * - 592TXR temperature and humidity sensor
 * - 5-n-1 weather station
 * - 6045M Lightning Detectur with Temperature and Humidity
 */
static int acurite_txr_callback(bitbuffer_t *bitbuf) {
    int browlen, valid = 0;
    uint8_t *bb;
    float tempc, tempf, wind_dird, rainfall = 0.0, wind_speed, wind_speedmph;
    uint8_t humidity, sensor_status, sequence_num, message_type;
    char channel, *wind_dirstr = "";
    char channel_str[2];
    uint16_t sensor_id;
    int raincounter, temp, battery_low;
    uint8_t strike_count, strike_distance;
    data_t *data;


    local_time_str(0, time_str);

    if (debug_output > 1) {
        fprintf(stderr,"acurite_txr\n");
        bitbuffer_print(bitbuf);
    }

    for (uint16_t brow = 0; brow < bitbuf->num_rows; ++brow) {
	browlen = (bitbuf->bits_per_row[brow] + 7)/8;
	bb = bitbuf->bb[brow];

	if (debug_output > 1)
	    fprintf(stderr,"acurite_txr: row %d bits %d, bytes %d \n", brow, bitbuf->bits_per_row[brow], browlen);

	if ((bitbuf->bits_per_row[brow] < ACURITE_TXR_BITLEN ||
	     bitbuf->bits_per_row[brow] > ACURITE_5N1_BITLEN + 1) &&
	    bitbuf->bits_per_row[brow] != ACURITE_6045_BITLEN) {
	    if (debug_output > 1 && bitbuf->bits_per_row[brow] > 16)
		fprintf(stderr,"acurite_txr: skipping wrong len\n");
	    continue;
	}

	// There will be 1 extra false zero bit added by the demod.
	// this forces an extra zero byte to be added
	if (bb[browlen - 1] == 0)
	    browlen--;

	if (!acurite_checksum(bb,browlen - 1)) {
	    if (debug_output) {
		fprintf(stderr, "%s Acurite bad checksum:", time_str);
		for (uint8_t i = 0; i < browlen; i++)
		    fprintf(stderr," 0x%02x",bb[i]);
		fprintf(stderr,"\n");
	    }
	    continue;
	}

	if (debug_output) {
	    fprintf(stderr, "acurite_txr Parity: ");
	    for (uint8_t i = 0; i < browlen; i++) {
		fprintf(stderr,"%d",byteParity(bb[i]));
	    }
	    fprintf(stderr,"\n");
	}


	// tower sensor messages are 7 bytes.
	// @todo - see if there is a type in the message that
	// can be used instead of length to determine type
	if (browlen == ACURITE_TXR_BITLEN / 8) {
	    channel = acurite_getChannel(bb[0]);
	    sensor_id = acurite_txr_getSensorId(bb[0],bb[1]);
	    sensor_status = bb[2]; // @todo, uses parity? & 0x07f
	    humidity = acurite_getHumidity(bb[3]);
	    tempc = acurite_txr_getTemp(bb[4], bb[5]);
            sprintf(channel_str, "%c", channel);
            battery_low = sensor_status >>7;
		
            data = data_make(
                    "time",			"",		DATA_STRING,	time_str,
                    "model",	        	"",		DATA_STRING,	"Acurite tower sensor",
                    "id",			"",		DATA_INT,	sensor_id,
                    "channel",  		"",     	DATA_STRING, 	&channel_str,
                    "temperature_C", 	"Temperature",	DATA_FORMAT,	"%.1f C", DATA_DOUBLE, tempc,
                    "humidity",         "Humidity",	DATA_INT,	humidity,
                    "battery",          "Battery",    	DATA_INT, 	battery_low,
                    "status",		"",		DATA_INT,	sensor_status,
                    NULL);

            data_acquired_handler(data);
            valid++;
	}

	// The 5-n-1 weather sensor messages are 8 bytes.
	if (browlen == ACURITE_5N1_BITLEN / 8) {
        if (debug_output) {
            fprintf(stderr, "Acurite 5n1 raw msg: %02X %02X %02X %02X %02X %02X %02X %02X\n",
                bb[0], bb[1], bb[2], bb[3], bb[4], bb[5], bb[6], bb[7]);
        }
	    channel = acurite_getChannel(bb[0]);
        sprintf(channel_str, "%c", channel);        
	    sensor_id = acurite_5n1_getSensorId(bb[0],bb[1]);
	    sequence_num = acurite_5n1_getMessageCaught(bb[0]);
	    message_type = bb[2] & 0x3f;
        battery_low = (bb[2] & 0x40) >> 6;

	    if (message_type == ACURITE_MSGTYPE_WINDSPEED_WINDDIR_RAINFALL) {
            // Wind speed, wind direction, and rain fall
            wind_speed = acurite_getWindSpeed_kph(bb[3], bb[4]);
            wind_speedmph = kmph2mph(wind_speed);
            wind_dird = acurite_5n1_winddirections[bb[4] & 0x0f];
            wind_dirstr = acurite_5n1_winddirection_str[bb[4] & 0x0f];
            raincounter = acurite_getRainfallCounter(bb[5], bb[6]);
            if (acurite_5n1t_raincounter > 0) {
                // track rainfall difference after first run
                // FIXME when converting to structured output, just output
                // the reading, let consumer track state/wrap around, etc. 
                rainfall = ( raincounter - acurite_5n1t_raincounter ) * 0.01;
                if (raincounter < acurite_5n1t_raincounter) {
                    fprintf(stderr, "%s Acurite 5n1 sensor 0x%04X Ch %c, rain counter reset or wrapped around (old %d, new %d)\n",
                        time_str, sensor_id, channel, acurite_5n1t_raincounter, raincounter);
                    acurite_5n1t_raincounter = raincounter;
                }
            } else {
                // capture starting counter
                acurite_5n1t_raincounter = raincounter;
                fprintf(stderr, "%s Acurite 5n1 sensor 0x%04X Ch %c, Total rain fall since last reset: %0.2f\n",
                time_str, sensor_id, channel, raincounter * 0.01);
            }
                
            data = data_make(
                "time",         "",   DATA_STRING,    time_str,
                "model",        "",   DATA_STRING,    "Acurite 5n1 sensor",
                "sensor_id",    NULL,   DATA_FORMAT,    "0x%02X",   DATA_INT,       sensor_id,   
                "channel",      NULL,   DATA_STRING,    &channel_str,
                "sequence_num",  NULL,   DATA_INT,      sequence_num,
                "battery",      NULL,   DATA_STRING,    battery_low ? "OK" : "LOW",
                "message_type", NULL,   DATA_INT,       message_type,
                "wind_speed",   NULL,   DATA_FORMAT,    "%.1f mph", DATA_DOUBLE,     wind_speedmph,
                "wind_dir_deg", NULL,   DATA_FORMAT,    "%.1f", DATA_DOUBLE,    wind_dird,
                "wind_dir",     NULL,   DATA_STRING,    wind_dirstr,
                "rainfall_accumulation",     NULL,   DATA_FORMAT,    "%.2f in", DATA_DOUBLE,    rainfall,
                "raincounter_raw",  NULL,   DATA_INT,   raincounter,
                NULL);

            data_acquired_handler(data);

	    } else if (message_type == ACURITE_MSGTYPE_WINDSPEED_TEMP_HUMIDITY) {
            // Wind speed, temperature and humidity
            wind_speed = acurite_getWindSpeed_kph(bb[3], bb[4]);
            wind_speedmph = kmph2mph(wind_speed);
            tempf = acurite_getTemp(bb[4], bb[5]);
            tempc = fahrenheit2celsius(tempf);
            humidity = acurite_getHumidity(bb[6]);

            data = data_make(
                "time",         "",   DATA_STRING,    time_str,
                "model",        "",   DATA_STRING,    "Acurite 5n1 sensor",
                "sensor_id",    NULL,   DATA_FORMAT,    "0x%02X",   DATA_INT,       sensor_id,   
                "channel",      NULL,   DATA_STRING,    &channel_str,
                "sequence_num",  NULL,   DATA_INT,      sequence_num,
                "battery",      NULL,   DATA_STRING,    battery_low ? "OK" : "LOW",
                "message_type", NULL,   DATA_INT,       message_type,
                "wind_speed",   NULL,   DATA_FORMAT,    "%.1f mph", DATA_DOUBLE,     wind_speedmph,
                "temperature_F", 	"temperature",	DATA_FORMAT,    "%.1f F", DATA_DOUBLE,    tempf,
                "humidity",     NULL,	DATA_FORMAT,    "%d",   DATA_INT,   humidity,
                NULL);
            data_acquired_handler(data);
            
	    } else {
            fprintf(stderr, "%s Acurite 5n1 sensor 0x%04X Ch %c, Status %02X, Unknown message type 0x%02x\n",
                time_str, sensor_id, channel, bb[3], message_type);
	    }
	}

	if (browlen == ACURITE_6045_BITLEN / 8) {
	    channel = acurite_getChannel(bb[0]);  // same as TXR
	    sensor_id = (bb[1] << 8) | bb[2];     // TBD 16 bits or 20?
	    humidity = acurite_getHumidity(bb[3]);  // same as TXR
	    message_type = bb[4] & 0x7f;
	    temp = bb[5] & 0x7f; // TBD Not sure if this is the temp.
	    strike_count = bb[6] & 0x7f;
	    strike_distance = bb[7] & 0x7f;


	    printf("%s Acurite lightning 0x%04X Ch %c Msg Type 0x%02x: %d C %d %% RH Strikes %d Distance %d -",
		   time_str, sensor_id, channel, message_type, temp, humidity, strike_count, strike_distance);

	    // FIXME Temporarily dump message data until the decoding improves.
	    // Include parity indicator.
	    for (int i=0; i < browlen; i++) {
		char pc;
		pc = byteParity(bb[i]) == 0 ? ' ' : '*';
		fprintf(stdout, " %02x%c", bb[i], pc);
	    }
	    printf("\n");
	}

    }