UNPKG

matterbridge-dyson-robot

Version:

A Matterbridge plugin that connects Dyson robot vacuums and air treatment devices to the Matter smart home ecosystem via their local or cloud MQTT APIs.

101 lines 4.68 kB
// Matterbridge plugin for Dyson robot vacuum and air treatment devices // Copyright © 2025 Alexander Thoukydides import { AirQuality, ConcentrationMeasurement } from 'matterbridge/matter/clusters'; import { assertIsDefined, formatList } from './utils.js'; // Thresholds to map different pollutants to Air Quality levels: // co2r CO2 Common indoor air quality guidelines // hcho Formaldehyde WHO guidelines and typical concern levels // pm25 PM2.5 US EPA 24-hour AQI breakpoints * // pm10 PM10 US EPA 24-hour AQI breakpoints * // vact VOC Arbitrary mapping of unknown index values // noxl NOx Arbitrary mapping of unknown index values // pact Dust Arbitrary mapping of unknown index values // * = https://aqs.epa.gov/aqsweb/documents/codetables/aqi_breakpoints.html const AQI_COLUMNS = ['co2r', 'hcho', 'pm25', 'pm10', 'vact', 'noxl', 'pact' ]; const AQI_THRESHOLDS = [ // ppm µg/m³ µg/m³ µg/m³ 0~99 0~99 0~9 [AirQuality.AirQualityEnum.Good, [800, 10, 9.0, 54, 10, 10, 0]], [AirQuality.AirQualityEnum.Fair, [1000, 30, 35.4, 154, 25, 25, 1]], [AirQuality.AirQualityEnum.Moderate, [1500, 60, 55.4, 254, 50, 50, 3]], [AirQuality.AirQualityEnum.Poor, [2500, 100, 125.4, 354, 75, 75, 5]], [AirQuality.AirQualityEnum.VeryPoor, [5000, 200, 225.4, 424, 90, 90, 7]] // (AirQuality.AirQualityEnum.ExtremelyPoor for anything higher) ]; // Mapping from Air Quality to Concentration Measurement levels const LEVEL_MAP = { [AirQuality.AirQualityEnum.Unknown]: ConcentrationMeasurement.LevelValue.Unknown, [AirQuality.AirQualityEnum.Good]: ConcentrationMeasurement.LevelValue.Low, [AirQuality.AirQualityEnum.Fair]: ConcentrationMeasurement.LevelValue.Low, [AirQuality.AirQualityEnum.Moderate]: ConcentrationMeasurement.LevelValue.Medium, [AirQuality.AirQualityEnum.Poor]: ConcentrationMeasurement.LevelValue.High, [AirQuality.AirQualityEnum.VeryPoor]: ConcentrationMeasurement.LevelValue.High, [AirQuality.AirQualityEnum.ExtremelyPoor]: ConcentrationMeasurement.LevelValue.Critical }; // Map numeric sensor values to Air Quality Sensor enum values function mapToAirQualitySensorEnum(sensors) { const aqiValues = new Map(); AQI_COLUMNS.forEach((key, index) => { const value = sensors[key]; if (value === undefined) return; if (typeof value === 'number') { const aqiRow = AQI_THRESHOLDS.find(([, thresholds]) => value <= (thresholds[index] ?? Infinity)); const aqi = aqiRow ? aqiRow[0] : AirQuality.AirQualityEnum.ExtremelyPoor; aqiValues.set(key, aqi); } else { aqiValues.set(key, AirQuality.AirQualityEnum.Unknown); } }); return aqiValues; } // Determine the overall air quality as the worst of the available data function worstAirQuality(log, aqiValues) { const values = []; let aqi = AirQuality.AirQualityEnum.Unknown; aqiValues.forEach((aqiValue, key) => { if (aqiValue > aqi) aqi = aqiValue; values.push(`${key}:${AirQuality.AirQualityEnum[aqiValue]}`); }); log.debug(`Air quality is ${AirQuality.AirQualityEnum[aqi]} (${formatList(values)})`); return aqi; } // Map Air Quality Sensor values to Concentration Measurement levels function mapToAirQualityLevelEnum(aqiValues) { const levelValues = new Map(); aqiValues.forEach((aqi, key) => { levelValues.set(key, LEVEL_MAP[aqi]); }); return levelValues; } export function numeric(value, factor = 1) { if (value === undefined) return undefined; if (typeof value === 'string') return null; return Math.round(value * factor); } // Map the Dyson sensor data to Matter attribute values export function mapDysonAirSensorStatus(log, status) { const { tact, hact, co2r, hcho, pm25, pm10 } = status; assertIsDefined(tact); assertIsDefined(hact); // Map the available measurements to Air Quality const aqiValues = mapToAirQualitySensorEnum(status); const levelValues = mapToAirQualityLevelEnum(aqiValues); // Return the mapped sensor readings return { airQuality: worstAirQuality(log, aqiValues), temperature: numeric(tact, 100), // centi-°C humidity: numeric(hact, 100), // centi-% voc: levelValues.get('vact'), co2: numeric(co2r), // ppm nox: levelValues.get('noxl'), hcho: numeric(hcho), // µg/m³ pm25: numeric(pm25), // µg/m³ pm10: numeric(pm10) // µg/m³ }; } //# sourceMappingURL=dyson-device-air-quality.js.map