-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add protocol 278 'omni.c' device driver for microcontroller multisensor protocol #3278
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
Open
hdtodd
wants to merge
43
commits into
merbanan:master
Choose a base branch
from
hdtodd:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
75ccbbf
Add Omni protocol
hdtodd 3f0fdf9
Add Omni protocol
hdtodd 5dc7fe3
Merge branch 'master' of https://github.com/merbanan/rtl_433
hdtodd f686aa3
Update comments for light intensity
hdtodd 8e81fb5
Fix coding style
hdtodd 6c8d665
Fix coding style
hdtodd ca701dc
Fix coding style
hdtodd b84c5ed
Correct 'const r_device omni'
hdtodd 8474d4a
Correct 'const r_device omni'
hdtodd 6f89084
Correct 'const r_device omni'
hdtodd e369f5a
Correct 'const r_device omni'
hdtodd 3db0926
Correct 'const r_device omni'
hdtodd 641f909
Correct 'const r_device omni'
hdtodd dfdc55d
Correct 'const r_device omni'
hdtodd be47e4a
Correct 'const r_device omni'
hdtodd 9324d13
Correct 'const r_device omni'
hdtodd e72c02d
Correct 'const r_device omni'
hdtodd a61f3ef
Correct 'const r_device omni'
hdtodd a58873f
Correct 'const r_device omni'
hdtodd 23d2b75
Correct 'const r_device omni'
hdtodd a996b24
Reinsert missing code for format 01
hdtodd b0ef345
remove tab char
hdtodd 440cf9a
Merge branch 'merbanan:master' into master
hdtodd 7b86fc1
Fix issues with PR
hdtodd 07563fe
fixpull
hdtodd a5109f7
Address pull issues
hdtodd 8c6bf45
remove trailing blanks
hdtodd 8d70b53
Fix Pull #2
hdtodd b6b5bbd
Fix Pull #2
hdtodd fc27065
Fix Pull #2
hdtodd 1329e29
Fix Pull #2
hdtodd b34dd96
Fix Pull #3
hdtodd 80dee29
Fix Pull #3
hdtodd 55276bc
Merge branch 'master' into master
hdtodd b9f21f7
merge with merbanan master
hdtodd d977e3d
Merge branch 'master' of http://github.com/hdtodd/rtl_433
hdtodd f9c9096
fixpull3
hdtodd 195ede7
fixpull3
hdtodd 33b32e0
Merge branch 'master' of https://github.com/merbanan/rtl_433
hdtodd ae15445
fixpull4
hdtodd da849fc
fixpull4
hdtodd 523b81e
Correct >>4 shift in revised itemp calc
hdtodd 4b2bd8d
Merge branch 'master' of https://github.com/merbanan/rtl_433
hdtodd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
/** @file | ||
Omni Multisensor. | ||
|
||
Copyright (C) 2025 H. David Todd <[email protected]> | ||
|
||
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. | ||
*/ | ||
/** | ||
The 'sensor' is actually a programmed microcontroller, such as | ||
Raspberry Pi Pico 2 or similar, with multiple possible data-sensor | ||
attachments. A message 'format' field indicates the format of the data | ||
packet being sent. The protocol, and this decoder, support up to | ||
16 different message formats: | ||
- Single transmission protocol | ||
- Flexible 64-bit data payload field structure | ||
- Two initial formats, extensible to a total of 16 possible formats. | ||
|
||
NOTE: the rtl_433 decoder, omni.c, uses the "fmt" or "Format" field | ||
here, as transmitted by omni.c, to decode the incoming message. | ||
But, through omni.c, rtl_433 reports the packet format-field value | ||
as "channel" in its published reporting (JSON, for example), | ||
in keeping with the standard nomenclature and order of field-name | ||
precedence used within rtl_433 for data fields. | ||
|
||
The omni protocol is OOK modulated PWM with fixed period of 600μs | ||
for data bits, preambled by four long startbit pulses of fixed period equal | ||
to 1200μs. It is similar to the Lacrosse TX141TH-BV2. | ||
|
||
A single data packet looks as follows: | ||
1) preamble - 600μs high followed by 600μs low, repeated 4 times: | ||
|
||
---- ---- ---- ---- | ||
| | | | | | | | | ||
---- ---- ---- ---- | ||
|
||
2) a train of 80 data pulses with fixed 600μs period follows immediately: | ||
|
||
--- -- -- --- --- -- --- | ||
| | | | | | | | | | | | | | | ||
-- --- --- -- -- --- -- .... | ||
|
||
A logical 0 is 400μs of high followed by 200μs of low. | ||
A logical 1 is 200μs of high followed by 400μs of low. | ||
|
||
Thus, in the example pictured above the bits are 0 1 1 0 0 1 0 ... | ||
|
||
The omni microcontroller sends 4 of identical packets of | ||
4-pulse preamble followed by 80 data bits in a single burst, for a | ||
total of 336 bits requiring ~212μs. | ||
|
||
The last packet in a burst is followed by a postamble low | ||
of at least 1250μs. | ||
|
||
These 4-packet bursts repeat every 30 seconds. | ||
|
||
The message in each packet is 10 bytes / 20 nibbles: | ||
|
||
[fmt] [id] 16*[data] [crc8] [crc8] | ||
|
||
- fmt is a 4-bit message data format identifier | ||
- id is a 4-bit device identifier | ||
- data are 16 nibbles = 8 bytes of data payload fields, | ||
interpreted according to 'fmt' | ||
- crc8 is 2 nibbles = 1 byte of CRC8 checksum of the first 9 bytes: | ||
polynomial 0x97, init 0xaa | ||
|
||
A format=0 message simply transmits the core temperature and input power | ||
voltage of the microcontroller and is the format used if no data | ||
sensor is present. For format=0 messages, the message | ||
nibbles are to be read as: | ||
|
||
fi tt t0 00 00 00 00 00 vv cc | ||
|
||
f: format of datagram, 0-15 | ||
i: id of device, 0-15 | ||
t: Pico 2 core temperature: °C *10, 12-bit, 2's complement integer | ||
0: bytes should be 0 (but aren't required to be) | ||
v: (VCC-3.00)*100, as 8-bit integer, in volts: 3V00..5V55 volts | ||
c: CRC8 checksum of bytes 1..9, initial remainder 0xaa, | ||
divisor polynomial 0x97, no reflections or inversions | ||
|
||
A format=1 message format is provided as a more complete example. | ||
It uses the Bosch BME688 environmental sensor as a data source. | ||
It is an indoor-outdoor temperature/humidity/pressure sensor, and the | ||
message packet has the following fields: | ||
indoor temp, outdoor temp, indoor humidity, outdoor humidity, | ||
barometric pressure, sensor power VCC. | ||
The data fields are binary values, 2's complement for temperatures. | ||
For format=1 messages, the message nibbles are to be read as: | ||
|
||
fi 11 12 22 hh gg pp pp vv cc | ||
|
||
f: format of datagram, 0-15 | ||
i: id of device, 0-15 | ||
1: sensor 1 temp reading (e.g, indoor), °C *10, 12-bit, 2's complement integer | ||
2: sensor 2 temp reading (e.g, outdoor), °C *10, 12-bit, 2's complement integer | ||
h: sensor 1 humidity reading (e.g., indoor), %RH as 8-bit integer | ||
g: sensor 2 humidity reading (e.g., outdoor), %RH as 8-bit integer | ||
p: barometric pressure * 10, in hPa, as 16-bit integer, 0..6553.5 hPa | ||
v: (VCC-3.00)*100, as 8-bit integer, in volts: 3V00..5V55 volts | ||
c: CRC8 checksum of bytes 1..9, initial remainder 0xaa, | ||
divisor polynomial 0x97, no reflections or inversions | ||
*/ | ||
|
||
#include "decoder.h" | ||
|
||
#define initCRC 0xaa | ||
#define OMNI_MSGFMT_00 0x00 | ||
#define OMNI_MSGFMT_01 0x01 | ||
|
||
static int omni_decode(r_device *decoder, bitbuffer_t *bitbuffer) | ||
{ | ||
// Find a row that's a candidate for decoding | ||
int r = bitbuffer_find_repeated_row(bitbuffer, 2, 80); | ||
|
||
if (r < 0 || bitbuffer->bits_per_row[r] > 82) { | ||
decoder_log(decoder, 1, __func__, "omni: Invalid message"); | ||
return DECODE_ABORT_LENGTH; | ||
}; | ||
|
||
// OK, that's our message buffer for decoding | ||
uint8_t *b = bitbuffer->bb[r]; | ||
|
||
// Validate the packet against the CRC8 checksum | ||
if (crc8(b, 9, 0x97, initCRC) != b[9]) { | ||
decoder_log(decoder, 1, __func__, "omni: CRC8 checksum error"); | ||
return DECODE_FAIL_MIC; | ||
} | ||
|
||
// OK looks like we have a valid packet. What format? | ||
int message_fmt = b[0] >> 4; | ||
int id = b[0] & 0x0F; | ||
char hexstring[50]; | ||
char *ptr; | ||
data_t *data; | ||
|
||
// Decode that format, if we know it | ||
switch (message_fmt) { | ||
|
||
// Default to fmt=00 so unformatted message data are reported in hex | ||
case OMNI_MSGFMT_00: | ||
ptr = &hexstring[0]; | ||
hdtodd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// print just the 8 data bytes as payload data | ||
for (int ij = 1; ij < 9; ij++) | ||
ptr += sprintf(ptr, "%02x", b[ij]); | ||
double itemp_c = (double)(((int16_t)( b[1]<<8 | b[2] )) >> 4) * 0.10; | ||
double volts = ((double)(b[8])) * 0.01 + 3.00; | ||
// Make the data descriptor | ||
/* clang-format off */ | ||
data = data_make( | ||
"model", "", DATA_STRING, "Omni-Multisensor", | ||
"id", "Id", DATA_INT, id, | ||
"channel", "Format", DATA_INT, message_fmt, | ||
"temperature_C" , "Core Temperature", DATA_FORMAT, "%.2f ˚C", DATA_DOUBLE, itemp_c, | ||
"voltage_V", "VCC voltage", DATA_FORMAT, "%.2f V", DATA_DOUBLE, volts, | ||
"payload", "Payload", DATA_STRING, hexstring, | ||
"mic", "Integrity", DATA_STRING, "CRC", | ||
NULL); | ||
/* clang-format on */ | ||
break; | ||
|
||
case OMNI_MSGFMT_01: | ||
itemp_c = (double)(((int16_t)( b[1]<<8 | b[2] )) >> 4) * 0.10; | ||
double otemp_c = (double) (((int16_t)(b[2]<<12 | b[3]<<4 )) >> 4) * 0.10; | ||
double ihum = (double)b[4]; | ||
double light = (double)b[5]; | ||
double press = (double)(((uint16_t)(b[6] << 8)) | b[7]) * 0.10; | ||
volts = ((double)(b[8])) * 0.01 + 3.00; | ||
// Make the data descriptor | ||
/* clang-format off */ | ||
data = data_make( | ||
"model", "", DATA_STRING, "Omni-Multisensor", | ||
"id", "Id", DATA_INT, id, | ||
"channel", "Format", DATA_INT, message_fmt, | ||
"temperature_C" , "Indoor Temperature", DATA_FORMAT, "%.2f ˚C", DATA_DOUBLE, itemp_c, | ||
"temperature_2_C", "Outdoor Temperature",DATA_FORMAT, "%.2f ˚C", DATA_DOUBLE, otemp_c, | ||
"humidity", "Indoor Humidity", DATA_FORMAT, "%.0f %%", DATA_DOUBLE, ihum, | ||
"light_pct", "Light", DATA_FORMAT, "%.0f %%", DATA_DOUBLE, light, | ||
"pressure_hPa", "BarometricPressure", DATA_FORMAT, "%.1f hPa", DATA_DOUBLE, press, | ||
"voltage_V", "VCC voltage", DATA_FORMAT, "%.2f V", DATA_DOUBLE, volts, | ||
"mic", "Integrity", DATA_STRING, "CRC", | ||
NULL); | ||
/* clang-format on */ | ||
break; | ||
|
||
default: | ||
// Print the whole 10 bytes in hex, with id and fmt explicit | ||
ptr = &hexstring[0]; | ||
// print just the 8 data bytes as payload data | ||
for (int ij = 1; ij < 9; ij++) | ||
ptr += sprintf(ptr, "%02x", b[ij]); | ||
// Make the data descriptor | ||
data = data_make( | ||
"model", "", DATA_STRING, "Omni-Multisensor", | ||
"id", "Id", DATA_INT, id, | ||
"channel", "Format", DATA_INT, message_fmt, | ||
"payload", "Payload", DATA_STRING, hexstring, | ||
"mic", "Integrity", DATA_STRING, "CRC", | ||
NULL); | ||
break; | ||
|
||
/* New decoders follow here */ | ||
break; | ||
|
||
}; | ||
|
||
// And output the field values | ||
decoder_output_data(decoder, data); | ||
return 1; // if we got here, one valid message was returned | ||
} | ||
|
||
// List the output fields for various message types | ||
static char const *const output_fields[] = { | ||
"model", | ||
"fmt", | ||
"id", | ||
"temperature_C", | ||
"temperature_2_C", | ||
"humidity", | ||
"pressure_hPa", | ||
"light_pct", | ||
"voltage_V", | ||
"payload", | ||
"mic", | ||
NULL, | ||
}; | ||
|
||
/* clang-format off */ | ||
r_device const omni = { | ||
.name = "Omni Multisensor", | ||
.modulation = OOK_PULSE_PWM, | ||
.short_width = 200, // short pulse is ~200 us | ||
.long_width = 400, // long pulse is ~400 us | ||
.sync_width = 600, // sync pulse is ~600 us | ||
.gap_limit = 500, // long gap (with short pulse) is ~400 us, sync gap is ~600 us | ||
.reset_limit = 1250, // maximum gap is 1250 us (long gap + longer sync gap on last repeat) | ||
.decode_fn = &omni_decode, | ||
.fields = output_fields, | ||
}; | ||
/* clang-format on */ |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.