ysard / mi_remote_database

Proof of concept aiming to reproduce and query the infrared code database (IRDB) used by the Xiaomi *Mi Remote* application.
GNU Affero General Public License v3.0
52 stars 8 forks source link

GitHub release (latest SemVer) python docstring coverage python test coverage

You will find on this repository a proof of concept aiming to reproduce and query the infrared code database used by the Xiaomi Mi Remote application.

The codes are decrypted and can be converted into a number of formats.

This will hopefully allow the creation or improvement of free and gratis alternatives (and not just gratis with behavioral tracking).

You will find a write-up about this project on the following site: reversing Xiaomi Mi Remote (in French)

Full database and TVKILL exports are available in the assets of the GitHub release page.

Data overview

Data from the DB could be localized (not really studied at the moment); however, codes are currently queried for France and by extension for Europe (I guess...).

Please note that the following numbers are for power codes (ON/OFF codes) only (python -m src db_export -f flipper -k power power_r -d xxx). The number of patterns for other commands is much more important (see below).

TV codes:
Nb brands: 1060
Nb models: 2848
Nb unique patterns: 1346

Set-top box:
Nb brands: 43
Nb models: 172
Nb unique patterns: 134

Air conditioners:
Nb brands: 280
Nb models: 1828
Nb unique patterns: ??
(much more in fact, but patterns are crypted and not reversed for now)

DVD players:
Nb brands: 247
Nb models: 839
Nb unique patterns: 775

Fans:
Nb brands: 133
Nb models: 422
Nb unique patterns: 191

Audio/video:
Nb brands: 202
Nb models: 455
Nb unique patterns: 446

Projectors:
Nb brands: 118
Nb models: 370
Nb unique patterns: 274

Cable _ Satellite box
Nb brands: 2
Nb models: 13
Unique patterns: 14

Internet Box:
Nb brands: 136
Nb models: 221
Nb unique patterns: 140

Camera:
Nb brands: 12
Nb models: 18
Nb unique patterns: 4

Stats for all key codes (python -m src db_export -f flipper -d xxx):

TV codes:
Nb brands: 1060
Nb models: 2848
Unique patterns: 46228

Set-top box:
Nb brands: 43
Nb models: 172
Unique patterns: 3134

Air conditioners:
Nb brands: 280
Nb models: 1828
Unique patterns: 507

DVD players:
Nb brands: 247
Nb models: 839
Unique patterns: 25954

Fans:
Nb brands: 133
Nb models: 422
Unique patterns: 1435

Audio/video:
Nb brands: 202
Nb models: 455
Unique patterns: 8615

Projectors:
Nb brands: 118
Nb models: 370
Unique patterns: 5518

Cable _ Satellite box
Nb brands: 2
Nb models: 13
Unique patterns: 548

Internet Box:
Nb brands: 136
Nb models: 221
Unique patterns: 4031

Camera:
Nb brands: 12
Nb models: 18
Unique patterns: 113

Installation

The project is written for Python 3.6+:

$ pip install -r requirements.txt

Usage

Get some help:

$ python -m src --help

TV Kill Android app

Export IR codes for one device type to the format of TVKILL Android app. The number 1 in the command is the internal device id in the database (see above).

$ python -m src db_export -d 1 -f tvkill

A JSON file (Xiaomi_TV.json) will be exported with the following structure as example:

[
    {
        "designation": "Xiaomi Projector",
        "patterns": [
        {
            "comment": "kk 111_6667",
            "frequency": 37960,
            "pattern": [
                341,171,20,22,20,...
            ]
        }
    }
]

Flipper Zero

Export is also available for Flipper Zero. The number 1 in the command is the internal device id in the database (see above).

$ python -m src db_export -d 1 -f flipper

ir files will be exported with the following structure:

Filetype: IR signals file
Version: 1
# Comments
#
name: down
type: raw
frequency: 38000
duty_cycle: 0.330000
data: ...

Developers

Functions are fully documented in the source code according to Python documentation standards; moreover, some examples are available in unit tests.

Data structure

.
├── database_dump
│   ├── 10_Projector.json # "Device" file: List of brands for this type of device (HP, Epson, Philips, etc.)
│   ├── 10_Projector      # "Brands" directory: 1 file per brand
│   │   ├── 3M_1.json     # "Brand" file: each file contains multiple models references with (most of the time) their *power* code
│   │   ├── ...
│   │   ├── models        # "Models" directory: 1 file per model
│   │   │   ├── 1_8582.json # "Model" file: Definitions of all IR codes known for one model
│   │   │   ├── ...

Online API description & flowchart


    flowchart TD
        A[Get devices] --> |/controller/device/1| B{Is Set-top box device?}
        B --> |No| C[Get all brands] --> |/controller/brand/list/1| D[Get brand]
        B --> |Yes| E[Get all set-topbox brands] --> |/controller/stb/lineup/match/1| D
        D --> |/controller/match/tree/1| G[Get models]
        G --> |/controller/code/1| H[done]

Pattern object

Pattern is a wrapper for IR pulses format.

One pulse is the number of cycles of the carrier for which to turn the emitter light ON or OFF. Pulses are used for IR transmission based on PWM (Pulses Width Modulation) where the carrier frequency acts as a clock.

Timmings are expressed in microseconds (us or µs), Burst/pulse values are expressed in number of cycles of the carrier for which to turn the light on and off.

Supported formats:

Conversion methods available (See in-code documentation):

to_pronto
from_pronto
from_pulses
to_raw
to_signed_raw
to_pulses

Examples:

>>> pronto = "0000 0071 0000 0002 0000 00AA 0000 0040 0000 0040 0000 0015"
>>> pattern = Pattern(pronto, None, code_type="pronto")

>>> ir_code = [9042,4484,579,552,580,567,579,567,544,554]
>>> pattern = Pattern(ir_code, 37990, code_type="raw")

Python sets can be made to ensure the uniqueness of Pattern objects.

Cast crypted IR code from database to raw timmings (µs)

>>> mi = "QJPmll3+SCgpSE73bTO9hni9upbSpKrS73cugR4FZSMT2VGtMTkEIsegm1kjFy3bCLQJsJZKAXxjDF7hGaYIolNzR+qo5f2H3C/PqsSK2Q8kaQaJAycytxhqhVgnwnOUZ6gj0xXscdkPK3MBzr6HH5yEOGDtocCXKP8qEXZdvctnCmFZaZwubXf1Cscf/rlVkAz53JacxfUkCiDqw8M27g=="
>>> ir_code = process_xiaomi_shit(mi)

Load codes from a directory

>>> codes = load_device_codes("./database_dump/1_TV/")

Some brands have an additional section named "others" in the JSON response. Currently this section is used to retrieve codes. This influences the number of codes collected.

For exemple, for TV codes:

Without others section:
Nb brands: 1060
Nb models: 2302
Nb Patterns: 2625

With others section:
Nb brands: 1060
Nb models: 2634
Nb Patterns: 2998
Nb unique patterns: 1290
1236 unique IR codes (without frequency param)

Contributing

Feedback in issues is important and pull-requests are welcome, but time could be missing to implement large functionality requests ;)

Thanks

@LionZXY (Help with Flipper Zero support #3). @Biswa96 (Bug fixes).