Skip to content

Commit

Permalink
Add support for Regency ceiling fans (merbanan#1948)
Browse files Browse the repository at this point in the history
  • Loading branch information
dtiller authored Jan 21, 2022
1 parent 32c1f4a commit e66eec4
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 4 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
[-w <filename> | help] Save data stream to output file (a '-' dumps samples to stdout)
[-W <filename> | help] Save data stream to output file, overwrite existing file
= Data output options =
[-F kv | json | csv | mqtt | influx | syslog | null | help] Produce decoded output in given format.
[-F kv | json | csv | mqtt | influx | syslog | trigger | null | help] Produce decoded output in given format.
Append output to file with :<filename> (e.g. -F csv:log.csv), defaults to stdout.
Specify host/port for syslog with e.g. -F syslog:127.0.0.1:1514
[-M time[:<options>] | protocol | level | noise[:secs] | stats | bits | help] Add various meta data to each output.
Expand Down Expand Up @@ -294,6 +294,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
[208] AVE TPMS
[209] SimpliSafe Gen 3 Home Security System
[210] Yale HSA (Home Security Alarm), YES-Alarmkit
[211] Regency Ceiling Fan Remote (-f 303.75M to 303.96M)
* Disabled by default, use -R n or -G
Expand Down Expand Up @@ -377,7 +378,7 @@ E.g. -X "n=doorbell,m=OOK_PWM,s=400,l=800,r=7000,g=1000,match={24}0xa9878c,repea
= Output format option =
[-F kv|json|csv|mqtt|influx|syslog|null] Produce decoded output in given format.
[-F kv|json|csv|mqtt|influx|syslog|trigger|null] Produce decoded output in given format.
Without this option the default is KV output. Use "-F null" to remove the default.
Append output to file with :<filename> (e.g. -F csv:log.csv), defaults to stdout.
Specify MQTT server with e.g. -F mqtt://localhost:1883
Expand Down
1 change: 1 addition & 0 deletions conf/rtl_433.example.conf
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ stop_after_successful_events false
protocol 208 # AVE TPMS
protocol 209 # SimpliSafe Gen 3 Home Security System
protocol 210 # Yale HSA (Home Security Alarm), YES-Alarmkit
protocol 211 # Regency Ceiling Fan Remote (-f 303.75M to 303.96M)

## 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 @@ -218,6 +218,7 @@
DECL(tpms_ave) \
DECL(simplisafe_gen3) \
DECL(yale_hsa) \
DECL(regency_fan) \

/* Add new decoders here. */

Expand Down
4 changes: 2 additions & 2 deletions man/man1/rtl_433.1
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Save data stream to output file (a '\-' dumps samples to stdout)
Save data stream to output file, overwrite existing file
.SS "Data output options"
.TP
[ \fB\-F\fI kv | json | csv | mqtt | influx | syslog | null | help\fP ]
[ \fB\-F\fI kv | json | csv | mqtt | influx | syslog | trigger | null | help\fP ]
Produce decoded output in given format.
Append output to file with :<filename> (e.g. \-F csv:log.csv), defaults to stdout.
Specify host/port for syslog with e.g. \-F syslog:127.0.0.1:1514
Expand Down Expand Up @@ -315,7 +315,7 @@ countonly : suppress detailed row output
E.g. \-X "n=doorbell,m=OOK_PWM,s=400,l=800,r=7000,g=1000,match={24}0xa9878c,repeats>=3"
.SS "Output format option"
.TP
[ \fB\-F\fI kv|json|csv|mqtt|influx|syslog|null\fP ]
[ \fB\-F\fI kv|json|csv|mqtt|influx|syslog|trigger|null\fP ]
Produce decoded output in given format.
.RS
Without this option the default is KV output. Use "\-F null" to remove the default.
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ add_library(r_433 STATIC
devices/quhwa.c
devices/radiohead_ask.c
devices/rainpoint.c
devices/regency_fan.c
devices/rftech.c
devices/rojaflex.c
devices/rubicson.c
Expand Down
204 changes: 204 additions & 0 deletions src/devices/regency_fan.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/** @file
Decoder for Regency fan remotes.
Copyright (C) 2020-2022 David E. Tiller
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.
*/

/**
Regency fans use OOK_PULSE_PPM encoding.
The packet starts with 576 uS start pulse.
- 0 is defined as a 375 uS gap followed by a 970 uS pulse.
- 1 is defined as a 880 uS gap followed by a 450 uS pulse.
Transmissions consist of the start bit followed by bursts of 20 bits.
These packets ar repeated up to 11 times.
As written, the PPM code always interpets a narrow gap as a 1 and a
long gap as a 0, however the actual data over the air is inverted,
i.e. a short gap is a 0 and a long gap is a 1. In addition, the data
is 5 nibbles long and is represented in Little-Endian format. In the
code I invert the bits and also reflect the bytes. Reflection introduces
an additional nibble at bit offsets 16-19, so the data is expressed a 3
complete bytes.
The examples below are _after_ inversion and reflection (MSB's are on
the left).
Packet layout
Bit number
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
CHANNEL | COMMAND | VALUE | 0 0 0 0| 4 bit checksum
CHANNEL is determined by the bit switches in the battery compartment. All
switches in the 'off' position result in a channel of 15, implying that the
switches pull the address lines down when in the on position.
COMMAND is one of the following:
1 0x01
value: (0xc0, unused).
2 0x02
value: 0x01-0x07. On my remote, the speeds are shown as 8 - value.
4 0x04
value: 0x00-0xc3. The value is the intensity percentage.
0x00 is off, 0xc3 is 99% (full).
5 0x05
value: 0x00 is 'off', 0x01 is on.
6 0x06
value: 0x07 is one way, 0x83 is the other.
The CHECKSUM is calculated by adding the nibbles of the first two bytes
and ANDing the result with 0x0f.
*/

#include "decoder.h"

static char *command_names[] = {
/* 0 */ "invalid",
/* 1 */ "fan_speed",
/* 2 */ "fan_speed",
/* 3 */ "invalid",
/* 4 */ "light_intensity",
/* 5 */ "light_delay",
/* 6 */ "fan_direction",
/* 7 */ "invalid",
/* 8 */ "invalid",
/* 9 */ "invalid",
/* 10 */ "invalid",
/* 11 */ "invalid",
/* 12 */ "invalid",
/* 13 */ "invalid",
/* 14 */ "invalid",
/* 15 */ "invalid"
};

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

data_t *data = NULL;
int row = 0; // a row index
int num_bits = 0;
int debug_output = decoder->verbose;
int return_code = 0;

bitbuffer_invert(bitbuffer);

for (row = 0; row < bitbuffer->num_rows; row++) {
num_bits = bitbuffer->bits_per_row[row];

if (num_bits != 21) { // Max number of bits is 21
if (debug_output > 1) {
fprintf(stderr, "Expected %d bits, got %d.\n", 21, num_bits); // Max number of bits is 21
}

continue;
}

uint8_t bytes[3]; // Max number of bytes is 3
bitbuffer_extract_bytes(bitbuffer, row, 1, bytes, 21); // Valid byte offset is 1, Max number of bits is 21
reflect_bytes(bytes, 3); // Max number of bytes is 3

// Calculate nibble sum and compare
int checksum = add_nibbles(bytes, 2) & 0x0f;
if (checksum != bytes[2]) { // Sum is in byte 2
if (debug_output > 1) {
fprintf(stderr, "Checksum failure: expected %0x, got %0x\n", bytes[2], checksum); // Sum is in byte 2
}

continue;
}

/*
* Now that message "envelope" has been validated, start parsing data.
*/
int command = bytes[0] >> 4; // Command and Channel are in byte 0
int channel = ~bytes[0] & 0x0f; // Command and Channel are in byte 0
int value = bytes[1]; // Value is ib byte 1
char value_string[64] = {0};

switch(command) {
case 1: // 1 is the command to STOP
sprintf(value_string, "stop");
break;

case 2: // 2 is the command to change fan speed
sprintf(value_string, "speed %d", value);
break;

case 4: // 4 is the command to change the light intensity
sprintf(value_string, "%d %%", value);
break;

case 5: // 5 is the command to set the light delay
sprintf(value_string, "%s", value == 0 ? "off" : "on");
break;

case 6: // 6 is the command to change fan direction
sprintf(value_string, "%s", value == 0x07 ? "clockwise" : "counter-clockwise");
break;

default:
if (debug_output > 1) {
fprintf(stderr, "Unknown command: %d\n", command);
continue;
}
break;
}

return_code++;

/* clang-format off */

data = data_make(
"model", "", DATA_STRING, "Regency-Remote",
"channel", "", DATA_INT, channel,
"command", "", DATA_STRING, command_names[command],
"value", "", DATA_STRING, value_string,
"mic", "", DATA_STRING, "nibble_sum",
NULL);

/* clang-format on */

decoder_output_data(decoder, data);
}

return return_code;
}

/*
* List of fields that may appear in the output
*
* Used to determine what fields will be output in what
* order for this device when using -F csv.
*
*/
static char *output_fields[] = {
"model",
"type",
"channel",
"command",
"value",
"mic",
NULL,
};

r_device regency_fan = {
.name = "Regency Ceiling Fan Remote (-f 303.75M to 303.96M)",
.modulation = OOK_PULSE_PWM,
.short_width = 580,
.long_width = 976,
.gap_limit = 8000,
.reset_limit = 14000,
.decode_fn = &regency_fan_decode,
.fields = output_fields,
};
1 change: 1 addition & 0 deletions vs15/rtl_433.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ COPY ..\..\libusb\MS64\dll\libusb*.dll $(TargetDir)</Command>
<ClCompile Include="..\src\devices\quhwa.c" />
<ClCompile Include="..\src\devices\radiohead_ask.c" />
<ClCompile Include="..\src\devices\rainpoint.c" />
<ClCompile Include="..\src\devices\regency_fan.c" />
<ClCompile Include="..\src\devices\rftech.c" />
<ClCompile Include="..\src\devices\rojaflex.c" />
<ClCompile Include="..\src\devices\rubicson.c" />
Expand Down
3 changes: 3 additions & 0 deletions vs15/rtl_433.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,9 @@
<ClCompile Include="..\src\devices\rainpoint.c">
<Filter>Source Files\devices</Filter>
</ClCompile>
<ClCompile Include="..\src\devices\regency_fan.c">
<Filter>Source Files\devices</Filter>
</ClCompile>
<ClCompile Include="..\src\devices\rftech.c">
<Filter>Source Files\devices</Filter>
</ClCompile>
Expand Down

0 comments on commit e66eec4

Please sign in to comment.