Skip to main content

Python library rfcontrolpy

Python GitHub Release Licence Maintainer
GitHub Sponsors PayPal BuyMeCoffee Patreon

Introduction

rfcontrolpy is a Python library and port of the node.js rfcontroljs module for parsing and constructing 433mhz On-Off Keying (OOK) signals for various devices, switches and weather stations.

It works together with the RFControl Arduino library for receiving the signals.

The Python port now contains a working controller and a dozen of protocols. Not all protocols are ported yet due to low demand or lack of hardware.

You can find a list of all supported protocols here.

The Processing Pipeline

Receiving

The arduino is connected via serial bus to the processing computer (for example a raspberry pi) and waits for rf signal.

Mostly all 433mhzw OOK signals from devices are send multiple times directly in row and have a longer footer pulse in between. They differ by the pulse lengths used to encode the data and footer and the pulse count.

RFControl running on the Arduino detects the start of a signal by its longer footer pulse and verifies it one time by comparing it with the next signal. It is unaware of the specific protocol, it just uses the stated fact above. Also we are not interested in it if the pulse was a high or low pulse (presence or absence of a carrier wave), because the information is decoded in the pulse lengths.

We will call the received sequence of pulse lengths now timings sequence. For example a timing sequence in microseconds could look like this:

288  972  292  968  292  972  292  968  292  972  920  344  288  976  920  348  
284  976  288  976  284  976  288  976  288  976  916  348  284  980  916  348  
284  976  920  348  284  976  920  348  284  980  280  980  284  980  916  348  
284  9808

You can clearly see the two different pulse lengths (around 304 and 959 microseconds) for the data encoding and the longer footer pulse (9808 microseconds).

All observed protocols have less than 8 different pulse length and all pulse length do differ by at least a factor of 2. This makes a further compression and simplification possible: We map each pulse length to a number from 0 to 7 (a bucket) and calculate for a better accuracy the average of all timings mapped to each of the bucket. The result is something like that:

buckets: 304, 959, 9808
pulses: 01010101011001100101010101100110011001100101011002

To make the representation unique, we choose the buckets in ascending order (respectively we are sorting it after receiving from the Arduino).

We call the sorted buckets pulse lengths, the compressed timings pulse sequence and the length of the pulse sequence (inclusive footer) pulse count.

Protocol Matching

We detect possible protocols by two criteria. The pulse length must match with a small tolerance and the pulse count must match.

Protocol Parsing

If a protocol matches, its parse function is called with the pulse sequence. Most protocols are parsed almost the same way. First the pulse sequence must be converted to a binary representation.

In almost all cases there exist a mapping from pulse sequences to a binary 0 and 1. In this example the pulse sequence 0110 represents a binary 0 and 0101 maps to a binary 1:

pulses2binary_mapping = {
  ["0110": "0"], # Binary 0
  ["0101": "1"], # Binary 1 
  ["02": ""]     # Footer
}
binary = helpers.pulses2binary(pulses, pulses2binary_mapping)

The binary representation now looks like this:

110011000010

As last step the protocol dependent information must be extracted from the binary representation:

decoded = {
  "id": int(binary[:6], 2),
  "unit": int(binary[6:11], 2),
  "state": binary[12] == "1"
}

Details

RFControl is more sensitive than needed for most protocols. So we get sometimes, depending of the accuracy of the sender/remote, different bucket counts.

This is by design, to catch up further protocols that maybe need a higher sensitivity. The specific protocol has not to deal with this issue, because rfcontrolpy auto merges similar buckets before calling the decodePulses function of each protocol.

The algorithm is the following:

  1. Record the (maybe to many) buckets and compressed pulses with RFControl (Arduino / c++)
  2. Sort the buckets in rfcontrolpy prepare_compressed_pulses
  3. Try to find a matching protocol in rfcontrolpy decode_pulses
  4. If we have more than 3 buckets and two of the buckets are similar (b1*2 < b2) we merge them to just one bucket by averaging and adapting the pulses in rfcontrolpy fix_pulses
  5. Go to step 3

Contribution and appreciation

You can contribute to this library, or show your appreciation, in the following ways.

Add a protocol for you device

If the protocol for your device is not yet supported you are encouraged to add support for your protocol to this library.

Preparation

  1. Fork the rfcontrolpy repository and clone your fork into a local directory.
  2. unittest is used for automating tests.
  3. You should be able to run the tests with python3 -m unittest discover.
  4. Running python3 -m build let it compile all files.

Protocol development

  1. Create a new protocol file in rfcontrol/protocols/, you can use one of the other protocol files as a guideline.
  2. Add a test case in tests/protocols with the data from the Arduino.
  3. Adapt the protocol file, so that the test get passed.

Star this library

Help other users find this library by starring this GitHub page. Click ⭐ Star on the top right of the GitHub page.

Support my work

Do you enjoy using this Python library? Please consider supporting my work through one of the following platforms. Your contribution is greatly appreciated and keeps me motivated:

GitHub Sponsors PayPal BuyMeCoffee Patreon

Hire me

If you're in need of a freelance Python developer for your project please contact me, you can find my email address on my GitHub profile.

Metadata

Release files for rfcontrolpy 0.0.12

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rfcontrolpy 0.0.12
File Size Uploaded
rfcontrolpy-0.0.12.tar.gz 27.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rfcontrolpy 0.0.12
File Interpreter ABI Platform
rfcontrolpy-0.0.12-py3-none-any.whl Python 3 none any Details

Total release size: 73.7 kB

Release files / rfcontrolpy-0.0.12.tar.gz

Download URL rfcontrolpy-0.0.12.tar.gz
Size 27.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ff8da54135f938d0825f717d4b2aee1d8e3bb4588eaf9863e5719e5de8cc2467
BLAKE2b-256 checksum
How to use checksums
50da00837590a25bdf12c2ff211f8f3f054653625f912cb0e9c629358f9d5ebb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 10, 2026.

Transparency log

Release files / rfcontrolpy-0.0.12-py3-none-any.whl

Download URL rfcontrolpy-0.0.12-py3-none-any.whl
Size 46.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e01bf566807bff3d764c342b2d7dd4d119297918d02c55ec50e0c91cf92e5407
BLAKE2b-256 checksum
How to use checksums
2dff649d5508097ad56c03c0e2ab1a825498e1a80dd86d011d256b9b349d5530
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.12 This release

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page