Entity Map¶
Фабрики маппинга: связь HA domain и entity_id с соответствующими классами устройств Sber.
Mapping from HA entity domains to Sber device entity classes.
Provides factory functions that create the appropriate Sber entity
subclass based on the HA entity domain and device class.
Supports user-defined overrides via sber_category parameter.
Also hosts the single source of truth for Sber category → HA domain
promotion: :data:CATEGORY_DOMAIN_MAP + :func:categories_for_domain +
:data:CATEGORY_UI_META drive the device-centric wizard introduced in
v1.26.0. See docs/DEVICE_WIZARD_PLAN.md for the full design.
OVERRIDABLE_CATEGORIES
module-attribute
¶
OVERRIDABLE_CATEGORIES = ['light', 'led_strip', 'relay', 'socket', 'curtain', 'window_blind', 'gate', 'hvac_ac', 'hvac_radiator', 'hvac_heater', 'hvac_boiler', 'hvac_underfloor_heating', 'hvac_fan', 'valve', 'hvac_humidifier', 'scenario_button', 'hvac_air_purifier', 'kettle', 'tv', 'vacuum_cleaner', 'intercom']
Sber categories that users can select as type overrides.
CATEGORY_DOMAIN_MAP
module-attribute
¶
CATEGORY_DOMAIN_MAP = {'light': CategorySpec(cls=LightEntity, domains=('light',), preferred_rank=1), 'led_strip': CategorySpec(cls=LedStripEntity, domains=('light',), preferred_rank=5), 'socket': CategorySpec(cls=SocketEntity, domains=('switch',), device_classes=('outlet',), preferred_rank=8), 'relay': CategorySpec(cls=RelayEntity, domains=('switch', 'script', 'button'), device_classes=None, preferred_rank=10, fallback_when_no_device_class=True), 'scenario_button': CategorySpec(cls=ScenarioButtonEntity, domains=('input_boolean',), preferred_rank=12), 'gate': CategorySpec(cls=GateEntity, domains=('cover',), device_classes=('gate', 'garage_door', 'garage', 'door'), preferred_rank=3), 'window_blind': CategorySpec(cls=WindowBlindEntity, domains=('cover',), device_classes=('blind', 'shade', 'shutter'), preferred_rank=4), 'curtain': CategorySpec(cls=CurtainEntity, domains=('cover',), device_classes=('curtain', 'awning'), preferred_rank=6, fallback_when_no_device_class=True), 'hvac_radiator': CategorySpec(cls=HvacRadiatorEntity, domains=('climate',), device_classes=('radiator',), preferred_rank=3), 'hvac_heater': CategorySpec(cls=HvacHeaterEntity, domains=('climate',), device_classes=('heater',), preferred_rank=4), 'hvac_underfloor_heating': CategorySpec(cls=HvacUnderfloorEntity, domains=('climate',), device_classes=('underfloor', 'underfloor_heating'), preferred_rank=5), 'hvac_ac': CategorySpec(cls=ClimateEntity, domains=('climate',), device_classes=None, preferred_rank=6, fallback_when_no_device_class=True), 'hvac_boiler': CategorySpec(cls=HvacBoilerEntity, domains=('water_heater',), preferred_rank=5), 'hvac_air_purifier': CategorySpec(cls=HvacAirPurifierEntity, domains=('fan',), device_classes=('purifier', 'air_purifier'), preferred_rank=4), 'hvac_fan': CategorySpec(cls=HvacFanEntity, domains=('fan',), device_classes=None, preferred_rank=6, fallback_when_no_device_class=True), 'hvac_humidifier': CategorySpec(cls=HumidifierEntity, domains=('humidifier',), preferred_rank=5), 'valve': CategorySpec(cls=ValveEntity, domains=('valve',), preferred_rank=5), 'kettle': CategorySpec(cls=KettleEntity, domains=('water_heater', 'switch'), device_classes=None, preferred_rank=40, fallback_when_no_device_class=True), 'tv': CategorySpec(cls=TvEntity, domains=('media_player',), device_classes=None, preferred_rank=5, fallback_when_no_device_class=True), 'vacuum_cleaner': CategorySpec(cls=VacuumCleanerEntity, domains=('vacuum',), preferred_rank=5), 'intercom': CategorySpec(cls=IntercomEntity, domains=('lock', 'switch'), device_classes=None, preferred_rank=30), 'sensor_temp': CategorySpec(cls=SensorTempEntity, domains=('sensor',), device_classes=('temperature',), preferred_rank=30), 'sensor_humidity': CategorySpec(cls=HumiditySensorEntity, domains=('sensor',), device_classes=('humidity',), preferred_rank=30), 'sensor_pir': CategorySpec(cls=MotionSensorEntity, domains=('binary_sensor',), device_classes=('motion', 'occupancy', 'presence'), preferred_rank=20), 'sensor_door': CategorySpec(cls=DoorSensorEntity, domains=('binary_sensor',), device_classes=('door', 'window', 'garage_door', 'opening'), preferred_rank=20), 'sensor_water_leak': CategorySpec(cls=WaterLeakSensorEntity, domains=('binary_sensor',), device_classes=('moisture', 'water'), preferred_rank=20), 'sensor_smoke': CategorySpec(cls=SmokeSensorEntity, domains=('binary_sensor',), device_classes=('smoke',), preferred_rank=20), 'sensor_gas': CategorySpec(cls=GasSensorEntity, domains=('binary_sensor',), device_classes=('gas', 'carbon_monoxide'), preferred_rank=20)}
Authoritative Sber-category → HA-entity-class promotion table.
Every entry carries its own entity constructor via :attr:CategorySpec.cls,
so this single dict drives both auto-detection (by HA domain/device_class)
and user overrides (by explicit category id).
CATEGORY_UI_META
module-attribute
¶
CATEGORY_UI_META = {'light': CategoryUiMeta('💡', 'control', 'Light'), 'led_strip': CategoryUiMeta('🎚️', 'control', 'LED strip'), 'relay': CategoryUiMeta('🔌', 'control', 'Relay'), 'socket': CategoryUiMeta('🔋', 'control', 'Socket'), 'hvac_ac': CategoryUiMeta('❄️', 'control', 'Air conditioner'), 'hvac_radiator': CategoryUiMeta('🔥', 'control', 'Radiator'), 'hvac_heater': CategoryUiMeta('♨️', 'control', 'Heater'), 'hvac_underfloor_heating': CategoryUiMeta('🧱', 'control', 'Underfloor heating'), 'hvac_boiler': CategoryUiMeta('🫖', 'control', 'Boiler'), 'hvac_humidifier': CategoryUiMeta('💧', 'control', 'Humidifier'), 'hvac_air_purifier': CategoryUiMeta('🌬️', 'control', 'Air purifier'), 'hvac_fan': CategoryUiMeta('🌀', 'control', 'Fan'), 'kettle': CategoryUiMeta('☕', 'control', 'Kettle'), 'vacuum_cleaner': CategoryUiMeta('🤖', 'control', 'Vacuum'), 'valve': CategoryUiMeta('🚰', 'control', 'Valve'), 'curtain': CategoryUiMeta('🟨', 'control', 'Curtain'), 'window_blind': CategoryUiMeta('🪟', 'control', 'Window blind'), 'gate': CategoryUiMeta('🚪', 'control', 'Gate / Garage'), 'tv': CategoryUiMeta('📺', 'control', 'TV / Media player'), 'intercom': CategoryUiMeta('🔔', 'control', 'Intercom'), 'sensor_temp': CategoryUiMeta('🌡️', 'sensors', 'Temperature'), 'sensor_humidity': CategoryUiMeta('💦', 'sensors', 'Humidity', user_selectable=False), 'sensor_pir': CategoryUiMeta('🚶', 'sensors', 'Motion'), 'sensor_door': CategoryUiMeta('🚪', 'sensors', 'Door / Window'), 'sensor_water_leak': CategoryUiMeta('🌊', 'sensors', 'Water leak'), 'sensor_smoke': CategoryUiMeta('💨', 'sensors', 'Smoke'), 'sensor_gas': CategoryUiMeta('⚠️', 'sensors', 'Gas'), 'scenario_button': CategoryUiMeta('🔔', 'automations', 'Scenario button')}
Presentation data for each Sber category in the wizard UI.
Keys must be a subset of :data:CATEGORY_DOMAIN_MAP. See the consistency
test test_category_domain_map.py::test_ui_meta_is_subset_of_domain_map.
CATEGORY_GROUPS
module-attribute
¶
Ordered list of (group_id, label) for Step 1 grid grouping.
CategorySpec
dataclass
¶
CategorySpec(cls, domains, device_classes=None, preferred_rank=50, fallback_when_no_device_class=False)
Rules for promoting an HA entity to a specific Sber category.
Attributes:
| Name | Type | Description |
|---|---|---|
cls |
type[BaseEntity]
|
Entity class to instantiate for this category. Serves as the single source of truth for both auto-detection (pick by domain) and user overrides (pick by explicit category name). |
domains |
tuple[str, ...]
|
HA domains that can match this category. Order matters for presentation but not correctness — any listed domain is accepted. |
device_classes |
tuple[str, ...] | None
|
If |
preferred_rank |
int
|
Tie-breaking priority when the same |
fallback_when_no_device_class |
bool
|
When |
matches
¶
Return True if an HA entity of (domain, device_class) promotes here.
Source code in custom_components/sber_mqtt_bridge/sber_entity_map.py
CategoryUiMeta
dataclass
¶
Presentation metadata for a Sber category in the wizard UI.
Attributes:
| Name | Type | Description |
|---|---|---|
icon |
str
|
Unicode emoji shown in the Step 1 grid tile. |
group |
str
|
UI group identifier ( |
label_key |
str
|
Translation key suffix; frontend resolves it against its i18n table. For the panel which currently uses hard-coded strings, this is also used as a short English fallback label. |
user_selectable |
bool
|
When |
categories_for_domain
¶
Return all Sber categories matching the given HA (domain, device_class).
Result is sorted by :attr:CategorySpec.preferred_rank ascending — so
the first item is the auto-detected category, subsequent items are
alternatives the user could pick.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
domain
|
str
|
HA entity domain (e.g. |
required |
device_class
|
str | None
|
Optional |
None
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of Sber category IDs. Empty when no category matches. |
Source code in custom_components/sber_mqtt_bridge/sber_entity_map.py
create_sber_entity
¶
Create a Sber device entity from HA entity data.
Uses :data:CATEGORY_DOMAIN_MAP as the single source of truth. When
sber_category is provided, it resolves directly against the map;
otherwise :func:categories_for_domain picks the best-ranked match
for the entity's (domain, device_class).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entity_id
|
str
|
HA entity ID (e.g., |
required |
entity_data
|
dict
|
Dict with entity registry data (entity_id, device_id, area_id, original_device_class, etc.). |
required |
sber_category
|
str | None
|
Optional Sber category override (e.g. |
None
|
Returns:
| Type | Description |
|---|---|
BaseEntity | None
|
BaseEntity subclass instance, or |