diff --git a/.homeycompose/flow/actions/alarm_switch_off.json b/.homeycompose/flow/actions/alarm_switch_off.json index 6d830064..f8f16310 100644 --- a/.homeycompose/flow/actions/alarm_switch_off.json +++ b/.homeycompose/flow/actions/alarm_switch_off.json @@ -7,7 +7,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "onoff.alarm_switch" }, "title": { diff --git a/.homeycompose/flow/actions/alarm_switch_on.json b/.homeycompose/flow/actions/alarm_switch_on.json index 35261020..fb6b040f 100644 --- a/.homeycompose/flow/actions/alarm_switch_on.json +++ b/.homeycompose/flow/actions/alarm_switch_on.json @@ -7,7 +7,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "onoff.alarm_switch" }, "title": { diff --git a/.homeycompose/flow/actions/send_command_boolean.json b/.homeycompose/flow/actions/send_command_boolean.json index 6c93d45c..b54014c5 100644 --- a/.homeycompose/flow/actions/send_command_boolean.json +++ b/.homeycompose/flow/actions/send_command_boolean.json @@ -13,7 +13,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_json.json b/.homeycompose/flow/actions/send_command_json.json index 6d40296c..8a1f773f 100644 --- a/.homeycompose/flow/actions/send_command_json.json +++ b/.homeycompose/flow/actions/send_command_json.json @@ -13,7 +13,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_number.json b/.homeycompose/flow/actions/send_command_number.json index 3387a426..46f96db8 100644 --- a/.homeycompose/flow/actions/send_command_number.json +++ b/.homeycompose/flow/actions/send_command_number.json @@ -13,7 +13,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_string.json b/.homeycompose/flow/actions/send_command_string.json index 657709d9..3b705986 100644 --- a/.homeycompose/flow/actions/send_command_string.json +++ b/.homeycompose/flow/actions/send_command_string.json @@ -13,7 +13,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/set_sensor_alarm_bright.json b/.homeycompose/flow/actions/set_sensor_alarm_bright.json index 061d40b5..4e78f8e5 100644 --- a/.homeycompose/flow/actions/set_sensor_alarm_bright.json +++ b/.homeycompose/flow/actions/set_sensor_alarm_bright.json @@ -10,7 +10,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.alarm_bright" }, "title": { diff --git a/.homeycompose/flow/actions/set_sensor_alarm_ringtone.json b/.homeycompose/flow/actions/set_sensor_alarm_ringtone.json index 7f1fb096..2fb84360 100644 --- a/.homeycompose/flow/actions/set_sensor_alarm_ringtone.json +++ b/.homeycompose/flow/actions/set_sensor_alarm_ringtone.json @@ -10,7 +10,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.alarm_ringtone" }, "title": { diff --git a/.homeycompose/flow/actions/set_sensor_alarm_time.json b/.homeycompose/flow/actions/set_sensor_alarm_time.json index e80b5b49..f95075ff 100644 --- a/.homeycompose/flow/actions/set_sensor_alarm_time.json +++ b/.homeycompose/flow/actions/set_sensor_alarm_time.json @@ -10,7 +10,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.alarm_time" }, "title": { diff --git a/.homeycompose/flow/actions/set_sensor_alarm_volume.json b/.homeycompose/flow/actions/set_sensor_alarm_volume.json index c9bd1338..88e64778 100644 --- a/.homeycompose/flow/actions/set_sensor_alarm_volume.json +++ b/.homeycompose/flow/actions/set_sensor_alarm_volume.json @@ -10,7 +10,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.alarm_volume" }, "title": { diff --git a/.homeycompose/flow/actions/set_sensor_muffling.json b/.homeycompose/flow/actions/set_sensor_muffling.json index 2f9d6efb..b9f9e8af 100644 --- a/.homeycompose/flow/actions/set_sensor_muffling.json +++ b/.homeycompose/flow/actions/set_sensor_muffling.json @@ -10,7 +10,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.muffling" }, "title": { diff --git a/.homeycompose/flow/triggers/receive_status_boolean.json b/.homeycompose/flow/triggers/receive_status_boolean.json index 56f959d5..fd88690d 100644 --- a/.homeycompose/flow/triggers/receive_status_boolean.json +++ b/.homeycompose/flow/triggers/receive_status_boolean.json @@ -13,7 +13,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_json.json b/.homeycompose/flow/triggers/receive_status_json.json index fe1219fd..919c44c5 100644 --- a/.homeycompose/flow/triggers/receive_status_json.json +++ b/.homeycompose/flow/triggers/receive_status_json.json @@ -13,7 +13,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_number.json b/.homeycompose/flow/triggers/receive_status_number.json index 6963729d..618af34b 100644 --- a/.homeycompose/flow/triggers/receive_status_number.json +++ b/.homeycompose/flow/triggers/receive_status_number.json @@ -13,7 +13,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_string.json b/.homeycompose/flow/triggers/receive_status_string.json index 367e9d71..1ae3134e 100644 --- a/.homeycompose/flow/triggers/receive_status_string.json +++ b/.homeycompose/flow/triggers/receive_status_string.json @@ -13,7 +13,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" diff --git a/app.json b/app.json index 2cad655e..b4f8f535 100644 --- a/app.json +++ b/app.json @@ -438,7 +438,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" @@ -479,7 +479,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" @@ -520,7 +520,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" @@ -561,7 +561,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" @@ -1305,7 +1305,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "onoff.alarm_switch" }, "title": { @@ -1324,7 +1324,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "onoff.alarm_switch" }, "title": { @@ -1349,7 +1349,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" @@ -1387,7 +1387,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" @@ -1425,7 +1425,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" @@ -1463,7 +1463,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_smoke|siren|socket|thermostat|window_coverings" + "driver_id": "button|camera|circuit_breaker|dehumidifier|dimmer|doorbell|fan|garage_door|heater|humidifier|irrigator|light|other|sensor_climate|sensor_co2|sensor_contact|sensor_human|sensor_motion|sensor_pm2.5|sensor_smoke|siren|socket|thermostat|window_coverings" }, "title": { "en": "Device" @@ -1498,7 +1498,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.alarm_bright" }, "title": { @@ -1533,7 +1533,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.alarm_ringtone" }, "title": { @@ -1584,7 +1584,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.alarm_time" }, "title": { @@ -1618,7 +1618,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.alarm_volume" }, "title": { @@ -1673,7 +1673,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "sensor_smoke|sensor_co2", + "driver_id": "sensor_co2|sensor_pm2.5|sensor_smoke", "capabilities": "hidden.muffling" }, "title": { @@ -6656,6 +6656,272 @@ } ] }, + { + "capabilities": [ + "alarm_pm25", + "measure_pm25" + ], + "connectivity": [ + "cloud" + ], + "platforms": [ + "local", + "cloud" + ], + "images": { + "small": "/drivers/sensor_pm2.5/assets/images/small.png", + "large": "/drivers/sensor_pm2.5/assets/images/large.png", + "xlarge": "/drivers/sensor_pm2.5/assets/images/xlarge.png" + }, + "pair": [ + { + "id": "welcome", + "navigation": { + "next": "login_oauth2" + } + }, + { + "id": "login_oauth2", + "template": "login_oauth2" + }, + { + "id": "list_devices", + "template": "list_devices", + "navigation": { + "next": "add_devices" + } + }, + { + "id": "add_devices", + "template": "add_devices" + } + ], + "repair": [ + { + "id": "login_oauth2", + "template": "login_oauth2" + } + ], + "class": "sensor", + "name": { + "en": "PM2.5 Detector", + "nl": "PM2.5 Meter" + }, + "id": "sensor_pm2.5", + "settings": [ + { + "id": "measure_temperature_scaling", + "label": { + "en": "Measured Temperature Scale" + }, + "hint": { + "en": "By how much the temperature measured by the device is scaled." + }, + "value": "1", + "type": "dropdown", + "values": [ + { + "id": "0", + "label": { + "en": "1" + } + }, + { + "id": "1", + "label": { + "en": "1/10" + } + }, + { + "id": "2", + "label": { + "en": "1/100" + } + }, + { + "id": "3", + "label": { + "en": "1/1000" + } + } + ] + }, + { + "id": "measure_humidity_scaling", + "label": { + "en": "Measured Humidity Scale" + }, + "hint": { + "en": "By how much the humidity measured by the device is scaled." + }, + "value": "1", + "type": "dropdown", + "values": [ + { + "id": "0", + "label": { + "en": "1" + } + }, + { + "id": "1", + "label": { + "en": "1/10" + } + }, + { + "id": "2", + "label": { + "en": "1/100" + } + }, + { + "id": "3", + "label": { + "en": "1/1000" + } + } + ] + }, + { + "id": "use_alarm_timeout", + "type": "checkbox", + "hint": { + "en": "Turn the alarm off a set time after the start signal, even if no end signal is received." + }, + "label": { + "en": "Use Alarm Timeout" + }, + "value": false + }, + { + "id": "alarm_timeout", + "type": "number", + "label": { + "en": "Alarm Timeout" + }, + "value": 10, + "min": 1, + "units": { + "en": "seconds" + } + }, + { + "id": "sensor_alarm_group", + "type": "group", + "label": { + "en": "NOTE: Some settings are not supported by every device." + }, + "children": [ + { + "id": "muffling", + "type": "checkbox", + "label": { + "en": "Mute Alarm" + } + }, + { + "id": "alarm_volume", + "type": "dropdown", + "label": { + "en": "Alarm Volume" + }, + "values": [ + { + "id": "low", + "label": { + "en": "Low" + } + }, + { + "id": "middle", + "label": { + "en": "Middle" + } + }, + { + "id": "high", + "label": { + "en": "High" + } + }, + { + "id": "mute", + "label": { + "en": "Mute" + } + } + ] + }, + { + "id": "alarm_time", + "type": "number", + "label": { + "en": "Alarm Duration" + }, + "min": 1, + "step": 1, + "value": 1, + "units": { + "en": "seconds" + } + }, + { + "id": "alarm_ringtone", + "type": "dropdown", + "label": { + "en": "Alarm Tone" + }, + "values": [ + { + "id": "1", + "label": "1" + }, + { + "id": "2", + "label": "2" + }, + { + "id": "3", + "label": "3" + }, + { + "id": "4", + "label": "4" + }, + { + "id": "5", + "label": "5" + } + ] + }, + { + "id": "alarm_bright", + "type": "number", + "label": { + "en": "Alarm Brightness" + }, + "min": 0, + "step": 1, + "max": 100, + "value": 100, + "units": "%" + } + ] + }, + { + "id": "deviceSpecification", + "type": "label", + "label": { + "en": "Device Specification" + }, + "hint": { + "en": "The Tuya specification of this device" + }, + "value": "" + } + ] + }, { "capabilities": [ "alarm_smoke" diff --git a/drivers/sensor_pm2.5/SensorPm25Constants.ts b/drivers/sensor_pm2.5/SensorPm25Constants.ts new file mode 100644 index 00000000..ac90497a --- /dev/null +++ b/drivers/sensor_pm2.5/SensorPm25Constants.ts @@ -0,0 +1,26 @@ +import { HomeySensorSettings, TuyaSensorSettings } from '../../lib/sensor/TuyaSensorConstants'; +import { ScaledProperty } from '../../types/TuyaTypes'; + +export const SENSOR_PM25_CAPABILITY_MAPPING = { + pm25_state: 'alarm_pm25', + pm25_value: 'measure_pm25', // μg/m³ + ch2o_value: 'measure_ch2o', // ppm + voc_value: 'measure_tvoc', // ppm + co2_value: 'measure_co2', // ppm + pm1: 'measure_pm1', // μg/m³ + pm10: 'measure_pm10', // μg/m³ + temp_current: 'measure_temperature', + humidity_value: 'measure_humidity', +} as const; + +export const SENSOR_PM25_CAPABILITIES = { + read_only: ['pm25_value', 'ch2o_value', 'voc_value', 'co2_value', 'pm1', 'pm10'], + read_only_scaled: ['temp_current', 'humidity_value'], +} as const; + +export type HomeyPM25SensorSettings = { + measure_temperature_scaling: ScaledProperty; + measure_humidity_scaling: ScaledProperty; +} & HomeySensorSettings; + +export type TuyaPM25SensorSettings = TuyaSensorSettings; diff --git a/drivers/sensor_pm2.5/assets/icon.svg b/drivers/sensor_pm2.5/assets/icon.svg new file mode 100644 index 00000000..74872e0b --- /dev/null +++ b/drivers/sensor_pm2.5/assets/icon.svg @@ -0,0 +1 @@ + diff --git a/drivers/sensor_pm2.5/assets/images/large.png b/drivers/sensor_pm2.5/assets/images/large.png new file mode 100644 index 00000000..d5fd4a97 Binary files /dev/null and b/drivers/sensor_pm2.5/assets/images/large.png differ diff --git a/drivers/sensor_pm2.5/assets/images/small.png b/drivers/sensor_pm2.5/assets/images/small.png new file mode 100644 index 00000000..982e9d95 Binary files /dev/null and b/drivers/sensor_pm2.5/assets/images/small.png differ diff --git a/drivers/sensor_pm2.5/assets/images/xlarge.png b/drivers/sensor_pm2.5/assets/images/xlarge.png new file mode 100644 index 00000000..abe8e68c Binary files /dev/null and b/drivers/sensor_pm2.5/assets/images/xlarge.png differ diff --git a/drivers/sensor_pm2.5/device.ts b/drivers/sensor_pm2.5/device.ts new file mode 100644 index 00000000..3e97805a --- /dev/null +++ b/drivers/sensor_pm2.5/device.ts @@ -0,0 +1,56 @@ +import TuyaOAuth2DeviceSensor from '../../lib/sensor/TuyaOAuth2DeviceSensor'; +import { SettingsEvent, TuyaStatus } from '../../types/TuyaTypes'; +import { HomeySensorSettings, SENSOR_SETTING_LABELS } from '../../lib/sensor/TuyaSensorConstants'; +import * as Util from '../../lib/TuyaOAuth2Util'; +import { + HomeyPM25SensorSettings, + SENSOR_PM25_CAPABILITIES, + SENSOR_PM25_CAPABILITY_MAPPING, +} from './SensorPm25Constants'; +import { constIncludes, getFromMap } from '../../lib/TuyaOAuth2Util'; + +module.exports = class TuyaOAuth2DeviceSensorPM25 extends TuyaOAuth2DeviceSensor { + async onOAuth2Init(): Promise { + await this.initAlarm('alarm_pm25').catch(this.error); + return super.onOAuth2Init(); + } + + async onTuyaStatus(status: TuyaStatus, changedStatusCodes: string[]): Promise { + await super.onTuyaStatus(status, changedStatusCodes); + + for (const tuyaCapability in status) { + const value = status[tuyaCapability]; + const homeyCapability = getFromMap(SENSOR_PM25_CAPABILITY_MAPPING, tuyaCapability); + + if ( + tuyaCapability === 'pm25_state' && + (!this.getSetting('use_alarm_timeout') || changedStatusCodes.includes(tuyaCapability)) + ) { + await this.setAlarmCapabilityValue(SENSOR_PM25_CAPABILITY_MAPPING[tuyaCapability], value === 'alarm').catch( + this.error, + ); + } + + if (constIncludes(SENSOR_PM25_CAPABILITIES.read_only, tuyaCapability) && homeyCapability) { + await this.safeSetCapabilityValue(homeyCapability, value); + } + + if (constIncludes(SENSOR_PM25_CAPABILITIES.read_only_scaled, tuyaCapability) && homeyCapability) { + const scaling = 10.0 ** Number.parseInt(this.getSetting(`${homeyCapability}_scaling`) ?? '0', 10); + await this.safeSetCapabilityValue(homeyCapability, (status[tuyaCapability] as number) / scaling); + } + } + } + + async onSettings(event: SettingsEvent): Promise { + for (const tuyaCapability of SENSOR_PM25_CAPABILITIES.read_only_scaled) { + const homeyCapability = SENSOR_PM25_CAPABILITY_MAPPING[tuyaCapability]; + await Util.handleScaleSetting(this, event, `${homeyCapability}_scaling`, homeyCapability); + } + + const [unsupportedSettings, unsupportedValues] = await super.onAlarmSettings( + event as unknown as SettingsEvent, + ); + return Util.reportUnsupportedSettings(this, unsupportedSettings, unsupportedValues, SENSOR_SETTING_LABELS); + } +}; diff --git a/drivers/sensor_pm2.5/driver.compose.json b/drivers/sensor_pm2.5/driver.compose.json new file mode 100644 index 00000000..269caaf4 --- /dev/null +++ b/drivers/sensor_pm2.5/driver.compose.json @@ -0,0 +1,9 @@ +{ + "$extends": "tuya", + "class": "sensor", + "name": { + "en": "PM2.5 Detector", + "nl": "PM2.5 Meter" + }, + "capabilities": ["alarm_pm25", "measure_pm25"] +} diff --git a/drivers/sensor_pm2.5/driver.settings.compose.json b/drivers/sensor_pm2.5/driver.settings.compose.json new file mode 100644 index 00000000..9c6a2e27 --- /dev/null +++ b/drivers/sensor_pm2.5/driver.settings.compose.json @@ -0,0 +1,36 @@ +[ + { + "$extends": "scaledProperty", + "id": "measure_temperature_scaling", + "label": { + "en": "Measured Temperature Scale" + }, + "hint": { + "en": "By how much the temperature measured by the device is scaled." + }, + "value": "1" + }, + { + "$extends": "scaledProperty", + "id": "measure_humidity_scaling", + "label": { + "en": "Measured Humidity Scale" + }, + "hint": { + "en": "By how much the humidity measured by the device is scaled." + }, + "value": "1" + }, + { + "$extends": "useAlarmTimeout" + }, + { + "$extends": "alarmTimeout" + }, + { + "$extends": "sensor_alarm_group" + }, + { + "$extends": "deviceSpecification" + } +] diff --git a/drivers/sensor_pm2.5/driver.ts b/drivers/sensor_pm2.5/driver.ts new file mode 100644 index 00000000..7a2d16e2 --- /dev/null +++ b/drivers/sensor_pm2.5/driver.ts @@ -0,0 +1,59 @@ +import { DEVICE_CATEGORIES } from '../../lib/TuyaOAuth2Constants'; +import { ListDeviceProperties } from '../../lib/TuyaOAuth2Driver'; +import TuyaOAuth2DriverSensor from '../../lib/sensor/TuyaOAuth2DriverSensor'; +import { + type TuyaDeviceDataPointResponse, + TuyaDeviceResponse, + TuyaDeviceSpecificationResponse, +} from '../../types/TuyaApiTypes'; +import { constIncludes, getFromMap } from '../../lib/TuyaOAuth2Util'; +import { SENSOR_PM25_CAPABILITY_MAPPING } from './SensorPm25Constants'; +import { CLIMATE_SENSOR_CAPABILITIES } from '../sensor_climate/TuyaClimateSensorConstants'; + +module.exports = class TuyaOAuth2DriverSensorPM25 extends TuyaOAuth2DriverSensor { + TUYA_DEVICE_CATEGORIES = [DEVICE_CATEGORIES.SECURITY_VIDEO_SURV.PM25_DETECTOR, 'pm2.5'] as const; + + onTuyaPairListDeviceProperties( + device: TuyaDeviceResponse, + specifications?: TuyaDeviceSpecificationResponse, + dataPoints?: TuyaDeviceDataPointResponse, + ): ListDeviceProperties { + const props = super.onTuyaPairListDeviceProperties(device, specifications, dataPoints); + + for (const status of device.status) { + const tuyaCapability = status.code; + const homeyCapability = getFromMap(SENSOR_PM25_CAPABILITY_MAPPING, tuyaCapability); + + if (homeyCapability) { + props.store.tuya_capabilities.push(tuyaCapability); + props.capabilities.push(homeyCapability); + } + } + + if (!specifications || !specifications.status) { + return props; + } + + for (const specification of specifications.status) { + const tuyaCapability = specification.code; + const values = JSON.parse(specification.values); + const homeyCapability = getFromMap(SENSOR_PM25_CAPABILITY_MAPPING, tuyaCapability); + + if (tuyaCapability === 'pm25_state') { + if (!values.range.includes('normal')) { + props.settings['use_alarm_timeout'] = true; + } + } + + if (constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability)) { + if ([0, 1, 2, 3].includes(values.scale)) { + props.settings[`${homeyCapability}_scaling`] = `${values.scale}`; + } else { + this.error(`Unsupported ${tuyaCapability} scale:`, values.scale); + } + } + } + + return props; + } +}; diff --git a/drivers/sensor_pm2.5/pair/welcome.assets/chevron-right.png b/drivers/sensor_pm2.5/pair/welcome.assets/chevron-right.png new file mode 100644 index 00000000..d7331b23 Binary files /dev/null and b/drivers/sensor_pm2.5/pair/welcome.assets/chevron-right.png differ diff --git a/drivers/sensor_pm2.5/pair/welcome.assets/logos.png b/drivers/sensor_pm2.5/pair/welcome.assets/logos.png new file mode 100644 index 00000000..faefa496 Binary files /dev/null and b/drivers/sensor_pm2.5/pair/welcome.assets/logos.png differ diff --git a/drivers/sensor_pm2.5/pair/welcome.html b/drivers/sensor_pm2.5/pair/welcome.html new file mode 100644 index 00000000..14a7e06e --- /dev/null +++ b/drivers/sensor_pm2.5/pair/welcome.html @@ -0,0 +1,60 @@ + + +

+ +

+ +

+ +

+ + + + +

+ +

+ +