-
-
Notifications
You must be signed in to change notification settings - Fork 0
Section 7 Sensors
This guide covers Matter device types for various sensors, including air quality, contact, occupancy, light, temperature, humidity, smoke/CO alarm, and water leak detectors.
| Property | Value |
|---|---|
| Device Type | api.matter.deviceTypes.AirQualitySensor |
| Description | A multi-sensor that monitors air quality, particulate matter (PM2.5 and PM10), temperature, and humidity. |
| Matter Specification | § 7.6 |
Apple Home Compatibility Note: Currently, only the Air Quality cluster appears in the Apple Home app. The PM2.5, PM10, temperature, and humidity measurements are available in the Matter accessory but are not displayed by Apple Home. However, these measurements can be accessed by other Matter-compatible apps.
This device combines multiple measurement clusters:
- Air Quality - Overall air quality rating
- PM2.5 Concentration Measurement - Fine particulate matter (≤2.5 micrometers)
- PM10 Concentration Measurement - Coarse particulate matter (≤10 micrometers)
- Temperature Measurement - Ambient temperature
- Relative Humidity Measurement - Relative humidity
Provides an overall air quality assessment.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
airQuality |
number | 0-6 | Overall air quality rating ¹ |
¹ Air Quality Values:
| Value | Quality | Description |
|---|---|---|
| 0 | Unknown | Air quality cannot be determined |
| 1 | Good | Air quality is good |
| 2 | Fair | Air quality is fair |
| 3 | Moderate | Air quality is moderate |
| 4 | Poor | Air quality is poor |
| 5 | Very Poor | Air quality is very poor |
| 6 | Extremely Poor | Air quality is extremely poor |
const airQuality = accessory.clusters.airQuality.airQuality
const qualityNames = ['Unknown', 'Good', 'Fair', 'Moderate', 'Poor', 'Very Poor', 'Extremely Poor']
log.info(`Air Quality: ${qualityNames[airQuality]}`)// Update overall air quality rating
async function updateAirQuality(quality: 0 | 1 | 2 | 3 | 4 | 5 | 6) {
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.AirQuality,
{ airQuality: quality }
)
const qualityStr = ['Unknown', 'Good', 'Fair', 'Moderate', 'Poor', 'Very Poor', 'Extremely Poor'][quality]
log.info(`Air quality: ${qualityStr}`)
}
// Example: Set to Good
updateAirQuality(1)Measures fine particulate matter concentration.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
measuredValue |
number | 0-1000 | PM2.5 concentration in µg/m³ |
minMeasuredValue |
number | 0-999 | Minimum measurable value |
maxMeasuredValue |
number | 1-1000 | Maximum measurable value |
measurementUnit |
number | 0 | Unit type (0 = µg/m³) |
measurementMedium |
number | 0 | Measurement medium (0 = Air) |
// Update PM2.5 concentration
async function updatePM25(value: number) {
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.Pm25ConcentrationMeasurement,
{ measuredValue: value }
)
log.info(`PM2.5: ${value} µg/m³`)
}
// Example: 12 µg/m³ (good air quality)
updatePM25(12)Measures coarse particulate matter concentration.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
measuredValue |
number | 0-1000 | PM10 concentration in µg/m³ |
minMeasuredValue |
number | 0-999 | Minimum measurable value |
maxMeasuredValue |
number | 1-1000 | Maximum measurable value |
measurementUnit |
number | 0 | Unit type (0 = µg/m³) |
measurementMedium |
number | 0 | Measurement medium (0 = Air) |
// Update PM10 concentration
async function updatePM10(value: number) {
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.Pm10ConcentrationMeasurement,
{ measuredValue: value }
)
log.info(`PM10: ${value} µg/m³`)
}
// Example: 25 µg/m³ (good air quality)
updatePM10(25)The Air Quality Sensor also includes TemperatureMeasurement and RelativeHumidityMeasurement clusters. See the Temperature Sensor and Humidity Sensor sections for details on these clusters.
clusters: {
airQuality: {
airQuality: 1, // Good
},
pm25ConcentrationMeasurement: {
measuredValue: 12, // 12 µg/m³
minMeasuredValue: 0,
maxMeasuredValue: 1000,
measurementUnit: 0, // µg/m³
measurementMedium: 0, // Air
},
pm10ConcentrationMeasurement: {
measuredValue: 25, // 25 µg/m³
minMeasuredValue: 0,
maxMeasuredValue: 1000,
measurementUnit: 0, // µg/m³
measurementMedium: 0, // Air
},
temperatureMeasurement: {
measuredValue: 2100, // 21.00°C
minMeasuredValue: -5000, // -50°C
maxMeasuredValue: 10000, // 100°C
},
relativeHumidityMeasurement: {
measuredValue: 5500, // 55%
minMeasuredValue: 0,
maxMeasuredValue: 10000, // 100%
},
}Handler: Air quality sensors are read-only (no handlers needed).
| Property | Value |
|---|---|
| Device Type | api.matter.deviceTypes.ContactSensor |
| Description | A contact sensor that detects open/closed state (e.g., door sensor, window sensor). |
| Matter Specification | § 7.1 |
Represents the contact sensor state using a boolean value.
IMPORTANT - Inverted Semantics: The BooleanState cluster for contact sensors uses inverted logic:
-
true= Contact closed / Normal state (door/window is closed) -
false= Contact open / Triggered state (door/window is open)
This is the opposite of intuitive expectation, so you must invert values when updating the state.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
stateValue |
boolean |
true, false
|
Contact state (true=closed/normal, false=open/triggered) |
const stateValue = accessory.clusters.booleanState.stateValue
// true = closed/normal, false = open/triggered
const isOpen = !stateValue // Invert to get intuitive open/closed// When your physical sensor reports a state change
async function updateContactState(isOpen: boolean) {
// IMPORTANT: Invert the value!
// Matter BooleanState: false = open/triggered, true = closed/normal
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.BooleanState,
{ stateValue: !isOpen } // Invert!
)
log.info(`Contact state: ${isOpen ? 'OPEN' : 'CLOSED'}`)
}
// Example: Door opened
updateContactState(true) // Sends stateValue: false to Matter
// Example: Door closed
updateContactState(false) // Sends stateValue: true to Matterclusters: {
booleanState: {
stateValue: true, // true = closed/normal (safe default)
},
}Handler: Contact sensors are read-only (no handlers needed).
| Property | Value |
|---|---|
| Device Type |
api.matter.deviceTypes.MotionSensor (with OccupancySensing cluster) |
| Description | A sensor that detects occupancy/motion using PIR, ultrasonic, or physical contact methods. |
| Matter Specification | § 7.3 |
Note: Matter.js API calls this device type "MotionSensor" but it's actually an Occupancy Sensor - this is how it appears in Apple Home and other Matter controllers.
Detects occupancy using various sensing methods.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
occupancy.occupied |
boolean |
true, false
|
Occupancy detected (true=occupied, false=clear) |
occupancySensorType |
number | 0-2 | Sensor type (0=PIR, 1=Ultrasonic, 2=Physical) |
occupancySensorTypeBitmap |
object | See below | Bitmap of supported sensor types |
Occupancy Sensor Type Bitmap:
{
pir: true, // Passive infrared
ultrasonic: false, // Ultrasonic
physicalContact: false, // Physical contact
}const isOccupied = accessory.clusters.occupancySensing.occupancy.occupied// When your physical sensor detects motion/occupancy
mqttClient.on('message', async (topic, message) => {
const detected = message.toString() === 'motion'
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.OccupancySensing,
{ occupancy: { occupied: detected } }
)
log.info(`Occupancy: ${detected ? 'detected' : 'clear'}`)
})// Configure OccupancySensor with PIR feature
const OccupancySensingServer = api.matter.deviceTypes.MotionSensor.requirements.OccupancySensingServer
const OccupancySensorWithPIR = api.matter.deviceTypes.MotionSensor.with(
OccupancySensingServer.with('PassiveInfrared'),
)
{
deviceType: OccupancySensorWithPIR,
clusters: {
occupancySensing: {
occupancy: {
occupied: false, // No occupancy detected initially
},
occupancySensorType: 0, // PIR
occupancySensorTypeBitmap: {
pir: true,
ultrasonic: false,
physicalContact: false,
},
},
},
}Handler: Occupancy sensors are read-only (no handlers needed).
| Property | Value |
|---|---|
| Device Type | api.matter.deviceTypes.LightSensor |
| Description | A sensor that measures ambient light levels. |
| Matter Specification | § 7.2 |
Measures illuminance (light level) in lux.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
measuredValue |
number | 0-65534 | Current light level (logarithmic scale) ¹ |
minMeasuredValue |
number | 1-65533 | Minimum measurable light level |
maxMeasuredValue |
number | 2-65534 | Maximum measurable light level |
¹ The measuredValue uses a logarithmic scale: value = 10000 × log₁₀(lux)
Value Conversion:
// Lux to Matter value
const matterValue = Math.round(10000 * Math.log10(lux))
// Matter value to Lux
const lux = 10 ** (matterValue / 10000)const matterValue = accessory.clusters.illuminanceMeasurement.measuredValue
const lux = 10 ** (matterValue / 10000)
log.info(`Light level: ${lux.toFixed(1)} lux`)// When your physical sensor reports a new light level
async function updateIlluminance(lux: number) {
const value = Math.round(10000 * Math.log10(lux))
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.IlluminanceMeasurement,
{ measuredValue: value }
)
log.info(`Illuminance: ${lux} lux`)
}
// Example: 500 lux
updateIlluminance(500) // Sends value: ~27000clusters: {
illuminanceMeasurement: {
measuredValue: 5000, // ~3.16 lux
minMeasuredValue: 1, // Minimum
maxMeasuredValue: 65534, // Maximum
},
}Handler: Light sensors are read-only (no handlers needed).
| Property | Value |
|---|---|
| Device Type | api.matter.deviceTypes.TemperatureSensor |
| Description | A sensor that measures ambient temperature. |
| Matter Specification | § 7.4 |
Measures temperature in degrees Celsius.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
measuredValue |
number | -27315-32767 | Current temperature (hundredths of °C) ¹ |
minMeasuredValue |
number | -27315-32767 | Minimum measurable temperature |
maxMeasuredValue |
number | -27315-32767 | Maximum measurable temperature |
¹ Temperature values are in hundredths of degrees Celsius: 2100 = 21.00°C
const tempHundredths = accessory.clusters.temperatureMeasurement.measuredValue
const celsius = tempHundredths / 100
log.info(`Temperature: ${celsius}°C`)// When your physical sensor reports a new temperature
async function updateTemperature(celsius: number) {
const value = Math.round(celsius * 100)
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.TemperatureMeasurement,
{ measuredValue: value }
)
log.info(`Temperature: ${celsius}°C`)
}
// Example: 21.5°C
updateTemperature(21.5) // Sends value: 2150clusters: {
temperatureMeasurement: {
measuredValue: 2100, // 21.00°C
minMeasuredValue: -5000, // -50.00°C
maxMeasuredValue: 10000, // 100.00°C
},
}Handler: Temperature sensors are read-only (no handlers needed).
| Property | Value |
|---|---|
| Device Type | api.matter.deviceTypes.HumiditySensor |
| Description | A sensor that measures relative humidity. |
| Matter Specification | § 7.7 |
Measures relative humidity as a percentage.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
measuredValue |
number | 0-10000 | Current humidity (hundredths of a percent) ¹ |
minMeasuredValue |
number | 0-9999 | Minimum measurable humidity |
maxMeasuredValue |
number | 1-10000 | Maximum measurable humidity |
¹ Humidity values are in hundredths of a percent: 5500 = 55.00%
const humidityHundredths = accessory.clusters.relativeHumidityMeasurement.measuredValue
const percent = humidityHundredths / 100
log.info(`Humidity: ${percent}%`)// When your physical sensor reports new humidity
async function updateHumidity(percent: number) {
const value = Math.round(percent * 100)
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.RelativeHumidityMeasurement,
{ measuredValue: value }
)
log.info(`Humidity: ${percent}%`)
}
// Example: 65.5%
updateHumidity(65.5) // Sends value: 6550clusters: {
relativeHumidityMeasurement: {
measuredValue: 5500, // 55%
minMeasuredValue: 0, // 0%
maxMeasuredValue: 10000, // 100%
},
}Handler: Humidity sensors are read-only (no handlers needed).
| Property | Value |
|---|---|
| Device Type |
api.matter.deviceTypes.SmokeSensor (with SmokeAlarm and CoAlarm features) |
| Description | A combined smoke and carbon monoxide alarm sensor. |
| Matter Specification | § 7.9 |
Detects smoke and carbon monoxide with three alarm states.
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
smokeState |
number | 0-2 | Smoke alarm state (0=Normal, 1=Warning, 2=Critical) |
coState |
number | 0-2 | CO alarm state (0=Normal, 1=Warning, 2=Critical) |
batteryAlert |
number | 0-2 | Battery level alert |
deviceMuted |
number | 0-2 | Device mute status |
testInProgress |
boolean | true/false | Whether self-test is running |
hardwareFaultAlert |
boolean | true/false | Hardware fault detected |
endOfServiceAlert |
number | 0-2 | End of service life alert |
interconnectSmokeAlarm |
number | 0-2 | Interconnected smoke alarm status |
interconnectCoAlarm |
number | 0-2 | Interconnected CO alarm status |
contaminationState |
number | 0-2 | Sensor contamination state |
smokeSensitivityLevel |
number | 0-2 | Smoke sensitivity level |
expressedState |
number | 0-10 | Overall alarm state |
Alarm State Values:
| Value | State | Description |
|---|---|---|
| 0 | Normal | No alarm detected |
| 1 | Warning | Warning level detected |
| 2 | Critical | Critical level detected |
const smokeState = accessory.clusters.smokeCoAlarm.smokeState
const coState = accessory.clusters.smokeCoAlarm.coState
const stateNames = ['Normal', 'Warning', 'Critical']
log.info(`Smoke: ${stateNames[smokeState]}, CO: ${stateNames[coState]}`)// Update smoke alarm state
async function updateSmokeState(state: 0 | 1 | 2) {
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.SmokeCoAlarm,
{ smokeState: state }
)
const stateStr = ['Normal', 'Warning', 'Critical'][state]
log.info(`Smoke state: ${stateStr}`)
}
// Update CO alarm state
async function updateCOState(state: 0 | 1 | 2) {
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.SmokeCoAlarm,
{ coState: state }
)
const stateStr = ['Normal', 'Warning', 'Critical'][state]
log.info(`CO state: ${stateStr}`)
}
// Example: Smoke detected
updateSmokeState(2) // Critical// Configure Smoke/CO Alarm with both features
const SmokeCoAlarmServer = api.matter.deviceTypes.SmokeSensor.requirements.SmokeCoAlarmServer
const SmokeSensorWithBoth = api.matter.deviceTypes.SmokeSensor.with(
SmokeCoAlarmServer.with('SmokeAlarm', 'CoAlarm'),
)
{
deviceType: SmokeSensorWithBoth,
clusters: {
smokeCoAlarm: {
smokeState: 0, // Normal
coState: 0, // Normal
batteryAlert: 0, // Normal
deviceMuted: 0, // Not muted
testInProgress: false, // No test running
hardwareFaultAlert: false, // No fault
endOfServiceAlert: 0, // Normal
interconnectSmokeAlarm: 0, // Normal
interconnectCoAlarm: 0, // Normal
contaminationState: 0, // Normal
smokeSensitivityLevel: 1, // Standard sensitivity
expressedState: 0, // Normal
},
},
}Handler: Smoke/CO alarms are read-only (no handlers needed).
| Property | Value |
|---|---|
| Device Type | api.matter.deviceTypes.LeakSensor |
| Description | A sensor that detects water leaks. |
| Matter Specification | § 7.12 |
Represents water leak detection state using a boolean value.
NOTE: Unlike contact sensors, leak detectors use standard (non-inverted) semantics:
-
false= No leak detected / Dry (normal state) -
true= Leak detected / Wet (triggered state)
| Attribute | Type | Range/Values | Description |
|---|---|---|---|
stateValue |
boolean |
true, false
|
Leak state (true=leak, false=dry) |
const leakDetected = accessory.clusters.booleanState.stateValue
log.info(`Leak: ${leakDetected ? 'DETECTED' : 'None'}`)// When your physical sensor reports leak state
async function updateLeakState(leakDetected: boolean) {
await api.matter.updateAccessoryState(
uuid,
api.matter.clusterNames.BooleanState,
{ stateValue: leakDetected }
)
log.info(`Leak: ${leakDetected ? 'detected' : 'none'}`)
}
// Example: Leak detected
updateLeakState(true) // Sends stateValue: true
// Example: Leak cleared
updateLeakState(false) // Sends stateValue: falseclusters: {
booleanState: {
stateValue: false, // false = dry/normal (safe default)
},
}Handler: Leak sensors are read-only (no handlers needed).