Skip to content

Commit

Permalink
Added RF & docs
Browse files Browse the repository at this point in the history
  • Loading branch information
JexSrs committed Dec 30, 2024
1 parent e37e01f commit 7072268
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 37 deletions.
28 changes: 28 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!--- Provide a general summary of your changes in the Title above -->

## Description
<!--- Describe your changes in detail -->

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

## How has this been tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, tests ran to see how -->
<!--- your change affects other areas of the code, etc. -->

## Screenshots (if appropriate):

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
32 changes: 32 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests

on:
workflow_dispatch:
schedule:
- cron: '*/5 * * * *'

jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
days-before-issue-stale: 30
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
days-before-pr-stale: 30
days-before-pr-close: 14
stale-pr-message: "This PR is stale because it has been open for 30 days with no activity."
close-pr-message: "This PR was closed because it has been inactive for 14 days since being marked as stale."
repo-token: ${{ secrets.GITHUB_TOKEN }}
operations-per-run: 100
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
# Broadlink Reader

Broadlink Reader is a Python command-line interface (CLI) tool designed to interact with
Broadlink remotes to learn and capturing IR commands.
This tool allows users to connect to a Broadlink device, learn commands, and save
them to a file for future use.
Broadlink remotes to learn and capture IR/RF commands.

## Features

- Connect to Broadlink remote over a network.
- Learn and capture IR commands
- Save captured commands to a specified file in JSON format (can be passed to [SmartIR](https://github.com/smartHomeHub/SmartIR) later.
- Learn and capture IR/RF commands
- Save captured commands to a specified file in JSON format
- Generate "commands.json" file that can be integrated to [SmartIR](https://github.com/smartHomeHub/SmartIR).

## Installation

To get started with Broadlink Reader, clone the repository from GitHub:

```sh
git clone https://github.com/JexSrs/broadlink-reader.git
cd broadlink-reader
```

and install the project:

```sh
python3 setup.py install
```
or
```sh
# or
pip install -r requirements.txt
```

Expand All @@ -38,16 +35,20 @@ interaction with the Broadlink device:
python main.py --ip 192.168.1.100 # Remote's IP address
```

Options:
### Options

- `-h, --help`: Show the help message and exit.
- `--ip <ip>`: Specify the IP Address of the Broadlink device (required).
- `--port <port`: Specify the port of the Broadlink device (default: 80).
- `--timeout <timeout>`: Set the timeout for device connection in seconds (default: 10).
- `--file <filename>`: Specify the output file for saving learned commands (default: commands.json).
- `--read <seconds>`: Set the time to wait for the user to send the command in seconds (default: 2).
| Name | Required | Default | Description |
|-----------------------|----------|-------------------|---------------------------------------------------------------------|
| `-h, --help` | No | N/A | Show the help message and exit. |
| `--ip <ip>` | Yes | N/A | Specify the IP Address of the Broadlink device. |
| `--port <port>` | No | `80` | Specify the port of the Broadlink device. |
| `--timeout <timeout>` | No | `10` | Set the timeout (in seconds) for device connection. |
| `--type <type>` | No | `"ir"` | Specify the capture type: `"ir"` or `"rf"`. |
| `--file <filename>` | No | `./commands.json` | Specify the output file for saving learned commands. |
| `--read <seconds>` | No | `2` | Set the time to wait (in seconds) for the user to send the command. |

The default input file, [commands.json](./commands.json), can be extended under the commands key to provide the program with additional IR actions.
The default input file, [commands.json](./commands.json), can be extended under the commands key to provide the program
with additional IR actions.

## Contributing

Expand Down
22 changes: 11 additions & 11 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import argparse
import json
import os
import remote

from broadlink import Device
from colorama import Fore, init

import remote
from cli_utils import print_keys

init(autoreset=True)

data = {}
mFile = 'commands.json'
mFile = './commands.json'
read_timeout = 2
read_type = 'ir'


def navigate_actions(device: Device, actions):
current_path = []
while True:
if current_path:
print(Fore.LIGHTBLUE_EX + f'\nCurrent path: {' > '.join(current_path)}')
print(Fore.LIGHTBLUE_EX + '\nCurrent path: ' + (' > '.join(current_path)))
else:
print(Fore.LIGHTBLUE_EX + '\nCurrent path: Home')
print("Choose an action by index to register:")
Expand Down Expand Up @@ -49,7 +49,7 @@ def navigate_actions(device: Device, actions):
else:
# If it's a leaf and read the packet
try:
packet = remote.handle_action(device, read_timeout)
packet = remote.read_action(device, read_type, read_timeout)
except Exception as e:
print(Fore.RED + 'Failed to read from remote: ' + str(e))
continue
Expand All @@ -67,19 +67,19 @@ def navigate_actions(device: Device, actions):


def main():
global data, mFile, read_timeout
global data, mFile, read_timeout, read_type

parser = argparse.ArgumentParser(description='Broadlink Device Command Learning')
parser.add_argument('--ip', required=True, help='IP Address of the Broadlink device')
parser.add_argument('--port', type=int, default=80, help='Port of the Broadlink device (default: 80)')
parser.add_argument('--timeout', type=int, default=10, help='Timeout for device connection (default: 10)')
parser.add_argument('--file', type=str, default='commands.json',
help='Output file for saving learned commands (default: commands.json)')
parser.add_argument('--read', type=int, default=2,
help='Time to wait for the user to send the command (default: 2 seconds)')
parser.add_argument('--timeout', type=int, default=10, help='Timeout (in seconds) for device connection (default: 10)')
parser.add_argument('--type', type=str, default='ir', choices=['ir', 'rf'], help='Specify the capture type: "ir" or "rf" (default: ir)')
parser.add_argument('--file', type=str, default='./commands.json', help='Output file for saving learned commands (default: ./commands.json)')
parser.add_argument('--read', type=int, default=2, help='Time to wait (in seconds) for the user to send the command (default: 2)')
args = parser.parse_args()

read_timeout = args.read
read_type = args.type
mFile = args.file
# Load existing data from the input file if it exists
if os.path.exists(mFile):
Expand Down
39 changes: 30 additions & 9 deletions remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,47 @@


def get_device(ip_address: str, port: int, timeout: int) -> Device | None:
print(f'Searching for device in {ip_address}...')
print(f'Connecting to device using IP address: "{ip_address}"...')
try:
device = broadlink.hello(ip_address=ip_address, port=port, timeout=timeout)
print(f'Found device "{device.manufacturer} {device.model} ({device.name})". Attempting to authenticate...')
device.auth()
return device
except Exception as e:
print(Fore.RED + f'Could not find device in {ip_address}.')
print(Fore.RED + f'Could not connect to device using IP address: "{ip_address}", Reason: {e}.')
return None


def handle_action(device: Device, read_timeout: int):
print('Reading...')
device.enter_learning()
def read_action(device: Device, type: str, read_timeout: int) -> str:
if type == 'ir':
print('Point to the device and short press the button to be captured...')
device.enter_learning()

# Wait for the user to point the remote
sleep(read_timeout)
# Wait for the user to point the remote
sleep(read_timeout)

print('Getting packets...')
packet = device.check_data()
print('Retrieving packets...')
packet = device.check_data()
elif type == 'rf':
print('Point to the device and long press the button to be captured (step 1)...')
device.sweep_frequency()

# Wait for the user to point the remote
sleep(read_timeout)

ok = device.check_frequency()
if not ok:
raise IOError('Failed to acquire frequency')

print('Point again to the device and short press the button to be captured (step 2)...')
device.find_rf_packet()

# Wait for the user to point the remote
sleep(read_timeout)

packet = device.check_data()
else:
raise TypeError('Unknown action type')

# Convert bytes to Base64
base64_encoded = base64.b64encode(packet)
Expand Down

0 comments on commit 7072268

Please sign in to comment.