Summary
A Matter air quality sensor / purifier reporting a small but valid formaldehyde value can appear as 0 in the SmartThings app.
A real-world report from the SmartThings Community shows a Dyson purifier paired through Matter. The Dyson device/app reports:
but the SmartThings app shows:
Community report:
https://community.smartthings.com/t/formaldehyde-value-on-smart-things-app-always-0/309130
This looks like an issue in the Matter Sensor Edge Driver’s air quality subdriver, specifically in the formaldehyde unit handling and conversion/rounding logic.
Affected driver area
drivers/SmartThings/matter-sensor/src/sub_drivers/air_quality_sensor/
Relevant files:
air_quality_sensor_utils/fields.lua
air_quality_sensor_handlers/attribute_handlers.lua
init.lua
Current behavior
In init.lua, FormaldehydeConcentrationMeasurement.MeasuredValue is handled with fields.units.PPM as the target unit:
[clusters.FormaldehydeConcentrationMeasurement.ID] = {
[clusters.FormaldehydeConcentrationMeasurement.attributes.MeasuredValue.ID] =
attribute_handlers.measured_value_factory(
capabilities.formaldehydeMeasurement.NAME,
capabilities.formaldehydeMeasurement.formaldehydeLevel,
fields.units.PPM
),
[clusters.FormaldehydeConcentrationMeasurement.attributes.MeasurementUnit.ID] =
attribute_handlers.measurement_unit_factory(capabilities.formaldehydeMeasurement.NAME),
[clusters.FormaldehydeConcentrationMeasurement.attributes.LevelValue.ID] =
attribute_handlers.level_value_factory(capabilities.formaldehydeHealthConcern.formaldehydeHealthConcern),
},
In fields.lua, formaldehydeMeasurement also defaults to PPM:
[capabilities.formaldehydeMeasurement.NAME] = units.PPM,
The conversion table supports PPM, PPB, and PPT conversions toward PPM, but those conversions round to whole numbers:
[units.PPM] = {
[units.PPM] = function(value) return utils.round(value) end,
[units.PPB] = function(value) return utils.round(value * (10^3)) end
},
[units.PPB] = {
[units.PPM] = function(value) return utils.round(value/(10^3)) end,
[units.PPB] = function(value) return utils.round(value) end
},
[units.PPT] = {
[units.PPM] = function(value) return utils.round(value/(10^6)) end
},
Mass concentration units are only converted toward UGM3:
[units.MGM3] = {
[units.UGM3] = function(value) return utils.round(value * (10^3)) end
},
[units.UGM3] = {
[units.UGM3] = function(value) return utils.round(value) end
},
[units.NGM3] = {
[units.UGM3] = function(value) return utils.round(value/(10^3)) end
},
There is currently no conversion path from MGM3, UGM3, or NGM3 to PPM.
Why this is a problem
Matter’s FormaldehydeConcentrationMeasurement cluster has a mandatory MeasurementUnit attribute. The MeasurementUnit enum can represent units such as:
PPM = 0
PPB = 1
PPT = 2
MGM3 = 3
UGM3 = 4
NGM3 = 5
PM3 = 6
BQM3 = 7
So a Matter device can report formaldehyde as a mass concentration, for example mg/m³ or µg/m³.
If the device reports:
MeasurementUnit = MGM3
MeasuredValue = 0.002
the current driver tries to convert from MGM3 to target PPM.
However, conversion_tables[MGM3][PPM] does not exist. As a result, the driver does not emit a formaldehydeMeasurement event for that value.
This can make the SmartThings app show 0 even though the Matter device is reporting a valid non-zero value.
There is a second related problem: if a device reports a small value in PPM, PPB, or PPT, the current conversion table rounds to whole numbers. For formaldehyde, useful indoor values are often far below 1 ppm, so whole-number rounding destroys meaningful precision.
For example:
but the current conversion does:
utils.round(2 / 1000) -- 0
So a valid small formaldehyde value can become 0.
Formaldehyde-specific unit conversion issue
Converting between mg/m³ and ppm is not a generic unit conversion. It depends on the substance’s molecular weight and on temperature/pressure assumptions.
For formaldehyde, using the common 25 °C / 1 atm assumption:
1 ppm formaldehyde ≈ 1.228–1.24 mg/m³
1 mg/m³ formaldehyde ≈ 0.81 ppm
So the reported Dyson value:
is approximately:
This is small, but it is not zero.
Adding a global MGM3 -> PPM conversion would not be correct for all gases, because CO, CO₂, NO₂, ozone, TVOC, and formaldehyde have different molecular weights.
Expected behavior
Small but valid formaldehyde values should not be dropped or rounded to zero.
For example, a device reporting:
MeasurementUnit = MGM3
MeasuredValue = 0.002
should result in either:
or, if SmartThings prefers ppm:
but not:
Suggested fix
Handle formaldehyde separately instead of relying only on the generic concentration conversion table.
Option A: Preserve mass units for formaldehyde
If the Matter device reports formaldehyde in MGM3, UGM3, or NGM3, emit the value as mg/m^3 with sufficient decimal precision rather than forcing it to PPM.
Example behavior:
MGM3 -> mg/m^3
UGM3 -> mg/m^3
NGM3 -> mg/m^3
Option B: Convert formaldehyde mass concentration to ppm using an HCHO-specific conversion
If SmartThings prefers ppm, use a formaldehyde-specific conversion factor rather than a generic one.
At 25 °C / 1 atm:
ppm = mg/m³ * 24.45 / 30.026
or approximately:
Also avoid integer rounding for gas concentrations
For gas measurements, especially formaldehyde, ozone, NO₂, and CO, conversions should preserve useful decimal precision.
For example:
local function round_to(value, decimals)
local p = 10 ^ decimals
return utils.round(value * p) / p
end
Then:
PPB -> PPM: round_to(value / 1000, 3)
PPT -> PPM: round_to(value / 1000000, 6)
PPM -> PPM: round_to(value, 3)
For formaldehyde specifically, more precision may be useful for very low indoor readings.
Defensive improvement
measured_value_factory() currently does this:
local conversion_function = aqs_fields.conversion_tables[reporting_unit][target_unit]
This works when reporting_unit exists in the conversion table, even if the target conversion is missing. But if a device reports a unit that has no top-level entry in conversion_tables, this can throw before reaching the existing “Unsupported unit conversion” log message.
A safer version would be:
local conversions = aqs_fields.conversion_tables[reporting_unit]
local conversion_function = conversions and conversions[target_unit]
if conversion_function then
local converted_value = conversion_function(ib.data.value)
device:emit_event_for_endpoint(
ib.endpoint_id,
attribute({
value = converted_value,
unit = aqs_fields.unit_strings[target_unit]
})
)
else
device.log.info_with(
{ hub_logs = true },
string.format(
"Unsupported unit conversion from %s to %s",
aqs_fields.unit_strings[reporting_unit] or tostring(reporting_unit),
aqs_fields.unit_strings[target_unit] or tostring(target_unit)
)
)
end
Suggested test cases
The driver should preserve non-zero formaldehyde values in these cases:
Reporting unit: MGM3
MeasuredValue: 0.002
Expected: non-zero formaldehyde value, preferably 0.002 mg/m^3 or ~0.0016 ppm
Reporting unit: UGM3
MeasuredValue: 2
Expected: non-zero formaldehyde value, preferably 0.002 mg/m^3 or ~0.0016 ppm
Reporting unit: PPB
MeasuredValue: 2
Expected: 0.002 ppm, not 0
Reporting unit: PPB
MeasuredValue: 80
Expected: 0.08 ppm, not 0
User impact
Matter air quality devices that report formaldehyde in realistic indoor ranges can appear broken or misleading in SmartThings because the app may show 0 even when the device is reporting a valid non-zero value.
This makes the formaldehyde capability unreliable for Matter air quality sensors and purifiers, including devices such as Dyson purifiers that expose formaldehyde measurements over Matter.
Summary
A Matter air quality sensor / purifier reporting a small but valid formaldehyde value can appear as
0in the SmartThings app.A real-world report from the SmartThings Community shows a Dyson purifier paired through Matter. The Dyson device/app reports:
but the SmartThings app shows:
Community report:
https://community.smartthings.com/t/formaldehyde-value-on-smart-things-app-always-0/309130
This looks like an issue in the Matter Sensor Edge Driver’s air quality subdriver, specifically in the formaldehyde unit handling and conversion/rounding logic.
Affected driver area
Relevant files:
Current behavior
In
init.lua,FormaldehydeConcentrationMeasurement.MeasuredValueis handled withfields.units.PPMas the target unit:In
fields.lua,formaldehydeMeasurementalso defaults toPPM:The conversion table supports
PPM,PPB, andPPTconversions towardPPM, but those conversions round to whole numbers:Mass concentration units are only converted toward
UGM3:There is currently no conversion path from
MGM3,UGM3, orNGM3toPPM.Why this is a problem
Matter’s
FormaldehydeConcentrationMeasurementcluster has a mandatoryMeasurementUnitattribute. The MeasurementUnit enum can represent units such as:So a Matter device can report formaldehyde as a mass concentration, for example
mg/m³orµg/m³.If the device reports:
the current driver tries to convert from
MGM3to targetPPM.However,
conversion_tables[MGM3][PPM]does not exist. As a result, the driver does not emit a formaldehydeMeasurement event for that value.This can make the SmartThings app show
0even though the Matter device is reporting a valid non-zero value.There is a second related problem: if a device reports a small value in
PPM,PPB, orPPT, the current conversion table rounds to whole numbers. For formaldehyde, useful indoor values are often far below1 ppm, so whole-number rounding destroys meaningful precision.For example:
but the current conversion does:
So a valid small formaldehyde value can become
0.Formaldehyde-specific unit conversion issue
Converting between
mg/m³andppmis not a generic unit conversion. It depends on the substance’s molecular weight and on temperature/pressure assumptions.For formaldehyde, using the common 25 °C / 1 atm assumption:
So the reported Dyson value:
is approximately:
This is small, but it is not zero.
Adding a global
MGM3 -> PPMconversion would not be correct for all gases, because CO, CO₂, NO₂, ozone, TVOC, and formaldehyde have different molecular weights.Expected behavior
Small but valid formaldehyde values should not be dropped or rounded to zero.
For example, a device reporting:
should result in either:
or, if SmartThings prefers ppm:
but not:
Suggested fix
Handle formaldehyde separately instead of relying only on the generic concentration conversion table.
Option A: Preserve mass units for formaldehyde
If the Matter device reports formaldehyde in
MGM3,UGM3, orNGM3, emit the value asmg/m^3with sufficient decimal precision rather than forcing it toPPM.Example behavior:
Option B: Convert formaldehyde mass concentration to ppm using an HCHO-specific conversion
If SmartThings prefers ppm, use a formaldehyde-specific conversion factor rather than a generic one.
At 25 °C / 1 atm:
or approximately:
Also avoid integer rounding for gas concentrations
For gas measurements, especially formaldehyde, ozone, NO₂, and CO, conversions should preserve useful decimal precision.
For example:
Then:
For formaldehyde specifically, more precision may be useful for very low indoor readings.
Defensive improvement
measured_value_factory()currently does this:This works when
reporting_unitexists in the conversion table, even if the target conversion is missing. But if a device reports a unit that has no top-level entry inconversion_tables, this can throw before reaching the existing “Unsupported unit conversion” log message.A safer version would be:
Suggested test cases
The driver should preserve non-zero formaldehyde values in these cases:
User impact
Matter air quality devices that report formaldehyde in realistic indoor ranges can appear broken or misleading in SmartThings because the app may show
0even when the device is reporting a valid non-zero value.This makes the formaldehyde capability unreliable for Matter air quality sensors and purifiers, including devices such as Dyson purifiers that expose formaldehyde measurements over Matter.