Repository: milaq/rpi-rf
Branch: master
Commit: 71fbe0507588
Files: 9
Total size: 17.7 KB
Directory structure:
gitextract_qi1oa1ht/
├── .gitignore
├── LICENSE.txt
├── MANIFEST.in
├── README.rst
├── rpi_rf/
│ ├── __init__.py
│ └── rpi_rf.py
├── scripts/
│ ├── rpi-rf_receive
│ └── rpi-rf_send
└── setup.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea
dist
*.egg-info
*.pyc
================================================
FILE: LICENSE.txt
================================================
Copyright (c) 2016 Suat Özgür, Micha LaQua
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: MANIFEST.in
================================================
include README.rst
include LICENCE.txt
================================================
FILE: README.rst
================================================
rpi-rf
======
Introduction
------------
Python module for sending and receiving 433/315MHz LPD/SRD signals with generic low-cost GPIO RF modules on a Raspberry Pi.
Protocol and base logic ported ported from `rc-switch`_.
Supported hardware
------------------
Most generic 433/315MHz capable modules (cost: ~2€) connected via GPIO to a Raspberry Pi.
.. figure:: http://i.imgur.com/vG89UP9.jpg
:alt: 433modules
Compatibility
-------------
Generic RF outlets and most 433/315MHz switches (cost: ~15€/3pcs).
.. figure:: http://i.imgur.com/WVRxvWe.jpg
:alt: rfoutlet
Chipsets:
* SC5262 / SC5272
* HX2262 / HX2272
* PT2262 / PT2272
* EV1527 / RT1527 / FP1527 / HS1527
For a full list of compatible devices and chipsets see the `rc-switch Wiki`_
Dependencies
------------
::
RPi.GPIO
Installation
------------
On your Raspberry Pi, install the *rpi_rf* module via pip.
Python 3::
# apt-get install python3-pip
# pip3 install rpi-rf
Wiring diagram (example)
------------------------
Raspberry Pi 1/2(B+)::
RPI GPIO HEADER
____________
| ____|__
| | | |
| 01| . x |02
| | . x__|________ RX
| | . x__|______ | ________
| | . . | | | | |
TX | ____|__x . | | |__|VCC |
_______ | | __|__x . | | | |
| | | | | | x____|______|____|DATA |
| GND|____|__| | | . . | | | |
| | | | | . . | | |DATA |
| VCC|____| | | . . | | | |
| | | | . . | |____|GND |
| DATA|_________| | . . | |________|
|_______| | . . |
| . . |
| . . |
| . . |
| . . |
| . . |
| . . |
39| . . |40
|_______|
TX:
GND > PIN 09 (GND)
VCC > PIN 02 (5V)
DATA > PIN 11 (GPIO17)
RX:
VCC > PIN 04 (5V)
DATA > PIN 13 (GPIO27)
GND > PIN 06 (GND)
Usage
-----
See `scripts`_ (`rpi-rf_send`_, `rpi-rf_receive`_) which are also shipped as cmdline tools.
Open Source
-----------
* The code is licensed under the `BSD Licence`_
* The project source code is hosted on `GitHub`_
* Please use `GitHub issues`_ to submit bugs and report issues
.. _rc-switch: https://github.com/sui77/rc-switch
.. _rc-switch Wiki: https://github.com/sui77/rc-switch/wiki
.. _BSD Licence: http://www.linfo.org/bsdlicense.html
.. _GitHub: https://github.com/milaq/rpi-rf
.. _GitHub issues: https://github.com/milaq/rpi-rf/issues
.. _scripts: https://github.com/milaq/rpi-rf/blob/master/scripts
.. _rpi-rf_send: https://github.com/milaq/rpi-rf/blob/master/scripts/rpi-rf_send
.. _rpi-rf_receive: https://github.com/milaq/rpi-rf/blob/master/scripts/rpi-rf_receive
================================================
FILE: rpi_rf/__init__.py
================================================
from __future__ import absolute_import
from .rpi_rf import RFDevice
__version__ = '0.9.7'
================================================
FILE: rpi_rf/rpi_rf.py
================================================
"""
Sending and receiving 433/315Mhz signals with low-cost GPIO RF Modules on a Raspberry Pi.
"""
import logging
import time
from collections import namedtuple
from RPi import GPIO
MAX_CHANGES = 67
_LOGGER = logging.getLogger(__name__)
Protocol = namedtuple('Protocol',
['pulselength',
'sync_high', 'sync_low',
'zero_high', 'zero_low',
'one_high', 'one_low'])
PROTOCOLS = (None,
Protocol(350, 1, 31, 1, 3, 3, 1),
Protocol(650, 1, 10, 1, 2, 2, 1),
Protocol(100, 30, 71, 4, 11, 9, 6),
Protocol(380, 1, 6, 1, 3, 3, 1),
Protocol(500, 6, 14, 1, 2, 2, 1),
Protocol(200, 1, 10, 1, 5, 1, 1))
class RFDevice:
"""Representation of a GPIO RF device."""
# pylint: disable=too-many-instance-attributes,too-many-arguments
def __init__(self, gpio,
tx_proto=1, tx_pulselength=None, tx_repeat=10, tx_length=24, rx_tolerance=80):
"""Initialize the RF device."""
self.gpio = gpio
self.tx_enabled = False
self.tx_proto = tx_proto
if tx_pulselength:
self.tx_pulselength = tx_pulselength
else:
self.tx_pulselength = PROTOCOLS[tx_proto].pulselength
self.tx_repeat = tx_repeat
self.tx_length = tx_length
self.rx_enabled = False
self.rx_tolerance = rx_tolerance
# internal values
self._rx_timings = [0] * (MAX_CHANGES + 1)
self._rx_last_timestamp = 0
self._rx_change_count = 0
self._rx_repeat_count = 0
# successful RX values
self.rx_code = None
self.rx_code_timestamp = None
self.rx_proto = None
self.rx_bitlength = None
self.rx_pulselength = None
GPIO.setmode(GPIO.BCM)
_LOGGER.debug("Using GPIO " + str(gpio))
def cleanup(self):
"""Disable TX and RX and clean up GPIO."""
if self.tx_enabled:
self.disable_tx()
if self.rx_enabled:
self.disable_rx()
_LOGGER.debug("Cleanup")
GPIO.cleanup()
def enable_tx(self):
"""Enable TX, set up GPIO."""
if self.rx_enabled:
_LOGGER.error("RX is enabled, not enabling TX")
return False
if not self.tx_enabled:
self.tx_enabled = True
GPIO.setup(self.gpio, GPIO.OUT)
_LOGGER.debug("TX enabled")
return True
def disable_tx(self):
"""Disable TX, reset GPIO."""
if self.tx_enabled:
# set up GPIO pin as input for safety
GPIO.setup(self.gpio, GPIO.IN)
self.tx_enabled = False
_LOGGER.debug("TX disabled")
return True
def tx_code(self, code, tx_proto=None, tx_pulselength=None, tx_length=None):
"""
Send a decimal code.
Optionally set protocol, pulselength and code length.
When none given reset to default protocol, default pulselength and set code length to 24 bits.
"""
if tx_proto:
self.tx_proto = tx_proto
else:
self.tx_proto = 1
if tx_pulselength:
self.tx_pulselength = tx_pulselength
elif not self.tx_pulselength:
self.tx_pulselength = PROTOCOLS[self.tx_proto].pulselength
if tx_length:
self.tx_length = tx_length
elif self.tx_proto == 6:
self.tx_length = 32
elif (code > 16777216):
self.tx_length = 32
else:
self.tx_length = 24
rawcode = format(code, '#0{}b'.format(self.tx_length + 2))[2:]
if self.tx_proto == 6:
nexacode = ""
for b in rawcode:
if b == '0':
nexacode = nexacode + "01"
if b == '1':
nexacode = nexacode + "10"
rawcode = nexacode
self.tx_length = 64
_LOGGER.debug("TX code: " + str(code))
return self.tx_bin(rawcode)
def tx_bin(self, rawcode):
"""Send a binary code."""
_LOGGER.debug("TX bin: " + str(rawcode))
for _ in range(0, self.tx_repeat):
if self.tx_proto == 6:
if not self.tx_sync():
return False
for byte in range(0, self.tx_length):
if rawcode[byte] == '0':
if not self.tx_l0():
return False
else:
if not self.tx_l1():
return False
if not self.tx_sync():
return False
return True
def tx_l0(self):
"""Send a '0' bit."""
if not 0 < self.tx_proto < len(PROTOCOLS):
_LOGGER.error("Unknown TX protocol")
return False
return self.tx_waveform(PROTOCOLS[self.tx_proto].zero_high,
PROTOCOLS[self.tx_proto].zero_low)
def tx_l1(self):
"""Send a '1' bit."""
if not 0 < self.tx_proto < len(PROTOCOLS):
_LOGGER.error("Unknown TX protocol")
return False
return self.tx_waveform(PROTOCOLS[self.tx_proto].one_high,
PROTOCOLS[self.tx_proto].one_low)
def tx_sync(self):
"""Send a sync."""
if not 0 < self.tx_proto < len(PROTOCOLS):
_LOGGER.error("Unknown TX protocol")
return False
return self.tx_waveform(PROTOCOLS[self.tx_proto].sync_high,
PROTOCOLS[self.tx_proto].sync_low)
def tx_waveform(self, highpulses, lowpulses):
"""Send basic waveform."""
if not self.tx_enabled:
_LOGGER.error("TX is not enabled, not sending data")
return False
GPIO.output(self.gpio, GPIO.HIGH)
self._sleep((highpulses * self.tx_pulselength) / 1000000)
GPIO.output(self.gpio, GPIO.LOW)
self._sleep((lowpulses * self.tx_pulselength) / 1000000)
return True
def enable_rx(self):
"""Enable RX, set up GPIO and add event detection."""
if self.tx_enabled:
_LOGGER.error("TX is enabled, not enabling RX")
return False
if not self.rx_enabled:
self.rx_enabled = True
GPIO.setup(self.gpio, GPIO.IN)
GPIO.add_event_detect(self.gpio, GPIO.BOTH)
GPIO.add_event_callback(self.gpio, self.rx_callback)
_LOGGER.debug("RX enabled")
return True
def disable_rx(self):
"""Disable RX, remove GPIO event detection."""
if self.rx_enabled:
GPIO.remove_event_detect(self.gpio)
self.rx_enabled = False
_LOGGER.debug("RX disabled")
return True
# pylint: disable=unused-argument
def rx_callback(self, gpio):
"""RX callback for GPIO event detection. Handle basic signal detection."""
timestamp = int(time.perf_counter() * 1000000)
duration = timestamp - self._rx_last_timestamp
if duration > 5000:
if abs(duration - self._rx_timings[0]) < 200:
self._rx_repeat_count += 1
self._rx_change_count -= 1
if self._rx_repeat_count == 2:
for pnum in range(1, len(PROTOCOLS)):
if self._rx_waveform(pnum, self._rx_change_count, timestamp):
_LOGGER.debug("RX code " + str(self.rx_code))
break
self._rx_repeat_count = 0
self._rx_change_count = 0
if self._rx_change_count >= MAX_CHANGES:
self._rx_change_count = 0
self._rx_repeat_count = 0
self._rx_timings[self._rx_change_count] = duration
self._rx_change_count += 1
self._rx_last_timestamp = timestamp
def _rx_waveform(self, pnum, change_count, timestamp):
"""Detect waveform and format code."""
code = 0
delay = int(self._rx_timings[0] / PROTOCOLS[pnum].sync_low)
delay_tolerance = delay * self.rx_tolerance / 100
for i in range(1, change_count, 2):
if (abs(self._rx_timings[i] - delay * PROTOCOLS[pnum].zero_high) < delay_tolerance and
abs(self._rx_timings[i+1] - delay * PROTOCOLS[pnum].zero_low) < delay_tolerance):
code <<= 1
elif (abs(self._rx_timings[i] - delay * PROTOCOLS[pnum].one_high) < delay_tolerance and
abs(self._rx_timings[i+1] - delay * PROTOCOLS[pnum].one_low) < delay_tolerance):
code <<= 1
code |= 1
else:
return False
if self._rx_change_count > 6 and code != 0:
self.rx_code = code
self.rx_code_timestamp = timestamp
self.rx_bitlength = int(change_count / 2)
self.rx_pulselength = delay
self.rx_proto = pnum
return True
return False
def _sleep(self, delay):
_delay = delay / 100
end = time.time() + delay - _delay
while time.time() < end:
time.sleep(_delay)
================================================
FILE: scripts/rpi-rf_receive
================================================
#!/usr/bin/env python3
import argparse
import signal
import sys
import time
import logging
from rpi_rf import RFDevice
rfdevice = None
# pylint: disable=unused-argument
def exithandler(signal, frame):
rfdevice.cleanup()
sys.exit(0)
logging.basicConfig(level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S',
format='%(asctime)-15s - [%(levelname)s] %(module)s: %(message)s', )
parser = argparse.ArgumentParser(description='Receives a decimal code via a 433/315MHz GPIO device')
parser.add_argument('-g', dest='gpio', type=int, default=27,
help="GPIO pin (Default: 27)")
args = parser.parse_args()
signal.signal(signal.SIGINT, exithandler)
rfdevice = RFDevice(args.gpio)
rfdevice.enable_rx()
timestamp = None
logging.info("Listening for codes on GPIO " + str(args.gpio))
while True:
if rfdevice.rx_code_timestamp != timestamp:
timestamp = rfdevice.rx_code_timestamp
logging.info(str(rfdevice.rx_code) +
" [pulselength " + str(rfdevice.rx_pulselength) +
", protocol " + str(rfdevice.rx_proto) + "]")
time.sleep(0.01)
rfdevice.cleanup()
================================================
FILE: scripts/rpi-rf_send
================================================
#!/usr/bin/env python3
import argparse
import logging
from rpi_rf import RFDevice
logging.basicConfig(level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S',
format='%(asctime)-15s - [%(levelname)s] %(module)s: %(message)s',)
parser = argparse.ArgumentParser(description='Sends a decimal code via a 433/315MHz GPIO device')
parser.add_argument('code', metavar='CODE', type=int,
help="Decimal code to send")
parser.add_argument('-g', dest='gpio', type=int, default=17,
help="GPIO pin (Default: 17)")
parser.add_argument('-p', dest='pulselength', type=int, default=None,
help="Pulselength (Default: 350)")
parser.add_argument('-t', dest='protocol', type=int, default=None,
help="Protocol (Default: 1)")
parser.add_argument('-l', dest='length', type=int, default=None,
help="Codelength (Default: 24)")
parser.add_argument('-r', dest='repeat', type=int, default=10,
help="Repeat cycles (Default: 10)")
args = parser.parse_args()
rfdevice = RFDevice(args.gpio)
rfdevice.enable_tx()
rfdevice.tx_repeat = args.repeat
if args.protocol:
protocol = args.protocol
else:
protocol = "default"
if args.pulselength:
pulselength = args.pulselength
else:
pulselength = "default"
if args.length:
length = args.length
else:
length = "default"
logging.info(str(args.code) +
" [protocol: " + str(protocol) +
", pulselength: " + str(pulselength) +
", length: " + str(length) +
", repeat: " + str(rfdevice.tx_repeat) + "]")
rfdevice.tx_code(args.code, args.protocol, args.pulselength, args.length)
rfdevice.cleanup()
================================================
FILE: setup.py
================================================
from setuptools import setup, find_packages
from os import path
here = path.abspath(path.dirname(__file__))
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
long_description = f.read()
setup(
name='rpi-rf',
version='0.9.7',
author='Micha LaQua',
author_email='micha.laqua@gmail.com',
description='Sending and receiving 433/315MHz signals with low-cost GPIO RF modules on a Raspberry Pi',
long_description=long_description,
url='https://github.com/milaq/rpi-rf',
license='BSD',
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python :: 3',
'Operating System :: POSIX :: Linux',
'Topic :: Software Development :: Libraries :: Python Modules'
],
keywords=[
'rpi',
'raspberry',
'raspberry pi',
'rf',
'gpio',
'radio',
'433',
'433mhz',
'315',
'315mhz'
],
install_requires=['RPi.GPIO'],
scripts=['scripts/rpi-rf_send', 'scripts/rpi-rf_receive'],
packages=find_packages(exclude=['contrib', 'docs', 'tests'])
)
gitextract_qi1oa1ht/ ├── .gitignore ├── LICENSE.txt ├── MANIFEST.in ├── README.rst ├── rpi_rf/ │ ├── __init__.py │ └── rpi_rf.py ├── scripts/ │ ├── rpi-rf_receive │ └── rpi-rf_send └── setup.py
SYMBOL INDEX (16 symbols across 1 files)
FILE: rpi_rf/rpi_rf.py
class RFDevice (line 29) | class RFDevice:
method __init__ (line 33) | def __init__(self, gpio,
method cleanup (line 62) | def cleanup(self):
method enable_tx (line 71) | def enable_tx(self):
method disable_tx (line 82) | def disable_tx(self):
method tx_code (line 91) | def tx_code(self, code, tx_proto=None, tx_pulselength=None, tx_length=...
method tx_bin (line 127) | def tx_bin(self, rawcode):
method tx_l0 (line 146) | def tx_l0(self):
method tx_l1 (line 154) | def tx_l1(self):
method tx_sync (line 162) | def tx_sync(self):
method tx_waveform (line 170) | def tx_waveform(self, highpulses, lowpulses):
method enable_rx (line 181) | def enable_rx(self):
method disable_rx (line 194) | def disable_rx(self):
method rx_callback (line 203) | def rx_callback(self, gpio):
method _rx_waveform (line 227) | def _rx_waveform(self, pnum, change_count, timestamp):
method _sleep (line 254) | def _sleep(self, delay):
Condensed preview — 9 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (19K chars).
[
{
"path": ".gitignore",
"chars": 28,
"preview": ".idea\ndist\n*.egg-info\n*.pyc\n"
},
{
"path": "LICENSE.txt",
"chars": 1501,
"preview": "Copyright (c) 2016 Suat Özgür, Micha LaQua\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with"
},
{
"path": "MANIFEST.in",
"chars": 39,
"preview": "include README.rst\ninclude LICENCE.txt\n"
},
{
"path": "README.rst",
"chars": 3113,
"preview": "rpi-rf\n======\n\nIntroduction\n------------\n\nPython module for sending and receiving 433/315MHz LPD/SRD signals with generi"
},
{
"path": "rpi_rf/__init__.py",
"chars": 92,
"preview": "from __future__ import absolute_import\nfrom .rpi_rf import RFDevice\n\n\n__version__ = '0.9.7'\n"
},
{
"path": "rpi_rf/rpi_rf.py",
"chars": 9193,
"preview": "\"\"\"\nSending and receiving 433/315Mhz signals with low-cost GPIO RF Modules on a Raspberry Pi.\n\"\"\"\n\nimport logging\nimport"
},
{
"path": "scripts/rpi-rf_receive",
"chars": 1148,
"preview": "#!/usr/bin/env python3\n\nimport argparse\nimport signal\nimport sys\nimport time\nimport logging\n\nfrom rpi_rf import RFDevice"
},
{
"path": "scripts/rpi-rf_send",
"chars": 1711,
"preview": "#!/usr/bin/env python3\n\nimport argparse\nimport logging\n\nfrom rpi_rf import RFDevice\n\nlogging.basicConfig(level=logging.I"
},
{
"path": "setup.py",
"chars": 1271,
"preview": "from setuptools import setup, find_packages\nfrom os import path\n\nhere = path.abspath(path.dirname(__file__))\n\nwith open("
}
]
About this extraction
This page contains the full source code of the milaq/rpi-rf GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9 files (17.7 KB), approximately 4.8k tokens, and a symbol index with 16 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.