Turn the Xiaomi smart home gateway into a column

  • Tutorial
Hi, Habra Giktayms-reader! Today I will teach you how to get useful out of useless functionality. We will receive by the example of a smart home from the notorious Xiaomi company and its product in the form of a ZigBee gateway.

Owners of Xiaomi smart home components know that most of them are divided into those who can communicate via zigbee or bluetooth. We will be interested in the gateway for zigbee devices version 2, because it was there that the radio functionality appeared, which by default can only play Chinese Internet radio stations.


Of course, there is a project on the Internet with the help of which you can not tricky add various other radio stations, but we will go the other way and will make a wireless speaker from the gateway.

What do you need?


For the successful implementation of the operation you need:

  • Actually, the ZigBee gateway version is at least 2 (a radio appeared in it)
  • Any web server
  • A smartphone on which there is a root and installed MiHome software from the selected country China Mainland

What do we do?


In order to make a wireless speaker out of our gateway, you need to pretend to be an Internet radio stream and train the gateway that you need to knock on the list of stations to us, and not to the Chinese API.

In order to understand how the application on the phone communicates with Chinese servers, you can sniff traffic, but I will save you from this hemorrhoids :) If you want to expand your horizons, you can do this optionally.

So, we will be interested in three requests and, accordingly, the answer to the Chinese API, which lives at api.ximalaya.com:

  • / openapi-gateway-app / live / radios
  • / openapi-gateway-app / live / get_radios_by_ids
  • / openapi-gateway-app / search / radios

The word openapi in the way hints at something open, but I did not find a public specification. The request comes with parameters that are not needed for our purposes, so we discard them.

I used nginx as a web server, here is the config:

server {
    listen      *:80;
    server_name api.io.mi.com ximalaya.com www.ximalaya.com api.ximalaya.com mobile.ximalaya.com open.ximalaya.com ximiraga.ru www.ximiraga.ru;
    root        /opt/xiaomiradio/www;
    index       index.php index.html index.htm;
    access_log  /var/log/nginx/radio_access.log;
    error_log   /var/log/nginx/radio_error.log;

    location @ximalaya {
      proxy_pass http://api.ximalaya.com;
    }
}

Create the same hierarchy at the root of your web server. Additionally, create the radio and hls folders in the root of the web server. All calls on these paths should output the same JSON, so it makes sense to make them links to a file, which we will call stations.json.
Here is its contents:

{
  "total_page":1,
  "total_count":1,
  "current_page":0,
  "radios":[
    {
      "id":527782023,
      "kind":"radio",
      "program_name":"AirSound1",
      "radio_name":"AirSound1",
      "radio_desc":"",
      "schedule_id":0,
      "support_bitrates":[
        64
      ],
      "rate24_aac_url":"",
      "rate64_aac_url":"http://<ваш адрес в локальной сети>/hls/live1.m3u8",
      "rate24_ts_url":"",
      "rate64_ts_url":"",
      "radio_play_count":1,
      "cover_url_small":"http://<ваш адрес в локальной сети>/radio/527782023/cover_small.png",
      "cover_url_large":"http://<ваш адрес в локальной сети>/radio/527782023/cover_big.png",
      "updated_at":0,
      "created_at":0
    }
  ]
}

As you can see, everything is simple here - we give away an array of radio indicating where to look for the stream. If you have several gateways - you can make several channels. An important note - the address indicated here must be accessible from the gateway!

In order for the application to see your changes, you need to edit the hosts on your smartphone and write api.ximalaya.com there to match the address of your web server.

Now about how to get the stream. I decided to output everything from my sound card from the PC on which the web server is deployed. For this we will use ffmpeg:

#!/bin/bash

ffmpeg -f alsa -i hw:Loopback,1,0 -c:a libfdk_aac -b:a 64k -f ssegment -segment_list /opt/xiaomiradio/hls/live1.m3u8 -segment_list_flags +live -segment_time 1 -segment_list_size 1 -segment_wrap 5 -segment_list_entry_prefix http://<ваш адрес в локальной сети>/hls/ /opt/xiaomiradio/hls/64%03d.aac

Pay attention to the paths and address of the web server - substitute yours.

In principle, this is all for successful work - run the ffmpeg script, it will start creating segments with sound from your sound card, launch the application on the phone and select your station - after a second or two, sound from the PC should go.