Skip to content

Commit

Permalink
Merge pull request #2 from leonxi/dev
Browse files Browse the repository at this point in the history
Add config flow and options with discovery merged.
  • Loading branch information
leonxi authored Oct 29, 2020
2 parents 081cd73 + 2f29218 commit a60b4a6
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 67 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/validate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Validate

on:
push:
pull_request:
schedule:
- cron: "0 0 * * *"

jobs:
validate:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- name: HACS validation
uses: "hacs/integration/action@main"
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CATEGORY: "integration"
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ English | [简体中文](./README_zh-CN.md)
# Xiaomi Mijia BLE Temperature Hygrometer 2

[![GitHub Release][releases-shield]][releases]
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs)

This is a custom component for home assistant to use bluetooth adapter directly integrate the Xiaomi Mijia BLE Temperature Hygrometer (LYWSDCGQ/01ZM) and Mijia BLE Temperature Hygrometer 2 (LYWSD03MMC).

Expand Down Expand Up @@ -80,5 +81,14 @@ Configuration variables:
![LYWSD03MMC_PANEL_SHOW](/pictures/sample_panel_1.png)
## Todo
- Integration Options
- Add auto discovery option, to control enable or disable discovery
- Add period option, to control period of fetching devices' data, default period is 15 minutes. Avoid frequent access to Bluetooth devices, resulting in high power consumption of them.
- Known issues
- When installation, discoverred devices can not be displayed, and set their own areas.
- In devices list, area or name can not be modified. (Fixed)
[releases-shield]: https://img.shields.io/github/release/leonxi/mitemp_bt2.svg
[releases]: https://github.com/leonxi/mitemp_bt2/releases
10 changes: 10 additions & 0 deletions README_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# 小米 米家蓝牙温湿度计2

[![GitHub Release][releases-shield]][releases]
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs)

这是一个Home Assistant自定义组件,用于 Home Assistant 通过 蓝牙适配器 直接集成 小米 米家蓝牙温湿度计 (LYWSDCGQ/01ZM) 和 米家蓝牙温湿度计2 (LYWSD03MMC)。

Expand Down Expand Up @@ -79,5 +80,14 @@ sensor:
![LYWSD03MMC_PANEL_SHOW](/pictures/sample_panel_1.png)
## 待处理事项
- 集成选项
- 增加自动发现选项,控制自动发现(启用/禁用)
- 增加周期选项,控制读取蓝牙设备数据周期(默认15分钟),避免频繁访问蓝牙设备,造成蓝牙设备耗电高
- 已知问题
- 安装集成的时候,无法每次都显示扫描到的设备,并设置所在区域
- 设备区域和名称无法设置和修改 (已解决)
[releases-shield]: https://img.shields.io/github/release/leonxi/mitemp_bt2.svg
[releases]: https://github.com/leonxi/mitemp_bt2/releases
31 changes: 23 additions & 8 deletions custom_components/mitemp_bt2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
DOMAIN,
ATTR_CONFIG,
CONF_DISCOVERY,
CONF_PERIOD,
UPDATE_TOPIC,
ERROR_TOPIC
)
Expand All @@ -33,7 +34,9 @@
async def async_setup(hass, config):
"""Do not allow config via configuration.yaml"""
conf = config.get("sensor")
_LOGGER.debug("async_setup %s", conf)
_LOGGER.debug("async_setup sensor %s", conf)
conf2 = config.get(DOMAIN)
_LOGGER.debug("async_setup %s %s", DOMAIN, conf2)

if not hasattr(hass.data, DOMAIN):
hass.data[DOMAIN] = {}
Expand All @@ -51,9 +54,17 @@ async def async_setup(hass, config):

async def async_setup_entry(hass, entry):
"""Set up a config entry."""
_LOGGER.debug("async_setup_entry %s", entry.data)
ui_config_data = entry.data
_LOGGER.debug("async_setup_entry ui config %s", ui_config_data)
ui_config_options = entry.options
_LOGGER.debug("async_setup_entry ui config options %s", ui_config_options)

# Set options values to operation
discovery = ui_config_options.get("CONF_DISCOVERY") or ui_config_data.get("CONF_DISCOVERY")
period = ui_config_options.get("CONF_PERIOD") or ui_config_data.get("CONF_PERIOD")

config_data = hass.data[DOMAIN].get(ATTR_CONFIG)
_LOGGER.debug("async_setup_entry %s", config_data)
_LOGGER.debug("async_setup_entry yaml config %s", config_data)

sensors = hass.data[DOMAIN]["sensor"] = []

Expand All @@ -65,7 +76,7 @@ async def async_setup_entry(hass, entry):
# sensors.extend(static_devices)

# Add discovered devices
if config_data is None or True: # config_data[CONF_DISCOVERY]
if config_data is None or discovery: # config_data[CONF_DISCOVERY]
discovered_devices = await async_discover_devices(hass, static_devices)

sensors.extend(discovered_devices)
Expand All @@ -92,7 +103,11 @@ async def async_setup_entry(hass, entry):
)

if len(sensors) > 0:
hass.data[DOMAIN]["hub"] = MiTempBT2Hub(SingletonBLEScanner(), hass, sensors)

if period:
period = timedelta(seconds=period)

hass.data[DOMAIN]["hub"] = MiTempBT2Hub(SingletonBLEScanner(), hass, sensors, period)

return True

Expand All @@ -103,14 +118,14 @@ async def async_unload_entry(hass, config_entry):
class MiTempBT2Hub(threading.Thread):
"""蓝牙设备数据扫描"""

def __init__(self, instance, hass, sensors):
def __init__(self, instance, hass, sensors, period = MIN_TIME_BETWEEN_UPDATES):
"""Init MiTempBT2 Hub"""
super().__init__()
self.instance = instance
self.hass = hass
self.sensors = sensors
self.period = period or MIN_TIME_BETWEEN_UPDATES

@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Update sensors from Bluetooth devices."""
for sensor in self.sensors:
Expand All @@ -132,4 +147,4 @@ def run(self):
while True:
_LOGGER.debug("Starting mitemp_bt2 loop")
self.update()
time.sleep(MIN_TIME_BETWEEN_UPDATES.seconds)
time.sleep(self.period.seconds)
89 changes: 54 additions & 35 deletions custom_components/mitemp_bt2/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.helpers import config_entry_flow
# from homeassistant.core import callback
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
DEVICE_CLASS_TEMPERATURE,
Expand All @@ -25,6 +25,8 @@
from .const import (
DOMAIN,
MODES,
CONF_DISCOVERY,
DEFAULT_DISCOVERY,
DEFAULT_NAME,
DEFAULT_MODE,
DEFAULT_PERIOD,
Expand All @@ -36,7 +38,7 @@

_LOGGER = logging.getLogger(__name__)

class MitempBT2ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
class ConfigFlowHanlder(config_entries.ConfigFlow, domain=DOMAIN):
"""config flow for mitemp_bt2."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
Expand All @@ -45,11 +47,6 @@ def __init__(self):
"""Initialize."""
self._errors = {}

# @staticmethod
# @callback
# def async_get_options_flow(config_entry):
# return ModeOptionsFlowHandler()

async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
self._errors = {}
Expand All @@ -60,43 +57,65 @@ async def async_step_user(self, user_input=None):
return self.async_abort(reason="single_instance_allowed")

if user_input is not None:
return self.async_create_entry(title="", data=user_input)
return self.async_create_entry(title="米家温湿度计", data=user_input)

return await self._show_config_form(user_input)

async def _show_config_form(self, user_input): # pylint: disable=unused-argument
"""Show the configuration form to edit the data."""
data_schema = OrderedDict()
data_schema[vol.Required(CONF_MAC, default="")] = str
data_schema[vol.Optional(CONF_MODE, default=DEFAULT_MODE)] = vol.In(MODES)
data_schema[vol.Optional(CONF_NAME, default=DEFAULT_NAME)] = str
data_schema[vol.Optional(CONF_PERIOD, default=DEFAULT_PERIOD)] = int

data_schema[vol.Required(CONF_DISCOVERY, default=DEFAULT_DISCOVERY)] = bool
data_schema[vol.Required(CONF_PERIOD, default=DEFAULT_PERIOD)] = int

_LOGGER.debug("config form")

return self.async_show_form(
step_id="user", data_schema=vol.Schema(data_schema), errors=self._errors,
)

# class ModeOptionsFlowHandler(config_entries.OptionsFlow):
# def __init__(self, config_entry):
# """Initialize UniFi options flow."""
# self.config_entry = config_entry
#
# async def async_step_user(self, user_input=None):
# """Manage the options."""
# if user_input is not None:
# return self.async_create_entry(title="", data=user_input)
#
# data_schema = OrderedDict()
# data_schema[
# vol.Required(CONF_MODE, default=self.config_entry.options.get(CONF_MODE))
# ] = str
#
# return self.async_show_form(
# step_id="user",
# data_schema=vol.Schema(data_schema)
# )

config_entry_flow.register_discovery_flow(
DOMAIN, "米家温湿度计", async_get_discoverable_devices, config_entries.CONN_CLASS_LOCAL_POLL
)
@staticmethod
@callback
def async_get_options_flow(config_entry):
"""Options callback for MiTempBT2."""
return OptionsFlowHandler(config_entry)

class OptionsFlowHandler(config_entries.OptionsFlow):
def __init__(self, config_entry):
"""Initialize UniFi options flow."""
self.config_entry = config_entry

async def async_step_init(self, _user_input=None):
"""Manage the options."""
return await self.async_step_user()

async def async_step_user(self, user_input=None):
"""Manage the options."""
if user_input is not None:
return self.async_create_entry(title="选项", data=user_input)

discovery = self.config_entry.options.get(CONF_DISCOVERY)
period = self.config_entry.options.get(CONF_PERIOD)

if discovery is None:
discovery = self.config_entry.data.get(CONF_DISCOVERY)

if period is None:
period = self.config_entry.data.get(CONF_PERIOD)

data_schema = OrderedDict()
data_schema[
vol.Required(CONF_DISCOVERY, default=discovery)
] = bool
data_schema[
vol.Required(CONF_PERIOD, default=period)
] = int

return self.async_show_form(
step_id="user",
data_schema=vol.Schema(data_schema)
)

# config_entry_flow.register_discovery_flow(
# DOMAIN, "米家温湿度计", async_get_discoverable_devices, config_entries.CONN_CLASS_LOCAL_POLL
# )
3 changes: 2 additions & 1 deletion custom_components/mitemp_bt2/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
CONF_DISCOVERY = "discovery"

# Default values for configuration options
DEFAULT_PERIOD = 300
DEFAULT_PERIOD = 1800
DEFAULT_USE_MEDIAN = False
DEFAULT_ACTIVE_SCAN = False
DEFAULT_MODE = "LYWSD03MMC" # "LYWSD03MMC", "LYWSDCGQ/01ZM" are available
DEFAULT_DISCOVERY = True

MODES = ["LYWSD03MMC", "LYWSDCGQ/01ZM"]
NAMES = ["米家蓝牙温湿度计2", "米家蓝牙温湿度计"]
Expand Down
9 changes: 4 additions & 5 deletions custom_components/mitemp_bt2/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ def __init__(self, mac, mode, parameter, name, unit):
self._mac = mac
self._mode = mode
self.parameter = parameter
self._device_id = mac.replace(":", "").lower()
self._unique_id = "{}_{}".format(parameter, mac.replace(":", "").lower())
self.entity_id = "{}.{}".format("sensor", self._unique_id)
self._unit = unit
Expand Down Expand Up @@ -311,13 +312,11 @@ def unit_of_measurement(self):
# return {
# "identifiers": {
# # Serial numbers are unique identifiers within a specific domain
# (DOMAIN, self._unique_id)
# (DOMAIN, self._device_id)
# },
# "name": self._name,
# "manufacturer": self.light.manufacturername,
# "model": self.light.productname,
# "sw_version": self.light.swversion,
# "via_device": (hue.DOMAIN, self.api.bridgeid),
# "manufacturer": "小米 米家",
# "model": self._mode,
# }

@property
Expand Down
25 changes: 19 additions & 6 deletions custom_components/mitemp_bt2/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@
"config": {
"step": {
"user": {
"title": "New Mijia Hygrometer Sensor",
"description": "If you need help with the configuration have a look here: https:\/\/github.com\/leonxi\/mitemp_bt2\/",
"title": "Mijia Hygrometer Integration",
"description": "This integration support auto discovery devices for Xiaomi Mijia BLE Temperature Hygrometer 2, If you want more detail information for this integration, please visit our project site: https:\/\/github.com\/leonxi\/mitemp_bt2\/",
"data": {
"mac": "Device MAC (e.g. \"A4:C1:38:AA:AA:AA\")",
"mode": "Device mode no.",
"name": "Device name",
"period": "Scan period of this device"
"period": "Scan period of this device",
"discovery": "Auto discovery"
}
}
},
"abort": {
"single_instance_allowed": "This integration only allow single instance."
}
},
"options": {
"step": {
"user": {
"title": "Mijia Hygrometer Integration",
"description": "This integration support auto discovery devices for Xiaomi Mijia BLE Temperature Hygrometer 2, If you want more detail information for this integration, please visit our project site: https:\/\/github.com\/leonxi\/mitemp_bt2\/",
"data": {
"period": "Scan period of this device",
"discovery": "Auto discovery"
}
}
}
Expand Down
25 changes: 19 additions & 6 deletions custom_components/mitemp_bt2/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@
"config": {
"step": {
"user": {
"title": "New Mijia Hygrometer Sensor",
"description": "If you need help with the configuration have a look here: https:\/\/github.com\/leonxi\/mitemp_bt2\/",
"title": "Mijia Hygrometer Integration",
"description": "This integration support auto discovery devices for Xiaomi Mijia BLE Temperature Hygrometer 2, If you want more detail information for this integration, please visit our project site: https:\/\/github.com\/leonxi\/mitemp_bt2\/",
"data": {
"mac": "Device MAC (e.g. \"A4:C1:38:AA:AA:AA\")",
"mode": "Device mode no.",
"name": "Device name",
"period": "Scan period of this device"
"period": "Scan period of this device",
"discovery": "Auto discovery"
}
}
},
"abort": {
"single_instance_allowed": "This integration only allow single instance."
}
},
"options": {
"step": {
"user": {
"title": "Mijia Hygrometer Integration",
"description": "This integration support auto discovery devices for Xiaomi Mijia BLE Temperature Hygrometer 2, If you want more detail information for this integration, please visit our project site: https:\/\/github.com\/leonxi\/mitemp_bt2\/",
"data": {
"period": "Scan period of this device",
"discovery": "Auto discovery"
}
}
}
Expand Down
Loading

0 comments on commit a60b4a6

Please sign in to comment.