From 6632229bcb4b8a2956f99cb10f667df7e732c9ab Mon Sep 17 00:00:00 2001 From: Joost Loohuis Date: Wed, 14 Aug 2024 15:49:31 +0200 Subject: [PATCH 1/6] Add temp/humidity sensor --- .../flow/actions/send_command_boolean.json | 2 +- .../flow/actions/send_command_json.json | 2 +- .../flow/actions/send_command_number.json | 2 +- .../flow/actions/send_command_string.json | 2 +- .../flow/triggers/receive_status_boolean.json | 2 +- .../flow/triggers/receive_status_json.json | 2 +- .../flow/triggers/receive_status_number.json | 2 +- .../flow/triggers/receive_status_string.json | 2 +- app.json | 190 +++++++++++++++++- .../TuyaTemperatureHumiditySensorConstants.ts | 33 +++ drivers/sensor_temperature_humidity/device.ts | 59 ++++++ .../driver.compose.json | 8 + .../driver.settings.compose.json | 116 +++++++++++ drivers/sensor_temperature_humidity/driver.ts | 50 +++++ .../pair/welcome.assets/chevron-right.png | Bin 0 -> 647 bytes .../pair/welcome.assets/logos.png | Bin 0 -> 66184 bytes .../pair/welcome.html | 60 ++++++ 17 files changed, 516 insertions(+), 16 deletions(-) create mode 100644 drivers/sensor_temperature_humidity/TuyaTemperatureHumiditySensorConstants.ts create mode 100644 drivers/sensor_temperature_humidity/device.ts create mode 100644 drivers/sensor_temperature_humidity/driver.compose.json create mode 100644 drivers/sensor_temperature_humidity/driver.settings.compose.json create mode 100644 drivers/sensor_temperature_humidity/driver.ts create mode 100644 drivers/sensor_temperature_humidity/pair/welcome.assets/chevron-right.png create mode 100644 drivers/sensor_temperature_humidity/pair/welcome.assets/logos.png create mode 100644 drivers/sensor_temperature_humidity/pair/welcome.html diff --git a/.homeycompose/flow/actions/send_command_boolean.json b/.homeycompose/flow/actions/send_command_boolean.json index 1b1d1703..cb473df3 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_json.json b/.homeycompose/flow/actions/send_command_json.json index 4e8b1e7c..17e6b6d9 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_number.json b/.homeycompose/flow/actions/send_command_number.json index fa83c40f..995ce642 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_string.json b/.homeycompose/flow/actions/send_command_string.json index c37e8884..a4a6cd5f 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_boolean.json b/.homeycompose/flow/triggers/receive_status_boolean.json index 7d0007e4..a2558e77 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_json.json b/.homeycompose/flow/triggers/receive_status_json.json index d8f7be25..0edf415c 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_number.json b/.homeycompose/flow/triggers/receive_status_number.json index 01714a69..85600c79 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_string.json b/.homeycompose/flow/triggers/receive_status_string.json index b6865d44..50c2881c 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" diff --git a/app.json b/app.json index 998f2ffd..bea6f75b 100644 --- a/app.json +++ b/app.json @@ -400,7 +400,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" @@ -441,7 +441,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" @@ -482,7 +482,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" @@ -523,7 +523,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" @@ -920,7 +920,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" @@ -958,7 +958,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" @@ -996,7 +996,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" @@ -1034,7 +1034,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" }, "title": { "en": "Device" @@ -3188,6 +3188,180 @@ } ] }, + { + "capabilities": [], + "connectivity": [ + "cloud" + ], + "platforms": [ + "local", + "cloud" + ], + "images": { + "small": "/drivers/sensor_temperature_humidity/assets/images/small.png", + "large": "/drivers/sensor_temperature_humidity/assets/images/large.png", + "xlarge": "/drivers/sensor_temperature_humidity/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": "Temperature/Humidity Sensor", + "nl": "Temperatuur/luchtvochtigheidssensor" + }, + "id": "sensor_temperature_humidity", + "settings": [ + { + "id": "deviceSpecification", + "type": "label", + "label": { + "en": "Device Specification" + }, + "hint": { + "en": "The Tuya specification of this device" + }, + "value": "" + }, + { + "id": "va_temperature_scaling", + "type": "dropdown", + "label": { + "en": "Measured Temperature Scale" + }, + "hint": { + "en": "By how much the temperature measured by the device is scaled." + }, + "value": "1", + "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": "va_humidity_scaling", + "type": "dropdown", + "label": { + "en": "Measured Humidity Scale" + }, + "hint": { + "en": "By how much the humidity measured by the device is scaled." + }, + "value": "1", + "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": "bright_value_scaling", + "type": "dropdown", + "label": { + "en": "Measured Brightness Scale" + }, + "hint": { + "en": "By how much the brightness measured by the device is scaled." + }, + "value": "0", + "values": [ + { + "id": "0", + "label": { + "en": "1" + } + }, + { + "id": "1", + "label": { + "en": "1/10" + } + }, + { + "id": "2", + "label": { + "en": "1/100" + } + }, + { + "id": "3", + "label": { + "en": "1/1000" + } + } + ] + } + ] + }, { "capabilities": [ "onoff" diff --git a/drivers/sensor_temperature_humidity/TuyaTemperatureHumiditySensorConstants.ts b/drivers/sensor_temperature_humidity/TuyaTemperatureHumiditySensorConstants.ts new file mode 100644 index 00000000..f90b1278 --- /dev/null +++ b/drivers/sensor_temperature_humidity/TuyaTemperatureHumiditySensorConstants.ts @@ -0,0 +1,33 @@ +/** capabilities that map one to one to a Homey capability */ +export const TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES = { + read_write: ['switch'], + read_only: ['temper_alarm', 'battery_percentage'], + read_only_scaled: ['va_temperature', 'va_humidity', 'bright_value'], + setting: [], +} as const; + +export const TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING = { + switch: 'onoff', + temper_alarm: 'alarm_tamper', + va_temperature: 'measure_temperature', + va_humidity: 'measure_humidity', + bright_value: 'measure_luminance', + battery_state: 'alarm_battery', + battery_percentage: 'measure_battery', + battery_value: 'measure_battery', + va_battery: 'measure_battery', +} as const; + +export const TEMPERATURE_HUMIDITY_SENSOR_SETTING_LABELS = { + va_temperature_scaling: 'Measured Temperature Scale', + va_humidity_scaling: 'Measured Humidity Scale', + bright_value_scaling: 'Measured Brightness Scale', +} as const; + +export type HomeyTemperatureHumiditySensorSettings = { + va_temperature_scaling: '0' | '1' | '2' | '3'; + va_humidity_scaling: '0' | '1' | '2' | '3'; + bright_value_scaling: '0' | '1' | '2' | '3'; +}; + +export type TuyaTemperatureHumiditySensorSettings = Record; diff --git a/drivers/sensor_temperature_humidity/device.ts b/drivers/sensor_temperature_humidity/device.ts new file mode 100644 index 00000000..50597bab --- /dev/null +++ b/drivers/sensor_temperature_humidity/device.ts @@ -0,0 +1,59 @@ +import { + HomeyTemperatureHumiditySensorSettings, + TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING, + TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES, + TEMPERATURE_HUMIDITY_SENSOR_SETTING_LABELS, +} from './TuyaTemperatureHumiditySensorConstants'; +import TuyaOAuth2DeviceSensor from '../../lib/TuyaOAuth2DeviceSensor'; +import { constIncludes } from '../../lib/TuyaOAuth2Util'; +import { SettingsEvent, TuyaStatus } from '../../types/TuyaTypes'; +import * as TuyaOAuth2Util from '../../lib/TuyaOAuth2Util'; + +module.exports = class TuyaOAuth2DeviceSensorTemperatureHumidity extends TuyaOAuth2DeviceSensor { + async onOAuth2Init(): Promise { + await super.onOAuth2Init(); + + if (this.hasCapability('onoff')) { + this.registerCapabilityListener('onoff', value => this.sendCommand({ code: 'switch', value })); + } + } + + async onTuyaStatus(status: TuyaStatus, changedStatusCodes: string[]): Promise { + await super.onTuyaStatus(status, changedStatusCodes); + + for (const tuyaCapability in status) { + const homeyCapability = + TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING[tuyaCapability as keyof typeof TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING]; + const value = status[tuyaCapability]; + + if ( + constIncludes(TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES.read_only, tuyaCapability) || + constIncludes(TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES.read_write, tuyaCapability) + ) { + this.setCapabilityValue(homeyCapability, value).catch(this.error); + } + + if (constIncludes(TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability)) { + const scaling = 10.0 ** Number.parseInt(this.getSetting(`${tuyaCapability}_scaling`) ?? '0', 10); + this.setCapabilityValue(homeyCapability, (status[tuyaCapability] as number) / scaling).catch(this.error); + } + + // Battery + // battery_state is handled by superclass + + if (tuyaCapability === 'battery_value') { + const scaledValue = (value as number) / 300; + this.setCapabilityValue(homeyCapability, scaledValue).catch(this.error); + } + + if (tuyaCapability === 'va_battery') { + const scaledValue = (value as number) / 100; + this.setCapabilityValue(homeyCapability, scaledValue).catch(this.error); + } + } + } + + async onSettings(event: SettingsEvent): Promise { + return await TuyaOAuth2Util.onSettings(this, event, TEMPERATURE_HUMIDITY_SENSOR_SETTING_LABELS); + } +}; diff --git a/drivers/sensor_temperature_humidity/driver.compose.json b/drivers/sensor_temperature_humidity/driver.compose.json new file mode 100644 index 00000000..38420f64 --- /dev/null +++ b/drivers/sensor_temperature_humidity/driver.compose.json @@ -0,0 +1,8 @@ +{ + "$extends": "tuya", + "class": "sensor", + "name": { + "en": "Temperature/Humidity Sensor", + "nl": "Temperatuur/luchtvochtigheidssensor" + } +} diff --git a/drivers/sensor_temperature_humidity/driver.settings.compose.json b/drivers/sensor_temperature_humidity/driver.settings.compose.json new file mode 100644 index 00000000..44af57f0 --- /dev/null +++ b/drivers/sensor_temperature_humidity/driver.settings.compose.json @@ -0,0 +1,116 @@ +[ + { + "$extends": "deviceSpecification" + }, + { + "id": "va_temperature_scaling", + "type": "dropdown", + "label": { + "en": "Measured Temperature Scale" + }, + "hint": { + "en": "By how much the temperature measured by the device is scaled." + }, + "value": "1", + "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": "va_humidity_scaling", + "type": "dropdown", + "label": { + "en": "Measured Humidity Scale" + }, + "hint": { + "en": "By how much the humidity measured by the device is scaled." + }, + "value": "1", + "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": "bright_value_scaling", + "type": "dropdown", + "label": { + "en": "Measured Brightness Scale" + }, + "hint": { + "en": "By how much the brightness measured by the device is scaled." + }, + "value": "0", + "values": [ + { + "id": "0", + "label": { + "en": "1" + } + }, + { + "id": "1", + "label": { + "en": "1/10" + } + }, + { + "id": "2", + "label": { + "en": "1/100" + } + }, + { + "id": "3", + "label": { + "en": "1/1000" + } + } + ] + } +] diff --git a/drivers/sensor_temperature_humidity/driver.ts b/drivers/sensor_temperature_humidity/driver.ts new file mode 100644 index 00000000..e6677600 --- /dev/null +++ b/drivers/sensor_temperature_humidity/driver.ts @@ -0,0 +1,50 @@ +import { TuyaDeviceResponse, TuyaDeviceSpecificationResponse } from '../../types/TuyaApiTypes'; +import { + TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING, + TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES, +} from './TuyaTemperatureHumiditySensorConstants'; +import { ListDeviceProperties } from '../../lib/TuyaOAuth2Driver'; +import TuyaOAuth2DriverSensor from '../../lib/TuyaOAuth2DriverSensor'; +import { DEVICE_CATEGORIES } from '../../lib/TuyaOAuth2Constants'; +import { constIncludes } from '../../lib/TuyaOAuth2Util'; + +module.exports = class TuyaOAuth2DriverSensorTemperatureHumidity extends TuyaOAuth2DriverSensor { + TUYA_DEVICE_CATEGORIES = [DEVICE_CATEGORIES.SECURITY_VIDEO_SURV.TEMP_HUMI_SENSOR]; + + onTuyaPairListDeviceProperties( + device: TuyaDeviceResponse, + specifications: TuyaDeviceSpecificationResponse, + ): ListDeviceProperties { + const props = super.onTuyaPairListDeviceProperties(device, specifications); + + for (const status of device.status) { + const tuyaCapability = status.code; + const homeyCapability = + TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING[tuyaCapability as keyof typeof TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING]; + + // Capabilities that map one to one + if (homeyCapability) { + props.store.tuya_capabilities.push(tuyaCapability); + props.capabilities.push(homeyCapability); + } + } + + // Remove duplicate capabilities + props.capabilities = [...new Set(props.capabilities)]; + + for (const statusSpecifications of specifications.status) { + const tuyaCapability = statusSpecifications.code; + const values = JSON.parse(statusSpecifications.values); + + if (constIncludes(TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability)) { + if ([0, 1, 2, 3].includes(values.scale)) { + props.settings[`${tuyaCapability}_scaling`] = `${values.scale}`; + } else { + this.error(`Unsupported ${tuyaCapability} scale:`, values.scale); + } + } + } + + return props; + } +}; diff --git a/drivers/sensor_temperature_humidity/pair/welcome.assets/chevron-right.png b/drivers/sensor_temperature_humidity/pair/welcome.assets/chevron-right.png new file mode 100644 index 0000000000000000000000000000000000000000..d7331b236fe1d1c6d330621b0a6c62b8258b0691 GIT binary patch literal 647 zcmeAS@N?(olHy`uVBq!ia0vp^N+8U^1|+TAxeoy;#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07TEL88gA_7VEeruF`{?Q77!twx zHgu!kVF#YCOLaZ5t z$8l;`YnzSAwg@eKLEeYYv=tsSElA`kWjdQEZIW!*8ZO24Xybyui!S_^S+Cz?bKetu zU8CxcOUajK3EbYry-^bzzD`)^yFz?k$JrH^E=$Z!m)WBhnz}`Khrad=_x`v^`%bP= z@pd_WUA_FRP*yC{@w`VVOBGMtYxq4yHy~hX+WL*x-`L&|T-;FmN`0@3TI1o_JGj2K zp6>L%VP2VeXp!G-kxxkz_9WW=+B8qmvXam1?6hNB*ZVZ~%$&tk@wzYS(8c=ZUu+-C zKYo*OylbbrZD-aemp$$NHVRB}(eXF(12)NBWcEGZlOSX(lacz)S;Ahh*7{4c_?%T$ zN2c!x4*h&WzxVzW#m`A8?;l$?>zl;?*si92+hR)@=au;2Yl}=(Z;A(0_H3ELoBv5# z*@y2y-YEvFpAWyDXq>QPyYapMQp+_t%eYp3-rCdLeLRh8Lu5x!V-Mr01NvtVcKqa; RV%P^t1fH&bF6*2UngCf!0N?-s literal 0 HcmV?d00001 diff --git a/drivers/sensor_temperature_humidity/pair/welcome.assets/logos.png b/drivers/sensor_temperature_humidity/pair/welcome.assets/logos.png new file mode 100644 index 0000000000000000000000000000000000000000..faefa496b892dac27b44c2eab48ff6b929a9cf34 GIT binary patch literal 66184 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

>6}e^ikz%!=;Kn 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 + .tuya-welcome-title { + text-align: center; + } + + .tuya-welcome-text { + text-align: center; + font-size: 17px; + line-height: 24px; + color: #1c1c1c; + } + + .tuya-welcome-link { + color: #0082fa; + text-decoration: none; + font-size: 0; + } + + .tuya-welcome-link > span { + vertical-align: middle; + font-size: 17px; + } + + .tuya-welcome-link:hover > span { + text-decoration: underline; + } + + .tuya-welcome-link > img { + height: 17px; + vertical-align: middle; + margin-top: 2px; + } + + .tuya-welcome-logos { + height: 184px; + margin-top: 50px; + } + + +

+ +

+ +

+ +

+ + + + +

+ +

+ +

From 7b3a10e1b032948dc607b471a83ae33ad2234028 Mon Sep 17 00:00:00 2001 From: Joost Loohuis Date: Thu, 29 Aug 2024 16:02:44 +0200 Subject: [PATCH 2/6] Rename temperature/humidity sensor to climate sensor --- .../flow/actions/send_command_boolean.json | 2 +- .../flow/actions/send_command_json.json | 2 +- .../flow/actions/send_command_number.json | 2 +- .../flow/actions/send_command_string.json | 2 +- .../flow/triggers/receive_status_boolean.json | 2 +- .../flow/triggers/receive_status_json.json | 2 +- .../flow/triggers/receive_status_number.json | 2 +- .../flow/triggers/receive_status_string.json | 2 +- app.json | 324 +++++++++--------- .../TuyaClimateSensorConstants.ts} | 10 +- .../device.ts | 25 +- drivers/sensor_climate/driver.compose.json | 8 + .../driver.settings.compose.json | 0 .../driver.ts | 12 +- .../pair/welcome.assets/chevron-right.png | Bin .../pair/welcome.assets/logos.png | Bin .../pair/welcome.html | 0 .../driver.compose.json | 8 - 18 files changed, 199 insertions(+), 204 deletions(-) rename drivers/{sensor_temperature_humidity/TuyaTemperatureHumiditySensorConstants.ts => sensor_climate/TuyaClimateSensorConstants.ts} (74%) rename drivers/{sensor_temperature_humidity => sensor_climate}/device.ts (61%) create mode 100644 drivers/sensor_climate/driver.compose.json rename drivers/{sensor_temperature_humidity => sensor_climate}/driver.settings.compose.json (100%) rename drivers/{sensor_temperature_humidity => sensor_climate}/driver.ts (75%) rename drivers/{sensor_temperature_humidity => sensor_climate}/pair/welcome.assets/chevron-right.png (100%) rename drivers/{sensor_temperature_humidity => sensor_climate}/pair/welcome.assets/logos.png (100%) rename drivers/{sensor_temperature_humidity => sensor_climate}/pair/welcome.html (100%) delete mode 100644 drivers/sensor_temperature_humidity/driver.compose.json diff --git a/.homeycompose/flow/actions/send_command_boolean.json b/.homeycompose/flow/actions/send_command_boolean.json index cb473df3..e3f3430e 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_json.json b/.homeycompose/flow/actions/send_command_json.json index 17e6b6d9..d305c917 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_number.json b/.homeycompose/flow/actions/send_command_number.json index 995ce642..25bcb7e1 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/actions/send_command_string.json b/.homeycompose/flow/actions/send_command_string.json index a4a6cd5f..0776b18a 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_boolean.json b/.homeycompose/flow/triggers/receive_status_boolean.json index a2558e77..f0f7ee75 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_json.json b/.homeycompose/flow/triggers/receive_status_json.json index 0edf415c..b0dd5e6a 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_number.json b/.homeycompose/flow/triggers/receive_status_number.json index 85600c79..f0330866 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" diff --git a/.homeycompose/flow/triggers/receive_status_string.json b/.homeycompose/flow/triggers/receive_status_string.json index 50c2881c..1e892ff7 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": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" diff --git a/app.json b/app.json index bea6f75b..ef7836c1 100644 --- a/app.json +++ b/app.json @@ -400,7 +400,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" @@ -441,7 +441,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" @@ -482,7 +482,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" @@ -523,7 +523,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" @@ -920,7 +920,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" @@ -958,7 +958,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" @@ -996,7 +996,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" @@ -1034,7 +1034,7 @@ "name": "device", "type": "device", "filter": { - "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_contact|sensor_motion|sensor_smoke|sensor_temperature_humidity|siren|socket" + "driver_id": "camera|dimmer|doorbell|fan|heater|light|other|sensor_climate|sensor_contact|sensor_motion|sensor_smoke|siren|socket" }, "title": { "en": "Device" @@ -2925,9 +2925,7 @@ ] }, { - "capabilities": [ - "alarm_contact" - ], + "capabilities": [], "connectivity": [ "cloud" ], @@ -2936,9 +2934,9 @@ "cloud" ], "images": { - "small": "/drivers/sensor_contact/assets/images/small.png", - "large": "/drivers/sensor_contact/assets/images/large.png", - "xlarge": "/drivers/sensor_contact/assets/images/xlarge.png" + "small": "/drivers/sensor_climate/assets/images/small.png", + "large": "/drivers/sensor_climate/assets/images/large.png", + "xlarge": "/drivers/sensor_climate/assets/images/xlarge.png" }, "pair": [ { @@ -2971,50 +2969,138 @@ ], "class": "sensor", "name": { - "en": "Door Sensor", - "nl": "Deur Sensor" + "en": "Climate Sensor", + "nl": "Klimaatsensor" }, - "id": "sensor_contact", + "id": "sensor_climate", "settings": [ { - "id": "use_alarm_timeout", - "type": "checkbox", + "id": "deviceSpecification", + "type": "label", + "label": { + "en": "Device Specification" + }, "hint": { - "en": "Turn the alarm off a set time after the start signal, even if no end signal is received." + "en": "The Tuya specification of this device" }, + "value": "" + }, + { + "id": "va_temperature_scaling", + "type": "dropdown", "label": { - "en": "Use Alarm Timeout" + "en": "Measured Temperature Scale" }, - "value": false + "hint": { + "en": "By how much the temperature measured by the device is scaled." + }, + "value": "1", + "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": "alarm_timeout", - "type": "number", + "id": "va_humidity_scaling", + "type": "dropdown", "label": { - "en": "Alarm Timeout" + "en": "Measured Humidity Scale" }, - "value": 10, - "min": 1, - "units": { - "en": "seconds" - } + "hint": { + "en": "By how much the humidity measured by the device is scaled." + }, + "value": "1", + "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": "deviceSpecification", - "type": "label", + "id": "bright_value_scaling", + "type": "dropdown", "label": { - "en": "Device Specification" + "en": "Measured Brightness Scale" }, "hint": { - "en": "The Tuya specification of this device" + "en": "By how much the brightness measured by the device is scaled." }, - "value": "" + "value": "0", + "values": [ + { + "id": "0", + "label": { + "en": "1" + } + }, + { + "id": "1", + "label": { + "en": "1/10" + } + }, + { + "id": "2", + "label": { + "en": "1/100" + } + }, + { + "id": "3", + "label": { + "en": "1/1000" + } + } + ] } ] }, { "capabilities": [ - "alarm_motion" + "alarm_contact" ], "connectivity": [ "cloud" @@ -3024,9 +3110,9 @@ "cloud" ], "images": { - "small": "/drivers/sensor_motion/assets/images/small.png", - "large": "/drivers/sensor_motion/assets/images/large.png", - "xlarge": "/drivers/sensor_motion/assets/images/xlarge.png" + "small": "/drivers/sensor_contact/assets/images/small.png", + "large": "/drivers/sensor_contact/assets/images/large.png", + "xlarge": "/drivers/sensor_contact/assets/images/xlarge.png" }, "pair": [ { @@ -3059,10 +3145,10 @@ ], "class": "sensor", "name": { - "en": "Motion Sensor", - "nl": "Bewegingssensor" + "en": "Door Sensor", + "nl": "Deur Sensor" }, - "id": "sensor_motion", + "id": "sensor_contact", "settings": [ { "id": "use_alarm_timeout", @@ -3102,7 +3188,7 @@ }, { "capabilities": [ - "alarm_smoke" + "alarm_motion" ], "connectivity": [ "cloud" @@ -3112,9 +3198,9 @@ "cloud" ], "images": { - "small": "/drivers/sensor_smoke/assets/images/small.png", - "large": "/drivers/sensor_smoke/assets/images/large.png", - "xlarge": "/drivers/sensor_smoke/assets/images/xlarge.png" + "small": "/drivers/sensor_motion/assets/images/small.png", + "large": "/drivers/sensor_motion/assets/images/large.png", + "xlarge": "/drivers/sensor_motion/assets/images/xlarge.png" }, "pair": [ { @@ -3147,10 +3233,10 @@ ], "class": "sensor", "name": { - "en": "Smoke Detector", - "nl": "Rookmelder" + "en": "Motion Sensor", + "nl": "Bewegingssensor" }, - "id": "sensor_smoke", + "id": "sensor_motion", "settings": [ { "id": "use_alarm_timeout", @@ -3189,7 +3275,9 @@ ] }, { - "capabilities": [], + "capabilities": [ + "alarm_smoke" + ], "connectivity": [ "cloud" ], @@ -3198,9 +3286,9 @@ "cloud" ], "images": { - "small": "/drivers/sensor_temperature_humidity/assets/images/small.png", - "large": "/drivers/sensor_temperature_humidity/assets/images/large.png", - "xlarge": "/drivers/sensor_temperature_humidity/assets/images/xlarge.png" + "small": "/drivers/sensor_smoke/assets/images/small.png", + "large": "/drivers/sensor_smoke/assets/images/large.png", + "xlarge": "/drivers/sensor_smoke/assets/images/xlarge.png" }, "pair": [ { @@ -3233,132 +3321,44 @@ ], "class": "sensor", "name": { - "en": "Temperature/Humidity Sensor", - "nl": "Temperatuur/luchtvochtigheidssensor" + "en": "Smoke Detector", + "nl": "Rookmelder" }, - "id": "sensor_temperature_humidity", + "id": "sensor_smoke", "settings": [ { - "id": "deviceSpecification", - "type": "label", - "label": { - "en": "Device Specification" - }, + "id": "use_alarm_timeout", + "type": "checkbox", "hint": { - "en": "The Tuya specification of this device" + "en": "Turn the alarm off a set time after the start signal, even if no end signal is received." }, - "value": "" - }, - { - "id": "va_temperature_scaling", - "type": "dropdown", "label": { - "en": "Measured Temperature Scale" - }, - "hint": { - "en": "By how much the temperature measured by the device is scaled." + "en": "Use Alarm Timeout" }, - "value": "1", - "values": [ - { - "id": "0", - "label": { - "en": "1" - } - }, - { - "id": "1", - "label": { - "en": "1/10" - } - }, - { - "id": "2", - "label": { - "en": "1/100" - } - }, - { - "id": "3", - "label": { - "en": "1/1000" - } - } - ] + "value": false }, { - "id": "va_humidity_scaling", - "type": "dropdown", + "id": "alarm_timeout", + "type": "number", "label": { - "en": "Measured Humidity Scale" - }, - "hint": { - "en": "By how much the humidity measured by the device is scaled." + "en": "Alarm Timeout" }, - "value": "1", - "values": [ - { - "id": "0", - "label": { - "en": "1" - } - }, - { - "id": "1", - "label": { - "en": "1/10" - } - }, - { - "id": "2", - "label": { - "en": "1/100" - } - }, - { - "id": "3", - "label": { - "en": "1/1000" - } - } - ] + "value": 10, + "min": 1, + "units": { + "en": "seconds" + } }, { - "id": "bright_value_scaling", - "type": "dropdown", + "id": "deviceSpecification", + "type": "label", "label": { - "en": "Measured Brightness Scale" + "en": "Device Specification" }, "hint": { - "en": "By how much the brightness measured by the device is scaled." + "en": "The Tuya specification of this device" }, - "value": "0", - "values": [ - { - "id": "0", - "label": { - "en": "1" - } - }, - { - "id": "1", - "label": { - "en": "1/10" - } - }, - { - "id": "2", - "label": { - "en": "1/100" - } - }, - { - "id": "3", - "label": { - "en": "1/1000" - } - } - ] + "value": "" } ] }, diff --git a/drivers/sensor_temperature_humidity/TuyaTemperatureHumiditySensorConstants.ts b/drivers/sensor_climate/TuyaClimateSensorConstants.ts similarity index 74% rename from drivers/sensor_temperature_humidity/TuyaTemperatureHumiditySensorConstants.ts rename to drivers/sensor_climate/TuyaClimateSensorConstants.ts index f90b1278..0db4b08a 100644 --- a/drivers/sensor_temperature_humidity/TuyaTemperatureHumiditySensorConstants.ts +++ b/drivers/sensor_climate/TuyaClimateSensorConstants.ts @@ -1,12 +1,12 @@ /** capabilities that map one to one to a Homey capability */ -export const TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES = { +export const CLIMATE_SENSOR_CAPABILITIES = { read_write: ['switch'], read_only: ['temper_alarm', 'battery_percentage'], read_only_scaled: ['va_temperature', 'va_humidity', 'bright_value'], setting: [], } as const; -export const TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING = { +export const CLIMATE_CAPABILITY_MAPPING = { switch: 'onoff', temper_alarm: 'alarm_tamper', va_temperature: 'measure_temperature', @@ -18,16 +18,16 @@ export const TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING = { va_battery: 'measure_battery', } as const; -export const TEMPERATURE_HUMIDITY_SENSOR_SETTING_LABELS = { +export const CLIMATE_SENSOR_SETTING_LABELS = { va_temperature_scaling: 'Measured Temperature Scale', va_humidity_scaling: 'Measured Humidity Scale', bright_value_scaling: 'Measured Brightness Scale', } as const; -export type HomeyTemperatureHumiditySensorSettings = { +export type HomeyClimateSensorSettings = { va_temperature_scaling: '0' | '1' | '2' | '3'; va_humidity_scaling: '0' | '1' | '2' | '3'; bright_value_scaling: '0' | '1' | '2' | '3'; }; -export type TuyaTemperatureHumiditySensorSettings = Record; +export type TuyaClimateSensorSettings = Record; diff --git a/drivers/sensor_temperature_humidity/device.ts b/drivers/sensor_climate/device.ts similarity index 61% rename from drivers/sensor_temperature_humidity/device.ts rename to drivers/sensor_climate/device.ts index 50597bab..4b387d47 100644 --- a/drivers/sensor_temperature_humidity/device.ts +++ b/drivers/sensor_climate/device.ts @@ -1,15 +1,15 @@ import { - HomeyTemperatureHumiditySensorSettings, - TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING, - TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES, - TEMPERATURE_HUMIDITY_SENSOR_SETTING_LABELS, -} from './TuyaTemperatureHumiditySensorConstants'; + HomeyClimateSensorSettings, + CLIMATE_CAPABILITY_MAPPING, + CLIMATE_SENSOR_CAPABILITIES, + CLIMATE_SENSOR_SETTING_LABELS, +} from './TuyaClimateSensorConstants'; import TuyaOAuth2DeviceSensor from '../../lib/TuyaOAuth2DeviceSensor'; import { constIncludes } from '../../lib/TuyaOAuth2Util'; import { SettingsEvent, TuyaStatus } from '../../types/TuyaTypes'; import * as TuyaOAuth2Util from '../../lib/TuyaOAuth2Util'; -module.exports = class TuyaOAuth2DeviceSensorTemperatureHumidity extends TuyaOAuth2DeviceSensor { +module.exports = class TuyaOAuth2DeviceSensorClimate extends TuyaOAuth2DeviceSensor { async onOAuth2Init(): Promise { await super.onOAuth2Init(); @@ -22,18 +22,17 @@ module.exports = class TuyaOAuth2DeviceSensorTemperatureHumidity extends TuyaOAu await super.onTuyaStatus(status, changedStatusCodes); for (const tuyaCapability in status) { - const homeyCapability = - TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING[tuyaCapability as keyof typeof TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING]; + const homeyCapability = CLIMATE_CAPABILITY_MAPPING[tuyaCapability as keyof typeof CLIMATE_CAPABILITY_MAPPING]; const value = status[tuyaCapability]; if ( - constIncludes(TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES.read_only, tuyaCapability) || - constIncludes(TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES.read_write, tuyaCapability) + constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_only, tuyaCapability) || + constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_write, tuyaCapability) ) { this.setCapabilityValue(homeyCapability, value).catch(this.error); } - if (constIncludes(TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability)) { + if (constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability)) { const scaling = 10.0 ** Number.parseInt(this.getSetting(`${tuyaCapability}_scaling`) ?? '0', 10); this.setCapabilityValue(homeyCapability, (status[tuyaCapability] as number) / scaling).catch(this.error); } @@ -53,7 +52,7 @@ module.exports = class TuyaOAuth2DeviceSensorTemperatureHumidity extends TuyaOAu } } - async onSettings(event: SettingsEvent): Promise { - return await TuyaOAuth2Util.onSettings(this, event, TEMPERATURE_HUMIDITY_SENSOR_SETTING_LABELS); + async onSettings(event: SettingsEvent): Promise { + return await TuyaOAuth2Util.onSettings(this, event, CLIMATE_SENSOR_SETTING_LABELS); } }; diff --git a/drivers/sensor_climate/driver.compose.json b/drivers/sensor_climate/driver.compose.json new file mode 100644 index 00000000..910cbec2 --- /dev/null +++ b/drivers/sensor_climate/driver.compose.json @@ -0,0 +1,8 @@ +{ + "$extends": "tuya", + "class": "sensor", + "name": { + "en": "Climate Sensor", + "nl": "Klimaatsensor" + } +} diff --git a/drivers/sensor_temperature_humidity/driver.settings.compose.json b/drivers/sensor_climate/driver.settings.compose.json similarity index 100% rename from drivers/sensor_temperature_humidity/driver.settings.compose.json rename to drivers/sensor_climate/driver.settings.compose.json diff --git a/drivers/sensor_temperature_humidity/driver.ts b/drivers/sensor_climate/driver.ts similarity index 75% rename from drivers/sensor_temperature_humidity/driver.ts rename to drivers/sensor_climate/driver.ts index e6677600..1fb16fc8 100644 --- a/drivers/sensor_temperature_humidity/driver.ts +++ b/drivers/sensor_climate/driver.ts @@ -1,14 +1,11 @@ import { TuyaDeviceResponse, TuyaDeviceSpecificationResponse } from '../../types/TuyaApiTypes'; -import { - TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING, - TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES, -} from './TuyaTemperatureHumiditySensorConstants'; +import { CLIMATE_CAPABILITY_MAPPING, CLIMATE_SENSOR_CAPABILITIES } from './TuyaClimateSensorConstants'; import { ListDeviceProperties } from '../../lib/TuyaOAuth2Driver'; import TuyaOAuth2DriverSensor from '../../lib/TuyaOAuth2DriverSensor'; import { DEVICE_CATEGORIES } from '../../lib/TuyaOAuth2Constants'; import { constIncludes } from '../../lib/TuyaOAuth2Util'; -module.exports = class TuyaOAuth2DriverSensorTemperatureHumidity extends TuyaOAuth2DriverSensor { +module.exports = class TuyaOAuth2DriverSensorClimate extends TuyaOAuth2DriverSensor { TUYA_DEVICE_CATEGORIES = [DEVICE_CATEGORIES.SECURITY_VIDEO_SURV.TEMP_HUMI_SENSOR]; onTuyaPairListDeviceProperties( @@ -19,8 +16,7 @@ module.exports = class TuyaOAuth2DriverSensorTemperatureHumidity extends TuyaOAu for (const status of device.status) { const tuyaCapability = status.code; - const homeyCapability = - TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING[tuyaCapability as keyof typeof TEMPERATURE_HUMIDITY_CAPABILITY_MAPPING]; + const homeyCapability = CLIMATE_CAPABILITY_MAPPING[tuyaCapability as keyof typeof CLIMATE_CAPABILITY_MAPPING]; // Capabilities that map one to one if (homeyCapability) { @@ -36,7 +32,7 @@ module.exports = class TuyaOAuth2DriverSensorTemperatureHumidity extends TuyaOAu const tuyaCapability = statusSpecifications.code; const values = JSON.parse(statusSpecifications.values); - if (constIncludes(TEMPERATURE_HUMIDITY_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability)) { + if (constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability)) { if ([0, 1, 2, 3].includes(values.scale)) { props.settings[`${tuyaCapability}_scaling`] = `${values.scale}`; } else { diff --git a/drivers/sensor_temperature_humidity/pair/welcome.assets/chevron-right.png b/drivers/sensor_climate/pair/welcome.assets/chevron-right.png similarity index 100% rename from drivers/sensor_temperature_humidity/pair/welcome.assets/chevron-right.png rename to drivers/sensor_climate/pair/welcome.assets/chevron-right.png diff --git a/drivers/sensor_temperature_humidity/pair/welcome.assets/logos.png b/drivers/sensor_climate/pair/welcome.assets/logos.png similarity index 100% rename from drivers/sensor_temperature_humidity/pair/welcome.assets/logos.png rename to drivers/sensor_climate/pair/welcome.assets/logos.png diff --git a/drivers/sensor_temperature_humidity/pair/welcome.html b/drivers/sensor_climate/pair/welcome.html similarity index 100% rename from drivers/sensor_temperature_humidity/pair/welcome.html rename to drivers/sensor_climate/pair/welcome.html diff --git a/drivers/sensor_temperature_humidity/driver.compose.json b/drivers/sensor_temperature_humidity/driver.compose.json deleted file mode 100644 index 38420f64..00000000 --- a/drivers/sensor_temperature_humidity/driver.compose.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$extends": "tuya", - "class": "sensor", - "name": { - "en": "Temperature/Humidity Sensor", - "nl": "Temperatuur/luchtvochtigheidssensor" - } -} From b20dd073a3f283d36e2ae13ef0340751f23f5bb0 Mon Sep 17 00:00:00 2001 From: Joost Loohuis Date: Thu, 29 Aug 2024 16:14:10 +0200 Subject: [PATCH 3/6] Rework climate sensor to new sensor style --- app.json | 45 ++++++++++++++----- .../TuyaClimateSensorConstants.ts | 5 +-- drivers/sensor_climate/device.ts | 3 +- .../driver.settings.compose.json | 12 +++-- drivers/sensor_climate/driver.ts | 1 + 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/app.json b/app.json index ef7836c1..27993ec8 100644 --- a/app.json +++ b/app.json @@ -2974,17 +2974,6 @@ }, "id": "sensor_climate", "settings": [ - { - "id": "deviceSpecification", - "type": "label", - "label": { - "en": "Device Specification" - }, - "hint": { - "en": "The Tuya specification of this device" - }, - "value": "" - }, { "id": "va_temperature_scaling", "type": "dropdown", @@ -3095,6 +3084,40 @@ } } ] + }, + { + "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": "deviceSpecification", + "type": "label", + "label": { + "en": "Device Specification" + }, + "hint": { + "en": "The Tuya specification of this device" + }, + "value": "" } ] }, diff --git a/drivers/sensor_climate/TuyaClimateSensorConstants.ts b/drivers/sensor_climate/TuyaClimateSensorConstants.ts index 0db4b08a..7ed5f2d3 100644 --- a/drivers/sensor_climate/TuyaClimateSensorConstants.ts +++ b/drivers/sensor_climate/TuyaClimateSensorConstants.ts @@ -1,19 +1,16 @@ /** capabilities that map one to one to a Homey capability */ export const CLIMATE_SENSOR_CAPABILITIES = { read_write: ['switch'], - read_only: ['temper_alarm', 'battery_percentage'], + read_only: ['temper_alarm'], read_only_scaled: ['va_temperature', 'va_humidity', 'bright_value'], setting: [], } as const; export const CLIMATE_CAPABILITY_MAPPING = { switch: 'onoff', - temper_alarm: 'alarm_tamper', va_temperature: 'measure_temperature', va_humidity: 'measure_humidity', bright_value: 'measure_luminance', - battery_state: 'alarm_battery', - battery_percentage: 'measure_battery', battery_value: 'measure_battery', va_battery: 'measure_battery', } as const; diff --git a/drivers/sensor_climate/device.ts b/drivers/sensor_climate/device.ts index 4b387d47..24d9b0ba 100644 --- a/drivers/sensor_climate/device.ts +++ b/drivers/sensor_climate/device.ts @@ -19,6 +19,7 @@ module.exports = class TuyaOAuth2DeviceSensorClimate extends TuyaOAuth2DeviceSen } async onTuyaStatus(status: TuyaStatus, changedStatusCodes: string[]): Promise { + // battery_state, battery_percentage and temper_alarm are handled by the superclass await super.onTuyaStatus(status, changedStatusCodes); for (const tuyaCapability in status) { @@ -38,8 +39,6 @@ module.exports = class TuyaOAuth2DeviceSensorClimate extends TuyaOAuth2DeviceSen } // Battery - // battery_state is handled by superclass - if (tuyaCapability === 'battery_value') { const scaledValue = (value as number) / 300; this.setCapabilityValue(homeyCapability, scaledValue).catch(this.error); diff --git a/drivers/sensor_climate/driver.settings.compose.json b/drivers/sensor_climate/driver.settings.compose.json index 44af57f0..89a6c03a 100644 --- a/drivers/sensor_climate/driver.settings.compose.json +++ b/drivers/sensor_climate/driver.settings.compose.json @@ -1,7 +1,4 @@ [ - { - "$extends": "deviceSpecification" - }, { "id": "va_temperature_scaling", "type": "dropdown", @@ -112,5 +109,14 @@ } } ] + }, + { + "$extends": "useAlarmTimeout" + }, + { + "$extends": "alarmTimeout" + }, + { + "$extends": "deviceSpecification" } ] diff --git a/drivers/sensor_climate/driver.ts b/drivers/sensor_climate/driver.ts index 1fb16fc8..1109fb18 100644 --- a/drivers/sensor_climate/driver.ts +++ b/drivers/sensor_climate/driver.ts @@ -12,6 +12,7 @@ module.exports = class TuyaOAuth2DriverSensorClimate extends TuyaOAuth2DriverSen device: TuyaDeviceResponse, specifications: TuyaDeviceSpecificationResponse, ): ListDeviceProperties { + // battery_state, battery_percentage and temper_alarm are handled by the superclass const props = super.onTuyaPairListDeviceProperties(device, specifications); for (const status of device.status) { From c5168dda1af4cce19ec3ab59cc5b0f26e20cb4cc Mon Sep 17 00:00:00 2001 From: Bob van de Vijver Date: Thu, 29 Aug 2024 16:20:47 +0200 Subject: [PATCH 4/6] Add climate device image and icon --- drivers/sensor_climate/assets/icon.svg | 10 ++++++++++ drivers/sensor_climate/assets/images/large.png | Bin 0 -> 12351 bytes drivers/sensor_climate/assets/images/small.png | Bin 0 -> 1005 bytes drivers/sensor_climate/assets/images/xlarge.png | Bin 0 -> 28856 bytes 4 files changed, 10 insertions(+) create mode 100644 drivers/sensor_climate/assets/icon.svg create mode 100644 drivers/sensor_climate/assets/images/large.png create mode 100644 drivers/sensor_climate/assets/images/small.png create mode 100644 drivers/sensor_climate/assets/images/xlarge.png diff --git a/drivers/sensor_climate/assets/icon.svg b/drivers/sensor_climate/assets/icon.svg new file mode 100644 index 00000000..ba6de1fb --- /dev/null +++ b/drivers/sensor_climate/assets/icon.svg @@ -0,0 +1,10 @@ + + + drivers/sensor_contact/assets/icon + + + + + + + diff --git a/drivers/sensor_climate/assets/images/large.png b/drivers/sensor_climate/assets/images/large.png new file mode 100644 index 0000000000000000000000000000000000000000..096ea7c056e6f85765ede3e66da557bb4f03d1de GIT binary patch literal 12351 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 SPVk2T44P_s_sj0uKKn1w`=UVr literal 0 HcmV?d00001 diff --git a/drivers/sensor_climate/assets/images/small.png b/drivers/sensor_climate/assets/images/small.png new file mode 100644 index 0000000000000000000000000000000000000000..d341241bccacbe2933c66cf207030c98f5f796f7 GIT binary patch literal 1005 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 literal 0 HcmV?d00001 From e417fcb56cc16652546a0bfcfac53756aa582a1e Mon Sep 17 00:00:00 2001 From: Joost Loohuis Date: Fri, 30 Aug 2024 13:33:53 +0200 Subject: [PATCH 5/6] Add climate sensor standard capabilities --- app.json | 5 ++++- drivers/sensor_climate/driver.compose.json | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app.json b/app.json index 27993ec8..eb09dfdc 100644 --- a/app.json +++ b/app.json @@ -2925,7 +2925,10 @@ ] }, { - "capabilities": [], + "capabilities": [ + "measure_temperature", + "measure_humidity" + ], "connectivity": [ "cloud" ], diff --git a/drivers/sensor_climate/driver.compose.json b/drivers/sensor_climate/driver.compose.json index 910cbec2..1f418312 100644 --- a/drivers/sensor_climate/driver.compose.json +++ b/drivers/sensor_climate/driver.compose.json @@ -4,5 +4,6 @@ "name": { "en": "Climate Sensor", "nl": "Klimaatsensor" - } + }, + "capabilities": ["measure_temperature", "measure_humidity"] } From e8f32542e3e04f4c4f3605766aa6d575d18cf173 Mon Sep 17 00:00:00 2001 From: Joost Loohuis Date: Fri, 30 Aug 2024 13:37:53 +0200 Subject: [PATCH 6/6] Refactor climate sensor capabilities mapping --- drivers/sensor_climate/device.ts | 23 ++++++++++++----------- drivers/sensor_climate/driver.ts | 4 ++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/sensor_climate/device.ts b/drivers/sensor_climate/device.ts index 24d9b0ba..f87d11e0 100644 --- a/drivers/sensor_climate/device.ts +++ b/drivers/sensor_climate/device.ts @@ -5,7 +5,7 @@ import { CLIMATE_SENSOR_SETTING_LABELS, } from './TuyaClimateSensorConstants'; import TuyaOAuth2DeviceSensor from '../../lib/TuyaOAuth2DeviceSensor'; -import { constIncludes } from '../../lib/TuyaOAuth2Util'; +import { constIncludes, getFromMap } from '../../lib/TuyaOAuth2Util'; import { SettingsEvent, TuyaStatus } from '../../types/TuyaTypes'; import * as TuyaOAuth2Util from '../../lib/TuyaOAuth2Util'; @@ -23,30 +23,31 @@ module.exports = class TuyaOAuth2DeviceSensorClimate extends TuyaOAuth2DeviceSen await super.onTuyaStatus(status, changedStatusCodes); for (const tuyaCapability in status) { - const homeyCapability = CLIMATE_CAPABILITY_MAPPING[tuyaCapability as keyof typeof CLIMATE_CAPABILITY_MAPPING]; + const homeyCapability = getFromMap(CLIMATE_CAPABILITY_MAPPING, tuyaCapability); const value = status[tuyaCapability]; if ( - constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_only, tuyaCapability) || - constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_write, tuyaCapability) + (constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_only, tuyaCapability) || + constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_write, tuyaCapability)) && + homeyCapability ) { - this.setCapabilityValue(homeyCapability, value).catch(this.error); + await this.safeSetCapabilityValue(homeyCapability, value); } - if (constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability)) { + if (constIncludes(CLIMATE_SENSOR_CAPABILITIES.read_only_scaled, tuyaCapability) && homeyCapability) { const scaling = 10.0 ** Number.parseInt(this.getSetting(`${tuyaCapability}_scaling`) ?? '0', 10); - this.setCapabilityValue(homeyCapability, (status[tuyaCapability] as number) / scaling).catch(this.error); + await this.safeSetCapabilityValue(homeyCapability, (status[tuyaCapability] as number) / scaling); } // Battery - if (tuyaCapability === 'battery_value') { + if (tuyaCapability === 'battery_value' && homeyCapability) { const scaledValue = (value as number) / 300; - this.setCapabilityValue(homeyCapability, scaledValue).catch(this.error); + await this.safeSetCapabilityValue(homeyCapability, scaledValue); } - if (tuyaCapability === 'va_battery') { + if (tuyaCapability === 'va_battery' && homeyCapability) { const scaledValue = (value as number) / 100; - this.setCapabilityValue(homeyCapability, scaledValue).catch(this.error); + await this.safeSetCapabilityValue(homeyCapability, scaledValue); } } } diff --git a/drivers/sensor_climate/driver.ts b/drivers/sensor_climate/driver.ts index 1109fb18..bdd35a20 100644 --- a/drivers/sensor_climate/driver.ts +++ b/drivers/sensor_climate/driver.ts @@ -3,7 +3,7 @@ import { CLIMATE_CAPABILITY_MAPPING, CLIMATE_SENSOR_CAPABILITIES } from './TuyaC import { ListDeviceProperties } from '../../lib/TuyaOAuth2Driver'; import TuyaOAuth2DriverSensor from '../../lib/TuyaOAuth2DriverSensor'; import { DEVICE_CATEGORIES } from '../../lib/TuyaOAuth2Constants'; -import { constIncludes } from '../../lib/TuyaOAuth2Util'; +import { constIncludes, getFromMap } from '../../lib/TuyaOAuth2Util'; module.exports = class TuyaOAuth2DriverSensorClimate extends TuyaOAuth2DriverSensor { TUYA_DEVICE_CATEGORIES = [DEVICE_CATEGORIES.SECURITY_VIDEO_SURV.TEMP_HUMI_SENSOR]; @@ -17,7 +17,7 @@ module.exports = class TuyaOAuth2DriverSensorClimate extends TuyaOAuth2DriverSen for (const status of device.status) { const tuyaCapability = status.code; - const homeyCapability = CLIMATE_CAPABILITY_MAPPING[tuyaCapability as keyof typeof CLIMATE_CAPABILITY_MAPPING]; + const homeyCapability = getFromMap(CLIMATE_CAPABILITY_MAPPING, tuyaCapability); // Capabilities that map one to one if (homeyCapability) {