Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
<!--
You are amazing! Thanks for contributing to our project!
Please fill the template to help maintainers processing your PR.
Thanks for contributing. Please fill in the sections below; it helps the
maintainer process your change.

Don't forget to create the PR against the correct branch:
- new product id -> new_product_ids
- anything else -> dev
Open the pull request against the master branch.
-->
## Context
<!--
Expand All @@ -21,8 +19,7 @@

## Type of change
<!--
What type of change does your PR introduce?
Please, check only 1 box!
Check one.
-->

- [ ] Dependency upgrade
Expand All @@ -41,15 +38,10 @@

- This PR fixes issue: fixes #
- This PR is related to:
- Link to documentation pull request:

## Checklist
<!--
Please do your best to check these boxes.
-->

- [ ] The code change is tested and works locally.
- [ ] The code has been formatted using Black.
- [ ] The code follows the [Zen of Python](https://www.python.org/dev/peps/pep-0020/).
- [ ] I am creating the Pull Request against the correct branch.
- [ ] Documentation added/updated.
- [ ] The code change is tested and works locally (`pytest`).
- [ ] `ruff check .` passes.
- [ ] New device support was verified on real hardware, or the PR says it was not.
- [ ] `CHANGELOG.md` has an entry under Unreleased.
49 changes: 49 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CI

on:
push:
branches: [master]
pull_request:

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.13", "3.14"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
- name: Lint
run: ruff check .
- name: Test
run: pytest

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Build sdist and wheel
run: |
python -m pip install --upgrade pip build
python -m build
- name: Check the wheel imports
run: |
python -m venv /tmp/check
/tmp/check/bin/pip install dist/*.whl
/tmp/check/bin/python -c "import broadlink; print(broadlink.__name__)"
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
33 changes: 0 additions & 33 deletions .github/workflows/flake8.yaml

This file was deleted.

46 changes: 46 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Publish to PyPI

# Runs on a version tag (v1.0.0, v1.0.1, ...). Uses PyPI trusted publishing:
# the project on PyPI is configured to trust this repository, this workflow
# file name, and the "pypi" environment. No API token is stored anywhere.

on:
push:
tags:
- "v*"

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Check the tag matches the package version
run: |
TAG="${GITHUB_REF_NAME#v}"
VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
echo "tag=$TAG version=$VERSION"
test "$TAG" = "$VERSION"
- name: Build
run: |
python -m pip install --upgrade pip build
python -m build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish:
needs: build
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
*.pyc
__pycache__/
*.egg-info/
build/
dist/
.venv/
.pytest_cache/
.ruff_cache/
.DS_Store

# Working notes that are not part of the published project.
docs/internal/
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Changelog

All notable changes to this project are recorded here. The format follows
Keep a Changelog; versions follow Semantic Versioning.

## Unreleased

This is the first release of `python-broadlink`, a maintained fork of
`mjg59/python-broadlink` (PyPI `broadlink`, last released as 0.19.0). The
history below starts at that fork point.

### Changed

- Packaging moved to `pyproject.toml`; `setup.py` and the stale
`requirements.txt` pin are gone. The distribution name is now
`python-broadlink`; the import name stays `broadlink`. Python 3.13 or
newer is required.
- Continuous integration now runs `ruff` and `pytest` on Python 3.13 and
3.14, and builds the sdist and wheel on every pull request. Releases are
published to PyPI from version tags using trusted publishing.

### Added

- A test suite. The `tests/oracle` package records the exact request bytes
every public method of every device class sends, and the results it
decodes from canned responses, so that later changes to the transport
can be checked byte for byte against the original behavior.
5 changes: 5 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
include LICENSE README.md CHANGELOG.md protocol.md TROUBLESHOOTING.md
include pyproject.toml
graft cli
graft tests
global-exclude __pycache__ *.py[cod] .DS_Store
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
# python-broadlink

A Python module and CLI for controlling Broadlink devices locally. The following devices are supported:
A Python module and CLI for controlling Broadlink devices locally.

> **About this fork.** This repository is a maintained fork of
> [mjg59/python-broadlink](https://github.com/mjg59/python-broadlink), which
> has not accepted changes since 2024. It exists so that Home Assistant's
> Broadlink integration has a library that can take fixes and new devices.
> The distribution on PyPI is `python-broadlink`; the import name stays
> `broadlink`. The first release corrects the IR timing constant reported in
> upstream [#839](https://github.com/mjg59/python-broadlink/issues/839)
> (fix in [#841](https://github.com/mjg59/python-broadlink/pull/841)) and
> adds the devices waiting in upstream's pull request queue, including the
> RM Max and RM5 Plus. Version 1.0 will be asynchronous; see `CHANGELOG.md`.
> Upstream's credit and MIT license are preserved.

The following devices are supported:

- **Universal remotes**: RM home, RM mini 3, RM plus, RM pro, RM pro+, RM4 mini, RM4 pro, RM4C mini, RM4S, RM4 TV mate
- **Smart plugs**: SP mini, SP mini 3, SP mini+, SP1, SP2, SP2-BR, SP2-CL, SP2-IN, SP2-UK, SP3, SP3-EU, SP3S-EU, SP3S-US, SP4L-AU, SP4L-EU, SP4L-UK, SP4M, SP4M-US, Ankuoo NEO, Ankuoo NEO PRO, Efergy Ego, BG AHC/U-01
Expand All @@ -19,9 +33,13 @@ A Python module and CLI for controlling Broadlink devices locally. The following
Use pip3 to install the latest version of this module.

```
pip3 install broadlink
pip3 install python-broadlink
```

If the original `broadlink` distribution is also installed in the same
environment, remove it first (`pip3 uninstall broadlink`); both provide the
`broadlink` package.

## Basic functions

First, open Python 3 and import this module.
Expand Down
2 changes: 1 addition & 1 deletion broadlink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from typing import Generator, List, Optional, Tuple, Union

from . import exceptions as e
from .const import DEFAULT_BCAST_ADDR, DEFAULT_PORT, DEFAULT_TIMEOUT
from .alarm import S1C
from .climate import hvac, hysen
from .const import DEFAULT_BCAST_ADDR, DEFAULT_PORT, DEFAULT_TIMEOUT
from .cover import dooya, dooya2, wser
from .device import Device, ping, scan
from .hub import s3
Expand Down
2 changes: 1 addition & 1 deletion broadlink/device.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Support for Broadlink devices."""
import random
import socket
import threading
import random
import time
from typing import Generator, Optional, Tuple, Union

Expand Down
2 changes: 1 addition & 1 deletion broadlink/hub.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Support for hubs."""
import struct
import json
import struct
from typing import Optional

from . import exceptions as e
Expand Down
66 changes: 66 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[build-system]
requires = ["setuptools>=77"]
build-backend = "setuptools.build_meta"

[project]
name = "python-broadlink"
version = "1.0.0.dev0"
description = "Python API for controlling Broadlink devices"
readme = "README.md"
license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.13"
authors = [
{ name = "Matthew Garrett", email = "mjg59@srcf.ucam.org" },
{ name = "DAB-LABS" },
]
maintainers = [
{ name = "DAB-LABS" },
]
keywords = ["broadlink", "infrared", "rf", "home-assistant", "rm4", "rm-pro"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Topic :: Home Automation",
]
dependencies = [
"cryptography>=3.2",
]

[project.optional-dependencies]
dev = [
"pytest>=8",
"ruff>=0.5",
"build",
]

[project.urls]
Homepage = "https://github.com/DAB-LABS/python-broadlink"
Repository = "https://github.com/DAB-LABS/python-broadlink"
Issues = "https://github.com/DAB-LABS/python-broadlink/issues"
Changelog = "https://github.com/DAB-LABS/python-broadlink/blob/master/CHANGELOG.md"
Upstream = "https://github.com/mjg59/python-broadlink"

[tool.setuptools]
packages = ["broadlink"]

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-q"

[tool.ruff]
line-length = 90
target-version = "py313"

[tool.ruff.lint]
# Start from the upstream flake8 gate (syntax errors and undefined names)
# plus pyflakes and import hygiene. Style rules widen once the async port lands.
select = ["E9", "F", "I"]

[tool.ruff.lint.per-file-ignores]
# The package __init__ re-exports the public API.
"broadlink/__init__.py" = ["F401"]
1 change: 0 additions & 1 deletion requirements.txt

This file was deleted.

29 changes: 0 additions & 29 deletions setup.py

This file was deleted.

Empty file added tests/__init__.py
Empty file.
1 change: 1 addition & 0 deletions tests/oracle/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Byte-level oracle for the device classes. See harness.py."""
Loading
Loading