Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Rosstech Digital Control Unit DCU-706/Sundance/Jacuzzi #2612

Merged
merged 10 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,9 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
[242]* Baldr / RainPoint rain gauge.
[243] Celsia CZC1 Thermostat
[244] Fine Offset Electronics WS90 weather station
[245]* ThermoPro TX-2C Thermometer
[245]* ThermoPro TX-2C Thermometer and Humidity sensor
[246] TFA 30.3151 Weather Station
[247] Rosstech Digital Control Unit DCU-706/Sundance/Jacuzzi

* Disabled by default, use -R n or a conf file to enable

Expand All @@ -339,7 +340,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
[-d <RTL-SDR USB device index>] (default: 0)
[-d :<RTL-SDR USB device serial (can be set with rtl_eeprom -s)>]
To set gain for RTL-SDR use -g <gain> to set an overall gain in dB.
SoapySDR device driver is available.
SoapySDR device driver is not available.
[-d ""] Open default SoapySDR device
[-d driver=rtlsdr] Open e.g. specific SoapySDR device
To set gain for SoapySDR use -g ELEM=val,ELEM=val,... e.g. -g LNA=20,TIA=8,PGA=2 (for LimeSDR).
Expand Down
4 changes: 3 additions & 1 deletion conf/rtl_433.example.conf
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,9 @@ stop_after_successful_events false
# protocol 242 # Baldr / RainPoint rain gauge.
protocol 243 # Celsia CZC1 Thermostat
protocol 244 # Fine Offset Electronics WS90 weather station
# protocol 245 # ThermoPro TX-2C Thermometer
# protocol 245 # ThermoPro TX-2C Thermometer and Humidity sensor
protocol 246 # TFA 30.3151 Weather Station
protocol 247 # Rosstech Digital Control Unit DCU-706/Sundance/Jacuzzi

## Flex devices (command line option "-X")

Expand Down
1 change: 1 addition & 0 deletions include/rtl_433_devices.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@
DECL(fineoffset_ws90) \
DECL(thermopro_tx2c) \
DECL(tfa_303151) \
DECL(rosstech_dcu706) \

/* Add new decoders here. */

Expand Down
2 changes: 1 addition & 1 deletion man/man1/rtl_433.1
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ RTL\-SDR device driver is available.
To set gain for RTL\-SDR use \-g <gain> to set an overall gain in dB.
.RE
.RS
SoapySDR device driver is available.
SoapySDR device driver is not available.
.RE
.TP
[ \fB\-d\fI ""\fP ]
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ add_library(r_433 STATIC
devices/revolt_nc5462.c
devices/rftech.c
devices/rojaflex.c
devices/rosstech_dcu706.c
devices/rubicson.c
devices/rubicson_48659.c
devices/rubicson_pool_48942.c
Expand Down
149 changes: 149 additions & 0 deletions src/devices/rosstech_dcu706.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/** @file
Rosstech Digital Control Unit DCU-706/Sundance

Copyright (C) 2023 suaveolent

This program 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 of the License, or
(at your option) any later version.
*/

#include "decoder.h"

/**
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
Rosstech Digital Control Unit DCU-706/Sundance/Jacuzzi

Supported Models:
Sundance DCU-6560-131, SD-880 Series, PN 6560-131
Jacuzzi DCU-2560-131, Jac-J300/J400 and SD-780 series, PN 6560-132/2560-131

Data layout:

SS IIII TT CC

- S: 8 bit sync byte and type of transmission
- I: 16 bit ID
- T: 8 bit temp packet in degrees F
- C: 8 bit Checksum: Count 1s for each bit of each element:
Set bit to 1 if number is even 0 if odd

11 bits/byte: 1 start bit, 0 stop bits and odd parity

*/

static const char transmissionTypeData[] = "Data Transmission";
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
static const char transmissionTypeBond[] = "Bond";


static uint8_t calculateChecksum(const uint8_t *data, size_t size) {
uint8_t checksum = 0;

for (int bit = 0; bit < 8; bit++) {
int count = 0;

for (size_t i = 0; i < size; i++) {
count += (data[i] >> bit) & 1;
}

if (count % 2 == 0) {
checksum |= (1 << bit);
}
}

return checksum;
}

suaveolent marked this conversation as resolved.
Show resolved Hide resolved


static int rosstech_dcu706_decode(r_device *decoder, bitbuffer_t *bitbuffer)
{

// We need 55 bits
uint8_t msg[7];

if (bitbuffer->num_rows != 1
|| bitbuffer->bits_per_row[0] < 55
|| bitbuffer->bits_per_row[0] > 300) {
decoder_logf(decoder, 2, __func__, "bit_per_row %u out of range", bitbuffer->bits_per_row[0]);
return DECODE_ABORT_EARLY; // Unrecognized data
}

uint8_t const preambleDataTransmission[] = {0xDD, 0x40};
suaveolent marked this conversation as resolved.
Show resolved Hide resolved

unsigned start_pos = bitbuffer_search(bitbuffer, 0, 0, preambleDataTransmission, 11);

if (start_pos == bitbuffer->bits_per_row[0]) {

// The Bond command also contains the temperature
uint8_t const preambleBond[] = {0xCD, 0x00};
suaveolent marked this conversation as resolved.
Show resolved Hide resolved

start_pos = bitbuffer_search(bitbuffer, 0, 0, preambleBond, 11);

if (start_pos == bitbuffer->bits_per_row[0]) {
return DECODE_ABORT_LENGTH;
}
}

if (start_pos + 55 > bitbuffer->bits_per_row[0]) {
return DECODE_ABORT_LENGTH;
}

bitbuffer_extract_bytes(bitbuffer, 0, start_pos, msg, sizeof(msg) * 8);

uint8_t syncType = (msg[0] << 1) | (msg[1] >> 7); //S
uint8_t id_high = (msg[1] << 4 | msg[2] >> 4);
uint8_t id_low = (msg[2] << 7 | msg[3] >> 1);
uint16_t id = (uint16_t)(id_high << 8) | id_low; // I
uint8_t temp = msg[4] << 2 | msg[5] >> 6; // T
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
uint8_t checkSum = msg[5] << 5 | msg[6] >> 3; // C

suaveolent marked this conversation as resolved.
Show resolved Hide resolved

// Create a uint8_t array to hold the extracted values
uint8_t extractedData[4];
extractedData[0] = syncType;
extractedData[1] = id_high;
extractedData[2] = id_low;
extractedData[3] = temp;

uint8_t calculatedChecksum = calculateChecksum(extractedData, sizeof(extractedData) / sizeof(extractedData[0]));
if (calculatedChecksum != checkSum) {
decoder_logf(decoder, 2, __func__, "Sanity Check failed. Expected: %04x, Calculated: %04x. Maybe sanity function calculated wrong!", checkSum, calculatedChecksum);
// return DECODE_FAIL_SANITY;
}

uint8_t temp_c = ((temp-32)*5)/9;

/* clang-format off */
data_t *data = data_make(
"model", "Model", DATA_STRING, "Rosstech Digital Control Unit DCU-706/Sundance/Jacuzzi",
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
"syncType", "Transmission Type", DATA_STRING, syncType == 0xba ? transmissionTypeData : transmissionTypeBond,
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
"id", "ID", DATA_FORMAT, "%04x", DATA_INT, id,
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
"temperature_C", "Temperature", DATA_FORMAT, "%d °C", DATA_INT, temp_c,
"checkSum", "Integrity", DATA_STRING, "Check Sum",
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
NULL);
/* clang-format on */

decoder_output_data(decoder, data);
return 1;

}

static char const *const output_fields[] = {
"model",
"id",
"temp",
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
"mic",
NULL,
};

r_device const rosstech_dcu706 = {
.name = "Rosstech Digital Control Unit DCU-706/Sundance/Jacuzzi",
.modulation = OOK_PULSE_PCM,
.short_width = 200,
.long_width = 200,
.sync_width = 0, // 1:10, tuned to widely match 2450 to 2850
suaveolent marked this conversation as resolved.
Show resolved Hide resolved
.reset_limit = 2000,
.decode_fn = &rosstech_dcu706_decode,
.fields = output_fields,
};
suaveolent marked this conversation as resolved.
Show resolved Hide resolved