Add support for Regency ceiling fans (#1948)
This commit is contained in:
parent
32c1f4a65f
commit
e66eec4e3b
8 changed files with 216 additions and 4 deletions
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -218,6 +218,7 @@
|
|||
DECL(tpms_ave) \
|
||||
DECL(simplisafe_gen3) \
|
||||
DECL(yale_hsa) \
|
||||
DECL(regency_fan) \
|
||||
|
||||
/* Add new decoders here. */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
204
src/devices/regency_fan.c
Normal file
204
src/devices/regency_fan.c
Normal file
|
@ -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 = ®ency_fan_decode,
|
||||
.fields = output_fields,
|
||||
};
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue