fix(fridge): translate enum select/sensor values in Python, not strings.json

hassfest rejects translation keys containing uppercase letters, but the
raw Samsung enum values for flex zone, beverage zone, ice type, and ice
making status are uppercase (e.g. CV_TTYPE_RF9000A_FREEZE). Follow the
existing dryer-course pattern instead: map raw device values to
human-readable names in Python via a new SelectDesc.option_names field
(mirrored read/write in select.py) and a value_fn for the sensor, and
drop the now-unused translation_key entries from strings.json/en.json.
This commit is contained in:
Marc Billow
2026-07-09 14:12:58 -05:00
parent 5b8a079fa6
commit b386063e79
5 changed files with 49 additions and 71 deletions
@@ -20,7 +20,32 @@ from ..entities import (
)
# Beverage zone flex modes.
_BZONE_MODES = ('SP_TTYPE_BEER_DRINKS', 'SP_TTYPE_WINE_DESSERT')
_BZONE_MODE_NAMES = {
'SP_TTYPE_BEER_DRINKS': 'Beverage',
'SP_TTYPE_WINE_DESSERT': 'Wine and Dessert',
}
_BZONE_MODES = tuple(_BZONE_MODE_NAMES)
# Flex zone (convertible drawer) modes.
_FLEX_ZONE_MODE_NAMES = {
'CV_TTYPE_RF9000A_FREEZE': 'Freeze',
'CV_TTYPE_RF9000A_SOFTFREEZE': 'Soft Freeze',
'CV_TTYPE_RF9000A_MEAT_FISH': 'Meat/Fish',
'CV_TTYPE_RF9000A_FRUIT_VEGGIES': 'Fruit & Veggies',
'CV_TTYPE_RF9000A_BEVERAGE': 'Beverage',
}
# Icemaker ball-production rate options (whiskey icemaker models).
_ICE_TYPE_NAMES = {
'WHISKEY_ICEBALL_3': '3 Balls/Day',
'WHISKEY_ICEBALL_6': '6 Balls/Day',
'WHISKEY_ICEBALL_9': '9 Balls/Day',
}
_ICE_MAKING_STATUS_NAMES = {
'ICESTATUS_STOP': 'Idle',
'ICESTATUS_RUN': 'Making ice',
}
def _int(v):
@@ -102,17 +127,17 @@ ICEMAKER_GENERIC = Capability(
entities=(
SensorDesc(key='making_status',
field='x.com.samsung.da.iceMaker.iceMakingStatus',
name=None, icon='mdi:cube-outline',
translation_key='ice_making_status'),
name='Making status', icon='mdi:cube-outline',
value_fn=lambda v: _ICE_MAKING_STATUS_NAMES.get(v, v)),
SwitchDesc(key='enabled', field='x.com.samsung.da.iceMaker.state',
name=None, icon='mdi:cube-outline',
value_fn=lambda v: v == 'On',
write_fn=_icemaker_write('x.com.samsung.da.iceMaker.state')),
SelectDesc(key='type', field='x.com.samsung.da.iceType.desired',
name=None, icon='mdi:cube-outline',
translation_key='ice_type',
name='Ice type', icon='mdi:cube-outline',
entity_category='config',
options_field='x.com.samsung.da.iceType.supported',
option_names=_ICE_TYPE_NAMES,
exists_fn=lambda rep: bool(rep.get('x.com.samsung.da.iceType.supported')),
write_fn=_icemaker_write('x.com.samsung.da.iceType.desired')),
),
@@ -468,9 +493,9 @@ BEVERAGE_ZONE = Capability(
entities=(
SelectDesc(key='beverage_zone_mode', field='roomDesiredMode',
name='Beverage zone mode', icon='mdi:glass-wine',
translation_key='beverage_zone_mode',
entity_category='config',
options=_BZONE_MODES, write_fn=_bzone_write),
options=_BZONE_MODES, option_names=_BZONE_MODE_NAMES,
write_fn=_bzone_write),
),
)
@@ -496,9 +521,9 @@ FLEX_ZONE = Capability(
SelectDesc(key='flex_zone_mode',
field='x.com.samsung.da.modes',
name='Flex zone mode', icon='mdi:thermostat',
translation_key='flex_zone_mode',
entity_category='config',
options_field='x.com.samsung.da.supportedOptions',
option_names=_FLEX_ZONE_MODE_NAMES,
exists_fn=lambda rep: bool(
rep.get('x.com.samsung.da.supportedOptions')),
value_fn=lambda modes: next(
@@ -46,6 +46,7 @@ class BinarySensorDesc(SamsungEntityDescription):
class SelectDesc(SamsungEntityDescription):
options: Any = () # tuple[str,...] | Callable[[dict], list[str]]
options_field: Optional[str] = None # resource field that contains the live options list
option_names: Optional[dict] = None # raw device value -> human-readable name
write_fn: WriteFn = None
+15 -3
View File
@@ -39,12 +39,24 @@ class LocalThingsSelect(LocalThingsEntity, SelectEntity):
desc: SelectDesc = self._bound.desc
if desc.options_field:
rep = self.coordinator.last_resources.get(self._bound.href) or {}
return list(rep.get(desc.options_field) or [])
return self._attr_options
raw = list(rep.get(desc.options_field) or [])
else:
raw = self._attr_options
if desc.option_names:
return [desc.option_names.get(o, o) for o in raw]
return raw
@property
def current_option(self):
return (self.coordinator.data or {}).get(self._state_key)
desc: SelectDesc = self._bound.desc
raw = (self.coordinator.data or {}).get(self._state_key)
if desc.option_names:
return desc.option_names.get(raw, raw)
return raw
async def async_select_option(self, option: str) -> None:
desc: SelectDesc = self._bound.desc
if desc.option_names:
reverse = {v: k for k, v in desc.option_names.items()}
option = reverse.get(option, option)
await self.coordinator.async_send_command(self._bound, option)
@@ -1,13 +1,5 @@
{
"entity": {
"sensor": {
"ice_making_status": {
"state": {
"ICESTATUS_STOP": "Idle",
"ICESTATUS_RUN": "Making ice"
}
}
},
"select": {
"door_alert": {
"state": {
@@ -23,28 +15,6 @@
"66": "Medium",
"100": "High"
}
},
"ice_type": {
"state": {
"WHISKEY_ICEBALL_3": "3 Balls/Day",
"WHISKEY_ICEBALL_6": "6 Balls/Day",
"WHISKEY_ICEBALL_9": "9 Balls/Day"
}
},
"beverage_zone_mode": {
"state": {
"SP_TTYPE_BEER_DRINKS": "Beverage",
"SP_TTYPE_WINE_DESSERT": "Wine and Dessert"
}
},
"flex_zone_mode": {
"state": {
"CV_TTYPE_RF9000A_FREEZE": "Freeze",
"CV_TTYPE_RF9000A_SOFTFREEZE": "Soft Freeze",
"CV_TTYPE_RF9000A_MEAT_FISH": "Meat/Fish",
"CV_TTYPE_RF9000A_FRUIT_VEGGIES": "Fruit & Veggies",
"CV_TTYPE_RF9000A_BEVERAGE": "Beverage"
}
}
}
},
@@ -1,13 +1,5 @@
{
"entity": {
"sensor": {
"ice_making_status": {
"state": {
"ICESTATUS_STOP": "Idle",
"ICESTATUS_RUN": "Making ice"
}
}
},
"select": {
"door_alert": {
"state": {
@@ -23,28 +15,6 @@
"66": "Medium",
"100": "High"
}
},
"ice_type": {
"state": {
"WHISKEY_ICEBALL_3": "3 Balls/Day",
"WHISKEY_ICEBALL_6": "6 Balls/Day",
"WHISKEY_ICEBALL_9": "9 Balls/Day"
}
},
"beverage_zone_mode": {
"state": {
"SP_TTYPE_BEER_DRINKS": "Beverage",
"SP_TTYPE_WINE_DESSERT": "Wine and Dessert"
}
},
"flex_zone_mode": {
"state": {
"CV_TTYPE_RF9000A_FREEZE": "Freeze",
"CV_TTYPE_RF9000A_SOFTFREEZE": "Soft Freeze",
"CV_TTYPE_RF9000A_MEAT_FISH": "Meat/Fish",
"CV_TTYPE_RF9000A_FRUIT_VEGGIES": "Fruit & Veggies",
"CV_TTYPE_RF9000A_BEVERAGE": "Beverage"
}
}
}
},