diff --git a/custom_components/elehant/config_flow.py b/custom_components/elehant/config_flow.py index c2b9682..2dd3b46 100644 --- a/custom_components/elehant/config_flow.py +++ b/custom_components/elehant/config_flow.py @@ -9,11 +9,12 @@ BluetoothServiceInfoBleak, async_discovered_service_info, ) -from homeassistant.const import CONF_ADDRESS +from homeassistant.const import CONF_UNIQUE_ID from homeassistant.data_entry_flow import FlowResult from .const import DOMAIN from .elehant import ElehantData, ElehantError +from .helpers import get_device_name _LOGGER = logging.getLogger(__name__) @@ -32,28 +33,28 @@ def __init__(self) -> None: async def async_step_bluetooth(self, info: BluetoothServiceInfoBleak) -> FlowResult: """Handle the Bluetooth discovery step.""" - await self.async_set_unique_id(info.address) - self._abort_if_unique_id_configured() - try: - self._discovered_device = ElehantData.from_ble( - info.device, info.advertisement - ) + device = ElehantData.from_ble(info.device, info.advertisement) except ElehantError: return self.async_abort(reason="not_supported") + await self.async_set_unique_id(info.address) + self._discovered_device = device + return await self.async_step_bluetooth_confirm() async def async_step_bluetooth_confirm( self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Confirm discovery.""" - assert (dev := self._discovered_device) + assert (device := self._discovered_device) if user_input is not None: - return self.async_create_entry(title=dev.unique_id, data={}) + return self.async_create_entry(title=device.unique_id, data={}) + name = await get_device_name(self.hass, device) + self.context["title_placeholders"] = {"name": name} self._set_confirm_only() return self.async_show_form(step_id="bluetooth_confirm") @@ -63,29 +64,27 @@ async def async_step_user( ) -> FlowResult: """Handle the user step to pick discovered device.""" if user_input is not None: - address = user_input[CONF_ADDRESS] - dev = self._discovered_devices[address] + unique_id = user_input[CONF_UNIQUE_ID] + device = self._discovered_devices[unique_id] - await self.async_set_unique_id(address, raise_on_progress=False) + await self.async_set_unique_id(device.address, raise_on_progress=False) self._abort_if_unique_id_configured() - return self.async_create_entry(title=dev.unique_id, data={}) + return self.async_create_entry(title=device.unique_id, data={}) - current_addresses = self._async_current_ids() + current_ids = self._async_current_ids() for info in async_discovered_service_info(self.hass, False): - address = info.address - - if address in current_addresses or address in self._discovered_devices: + if info.address in current_ids: continue try: - dev = ElehantData.from_ble(info.device, info.advertisement) + device = ElehantData.from_ble(info.device, info.advertisement) except ElehantError: continue - self._discovered_devices[address] = dev + self._discovered_devices[device.unique_id] = device if not self._discovered_devices: return self.async_abort(reason="no_devices_found") @@ -93,6 +92,13 @@ async def async_step_user( return self.async_show_form( step_id="user", data_schema=vol.Schema( - {vol.Required(CONF_ADDRESS): vol.In(self._discovered_devices)} + { + vol.Required(CONF_UNIQUE_ID): vol.In( + { + k: await get_device_name(self.hass, v) + for k, v in self._discovered_devices.items() + } + ) + } ), ) diff --git a/custom_components/elehant/elehant.py b/custom_components/elehant/elehant.py index 8c40ae4..9cb65c1 100644 --- a/custom_components/elehant/elehant.py +++ b/custom_components/elehant/elehant.py @@ -29,20 +29,20 @@ class ElehantData: _: dc.KW_ONLY - firmware: str - """Версия ПО""" + sw_version: str + """Версия прошивки""" battery: int - """Состояние батареи""" + """Уровень заряда батареи""" temperature: float """Температура среды""" value_1: float - """Показания 1""" + """Показание 1""" value_2: float | None = None - """Показания 2""" + """Показание 2""" address: str """Адрес""" rssi: int - """RSSI""" + """Уровень сигнала RSSI""" @classmethod def from_ble(cls, dev: BLEDevice, adv: AdvertisementData): @@ -62,12 +62,12 @@ def from_ble(cls, dev: BLEDevice, adv: AdvertisementData): "Device signatures in address and adverisement data aren't equals." ) - fw, packet = "{}.{}".format(*divmod(x[16], 10)), x[3] + sw_version, packet_version = "{}.{}".format(*divmod(x[16], 10)), x[3] - if packet == 0x01: + if packet_version == 0x01: return cls( *sign, - firmware=fw, + sw_version=sw_version, battery=min(x[13], 100), temperature=int.from_bytes(x[14:16], "little") / 1e2, value_1=int.from_bytes(x[9:13], "little") / 1e4, @@ -75,14 +75,15 @@ def from_ble(cls, dev: BLEDevice, adv: AdvertisementData): rssi=adv.rssi, ) - if packet == 0x05: + if packet_version == 0x05: + # Значения показаний 28-битные v1, v2 = map(lambda x: x << 24, divmod(x[9], 16)) v1 += int.from_bytes(x[10:13], "big") v2 += int.from_bytes(x[13:16], "big") return cls( *sign, - firmware=fw, + sw_version=sw_version, battery=min(x[1], 100), temperature=x[2], value_1=v1 / 1e3, @@ -91,7 +92,7 @@ def from_ble(cls, dev: BLEDevice, adv: AdvertisementData): rssi=adv.rssi, ) - raise UnsupportedPacket("Packet version %d is not supported.", packet) + raise UnsupportedPacket("Packet version %d is not supported.", packet_version) @property def key_type(self) -> str: diff --git a/custom_components/elehant/helpers.py b/custom_components/elehant/helpers.py new file mode 100644 index 0000000..70a3cc4 --- /dev/null +++ b/custom_components/elehant/helpers.py @@ -0,0 +1,29 @@ +from homeassistant.core import HomeAssistant +from homeassistant.helpers import translation as i18n + +from .const import DOMAIN +from .elehant import ElehantData + + +async def get_translated_key( + hass: HomeAssistant, + category: str, + key: str, + placeholders: dict[str, str] | None = None, + fallback: str | None = None, +): + language = hass.config.language + tr = await i18n.async_get_translations(hass, language, category, [DOMAIN]) + + return tr.get(f"component.{DOMAIN}.{category}.{key}", fallback or "").format( + **placeholders or {} + ) + + +def get_device_name(hass: HomeAssistant, device: ElehantData): + return get_translated_key( + hass, + "device", + key=f"{device.key_model}.name", + placeholders={"serial": device.str_serial}, + ) diff --git a/custom_components/elehant/manifest.json b/custom_components/elehant/manifest.json index ea4de49..a76ad77 100644 --- a/custom_components/elehant/manifest.json +++ b/custom_components/elehant/manifest.json @@ -3,7 +3,7 @@ "name": "Elehant Meters", "bluetooth": [ { - "connectable": false, + "connectable": false, "manufacturer_id": 65535, "manufacturer_data_start": [128] } @@ -15,5 +15,5 @@ "integration_type": "device", "iot_class": "local_push", "issue_tracker": "https://github.com/dudanov/hassio-elehant/issues", - "version": "0.9.1" + "version": "0.10.0" } \ No newline at end of file diff --git a/custom_components/elehant/sensor.py b/custom_components/elehant/sensor.py index f648e19..2b09cef 100644 --- a/custom_components/elehant/sensor.py +++ b/custom_components/elehant/sensor.py @@ -96,11 +96,12 @@ def _it(): connections={(dr.CONNECTION_BLUETOOTH, data.address)}, identifiers={(DOMAIN, data.unique_id)}, manufacturer="Элехант", - model_id=data.key_model, + # model_id=data.key_model, # model=data.name_model, serial_number=data.str_serial, - sw_version=data.firmware, - translation_key=data.key_type, + sw_version=data.sw_version, + translation_key=data.key_model, + translation_placeholders={"serial": data.str_serial}, ) result = PassiveBluetoothDataUpdate( diff --git a/custom_components/elehant/translations/en.json b/custom_components/elehant/translations/en.json index 10f32fe..6fc3cb3 100644 --- a/custom_components/elehant/translations/en.json +++ b/custom_components/elehant/translations/en.json @@ -4,9 +4,8 @@ "step": { "user": { "title": "Select a meter", - "description": "Select a meter from the list below.", "data": { - "address": "Discovered meters:" + "unique_id": "Select meter:" } }, "bluetooth_confirm": { @@ -22,17 +21,119 @@ } }, "device": { - "1": { - "name": "Gas meter" + "1-1": { + "name": "Gas meter DGM-1.8-{serial}" }, - "2": { - "name": "Water meter" + "1-2": { + "name": "Gas meter DGM-3.2-{serial}" }, - "3": { - "name": "Electricity meter" + "1-3": { + "name": "Gas meter DGM-4.0-{serial}" }, - "4": { - "name": "Heat meter" + "1-4": { + "name": "Gas meter DGM-6.0-{serial}" + }, + "1-5": { + "name": "Gas meter DGM-1.6-{serial}" + }, + "1-16": { + "name": "Gas meter GMDL-1.8-{serial}" + }, + "1-17": { + "name": "Gas meter GMDL-3.2-{serial}" + }, + "1-18": { + "name": "Gas meter GMDL-4.0-{serial}" + }, + "1-19": { + "name": "Gas meter GMDL-6.0-{serial}" + }, + "1-20": { + "name": "Gas meter GMDL-1.6-{serial}" + }, + "1-32": { + "name": "Gas meter USGM-G1,6-{serial}" + }, + "1-33": { + "name": "Gas meter USGM-G2,5-{serial}" + }, + "1-34": { + "name": "Gas meter USGM-G4-{serial}" + }, + "1-35": { + "name": "Gas meter USGM-G6-{serial}" + }, + "1-36": { + "name": "Gas meter USGM-G10-{serial}" + }, + "1-48": { + "name": "Gas meter GMDL-1.8TC-{serial}" + }, + "1-49": { + "name": "Gas meter GMDL-3.2TC-{serial}" + }, + "1-50": { + "name": "Gas meter GMDL-4.0TC-{serial}" + }, + "1-51": { + "name": "Gas meter GMDL-6.0TC-{serial}" + }, + "1-52": { + "name": "Gas meter GMDL-1.6TC-{serial}" + }, + "1-64": { + "name": "Gas meter USGM-G1,6TC-{serial}" + }, + "1-65": { + "name": "Gas meter USGM-G2,5TC-{serial}" + }, + "1-66": { + "name": "Gas meter USGM-G4TC-{serial}" + }, + "1-67": { + "name": "Gas meter USGM-G6TC-{serial}" + }, + "1-68": { + "name": "Gas meter USGM-G10TC-{serial}" + }, + "1-80": { + "name": "Gas meter DGM-1.8TC-{serial}" + }, + "1-81": { + "name": "Gas meter DGM-3.2TC-{serial}" + }, + "1-82": { + "name": "Gas meter DGM-4.0TC-{serial}" + }, + "1-83": { + "name": "Gas meter DGM-6.0TC-{serial}" + }, + "1-84": { + "name": "Gas meter DGM-1.6TC-{serial}" + }, + "2-1": { + "name": "Water meter DWM-15-{serial}" + }, + "2-2": { + "name": "Water meter DWM-20-{serial}" + }, + "2-3": { + "name": "Water meter DTM-15-{serial}" + }, + "2-4": { + "name": "Water meter DTM-15-{serial}" + }, + "2-5": { + "name": "Water meter DTM-20-{serial}" + }, + "2-6": { + "name": "Water meter DTM-20-{serial}" + }, + "3-1": { + "name": "Electricity meter DEM-{serial}" + }, + "4-1": { + "name": "Heat meter DTM-10-{serial}" } } } \ No newline at end of file diff --git a/custom_components/elehant/translations/ru.json b/custom_components/elehant/translations/ru.json index 6ab8816..253fee2 100644 --- a/custom_components/elehant/translations/ru.json +++ b/custom_components/elehant/translations/ru.json @@ -4,9 +4,8 @@ "step": { "user": { "title": "Выбор прибора учета", - "description": "Выберите прибор учета из списка ниже.", "data": { - "address": "Обнаруженные приборы:" + "unique_id": "Выберите прибор учета:" } }, "bluetooth_confirm": { @@ -22,17 +21,119 @@ } }, "device": { - "1": { - "name": "Счетчик газа" + "1-1": { + "name": "Счетчик газа СГБ-1.8-{serial}" }, - "2": { - "name": "Счетчик воды" + "1-2": { + "name": "Счетчик газа СГБ-3.2-{serial}" }, - "3": { - "name": "Счетчик электроэнергии" + "1-3": { + "name": "Счетчик газа СГБ-4.0-{serial}" }, - "4": { - "name": "Счетчик тепла" + "1-4": { + "name": "Счетчик газа СГБ-6.0-{serial}" + }, + "1-5": { + "name": "Счетчик газа СГБ-1.6-{serial}" + }, + "1-16": { + "name": "Счетчик газа СГБД-1.8-{serial}" + }, + "1-17": { + "name": "Счетчик газа СГБД-3.2-{serial}" + }, + "1-18": { + "name": "Счетчик газа СГБД-4.0-{serial}" + }, + "1-19": { + "name": "Счетчик газа СГБД-6.0-{serial}" + }, + "1-20": { + "name": "Счетчик газа СГБД-1.6-{serial}" + }, + "1-32": { + "name": "Счетчик газа СОНИК-G1,6-{serial}" + }, + "1-33": { + "name": "Счетчик газа СОНИК-G2,5-{serial}" + }, + "1-34": { + "name": "Счетчик газа СОНИК-G4-{serial}" + }, + "1-35": { + "name": "Счетчик газа СОНИК-G6-{serial}" + }, + "1-36": { + "name": "Счетчик газа СОНИК-G10-{serial}" + }, + "1-48": { + "name": "Счетчик газа СГБД-1.8ТК-{serial}" + }, + "1-49": { + "name": "Счетчик газа СГБД-3.2ТК-{serial}" + }, + "1-50": { + "name": "Счетчик газа СГБД-4.0ТК-{serial}" + }, + "1-51": { + "name": "Счетчик газа СГБД-6.0ТК-{serial}" + }, + "1-52": { + "name": "Счетчик газа СГБД-1.6ТК-{serial}" + }, + "1-64": { + "name": "Счетчик газа СОНИК-G1,6ТК-{serial}" + }, + "1-65": { + "name": "Счетчик газа СОНИК-G2,5ТК-{serial}" + }, + "1-66": { + "name": "Счетчик газа СОНИК-G4ТК-{serial}" + }, + "1-67": { + "name": "Счетчик газа СОНИК-G6ТК-{serial}" + }, + "1-68": { + "name": "Счетчик газа СОНИК-G10ТК-{serial}" + }, + "1-80": { + "name": "Счетчик газа СГБ-1.8ТК-{serial}" + }, + "1-81": { + "name": "Счетчик газа СГБ-3.2ТК-{serial}" + }, + "1-82": { + "name": "Счетчик газа СГБ-4.0ТК-{serial}" + }, + "1-83": { + "name": "Счетчик газа СГБ-6.0ТК-{serial}" + }, + "1-84": { + "name": "Счетчик газа СГБ-1.6ТК-{serial}" + }, + "2-1": { + "name": "Счетчик воды СВД-15-{serial}" + }, + "2-2": { + "name": "Счетчик воды СВД-20-{serial}" + }, + "2-3": { + "name": "Счетчик воды СВТ-15-{serial}" + }, + "2-4": { + "name": "Счетчик воды СВТ-15-{serial}" + }, + "2-5": { + "name": "Счетчик воды СВТ-20-{serial}" + }, + "2-6": { + "name": "Счетчик воды СВТ-20-{serial}" + }, + "3-1": { + "name": "Счетчик электроэнергии СЭБ-{serial}" + }, + "4-1": { + "name": "Счетчик тепла СТБ-10-{serial}" } } } \ No newline at end of file