Repository: mill1000/midea-msmart
Pull request #29 (2023-08-17 22:55:39)

Clean up misc linter warnings from Pylint


Patch:
diff --git a/example.py b/example.py
index c7fb512..4b03cef 100644
--- a/example.py
+++ b/example.py
@@ -26,7 +26,7 @@ async def main():
 
     # Manually construct the device
     #  - See midea-discover to read ID, token and key
-    device = ac(ip=DEVICE_IP, port=6444, id=int(DEVICE_ID))
+    device = ac(ip=DEVICE_IP, port=6444, device_id=int(DEVICE_ID))
     if DEVICE_TOKEN and DEVICE_KEY:
         await device.authenticate(DEVICE_TOKEN, DEVICE_KEY)
 
diff --git a/msmart/base_command.py b/msmart/base_command.py
index ea3be69..1781440 100644
--- a/msmart/base_command.py
+++ b/msmart/base_command.py
@@ -1,6 +1,5 @@
 import logging
 from abc import ABC, abstractmethod
-from collections import namedtuple
 
 import msmart.crc8 as crc8
 from msmart.const import FRAME_TYPE
@@ -11,9 +10,9 @@ _LOGGER = logging.getLogger(__name__)
 class command(ABC):
     _message_id = 0
 
-    def __init__(self, device_type=0xAC, FRAME_TYPE=FRAME_TYPE.Request):
+    def __init__(self, device_type=0xAC, frame_type=FRAME_TYPE.Request):
         self.device_type = device_type
-        self.FRAME_TYPE = FRAME_TYPE
+        self.frame_type = frame_type
         self.protocol_version = 0
 
     def pack(self):
@@ -45,7 +44,7 @@ class command(ABC):
             # Device protocol version
             self.protocol_version,
             # Frame type
-            self.FRAME_TYPE
+            self.frame_type
         ])
 
         # Build frame from header and payload with CRC
@@ -74,8 +73,8 @@ class command(ABC):
 
 
 class set_customize_command(command):
-    def __init__(self, device_type, FRAME_TYPE, customize_cmd,):
-        super().__init__(device_type, FRAME_TYPE=FRAME_TYPE.Request)
+    def __init__(self, device_type, frame_type, customize_cmd,):
+        super().__init__(device_type, frame_type=frame_type.Request)
         self.customize_cmd = customize_cmd
 
     @property
diff --git a/msmart/cli.py b/msmart/cli.py
index 7e65d75..bdd2f65 100644
--- a/msmart/cli.py
+++ b/msmart/cli.py
@@ -12,9 +12,9 @@ _LOGGER = logging.getLogger(__name__)
 async def _discover(ip: str, count: int, account: str, password: str, china: bool, **_kwargs):
     """Discover Midea devices and print configuration information."""
 
-    _LOGGER.info(f"msmart version: {__version__}")
+    _LOGGER.info("msmart version: %s", __version__)
     _LOGGER.info(
-        f"Only supports AC devices. Only supports MSmartHome and 美的美居.")
+        "Only supports AC devices. Only supports MSmartHome and 美的美居.")
 
     if china and (account == OPEN_MIDEA_APP_ACCOUNT or password == OPEN_MIDEA_APP_PASSWORD):
         _LOGGER.error(
diff --git a/msmart/const.py b/msmart/const.py
index d3f9cf9..c9160b4 100644
--- a/msmart/const.py
+++ b/msmart/const.py
@@ -27,7 +27,7 @@ OPEN_MIDEA_APP_ACCOUNT = 'midea_is_best@outlook.com'
 OPEN_MIDEA_APP_PASSWORD = 'lovemidea4ever'
 
 
-class DeviceId(IntEnum):
+class DeviceType(IntEnum):
     AIR_CONDITIONER = 0xAC
 
 
diff --git a/msmart/device/AC/appliance.py b/msmart/device/AC/appliance.py
index 153c0a2..340fecc 100644
--- a/msmart/device/AC/appliance.py
+++ b/msmart/device/AC/appliance.py
@@ -1,7 +1,7 @@
 import logging
 from enum import IntEnum
 
-from msmart.const import DeviceId
+from msmart.const import DeviceType
 from msmart.device.base import device
 
 from .command import (InvalidResponseException, ResponseId,
@@ -74,11 +74,11 @@ class air_conditioning(device):
         def get(value):
             return IntEnumHelper.get(__class__, value, air_conditioning.swing_mode_enum.Off)
 
-    def __init__(self, ip: str, id: int,  port: int, **kwargs):
+    def __init__(self, ip: str, device_id: int,  port: int, **kwargs):
         # Ensure type is set
-        kwargs["type"] = DeviceId.AIR_CONDITIONER.value
+        kwargs["type"] = DeviceType.AIR_CONDITIONER.value
 
-        super().__init__(ip=ip, port=port, id=id, **kwargs)
+        super().__init__(ip=ip, port=port, device_id=device_id, **kwargs)
 
         self._updating = False
         self._keep_last_known_online_state = False
@@ -134,8 +134,8 @@ class air_conditioning(device):
         cmd = get_state_command(self.type)
         await self.send_command(cmd)
 
-    async def send_command(self, cmd, ignore_response=False):
-        responses = await super().send_command(cmd)
+    async def send_command(self, command, ignore_response=False):
+        responses = await super().send_command(command)
 
         # Ignore responses if requested, or nonexistent
         if ignore_response or responses is None:
diff --git a/msmart/device/AC/command.py b/msmart/device/AC/command.py
index 8293148..63a5307 100644
--- a/msmart/device/AC/command.py
+++ b/msmart/device/AC/command.py
@@ -1,7 +1,6 @@
 import logging
 import math
 import struct
-from abc import ABC, abstractmethod
 from collections import namedtuple
 from enum import IntEnum
 
@@ -54,7 +53,7 @@ class temperature_type(IntEnum):
 
 class get_capabilities_command(command):
     def __init__(self, device_type):
-        super().__init__(device_type, FRAME_TYPE=FRAME_TYPE.Request)
+        super().__init__(device_type, frame_type=FRAME_TYPE.Request)
 
     @property
     def payload(self):
@@ -68,7 +67,7 @@ class get_capabilities_command(command):
 
 class get_state_command(command):
     def __init__(self, device_type):
-        super().__init__(device_type, FRAME_TYPE=FRAME_TYPE.Request)
+        super().__init__(device_type, frame_type=FRAME_TYPE.Request)
 
         self.temperature_type = temperature_type.Indoor
 
@@ -92,7 +91,7 @@ class get_state_command(command):
 
 class set_state_command(command):
     def __init__(self, device_type):
-        super().__init__(device_type, FRAME_TYPE=FRAME_TYPE.Set)
+        super().__init__(device_type, frame_type=FRAME_TYPE.Set)
 
         self.beep_on = True
         self.power_on = False
@@ -167,7 +166,7 @@ class set_state_command(command):
 class toggle_display_command(command):
     def __init__(self, device_type):
         # For whatever reason, toggle display uses a request type...
-        super().__init__(device_type, FRAME_TYPE=FRAME_TYPE.Request)
+        super().__init__(device_type, frame_type=FRAME_TYPE.Request)
 
     @property
     def payload(self):
@@ -225,11 +224,11 @@ class response():
             response.validate(frame_mv)
 
             # Parse frame depending on id
-            id = frame_mv[10]
+            response_id = frame_mv[10]
             payload = frame_mv[10:-2]
-            if id == ResponseId.State:
+            if response_id == ResponseId.State:
                 return state_response(payload)
-            elif id == ResponseId.Capabilities:
+            elif response_id == ResponseId.Capabilities:
                 return capabilities_response(payload)
             else:
                 return response(payload)
@@ -314,7 +313,7 @@ class capabilities_response(response):
         caps = payload[2:]
 
         # Loop through each capability
-        for i in range(0, count):
+        for _ in range(0, count):
             # Stop if out of data
             if len(caps) < 3:
                 break
@@ -325,14 +324,14 @@ class capabilities_response(response):
                 continue
 
             # Unpack 16 bit ID
-            (cap_id, ) = struct.unpack("<H", caps[0:2])
+            (raw_id, ) = struct.unpack("<H", caps[0:2])
 
             # Covert ID to enumerate type
             try:
-                id = CapabilityId(cap_id)
+                capability_id = CapabilityId(raw_id)
             except ValueError:
                 _LOGGER.warning(
-                    "Unknown capability. ID: 0x%4X, Size: %d.", cap_id, size)
+                    "Unknown capability. ID: 0x%4X, Size: %d.", raw_id, size)
                 # Advanced to next capability
                 caps = caps[3+size:]
                 continue
@@ -341,20 +340,20 @@ class capabilities_response(response):
             value = caps[3]
 
             # Apply predefined capability reader if it exists
-            if id in capability_readers:
+            if capability_id in capability_readers:
                 # Local function to apply a reader
-                def apply(d): return {d.name: d.read(value)}
+                def apply(d, v): return {d.name: d.read(v)}
 
-                reader = capability_readers[cap_id]
+                reader = capability_readers[raw_id]
                 if isinstance(reader, list):
                     # Apply each reader in the list
                     for r in reader:
-                        self._capabilities.update(apply(r))
+                        self._capabilities.update(apply(r, value))
                 else:
                     # Apply the single reader
-                    self._capabilities.update(apply(reader))
+                    self._capabilities.update(apply(reader, value))
 
-            elif id == CapabilityId.Temperatures:
+            elif capability_id == CapabilityId.Temperatures:
                 # Skip if capability size is too small
                 if size < 6:
                     continue
@@ -370,7 +369,7 @@ class capabilities_response(response):
 
             else:
                 _LOGGER.warning(
-                    "Unsupported capability. ID: 0x%04X, Size: %d.", id, size)
+                    "Unsupported capability. ID: 0x%04X, Size: %d.", capability_id, size)
 
             # Advanced to next capability
             caps = caps[3+size:]
diff --git a/msmart/device/base.py b/msmart/device/base.py
index e4bc308..4823e8f 100644
--- a/msmart/device/base.py
+++ b/msmart/device/base.py
@@ -1,6 +1,5 @@
 import logging
 import time
-from abc import ABC, abstractmethod
 from typing import List, Union
 
 from msmart.lan import LAN, AuthenticationError, ProtocolError
@@ -9,26 +8,24 @@ from msmart.types import Key, Token
 _LOGGER = logging.getLogger(__name__)
 
 
-class device(ABC):
+class device():
 
-    def __init__(self, *, ip: str, port: int, id: int, **kwargs):
+    def __init__(self, *, ip: str, port: int, device_id: int, **kwargs) -> None:
         self._ip = ip
         self._port = port
 
-        self._id = id
+        self._id = device_id
         self._sn = kwargs.get("sn", None)
         self._name = kwargs.get("name", None)
         self._type = kwargs.get("type", None)
 
-        self._lan = LAN(ip, port, id)
+        self._lan = LAN(ip, port, device_id)
         self._support = False
         self._online = False
 
-    @abstractmethod
     async def refresh(self):
         raise NotImplementedError()
 
-    @abstractmethod
     async def apply(self):
         raise NotImplementedError()
 
diff --git a/msmart/discover.py b/msmart/discover.py
index f49fa58..fa264df 100644
--- a/msmart/discover.py
+++ b/msmart/discover.py
@@ -9,7 +9,7 @@ from typing import Optional, cast
 from msmart.cloud import Cloud
 from msmart.const import (DEVICE_INFO_MSG, DISCOVERY_MSG,
                           OPEN_MIDEA_APP_ACCOUNT, OPEN_MIDEA_APP_PASSWORD,
-                          DeviceId)
+                          DeviceType)
 from msmart.device import air_conditioning, device
 from msmart.lan import Security
 
@@ -23,6 +23,7 @@ class _V1DeviceInfoProtocol(asyncio.Protocol):
 
     def __init__(self):
         self._transport = None
+        self.response = None
 
     def connection_made(self, transport) -> None:
         """Send device info request on connection."""
@@ -37,7 +38,7 @@ class _V1DeviceInfoProtocol(asyncio.Protocol):
 
         self.response = data
 
-    def connection_lost(self, ex):
+    def connection_lost(self, exc) -> None:
         """NOP implementation of connection lost."""
 
 
@@ -81,7 +82,7 @@ class _DiscoverProtocol(asyncio.DatagramProtocol):
 
         for port in [6445, 20086]:
             _LOGGER.debug("Discovery sent to %s:%d.", self._target, port)
-            for i in range(self._discovery_packets):
+            for _ in range(self._discovery_packets):
                 self._transport.sendto(DISCOVERY_MSG, (self._target, port))
 
     def datagram_received(self, data, addr) -> None:
@@ -98,20 +99,24 @@ class _DiscoverProtocol(asyncio.DatagramProtocol):
         _LOGGER.debug("Discovery response from %s: %s", ip, data.hex())
 
         try:
+            # pylint: disable=protected-access
             version = Discover._get_device_version(data)
         except Discover.UnknownDeviceVersion:
             _LOGGER.error("Unknown device version for %s.", ip)
             return
 
         # Construct a task
-        task = asyncio.create_task(Discover._get_device(ip, version, data))
+        task = asyncio.create_task(
+            # pylint: disable=protected-access
+            Discover._get_device(ip, version, data)
+        )
         self.tasks.add(task)
 
-    def error_received(self, ex):
+    def error_received(self, exc) -> None:
         """Handle asyncio.Protocol errors."""
-        _LOGGER.error("Got error: %s", ex)
+        _LOGGER.error("Got error: %s", exc)
 
-    def connection_lost(self, ex):
+    def connection_lost(self, exc) -> None:
         """NOP implementation of connection lost."""
 
 
@@ -120,7 +125,6 @@ class Discover:
 
     class UnknownDeviceVersion(Exception):
         """Exception for unknown device version."""
-        pass
 
     _account = OPEN_MIDEA_APP_ACCOUNT
     _password = OPEN_MIDEA_APP_PASSWORD
@@ -246,7 +250,7 @@ class Discover:
 
             loop = asyncio.get_event_loop()
             transport, protocol = await loop.create_connection(
-                lambda: _V1DeviceInfoProtocol(), ip, port)
+                lambda: _V1DeviceInfoProtocol(), ip, port)  # pylint: disable=unnecessary-lambda
             protocol = cast(_V1DeviceInfoProtocol, protocol)
 
             try:
@@ -273,7 +277,7 @@ class Discover:
                 encrypted_data = data_mv[40:-16]
 
                 # Extract ID
-                id = int.from_bytes(data_mv[20:26], 'little')
+                device_id = int.from_bytes(data_mv[20:26], 'little')
 
                 # Attempt to decrypt the packet
                 try:
@@ -302,16 +306,16 @@ class Discover:
                 name_length = decrypted_mv[40]
                 name = decrypted_mv[41:41+name_length].tobytes().decode()
 
-                type = int(name.split('_')[1], 16)
+                device_type = int(name.split('_')[1], 16)
 
             # Return dictionary of device info
-            return {"ip": ip_address, "port": port, "id": id, "name": name, "sn": sn, "type": type}
+            return {"ip": ip_address, "port": port, "device_id": device_id, "name": name, "sn": sn, "type": device_type}
 
     @classmethod
-    def _get_device_class(cls, type: int):
+    def _get_device_class(cls, device_type: int):
         """Get the device class from the device type."""
 
-        if type == DeviceId.AIR_CONDITIONER:
+        if device_type == DeviceType.AIR_CONDITIONER:
             return air_conditioning
 
         # Unknown type return generic device
diff --git a/msmart/lan.py b/msmart/lan.py
index 3bf0076..7bb9d4b 100644
--- a/msmart/lan.py
+++ b/msmart/lan.py
@@ -87,10 +87,10 @@ class _LanProtocol(asyncio.Protocol):
         _LOGGER.debug("Received data from %s: %s", self.peer, data.hex())
         self._queue.put_nowait(data)
 
-    def connection_lost(self, ex):
+    def connection_lost(self, exc) -> None:
         """Log connection lost."""
-        if ex:
-            _LOGGER.error("Connection to %s lost. Error: %s.", self.peer, ex)
+        if exc:
+            _LOGGER.error("Connection to %s lost. Error: %s.", self.peer, exc)
 
     def disconnect(self) -> None:
         """Disconnect from the peer."""
@@ -217,7 +217,7 @@ class _LanProtocolV3(_LanProtocol):
         # Extract header, encrypted payload and hash
         header = packet[:6]
         payload = packet[6:-32]
-        hash = packet[-32:]
+        rx_hash = packet[-32:]
 
         # Decrypt payload
         decrypted_payload = Security.decrypt_aes_cbc(self._local_key, payload)
@@ -225,7 +225,7 @@ class _LanProtocolV3(_LanProtocol):
         # TODO could padding module handle this padding?
 
         # Verify hash
-        if sha256(bytes(header) + decrypted_payload).digest() != hash:
+        if sha256(bytes(header) + decrypted_payload).digest() != rx_hash:
             raise ProtocolError(
                 "Calculated and received SHA256 digest do not match.")
 
@@ -259,15 +259,15 @@ class _LanProtocolV3(_LanProtocol):
                 f"Invalid magic byte: 0x{packet[4]:X}")
 
         # Handle packet based on type
-        type = packet[5] & 0xF
-        if type == self.PacketType.ENCRYPTED_RESPONSE:
+        packet_type = packet[5] & 0xF
+        if packet_type == self.PacketType.ENCRYPTED_RESPONSE:
             return self._decode_encrypted_response(packet)
-        elif type == self.PacketType.HANDSHAKE_RESPONSE:
+        elif packet_type == self.PacketType.HANDSHAKE_RESPONSE:
             return self._decode_handshake_response(packet)
-        elif type == self.PacketType.ERROR:
+        elif packet_type == self.PacketType.ERROR:
             raise ProtocolError("Error packet received.")
         else:
-            raise ProtocolError(f"Unexpected type: {type}")
+            raise ProtocolError(f"Unexpected type: {packet_type}")
 
     async def read(self, timeout: int = 2) -> bytes:
         """Asynchronously read data from the peer via the queue."""
@@ -305,8 +305,8 @@ class _LanProtocolV3(_LanProtocol):
         # Build payload to encrypt
         payload = packet_id.to_bytes(2, "big") + data + get_random_bytes(pad)
 
-        hash = sha256(header + payload).digest()
-        return header + Security.encrypt_aes_cbc(self._local_key, payload) + hash
+        calc_hash = sha256(header + payload).digest()
+        return header + Security.encrypt_aes_cbc(self._local_key, payload) + calc_hash
 
     def _encode_handshake_request(self, packet_id: int, data: bytes):
         """Encode a handshake request packet."""
@@ -320,20 +320,20 @@ class _LanProtocolV3(_LanProtocol):
 
         return header + payload
 
-    def write(self, data: bytes, *, type=PacketType.ENCRYPTED_REQUEST) -> None:
+    def write(self, data: bytes, *, packet_type=PacketType.ENCRYPTED_REQUEST) -> None:
         """Send a packet of the specified type to the peer."""
 
         # Raise an error if attempting to send an encryptd request without authenticating
-        if type == self.PacketType.ENCRYPTED_REQUEST and self._local_key is None:
+        if packet_type == self.PacketType.ENCRYPTED_REQUEST and self._local_key is None:
             raise ProtocolError("Protocol has not been authenticated.")
 
         # Encode the data according to the supplied type
-        if type == self.PacketType.ENCRYPTED_REQUEST:
+        if packet_type == self.PacketType.ENCRYPTED_REQUEST:
             packet = self._encode_encrypted_request(self._packet_id, data)
-        elif type == self.PacketType.HANDSHAKE_REQUEST:
+        elif packet_type == self.PacketType.HANDSHAKE_REQUEST:
             packet = self._encode_handshake_request(self._packet_id, data)
         else:
-            raise TypeError(f"Unknown type: {type}")
+            raise TypeError(f"Unknown type: {packet_type}")
 
         # Write to the peer
         super().write(packet)
@@ -350,12 +350,12 @@ class _LanProtocolV3(_LanProtocol):
 
         # Extract payload and hash
         payload = data[:32]
-        hash = data[32:]
+        rx_hash = data[32:]
 
         # Decrypt the payload with the provided key
         decrypted_payload = Security.decrypt_aes_cbc(key, payload)
 
-        if sha256(decrypted_payload).digest() != hash:
+        if sha256(decrypted_payload).digest() != rx_hash:
             raise AuthenticationError(
                 "Calculated and received SHA256 digest do not match.")
 
@@ -369,11 +369,11 @@ class _LanProtocolV3(_LanProtocol):
             raise AuthenticationError("Token and key must be supplied.")
 
         try:
-            self.write(token, type=self.PacketType.HANDSHAKE_REQUEST)
+            self.write(token, packet_type=self.PacketType.HANDSHAKE_REQUEST)
             response = await self.read()
         except ProtocolError as e:
             # Promote any protocol error to auth error
-            raise AuthenticationError(e)
+            raise AuthenticationError(e) from e
 
         # Generate local key from cloud key
         with memoryview(response) as response_mv:
@@ -404,7 +404,7 @@ class LAN:
         # TODO throws OSError and ???
         loop = asyncio.get_event_loop()
         _transport, protocol = await loop.create_connection(
-            lambda: protocol_class(), self._ip, self._port)
+            lambda: protocol_class(), self._ip, self._port)  # pylint: disable=unnecessary-lambda
 
         if self._protocol_version == 3:
             self._protocol = cast(_LanProtocolV3, protocol)
@@ -448,12 +448,12 @@ class LAN:
             try:
                 await self._protocol.authenticate(token, key)
                 break
-            except (TimeoutError, asyncio.TimeoutError):
+            except (TimeoutError, asyncio.TimeoutError) as e:
                 if retries > 1:
                     _LOGGER.warning("Authentication timeout. Resending.")
                     retries -= 1
                 else:
-                    raise TimeoutError("No response from host.")
+                    raise TimeoutError("No response from host.") from e
 
         # Update stored token and key if successful
         self._token = token
@@ -503,13 +503,13 @@ class LAN:
                 # Await a response
                 responses.append(await self._read())
                 break
-            except (TimeoutError, asyncio.TimeoutError):
+            except (TimeoutError, asyncio.TimeoutError) as e:
                 if retries > 1:
                     _LOGGER.warning("Request timeout. Resending.")
                     retries -= 1
                 else:
                     self._disconnect()
-                    raise TimeoutError("No response from host.")
+                    raise TimeoutError("No response from host.") from e
 
         # Attempt to read any additional responses without blocking
         while True:
@@ -552,9 +552,9 @@ class Security:
         return md5(data + Security.SIGN_KEY).digest()
 
     @classmethod
-    def udpid(cls, id: bytes):
-        with memoryview(sha256(id).digest()) as hash:
-            return strxor(hash[:16], hash[16:])
+    def udpid(cls, device_id: bytes):
+        with memoryview(sha256(device_id).digest()) as mv_hash:
+            return strxor(mv_hash[:16], mv_hash[16:])
 
 
 class _Packet:
@@ -593,7 +593,7 @@ class _Packet:
 
             if packet[:2] != b"\x5a\x5a":
                 # TODO old code handled raw frames? e.g start = 0xAA
-                raise ProtocolError(f"Unsupported packet: %s", packet.hex())
+                raise ProtocolError(f"Unsupported packet: {packet.hex()}")
 
             length = int.from_bytes(packet[4:6], "little")
 
@@ -603,12 +603,12 @@ class _Packet:
 
             packet = packet[:length]
             encrypted_frame = packet[40:-16]
-            hash = packet[-16:]
+            rx_hash = packet[-16:]
 
             # Check that received hash matches
-            if Security.sign(bytes(packet[:-16])) != hash:
+            if Security.sign(bytes(packet[:-16])) != rx_hash:
                 raise ProtocolError(
-                    f"Calculated and received MD5 digest do not match.")
+                    "Calculated and received MD5 digest do not match.")
 
             # Decrypt frame
             return Security.decrypt_aes(encrypted_frame)


Test patch:
diff --git a/msmart/tests/test_cloud.py b/msmart/tests/test_cloud.py
index 248df79..39805ff 100644
--- a/msmart/tests/test_cloud.py
+++ b/msmart/tests/test_cloud.py
@@ -5,6 +5,7 @@ from msmart.const import OPEN_MIDEA_APP_ACCOUNT, OPEN_MIDEA_APP_PASSWORD
 
 
 class TestCloud(unittest.IsolatedAsyncioTestCase):
+    # pylint: disable=protected-access
 
     async def _login(self) -> Cloud:
         client = Cloud(account=OPEN_MIDEA_APP_ACCOUNT,
diff --git a/msmart/tests/test_discover.py b/msmart/tests/test_discover.py
index 97a2778..d7c7a36 100644
--- a/msmart/tests/test_discover.py
+++ b/msmart/tests/test_discover.py
@@ -1,11 +1,12 @@
 import unittest
 
-from msmart.const import DeviceId
+from msmart.const import DeviceType
 from msmart.device import air_conditioning as AC
 from msmart.discover import Discover
 
 
 class TestDiscover(unittest.IsolatedAsyncioTestCase):
+    # pylint: disable=protected-access
 
     async def test_discover_v2(self):
         """Test that we can parse a V2 discovery response."""
@@ -24,8 +25,8 @@ class TestDiscover(unittest.IsolatedAsyncioTestCase):
         self.assertEqual(info["ip"], IP_ADDRESS)
         self.assertEqual(info["port"], 6444)
 
-        self.assertEqual(info["id"], 15393162840672)
-        self.assertEqual(info["type"], DeviceId.AIR_CONDITIONER)
+        self.assertEqual(info["device_id"], 15393162840672)
+        self.assertEqual(info["type"], DeviceType.AIR_CONDITIONER)
 
         self.assertEqual(info["name"], "net_ac_F7B4")
         self.assertEqual(info["sn"], "000000P0000000Q1F0C9D153F7B40000")
@@ -36,7 +37,7 @@ class TestDiscover(unittest.IsolatedAsyncioTestCase):
 
         # Check that device can be built
         device = device_class(**info)
-        self.assertIsNotNone(device_class)
+        self.assertIsNotNone(device)
 
     async def test_discover_v3(self):
         """Test that we can parse a V3 discovery response."""
@@ -55,8 +56,8 @@ class TestDiscover(unittest.IsolatedAsyncioTestCase):
         self.assertEqual(info["ip"], IP_ADDRESS)
         self.assertEqual(info["port"], 6444)
 
-        self.assertEqual(info["id"], 147334558165565)
-        self.assertEqual(info["type"], DeviceId.AIR_CONDITIONER)
+        self.assertEqual(info["device_id"], 147334558165565)
+        self.assertEqual(info["type"], DeviceType.AIR_CONDITIONER)
 
         self.assertEqual(info["name"], "net_ac_63BA")
         self.assertEqual(info["sn"], "000000P0000000Q1B88C29C963BA0000")
diff --git a/msmart/tests/test_lan.py b/msmart/tests/test_lan.py
index c97bf75..bff8ad4 100644
--- a/msmart/tests/test_lan.py
+++ b/msmart/tests/test_lan.py
@@ -4,6 +4,7 @@ from msmart.lan import _LanProtocolV3, _Packet
 
 
 class TestEncodeDecode(unittest.IsolatedAsyncioTestCase):
+    # pylint: disable=protected-access
 
     async def test_enocde_packet_roundtrip(self):
         """Test that we can encode and decode a frame."""