static int elro_db286a_callback(r_device *decoder, bitbuffer_t *bitbuffer) { data_t *data; uint8_t *b; char id_str[4*2+1]; // 33 bits expected, 5 minimum packet repetitions (14 expected) int row = bitbuffer_find_repeated_row(bitbuffer, 5, 33); if (row < 0 || bitbuffer->bits_per_row[row] != 33) return 0; b = bitbuffer->bb[row]; // 32 bits, trailing bit is dropped sprintf(id_str, "%02x%02x%02x%02x", b[0], b[1], b[2], b[3]); data = data_make( "model", "", DATA_STRING, "Elro-DB286A", "id", "ID", DATA_STRING, id_str, NULL); decoder_output_data(decoder, data); return 1; }
static int thermopro_tp11_sensor_callback(r_device *decoder, bitbuffer_t *bitbuffer) { int temp_raw, row; float temp_c; bitrow_t *bb = bitbuffer->bb; unsigned int device, value; data_t *data; // Compare first four bytes of rows that have 32 or 33 bits. row = bitbuffer_find_repeated_row(bitbuffer, 2, 32); if (row < 0) return 0; if (bitbuffer->bits_per_row[row] > 33) return 0; value = (bb[row][0] << 16) + (bb[row][1] << 8) + bb[row][2]; device = value >> 12; // Validate code for known devices. if ((device == 0xb34 || device == 0xdb4 ) && !valid(value, bb[row][3])) return 0; temp_raw = value & 0xfff; temp_c = (temp_raw - 200) / 10.; data = data_make( "model", "", DATA_STRING, _X("Thermopro-TP11","Thermopro TP11 Thermometer"), "id", "Id", DATA_INT, device, "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp_c, NULL); decoder_output_data(decoder, data); return 1; }
static int thermopro_tp12_sensor_callback(bitbuffer_t *bitbuffer) { int iTemp1, iTemp2, good = -1; float fTemp1, fTemp2; uint8_t *bytes; unsigned int device, value; char time_str[LOCAL_TIME_BUFLEN]; data_t *data; // The device transmits 16 rows, let's check for 3 matching. // (Really 17 rows, but the last one doesn't match because it's missing a trailing 1.) good = bitbuffer_find_repeated_row(bitbuffer, 5, 40); if (good < 0) { return 0; } bytes = bitbuffer->bb[good]; if (!bytes[0] && !bytes[1] && !bytes[2] && !bytes[3]) { return 0; // reduce false positives } // Note: the device ID changes randomly each time you replace the battery, so we can't early out based on it. // This is probably to allow multiple devices to be used at once. When you replace the receiver batteries // or long-press its power button, it pairs with the first device ID it hears. device = bytes[0]; if(debug_output) { // There is a mysterious checksum in bytes[4]. It may be the same as the checksum used by the TP-11, // which consisted of a lookup table containing, for each bit in the message, a byte to be xor-ed into // the checksum if the message bit was 1. It should be possible to solve for that table using Gaussian // elimination, so dump some data so we can try this. // This format is easily usable by bruteforce-crc, after piping through | grep raw_data | cut -d':' -f2 // bruteforce-crc didn't find anything, though - this may not be a CRC algorithm specifically. fprintf(stderr,"thermopro_tp12_raw_data:"); for(int bit_index = 0; bit_index < 40; ++bit_index){ fputc(bitrow_get_bit(bytes, bit_index) + '0', stderr); } fputc('\n', stderr); } iTemp1 = ((bytes[2] & 0xf0) << 4) | bytes[1]; iTemp2 = ((bytes[2] & 0x0f) << 8) | bytes[3]; fTemp1 = (iTemp1 - 200) / 10.; fTemp2 = (iTemp2 - 200) / 10.; local_time_str(0, time_str); data = data_make("time", "", DATA_STRING, time_str, "model", "", DATA_STRING, MODEL, "id", "Id", DATA_FORMAT, "\t %d", DATA_INT, device, "temperature_1_C", "Temperature 1 (Food)", DATA_FORMAT, "%.01f C", DATA_DOUBLE, fTemp1, "temperature_2_C", "Temperature 2 (Barbecue)", DATA_FORMAT, "%.01f C", DATA_DOUBLE, fTemp2, NULL); data_acquired_handler(data); return 1; }
static int maverick_et73_sensor_callback(r_device *decoder, bitbuffer_t *bitbuffer) { int temp1_raw, temp2_raw, row; float temp1_c, temp2_c; uint8_t *bytes; unsigned int device; data_t *data; // The device transmits many rows, let's check for 3 matching. row = bitbuffer_find_repeated_row(bitbuffer, 3, 48); if (row < 0) { return 0; } bytes = bitbuffer->bb[row]; if (!bytes[0] && !bytes[1] && !bytes[2] && !bytes[3]) { return 0; // reduce false positives } if (bitbuffer->bits_per_row[row] != 48) return 0; device = bytes[0]; if (decoder->verbose) { fprintf(stderr,"maverick_et73_raw_data:"); bitrow_print(bytes, 48); } temp1_raw = (bytes[1] << 4) | ((bytes[2] & 0xf0) ); temp2_raw = ((bytes[2] & 0x0f) << 8) | bytes[3]; temp1_c = temp1_raw * 0.1; temp2_c = temp2_raw * 0.1; data = data_make( "model", "", DATA_STRING, "Maverick ET73", "rid", "Random Id", DATA_INT, device, "temperature_1_C", "Temperature 1", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp1_c, "temperature_2_C", "Temperature 2", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp2_c, NULL); decoder_output_data(decoder, data); return 1; }
static int nexus_callback(bitbuffer_t *bitbuffer) { bitrow_t *bb = bitbuffer->bb; data_t *data; char time_str[LOCAL_TIME_BUFLEN]; if (debug_output > 1) { fprintf(stderr,"Possible Nexus: "); bitbuffer_print(bitbuffer); } uint8_t id; uint8_t channel; int16_t temp; uint8_t humidity; int r = bitbuffer_find_repeated_row(bitbuffer, 3, 36); /** The nexus protocol will trigger on rubicson data, so calculate the rubicson crc and make sure * it doesn't match. By guesstimate it should generate a correct crc 1/255% of the times. * So less then 0.5% which should be acceptable. */ if (!rubicson_crc_check(bb) && r >= 0 && bitbuffer->bits_per_row[r] <= 37 && // we expect 36 bits but there might be a trailing 0 bit bb[r][0] != 0 && bb[r][1] != 0 && bb[r][2] != 0 && bb[r][3] != 0) { /* Get time now */ local_time_str(0, time_str); /* Nibble 0,1 contains id */ id = bb[r][0]; channel = (bb[r][1]&0x03) + 1; /* Nible 3,4,5 contains 12 bits of temperature * The temerature is signed and scaled by 10 */ temp = (int16_t)((uint16_t)(bb[r][1] << 12) | (bb[r][2] << 4)); temp = temp >> 4; humidity = (uint8_t)(((bb[r][3]&0x0F)<<4)|(bb[r][4]>>4)); // Thermo if (bb[r][3] == 0xF0) { data = data_make("time", "", DATA_STRING, time_str, "model", "", DATA_STRING, "Nexus Temperature", "id", "House Code", DATA_INT, id, "channel", "Channel", DATA_INT, channel, "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp/10.0, NULL); data_acquired_handler(data); } // Thermo/Hygro else { data = data_make("time", "", DATA_STRING, time_str, "model", "", DATA_STRING, "Nexus Temperature/Humidity", "id", "House Code", DATA_INT, id, "channel", "Channel", DATA_INT, channel, "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp/10.0, "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, NULL); data_acquired_handler(data); } return 1; }