-
-
Notifications
You must be signed in to change notification settings - Fork 15
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
Dmitry Mamontov
committed
Mar 10, 2021
0 parents
commit e32b3fd
Showing
19 changed files
with
1,900 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,129 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
pip-wheel-metadata/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
db.sqlite3-journal | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# IPython | ||
profile_default/ | ||
ipython_config.py | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# pipenv | ||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
# install all needed dependencies. | ||
#Pipfile.lock | ||
|
||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow | ||
__pypackages__/ | ||
|
||
# Celery stuff | ||
celerybeat-schedule | ||
celerybeat.pid | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
# Pyre type checker | ||
.pyre/ |
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,101 @@ | ||
# MiWiFi for Home Assistant | ||
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs) | ||
[![donate paypal](https://img.shields.io/badge/Donate-PayPal-blue.svg)](https://paypal.me/dslonyara) | ||
[![donate tinkoff](https://img.shields.io/badge/Donate-Tinkoff-yellow.svg)](https://www.tinkoff.ru/sl/3FteV5DtBOV) | ||
|
||
Component for tracking devices and managing routers based on [MiWiFi](http://miwifi.com/) from [Home Assistant](https://www.home-assistant.io/). | ||
|
||
## Table of Contents | ||
- [FAQ](#faq) | ||
- [Install](#install) | ||
- [Config](#config) | ||
- [Advanced config](#advanced-config) | ||
- [Services](#services) | ||
- [Performance table](#performance-table) | ||
- [Routers tested](#routers-tested) | ||
|
||
## FAQ | ||
**Q. Do I need to get telnet or ssh?** | ||
|
||
A. Not. integration works through Luci-API | ||
|
||
**Q. How often are states updated?** | ||
|
||
A. Once every 10 seconds. This is the most optimal time for correct work. | ||
|
||
**Q. In addition to tracking devices, what else does the integration allow you to do?** | ||
|
||
A. The integration creates sensors to track the number of connected devices through different types of connections (`5 Ghz`, `2.4 Ghz`, `lan`). Creates binary sensors that track (`repeater mode`, `wifi state`, `wan state`). Creates switches to control `LEDs` and `reboot` the router. It also collects statistics on connected devices (Signal, Uptime, etc.) | ||
|
||
**Q. Does the integration support legacy device tracking via `known_devices.yaml`?** | ||
|
||
A. This is a legacy device tracking option. But the integration allows importing names, dev_id, icon from the file `known_devices.yaml` and associating with new devices by mac-address. To do this, simply create or rename the file to `legacy_known_devices.yaml` | ||
|
||
**Q. Does the integration support routers connected in `repeater mode`?** | ||
|
||
A. Yes, the integration supports devices connected in `repeater mode`. But to get the number of devices and their tracking, you will also need to connect and configure the parent router. | ||
|
||
## Install | ||
Installed through the custom repository [HACS](https://hacs.xyz/) - `dmamontov/hass-miwifi` | ||
|
||
Or by copying the `miwifi` folder from [the latest release](https://github.com/dmamontov/hass-miwifi/releases/latest) to the custom_components folder (create if necessary) of the configs directory. | ||
|
||
## Config | ||
**Via GUI (Recommended)** | ||
`Settings` > `Integrations` > `Plus` > `MiWiFi` | ||
|
||
For authorization, use the ip of your router and its password | ||
|
||
**Via YAML (legacy way)** | ||
```yaml | ||
miwifi: | ||
ip_address: router_ip | ||
password: router_pass | ||
``` | ||
## Advanced config | ||
#### Automatically remove devices | ||
The component supports automatic deletion of monitored devices after a specified number of days (Default: 30 days) after the last activity. If you specify 0, then automatic deletion will be disabled. | ||
**Via GUI (Recommended)** | ||
`Settings` > `Integrations` > `Your integration MiWiFi` > `Settings` | ||
|
||
**Via YAML (legacy way)** | ||
```yaml | ||
miwifi: | ||
... | ||
last_activity_days: 30 | ||
``` | ||
|
||
## Services | ||
#### Remove devices | ||
The component contains a service that allows you to delete a device by device_id or entity_id | ||
|
||
**Via GUI (Recommended)** | ||
`Developer-tools` > `Service` > `miwifi.remove_devices` | ||
|
||
**Via YAML (legacy way)** | ||
```yaml | ||
service: miwifi.remove_devices | ||
target: | ||
device_id: | ||
- ... | ||
entity_id: | ||
- device_tracker.... | ||
``` | ||
|
||
## Performance table | ||
![](table.png) | ||
|
||
1. Install [Auto-entities](https://github.com/thomasloven/lovelace-auto-entities) from HACS | ||
2. Install [Flex Table](https://github.com/custom-cards/flex-table-card) from HACS | ||
3. Add new Lovelace tab with **Panel Mode** | ||
4. Add new Lovelace card: [example](https://gist.github.com/dmamontov/e6fa1842c486388387aaf061d3a82818) | ||
|
||
## Routers tested | ||
| Router | Firmware version | Region | Status | | ||
| --------------------------------------------------------------------------------- | ---------------- | ------ | --------- | | ||
| [Xiaomi AC2100](https://xiaomiplanets.com/review-xiaomi-ac2100-router/) | 2.0.743 | CN | Supported | | ||
| [Xiaomi AX3600](https://xiaomiplanets.com/xiaomi-aiot-router-ax3600-performance/) | 1.0.79 | CN | Supported | | ||
|
||
Many more Xiaomi and Redmi routers supported by MiWiFi (OpenWRT - Luci API) |
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,119 @@ | ||
import logging | ||
import voluptuous as vol | ||
import homeassistant.helpers.config_validation as cv | ||
import homeassistant.helpers.device_registry as dr | ||
import homeassistant.helpers.entity_registry as er | ||
|
||
from homeassistant.core import HomeAssistant, ServiceCall | ||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry | ||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, EVENT_HOMEASSISTANT_STOP | ||
from homeassistant.helpers.json import JSONEncoder | ||
from homeassistant.helpers.storage import Store | ||
|
||
from .core.const import DOMAIN, CONF_LAST_ACTIVITY_DAYS, DEFAULT_LAST_ACTIVITY_DAYS, STORAGE_VERSION | ||
from .core.luci_data import LuciData | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
CONFIG_SCHEMA = vol.Schema({ | ||
DOMAIN: vol.All( | ||
cv.ensure_list, | ||
[ | ||
vol.Schema({ | ||
vol.Required(CONF_IP_ADDRESS): cv.string, | ||
vol.Required(CONF_PASSWORD): cv.string, | ||
vol.Optional(CONF_LAST_ACTIVITY_DAYS, default = DEFAULT_LAST_ACTIVITY_DAYS): cv.positive_int | ||
}) | ||
] | ||
) | ||
}, extra = vol.ALLOW_EXTRA) | ||
|
||
async def async_setup(hass: HomeAssistant, config: dict) -> bool: | ||
success = True | ||
|
||
if DOMAIN not in config: | ||
return success | ||
|
||
for router in config[DOMAIN]: | ||
hass.data[DOMAIN][router[CONF_IP_ADDRESS]] = router | ||
|
||
hass.async_create_task(hass.config_entries.flow.async_init( | ||
DOMAIN, context = {'source': SOURCE_IMPORT}, data = router | ||
)) | ||
|
||
return success | ||
|
||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: | ||
if config_entry.data: | ||
hass.config_entries.async_update_entry(config_entry, data = {} , options = config_entry.data) | ||
|
||
store = Store(hass, STORAGE_VERSION, "{}.{}".format(DOMAIN, config_entry.entry_id), encoder = JSONEncoder) | ||
|
||
devices = await store.async_load() | ||
if devices is None: | ||
devices = {} | ||
|
||
client = LuciData(hass, config_entry, store, devices) | ||
|
||
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = client | ||
|
||
async def async_close(event): | ||
await client.save_to_store() | ||
await client.api.logout() | ||
|
||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_close) | ||
|
||
await _init_services(hass) | ||
|
||
if not await client.async_setup(): | ||
return False | ||
|
||
return True | ||
|
||
async def _init_services(hass: HomeAssistant): | ||
async def remove_devices(call: ServiceCall): | ||
data = dict(call.data) | ||
|
||
entity_to_mac = {} | ||
|
||
devices = data.pop('device_id', []) | ||
entities = data.pop('entity_id', None) | ||
|
||
if entities: | ||
entity_registry = await er.async_get_registry(hass) | ||
|
||
for entity_id in entities: | ||
entity = entity_registry.async_get(entity_id) | ||
if not entity: | ||
continue | ||
|
||
devices.append(entity.device_id) | ||
|
||
if devices: | ||
device_registry = await dr.async_get_registry(hass) | ||
|
||
for device in devices: | ||
device_entry = device_registry.async_get(device) | ||
if not device_entry: | ||
continue | ||
|
||
device_registry.async_remove_device(device) | ||
|
||
for entry in device_entry.config_entries: | ||
if entry not in entity_to_mac: | ||
entity_to_mac[entry] = [] | ||
|
||
for domain, mac in device_entry.identifiers: | ||
entity_to_mac[entry].append(mac) | ||
|
||
if not entity_to_mac: | ||
return | ||
|
||
for entry_id in entity_to_mac: | ||
if entry_id not in hass.data[DOMAIN]: | ||
return | ||
|
||
for mac in entity_to_mac[entry_id]: | ||
hass.data[DOMAIN][entry_id].remove_device(mac) | ||
|
||
hass.services.async_register(DOMAIN, 'remove_devices', remove_devices) |
Oops, something went wrong.