Skip to content
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

Merge dev into master #796

Merged
merged 24 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b596984
Add ip_address option to setup() (#628)
felipediel Oct 18, 2021
11febb0
Improve README.md (#629)
felipediel Oct 18, 2021
9873af9
Standardize ip_address option (#630)
felipediel Oct 18, 2021
f2a582b
Add support for Broadlink MP1 with power meter (#631)
felipediel Oct 18, 2021
bb19504
Fix instructions for learning RF codes (#632)
felipediel Oct 18, 2021
70180cf
Merge branch 'master' into dev
felipediel Mar 19, 2022
d4dafa3
Merge 'master' into 'dev' (#734)
felipediel Jan 14, 2023
abcc9aa
Add heating_cooling state to Hysen (#722)
fustom Jan 22, 2023
634370d
Add ability to RF scan a specific frequency (#613)
DarkStarSword Apr 9, 2024
d7ed985
Thermostat: get the 1st decimal place (#772)
irsl Apr 9, 2024
06c91ae
Remove auxiliary functions from hysen class (#780)
felipediel Apr 9, 2024
c6bf96d
Add mp1s get_status function (#762)
Zrincet Apr 9, 2024
cacebe7
Rename MP1S state parameters (#783)
felipediel Apr 9, 2024
821820c
Add support for BG Electrical EHC31 (0x6480) (#784)
felipediel Apr 9, 2024
4766d68
Add support for Dooya DT360E (v2) (#785)
felipediel Apr 9, 2024
84af992
Add support for Wistar smart curtain (0x4F6C) (#786)
felipediel Apr 10, 2024
247be74
Expose IR/RF conversion functions (#788)
felipediel Apr 11, 2024
eb0f98a
Fix README.md (#789)
felipediel Apr 11, 2024
24b9d30
Fix s3.get_subdevices() (#790)
felipediel Apr 11, 2024
fa44b54
Add support for Broadlink A2 (#791)
felipediel Apr 12, 2024
1e11558
Add support for Tornado 16X SQ air conditioner (0x4E2A) (#520)
felipediel Apr 17, 2024
c497956
Fix type hints (#794)
felipediel Apr 17, 2024
eb56e7a
Merge branch 'master' into dev
felipediel Apr 17, 2024
0a9acab
Make type hints compatible with Python 3.6 (#797)
felipediel Apr 17, 2024
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
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ broadlink.setup('myssid', 'mynetworkpass', 3)

Security mode options are (0 = none, 1 = WEP, 2 = WPA1, 3 = WPA2, 4 = WPA1/2)

#### Advanced options

You may need to specify a broadcast address if setup is not working.
```python3
broadlink.setup('myssid', 'mynetworkpass', 3, ip_address='192.168.0.255')
```

### Discovery

Use this function to discover devices:
Expand All @@ -61,17 +68,19 @@ devices = broadlink.discover()
#### Advanced options
You may need to specify `local_ip_address` or `discover_ip_address` if discovery does not return any devices.

Using the IP address of your local machine:
```python3
devices = broadlink.discover(local_ip_address='192.168.0.100') # IP address of your local machine.
devices = broadlink.discover(local_ip_address='192.168.0.100')
```

Using the broadcast address of your subnet:
```python3
devices = broadlink.discover(discover_ip_address='192.168.0.255') # Broadcast address of your subnet.
devices = broadlink.discover(discover_ip_address='192.168.0.255')
```

If the device is locked, it may not be discoverable with broadcast. In such cases, you can use the unicast version `broadlink.hello()` for direct discovery:
```python3
device = broadlink.hello('192.168.0.16') # IP address of your Broadlink device.
device = broadlink.hello('192.168.0.16')
```

If you are a perfomance freak, use `broadlink.xdiscover()` to create devices instantly:
Expand Down Expand Up @@ -106,23 +115,33 @@ packet = device.check_data()

### Learning RF codes

Learning IR codes takes place in five steps.
Learning RF codes takes place in six steps.

1. Sweep the frequency:
```python3
device.sweep_frequency()
```
2. When the LED blinks, point the remote at the Broadlink device for the first time and long press the button you want to learn.
3. Enter learning mode:
3. Check if the frequency was successfully identified:
```python3
ok = device.check_frequency()
if ok:
print('Frequency found!')
```
4. Enter learning mode:
```python3
device.find_rf_packet()
```
4. When the LED blinks, point the remote at the Broadlink device for the second time and short press the button you want to learn.
5. Get the RF packet:
5. When the LED blinks, point the remote at the Broadlink device for the second time and short press the button you want to learn.
6. Get the RF packet:
```python3
packet = device.check_data()
```

#### Notes

Universal remotes with product id 0x2712 use the same method for learning IR and RF codes. They don't need to sweep frequency. Just call `device.enter_learning()` and `device.check_data()`.

### Canceling learning

You can exit the learning mode in the middle of the process by calling this method:
Expand Down
70 changes: 50 additions & 20 deletions broadlink/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
#!/usr/bin/env python3
"""The python-broadlink library."""
import socket
import typing as t
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 hysen
from .cover import dooya
from .climate import hvac, hysen
from .cover import dooya, dooya2, wser
from .device import Device, ping, scan
from .hub import s3
from .light import lb1, lb2
from .remote import rm, rm4, rm4mini, rm4pro, rmmini, rmminib, rmpro
from .sensor import a1
from .switch import bg1, mp1, sp1, sp2, sp2s, sp3, sp3s, sp4, sp4b
from .sensor import a1, a2
from .switch import bg1, ehc31, mp1, mp1s, sp1, sp2, sp2s, sp3, sp3s, sp4, sp4b

SUPPORTED_TYPES = {
sp1: {
Expand Down Expand Up @@ -148,14 +148,19 @@
0x653C: ("RM4 pro", "Broadlink"),
},
a1: {
0x2714: ("e-Sensor", "Broadlink"),
0x2714: ("A1", "Broadlink"),
},
a2: {
0x4F60: ("A2", "Broadlink"),
},
mp1: {
0x4EB5: ("MP1-1K4S", "Broadlink"),
0x4EF7: ("MP1-1K4S", "Broadlink (OEM)"),
0x4F1B: ("MP1-1K3S2U", "Broadlink (OEM)"),
0x4F65: ("MP1-1K3S2U", "Broadlink"),
},
mp1s: {
0x4EF7: ("MP1-1K4S", "Broadlink (OEM)"),
},
lb1: {
0x5043: ("SB800TD", "Broadlink (OEM)"),
0x504E: ("LB1", "Broadlink"),
Expand All @@ -177,26 +182,38 @@
S1C: {
0x2722: ("S2KIT", "Broadlink"),
},
s3: {
s3: {
0xA59C: ("S3", "Broadlink"),
0xA64D: ("S3", "Broadlink"),
},
hvac: {
0x4E2A: ("HVAC", "Licensed manufacturer"),
},
hysen: {
0x4EAD: ("HY02/HY03", "Hysen"),
},
dooya: {
0x4E4D: ("DT360E-45/20", "Dooya"),
},
dooya2: {
0x4F6E: ("DT360E-45/20", "Dooya"),
},
wser: {
0x4F6C: ("WSER", "Wistar"),
},
bg1: {
0x51E3: ("BG800/BG900", "BG Electrical"),
},
ehc31: {
0x6480: ("EHC31", "BG Electrical"),
},
}


def gendevice(
dev_type: int,
host: t.Tuple[str, int],
mac: t.Union[bytes, str],
host: Tuple[str, int],
mac: Union[bytes, str],
name: str = "",
is_locked: bool = False,
) -> Device:
Expand All @@ -222,7 +239,7 @@ def gendevice(


def hello(
host: str,
ip_address: str,
port: int = DEFAULT_PORT,
timeout: int = DEFAULT_TIMEOUT,
) -> Device:
Expand All @@ -232,7 +249,11 @@ def hello(
"""
try:
return next(
xdiscover(timeout=timeout, discover_ip_address=host, discover_ip_port=port)
xdiscover(
timeout=timeout,
discover_ip_address=ip_address,
discover_ip_port=port,
)
)
except StopIteration as err:
raise e.NetworkTimeoutError(
Expand All @@ -244,33 +265,42 @@ def hello(

def discover(
timeout: int = DEFAULT_TIMEOUT,
local_ip_address: str = None,
local_ip_address: Optional[str] = None,
discover_ip_address: str = DEFAULT_BCAST_ADDR,
discover_ip_port: int = DEFAULT_PORT,
) -> t.List[Device]:
) -> List[Device]:
"""Discover devices connected to the local network."""
responses = scan(timeout, local_ip_address, discover_ip_address, discover_ip_port)
responses = scan(
timeout, local_ip_address, discover_ip_address, discover_ip_port
)
return [gendevice(*resp) for resp in responses]


def xdiscover(
timeout: int = DEFAULT_TIMEOUT,
local_ip_address: str = None,
local_ip_address: Optional[str] = None,
discover_ip_address: str = DEFAULT_BCAST_ADDR,
discover_ip_port: int = DEFAULT_PORT,
) -> t.Generator[Device, None, None]:
) -> Generator[Device, None, None]:
"""Discover devices connected to the local network.

This function returns a generator that yields devices instantly.
"""
responses = scan(timeout, local_ip_address, discover_ip_address, discover_ip_port)
responses = scan(
timeout, local_ip_address, discover_ip_address, discover_ip_port
)
for resp in responses:
yield gendevice(*resp)


# Setup a new Broadlink device via AP Mode. Review the README to see how to enter AP Mode.
# Only tested with Broadlink RM3 Mini (Blackbean)
def setup(ssid: str, password: str, security_mode: int) -> None:
def setup(
ssid: str,
password: str,
security_mode: int,
ip_address: str = DEFAULT_BCAST_ADDR,
) -> None:
"""Set up a new Broadlink device via AP mode."""
# Security mode options are (0 - none, 1 = WEP, 2 = WPA1, 3 = WPA2, 4 = WPA1/2)
payload = bytearray(0x88)
Expand Down Expand Up @@ -299,5 +329,5 @@ def setup(ssid: str, password: str, security_mode: int) -> None:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet # UDP
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.sendto(payload, (DEFAULT_BCAST_ADDR, DEFAULT_PORT))
sock.sendto(payload, (ip_address, DEFAULT_PORT))
sock.close()
Loading
Loading