Skip to content

Commit

Permalink
Add ability to RF scan a specific frequency
Browse files Browse the repository at this point in the history
This adds an optional parameter to find_rf_packet(), along with a
corresponding --rflearn parameter (defaulting to 433.92) to
broadlink_cli that specifies the frequency to tune to, rather than
requiring the frequency be found via sweeping. This is almost mandatory
for certain types of remotes that do not repeat their signals while the
button is held, and saves significant time when the frequency is known
in advance or when many buttons are to be captured in a row.

Additionally:

- A get_frequency() API is added to return the current frequency the
  device is tuned to.

- A check_frequency_ex() API is added to perform functions of both
  check_frequency() and get_frequency() in a single call.

- broadlink_cli --rfscanlearn will now report the current frequency at 1
  second intervals during sweeping, and will report the frequency it
  finally locks on to.
  • Loading branch information
DarkStarSword committed Aug 15, 2021
1 parent a84a628 commit 168b901
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 21 deletions.
22 changes: 19 additions & 3 deletions broadlink/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,25 @@ def check_frequency(self) -> bool:
resp = self._send(0x1A)
return resp[0] == 1

def find_rf_packet(self) -> None:
"""Enter radiofrequency learning mode."""
self._send(0x1B)
def check_frequency_ex(self) -> (bool, float):
"""Return (True if the frequency was identified successfully, Current frequency)"""
resp = self._send(0x1A)
return resp[0] == 1, struct.unpack('<I', resp[1:5])[0] / 1000.0

def get_frequency(self) -> float:
"""Return frequency device is tuned to in MHz"""
resp = self._send(0x1A)
return struct.unpack('<I', resp[1:5])[0] / 1000.0

def find_rf_packet(self, frequency=None) -> None:
"""Enter radiofrequency learning mode, optionally tuning the device to a specific frequency"""
payload = b''
if frequency is not None:
payload = struct.pack('<I', int(frequency * 1000.0))
# Without this get_frequency() may suggest it is tuned to the
# specified frequency, but it fails to capture any signals:
self.cancel_sweep_frequency()
self._send(0x1B, payload)

def cancel_sweep_frequency(self) -> None:
"""Cancel sweep frequency."""
Expand Down
45 changes: 27 additions & 18 deletions cli/broadlink_cli
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ parser.add_argument("--send", action="store_true", help="send command")
parser.add_argument("--sensors", action="store_true", help="check all sensors")
parser.add_argument("--learn", action="store_true", help="learn command")
parser.add_argument("--rfscanlearn", action="store_true", help="rf scan learning")
parser.add_argument("--rflearn", nargs="?", type=float, const=433.92, metavar="FREQUENCY", help="rf learning on specified FREQUENCY, default: 433.92")
parser.add_argument("--learnfile", help="save learned command to a specified file")
parser.add_argument("--durations", action="store_true",
help="use durations in micro seconds instead of the Broadlink format")
Expand Down Expand Up @@ -127,7 +128,7 @@ if args.send:
data = durations_to_broadlink(parse_durations(' '.join(args.data))) \
if args.durations else bytearray.fromhex(''.join(args.data))
dev.send_data(data)
if args.learn or (args.learnfile and not args.rfscanlearn):
if args.learn or (args.learnfile and not args.rfscanlearn and not args.rflearn):
dev.enter_learning()
print("Learning...")
start = time.time()
Expand Down Expand Up @@ -195,29 +196,36 @@ if args.switch:
else:
dev.set_power(True)
print('* Switch to ON *')
if args.rfscanlearn:
if args.rfscanlearn or args.rflearn:
dev.sweep_frequency()
print("Learning RF Frequency, press and hold the button to learn...")
if args.rfscanlearn:
print("Learning RF Frequency, press and hold the button to learn...")

start = time.time()
while time.time() - start < TIMEOUT:
time.sleep(1)
locked, frequency = dev.check_frequency_ex()
if locked:
break
print("Sweeping {}MHz...".format(frequency))
else:
print("RF Frequency not found")
dev.cancel_sweep_frequency()
exit(1)
frequency = dev.get_frequency()

start = time.time()
while time.time() - start < TIMEOUT:
time.sleep(1)
if dev.check_frequency():
break
else:
print("RF Frequency not found")
dev.cancel_sweep_frequency()
exit(1)
print("Found RF Frequency {}MHz - 1 of 2!".format(frequency))
print("You can now let go of the button")

print("Found RF Frequency - 1 of 2!")
print("You can now let go of the button")
input("Press enter to continue...")

input("Press enter to continue...")
dev.find_rf_packet()
else:
dev.find_rf_packet(args.rflearn)
print("Device tuned to {}MHz".format(dev.get_frequency()))

print("To complete learning, single press the button you want to learn")

dev.find_rf_packet()

start = time.time()
while time.time() - start < TIMEOUT:
time.sleep(1)
Expand All @@ -231,7 +239,8 @@ if args.rfscanlearn:
print("No data received...")
exit(1)

print("Found RF Frequency - 2 of 2!")
if args.rfscanlearn:
print("Found RF Frequency - 2 of 2!")
learned = format_durations(to_microseconds(bytearray(data))) \
if args.durations \
else ''.join(format(x, '02x') for x in bytearray(data))
Expand Down

0 comments on commit 168b901

Please sign in to comment.