-
Notifications
You must be signed in to change notification settings - Fork 362
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 03d01d3
Showing
13 changed files
with
1,064 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 '' | ||
} | ||
) |
Oops, something went wrong.