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

Add support for "Sweep Frequency" RF #87

Closed
lprhodes opened this issue Apr 28, 2017 · 30 comments · Fixed by #218
Closed

Add support for "Sweep Frequency" RF #87

lprhodes opened this issue Apr 28, 2017 · 30 comments · Fixed by #218

Comments

@lprhodes
Copy link

Hi @mjg59

I have the full details on what happens when you press "Sweep Frequency" now.

These payloads are all sent with 0x6a commands.

Start Sweep Frequency: 0x19

Check for found frequency part 1 (repeat once per second): 0x1a
Wait for 0x01 as position 0x04 response: 0x1a000000010000000000000000000000

Check for found frequency part 2 (repeat once every second): 0x1b
Wait for 0x01 as position 0x04 response: 0x1b000000010000000000000000000000

Use the standard check data (release once per second): 0x04
Wait for hex code response as you would on the normal check data

@mjg59
Copy link
Owner

mjg59 commented May 7, 2017

Just to make sure I understand, the flow is:

Send 0x6a, 0x19
Send 0x6a, 0x1a until you get an 0x01
Send 0x6a, 0x1b until you get an 0x01
Send 0x6a, 0x04 to get the response

Is there any need to call 0x6a, 0x03 (the enter_learning command that's used for IR)? Does the orange LED turn on at any point in this process?

@ereg
Copy link

ereg commented Jun 18, 2017

Hello @mjg59 ,

I can confirm that the orange LED turns on, directly after entering learning "Sweep Frequency" (0x19, I guess). And it stays on during both steps.

First step is Learning frequency (0x1a ?), a long press on button until it´s done.
Second step is Learning Code (0x1b ?). and is only a short press, like with IR code.

Maybe not much help, but love to get this working.

@lprhodes
Copy link
Author

I ended up adding it to the JS version - it should help you work things out https://github.com/lprhodes/broadlinkjs-rm/blob/master/index.js

@lprhodes lprhodes reopened this Jun 19, 2017
@mjg59
Copy link
Owner

mjg59 commented Jun 21, 2017

@lprhodes Afraid not - it's still not clear what the correct sequence of events is. Is my understanding in #87 (comment) correct?

@ereg
Copy link

ereg commented Jun 29, 2017

is it possible to try this?

@mjg59
Copy link
Owner

mjg59 commented Nov 25, 2017

Could someone test https://github.com/mjg59/python-broadlink/tree/rf_experiment ? I don't have any RF equipment to test it with.

@iondulgheru
Copy link

iondulgheru commented Nov 29, 2017

@mjg59, I made a test and it works on python3 (3.6.3).
But on python 2.7 I get a timeout when I run device.check_data(). After that all the calls receive a timeout and I need to reconnect to the device.
Otherwise, on python3 works as expected. I also used the returned code (device.send_data(ir_packet)) and I could control the end device.

I used this cheap RF remote to test it:
https://www.amazon.com/Lerway-Controller-Wireless-Control-R106/dp/B00AHU2U7O

@masarliev
Copy link

@mjg59 Tested with some RF remotes and I get None on devices[0].check_data()
Here is example code that I use. May be I missed something

import broadlink
broadlink.setup('ssid', 'password', 3)

devices = broadlink.discover(timeout=5)
devices[0].auth()
devices[0].enter_learning()
devices[0].sweep_frequency()
print("learning")
while 1:
    found = devices[0].check_frequency()
    if found:
        print('Found')
        break

while 1:
    found = devices[0].find_rf_packet()
    if found:
        print(devices[0].check_data())

@iondulgheru
Copy link

iondulgheru commented Dec 1, 2017

@masarliev , try increasing your timeout to 120.
I got this timeout error also on the master branch, but after I increased it, the device was found.
If the device was already setup, and you know the IP and mac, you don't need to run discover.
Just create a device object by using:
dev = broadlink.gendevice(DEVICE_TYPE_HERE, ("DEVICE_IP_HERE",80), mac=bytearray.fromhex("DEVICE_MAC_HERE"))
You can get your device type from here:
https://github.com/mjg59/python-broadlink/blob/master/broadlink/__init__.py#L16
It's the devtype hex.

@masarliev
Copy link

I don't have problem on device discovery. I don't receive the RF code

@laviua
Copy link

laviua commented Dec 13, 2017

Something goes wrong...
i've created a loop with "sweep freq (0x19)", sleep, "check freq (0x1a)" until 0x04 == 1
then find rf packet (0x1b) returns 0x04 == 1, but get learned data (0x22, 0x23) returns error...

btw in some cases i can receive rf codes, even if check_frequency is false.
i didn't use sweep, find_rf_packet packets.....only learn

@a-lurker
Copy link

@brentavery Get rf scan learning working in CLI tool (#87) : I had this RF code learn method working in a Vera plugin I wrote, with an RM Pro (type 0x2787) and as of about early Feb 2018, it stopped working. I now always get (@laviua) learned data (0x22, 0x23) returns an error: where the error is always 0xfff6. Note then when doing an IR learn, the BroadLink device also returns the 0xfff6 error on get data, until it has an IR code to return.

Vera plugin:
https://github.com/a-lurker/Vera-Plugin-BroadLink-Mk2/blob/master/Luup_device/L_BroadLink_Mk2_1.lua

So do BroadLink do OTA updates automatically or do you have to manually update its firmware (note I don't use e_Control)? Maybe the firmware has changed? Is there a command to retrieve the firmware version information?

It's worthwhile running the RF code learn method without clicking on any RF remote control button. In my case I get the command: "check freq (0x1a)"; 0x04 == 0x04 when it gives up looking for a RF remote command. That is, when the LED goes out. So I interpret this as "Given up on getting an RF code"

Also using the RF code learn method without clicking on any RF remote control button, I sometimes get spurious: check freq (0x1a)"; 0x04 == 0x01 indicating an RF frequency was found. It's perhaps possible the BroadLink device is picking up misc signals from around the local environment?

It also seems strange that the protocol requires a stop RF learn method when the actual device either times out (LED goes out) with no code found or stops immediately it determines a code (LED goes out). Regardless that's maybe just how its programmed.

@Jeroen-R
Copy link

I can confirm that the test code from @masarliev works perfectly to pick up the RF remote for my electric gate (which requires sweep mode). Naturally you need to use the code on the https://github.com/mjg59/python-broadlink/tree/rf_experiment branch.

Hooked it up to the Google assistant (My code is all Python 3), I can now open the gate using voice control when half a mile away ('Open Sesame!'). By the time I drive up it is fully opened.

Saves me from reaching out to the RF remote and wait till I am in range. Saves me a good 10 - 15 seconds a day 😃

Is this change expected to be merged and packaged up any time soon?

@okaapi
Copy link

okaapi commented Jul 11, 2018

The code from @masarliev didn't work for me.... but I got it to work with my AC114-01B RF transmitter for my projection screen, as follows:

(I have to say that this is the first time I've used Python, so maybe its an issue of code versions, and I also can't figure out strings and bytearrays yet :-( ).

Two points:

#1 - in check_frequency there is a check

if payload[0x04] == 1:
    return True

which never triggers. I replaced it with

bb = bytearray(payload)
if bb[4] == 1 :
    return True

and that works for me.

#2 - calling enter_learning() before sweep_frequency() screws things up for me (as in reboot required), and find_rf_packet() should only be called once! find_rf_packet() seems to be the equivalent of enter_learning() for IR.

So it looks like this:

rm_sweep_frequency() # LED will be red
check_frequency()  # call until true (see #1), 1 sec intervals, requires 5-10 RF button clicks
                   # frequency is now found, and LED turns off
find_rf_packet()   # call only once, LED will turn on (just like with IR enter_learning())
check_data()       # call until result is not empty, usually requires only 1-2 RF button clicks
                   # LED will turn off, and data can be used for send_data()

I can share the code if somebody would like it...

My request: I have this on my Pi, and now I'd like to trigger it with Alexa...

experiment.txt

@mjg59
Copy link
Owner

mjg59 commented Jul 11, 2018

Thanks, that looks like enough detail for me to implement this.

@a-lurker
Copy link

okaapi - this looks good but I'm wondering how does one detect when no frequency is found or no button is pushed after a frequency is found. And what to do at those points.

@okaapi
Copy link

okaapi commented Jul 13, 2018

@a-lurker -

1 - when no frequency is found:

You are in a loop with check_frequency(), and you can obviously break after so many seconds. Also, the infamous \x04 position (which goes to 1 when a frequency is found) is set to 4 after 20 seconds or so, that may be a timeout. I changed my check_frequency() to return \x04 - 0, 1, or 4.

2 - if no button is pushed after the frequency is found:
At this point you're in a loop with check_data(), and you can break after, say, 10 seconds.

In both cases, the LED is still red and to get the device out of that state, cancel_learning() to the rescue!!!

  def cancel_learning(self):
    packet = bytearray(16)
    packet[0] = 0x1e;
    self.send_packet(0x6a, packet)

(I found the 0x1e command in this code https://github.com/lprhodes/broadlinkjs-rm/blob/master/index.js thank you @lprhodes )

Here's my code...
rf_experiment.txt
broadlink.txt

@okaapi
Copy link

okaapi commented Jul 13, 2018

Regarding Alexa. I have the RM send_data() in a web server on the Pi which responds to simple GET commands to read the codes and send them to the rm. In parallel I have fauxmo talking to Alexa, and sending Get commands to the webserver (https://github.com/makermusings/fauxmo). It all works great for now!

@sprilukin
Copy link

I was able to successfully read RF code using provided branch rf-experiment

using python 3 (did not testest on python 2) with the following code snippet (edited version of @okaapi rf_experiment.txt):

import broadlink
import time

device = broadlink.rm(host=("192.168.1.100", 80), mac=bytearray.fromhex("3333333333"))
device.auth()
device.sweep_frequency()
print("sweeping...; LED should be RED")

i = 0
while True:
    f = device.check_frequency()
    if not (f == 0):
        break
    i = i + 1
    time.sleep(1)
    print("check frequency... ", i)

if f == 1:
    print("frequency found! check LED, should be off")
else:
    device.cancel_learning()
    print("frequency not found... ")
    exit()
time.sleep(1)

print("learning command")

device.find_rf_packet()

i = 0
while True:
    data = device.check_data()
    if data:
        break
    elif i > 10:
        device.cancel_learning()
        print("command not learned")
        exit()
    i = i + 1
    time.sleep(1)
    print("check command... ", i)

print("command learned")

encodedData = ''.join(format(x, '02x') for x in bytearray(data))
print(encodedData)

fname = "learn_code.txt"
text_file = open(fname, "w")
text_file.write(encodedData)
text_file.close()

execute RF code which has been written to learn_code.txt:

#!/usr/bin/python
import broadlink

device = broadlink.rm(host=("192.168.1.100", 80), mac=bytearray.fromhex("3333333333"))
device.auth()

file = open("./learn_code.txt", 'r')
myhex = file.read()
print(myhex)
print(bytearray.fromhex(myhex))
device.send_data(bytearray.fromhex(myhex))

@sprilukin
Copy link

check out this PR: 218
this is almost the same as 148
but for the latest version of the library at the moment: v0.9,
also fixed couple issues in cli tool.

@madrose
Copy link

madrose commented Dec 4, 2018

I can share the code if somebody would like it...

My request: I have this on my Pi, and now I'd like to trigger it with Alexa...

[experiment.txt](https://github.com/mjg59/python-broadlink/files/2186468/experiment.txt)

Hi @okaapi
is it possible to share the codes for this remote? I have been struggling for a while now to get working codes.
Thanks in advance

@okaapi
Copy link

okaapi commented Dec 4, 2018

Hey madrose,

I can send it no problem, but you might be better off starting with @sprilukin (just one or two posts up) - I have not checked his stuff yet, but it seems to work, and I'll replace my local version with his also so we're all in sync soon :-)

If that doesn't work - or you insist! - I'll send you my files.

@madrose
Copy link

madrose commented Dec 4, 2018

Hey madrose,

I can send it no problem, but you might be better off starting with @sprilukin (just one or two posts up) - I have not checked his stuff yet, but it seems to work, and I'll replace my local version with his also so we're all in sync soon :-)

If that doesn't work - or you insist! - I'll send you my files.

Actually I got @sprilukin version to work, and I got some code from my RM. Thanks, but I am wondering how can I convert those codes to something I can use in Home Assistant. I believe that is base64 code (not sure ??)

@okaapi
Copy link

okaapi commented Dec 5, 2018 via email

@rwa
Copy link

rwa commented Jan 7, 2019

This looks like it has the potential to solve the massive headaches I have been encountering trying to learn RF codes for my RM Pro Plus 3. I am a little unclear on the status of this. These fixes haven't been integrated into the code yet? Is there a low pain way to try out the feature?

@sprilukin
Copy link

@rwa, in order to try out you can check out my test branch (steps are for linux and pip):

  • make sure python3 is installed
  • setup necessary python packages
$ sudo apt-get install python-setuptools python-dev
  • install pycrypto: $ sudo pip install pycrypto
  • checkout git repo:
git clone git@github.com:sprilukin/python-broadlink.git
cd python-broadlink
git checkout -b rf_experiment_v0.9 origin/rf_experiment_v0.9
  • prepare dist from the source files use python3:
cd python-broadlink
python3 setup.py sdist
sudo pip3 install .
  • to learn RF code to the file:
    python-broadlink/cli/broadlink_cli --device @<path-to-file-with-device-settings> --rfscanlearn --learnfile <path-to-file/filename>
  • to use learned file:
    python-broadlink/cli/broadlink_cli --device @<path-to-file-with-device-settings> --send @<path-to-file/filename>

@rwa
Copy link

rwa commented Jan 9, 2019

It worked! Not well, I had to learn the code 6 times and got a different one every single time, but one of them did work.

This really should get into a release asap.

@gavindsilver
Copy link

gavindsilver commented Apr 23, 2019

hi @sprilukin ;

I tried the above method and I am receiving this:

Learning...
No data received...
Traceback (most recent call last):
File "./broadlink_cli", line 186, in
dev.sweep_frequency()
AttributeError: 'rm' object has no attribute 'sweep_frequency'

edit: i am using a rm pro plus 3

@sprilukin
Copy link

I'm sorry, not sure how I can help.
I just needed that stuff to work, so I digged into the code and was in the context 4 months ago.
Now I completely forgot how it works )
I do not have that environment set up to check.

mjg59 added a commit that referenced this issue May 18, 2019
@steffenu
Copy link

steffenu commented Oct 10, 2020

Traceback (most recent call last):
  File "C:/Users/medy1/PycharmProjects/broadlink/RFFINALSEND.py", line 32, in <module>
    ir_packet = devices[0].check_data()
  File "C:\Users\medy1\PycharmProjects\untitled1\venv\lib\site-packages\broadlink\__init__.py", line 631, in check_data
    check_error(response[0x22:0x24])
  File "C:\Users\medy1\PycharmProjects\untitled1\venv\lib\site-packages\broadlink\exceptions.py", line 97, in check_error
    raise exception(error_code)
broadlink.exceptions.ReadError: Read error

when running the script from @sprilukin

using a broadlink pro plus_300

and the master branch

then switching out check data method to the one from the rf_experiment branch

made things work gg

  def check_data(self):
    packet = bytearray(16)
    packet[0] = 4
    response = self.send_packet(0x6a, packet)
    err = response[0x22] | (response[0x23] << 8)
    if err == 0:
      payload = self.decrypt(bytes(response[0x38:]))
      return payload[0x04:]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.