fix(airconditioner): label the 2Step preset and test presets by their HA value

The legacy Comode codes resolve through the same dynamic resolver as a real
convenient resource, so Nano lands on the existing 'nano' preset (already
labelled WindFree) rather than on a 'windfree' value of its own -- the new
tests asserted the label instead of the value. 2Step had no catalog entry in
either language and would have surfaced as the raw code.

Also updates the existing five-percent-humidity test, which reached into the
descriptor's field/value_fn directly, to the rep_fn the fallback needs, and
covers the fallback itself.
This commit is contained in:
perseus177 committed 2026-07-28 02:38:28 +02:00
1 parent 3032b0c032
commit 55c7b88a8f
4 files changed
+24 -8

No files matched your search

@@ -128,7 +128,8 @@
"longwind": "Long wind",
"motionindirect": "Motion indirect",
"motiondirect": "Motion direct",
"drycomfort": "Dry comfort"
"drycomfort": "Dry comfort",
"2step": "2-Step"
}
}
}
@@ -128,7 +128,8 @@
"longwind": "Lange wind",
"motionindirect": "Beweging indirect",
"motiondirect": "Beweging direct",
"drycomfort": "Droog comfort"
"drycomfort": "Droog comfort",
"2step": "2-Step"
}
}
}
+9 -5
View File
@@ -194,15 +194,19 @@ def test_preset_comes_from_the_comode_token():
entity = _climate(resources)
assert entity.preset_mode == 'none' # Comode_Off in the fixture
# Codes learned by driving this unit through its cloud integration and
# reading the token back: Nano is what the app calls WindFree.
assert 'windfree' in entity.preset_modes
# reading the token back. They go through the same dynamic resolver as a
# real convenient resource's supportedModes, so 'Nano' resolves to the
# existing 'nano' preset -- already labelled WindFree in the catalog.
assert entity.preset_modes == [
'none', 'nano', 'quiet', 'comfort', '2step', 'speed',
]
options = resources['/mode/vs/0']['x.com.samsung.da.options']
resources['/mode/vs/0']['x.com.samsung.da.options'] = [
'Comode_Nano' if option.startswith('Comode_') else option
for option in options
]
assert _climate(resources).preset_mode == 'windfree'
assert _climate(resources).preset_mode == 'nano'
async def test_preset_write_uses_the_token_path():
@@ -210,7 +214,7 @@ async def test_preset_write_uses_the_token_path():
coordinator = _FakeCoordinator(resources)
entity = _climate(resources, coordinator)
await entity.async_set_preset_mode('windfree')
await entity.async_set_preset_mode('nano')
assert coordinator.commands[-1][1] == ('preset_legacy', 'Nano')
@@ -224,7 +228,7 @@ async def test_newer_boards_keep_the_resource_paths():
await entity.async_set_fan_mode('high')
await entity.async_set_swing_mode('off')
await entity.async_set_preset_mode('windfree')
await entity.async_set_preset_mode('quiet') # from its own supportedModes
kinds = [payload[0] for _, payload in coordinator.commands]
assert kinds == ['fan', 'swing', 'preset']
+11 -1
View File
@@ -404,4 +404,14 @@ def test_current_temperature_vs_only_binds_when_ocf_href_absent():
def test_humidity_reads_five_percent_field_not_stuck_humidity_field():
desc = airconditioner.HUMIDITY.entities[0]
rep = {'x.com.samsung.da.humidity': '0', 'x.com.samsung.da.fivepercentHumidity': '42'}
assert desc.value_fn(rep.get(desc.field)) == 42.0
assert desc.rep_fn(rep) == 42.0
def test_humidity_falls_back_to_the_plain_field_where_five_percent_is_absent():
"""ARTIK051 boards (issue #136) have no fivepercentHumidity field at all.
Their plain field is not stuck -- it carries a reading while Air monitoring
is on -- so 0 means "not measuring" on both generations, not 0% humidity."""
desc = airconditioner.HUMIDITY.entities[0]
assert desc.rep_fn({'x.com.samsung.da.humidity': '51'}) == 51.0
assert desc.rep_fn({'x.com.samsung.da.humidity': '0'}) is None
assert desc.rep_fn({}) is None