Xiaomi Smart Home Gateway Network Radio

Hello there,

i’m sharing my custom component that adds the Xiaomi Smart Home Gateway as a media player for the Network Radio.

it supports play/stop, volume control and next radio in favorites
(same behaviour as miHome app)

hope is useful for anyone

5 Likes

Hi, thank you for this component.
But after upgrade HASS to 0.88 it stopped working.

I agree. After the upgrade, it stopped working.

Hi,

This is my modification, and works well:

""" https://github.com/h4v1nfun/xiaomi_miio_gateway/blob/master/custom_components/media_player/xiaomi_miio_gateway.py """
"""
Add support for the Xiaomi Gateway Radio.
"""

import logging
import voluptuous as vol
import asyncio
from functools import partial

import homeassistant.helpers.config_validation as cv
from homeassistant.components.media_player import (
    MediaPlayerDevice, MEDIA_PLAYER_SCHEMA, PLATFORM_SCHEMA)
from homeassistant.components.media_player.const import (
    SUPPORT_TURN_ON, SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE,
    SUPPORT_VOLUME_STEP, SUPPORT_VOLUME_SET, SUPPORT_NEXT_TRACK)
from homeassistant.const import (CONF_HOST, CONF_NAME, CONF_TOKEN, STATE_OFF, STATE_ON)

REQUIREMENTS = ['python-miio>=0.3.7']

ATTR_MODEL = 'model'
ATTR_FIRMWARE_VERSION = 'firmware_version'
ATTR_HARDWARE_VERSION = 'hardware_version'

DEFAULT_NAME = "Xiaomi Gateway Radio"
DATA_KEY = 'media_player.xiaomi_miio_gateway'

ATTR_STATE_PROPERTY = 'state_property'
ATTR_STATE_VALUE = 'state_value'

_LOGGER = logging.getLogger(__name__)

SUPPORT_XIAOMI_GATEWAY_FM = SUPPORT_VOLUME_STEP | SUPPORT_TURN_ON | \
                    SUPPORT_TURN_OFF | SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | SUPPORT_NEXT_TRACK

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_HOST): cv.string,
    vol.Required(CONF_TOKEN): vol.All(cv.string, vol.Length(min=32, max=32)),
    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
})

@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
    """Set up the Xiaomi Gateway miio platform."""
    from miio import Device, DeviceException
    if DATA_KEY not in hass.data:
        hass.data[DATA_KEY] = {}

    host = config.get(CONF_HOST)
    token = config.get(CONF_TOKEN)

    _LOGGER.info("Initializing Xiaomi Gateway with host %s (token %s...)", host, token[:5])

    try:
        miio_device = Device(host, token)
        device_info = miio_device.info()
        model = device_info.model
        _LOGGER.info("%s %s %s detected",
                     model,
                     device_info.firmware_version,
                     device_info.hardware_version)

        device = XiaomiGateway(miio_device, config, device_info)
    except DeviceException:
        raise PlatformNotReady

    hass.data[DATA_KEY][host] = device
    async_add_devices([device], update_before_add=True)

class XiaomiGateway(MediaPlayerDevice):
    """Represent the Xiaomi Gateway for Home Assistant."""

    def __init__(self, device, config, device_info):
        """Initialize the entity."""
        self._device = device

        self._name = config.get(CONF_NAME)
        self._skip_update = False

        self._model = device_info.model
        self._unique_id = "{}-{}-{}".format(device_info.model,
                                            device_info.mac_address,
                                            'pause')
        self._icon = 'mdi:radio'
        self._muted = False
        self._volume = 0
        self._available = None
        self._state = None
        self._state_attrs = {
            ATTR_MODEL: self._model,
            ATTR_FIRMWARE_VERSION: device_info.firmware_version,
            ATTR_HARDWARE_VERSION: device_info.hardware_version,
            ATTR_STATE_PROPERTY: 'pause'
        }

    async def _try_command(self, mask_error, func, *args, **kwargs):
        """Call a device command handling error messages."""
        from miio import DeviceException
        try:
            result = await self.hass.async_add_job(
                partial(func, *args, **kwargs))

            _LOGGER.info("Response received from Gateway: %s", result)

            return result[0] == "ok"
        except DeviceException as exc:
            _LOGGER.error(mask_error, exc)
            return False

    @property
    def name(self):
        """Return the display name of this Gateway."""
        return self._name

    @property
    def state(self):
        """Return _state variable, containing the appropriate constant."""
        return self._state

    @property
    def assumed_state(self):
        """Indicate that state is assumed."""
        return True

    @property
    def is_volume_muted(self):
        """Boolean if volume is currently muted."""
        return self._muted

    @property
    def volume_level(self):
        """Volume level of the media player (0..1)."""
        return self._volume

    @property
    def supported_features(self):
        """Flag media player features that are supported."""
        return SUPPORT_XIAOMI_GATEWAY_FM

    async def turn_off(self):
        result = await self._try_command(
            "Turning the Gateway off failed.", self._device.send,
            'play_fm', ['off'])

    async def turn_on(self):
        """Wake the Gateway back up from sleep."""
        result = await self._try_command(
            "Turning the Gateway on failed.", self._device.send,
            'play_fm', ['on'])

    async def volume_up(self):
        """Increase volume by one."""
        volume = round(self._volume * 100) + 1
        result = await self._try_command(
            "Turning the Gateway volume failed.", self._device.send,
            'set_fm_volume', [volume])

    async def media_next_track(self):
        """Send next track command."""
        result = await self._try_command(
            "Turning the Gateway volume failed.", self._device.send,
            'play_fm', ['next'])

    async def volume_down(self):
        """Decrease volume by one."""
        volume = round(self._volume * 100) - 1
        result = await self._try_command(
            "Turning the Gateway volume failed.", self._device.send,
            'set_fm_volume', [volume])

    async def set_volume_level(self, volume):
        volset = round(volume * 100)
        result = await self._try_command(
            "Setting the Gateway volume failed.", self._device.send,
            'set_fm_volume', [volset])

    async def mute_volume(self, mute):
        """Send mute command."""
        volume = 10
        if self._muted == False:
            volume = 0

        result = await self._try_command(
            "Turning the Gateway volume failed.", self._device.send,
            'set_fm_volume', [volume])
        if result:
            if volume == 0:
                self._muted = True
            else:
                self._muted = False

    async def async_update(self):
        """Fetch state from Gateway."""
        from miio import DeviceException

        try:
            state = await self.hass.async_add_job(
                self._device.send, 'get_prop_fm', '')
            _LOGGER.info("Got new state: %s", state)
            volume = state.pop('current_volume')
            state = state.pop('current_status')

            _LOGGER.debug("Got new state: %s", state)

            self._available = True
            if volume == 0:
                self._muted = True
            else:
                self._muted = False

            if state == 'pause':
                self._state = STATE_OFF
            elif state == 'run':
                self._state = STATE_ON
                self._volume = volume / 100
            else:
                _LOGGER.warning(
                    "New state (%s) doesn't match expected values: %s/%s",
                    state, 'pause', 'run')
                self._state = None

            self._state_attrs.update({
                ATTR_STATE_VALUE: state
            })

        except DeviceException as ex:
            self._available = False
            _LOGGER.error("Got exception while fetching the state: %s", ex)

Regards

1 Like

in 0.97 custom component is broken. home assistant says no integration found. Can someone help me?

in 0.98.5 custom component is broken. home assistant says no integration found :frowning:

Add the file __init__.py to the root of the plugin folder

Hello I have the same problem.
I am under 0.108.4. Can you tell me which files to put in the folder of the custom component directory as well as their content. I still get the “no integration found” error. Can you also give me back the code to put in configuration.yaml.
thank you in advance

Is this still working?

I use this to get the FM Radio to work since h4v1nfun doesn’t seem to be active on the project https://github.com/igzero/xiaomigateway <-- Works great

Can someone tell me is this network radio working ?
tried h41nfun method , then igzero and can’t make ir working.
Anybody have some directions ?
My HA version - Home Assistant 2021.3.4

This fork - GitHub - Burninf/xiaomi_miio_gateway: Home Assistant Xiaomi Gateway Radio of initial @h4v1nfun project is working for me including controls on HA 2021.5.0

.would like to spin up my own server to get the radio working don’t wanna depend on a Russian side anyway Russian servers are blocked in my router