miio.protocol module

miIO protocol implementation.

This module contains the implementation of the routines to encrypt and decrypt miIO payloads with a device-specific token.

The payloads to be encrypted (to be passed to a device) are expected to be JSON objects, the same applies for decryption where they are converted automatically to JSON objects. If the decryption fails, raw bytes as returned by the device are returned.

An usage example can be seen in the source of miio.Device.send(). If the decryption fails, raw bytes as returned by the device are returned.

class miio.protocol.EncryptionAdapter(subcon)[source]

Bases: Adapter

Adapter to handle communication encryption.

benchmark(sampledata, filename=None)

Measures performance of your construct (its parsing and building runtime), both for the original instance and the compiled instance. Uses timeit module, over at min 1 loop, and at max over 100 millisecond time.

Optionally, results are saved to a text file for later inspection. Otherwise you can print the resulting string to terminal.

Parameters:
  • sampledata – bytes, a valid blob parsable by this construct

  • filename – optional, string, results are saved to that file

Returns:

string containing measurements

build(obj, **contextkw)

Build an object in memory (a bytes object).

Whenever data cannot be written, ConstructError or its derivative is raised. This method is NOT ALLOWED to raise any other exceptions although (1) user-defined lambdas can raise arbitrary exceptions which are propagated (2) external libraries like numpy can raise arbitrary exceptions which are propagated (3) some list and dict lookups can raise IndexError and KeyError which are propagated.

Context entries are passed only as keyword parameters **contextkw.

Parameters:

**contextkw – context entries, usually empty

Returns:

bytes

Raises:

ConstructError – raised for any reason

build_file(obj, filename, **contextkw)

Build an object into a closed binary file. See build().

build_stream(obj, stream, **contextkw)

Build an object directly into a stream. See build().

compile(filename=None)

Transforms a construct into another construct that does same thing (has same parsing and building semantics) but is much faster when parsing. Already compiled instances just compile into itself.

Optionally, partial source code can be saved to a text file. This is meant only to inspect the generated code, not to import it from external scripts.

Returns:

Compiled instance

export_ksy(schemaname='unnamed_schema', filename=None)
parse(data, **contextkw)

Parse an in-memory buffer (often bytes object). Strings, buffers, memoryviews, and other complete buffers can be parsed with this method.

Whenever data cannot be read, ConstructError or its derivative is raised. This method is NOT ALLOWED to raise any other exceptions although (1) user-defined lambdas can raise arbitrary exceptions which are propagated (2) external libraries like numpy can raise arbitrary exceptions which are propagated (3) some list and dict lookups can raise IndexError and KeyError which are propagated.

Context entries are passed only as keyword parameters **contextkw.

Parameters:

**contextkw – context entries, usually empty

Returns:

some value, usually based on bytes read from the stream but sometimes it is computed from nothing or from the context dictionary, sometimes its non-deterministic

Raises:

ConstructError – raised for any reason

parse_file(filename, **contextkw)

Parse a closed binary file. See parse().

parse_stream(stream, **contextkw)

Parse a stream. Files, pipes, sockets, and other streaming sources of data are handled by this method. See parse().

sizeof(**contextkw)

Calculate the size of this object, optionally using a context.

Some constructs have fixed size (like FormatField), some have variable-size and can determine their size given a context entry (like Bytes(this.otherfield1)), and some cannot determine their size (like VarInt).

Whenever size cannot be determined, SizeofError is raised. This method is NOT ALLOWED to raise any other exception, even if eg. context dictionary is missing a key, or subcon propagates ConstructError-derivative exception.

Context entries are passed only as keyword parameters **contextkw.

Parameters:

**contextkw – context entries, usually empty

Returns:

integer if computable, SizeofError otherwise

Raises:

SizeofError – size could not be determined in actual context, or is impossible to be determined

class miio.protocol.TimeAdapter(subcon)[source]

Bases: Adapter

Adapter for timestamp conversion.

benchmark(sampledata, filename=None)

Measures performance of your construct (its parsing and building runtime), both for the original instance and the compiled instance. Uses timeit module, over at min 1 loop, and at max over 100 millisecond time.

Optionally, results are saved to a text file for later inspection. Otherwise you can print the resulting string to terminal.

Parameters:
  • sampledata – bytes, a valid blob parsable by this construct

  • filename – optional, string, results are saved to that file

Returns:

string containing measurements

build(obj, **contextkw)

Build an object in memory (a bytes object).

Whenever data cannot be written, ConstructError or its derivative is raised. This method is NOT ALLOWED to raise any other exceptions although (1) user-defined lambdas can raise arbitrary exceptions which are propagated (2) external libraries like numpy can raise arbitrary exceptions which are propagated (3) some list and dict lookups can raise IndexError and KeyError which are propagated.

Context entries are passed only as keyword parameters **contextkw.

Parameters:

**contextkw – context entries, usually empty

Returns:

bytes

Raises:

ConstructError – raised for any reason

build_file(obj, filename, **contextkw)

Build an object into a closed binary file. See build().

build_stream(obj, stream, **contextkw)

Build an object directly into a stream. See build().

compile(filename=None)

Transforms a construct into another construct that does same thing (has same parsing and building semantics) but is much faster when parsing. Already compiled instances just compile into itself.

Optionally, partial source code can be saved to a text file. This is meant only to inspect the generated code, not to import it from external scripts.

Returns:

Compiled instance

export_ksy(schemaname='unnamed_schema', filename=None)
parse(data, **contextkw)

Parse an in-memory buffer (often bytes object). Strings, buffers, memoryviews, and other complete buffers can be parsed with this method.

Whenever data cannot be read, ConstructError or its derivative is raised. This method is NOT ALLOWED to raise any other exceptions although (1) user-defined lambdas can raise arbitrary exceptions which are propagated (2) external libraries like numpy can raise arbitrary exceptions which are propagated (3) some list and dict lookups can raise IndexError and KeyError which are propagated.

Context entries are passed only as keyword parameters **contextkw.

Parameters:

**contextkw – context entries, usually empty

Returns:

some value, usually based on bytes read from the stream but sometimes it is computed from nothing or from the context dictionary, sometimes its non-deterministic

Raises:

ConstructError – raised for any reason

parse_file(filename, **contextkw)

Parse a closed binary file. See parse().

parse_stream(stream, **contextkw)

Parse a stream. Files, pipes, sockets, and other streaming sources of data are handled by this method. See parse().

sizeof(**contextkw)

Calculate the size of this object, optionally using a context.

Some constructs have fixed size (like FormatField), some have variable-size and can determine their size given a context entry (like Bytes(this.otherfield1)), and some cannot determine their size (like VarInt).

Whenever size cannot be determined, SizeofError is raised. This method is NOT ALLOWED to raise any other exception, even if eg. context dictionary is missing a key, or subcon propagates ConstructError-derivative exception.

Context entries are passed only as keyword parameters **contextkw.

Parameters:

**contextkw – context entries, usually empty

Returns:

integer if computable, SizeofError otherwise

Raises:

SizeofError – size could not be determined in actual context, or is impossible to be determined

class miio.protocol.Utils[source]

Bases: object

This class is adapted from the original xpn.py code by gst666.

static checksum_field_bytes(ctx: Dict[str, Any]) bytearray[source]

Gather bytes for checksum calculation.

static decrypt(ciphertext: bytes, token: bytes) bytes[source]

Decrypt ciphertext with a given token.

Parameters:
  • ciphertext (bytes) – Ciphertext to decrypt

  • token (bytes) – Token to use

Returns:

Decrypted bytes object

static encrypt(plaintext: bytes, token: bytes) bytes[source]

Encrypt plaintext with a given token.

Parameters:
  • plaintext (bytes) – Plaintext (json) to encrypt

  • token (bytes) – Token to use

Returns:

Encrypted bytes

static get_length(x) int[source]

Return total packet length.

static is_hello(x) bool[source]

Return if packet is a hello packet.

static key_iv(token: bytes) Tuple[bytes, bytes][source]

Generate an IV used for encryption based on given token.

static md5(data: bytes) bytes[source]

Calculates a md5 hashsum for the given bytes object.

static verify_token(token: bytes)[source]

Checks if the given token is of correct type and length.