rgerganov / py-air-control

Command line app for controlling Philips air purifiers
MIT License
266 stars 53 forks source link

ConnectionRefusedError: [Errno 111] Connection refused #21

Closed blastar closed 4 years ago

blastar commented 5 years ago

Hello there!

I have such error: "ConnectionRefusedError: [Errno 111] Connection refused" when trying to connect to AC5659. It is visible right after: Exchanging secret key with the device ...

It doesn't matter which command I'm trying to send (even --debug)

Does anyone know how to fix this? I see this device in AirMatter app and I can connect without any problems, so its connected to my wifi.

rgerganov commented 5 years ago

Are you sure you got the correct IP address of the purifier?

blastar commented 5 years ago

I'm not, I see something like: mico.home (192.168.1.43) at b0:f8:93:67:f7:a6 [ether] on eth0 with arp -a, and this is only new device. IP scanner shows: IP: 192.168.1.43 Ping: 11 ms Hostname: mico.home Ports: [n/s] Web detect: [n/a] MAC Vendor: Shanghai MXCHIP Information NetBIOS Info: [n/a] Not sure how can I get IP another way, don't see anything usefull in AirMatters.

freakadings commented 4 years ago

I got the same error but i'm sure the IP Is correct:

$ python3 airctrl.py 192.168.178.72 --debug
Exchanging secret key with the device ...
Traceback (most recent call last):
  File "/usr/lib/python3.5/urllib/request.py", line 1254, in do_open
    h.request(req.get_method(), req.selector, req.data, headers)
  File "/usr/lib/python3.5/http/client.py", line 1107, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python3.5/http/client.py", line 1152, in _send_request
    self.endheaders(body)
  File "/usr/lib/python3.5/http/client.py", line 1103, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python3.5/http/client.py", line 934, in _send_output
    self.send(msg)
  File "/usr/lib/python3.5/http/client.py", line 877, in send
    self.connect()
  File "/usr/lib/python3.5/http/client.py", line 849, in connect
    (self.host,self.port), self.timeout, self.source_address)
  File "/usr/lib/python3.5/socket.py", line 712, in create_connection
    raise err
  File "/usr/lib/python3.5/socket.py", line 703, in create_connection
    sock.connect(sa)
ConnectionRefusedError: [Errno 111] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "airctrl.py", line 310, in <module>
    main()
  File "airctrl.py", line 267, in main
    c.load_key()
  File "airctrl.py", line 87, in load_key
    self._get_key()
  File "airctrl.py", line 53, in _get_key
    with urllib.request.urlopen(req) as response:
  File "/usr/lib/python3.5/urllib/request.py", line 163, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib/python3.5/urllib/request.py", line 466, in open
    response = self._open(req, data)
  File "/usr/lib/python3.5/urllib/request.py", line 484, in _open
    '_open', req)
  File "/usr/lib/python3.5/urllib/request.py", line 444, in _call_chain
    result = func(*args)
  File "/usr/lib/python3.5/urllib/request.py", line 1282, in http_open
    return self.do_open(http.client.HTTPConnection, req)
  File "/usr/lib/python3.5/urllib/request.py", line 1256, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error [Errno 111] Connection refused>
rgerganov commented 4 years ago

What happens when you do curl http://<purifier-ip>? This is what I get:

$ curl http://192.168.0.91 
{"error":"Badly formed (DI Comm) request "}

Is port 80 open on the device? You can also try putting the device into pairing mode and then connect to the "PHILIPS Setup" network.

blastar commented 4 years ago

I see: curl: (7) Failed to connect to 192.168.1.43 port 80: Connection refused So seems that port 80 is closed

rgerganov commented 4 years ago

This is really strange. Can you try and sniff the traffic between AirMatters and the device?

freakadings commented 4 years ago

my connection is also refused, I'm trying to connect to a AC3036/10 btw.

Could it be that the initial configuration of the wifi has to be done with the pc (in my case a raspberry pi 2 with raspbian stretch ) i'm trying to run these commands from? I did the initial config via the air matters app.

Btw. i can't run the "airctrl" cmds from anywhere, i have to run the script directly, as you can see in my code from above.

rgerganov commented 4 years ago

Btw. i can't run the "airctrl" cmds from anywhere, i have to run the script directly, as you can see in my code from above.

You need to install the app with pip install py-air-control and then you will have airctrl executable

freakadings commented 4 years ago

i think you mean pip3, pip throws an error. Installed it a few times didn't help though it "installed correctly".

pip

$ pip install py-air-control
Collecting py-air-control
  Downloading https://files.pythonhosted.org/packages/53/1a/dcc775b86de43665097a9a9c7a99a0335b3bc9c38b9bf9adedaa8f10c91d/py-air-control-1.0.0.tar.gz
    Complete output from command python setup.py egg_info:
    Python 3.4 or newer is required.

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-ar6Ow0/py-air-control/

pip3

 $ pip3 install py-air-control
Collecting py-air-control
  Using cached https://files.pythonhosted.org/packages/e9/7d/38ffb2f83313f53b539ae556e16ebcf439c43e2bf560216656ec673a5032/py_air_control-1.0.0-py3-none-any.whl
Collecting pycryptodome>=3.4.7 (from py-air-control)
  Using cached https://www.piwheels.org/simple/pycryptodome/pycryptodome-3.9.4-cp35-cp35m-linux_armv7l.whl
Installing collected packages: pycryptodome, py-air-control
Successfully installed py-air-control-1.0.0 pycryptodome-3.9.4
dokterdok commented 4 years ago

Similar issue here with an AC3829/10, I'm getting an Errno 61.

airctrl 192.168.1.21       
Exchanging secret key with the device ...
Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1318, in do_open
    encode_chunked=req.has_header('Transfer-encoding'))
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1239, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1285, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1234, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 1026, in _send_output
    self.send(msg)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 964, in send
    self.connect()
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/http/client.py", line 936, in connect
    (self.host,self.port), self.timeout, self.source_address)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 724, in create_connection
    raise err
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 713, in create_connection
    sock.connect(sa)
ConnectionRefusedError: [Errno 61] Connection refused

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/bin/airctrl", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.6/site-packages/pyairctrl/airctrl.py", line 267, in main
    c.load_key()
  File "/usr/local/lib/python3.6/site-packages/pyairctrl/airctrl.py", line 87, in load_key
    self._get_key()
  File "/usr/local/lib/python3.6/site-packages/pyairctrl/airctrl.py", line 53, in _get_key
    with urllib.request.urlopen(req) as response:
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 223, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 526, in open
    response = self._open(req, data)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 544, in _open
    '_open', req)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 504, in _call_chain
    result = func(*args)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1346, in http_open
    return self.do_open(http.client.HTTPConnection, req)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 1320, in do_open
    raise URLError(err)
urllib.error.URLError: <urlopen error [Errno 61] Connection refused>
rgerganov commented 4 years ago

Can someone try to put the purifier into pairing mode and then check if port 80 is open on the device?

freakadings commented 4 years ago

Sorry my pc is connected via LAN, so it's not possible to access the wifi of the purifier.

rgerganov commented 4 years ago

If you are on Linux you can try to run SSDP discovery with the following command:

$ sudo apt-get install gupnp-tools
$ gssdp-discover -i eth0 --timeout=3
freakadings commented 4 years ago

Used it on my raspberry, there is a lot of stuff shown, what am i looking for?

rgerganov commented 4 years ago

This is the response that I get:

resource available
  USN:      uuid:12345678-1234-1234-1234-************::upnp:rootdevice
  Location: http://192.168.0.91/upnp/description.xml
resource available
  USN:      uuid:12345678-1234-1234-1234-************
  Location: http://192.168.0.91/upnp/description.xml
resource available
  USN:      uuid:12345678-1234-1234-1234-************::urn:philips-com:device:DiProduct:1
  Location: http://192.168.0.91/upnp/description.xml
freakadings commented 4 years ago

There's nothing with "philips" in the USN :/

hoky24 commented 4 years ago

I have the same problem as @dokterdok.

When I connect my notebook to the SSID “PHILIPS Setup” on my AC3829 air purifier, I get the address 10.0.0.2. I conclude that the default address of the air purifier will be 10.0.0.1.

Unfortunately on port 80 it doesn't respond at all. That's why I tried port scanning.

sudo nmap  -Pn -p-  10.0.0.1 
Starting Nmap 7.80 ( https://nmap.org ) at 2019-12-14 18:11 CET
Nmap scan report for 10.0.0.1
Host is up (0.31s latency).
Not shown: 65534 closed ports
PORT      STATE SERVICE
30123/tcp open  unknown
MAC Address: B0:F8:93:68:86:6B (Shanghai Mxchip Information Technology)

Nmap discovered an open tcp port 30123.

wget -O- http://10.0.0.1:30123
--2019-12-14 18:39:06--  http://10.0.0.1:30123/
Connecting to 10.0.0.1:30123... connected.
HTTP request sent, awaiting response... 200 No headers, assuming HTTP/0.9
Length: unspecified
Saving to: 'STDOUT'

{"type":"deviceinfo","meta":{"message":"check device info","code":100},"data":{"name":"Bedroom","type":"AC3829","modelid":"AC3829/10","swversion":"1.4.0"}}{"type":"config","meta":{"message":"no json","code":1000}}
wget -O- http://10.0.0.1:30123/di/v1/products/0/wifi
--2019-12-14 18:51:53--  http://10.0.0.1:30123/di/v1/products/0/wifi
Connecting to 10.0.0.1:30123... connected.
HTTP request sent, awaiting response... 200 No headers, assuming HTTP/0.9
Length: unspecified
Saving to: 'STDOUT'

{"type":"deviceinfo","meta":{"message":"check device info","code":100},"data":{"name":"Bedroom","type":"AC3829","modelid":"AC3829/10","swversion":"1.4.0"}}{"type":"config","meta":{"message":"no json","code":1000}}

The air purifier always responds in this way. Do you have any idea what to try next?

Edit: I have yet tried to eavesdrop on the communication between the AC3829 (192.168.1.37) and the Air Matters app (192.168.1.176). It looks like CoAP protocol is being used. tcpdump-ac3829-air_matters.pcap.zip

szogi commented 4 years ago

I have same issue with philips ac2729 (bought ~one month ago). I checked with nmap, all ports are closed :(

Starting Nmap 7.70 ( https://nmap.org ) at 2019-12-15 00:35 CET Nmap scan report for 172.16.0.140 Host is up (0.0053s latency). All 65535 scanned ports on 172.16.0.140 are closed MAC Address: XXXXXX (Shanghai Mxchip Information Technology)

Nmap done: 1 IP address (1 host up) scanned in 6404.26 seconds

mhabegger commented 4 years ago

Same with a new Series 1000i AC1214/10. No open ports and airctrl is not working with same errors described above. In pairing mode with nmap:

30123/tcp open  unknown
| fingerprint-strings:
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, GenericLines, GetRequest, HTTPOptions, RPCCheck, RTSPRequest:
|     {"type":"deviceinfo","meta":{"message":"check device info","code":100},"data":{"name":"AirPurifier","type":"AC1214","modelid":"AC1214/10","swversion":"2.0.0"}}{"type":"config","meta":{"message":"no json","code":1000}}
|   NULL:
|_    {"type":"deviceinfo","meta":{"message":"check device info","code":100},"data":{"name":"AirPurifier","type":"AC1214","modelid":"AC1214/10","swversion":"2.0.0"}}
tsigularov commented 4 years ago

Same problem with ac1214/10. There is no open port of the unit when I scan it. The host name is MiCO.

dos1 commented 4 years ago

Can confirm that it doesn't work on a new AC2729/50 either. The device's IP is 10.0.0.1 and the only open TCP port is 30123.

~$ telnet 10.0.0.1 30123
Trying 10.0.0.1...
Connected to 10.0.0.1.
Escape character is '^]'.
{"type":"deviceinfo","meta":{"message":"check device info","code":100},"data":{"name":"AirPurifier","type":"AC2729","modelid":"AC2729/50","swversion":"0.2.1"}}

when trying to send something it replies:

{"type":"config","meta":{"message":"no json","code":1000}}

Nothing on SSDP discovery. The protocol has completely changed, it seems.

rgerganov commented 4 years ago

Yeah, it seems they switched to another protocol. If anyone that has such device manage to reverse it, patches are welcome! :) This is how I did it for the purifier that I have: https://xakcop.com/post/ctrl-air-purifier/ https://xakcop.com/post/cloud-air-purifier/

shexbeer commented 4 years ago

I think the new models use CoAP to communicate like @hoky24 said. The tricky thing is to open the CoAP port 5683. After sniffing the traffic it looks like the app sends a special ICMP packet to the device. This looks like: ICMP packet (type: 3, code 3) with payload: TCP (srcip: app, dstip: device) and UDP(srcport: 5683, dstport: 5683). Need to figure out the correct formatting and checksums.

Edit1: There is indeed a special communication needed, as a combination of special ICMP and CoAP messages! Got to the point were my device is finally talking to me in CoAP, currently resets the connection but it does something :) Going on

Edit2: Did it! Got status infos from my brand new AC2729 unit. image

Next, refactoring code, send / dicover commands, think about if its good to integrate here or do a new project, because the protocol is totally different

rgerganov commented 4 years ago

@shexbeer Great! I will be happy to accept PRs if you decide to contribute.

shexbeer commented 4 years ago

@rgerganov Yes, i will create a PR as soon as i got everything in place 👍 Switching between old and new protocol via command line option is a possibility, what do you think?

rgerganov commented 4 years ago

Switching between old and new protocol via command line option is a possibility, what do you think?

Sure. I guess we can assume that if port 80 is closed on the device then we should use the CoAP protocol but let's keep it simple for now.

shexbeer commented 4 years ago

Pushed the code in #32 Yeah there are some improvements possible 👍 But for now, it works. Will do more research on initial pairing soon.

hoky24 commented 4 years ago

@shexbeer Thank you for your work on improving py-air-control. I tried your CoAP version with my AC3829, but I didn't get status:

sudo ./airctrl.py  --ipaddr 192.168.1.37 --protocol 2 -d
2020-02-01 09:05:33,384 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('192.168.1.37', 5683), None-None, EMPTY-None, [] No payload
2020-02-01 09:05:33,385 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('192.168.1.37', 5683), CON-25755, EMPTY-None, [] No payload
2020-02-01 09:05:33,385 - Thread-1   - coapthon.client.coap - DEBUG - Start receiver Thread
2020-02-01 09:05:33,386 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('192.168.1.37', 5683), ACK-None, GET-fIpf, [Uri-Path: sys, Uri-Path: dev, Uri-Path: status, Observe: 0, ] No payload
2020-02-01 09:05:33,386 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('192.168.1.37', 5683), ACK-25756, GET-fIpf, [Uri-Path: sys, Uri-Path: dev, Uri-Path: status, Observe: 0, ] No payload
2020-02-01 09:05:33,386 - MainThread-Retry-25755 - coapthon.client.coap - DEBUG - retransmit loop ... enter
2020-02-01 09:05:33,390 - Thread-1   - coapthon.layers.messagelayer - DEBUG - receive_empty - From ('192.168.1.37', 5683), To None, RST-25755, EMPTY-None, [] No payload
2020-02-01 09:05:33,390 - MainThread-Retry-25755 - coapthon.client.coap - DEBUG - retransmit loop ... exit
2020-02-01 09:05:35,393 - Thread-1   - coapthon.client.coap - DEBUG - Exiting receiver Thread due to request
Raw status: {}
shexbeer commented 4 years ago

Hello @hoky24, great you had time to try it out.

My communication looks like this:

2020-02-01 11:41:40,739 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('192.168.179.76', 5683), None-None, EMPTY-None, [] No payload
2020-02-01 11:41:40,739 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('192.168.179.76', 5683), CON-48336, EMPTY-None, [] No payload
2020-02-01 11:41:40,740 - Thread-1   - coapthon.client.coap - DEBUG - Start receiver Thread
2020-02-01 11:41:40,740 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('192.168.179.76', 5683), ACK-None, GET-wGEM, [Uri-Path: sys, Uri-Path: dev, Uri-Path: status, Observe: 0, ] No payload
2020-02-01 11:41:40,740 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('192.168.179.76', 5683), ACK-48337, GET-wGEM, [Uri-Path: sys, Uri-Path: dev, Uri-Path: status, Observe: 0, ] No payload
2020-02-01 11:41:40,741 - MainThread-Retry-48336 - coapthon.client.coap - DEBUG - retransmit loop ... enter
2020-02-01 11:41:40,747 - Thread-1   - coapthon.layers.messagelayer - DEBUG - receive_empty - From ('192.168.179.76', 5683), To None, RST-48336, EMPTY-None, [] No payload
2020-02-01 11:41:40,747 - MainThread-Retry-48336 - coapthon.client.coap - DEBUG - retransmit loop ... exit
2020-02-01 11:41:40,749 - Thread-1   - coapthon.client.coap - DEBUG - receive_datagram - From ('192.168.179.76', 5683), To None, ACK-27092, CONTENT-wGEM, [Observe: 13554, Content-Type: 50, Max-Age: 60, ] {"state":{"reported"...588 bytes
2020-02-01 11:41:40,749 - Thread-1   - coapthon.layers.messagelayer - DEBUG - receive_response - From ('192.168.179.76', 5683), To None, ACK-27092, CONTENT-wGEM, [Observe: 13554, Content-Type: 50, Max-Age: 60, ] {"state":{"reported"...588 bytes
2020-02-01 11:41:40,851 - Thread-1   - coapthon.client.coap - DEBUG - Exiting receiver Thread due to request

I can see that your device is indeed talking to you:

2020-02-01 09:05:33,390 - Thread-1   - coapthon.layers.messagelayer - DEBUG - receive_empty - From ('192.168.1.37', 5683), To None, RST-25755, EMPTY-None, [] No payload

After the empty message the device should connect to you and send you the status because of the GET request with observe addin. I will take a second look into your posted pcap file and maybe spot a important difference to my unit here

PS: Do you have Philips cloud enabled? PPS: What happens if you send a command like --pw 0 or / --pw 1 ? PPS: After having second look onto your pcap file, it looks like your app/device sends different coap messages than mine does. Also i saw in your pcap that your device is using firmware 1.4 and mine use 0.2.1. When did you buy your device? Did you connect it to Cloud, did any OTA? (for comparison: I bought my device on Monday from Amazon, never connected to Cloud, never did OTA) PPPS: After taking a look into your responses from GET /sys/dev/status, it looks like the json response may be encrypted. Mine is plain

rgerganov commented 4 years ago

I have merged @shexbeer work into master. You can do a git pull and then test the CoAP support by adding --protocol coap argument. Unfortunately I don't have such device and cannot do any testing but I will be happy to accept any patches from you guys.

szogi commented 4 years ago

I tried coAP w/ philips ac2729, but I didn't get status/response: ac2729-coap.zip

airctrl --ipaddr 172.16.0.140 --protocol coap --debug

2020-02-02 01:26:32,761 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('172.16.0.140', 5683), None-None, EMPTY-None, [] No payload 2020-02-02 01:26:32,762 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('172.16.0.140', 5683), CON-20162, EMPTY-None, [] No payload 2020-02-02 01:26:32,764 - Thread-1 - coapthon.client.coap - DEBUG - Start receiver Thread 2020-02-02 01:26:32,767 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('172.16.0.140', 5683), ACK-None, GET-BeGj, [Uri-Path: sys, Uri-Path: dev, Uri-Path: status, Observe: 0, ] No payload 2020-02-02 01:26:32,767 - MainThread-Retry-20162 - coapthon.client.coap - DEBUG - retransmit loop ... enter 2020-02-02 01:26:32,768 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('172.16.0.140', 5683), ACK-20163, GET-BeGj, [Uri-Path: sys, Uri-Path: dev, Uri-Path: status, Observe: 0, ] No payload 2020-02-02 01:26:32,770 - Thread-1 - coapthon.layers.messagelayer - DEBUG - receive_empty - From ('172.16.0.140', 5683), To None, RST-20162, EMPTY-None, [] No payload 2020-02-02 01:26:32,771 - MainThread-Retry-20162 - coapthon.client.coap - DEBUG - retransmit loop ... exit 2020-02-02 01:26:34,775 - Thread-1 - coapthon.client.coap - DEBUG - Exiting receiver Thread due to request Raw status: {}


~# airctrl --ipaddr 172.16.0.140 --protocol coap --debug --pw 1 2020-02-02 01:26:51,754 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('172.16.0.140', 5683), None-None, EMPTY-None, [] No payload 2020-02-02 01:26:51,755 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('172.16.0.140', 5683), CON-27954, EMPTY-None, [] No payload 2020-02-02 01:26:51,757 - Thread-1 - coapthon.client.coap - DEBUG - Start receiver Thread 2020-02-02 01:26:51,760 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('172.16.0.140', 5683), None-None, POST-BZ, [Uri-Path: sys, Uri-Path: dev, Uri-Path: control, ] {"state": {"desired"...36 bytes 2020-02-02 01:26:51,761 - MainThread-Retry-27954 - coapthon.client.coap - DEBUG - retransmit loop ... enter 2020-02-02 01:26:51,762 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('172.16.0.140', 5683), CON-27955, POST-BZ, [Uri-Path: sys, Uri-Path: dev, Uri-Path: control, ] {"state": {"desired"...36 bytes 2020-02-02 01:26:51,762 - Thread-1 - coapthon.layers.messagelayer - DEBUG - receive_empty - From ('172.16.0.140', 5683), To None, RST-27954, EMPTY-None, [] No payload 2020-02-02 01:26:51,765 - MainThread-Retry-27954 - coapthon.client.coap - DEBUG - retransmit loop ... exit 2020-02-02 01:26:51,766 - MainThread-Retry-27955 - coapthon.client.coap - DEBUG - retransmit loop ... enter 2020-02-02 01:26:51,767 - Thread-1 - coapthon.client.coap - DEBUG - receive_datagram - From ('172.16.0.140', 5683), To None, NON-27955, CONTENT-BZ, [Content-Type: 50, ] {"status":"failed"}...19 bytes 2020-02-02 01:26:51,768 - Thread-1 - coapthon.layers.messagelayer - DEBUG - receive_response - From ('172.16.0.140', 5683), To None, NON-27955, CONTENT-BZ, [Content-Type: 50, ] {"status":"failed"}...19 bytes 2020-02-02 01:26:51,771 - Thread-1 - coapthon.client.coap - DEBUG - Waiting for retransmit thread to finish ... 2020-02-02 01:26:51,772 - MainThread-Retry-27955 - coapthon.client.coap - DEBUG - retransmit loop ... exit 2020-02-02 01:26:51,883 - Thread-1 - coapthon.client.coap - DEBUG - Exiting receiver Thread due to request

shexbeer commented 4 years ago

@szogi Looks like you have a similar device like @hoky24. I can see the device is talking to you. Also when you set the state, the device is answering you (but it was not successful: {"status":"failed"} I guess your devices want to have some special formatting / encoding / encryption of the payloads, but iam still unsure

Can you please capture some packets while you are using the AirMatters App? Please follow this:

  1. Start capturing from mobile device
  2. Open App
  3. Click on Device
  4. Set ChildLock On/Off + Power On/Off
  5. Stop Capturing from mobile device

Just include the traffic between your mobile device and the purifier.

mhabegger commented 4 years ago

@shexbeer here's a pcap from communication between AirMatters and AC1214/10. There are 2 ICMP as you described and then CoAP messages.

mico_packet_capture.pcap.zip

Purifier IP: 172.25.1.72 Phone IP: 172.25.1.104

Operations performed, Child Lock ON + Off then Power OFF + ON

hoky24 commented 4 years ago

@shexbeer

PS: Do you have Philips cloud enabled?

Yes, I have Philips cloud enabled

PPS: What happens if you send a command like --pw 0 or / --pw 1 ?

sudo ./airctrl.py  --ipaddr 192.168.1.37 --protocol coap -d --pw 0
2020-02-03 17:27:02,202 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('192.168.1.37', 5683), None-None, EMPTY-None, [] No payload
2020-02-03 17:27:02,203 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('192.168.1.37', 5683), CON-19242, EMPTY-None, [] No payload
2020-02-03 17:27:02,203 - Thread-1   - coapthon.client.coap - DEBUG - Start receiver Thread
2020-02-03 17:27:02,203 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('192.168.1.37', 5683), None-None, POST-NF, [Uri-Path: sys, Uri-Path: dev, Uri-Path: control, ] {"state": {"desired"...36 bytes
2020-02-03 17:27:02,204 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('192.168.1.37', 5683), CON-19243, POST-NF, [Uri-Path: sys, Uri-Path: dev, Uri-Path: control, ] {"state": {"desired"...36 bytes
2020-02-03 17:27:02,204 - MainThread-Retry-19242 - coapthon.client.coap - DEBUG - retransmit loop ... enter
2020-02-03 17:27:02,204 - MainThread-Retry-19243 - coapthon.client.coap - DEBUG - retransmit loop ... enter
2020-02-03 17:27:02,210 - Thread-1   - coapthon.layers.messagelayer - DEBUG - receive_empty - From ('192.168.1.37', 5683), To None, RST-19242, EMPTY-None, [] No payload
2020-02-03 17:27:02,211 - MainThread-Retry-19242 - coapthon.client.coap - DEBUG - retransmit loop ... exit
2020-02-03 17:27:02,212 - Thread-1   - coapthon.client.coap - DEBUG - receive_datagram - From ('192.168.1.37', 5683), To None, NON-19243, CONTENT-NF, [Content-Type: 50, ] {"status":"failed"}...19 bytes
2020-02-03 17:27:02,212 - Thread-1   - coapthon.layers.messagelayer - DEBUG - receive_response - From ('192.168.1.37', 5683), To None, NON-19243, CONTENT-NF, [Content-Type: 50, ] {"status":"failed"}...19 bytes
2020-02-03 17:27:02,212 - Thread-1   - coapthon.client.coap - DEBUG - Waiting for retransmit thread to finish ...
2020-02-03 17:27:02,212 - MainThread-Retry-19243 - coapthon.client.coap - DEBUG - retransmit loop ... exit
2020-02-03 17:27:02,323 - Thread-1   - coapthon.client.coap - DEBUG - Exiting receiver Thread due to request
sudo ./airctrl.py  --ipaddr 192.168.1.37 --protocol coap -d --pw 1
2020-02-03 17:27:09,106 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('192.168.1.37', 5683), None-None, EMPTY-None, [] No payload
2020-02-03 17:27:09,106 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('192.168.1.37', 5683), CON-52185, EMPTY-None, [] No payload
2020-02-03 17:27:09,107 - Thread-1   - coapthon.client.coap - DEBUG - Start receiver Thread
2020-02-03 17:27:09,107 - MainThread - coapthon.layers.messagelayer - DEBUG - send_request - From None, To ('192.168.1.37', 5683), None-None, POST-CQ, [Uri-Path: sys, Uri-Path: dev, Uri-Path: control, ] {"state": {"desired"...36 bytes
2020-02-03 17:27:09,107 - MainThread-Retry-52185 - coapthon.client.coap - DEBUG - retransmit loop ... enter
2020-02-03 17:27:09,107 - MainThread - coapthon.client.coap - DEBUG - send_datagram - From None, To ('192.168.1.37', 5683), CON-52186, POST-CQ, [Uri-Path: sys, Uri-Path: dev, Uri-Path: control, ] {"state": {"desired"...36 bytes
2020-02-03 17:27:09,108 - MainThread-Retry-52186 - coapthon.client.coap - DEBUG - retransmit loop ... enter
2020-02-03 17:27:09,109 - Thread-1   - coapthon.layers.messagelayer - DEBUG - receive_empty - From ('192.168.1.37', 5683), To None, RST-52185, EMPTY-None, [] No payload
2020-02-03 17:27:09,109 - MainThread-Retry-52185 - coapthon.client.coap - DEBUG - retransmit loop ... exit
2020-02-03 17:27:09,111 - Thread-1   - coapthon.client.coap - DEBUG - receive_datagram - From ('192.168.1.37', 5683), To None, NON-52186, CONTENT-CQ, [Content-Type: 50, ] {"status":"failed"}...19 bytes
2020-02-03 17:27:09,111 - Thread-1   - coapthon.layers.messagelayer - DEBUG - receive_response - From ('192.168.1.37', 5683), To None, NON-52186, CONTENT-CQ, [Content-Type: 50, ] {"status":"failed"}...19 bytes
2020-02-03 17:27:09,112 - Thread-1   - coapthon.client.coap - DEBUG - Waiting for retransmit thread to finish ...
2020-02-03 17:27:09,112 - MainThread-Retry-52186 - coapthon.client.coap - DEBUG - retransmit loop ... exit
2020-02-03 17:27:09,222 - Thread-1   - coapthon.client.coap - DEBUG - Exiting receiver Thread due to request

PPS: After having second look onto your pcap file, it looks like your app/device sends different coap messages than mine does. Also i saw in your pcap that your device is using firmware 1.4 and mine use 0.2.1. When did you buy your device? Did you connect it to Cloud, did any OTA? (for comparison: I bought my device on Monday from Amazon, never connected to Cloud, never did OTA)

I bought my AC3829/10 on Amazon in November and connected to it using the Air Matters app from my Android phone. I've never confirmed any updates, but it's possible that it's running in the background.

PPPS: After taking a look into your responses from GET /sys/dev/status, it looks like the json response may be encrypted. Mine is plain

Yes, it looks like CoAP over TLS. I signed out of the Phillips account on Air Matters and tried to capture the communication again according to the recommended procedure:

  1. Start capturing from mobile device
  2. Open App
  3. Click on Device
  4. Set ChildLock On/Off + Power On/Off
  5. Stop Capturing from mobile device

purifier-coap_tls.pcap.zip

shexbeer commented 4 years ago

I guess the key to encrypt the payloads is stored in the cloud now. Currently dont have an idea how to proceed. Would be interesting if anyone with philips cloud can sniff their http(s) traffic and decrypt their encrypted traffic via https://www.charlesproxy.com for example to see if my guess if correct. Maybe we can do calls to the cloud to get the key 🤔

kokein commented 4 years ago

Hi, I'm trying to comunicate with above script PHILIPS AC3829/10 (wifi) but when typing "--protocol coap" the code give me this: error: unrecognized arguments: --protocol coap Any idea why i cant change it?

rgerganov commented 4 years ago

Hi, I'm trying to comunicate with above script PHILIPS AC3829/10 (wifi) but when typing "--protocol coap" the code give me this: error: unrecognized arguments: --protocol coap Any idea why i cant change it?

I haven't released a pypi package with these changes because they are unstable and work only for one person so far. If you want to try it out, please use the latest code from GitHub.

kokein commented 4 years ago

Thx! Tried, but with no success. "--protocol coap" gives nothing for me also.

regnets commented 4 years ago

I guess the key to encrypt the payloads is stored in the cloud now. Currently dont have an idea how to proceed. Would be interesting if anyone with philips cloud can sniff their http(s) traffic and decrypt their encrypted traffic via https://www.charlesproxy.com for example to see if my guess if correct. Maybe we can do calls to the cloud to get the key 🤔

Ok, i got a AC3259/10 which seems to be also on the COAP Protocol, what do i need to do to get the neccessary information?

regnets commented 4 years ago

Ok i just did a port scan, everything is closed, any ideas? Annotation 2020-02-21 165953

ghost commented 4 years ago

I guess the key to encrypt the payloads is stored in the cloud now.

No, that is not possible. The AES-128-CBC key and IV is probably derived from the coap message ID. Otherwise the communication between the devices would not work offline.

ghost commented 4 years ago

Ok i just did a port scan, everything is closed, any ideas? Annotation 2020-02-21 165953

nmap -p U:5683 -sU --script coap-resources <target>

rgerganov commented 4 years ago

Capturing the network traffic won't be enough here. You need to reverse the mobile app like I did for the HTTP devices.

robtop100 commented 4 years ago

hi

thank you for your work today received 2 philips models it isvpossible to control it via cloud with support message generated from philips android apk? it is possible to use direct calls without cloud?

Appliance: Appliance Name: Biuro ID: 297a9a9aadd911e9a1e306... Paired: true Firmware Version: AWS_Philips_AIR@51.1 Device Version: 1.4.0 Model: AC3829/50Model: AC3829 - AC3829/50

Appliance: Appliance Name: Pokój ID: e975430aa3ba11e9a1e30... Paired: true Firmware Version: AWS_Philips_AIR@51.1 Device Version: 0.2.1 Model: AC2729/50Model: AC2729 - AC2729/50

robtop100 commented 4 years ago

@rgerganov as you can see I have 2 devices with two device versions ..how can I help you with your reverse eng?

rgerganov commented 4 years ago

@rgerganov as you can see I have 2 devices with two device versions ..how can I help you with your reverse eng?

If you are located in Europe you can borrow me a device for a week or two. I won't be able to do this remotely, sorry ...

regnets commented 4 years ago

@rgerganov Where do you live? I am located in the western part of germany.

rgerganov commented 4 years ago

@rgerganov Where do you live? I am located in the western part of germany.

I am based in Sofia, Bulgaria

ghost commented 4 years ago

It looks a little more complicated than that. The message itself is encrypted AES-CBC. The key and IV seems to be derived from the COAP message ID. However, a simple replay attack does not work here because the COAP Message ID is synchronized (POST /sys/dev/sync). After every message, the client sends an empty message to the server to stay syncronized.

mateuszdrab commented 4 years ago

Hey guys. I've been observing this issue as well as I've just got the Philips AC2889 delivered about a week ago and I've not connected it to any wifi at all until now where I connected it to a 'jail' wifi network with no internet access for my home automation devices. Unfortunately, I am not able to control it via port 80 nor via port 30123 as both are closed. I had to use the app to get it to connect to the wifi. Considering that my device hasn't touched the internet yet. Is there a way I can help? I'd really like it to work with Home Assistant as otherwise the 'connected' feature is useless. I still don't understand why companies don't provide open APIs for their devices.