mac-zhou / midea-msmart

This is a library to allow communicating to a Midea AC via the Local area network.
MIT License
147 stars 40 forks source link

Couldn't connect but get response #45

Closed LaBoss closed 3 years ago

LaBoss commented 3 years ago

Hello ppl I have 4 AC units I'm trying to connect with the library. But after get K1 and Token sometimes works sometimes not.

Requirement already satisfied: msmart in ./.local/lib/python3.7/site-packages (0.1.28)
Requirement already satisfied: pycryptodomex in ./.local/lib/python3.7/site-packages (from msmart) (3.10.1)
Requirement already satisfied: pycryptodome in ./.local/lib/python3.7/site-packages (from msmart) (3.10.1)
Requirement already satisfied: click in ./.local/lib/python3.7/site-packages (from msmart) (8.0.1)
Requirement already satisfied: importlib-metadata; python_version < "3.8" in ./.local/lib/python3.7/site-packages (from click->msmart) (4.6.3)
Requirement already satisfied: zipp>=0.5 in ./.local/lib/python3.7/site-packages (from importlib-metadata; python_version < "3.8"->click->msmart) (3.5.0)
Requirement already satisfied: typing-extensions>=3.6.4; python_version < "3.8" in ./.local/lib/python3.7/site-packages (from importlib-metadata; python_version < "3.8"->click->msmart) (3.10.0.0)

The output log is

DEBUG:msmart.lan:Attempting new connection to 192.168.1.145:6444
DEBUG:msmart.lan:Sending to 192.168.1.145:6444 837000402000000078c9b43865b2b3ac5901d27a8b0785d17fccb796e1200eaba07e11ce4b0b59de16542d3dc9f9d9e75db9467a69ab9fb2783bdd119ac08cde20e80c7446a0e39f
DEBUG:msmart.lan:Received from 192.168.1.145:6444 8370004020010000b2cb8cb5f6dd50fc0657a896c05200fbb7204bb303ef21322d18f6ecc80005e4efe4c1888be95b5654cb97fbb5a1abdd0174c48222a657e6aa05ef9d97c3e941
INFO:msmart.lan:Got TCP key for 192.168.1.145:6444 8e414e29d357b38d3e4265aa5576e51ce905d0e9a2543f080dc23af1210a01c7
DEBUG:msmart.command:Finalize request data: aa20ac00000000000003418100ff03ff000200000000000000000000000006f274
DEBUG:msmart.device:pkt_builder: 192.168.1.145:192.168.1.145 len: 104 data: 5a5a0111680020000000000025060d0d1108151468590300001d00000000000000000000000000006b000a76e27eed2c3647e57d8602df8bf295fcc1f4b9ce80e506ab2a879fe3c5a8a539f3ded2b04298069292e4ad666e4dd02e9fe4b8fb958ea15ba3dca5f282
DEBUG:msmart.lan:Sending to 192.168.1.145:6444 8370008e206671ce9076ab3f7bc9f7981ddc2a5977874ae6aa72d2d382544e09d86fcd4171d878d4daebb934c9b7bd66dc68526951f6bdf09fd1a5a2f2ccfde734d9f9d84df855beb911d7806547201fb88d23b0af373de83d834a514f63ad32ddb826318872d4db93ac39c408aac4c4f6f1fdea034b780b6d1bd6438af2abf3f17f6ae8b5480e975f3e43f410f435908293bf8c3b9d
ERROR:msmart.lan:Couldn't connect with Device 192.168.1.145:6444 timed out
DEBUG:msmart.device:Got responses from 192.168.1.145:192.168.1.145 Version: 3 Count: 0
{'id': 31885837425000, 'name': '192.168.1.145', 'power_state': False, 'prompt_tone': False, 'target_temperature': 17.0, 'operational_mode': <operational_mode_enum.auto: 1>, 'fan_speed': <fan_speed_enum.Auto: 102>, 'swing_mode': <swing_mode_enum.Off: 0>, 'eco_mode': False, 'turbo_mode': False, 'indoor_temperature': 0.0, 'outdoor_temperature': 0.0}
{'id': 31885837425000, 'name': '192.168.1.145', 'power_state': True, 'prompt_tone': True, 'target_temperature': 19, 'operational_mode': <operational_mode_enum.cool: 2>, 'fan_speed': <fan_speed_enum.Auto: 102>, 'swing_mode': <swing_mode_enum.Off: 0>, 'eco_mode': False, 'turbo_mode': False, 'indoor_temperature': 0.0, 'outdoor_temperature': 0.0}

My script for test ist

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
from msmart.device import air_conditioning_device as ac
import logging
logging.basicConfig(level=logging.DEBUG)

device_ip = '192.168.1.145'
device_id = '31885837425000'
device_K1 = 'D86532ACE8564E34A0F51413FD1394A3937BA756C34348B485D84E4D2464F57A'
device_Token = '78C9B43865B2B3AC5901D27A8B0785D17FCCB796E1200EABA07E11CE4B0B59DE16542D3DC9F9D9E75DB9467A69AB9FB2783BDD119AC08CDE20E80C7446A0E39F'
port = 6444

device = ac(device_ip, int(device_id), port)

device.authenticate(device_K1, device_Token)

# Refresh the object with the actual state by querying it
device.refresh()
print({
        'id': device.id,
        'name': device.ip,
        'power_state': device.power_state,
        'prompt_tone': device.prompt_tone,
        'target_temperature': device.target_temperature,
        'operational_mode': device.operational_mode,
        'fan_speed': device.fan_speed,
        'swing_mode': device.swing_mode,
        'eco_mode': device.eco_mode,
        'turbo_mode': device.turbo_mode,
        'indoor_temperature': device.indoor_temperature,
        'outdoor_temperature': device.outdoor_temperature,
    })

what can i be doing wrong?

Thanks

mac-zhou commented 3 years ago
  1. kill midea app process on your phone
  2. modify lan.py add time.sleep(1) on line 54, like
            self._socket.send(message)
            time.sleep(1)
            # Received data
            response = self._socket.recv(1024)
seppe912 commented 3 years ago

you need to import time too:

line 3:

import logging
import socket
import time
from msmart.security import security, MSGTYPE_HANDSHAKE_REQUEST, MSGTYPE_ENCRYPTED_REQUEST

and then modify line 54/55 like:

            self._socket.send(message)
            time.sleep(1)
            # Received data
            response = self._socket.recv(1024)
LaBoss commented 3 years ago

Hello its works fine!

laboss@AirCon:~$ python3 teste.py
DEBUG:msmart.lan:Attempting new connection to 192.168.1.81:6444
DEBUG:msmart.lan:Sending to 192.168.1.81:6444 83700040200000004cb64ca865f406ceabd7992a9cb67df1cac30b477251304d9572bdcec083b76f3ff67ff659f5d856586f90f1dd34482a75301542e8d08e59c43f8e7c29e6bcea
DEBUG:msmart.lan:Received from 192.168.1.81:6444 837000402001000008477f9b13733d6938e9c8c11e4269ba464d83865f2544ec9cfd1450c30e16f619b2bac56026404c622b8a6cf6ca6b2c9ea8c0aae90860ff37082a3861c28639
INFO:msmart.lan:Got TCP key for 192.168.1.81:6444 f6f5eef3346d9a6b9179ce7f548522bc219807d3c2d89e70faca8ea9e98ebe8a
DEBUG:msmart.command:Finalize request data: aa20ac00000000000003418100ff03ff000200000000000000000000000009b3b0
DEBUG:msmart.device:pkt_builder: 192.168.1.81:192.168.1.81 len: 104 data: 5a5a011168002000000000005709100812081514fe5a0300001d00000000000000000000000000006b000a76e27eed2c3647e57d8602df8b21b039426e68de9944c80ea1959d1e7457166023780d35ebe761648a6a0633e1b63fd776a207f6a0a75053bfd84fda21
DEBUG:msmart.lan:Sending to 192.168.1.81:6444 8370008e2066f9e0e41401b8bb286d7af2e40b93933f307a484cf7eb93c51088c77bc5e8b1d92e2bfe9754e3143410bd963b3c83809afd70ce7dd402556bac03c5cfd91a05c10aaebd66d811b5f9487de275998e910d8c036c044f93500bae3ea9b55c39d7ce1a8ccbf05d84055545b99fe6f2d32e2fcb17226ede61dc5dc2195124a8a3677db6e2ed45a9dea9b7eaf2f6475e9a29ea
DEBUG:msmart.lan:Received from 192.168.1.81:6444 8370008e2063f0e728a8c5a26ea1749b8b8bdce0b9e1eda6867f53e425bbd804a8abbbc678db8275275820f04be0ea2cd095756518fe366ea0fddeb22d1d2ded9a5743d54bef4b1aeca7260c1cb96d382e6c46e25a91073c0a2ce676bb6c146b254d1acf840a44be38662496ca9b39249f93df49c45336d61d1b9f18854ec2a69890fcdb2b09cc4f81a4911b171ca2fac190626848c3
DEBUG:msmart.device:Got responses from 192.168.1.81:192.168.1.81 Version: 3 Count: 1
DEBUG:msmart.device:Update from 192.168.1.81:192.168.1.81 aa22ac00000000000303c00049667f7f00300000006762000000000000000000b0d83e
DEBUG:msmart.command:Appliance response data: c00049667f7f00300000006762000000000000000000b0d83e
{'id': 31885837425406, 'name': '192.168.1.81', 'power_state': False, 'prompt_tone': False, 'target_temperature': 25.0, 'operational_mode': <operational_mode_enum.cool: 2>, 'fan_speed': <fan_speed_enum.Auto: 102>, 'swing_mode': <swing_mode_enum.Off: 0>, 'eco_mode': False, 'turbo_mode': False, 'indoor_temperature': 26.0, 'outdoor_temperature': 24.0}
{'id': 31885837425406, 'name': '192.168.1.81', 'power_state': True, 'prompt_tone': True, 'target_temperature': 19, 'operational_mode': <operational_mode_enum.cool: 2>, 'fan_speed': <fan_speed_enum.Auto: 102>, 'swing_mode': <swing_mode_enum.Off: 0>, 'eco_mode': False, 'turbo_mode': False, 'indoor_temperature': 26.0, 'outdoor_temperature': 24.0}
laboss@AirCon:~$ python3 teste.py
DEBUG:msmart.lan:Attempting new connection to 192.168.1.81:6444
DEBUG:msmart.lan:Sending to 192.168.1.81:6444 83700040200000004cb64ca865f406ceabd7992a9cb67df1cac30b477251304d9572bdcec083b76f3ff67ff659f5d856586f90f1dd34482a75301542e8d08e59c43f8e7c29e6bcea
DEBUG:msmart.lan:Received from 192.168.1.81:6444 837000402001000038e40c1438f52b7409b4851036160bb883c6b1309b4fa739f55fed656e1badaa812dc4bb3cded92093632404654307adf9f2a048c425346323143bc974c3ba11
INFO:msmart.lan:Got TCP key for 192.168.1.81:6444 8efc66ef3bd1196eabfec47fd598adb8ba580cd584959774b1e985ac4cabb48e
DEBUG:msmart.command:Finalize request data: aa20ac00000000000003418100ff03ff00020000000000000000000000000c8cd4
DEBUG:msmart.device:pkt_builder: 192.168.1.81:192.168.1.81 len: 104 data: 5a5a01116800200000000000510c100812081514fe5a0300001d00000000000000000000000000006b000a76e27eed2c3647e57d8602df8b8b688a2805c90be589e77c77786e94e5beb10a3f262d838d74d1930679f6ac10dd0407a81367e29024816b647d94a90f
DEBUG:msmart.lan:Sending to 192.168.1.81:6444 8370008e2066dff522dd204fec35e204701d276375bbc4e5521069d8a51f860a6c420673eab7942f244a78724852fb03c6f2e940d650c0cfcd78256765d023a3226beb678d2bfe66ebebef161b7bf3e79bb244cc7e2368730b50d52df57960f5411a32b3959bbc81ab311ac189283d51d24055c5558e687732d73df828fe70d4dac73dc6e1c1b987f3a2bfb9750ee3bf6cfc7957f77b
DEBUG:msmart.lan:Received from 192.168.1.81:6444 8370008e2063f86db7fcac3f98be4dd80e660cd998b97cc20c59601b6b802c4552ac398396308656b05aeca0d4a6a91beb1e84319b6923d98718925b05db469c167c088f45ad6c95238ad27245905772dd32505b535ddfc72145843ff7d7de0c5d6a2948bf3564e8b7890843a85e7340f34b36cad9a699f7cc6a99c76b2560741665fd43e66a7df363c213ff1ece4951c2c6edfe1d65
DEBUG:msmart.device:Got responses from 192.168.1.81:192.168.1.81 Version: 3 Count: 1
DEBUG:msmart.device:Update from 192.168.1.81:192.168.1.81 aa22ac00000000000303c00049667f7f00300000006762000000000000000000d4dc16
DEBUG:msmart.command:Appliance response data: c00049667f7f00300000006762000000000000000000d4dc16
{'id': 31885837425406, 'name': '192.168.1.81', 'power_state': False, 'prompt_tone': False, 'target_temperature': 25.0, 'operational_mode': <operational_mode_enum.cool: 2>, 'fan_speed': <fan_speed_enum.Auto: 102>, 'swing_mode': <swing_mode_enum.Off: 0>, 'eco_mode': False, 'turbo_mode': False, 'indoor_temperature': 26.0, 'outdoor_temperature': 24.0}
{'id': 31885837425406, 'name': '192.168.1.81', 'power_state': True, 'prompt_tone': True, 'target_temperature': 19, 'operational_mode': <operational_mode_enum.cool: 2>, 'fan_speed': <fan_speed_enum.Auto: 102>, 'swing_mode': <swing_mode_enum.Off: 0>, 'eco_mode': False, 'turbo_mode': False, 'indoor_temperature': 26.0, 'outdoor_temperature': 24.0}
laboss@AirCon:~$ python3 teste.py
DEBUG:msmart.lan:Attempting new connection to 192.168.1.81:6444
DEBUG:msmart.lan:Sending to 192.168.1.81:6444 83700040200000004cb64ca865f406ceabd7992a9cb67df1cac30b477251304d9572bdcec083b76f3ff67ff659f5d856586f90f1dd34482a75301542e8d08e59c43f8e7c29e6bcea
DEBUG:msmart.lan:Received from 192.168.1.81:6444 8370004020010000222d5036925749b270530803c2e0e81c7118799228d82455617c3999f21d908f340d49af214e8e658c95f310d723eb1b8acda7f12b6b00c8bc8fd1918af8abdc
INFO:msmart.lan:Got TCP key for 192.168.1.81:6444 484b74dc86b28b6542205e74816c37b744f292da246a0979443919a116512882
DEBUG:msmart.command:Finalize request data: aa20ac00000000000003418100ff03ff00020000000000000000000000000f6eef
DEBUG:msmart.device:pkt_builder: 192.168.1.81:192.168.1.81 len: 104 data: 5a5a01116800200000000000450f100812081514fe5a0300001d00000000000000000000000000006b000a76e27eed2c3647e57d8602df8bd8843c397dead052d9dae3b48bf3b3b56ca53bb8c5a00c97cbbfa3fe254ffe83ed2f7610ca8b54e4c786faa72d100a3c
DEBUG:msmart.lan:Sending to 192.168.1.81:6444 8370008e2066f7e183b1d3509eea9e0037fcbfe3dc5d0f0ae2a5ff799695ada03c9584ec588494e1f71e3265d90b5a81619f53fe286344304ab26ccf6dcaf2400d42a0e64b89a4ccfb4922575ba107f61d8ed09a2c677430ce9871d915fbde0a5bef2faff0eb678a896632002790b34077435d7024ffa6a155c314c54e0cc67254f922dc96834136d12b66411847a13b15d8da52374b
DEBUG:msmart.lan:Received from 192.168.1.81:6444 8370008e20634a3fd18440b8f02ec51807c0f4cf93b45a3ecfb825bc5b6e899559980078c369d3991cdd6c5f60ee9a736b0b4bb60c5f7921091ca8a276d3d2cca9fb8abebb69dad50bca7da1dca2bfd98a1252da8d5f6017224614bfb32e7be7890c4a14eeadd1e41ee25cb7c0ecaeeecf330bb7e45598eef0a42744631bb368723cb6e5125e6bbf0796983bc2e9f11abe4430a4ca1b
DEBUG:msmart.device:Got responses from 192.168.1.81:192.168.1.81 Version: 3 Count: 1
DEBUG:msmart.device:Update from 192.168.1.81:192.168.1.81 aa22ac00000000000303c00049667f7f00300000006762000000000000000000ef4295
DEBUG:msmart.command:Appliance response data: c00049667f7f00300000006762000000000000000000ef4295
{'id': 31885837425406, 'name': '192.168.1.81', 'power_state': False, 'prompt_tone': False, 'target_temperature': 25.0, 'operational_mode': <operational_mode_enum.cool: 2>, 'fan_speed': <fan_speed_enum.Auto: 102>, 'swing_mode': <swing_mode_enum.Off: 0>, 'eco_mode': False, 'turbo_mode': False, 'indoor_temperature': 26.0, 'outdoor_temperature': 24.0}
{'id': 31885837425406, 'name': '192.168.1.81', 'power_state': True, 'prompt_tone': True, 'target_temperature': 19, 'operational_mode': <operational_mode_enum.cool: 2>, 'fan_speed': <fan_speed_enum.Auto: 102>, 'swing_mode': <swing_mode_enum.Off: 0>, 'eco_mode': False, 'turbo_mode': False, 'indoor_temperature': 26.0, 'outdoor_temperature': 24.0}
laboss@AirCon:~$

Are you going to put the fix into production?

mac-zhou commented 3 years ago

delete sleep and modify lan.py line 28, like:

            self._socket.settimeout(8)
            self._socket.setblocking(1)
            try:

then, try to test

mac-zhou commented 3 years ago

Are you going to put the fix into production?

I haven't found a best way to fix it in homeassistant, there is no this error

LaBoss commented 3 years ago

On HA mine often gives this error (In an hour 200x)

Sem Título

But entities appear as available. But I have to test even better

Sem Título

mac-zhou commented 3 years ago

On HA mine often gives this error (In an hour 200x)

did you add self._socket.setblocking(1)?

LaBoss commented 3 years ago

I didn't put... Where do I put it in the custom component?

If put on MideaClimateACDevice init method Complains that the _socket property does not exist

mac-zhou commented 3 years ago

I didn't put... Where do I put it in the custom component?

If put on MideaClimateACDevice init method Complains that the _socket property does not exist

lan.py

LaBoss commented 3 years ago

I don't know how to access the file... It must be inside the docker container and I can't access it (Its HASSOS)...

LaBoss commented 3 years ago

Ok I found a way to connect to the container, and it was slightly different

self._socket.settimeout(8)
            self._socket.setblocking(1)

image

With sleep(1) the timed out error also occurs

my lan.py

# -*- coding: UTF-8 -*-
import logging
import socket
import time
from msmart.security import security, MSGTYPE_HANDSHAKE_REQUEST, MSGTYPE_ENCRYPTED_REQUEST

VERSION = '0.1.29'

_LOGGER = logging.getLogger(__name__)

class lan:
    def __init__(self, device_ip, device_id, device_port=6444):
        self.device_ip = device_ip
        self.device_id = device_id
        self.device_port = device_port
        self.security = security()
        self._retries = 0
        self._socket = None
        self._token = None
        self._key = None

    def _connect(self):
        if self._socket is None:
            _LOGGER.debug("Attempting new connection to {}:{}".format(
                self.device_ip, self.device_port))
            self._buffer = b''
            self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self._socket.settimeout(8)
            self._socket.setblocking(1)
            try:
                self._socket.connect((self.device_ip, self.device_port))
            except Exception as error:
                _LOGGER.error("Connect Error: {}:{} {}".format(
                    self.device_ip, self.device_port, error))
                self._disconnect()

    def _disconnect(self):
        if self._socket:
            self._socket.close()
            self._socket = None

    def request(self, message):
        # Create a TCP/IP socket
        self._connect()

        try:
            if self._socket is None:
                _LOGGER.error("Sokcet is None: {}:{}".format(
                    self.device_ip, self.device_port))
                return bytearray(0)
            # Send data
            _LOGGER.debug("Sending to {}:{} {}".format(
                self.device_ip, self.device_port, message.hex()))
            self._socket.send(message)

            time.sleep(1)

            # Received data
            response = self._socket.recv(1024)
        except socket.error as error:
            _LOGGER.error("Couldn't connect with Device {}:{} {}".format(
                self.device_ip, self.device_port, error))
            self._disconnect()
            return bytearray(0)
        except socket.timeout:
            _LOGGER.error("Connect the Device {}:{} TimeOut for 8s. don't care about a small amount of this. if many maybe not support".format(
                self.device_ip, self.device_port))
            self._disconnect()
            return bytearray(0)
        _LOGGER.debug("Received from {}:{} {}".format(
            self.device_ip, self.device_port, response.hex()))
        return response

    def authenticate(self, token: bytearray, key: bytearray):
        self._token, self._key = token, key
        if not self._token or not self._key:
            raise Exception('missing token key pair')
        request = self.security.encode_8370(
            self._token, MSGTYPE_HANDSHAKE_REQUEST)
        response = self.request(request)[8:72]
        try:
            tcp_key = self.security.tcp_key(response, self._key)
            _LOGGER.info('Got TCP key for {}:{} {}'.format(
                self.device_ip, self.device_port, tcp_key.hex()))
        except Exception as error:
            self._disconnect()
            raise error

    def _authenticate(self):
        if not self._token or not self._key:
            raise Exception('missing token key pair')
        self.authenticate(self._token, self._key)

    def appliance_transparent_send_8370(self, data, msgtype=MSGTYPE_ENCRYPTED_REQUEST):
        if self._socket is None:
            self._authenticate()
        data = self.security.encode_8370(data, msgtype)
        responses, self._buffer = self.security.decode_8370(
            self._buffer + self.request(data))
        packets = []
        for response in responses:
            if len(response) > 40 + 16:
                response = self.security.aes_decrypt(response[40:-16])
            packets.append(response)
        return packets

    def appliance_transparent_send(self, data):
        responses = self.request(data)
        _LOGGER.debug("Got responses len: {}".format(len(responses)))
        if responses == bytearray(0):
            return responses
        packets = []
        if responses[:2].hex() == "5a5a":
            # maybe multiple response
            for response in responses.split(bytearray.fromhex('5a5a')):
                # 5a5a been removed, so (40-2)+16
                if len(response) > 38 + 16:
                    packets.append(self.security.aes_decrypt(response[38:-16]))
        elif responses[0] == 0xaa:
            for response in responses.split(bytearray.fromhex('aa')):
                packets.append(bytearray.fromhex('aa') + response)
        else:
            _LOGGER.error("Unknown responses {}".format(responses.hex()))
        return packets
mac-zhou commented 3 years ago

join telegram group https://t.me/joinchat/UFSSaqBJE5RqvSOq

mac-zhou commented 3 years ago

fix by https://github.com/mac-zhou/midea-msmart/commit/1c8e2a5c9357082a356c4814f9e93c05ee36d78d

LaBoss commented 3 years ago

thanks for effort.. you are the man