Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexxIT committed Aug 30, 2020
0 parents commit 03d01d3
Show file tree
Hide file tree
Showing 13 changed files with 1,064 additions and 0 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Xiaomi Gateway 3 integration for Home Assistant

[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs)
[![Donate](https://img.shields.io/badge/donate-Coffee-yellow.svg)](https://www.buymeacoffee.com/AlexxIT)
[![Donate](https://img.shields.io/badge/donate-Yandex-red.svg)](https://money.yandex.ru/to/41001428278477)

Control Zigbee devices from Home Assistant with **Xiaomi Gateway 3 (ZNDMWG03LM)** on original firmware.

Gateway support **Zigbee 3**, **Bluetooth Mesh** and **HomeKit**.

This method does not change the device firmware. Gateway continues to work with Mi Home and HomeKit.

Thanks to **Serrj** for [instruction how to enable Telnet](https://community.home-assistant.io/t/xiaomi-mijia-smart-multi-mode-gateway-zndmwg03lm-support/159586/61) on this device.

# Supported Devices

Currently supported and tested several Xiaomi and Aqara Zibee devices officially supported by the Gateway:

> Aqara Cube, Aqara Double Wall Button, Aqara Motion Sensor, Aqara Opple Six Button, Aqara Relay, Aqara Vibration Sensor, Aqara Water Leak Sensor, IKEA Bulb E14, Xiaomi Button, Xiaomi Plug, Xiaomi TH Sensor
Plans to support officially supported Bluetooth devices.

Plans to support for Zigbee devices from other manufacturers. May be support for [ZHA](https://www.home-assistant.io/integrations/zha/).

# Install

You can install component with HACS custom repo ([example](https://github.com/AlexxIT/SonoffLAN#install-with-hacs)): `AlexxIT/XiaomiGateway3`.

Or manually copy `xiaomi_gateway3` folder from latest release to `custom_components` folder in your config folder.

# Config

With GUI. Configuration > Integration > Xiaomi Gateway 3. And enter Gateway **IP address** and **Mi Home token**.

You need [obtain Mi Home token](https://github.com/Maxmudjon/com.xiaomi-miio/blob/master/docs/obtain_token.md). I am using the [method with Mi Home v5.4.54](https://github.com/Maxmudjon/com.xiaomi-miio/blob/master/docs/obtain_token.md#non-rooted-android-phones) for non-rooted Android. If you don't have an Android - you can install the [emulator on Windows](https://www.bignox.com/).

# How it works

The component enables **Telnet** on Gateway via [Miio protocol](https://github.com/rytilahti/python-miio). Only this Gateway supports this command. Do not try to execute it on other Xiaomi/Aqara Gateways.

The component starts the **MQTT Server** on the public port of the Gateway. All the logic in the Gateway runs on top of the built-in MQTT Server. By default, access to it is closed from the outside.

**ATTENTION:** Telnet and MQTT work without a password! Do not use this method on public networks.

After rebooting the device, all changes will be reset. The component will launch Telnet and public MQTT every time it detects that they are disabled.
93 changes: 93 additions & 0 deletions custom_components/xiaomi_gateway3/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import logging

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE
from homeassistant.helpers.entity import Entity

from . import utils
from .gateway3 import Gateway3

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'xiaomi_gateway3'


async def async_setup(hass: HomeAssistant, hass_config: dict):
hass.data[DOMAIN] = {}

if DOMAIN in hass_config and 'log' in hass_config[DOMAIN]:
Gateway3.log = hass.config.path(hass_config[DOMAIN]['log'])

return True


async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
hass.data[DOMAIN][config_entry.unique_id] = \
gw = Gateway3(**config_entry.data)

# init setup for each supported domains
for domain in ('binary_sensor', 'light', 'remote', 'sensor', 'switch'):
hass.async_create_task(hass.config_entries.async_forward_entry_setup(
config_entry, domain))

gw.start()

return True


class Gateway3Device(Entity):
_state = STATE_UNKNOWN

def __init__(self, gateway: Gateway3, device: dict, attr: str):
self.gw = gateway
self.device = device

self._attr = attr

self._unique_id = f"{self.device['mac']}_{self._attr}"
self._name = self.device['device_name'] + ' ' + self._attr.title()

self.entity_id = '.' + self._unique_id

gateway.add_update(device['did'], self.update)

async def async_added_to_hass(self):
if 'init' in self.device:
self.update(self.device['init'])

@property
def should_poll(self) -> bool:
return False

@property
def unique_id(self):
return self._unique_id

@property
def name(self):
return self._name

@property
def device_info(self):
if self.device['did'] == 'lumi.0':
return {
'identifiers': {(DOMAIN, self.device['mac'])},
'manufacturer': self.device['device_manufacturer'],
'model': self.device['device_model'],
'name': self.device['device_name']
}
else:
return {
'connections': {(CONNECTION_ZIGBEE, self.device['mac'])},
'identifiers': {(DOMAIN, self.device['mac'])},
'manufacturer': self.device['device_manufacturer'],
'model': self.device['device_model'],
'name': self.device['device_name'],
# 'sw_version': None,
'via_device': (DOMAIN, self.gw.device['mac'])
}

def update(self, data: dict):
pass
32 changes: 32 additions & 0 deletions custom_components/xiaomi_gateway3/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import logging

from homeassistant.components.binary_sensor import BinarySensorEntity

from . import DOMAIN, Gateway3Device
from .gateway3 import Gateway3

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass, config_entry, async_add_entities):
def setup(gateway: Gateway3, device: dict, attr: str):
async_add_entities([Gateway3BinarySensor(gateway, device, attr)])

gw: Gateway3 = hass.data[DOMAIN][config_entry.unique_id]
gw.add_setup('binary_sensor', setup)


class Gateway3BinarySensor(Gateway3Device, BinarySensorEntity):
@property
def is_on(self):
return self._state is True

@property
def device_class(self):
return self._attr

def update(self, data: dict = None):
if self._attr not in data:
return
self._state = data[self._attr] == 1
self.schedule_update_ha_state()
31 changes: 31 additions & 0 deletions custom_components/xiaomi_gateway3/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import logging

import voluptuous as vol
from homeassistant.config_entries import ConfigFlow

from . import DOMAIN, gateway3

_LOGGER = logging.getLogger(__name__)


class XiaomiGateway3FlowHandler(ConfigFlow, domain=DOMAIN):
async def async_step_user(self, user_input=None):
"""GUI > Configuration > Integrations > Plus > Xiaomi Gateway 3"""
error = None

if user_input is not None:
error = gateway3.is_gw3(user_input['host'], user_input['token'])
if not error:
return self.async_create_entry(title=user_input['host'],
data=user_input)

return self.async_show_form(
step_id='user',
data_schema=vol.Schema({
vol.Required('host'): str,
vol.Required('token'): str,
}),
description_placeholders={
'error_text': "\nERROR: " + error if error else ''
}
)
Loading

0 comments on commit 03d01d3

Please sign in to comment.