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

Support for SmartOne Alarm Kit #18

Open
eddyyanto opened this issue Nov 20, 2016 · 37 comments
Open

Support for SmartOne Alarm Kit #18

eddyyanto opened this issue Nov 20, 2016 · 37 comments

Comments

@eddyyanto
Copy link

eddyyanto commented Nov 20, 2016

Now that the library supports RM (Universal Remote), SP (Smart Plug), A1 (Environment Sensor) and their OEM branded variants, it would great if it also support Broadlink SmartOne Alarm Kit.

Broadlink SmartOne Alarm Kit has the following kits:

  • Host Device (the library can already discover this, it currently showed up a generic broadlink.device class).
  • Motion sensor (read-only motion value).
  • Door sensor (read-only closed/open value).
  • Key Fob Remote (4 buttons remote: Full Arm, Disarm, Part Arm and SOS). Pressing the first 3 buttons toggle the security level in the mobile app. Pressing the SOS button will trigger a warning in the mobile app.
@eddyyanto
Copy link
Author

Previously, I had tried to statically set the SmartOne Host as RM device but it doesn't work.

import broadlink
import time

# SmartOne Host device ip address: 192.168.0.174 and mac address: b4:43:0d:95:fd:6a
device = broadlink.rm(host=("192.168.0.174", 80), mac=bytearray([0xb4, 0x43, 0x0d, 0x95, 0xfd, 0x6a]))
device.auth()
device.enter_learning()

time.sleep(5) # press any key on the fob remote within 5 seconds

ir_packet = device.check_data()
print ir_packet # result in None

@eddyyanto eddyyanto reopened this Nov 20, 2016
@mjg59
Copy link
Owner

mjg59 commented Nov 20, 2016

The API supports subdevices, but I don't have any hardware that implements them. I suspect that the additional devices are accessed via commands sent to or from the host device, but I haven't looked at the protocol for that at all. Patches very welcome.

@akshitgupta95
Copy link

support for Broadlink S1 would be awesome.

@radinsky radinsky mentioned this issue Dec 23, 2016
@radinsky
Copy link

I have the hardware, any chance you can guide me or give a hint where to start looking in case to add S1 support? I see there's some hardcoded devtypes ?

@uvandres
Copy link

uvandres commented Jan 3, 2017

@mjg59 I have 2 s1 with lots of sensors installed in 2 different locations. Can I help someway to make this happen?

@radinsky
Copy link

@mjg59 So what do you think, can you give us some clue or hint where to start digging?

@uvandres
Copy link

@mjg59 Any updates on this? I'd love to be able to manage the s1 from the python as well. That way I will be able to fully uninstall the broadlink app from my phone :)

@pavram
Copy link

pavram commented Apr 27, 2017

In order to implement this; we'd need to do packet captures from the original hardware/remote software to capture each side of the communications and a copy of each of the events.

The AES encryption also means that we would need an authentication response for each packet-capture session to ensure we could decrypt the data. (because the key changes between sessions I think).

None of this is insurmountable, it's just a little bit of a pain to set up, and quite difficult to talk someone else through.

The starting point is wireshark, and an android emulator like Bluestacks.

Wireshark will capture a lot of information, most of it completely useless for this purpose, so you will need to filter the traffic to just the traffic relating to the broadlink device. (Not too hard if you have the device IP address to filter to just that)

Because wireshark doesn't understand the protocol; it doesn't show it nicely. So you will also need to perform your test requests and markup the packet captures with the times that you perform an event (so you know when a set of packets should relate to a specific command).

If you manage to get all of that, and export a wireshark packet capture someone here could probably attempt to implement the new packets, but then things like the lock sensors are difficult to implement without the device in your hands.

@radinsky
Copy link

I can do the sniffing and provide the session pcap capture. Will you able to process it?

@pavram
Copy link

pavram commented Apr 30, 2017

@radinsky I will have a look.

But just in case I drop off the face of the earth. when you do the packet capture attach it to this thread. That way even if I dont do it; it will be infinitely closer to being done.

Just remember to filter the pcap that you export to just comms to/from the device and App!

I wrote a tool that can inspect packets (assuming you pass in an Auth-reply that includes the key) but its written in c#, and I hate the idea of spreading executables.

@johado
Copy link

johado commented May 1, 2017

On my johado fork I also have started on a tool in Python to help decoding pcap dumps, maybe you find it useful.
(It uses the auth key from a previous discovery stored in a json file, so it probably need some adjustments to create that based on the dump and not an actual discovery.)

@radinsky
Copy link

radinsky commented May 7, 2017

Please find attached pcap for s1c session.
I only filtered the traffic (by ip) to and from the s1c.
Everything captured on router itself (without internet connection) on wireless interface.
IP's:
s1c 192.168.1.239
MBP 192.168.1.226
iPhone 192.168.1.100

I did ping to the s1c from MBP between some actions (just to be a bit easier to recognize where the command finish itself).

My scenario (ping between each of them)

  • connected s1c to power
  • opened app on iphone
  • switched to part arm
  • switched to full arm
  • switched to cancel arm
  • opened and closed door1
  • opened and closed door2
  • triggered motion sensor

s1c.pcap.zip

Let me know if I can help @pavram

@pavram
Copy link

pavram commented May 9, 2017

Sorry to be a pain @radinsky, but it turns out the app is slightly more annoying than I realised to get packet captures.

The app (I have verified this) caches the client is and the encryption key between launches.

Which means that since you didn't learn the device as new during the packet capture (I suspect you just powered it on) the actual auth request and auth reply aren't in the capture.

(I was doing my own packet captures and had the same issue).

In the Android app, I had to go to device list, long press the device and delete it, then add it again during the packet capture.

There's no need to reboot the device from scratch, just delete it from the app and add it from scratch,. THEN perform all your actions again.

I was looking at the file system for the app, and I believe it stores all this data in a filesystem based database (in android it is a Java implementation of an LRU cache according to the markup in the log file) which I suspect may contain the keys we need, but it is usually easier to grab another iPhone device and Wireshark while adding it and doing your tests over again.

(Doing the tests from a new iPhone is probably easier than tearing down your existing configuration off your primary device - though it does seem to have some kind of "export" function that might backup your config).

If you do go through the hassle of doing it from your primary device, the good news is future captures should use the same key, obviating the need to capture the auth key for future dumps.

@radinsky
Copy link

radinsky commented May 9, 2017

Hey

Please find new pcap as you required, SmartONE removed from the app, reset and adding the sensors again.
This time it required the internet connection, when you're adding new sensor, if no internet connection detected the adding process is failing (probably tries to verify the serial of the sensors with broadlink servers).
Filtred the capture by s1c ip.addr, also I saw few packets between s1c and rm2 and a1 devices, filtered also, let me know if you want it as well.
IPs:
s1c 192.168.1.239
MBP 192.168.1.226
iPhone 192.168.1.100

Updated scenario:

  • reseted all
  • connected to the power
  • opened app
  • add new device
  • wifi network name/pass
  • found SmartONE
  • ping
  • closed the app
  • opened the app
  • entered SmartONE
  • ping
  • add door sensor
  • ping
  • door open
  • 5 sec
  • door closed
  • ping
  • close app
  • ping
  • open app
  • set full alarm
  • ping
  • open door (alarm started)
  • close door
  • alarm disarm (alarm stopped but still in mode full alarm)
  • ping
  • alarm to mode cancel alarm
  • ping
  • add motion sensor
  • ping
  • person detected
  • ping
  • set motion delay time 30s
  • ping

s1c_100517.pcap.zip

Let's see if it's better now @pavram

@pavram
Copy link

pavram commented May 10, 2017

@radinsky looks good.

Just on a lunch break right now so I haven't teased the rest apart yet, but packet 99 in that capture is an Auth reply from the s1c .239 to the .100 iPhone.

I'll extract the rest of the payloads from this packet capture hopefully tonight, which will give us something to look at and build to.

@pavram
Copy link

pavram commented May 15, 2017

I've reformatted the packet capture into a simple file (including lines for the PING sections)

s1c_simple.txt

I have also built a web service that uses my library to investigate the format to make it easier for me. I'll use this to process the above data.

http://onlinebroadlinkinspector.azurewebsites.net/Inspect/Report

simple guide for the webservice is if it is encrypted; either include the AES_key specifically for the packets, or include the auth-reply packet first in the packets you paste in.

(you can paste the whole txt file dump in at once, it ignores blank lines and lines beginning with # if you want to add info to your own dumps as you go).

@radinsky
Copy link

stuck, tried your online inspector, don't know what to look for..

@pavram
Copy link

pavram commented May 15, 2017

Its all good. I've been working backwards.

The broadlink protocol uses the "data" and "data_reply" type packets to transmit requests and info.

Due to the encryption the payloads must be a multiple of 16 bytes long (32 characters, or 2 of the segments my inspector outputs).

So when your phone asks for the details of the sensors; it sends out a payload with a single piece of information. Usuaully a "06" as the very first byte in its payload.

The reply to the payload also begins with a 06.

Early on this payload is a whole lot of nothing. (literally its a "06" followed by 1359 bytes of "00").

The last couple of packets (in the 1300's) the output becomes its most interesting, specifically:

0600000002008001 0131446f6f722053 
656e736f72000000 0000000000000000 
310116a5f1faa195 0200000000000000 
0000000000000000 1f000000002d0000 
1e08000000000000 1d08000000000000 
1c0b000000000000 000002012157616c 
6c204d6f74696f6e 2053656e736f7200 
00000021022b89d6 ec4e770200000000 
0000000000000000 0000001f00000000 
2d00001e08000000 0000001d08000000 
0000001c0b00001e 

If you run that through a hex -> Ascii converter, you get to see the names of the devices "Door Sensor" and "Wall Motion Sensor"

So; payload reply with a leading 06 seems to be a status request.

earlier; you "add the wall sensor", the 06 packet before these contains only the door sensor (as expected), after a 07 packet request (the reply to which is a 06 reply, labeled 07 but with the new data)

** 06 Reply (before) **

0600000001008001 0131446f6f722053 
656e736f72000000 0000000000000000 
310116a5f1faa195 0200000000000000 
0000000000000000 1f000000002d0000 
1e08000000000000 1d08000000000000 
1c0b000000000000

** 07 Request ** (important; because it shows what settings are specific to a "Wall Sensor" in this case.)

0700000000012157 616c6c204d6f7469 
6f6e2053656e736f 720000000021022b 
89d6ec4e77020000 0000000000000000 
00000000001f0000 00002d00001e0800 
00000000001d0800 00000000001c0b00 
0068010000000000 0000000000000000 

** 07 Reply (which looks like a 06 reply - now including all devices) **

0700000002008001 0131446f6f722053 
656e736f72000000 0000000000000000 
310116a5f1faa195 0200000000000000 
0000000000000000 1f000000002d0000 
1e08000000000000 1d08000000000000 
1c0b000000000000 000002012157616c 
6c204d6f74696f6e 2053656e736f7200 
00000021022b89d6 ec4e770200000000 
0000000000000000 0000001f00000000 
2d00001e08000000 0000001d08000000 
0000001c0b000068 0100000000000000 

Basically, 06 seems to get the "current state" of all devices.
07 appears to add devices.
I think a 10 or 12 changes global settings (like "Alarm" modes)

Identifying the important packets is first; then identifying how they encode the info we are interested in can happen.

@jazzina
Copy link
Contributor

jazzina commented May 18, 2017

Hi. Ive just implemented s1 sensors status checking. Its dirty, but its works. https://github.com/jazzina/python-broadlink/

@radinsky
Copy link

Looking good so far @jazzina , would you prepare a pull request to merge it to this repo?

@jazzina
Copy link
Contributor

jazzina commented May 22, 2017

yeap, done
#103

@nitaybz
Copy link

nitaybz commented May 22, 2017

Hey Guys, great great work @jazzina for the S1C implementation, I already made a javascript library & plugin out of it so I can use with homebridge.
Everything works great so first of all thank you! I've been waiting for this for a while...

I wanted to know if there's gonna be some more progress? setting different alarm states? reading "Triggered" state?

@radinsky
Copy link

@nitaybz for triggering (as unitest as well) I'm using polling and checking if the status of a device was changed.
something like this:

devices = discover(timeout=1)
print (devices)
for d in devices:
  if str(d.type) == 'S1C':
    s = d
s.auth()

sens = s.get_sensors_status()
old = sens
while 1:


  for i, se in enumerate(sens['sensors']):
    if se['status'] != old['sensors'][i]['status']:
     print (time.ctime(), 'Name:', se['name'], 'Status:', se['status'], 'Type:', se['type'])
     old = sens

@nitaybz
Copy link

nitaybz commented May 22, 2017

@radinsky this will trigger any time the sensors changes, what I'm referring to is to get the "triggered" state that happens only when the alarm is armed. that way I can use the sensor all day long and be notify when the alarm is armed and one of the sensors catch movement/contact

@pavram
Copy link

pavram commented May 23, 2017

Nice work all, I've done some more poking around and have extracted each of the packets and a "state" before and a "State" after for each event.

We might need more packet dumps to isolate specific signals but I have found the following:

The aggregate state of the whole system is determined by performing 3 seperate requests.

  • 06 is the primary current state as we already know. (and @nitaybz has done a good job here)
    The "state" byte has 3 different values, which confuses me somewhat. (see below)
  • 10 tells you which devices are alarming. (Making noise? - do these make noise?)
  • 12 is the "Alarm Armed" state.

The following are "doing" packets. Change state or settings or something else.

  • 01 is weird.
    In radinsky's description of what he did to create the packet dump there is a blank dot-point
    the 01 packet seems to coincide with the blank dot-point.
    It is BEFORE arming the alarm system, but after testing the door sensor.
    This packet seems to put the door into the "80" state. Which is like a "I haven't been touched" state
    State 80 for the door appears to be "closed and not opened since a 01, or alarm armed/disarmed"
    The "I haven't been touched" state is spoken about more in file 4.
  • 07 adds devices to the known devices list.
    This probably requires adding in dumps for communication with the sensors also.
    I haven't looked at sensor communications at all yet.
  • 11 is how you Arm or disarm the alarm system.
    (11 is a reconfigure 12 packet, you send through 11 with the new "arm state")
  • 19 is how you "acknowledge" an alarm (leaves it armed, turns off the alarm sound)
    (this is a fire off to quiet the alarm message)
  • 0b reconfigures the "wait time" for the wall sensor. (default value 360? sound right anyone?)

I have included the packet ranges (but not the actual packets) in my txt files below, so you can decrypt the packets you are interested in if you think I haven't included something important.

The following is a list of packets and states before and after changes.
With a little bit of analysis by me.

1 - AddDoorSensor.txt
2 - Door open Door Close.txt
3 - Arm Alarm.txt
4 - Test Alarm with DoorSensor.txt
5 - Disarm Alarm.txt
6 - Add Motion Sensor.txt
7 - Motion Detect Person.txt
8 - Configure Motion time delay.txt

edit:
I just googled the s1c, and in the documentation it says it can manage "upto 16 devices". My diagnosis in file 6 above is that packet-type 10 supports a maximum of 16 devices. It is always good when speculation is accurate!

@radinsky
Copy link

@pavram thanks! just to be clear regarding the "blank dot points" - it's actually I did nothing, was busy by writing down the test steps) so it was like a pause for several moments, you can see it as well in capture file (packet times).

Anyway, would you like me to make some additional capturing/sniffing? If so, could you please specify the scenarios to sniff?

@radinsky
Copy link

radinsky commented Jul 2, 2017

Hey again guys,

So the s1c works perfect on my branch, I did integrate it to HomeAssistant as well.

What I'm curious now, how to allow non broadlink sensors (pir/door/windows sensors and maybe others?) to be learned by s1c?

@NightRang3r
Copy link

How did you integrate it ? Do you experience timeouts ?

@PeggyFree
Copy link

Hello,

Thank you for this work. I'm totally noob in python.
I tried @jazzina 's source code together with the @radinsky 's sample code proposed above.
Using a polling method, I can get these devices events : remote buttons pressed, sensor events.
Here are my questions :

  • Is there a better method than polling?
  • How can I get the global S1 state, or info from the S1?

@pavram
Copy link

pavram commented Aug 21, 2017

Hi @PeggyFree, of all the packet captures I investigated, there didn't appear to be any packets that originated from the S1C itself (without an associated request asking for the data). Which means Polling is the only way I am aware of to check sensor states.

I know it seems kind of wrong to be spewing packets every 1-5 seconds, but that's pretty much the only way I am aware of, and it appears to be the way that the official broadlink app does it.

There is a chance that the broadlink device itself initiates a communication to send alerts back to Broadlink HQ, it is possible that we could try to intercept this, but I doubt we could modify it easily.

(I suspect we could try to intercept the DNS requests for the device during boot and hijack that communication between device and server... No one has attempted this yet as far as I am aware).

@nick2525
Copy link

nick2525 commented Feb 2, 2020

@felipediel
Copy link
Collaborator

Fixed with #103. Thank you!

@KTibow
Copy link
Contributor

KTibow commented Feb 17, 2021

Wait. What? That was closed, not merged.

@felipediel
Copy link
Collaborator

felipediel commented Feb 17, 2021

That was the original PR. mgj merged with this commit. S1C is supported now.

@nick2525
Copy link

@felipediel but is not supported in HA yet?

@felipediel
Copy link
Collaborator

No. HA is a different code base, this is the API. I will reopen the issue because the implementation is incomplete, maybe someone wants to improve it.

@felipediel felipediel reopened this Mar 11, 2021
@felipediel felipediel reopened this Nov 25, 2021
@nick2525
Copy link

Thank you.

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

No branches or pull requests