Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ components:
- id: fanMode
version: 1
optional: true
- id: fanSpeedPercent
version: 1
config:
values:
- key: "percent.value"
range: [ 1, 100 ]
optional: true
- id: fanOscillationMode
version: 1
optional: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ local expected_metadata = {
{
"relativeHumidityMeasurement",
"fanMode",
"fanSpeedPercent",
"fanOscillationMode",
"thermostatHeatingSetpoint",
"thermostatCoolingSetpoint"
Expand All @@ -220,6 +221,7 @@ local new_cluster_subscribe_list = {
clusters.RelativeHumidityMeasurement.attributes.MeasuredValue,
clusters.FanControl.attributes.FanMode,
clusters.FanControl.attributes.FanModeSequence,
clusters.FanControl.attributes.PercentCurrent,
clusters.FanControl.attributes.RockSupport, -- These two attributes will be subscribed to following the profile
clusters.FanControl.attributes.RockSetting, -- change since the fanOscillationMode capability will be enabled.
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,6 @@ test.register_message_test(
}
)

-- test.socket.matter:__expect_send({mock_device_auto.id, clusters.Thermostat.attributes.MinSetpointDeadBand:read(mock_device_auto)})

test.register_message_test(
"Thermostat mode reports should generate correct messages",
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ local mock_device_basic = test.mock_device.build_test_matter_device({
{cluster_id = clusters.TemperatureMeasurement.ID, cluster_type = "SERVER"},
{cluster_id = clusters.RelativeHumidityMeasurement.ID, cluster_type = "SERVER"},
{cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = 0},
{cluster_id = clusters.FanControl.ID, cluster_type = "SERVER", feature_map = 0},
},
device_types = {
{device_type_id = 0x0301, device_type_revision = 1} -- Thermostat
Expand All @@ -54,7 +55,6 @@ local function initialize_mock_device(generic_mock_device, generic_subscribed_at
subscribe_request:merge(cluster:subscribe(generic_mock_device))
end
end
test.socket.matter:__expect_send({generic_mock_device.id, subscribe_request})
return subscribe_request
end

Expand Down Expand Up @@ -96,6 +96,7 @@ local function test_init()

test.socket.device_lifecycle:__queue_receive({ mock_device_basic.id, "init" })
subscribe_request_basic = initialize_mock_device(mock_device_basic, subscribed_attributes)
test.socket.matter:__expect_send({mock_device_basic.id, subscribe_request_basic})
end

-- run the profile configuration tests
Expand Down Expand Up @@ -123,6 +124,7 @@ local expected_metadata = {
{
"relativeHumidityMeasurement",
"fanMode",
"fanSpeedPercent",
"thermostatHeatingSetpoint",
"thermostatCoolingSetpoint"
},
Expand All @@ -134,7 +136,28 @@ local expected_metadata = {
test.register_coroutine_test(
"Device with modular profile should enable correct optional capabilities",
function()
test_thermostat_device_type_update_modular_profile(mock_device_basic, expected_metadata, subscribe_request_basic)
local subscribed_attributes = {
clusters.Thermostat.attributes.LocalTemperature,
clusters.Thermostat.attributes.OccupiedCoolingSetpoint,
clusters.Thermostat.attributes.OccupiedHeatingSetpoint,
clusters.Thermostat.attributes.AbsMinCoolSetpointLimit,
clusters.Thermostat.attributes.AbsMaxCoolSetpointLimit,
clusters.Thermostat.attributes.AbsMinHeatSetpointLimit,
clusters.Thermostat.attributes.AbsMaxHeatSetpointLimit,
clusters.Thermostat.attributes.SystemMode,
clusters.Thermostat.attributes.ThermostatRunningState,
clusters.Thermostat.attributes.ControlSequenceOfOperation,
clusters.TemperatureMeasurement.attributes.MeasuredValue,
clusters.TemperatureMeasurement.attributes.MinMeasuredValue,
clusters.TemperatureMeasurement.attributes.MaxMeasuredValue,
clusters.RelativeHumidityMeasurement.attributes.MeasuredValue,
clusters.FanControl.attributes.FanMode,
clusters.FanControl.attributes.FanModeSequence,
clusters.FanControl.attributes.PercentCurrent,
clusters.PowerSource.attributes.BatPercentRemaining,
}
local subscribe_request = initialize_mock_device(mock_device_basic, subscribed_attributes)
test_thermostat_device_type_update_modular_profile(mock_device_basic, expected_metadata, subscribe_request)
end,
{ test_init = test_init }
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ function AttributeHandlers.system_mode_handler(driver, device, ib, response)
return
end

local supported_modes = device:get_latest_state(device:endpoint_to_component(ib.endpoint_id), capabilities.thermostatMode.ID, capabilities.thermostatMode.supportedThermostatModes.NAME) or {}
local supported_modes = device:get_latest_state(
device:endpoint_to_component(ib.endpoint_id),
capabilities.thermostatMode.ID,
capabilities.thermostatMode.supportedThermostatModes.NAME
) or {}
-- check that the given mode was in the supported modes list
if thermostat_utils.tbl_contains(supported_modes, fields.THERMOSTAT_MODE_MAP[ib.data.value].NAME) then
device:emit_event_for_endpoint(ib.endpoint_id, fields.THERMOSTAT_MODE_MAP[ib.data.value]())
Expand Down Expand Up @@ -325,40 +329,58 @@ function AttributeHandlers.fan_mode_handler(driver, device, ib, response)
end

function AttributeHandlers.fan_mode_sequence_handler(driver, device, ib, response)
local supportedFanModes, supported_fan_modes_attribute
local supported_fan_modes, supported_fan_modes_capability, supported_fan_modes_attribute
if ib.data.value == clusters.FanControl.attributes.FanModeSequence.OFF_LOW_MED_HIGH then
supportedFanModes = { "off", "low", "medium", "high" }
supported_fan_modes = { "off", "low", "medium", "high" }
elseif ib.data.value == clusters.FanControl.attributes.FanModeSequence.OFF_LOW_HIGH then
supportedFanModes = { "off", "low", "high" }
supported_fan_modes = { "off", "low", "high" }
elseif ib.data.value == clusters.FanControl.attributes.FanModeSequence.OFF_LOW_MED_HIGH_AUTO then
supportedFanModes = { "off", "low", "medium", "high", "auto" }
supported_fan_modes = { "off", "low", "medium", "high", "auto" }
elseif ib.data.value == clusters.FanControl.attributes.FanModeSequence.OFF_LOW_HIGH_AUTO then
supportedFanModes = { "off", "low", "high", "auto" }
supported_fan_modes = { "off", "low", "high", "auto" }
elseif ib.data.value == clusters.FanControl.attributes.FanModeSequence.OFF_HIGH_AUTO then
supportedFanModes = { "off", "high", "auto" }
supported_fan_modes = { "off", "high", "auto" }
else
supportedFanModes = { "off", "high" }
supported_fan_modes = { "off", "high" }
end

if device:supports_capability_by_id(capabilities.airPurifierFanMode.ID) then
supported_fan_modes_attribute = capabilities.airPurifierFanMode.supportedAirPurifierFanModes
supported_fan_modes_capability = capabilities.airPurifierFanMode
supported_fan_modes_attribute = supported_fan_modes_capability.supportedAirPurifierFanModes
elseif device:supports_capability_by_id(capabilities.airConditionerFanMode.ID) then
supported_fan_modes_attribute = capabilities.airConditionerFanMode.supportedAcFanModes
supported_fan_modes_capability = capabilities.airConditionerFanMode
supported_fan_modes_attribute = supported_fan_modes_capability.supportedAcFanModes
elseif device:supports_capability_by_id(capabilities.thermostatFanMode.ID) then
supported_fan_modes_capability = capabilities.thermostatFanMode
supported_fan_modes_attribute = capabilities.thermostatFanMode.supportedThermostatFanModes
-- Our thermostat fan mode control is not granular enough to handle all of the supported modes
if ib.data.value >= clusters.FanControl.attributes.FanModeSequence.OFF_LOW_MED_HIGH_AUTO and
ib.data.value <= clusters.FanControl.attributes.FanModeSequence.OFF_ON_AUTO then
supportedFanModes = { "auto", "on" }
supported_fan_modes = { "auto", "on" }
else
supportedFanModes = { "on" }
supported_fan_modes = { "on" }
end
else
supported_fan_modes_attribute = capabilities.fanMode.supportedFanModes
supported_fan_modes_capability = capabilities.fanMode
supported_fan_modes_attribute = supported_fan_modes_capability.supportedFanModes
end

-- remove 'off' as a supported fan mode for thermostat device types, unless the
-- device previously had 'off' as a supported fan mode to avoid breaking routines
if thermostat_utils.get_device_type(device) == fields.THERMOSTAT_DEVICE_TYPE_ID and
device:supports_capability_by_id(capabilities.fanMode.ID) then
local prev_supported_fan_modes = device:get_latest_state(
device:endpoint_to_component(ib.endpoint_id),
supported_fan_modes_capability.ID,
supported_fan_modes_attribute.NAME
) or {}
-- per the definitions set above, the first index always contains "off"
if prev_supported_fan_modes[1] ~= "off" then
table.remove(supported_fan_modes, 1)
end
end

local event = supported_fan_modes_attribute(supportedFanModes, {visibility = {displayed = false}})
device:emit_event_for_endpoint(ib.endpoint_id, event)
device:emit_event_for_endpoint(ib.endpoint_id, supported_fan_modes_attribute(supported_fan_modes, {visibility = {displayed = false}}))
end

function AttributeHandlers.percent_current_handler(driver, device, ib, response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ function DeviceConfiguration.match_modular_profile_thermostat(device)

if #fan_eps > 0 then
table.insert(main_component_capabilities, capabilities.fanMode.ID)
table.insert(main_component_capabilities, capabilities.fanSpeedPercent.ID)
end
if #rock_eps > 0 then
table.insert(main_component_capabilities, capabilities.fanOscillationMode.ID)
Expand Down
Loading