From bd51d20219eb03543e443212cdd73e162ba5db28 Mon Sep 17 00:00:00 2001 From: araa Date: Fri, 19 Dec 2025 22:07:53 +0100 Subject: [PATCH 1/8] Add CO2 measurement and control capabilities, including home and away limits, to the SwegonCasa driver. Update related enums and settings in the application. --- .homeycompose/capabilities/measure_co2.json | 21 ++++++ app.json | 64 +++++++++++++++++++ drivers/swegoncasa/MeasurementHandler.ts | 11 ++++ drivers/swegoncasa/SettingsHandler.ts | 16 +++++ drivers/swegoncasa/SwegonClient.ts | 18 ++++++ drivers/swegoncasa/SwegonConstants.ts | 16 ++++- drivers/swegoncasa/device.ts | 12 ++++ drivers/swegoncasa/driver.compose.json | 1 + .../swegoncasa/driver.settings.compose.json | 43 +++++++++++++ lib/MeasurementType.ts | 1 + lib/SettingType.ts | 2 + lib/SwegonObjectId.ts | 3 + 12 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 .homeycompose/capabilities/measure_co2.json diff --git a/.homeycompose/capabilities/measure_co2.json b/.homeycompose/capabilities/measure_co2.json new file mode 100644 index 0000000..abe051f --- /dev/null +++ b/.homeycompose/capabilities/measure_co2.json @@ -0,0 +1,21 @@ +{ + "type": "number", + "uiComponent": "sensor", + "title": { + "en": "CO2", + "no": "CO2" + }, + "desc": { + "en": "Carbon dioxide level", + "no": "Karbondioksidnivå" + }, + "units": { + "en": "ppm", + "no": "ppm" + }, + "decimals": 0, + "getable": true, + "setable": false, + "insights": true +} + diff --git a/app.json b/app.json index e56dd73..bc6d790 100644 --- a/app.json +++ b/app.json @@ -159,6 +159,7 @@ "measure_ventilation_level_in", "measure_ventilation_level_out", "measure_air_quality", + "measure_co2", "climate_mode", "summer_night_cooling_mode", "auto_humidity_control_mode", @@ -446,6 +447,49 @@ } ] }, + { + "type": "group", + "label": { + "en": "CO2 Control", + "no": "CO2 Kontroll" + }, + "children": [ + { + "id": "co2HomeLimit", + "type": "number", + "value": 550, + "units": { + "en": "ppm", + "no": "ppm" + }, + "label": { + "en": "CO2 Home Limit", + "no": "CO2 Hjemme-grense" + }, + "hint": { + "en": "CO2 level threshold for Home mode in the Auto Home/Away/Boost feature", + "no": "CO2-nivågrense for Hjemme-modus i Auto Hjemme/Borte/Boost-funksjonen" + } + }, + { + "id": "co2AwayLimit", + "type": "number", + "value": 400, + "units": { + "en": "ppm", + "no": "ppm" + }, + "label": { + "en": "CO2 Away Limit", + "no": "CO2 Borte-grense" + }, + "hint": { + "en": "CO2 level threshold for Away mode in the Auto Home/Away/Boost feature", + "no": "CO2-nivågrense for Borte-modus i Auto Hjemme/Borte/Boost-funksjonen" + } + } + ] + }, { "type": "group", "label": { @@ -793,6 +837,26 @@ "setable": false, "insights": true }, + "measure_co2": { + "type": "number", + "uiComponent": "sensor", + "title": { + "en": "CO2", + "no": "CO2" + }, + "desc": { + "en": "Carbon dioxide level", + "no": "Karbondioksidnivå" + }, + "units": { + "en": "ppm", + "no": "ppm" + }, + "decimals": 0, + "getable": true, + "setable": false, + "insights": true + }, "measure_fan_speed": { "type": "enum", "uiComponent": "sensor", diff --git a/drivers/swegoncasa/MeasurementHandler.ts b/drivers/swegoncasa/MeasurementHandler.ts index c654198..8ddc4ab 100644 --- a/drivers/swegoncasa/MeasurementHandler.ts +++ b/drivers/swegoncasa/MeasurementHandler.ts @@ -69,6 +69,17 @@ class MeasurementHandler { await removeCapability(ModeType.AutoAirQualityControlMode); } break; + case MeasurementType.CO2: + this.logger.info(`CO2: ${data.value}`); + if (data.value > 0) { + if (!hasCapability('measure_co2')) + await addCapability('measure_co2'); + await setCapabilityValue('measure_co2', data.value); + } else if (data.value === 0) { + if (hasCapability('measure_co2')) + await removeCapability('measure_co2'); + } + break; default: break; } diff --git a/drivers/swegoncasa/SettingsHandler.ts b/drivers/swegoncasa/SettingsHandler.ts index 3321947..4d48826 100644 --- a/drivers/swegoncasa/SettingsHandler.ts +++ b/drivers/swegoncasa/SettingsHandler.ts @@ -82,6 +82,22 @@ class SettingsHandler { newSettings[SettingType.SupplyTemperatureSetpoint], ); } + + // CO2 Home Limit + if (newSettings[SettingType.CO2HomeLimit]) { + await swegonClient?.setValue( + SwegonObjectId.CO2HomeLimit, + newSettings[SettingType.CO2HomeLimit], + ); + } + + // CO2 Away Limit + if (newSettings[SettingType.CO2AwayLimit]) { + await swegonClient?.setValue( + SwegonObjectId.CO2AwayLimit, + newSettings[SettingType.CO2AwayLimit], + ); + } } public async HandleDeviceSettingChanged( diff --git a/drivers/swegoncasa/SwegonClient.ts b/drivers/swegoncasa/SwegonClient.ts index 2257865..302be5a 100644 --- a/drivers/swegoncasa/SwegonClient.ts +++ b/drivers/swegoncasa/SwegonClient.ts @@ -378,6 +378,12 @@ class SwegonClient { value: parseFloat(measurementValue), }); break; + case SwegonObjectId.CO2: + this.eventHandler.emit('measurement', { + type: MeasurementType.CO2, + value: parseInt(measurementValue, 10), + }); + break; case SwegonObjectId.Humidity: this.eventHandler.emit('measurement', { type: MeasurementType.HumidityPercent, @@ -486,6 +492,18 @@ class SwegonClient { value: parseInt(measurementValue, 10), }); break; + case SwegonObjectId.CO2HomeLimit: + this.eventHandler.emit('setting', { + id: SettingType.CO2HomeLimit, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.CO2AwayLimit: + this.eventHandler.emit('setting', { + id: SettingType.CO2AwayLimit, + value: parseInt(measurementValue, 10), + }); + break; default: break; } diff --git a/drivers/swegoncasa/SwegonConstants.ts b/drivers/swegoncasa/SwegonConstants.ts index 30b245f..26ce34f 100644 --- a/drivers/swegoncasa/SwegonConstants.ts +++ b/drivers/swegoncasa/SwegonConstants.ts @@ -67,7 +67,7 @@ const SubscriptionArgs: SwegonMeasurementMessage = { }, }, { - id: '21', + id: SwegonObjectId.CO2, device: '255', properties: { '85': {}, @@ -213,6 +213,20 @@ const SubscriptionArgs: SwegonMeasurementMessage = { '85': {}, }, }, + { + id: SwegonObjectId.CO2HomeLimit, + device: '255', + properties: { + '85': {}, + }, + }, + { + id: SwegonObjectId.CO2AwayLimit, + device: '255', + properties: { + '85': {}, + }, + }, ], }, }; diff --git a/drivers/swegoncasa/device.ts b/drivers/swegoncasa/device.ts index f408f41..4e20a97 100644 --- a/drivers/swegoncasa/device.ts +++ b/drivers/swegoncasa/device.ts @@ -35,6 +35,14 @@ class SwegonCasaDevice extends Homey.Device { if (!settings.summerNightCoolingBoost) { this.setSettings({ summerNightCoolingBoost: 'off' }); } + + if (!settings.co2HomeLimit) { + this.setSettings({ co2HomeLimit: 550 }); + } + + if (!settings.co2AwayLimit) { + this.setSettings({ co2AwayLimit: 400 }); + } } /** Add capabilities if they do not already exist */ @@ -94,6 +102,10 @@ class SwegonCasaDevice extends Homey.Device { if (!this.hasCapability('measure_air_quality')) { await this.addCapability('measure_air_quality'); } + + if (!this.hasCapability('measure_co2')) { + await this.addCapability('measure_co2'); + } } private async onMeasurement(data: Measurement): Promise { diff --git a/drivers/swegoncasa/driver.compose.json b/drivers/swegoncasa/driver.compose.json index 0fde29f..3f32c1f 100644 --- a/drivers/swegoncasa/driver.compose.json +++ b/drivers/swegoncasa/driver.compose.json @@ -21,6 +21,7 @@ "measure_ventilation_level_in", "measure_ventilation_level_out", "measure_air_quality", + "measure_co2", "climate_mode", "summer_night_cooling_mode", "auto_humidity_control_mode", diff --git a/drivers/swegoncasa/driver.settings.compose.json b/drivers/swegoncasa/driver.settings.compose.json index 77dcb64..03cecd3 100644 --- a/drivers/swegoncasa/driver.settings.compose.json +++ b/drivers/swegoncasa/driver.settings.compose.json @@ -239,6 +239,49 @@ } ] }, + { + "type": "group", + "label": { + "en": "CO2 Control", + "no": "CO2 Kontroll" + }, + "children": [ + { + "id": "co2HomeLimit", + "type": "number", + "value": 550, + "units": { + "en": "ppm", + "no": "ppm" + }, + "label": { + "en": "CO2 Home Limit", + "no": "CO2 Hjemme-grense" + }, + "hint": { + "en": "CO2 level threshold for Home mode in the Auto Home/Away/Boost feature", + "no": "CO2-nivågrense for Hjemme-modus i Auto Hjemme/Borte/Boost-funksjonen" + } + }, + { + "id": "co2AwayLimit", + "type": "number", + "value": 400, + "units": { + "en": "ppm", + "no": "ppm" + }, + "label": { + "en": "CO2 Away Limit", + "no": "CO2 Borte-grense" + }, + "hint": { + "en": "CO2 level threshold for Away mode in the Auto Home/Away/Boost feature", + "no": "CO2-nivågrense for Borte-modus i Auto Hjemme/Borte/Boost-funksjonen" + } + } + ] + }, { "type": "group", "label": { diff --git a/lib/MeasurementType.ts b/lib/MeasurementType.ts index 8cc2f68..0d876db 100644 --- a/lib/MeasurementType.ts +++ b/lib/MeasurementType.ts @@ -11,6 +11,7 @@ const enum MeasurementType { SummerNightCoolingMode, BoostCountDown, AirQuality, + CO2, } export default MeasurementType; diff --git a/lib/SettingType.ts b/lib/SettingType.ts index 3fd8f47..3e2b638 100644 --- a/lib/SettingType.ts +++ b/lib/SettingType.ts @@ -6,6 +6,8 @@ const enum SettingType { TravellingModeTemperatureDrop = 'travellingModeTemperatureDrop', AwayModeTemperatureDrop = 'awayModeTemperatureDrop', SupplyTemperatureSetpoint = 'supplyTemperatureSetpoint', + CO2HomeLimit = 'co2HomeLimit', + CO2AwayLimit = 'co2AwayLimit', } export default SettingType; diff --git a/lib/SwegonObjectId.ts b/lib/SwegonObjectId.ts index b3798ff..dba84b9 100644 --- a/lib/SwegonObjectId.ts +++ b/lib/SwegonObjectId.ts @@ -2,6 +2,7 @@ const enum SwegonObjectId { SupplyTemperature = '17', OutputTemperature = '18', IntakeTemperature = '19', + CO2 = '21', Humidity = '22', HumidityAmount = '23', AirQuality = '25', @@ -21,6 +22,8 @@ const enum SwegonObjectId { SupplyTemperatureSetpoint = '163', TemperatureControlMode = '164', AwayModeTemperatureDrop = '165', + CO2HomeLimit = '122', + CO2AwayLimit = '123', Device = '500', } From 82306cdeee19e81a13313fbe58bc94c1f557e3e0 Mon Sep 17 00:00:00 2001 From: araa Date: Mon, 5 Jan 2026 17:31:16 +0100 Subject: [PATCH 2/8] Add target temperature capability and enhance measurement handling in SwegonCasa driver. Implement triggers for temperature and ventilation level changes, and register new action and condition cards for improved control. Update localization files for additional terms. --- .../capabilities/target_temperature.json | 24 ++ .../set_auto_air_quality_control_mode.json | 75 +++++ .../set_auto_humidity_control_mode.json | 75 +++++ .../set_summer_night_cooling_mode.json | 75 +++++ .../flow/actions/set_temperature.json | 38 +++ .../flow/conditions/climate_mode_is.json | 75 +++++ .../flow/conditions/co2_is_above.json | 35 +++ .../flow/conditions/co2_is_below.json | 35 +++ .../flow/conditions/humidity_is_above.json | 35 +++ .../flow/conditions/humidity_is_below.json | 35 +++ .../flow/conditions/temperature_is_above.json | 66 +++++ .../flow/conditions/temperature_is_below.json | 66 +++++ .../flow/triggers/air_quality_changed.json | 30 ++ .../flow/triggers/climate_mode_changed.json | 30 ++ .../flow/triggers/co2_above_threshold.json | 46 +++ .../flow/triggers/co2_below_threshold.json | 46 +++ .homeycompose/flow/triggers/co2_changed.json | 30 ++ .../triggers/humidity_above_threshold.json | 46 +++ .../triggers/humidity_below_threshold.json | 46 +++ .../flow/triggers/humidity_changed.json | 30 ++ .../triggers/temperature_above_threshold.json | 77 +++++ .../triggers/temperature_below_threshold.json | 77 +++++ .../flow/triggers/temperature_changed.json | 65 +++++ .../ventilation_level_above_threshold.json | 70 +++++ .../ventilation_level_below_threshold.json | 70 +++++ .../triggers/ventilation_level_changed.json | 58 ++++ app.ts | 265 +++++++++++++++++- drivers/swegoncasa/MeasurementHandler.ts | 200 ++++++++++++- drivers/swegoncasa/SettingsHandler.ts | 5 + drivers/swegoncasa/device.ts | 90 +++++- drivers/swegoncasa/driver.compose.json | 1 + locales/en.json | 22 +- locales/no.json | 24 +- 33 files changed, 1944 insertions(+), 18 deletions(-) create mode 100644 .homeycompose/capabilities/target_temperature.json create mode 100644 .homeycompose/flow/actions/set_auto_air_quality_control_mode.json create mode 100644 .homeycompose/flow/actions/set_auto_humidity_control_mode.json create mode 100644 .homeycompose/flow/actions/set_summer_night_cooling_mode.json create mode 100644 .homeycompose/flow/actions/set_temperature.json create mode 100644 .homeycompose/flow/conditions/climate_mode_is.json create mode 100644 .homeycompose/flow/conditions/co2_is_above.json create mode 100644 .homeycompose/flow/conditions/co2_is_below.json create mode 100644 .homeycompose/flow/conditions/humidity_is_above.json create mode 100644 .homeycompose/flow/conditions/humidity_is_below.json create mode 100644 .homeycompose/flow/conditions/temperature_is_above.json create mode 100644 .homeycompose/flow/conditions/temperature_is_below.json create mode 100644 .homeycompose/flow/triggers/air_quality_changed.json create mode 100644 .homeycompose/flow/triggers/climate_mode_changed.json create mode 100644 .homeycompose/flow/triggers/co2_above_threshold.json create mode 100644 .homeycompose/flow/triggers/co2_below_threshold.json create mode 100644 .homeycompose/flow/triggers/co2_changed.json create mode 100644 .homeycompose/flow/triggers/humidity_above_threshold.json create mode 100644 .homeycompose/flow/triggers/humidity_below_threshold.json create mode 100644 .homeycompose/flow/triggers/humidity_changed.json create mode 100644 .homeycompose/flow/triggers/temperature_above_threshold.json create mode 100644 .homeycompose/flow/triggers/temperature_below_threshold.json create mode 100644 .homeycompose/flow/triggers/temperature_changed.json create mode 100644 .homeycompose/flow/triggers/ventilation_level_above_threshold.json create mode 100644 .homeycompose/flow/triggers/ventilation_level_below_threshold.json create mode 100644 .homeycompose/flow/triggers/ventilation_level_changed.json diff --git a/.homeycompose/capabilities/target_temperature.json b/.homeycompose/capabilities/target_temperature.json new file mode 100644 index 0000000..e84f151 --- /dev/null +++ b/.homeycompose/capabilities/target_temperature.json @@ -0,0 +1,24 @@ +{ + "type": "number", + "uiComponent": "thermostat", + "title": { + "en": "Target Temperature", + "no": "Ønsket temperatur" + }, + "desc": { + "en": "The target supply air temperature setpoint", + "no": "Ønsket temperaturinnstilling for tilluft" + }, + "units": { + "en": "°C", + "no": "°C" + }, + "min": 12, + "max": 22, + "step": 1, + "decimals": 0, + "getable": true, + "setable": true, + "insights": true +} + diff --git a/.homeycompose/flow/actions/set_auto_air_quality_control_mode.json b/.homeycompose/flow/actions/set_auto_air_quality_control_mode.json new file mode 100644 index 0000000..070f05b --- /dev/null +++ b/.homeycompose/flow/actions/set_auto_air_quality_control_mode.json @@ -0,0 +1,75 @@ +{ + "id": "set_auto_air_quality_control_mode", + "title": { + "en": "Set auto air quality control mode", + "no": "Sett automatisk luftkvalitetsmodus" + }, + "titleFormatted": { + "en": "Set auto air quality control mode to [[mode]]", + "no": "Sett automatisk luftkvalitetsmodus til [[mode]]" + }, + "hint": { + "en": "Sets the auto air quality control mode.", + "no": "Setter automatisk luftkvalitetsmodus." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "mode", + "type": "dropdown", + "title": { + "en": "Mode", + "no": "Modus" + }, + "values": [ + { + "id": "off", + "label": { + "en": "Off", + "no": "Av" + } + }, + { + "id": "user", + "label": { + "en": "User", + "no": "Bruker" + } + }, + { + "id": "low", + "label": { + "en": "Low", + "no": "Lav" + } + }, + { + "id": "normal", + "label": { + "en": "Normal", + "no": "Normal" + } + }, + { + "id": "high", + "label": { + "en": "High", + "no": "Høy" + } + }, + { + "id": "full", + "label": { + "en": "Full", + "no": "Full" + } + } + ] + } + ] +} + diff --git a/.homeycompose/flow/actions/set_auto_humidity_control_mode.json b/.homeycompose/flow/actions/set_auto_humidity_control_mode.json new file mode 100644 index 0000000..5179b3d --- /dev/null +++ b/.homeycompose/flow/actions/set_auto_humidity_control_mode.json @@ -0,0 +1,75 @@ +{ + "id": "set_auto_humidity_control_mode", + "title": { + "en": "Set auto humidity control mode", + "no": "Sett automatisk luftfuktighetsmodus" + }, + "titleFormatted": { + "en": "Set auto humidity control mode to [[mode]]", + "no": "Sett automatisk luftfuktighetsmodus til [[mode]]" + }, + "hint": { + "en": "Sets the auto humidity control mode.", + "no": "Setter automatisk luftfuktighetsmodus." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "mode", + "type": "dropdown", + "title": { + "en": "Mode", + "no": "Modus" + }, + "values": [ + { + "id": "off", + "label": { + "en": "Off", + "no": "Av" + } + }, + { + "id": "user", + "label": { + "en": "User", + "no": "Bruker" + } + }, + { + "id": "low", + "label": { + "en": "Low", + "no": "Lav" + } + }, + { + "id": "normal", + "label": { + "en": "Normal", + "no": "Normal" + } + }, + { + "id": "high", + "label": { + "en": "High", + "no": "Høy" + } + }, + { + "id": "full", + "label": { + "en": "Full", + "no": "Full" + } + } + ] + } + ] +} + diff --git a/.homeycompose/flow/actions/set_summer_night_cooling_mode.json b/.homeycompose/flow/actions/set_summer_night_cooling_mode.json new file mode 100644 index 0000000..2a7e812 --- /dev/null +++ b/.homeycompose/flow/actions/set_summer_night_cooling_mode.json @@ -0,0 +1,75 @@ +{ + "id": "set_summer_night_cooling_mode", + "title": { + "en": "Set summer night cooling mode", + "no": "Sett sommernatt avkjølingsmodus" + }, + "titleFormatted": { + "en": "Set summer night cooling mode to [[mode]]", + "no": "Sett sommernatt avkjølingsmodus til [[mode]]" + }, + "hint": { + "en": "Sets the summer night cooling mode.", + "no": "Setter sommernatt avkjølingsmodus." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "mode", + "type": "dropdown", + "title": { + "en": "Mode", + "no": "Modus" + }, + "values": [ + { + "id": "off", + "label": { + "en": "Off", + "no": "Av" + } + }, + { + "id": "low", + "label": { + "en": "Low", + "no": "Lav" + } + }, + { + "id": "normal", + "label": { + "en": "Normal", + "no": "Normal" + } + }, + { + "id": "high", + "label": { + "en": "High", + "no": "Høy" + } + }, + { + "id": "full", + "label": { + "en": "Full", + "no": "Full" + } + }, + { + "id": "user", + "label": { + "en": "User", + "no": "Bruker" + } + } + ] + } + ] +} + diff --git a/.homeycompose/flow/actions/set_temperature.json b/.homeycompose/flow/actions/set_temperature.json new file mode 100644 index 0000000..b018640 --- /dev/null +++ b/.homeycompose/flow/actions/set_temperature.json @@ -0,0 +1,38 @@ +{ + "id": "set_temperature", + "title": { + "en": "Set target temperature", + "no": "Sett ønsket temperatur" + }, + "titleFormatted": { + "en": "Set target temperature to [[temperature]] °C", + "no": "Sett ønsket temperatur til [[temperature]] °C" + }, + "hint": { + "en": "Sets the supply air temperature setpoint.", + "no": "Setter temperaturinnstillingen for tilluft." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature", + "type": "number", + "title": { + "en": "Temperature", + "no": "Temperatur" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + }, + "min": 12, + "max": 22, + "step": 1 + } + ] +} + diff --git a/.homeycompose/flow/conditions/climate_mode_is.json b/.homeycompose/flow/conditions/climate_mode_is.json new file mode 100644 index 0000000..24b9f67 --- /dev/null +++ b/.homeycompose/flow/conditions/climate_mode_is.json @@ -0,0 +1,75 @@ +{ + "id": "climate_mode_is", + "title": { + "en": "Climate mode !{{is|isn't}}", + "no": "Klimamodusen !{{er|er ikke}}" + }, + "titleFormatted": { + "en": "Climate mode !{{is|isn't}} [[climate_mode]]", + "no": "Klimamodusen !{{er|er ikke}} [[climate_mode]]" + }, + "hint": { + "en": "Check if the climate mode equals a specific mode.", + "no": "Sjekk om klimamodusen er lik en spesifikk modus." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "climate_mode", + "type": "dropdown", + "title": { + "en": "Climate Mode", + "no": "Klimamodus" + }, + "values": [ + { + "id": "away", + "label": { + "en": "Away", + "no": "Borte" + } + }, + { + "id": "home", + "label": { + "en": "Home", + "no": "Hjemme" + } + }, + { + "id": "boost", + "label": { + "en": "Boost", + "no": "Boost" + } + }, + { + "id": "travel", + "label": { + "en": "Travel", + "no": "Reise" + } + }, + { + "id": "off", + "label": { + "en": "Off", + "no": "Av" + } + }, + { + "id": "fireplace", + "label": { + "en": "Fireplace", + "no": "Peis" + } + } + ] + } + ] +} + diff --git a/.homeycompose/flow/conditions/co2_is_above.json b/.homeycompose/flow/conditions/co2_is_above.json new file mode 100644 index 0000000..185638d --- /dev/null +++ b/.homeycompose/flow/conditions/co2_is_above.json @@ -0,0 +1,35 @@ +{ + "id": "co2_is_above", + "title": { + "en": "CO2 level !{{is|isn't}} above", + "no": "CO2-nivået !{{er|er ikke}} over" + }, + "titleFormatted": { + "en": "CO2 level !{{is|isn't}} above [[threshold]] ppm", + "no": "CO2-nivået !{{er|er ikke}} over [[threshold]] ppm" + }, + "hint": { + "en": "Check if the CO2 level is above a specified value.", + "no": "Sjekk om CO2-nivået er over en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "CO2 in ppm", + "no": "CO2 i ppm" + } + } + ] +} + diff --git a/.homeycompose/flow/conditions/co2_is_below.json b/.homeycompose/flow/conditions/co2_is_below.json new file mode 100644 index 0000000..d1c0a46 --- /dev/null +++ b/.homeycompose/flow/conditions/co2_is_below.json @@ -0,0 +1,35 @@ +{ + "id": "co2_is_below", + "title": { + "en": "CO2 level !{{is|isn't}} below", + "no": "CO2-nivået !{{er|er ikke}} under" + }, + "titleFormatted": { + "en": "CO2 level !{{is|isn't}} below [[threshold]] ppm", + "no": "CO2-nivået !{{er|er ikke}} under [[threshold]] ppm" + }, + "hint": { + "en": "Check if the CO2 level is below a specified value.", + "no": "Sjekk om CO2-nivået er under en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "CO2 in ppm", + "no": "CO2 i ppm" + } + } + ] +} + diff --git a/.homeycompose/flow/conditions/humidity_is_above.json b/.homeycompose/flow/conditions/humidity_is_above.json new file mode 100644 index 0000000..cd2072a --- /dev/null +++ b/.homeycompose/flow/conditions/humidity_is_above.json @@ -0,0 +1,35 @@ +{ + "id": "humidity_is_above", + "title": { + "en": "Humidity !{{is|isn't}} above", + "no": "Luftfuktigheten !{{er|er ikke}} over" + }, + "titleFormatted": { + "en": "Humidity !{{is|isn't}} above [[threshold]]%", + "no": "Luftfuktigheten !{{er|er ikke}} over [[threshold]]%" + }, + "hint": { + "en": "Check if the humidity is above a specified value.", + "no": "Sjekk om luftfuktigheten er over en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Humidity in %", + "no": "Luftfuktighet i %" + } + } + ] +} + diff --git a/.homeycompose/flow/conditions/humidity_is_below.json b/.homeycompose/flow/conditions/humidity_is_below.json new file mode 100644 index 0000000..8639a54 --- /dev/null +++ b/.homeycompose/flow/conditions/humidity_is_below.json @@ -0,0 +1,35 @@ +{ + "id": "humidity_is_below", + "title": { + "en": "Humidity !{{is|isn't}} below", + "no": "Luftfuktigheten !{{er|er ikke}} under" + }, + "titleFormatted": { + "en": "Humidity !{{is|isn't}} below [[threshold]]%", + "no": "Luftfuktigheten !{{er|er ikke}} under [[threshold]]%" + }, + "hint": { + "en": "Check if the humidity is below a specified value.", + "no": "Sjekk om luftfuktigheten er under en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Humidity in %", + "no": "Luftfuktighet i %" + } + } + ] +} + diff --git a/.homeycompose/flow/conditions/temperature_is_above.json b/.homeycompose/flow/conditions/temperature_is_above.json new file mode 100644 index 0000000..09c02f6 --- /dev/null +++ b/.homeycompose/flow/conditions/temperature_is_above.json @@ -0,0 +1,66 @@ +{ + "id": "temperature_is_above", + "title": { + "en": "Temperature !{{is|isn't}} above", + "no": "Temperaturen !{{er|er ikke}} over" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature !{{is|isn't}} above [[threshold]] °C", + "no": "[[temperature_type]] temperaturen !{{er|er ikke}} over [[threshold]] °C" + }, + "hint": { + "en": "Check if the selected temperature is above a specified value.", + "no": "Sjekk om den valgte temperaturen er over en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + } + } + ] +} + diff --git a/.homeycompose/flow/conditions/temperature_is_below.json b/.homeycompose/flow/conditions/temperature_is_below.json new file mode 100644 index 0000000..2edc528 --- /dev/null +++ b/.homeycompose/flow/conditions/temperature_is_below.json @@ -0,0 +1,66 @@ +{ + "id": "temperature_is_below", + "title": { + "en": "Temperature !{{is|isn't}} below", + "no": "Temperaturen !{{er|er ikke}} under" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature !{{is|isn't}} below [[threshold]] °C", + "no": "[[temperature_type]] temperaturen !{{er|er ikke}} under [[threshold]] °C" + }, + "hint": { + "en": "Check if the selected temperature is below a specified value.", + "no": "Sjekk om den valgte temperaturen er under en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + } + } + ] +} + diff --git a/.homeycompose/flow/triggers/air_quality_changed.json b/.homeycompose/flow/triggers/air_quality_changed.json new file mode 100644 index 0000000..c6f8f6d --- /dev/null +++ b/.homeycompose/flow/triggers/air_quality_changed.json @@ -0,0 +1,30 @@ +{ + "id": "air_quality_changed", + "title": { + "en": "Air quality changed", + "no": "Luftkvaliteten endret seg" + }, + "hint": { + "en": "Triggers when the air quality level changes.", + "no": "Utløses når luftkvaliteten endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + } + ], + "tokens": [ + { + "name": "air_quality", + "type": "number", + "title": { + "en": "Air Quality", + "no": "Luftkvalitet" + }, + "example": 500 + } + ] +} + diff --git a/.homeycompose/flow/triggers/climate_mode_changed.json b/.homeycompose/flow/triggers/climate_mode_changed.json new file mode 100644 index 0000000..ba94b5d --- /dev/null +++ b/.homeycompose/flow/triggers/climate_mode_changed.json @@ -0,0 +1,30 @@ +{ + "id": "climate_mode_changed", + "title": { + "en": "Climate mode changed", + "no": "Klimamodusen endret seg" + }, + "hint": { + "en": "Triggers when the climate control mode changes.", + "no": "Utløses når klimakontrollmodusen endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + } + ], + "tokens": [ + { + "name": "climate_mode", + "type": "string", + "title": { + "en": "Climate Mode", + "no": "Klimamodus" + }, + "example": "home" + } + ] +} + diff --git a/.homeycompose/flow/triggers/co2_above_threshold.json b/.homeycompose/flow/triggers/co2_above_threshold.json new file mode 100644 index 0000000..b754d2b --- /dev/null +++ b/.homeycompose/flow/triggers/co2_above_threshold.json @@ -0,0 +1,46 @@ +{ + "id": "co2_above_threshold", + "title": { + "en": "CO2 level went above", + "no": "CO2-nivået gikk over" + }, + "titleFormatted": { + "en": "CO2 level went above [[threshold]] ppm", + "no": "CO2-nivået gikk over [[threshold]] ppm" + }, + "hint": { + "en": "Triggers when the CO2 level goes above the specified threshold.", + "no": "Utløses når CO2-nivået går over den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "CO2 in ppm", + "no": "CO2 i ppm" + } + } + ], + "tokens": [ + { + "name": "co2", + "type": "number", + "title": { + "en": "CO2", + "no": "CO2" + }, + "example": 450 + } + ] +} + diff --git a/.homeycompose/flow/triggers/co2_below_threshold.json b/.homeycompose/flow/triggers/co2_below_threshold.json new file mode 100644 index 0000000..1098314 --- /dev/null +++ b/.homeycompose/flow/triggers/co2_below_threshold.json @@ -0,0 +1,46 @@ +{ + "id": "co2_below_threshold", + "title": { + "en": "CO2 level went below", + "no": "CO2-nivået gikk under" + }, + "titleFormatted": { + "en": "CO2 level went below [[threshold]] ppm", + "no": "CO2-nivået gikk under [[threshold]] ppm" + }, + "hint": { + "en": "Triggers when the CO2 level goes below the specified threshold.", + "no": "Utløses når CO2-nivået går under den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "CO2 in ppm", + "no": "CO2 i ppm" + } + } + ], + "tokens": [ + { + "name": "co2", + "type": "number", + "title": { + "en": "CO2", + "no": "CO2" + }, + "example": 450 + } + ] +} + diff --git a/.homeycompose/flow/triggers/co2_changed.json b/.homeycompose/flow/triggers/co2_changed.json new file mode 100644 index 0000000..711b646 --- /dev/null +++ b/.homeycompose/flow/triggers/co2_changed.json @@ -0,0 +1,30 @@ +{ + "id": "co2_changed", + "title": { + "en": "CO2 level changed", + "no": "CO2-nivået endret seg" + }, + "hint": { + "en": "Triggers when the CO2 level changes.", + "no": "Utløses når CO2-nivået endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + } + ], + "tokens": [ + { + "name": "co2", + "type": "number", + "title": { + "en": "CO2", + "no": "CO2" + }, + "example": 450 + } + ] +} + diff --git a/.homeycompose/flow/triggers/humidity_above_threshold.json b/.homeycompose/flow/triggers/humidity_above_threshold.json new file mode 100644 index 0000000..c4c2840 --- /dev/null +++ b/.homeycompose/flow/triggers/humidity_above_threshold.json @@ -0,0 +1,46 @@ +{ + "id": "humidity_above_threshold", + "title": { + "en": "Humidity went above", + "no": "Luftfuktigheten gikk over" + }, + "titleFormatted": { + "en": "Humidity went above [[threshold]]%", + "no": "Luftfuktigheten gikk over [[threshold]]%" + }, + "hint": { + "en": "Triggers when the humidity goes above the specified threshold.", + "no": "Utløses når luftfuktigheten går over den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Humidity in %", + "no": "Luftfuktighet i %" + } + } + ], + "tokens": [ + { + "name": "humidity", + "type": "number", + "title": { + "en": "Humidity", + "no": "Luftfuktighet" + }, + "example": 45 + } + ] +} + diff --git a/.homeycompose/flow/triggers/humidity_below_threshold.json b/.homeycompose/flow/triggers/humidity_below_threshold.json new file mode 100644 index 0000000..fabf852 --- /dev/null +++ b/.homeycompose/flow/triggers/humidity_below_threshold.json @@ -0,0 +1,46 @@ +{ + "id": "humidity_below_threshold", + "title": { + "en": "Humidity went below", + "no": "Luftfuktigheten gikk under" + }, + "titleFormatted": { + "en": "Humidity went below [[threshold]]%", + "no": "Luftfuktigheten gikk under [[threshold]]%" + }, + "hint": { + "en": "Triggers when the humidity goes below the specified threshold.", + "no": "Utløses når luftfuktigheten går under den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Humidity in %", + "no": "Luftfuktighet i %" + } + } + ], + "tokens": [ + { + "name": "humidity", + "type": "number", + "title": { + "en": "Humidity", + "no": "Luftfuktighet" + }, + "example": 45 + } + ] +} + diff --git a/.homeycompose/flow/triggers/humidity_changed.json b/.homeycompose/flow/triggers/humidity_changed.json new file mode 100644 index 0000000..5f6c31f --- /dev/null +++ b/.homeycompose/flow/triggers/humidity_changed.json @@ -0,0 +1,30 @@ +{ + "id": "humidity_changed", + "title": { + "en": "Humidity changed", + "no": "Luftfuktigheten endret seg" + }, + "hint": { + "en": "Triggers when the humidity percentage changes.", + "no": "Utløses når luftfuktighetsprosenten endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + } + ], + "tokens": [ + { + "name": "humidity", + "type": "number", + "title": { + "en": "Humidity", + "no": "Luftfuktighet" + }, + "example": 45 + } + ] +} + diff --git a/.homeycompose/flow/triggers/temperature_above_threshold.json b/.homeycompose/flow/triggers/temperature_above_threshold.json new file mode 100644 index 0000000..380eabc --- /dev/null +++ b/.homeycompose/flow/triggers/temperature_above_threshold.json @@ -0,0 +1,77 @@ +{ + "id": "temperature_above_threshold", + "title": { + "en": "Temperature went above", + "no": "Temperaturen gikk over" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature went above [[threshold]] °C", + "no": "[[temperature_type]] temperaturen gikk over [[threshold]] °C" + }, + "hint": { + "en": "Triggers when the selected temperature goes above the specified threshold.", + "no": "Utløses når den valgte temperaturen går over den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + } + } + ], + "tokens": [ + { + "name": "temperature", + "type": "number", + "title": { + "en": "Temperature", + "no": "Temperatur" + }, + "example": 21.5 + } + ] +} + diff --git a/.homeycompose/flow/triggers/temperature_below_threshold.json b/.homeycompose/flow/triggers/temperature_below_threshold.json new file mode 100644 index 0000000..e27894c --- /dev/null +++ b/.homeycompose/flow/triggers/temperature_below_threshold.json @@ -0,0 +1,77 @@ +{ + "id": "temperature_below_threshold", + "title": { + "en": "Temperature went below", + "no": "Temperaturen gikk under" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature went below [[threshold]] °C", + "no": "[[temperature_type]] temperaturen gikk under [[threshold]] °C" + }, + "hint": { + "en": "Triggers when the selected temperature goes below the specified threshold.", + "no": "Utløses når den valgte temperaturen går under den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + } + } + ], + "tokens": [ + { + "name": "temperature", + "type": "number", + "title": { + "en": "Temperature", + "no": "Temperatur" + }, + "example": 21.5 + } + ] +} + diff --git a/.homeycompose/flow/triggers/temperature_changed.json b/.homeycompose/flow/triggers/temperature_changed.json new file mode 100644 index 0000000..ebfc350 --- /dev/null +++ b/.homeycompose/flow/triggers/temperature_changed.json @@ -0,0 +1,65 @@ +{ + "id": "temperature_changed", + "title": { + "en": "Temperature changed", + "no": "Temperaturen endret seg" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature changed", + "no": "[[temperature_type]] temperaturen endret seg" + }, + "hint": { + "en": "Triggers when the selected temperature changes.", + "no": "Utløses når den valgte temperaturen endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + } + ], + "tokens": [ + { + "name": "temperature", + "type": "number", + "title": { + "en": "Temperature", + "no": "Temperatur" + }, + "example": 21.5 + } + ] +} + diff --git a/.homeycompose/flow/triggers/ventilation_level_above_threshold.json b/.homeycompose/flow/triggers/ventilation_level_above_threshold.json new file mode 100644 index 0000000..b4f6cfa --- /dev/null +++ b/.homeycompose/flow/triggers/ventilation_level_above_threshold.json @@ -0,0 +1,70 @@ +{ + "id": "ventilation_level_above_threshold", + "title": { + "en": "Ventilation level went above", + "no": "Ventilasjonsnivået gikk over" + }, + "titleFormatted": { + "en": "[[ventilation_type]] ventilation level went above [[threshold]]%", + "no": "[[ventilation_type]] ventilasjonsnivået gikk over [[threshold]]%" + }, + "hint": { + "en": "Triggers when the ventilation level goes above the specified threshold.", + "no": "Utløses når ventilasjonsnivået går over den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "ventilation_type", + "type": "dropdown", + "title": { + "en": "Ventilation Type", + "no": "Ventilasjonstype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "exhaust", + "label": { + "en": "Exhaust", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Level in %", + "no": "Nivå i %" + } + } + ], + "tokens": [ + { + "name": "level", + "type": "number", + "title": { + "en": "Level", + "no": "Nivå" + }, + "example": 75 + } + ] +} + diff --git a/.homeycompose/flow/triggers/ventilation_level_below_threshold.json b/.homeycompose/flow/triggers/ventilation_level_below_threshold.json new file mode 100644 index 0000000..3180ba3 --- /dev/null +++ b/.homeycompose/flow/triggers/ventilation_level_below_threshold.json @@ -0,0 +1,70 @@ +{ + "id": "ventilation_level_below_threshold", + "title": { + "en": "Ventilation level went below", + "no": "Ventilasjonsnivået gikk under" + }, + "titleFormatted": { + "en": "[[ventilation_type]] ventilation level went below [[threshold]]%", + "no": "[[ventilation_type]] ventilasjonsnivået gikk under [[threshold]]%" + }, + "hint": { + "en": "Triggers when the ventilation level goes below the specified threshold.", + "no": "Utløses når ventilasjonsnivået går under den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "ventilation_type", + "type": "dropdown", + "title": { + "en": "Ventilation Type", + "no": "Ventilasjonstype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "exhaust", + "label": { + "en": "Exhaust", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Level in %", + "no": "Nivå i %" + } + } + ], + "tokens": [ + { + "name": "level", + "type": "number", + "title": { + "en": "Level", + "no": "Nivå" + }, + "example": 75 + } + ] +} + diff --git a/.homeycompose/flow/triggers/ventilation_level_changed.json b/.homeycompose/flow/triggers/ventilation_level_changed.json new file mode 100644 index 0000000..622b233 --- /dev/null +++ b/.homeycompose/flow/triggers/ventilation_level_changed.json @@ -0,0 +1,58 @@ +{ + "id": "ventilation_level_changed", + "title": { + "en": "Ventilation level changed", + "no": "Ventilasjonsnivået endret seg" + }, + "titleFormatted": { + "en": "[[ventilation_type]] ventilation level changed", + "no": "[[ventilation_type]] ventilasjonsnivået endret seg" + }, + "hint": { + "en": "Triggers when the ventilation level (fan speed %) changes.", + "no": "Utløses når ventilasjonsnivået (viftehastighet %) endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "ventilation_type", + "type": "dropdown", + "title": { + "en": "Ventilation Type", + "no": "Ventilasjonstype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "exhaust", + "label": { + "en": "Exhaust", + "no": "Avtrekk" + } + } + ] + } + ], + "tokens": [ + { + "name": "level", + "type": "number", + "title": { + "en": "Level", + "no": "Nivå" + }, + "example": 75 + } + ] +} + diff --git a/app.ts b/app.ts index 2d0763e..b205759 100644 --- a/app.ts +++ b/app.ts @@ -5,13 +5,274 @@ class SwegonCasa extends Homey.App { * onInit is called when the app is initialized. */ async onInit(): Promise { + // Register Action Cards + this.registerActionCards(); + + // Register Trigger Cards + this.registerTriggerCards(); + + // Register Condition Cards + this.registerConditionCards(); + + this.log('SwegonCasa has been initialized'); + } + + private registerActionCards(): void { + // Set Climate Mode this.homey.flow .getActionCard('set_climate_mode') - .registerRunListener((args, state) => + .registerRunListener((args) => args.device.onClimateModeActionTriggered(args.climate_mode), ); - this.log('SwegonCasa has been initialized'); + // Set Temperature + this.homey.flow + .getActionCard('set_temperature') + .registerRunListener((args) => + args.device.onSetTemperatureActionTriggered(args.temperature), + ); + + // Set Summer Night Cooling Mode + this.homey.flow + .getActionCard('set_summer_night_cooling_mode') + .registerRunListener((args) => + args.device.onSetSummerNightCoolingModeActionTriggered(args.mode), + ); + + // Set Auto Humidity Control Mode + this.homey.flow + .getActionCard('set_auto_humidity_control_mode') + .registerRunListener((args) => + args.device.onSetAutoHumidityControlModeActionTriggered(args.mode), + ); + + // Set Auto Air Quality Control Mode + this.homey.flow + .getActionCard('set_auto_air_quality_control_mode') + .registerRunListener((args) => + args.device.onSetAutoAirQualityControlModeActionTriggered(args.mode), + ); + } + + private registerTriggerCards(): void { + // Temperature Changed - filter by temperature type + this.homey.flow + .getDeviceTriggerCard('temperature_changed') + .registerRunListener((args, state) => { + return args.temperature_type === state.temperature_type; + }); + + // Temperature Above Threshold + this.homey.flow + .getDeviceTriggerCard('temperature_above_threshold') + .registerRunListener((args, state) => { + const { threshold, temperature_type } = args; + const { previousValue } = state; + const currentValue = state.temperature_type === temperature_type ? args.device.getCapabilityValue( + temperature_type === 'supply' ? 'measure_supply_temperature' : + temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' + ) : null; + + // Check if type matches and value crossed threshold from below + return temperature_type === state.temperature_type && + previousValue !== undefined && + previousValue <= threshold && + currentValue > threshold; + }); + + // Temperature Below Threshold + this.homey.flow + .getDeviceTriggerCard('temperature_below_threshold') + .registerRunListener((args, state) => { + const { threshold, temperature_type } = args; + const { previousValue } = state; + const currentValue = args.device.getCapabilityValue( + temperature_type === 'supply' ? 'measure_supply_temperature' : + temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' + ); + + return temperature_type === state.temperature_type && + previousValue !== undefined && + previousValue >= threshold && + currentValue < threshold; + }); + + // Ventilation Level Changed + this.homey.flow + .getDeviceTriggerCard('ventilation_level_changed') + .registerRunListener((args, state) => { + return args.ventilation_type === state.ventilation_type; + }); + + // Ventilation Level Above Threshold + this.homey.flow + .getDeviceTriggerCard('ventilation_level_above_threshold') + .registerRunListener((args, state) => { + const { threshold, ventilation_type } = args; + const { previousValue } = state; + const currentValue = args.device.getCapabilityValue( + ventilation_type === 'supply' ? 'measure_ventilation_level_in' : 'measure_ventilation_level_out' + ); + + return ventilation_type === state.ventilation_type && + previousValue !== undefined && + previousValue <= threshold && + currentValue > threshold; + }); + + // Ventilation Level Below Threshold + this.homey.flow + .getDeviceTriggerCard('ventilation_level_below_threshold') + .registerRunListener((args, state) => { + const { threshold, ventilation_type } = args; + const { previousValue } = state; + const currentValue = args.device.getCapabilityValue( + ventilation_type === 'supply' ? 'measure_ventilation_level_in' : 'measure_ventilation_level_out' + ); + + return ventilation_type === state.ventilation_type && + previousValue !== undefined && + previousValue >= threshold && + currentValue < threshold; + }); + + // Humidity Changed - no filtering needed + this.homey.flow + .getDeviceTriggerCard('humidity_changed') + .registerRunListener(() => true); + + // Humidity Above Threshold + this.homey.flow + .getDeviceTriggerCard('humidity_above_threshold') + .registerRunListener((args, state) => { + const { threshold } = args; + const { previousValue } = state; + const currentValue = args.device.getCapabilityValue('measure_humidity_percent'); + + return previousValue !== undefined && + previousValue <= threshold && + currentValue > threshold; + }); + + // Humidity Below Threshold + this.homey.flow + .getDeviceTriggerCard('humidity_below_threshold') + .registerRunListener((args, state) => { + const { threshold } = args; + const { previousValue } = state; + const currentValue = args.device.getCapabilityValue('measure_humidity_percent'); + + return previousValue !== undefined && + previousValue >= threshold && + currentValue < threshold; + }); + + // CO2 Changed - no filtering needed + this.homey.flow + .getDeviceTriggerCard('co2_changed') + .registerRunListener(() => true); + + // CO2 Above Threshold + this.homey.flow + .getDeviceTriggerCard('co2_above_threshold') + .registerRunListener((args, state) => { + const { threshold } = args; + const { previousValue } = state; + const currentValue = args.device.getCapabilityValue('measure_co2'); + + return previousValue !== undefined && + previousValue <= threshold && + currentValue > threshold; + }); + + // CO2 Below Threshold + this.homey.flow + .getDeviceTriggerCard('co2_below_threshold') + .registerRunListener((args, state) => { + const { threshold } = args; + const { previousValue } = state; + const currentValue = args.device.getCapabilityValue('measure_co2'); + + return previousValue !== undefined && + previousValue >= threshold && + currentValue < threshold; + }); + + // Air Quality Changed - no filtering needed + this.homey.flow + .getDeviceTriggerCard('air_quality_changed') + .registerRunListener(() => true); + + // Climate Mode Changed - no filtering needed + this.homey.flow + .getDeviceTriggerCard('climate_mode_changed') + .registerRunListener(() => true); + } + + private registerConditionCards(): void { + // Temperature Is Above + this.homey.flow + .getConditionCard('temperature_is_above') + .registerRunListener((args) => { + const { temperature_type, threshold } = args; + const currentValue = args.device.getCapabilityValue( + temperature_type === 'supply' ? 'measure_supply_temperature' : + temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' + ); + return currentValue > threshold; + }); + + // Temperature Is Below + this.homey.flow + .getConditionCard('temperature_is_below') + .registerRunListener((args) => { + const { temperature_type, threshold } = args; + const currentValue = args.device.getCapabilityValue( + temperature_type === 'supply' ? 'measure_supply_temperature' : + temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' + ); + return currentValue < threshold; + }); + + // Humidity Is Above + this.homey.flow + .getConditionCard('humidity_is_above') + .registerRunListener((args) => { + const currentValue = args.device.getCapabilityValue('measure_humidity_percent'); + return currentValue > args.threshold; + }); + + // Humidity Is Below + this.homey.flow + .getConditionCard('humidity_is_below') + .registerRunListener((args) => { + const currentValue = args.device.getCapabilityValue('measure_humidity_percent'); + return currentValue < args.threshold; + }); + + // CO2 Is Above + this.homey.flow + .getConditionCard('co2_is_above') + .registerRunListener((args) => { + const currentValue = args.device.getCapabilityValue('measure_co2'); + return currentValue > args.threshold; + }); + + // CO2 Is Below + this.homey.flow + .getConditionCard('co2_is_below') + .registerRunListener((args) => { + const currentValue = args.device.getCapabilityValue('measure_co2'); + return currentValue < args.threshold; + }); + + // Climate Mode Is + this.homey.flow + .getConditionCard('climate_mode_is') + .registerRunListener((args) => { + const currentMode = args.device.getCapabilityValue('climate_mode'); + return currentMode === args.climate_mode; + }); } } diff --git a/drivers/swegoncasa/MeasurementHandler.ts b/drivers/swegoncasa/MeasurementHandler.ts index 8ddc4ab..19aca4d 100644 --- a/drivers/swegoncasa/MeasurementHandler.ts +++ b/drivers/swegoncasa/MeasurementHandler.ts @@ -3,37 +3,144 @@ import MeasurementType from '../../lib/MeasurementType'; import { Measurement } from '../../types'; import ModeType from '../../lib/ModeType'; +export interface TriggerEvent { + triggerId: string; + state: Record; + tokens: Record; +} + class MeasurementHandler { private logger: Logger; + private previousValues: Map = new Map(); constructor(logger: Logger) { this.logger = logger; } + private getPreviousValue(key: string): number | undefined { + return this.previousValues.get(key); + } + + private setPreviousValue(key: string, value: number): void { + this.previousValues.set(key, value); + } + public async HandleMeasurement( setCapabilityValue: (capabilityId: string, value: any) => Promise, data: Measurement, hasCapability: (capabilityId: string) => boolean, addCapability: (capabilityId: string) => Promise, removeCapability: (capabilityId: string) => Promise, - ): Promise { + ): Promise { + const triggers: TriggerEvent[] = []; + switch (data.type) { - case MeasurementType.SupplyTemperature: + case MeasurementType.SupplyTemperature: { this.logger.info(`SupplyTemperature: ${data.value}`); + const prevValue = this.getPreviousValue('supply_temperature'); await setCapabilityValue('measure_supply_temperature', data.value); + + // Temperature changed trigger + triggers.push({ + triggerId: 'temperature_changed', + state: { temperature_type: 'supply' }, + tokens: { temperature: data.value }, + }); + + // Threshold triggers + if (prevValue !== undefined) { + triggers.push({ + triggerId: 'temperature_above_threshold', + state: { temperature_type: 'supply', previousValue: prevValue }, + tokens: { temperature: data.value }, + }); + triggers.push({ + triggerId: 'temperature_below_threshold', + state: { temperature_type: 'supply', previousValue: prevValue }, + tokens: { temperature: data.value }, + }); + } + this.setPreviousValue('supply_temperature', data.value); break; - case MeasurementType.ReturnTemperature: + } + case MeasurementType.ReturnTemperature: { this.logger.info(`ReturnTemperature: ${data.value}`); + const prevValue = this.getPreviousValue('return_temperature'); await setCapabilityValue('measure_return_temperature', data.value); + + triggers.push({ + triggerId: 'temperature_changed', + state: { temperature_type: 'return' }, + tokens: { temperature: data.value }, + }); + + if (prevValue !== undefined) { + triggers.push({ + triggerId: 'temperature_above_threshold', + state: { temperature_type: 'return', previousValue: prevValue }, + tokens: { temperature: data.value }, + }); + triggers.push({ + triggerId: 'temperature_below_threshold', + state: { temperature_type: 'return', previousValue: prevValue }, + tokens: { temperature: data.value }, + }); + } + this.setPreviousValue('return_temperature', data.value); break; - case MeasurementType.IntakeTemperature: + } + case MeasurementType.IntakeTemperature: { this.logger.info(`IntakeTemperature: ${data.value}`); + const prevValue = this.getPreviousValue('intake_temperature'); await setCapabilityValue('measure_intake_temperature', data.value); + + triggers.push({ + triggerId: 'temperature_changed', + state: { temperature_type: 'intake' }, + tokens: { temperature: data.value }, + }); + + if (prevValue !== undefined) { + triggers.push({ + triggerId: 'temperature_above_threshold', + state: { temperature_type: 'intake', previousValue: prevValue }, + tokens: { temperature: data.value }, + }); + triggers.push({ + triggerId: 'temperature_below_threshold', + state: { temperature_type: 'intake', previousValue: prevValue }, + tokens: { temperature: data.value }, + }); + } + this.setPreviousValue('intake_temperature', data.value); break; - case MeasurementType.HumidityPercent: + } + case MeasurementType.HumidityPercent: { this.logger.info(`HumidityPercent: ${data.value}`); + const prevValue = this.getPreviousValue('humidity_percent'); await setCapabilityValue('measure_humidity_percent', data.value); + + triggers.push({ + triggerId: 'humidity_changed', + state: {}, + tokens: { humidity: data.value }, + }); + + if (prevValue !== undefined) { + triggers.push({ + triggerId: 'humidity_above_threshold', + state: { previousValue: prevValue }, + tokens: { humidity: data.value }, + }); + triggers.push({ + triggerId: 'humidity_below_threshold', + state: { previousValue: prevValue }, + tokens: { humidity: data.value }, + }); + } + this.setPreviousValue('humidity_percent', data.value); break; + } case MeasurementType.HumidityAmount: this.logger.info(`HumidityAmount: ${data.value}`); await setCapabilityValue('measure_humidity_amount', data.value); @@ -42,19 +149,63 @@ class MeasurementHandler { this.logger.info(`CurrentFanSpeed: ${data.value}`); await setCapabilityValue('measure_fan_speed', data.value.toString()); break; - case MeasurementType.VentilationLevelIn: + case MeasurementType.VentilationLevelIn: { this.logger.info(`VentilationLevelIn: ${data.value}`); + const prevValue = this.getPreviousValue('ventilation_level_in'); await setCapabilityValue('measure_ventilation_level_in', data.value); + + triggers.push({ + triggerId: 'ventilation_level_changed', + state: { ventilation_type: 'supply' }, + tokens: { level: data.value }, + }); + + if (prevValue !== undefined) { + triggers.push({ + triggerId: 'ventilation_level_above_threshold', + state: { ventilation_type: 'supply', previousValue: prevValue }, + tokens: { level: data.value }, + }); + triggers.push({ + triggerId: 'ventilation_level_below_threshold', + state: { ventilation_type: 'supply', previousValue: prevValue }, + tokens: { level: data.value }, + }); + } + this.setPreviousValue('ventilation_level_in', data.value); break; - case MeasurementType.VentilationLevelOut: + } + case MeasurementType.VentilationLevelOut: { this.logger.info(`VentilationLevelOut: ${data.value}`); + const prevValue = this.getPreviousValue('ventilation_level_out'); await setCapabilityValue('measure_ventilation_level_out', data.value); + + triggers.push({ + triggerId: 'ventilation_level_changed', + state: { ventilation_type: 'exhaust' }, + tokens: { level: data.value }, + }); + + if (prevValue !== undefined) { + triggers.push({ + triggerId: 'ventilation_level_above_threshold', + state: { ventilation_type: 'exhaust', previousValue: prevValue }, + tokens: { level: data.value }, + }); + triggers.push({ + triggerId: 'ventilation_level_below_threshold', + state: { ventilation_type: 'exhaust', previousValue: prevValue }, + tokens: { level: data.value }, + }); + } + this.setPreviousValue('ventilation_level_out', data.value); break; + } case MeasurementType.BoostCountDown: this.logger.info(`BoostCountDown: ${data.value}`); await setCapabilityValue('measure_boost_countdown', data.value); break; - case MeasurementType.AirQuality: + case MeasurementType.AirQuality: { this.logger.info(`AirQuality: ${data.value}`); if (data.value > 0) { if (!hasCapability('measure_air_quality')) @@ -62,6 +213,12 @@ class MeasurementHandler { if (!hasCapability(ModeType.AutoAirQualityControlMode)) await addCapability(ModeType.AutoAirQualityControlMode); await setCapabilityValue('measure_air_quality', data.value); + + triggers.push({ + triggerId: 'air_quality_changed', + state: {}, + tokens: { air_quality: data.value }, + }); } else if (data.value === 0) { if (hasCapability('measure_air_quality')) await removeCapability('measure_air_quality'); @@ -69,20 +226,45 @@ class MeasurementHandler { await removeCapability(ModeType.AutoAirQualityControlMode); } break; - case MeasurementType.CO2: + } + case MeasurementType.CO2: { this.logger.info(`CO2: ${data.value}`); if (data.value > 0) { + const prevValue = this.getPreviousValue('co2'); if (!hasCapability('measure_co2')) await addCapability('measure_co2'); await setCapabilityValue('measure_co2', data.value); + + triggers.push({ + triggerId: 'co2_changed', + state: {}, + tokens: { co2: data.value }, + }); + + if (prevValue !== undefined) { + triggers.push({ + triggerId: 'co2_above_threshold', + state: { previousValue: prevValue }, + tokens: { co2: data.value }, + }); + triggers.push({ + triggerId: 'co2_below_threshold', + state: { previousValue: prevValue }, + tokens: { co2: data.value }, + }); + } + this.setPreviousValue('co2', data.value); } else if (data.value === 0) { if (hasCapability('measure_co2')) await removeCapability('measure_co2'); } break; + } default: break; } + + return triggers; } } diff --git a/drivers/swegoncasa/SettingsHandler.ts b/drivers/swegoncasa/SettingsHandler.ts index 4d48826..93424d9 100644 --- a/drivers/swegoncasa/SettingsHandler.ts +++ b/drivers/swegoncasa/SettingsHandler.ts @@ -127,6 +127,11 @@ class SettingsHandler { } } + // Supply Temperature Setpoint - also update the capability + if (newSetting[SettingType.SupplyTemperatureSetpoint]) { + await setCapabilityValue('target_temperature', newSetting[SettingType.SupplyTemperatureSetpoint]); + } + await setSettings(newSetting); } } diff --git a/drivers/swegoncasa/device.ts b/drivers/swegoncasa/device.ts index 4e20a97..5478ab3 100644 --- a/drivers/swegoncasa/device.ts +++ b/drivers/swegoncasa/device.ts @@ -4,7 +4,7 @@ import Logger from '../../lib/logger'; import SwegonClient from './SwegonClient'; import { Measurement, DeviceInfo, ConnectionInfo, Mode } from '../../types'; import { SettingsChangedEvent } from '../../types/homey'; -import MeasurementHandler from './MeasurementHandler'; +import MeasurementHandler, { TriggerEvent } from './MeasurementHandler'; import SettingsHandler from './SettingsHandler'; import SummerNightCoolingModes from '../../lib/SummerNightCoolingModes'; import ModeHandler from './ModeHandler'; @@ -19,6 +19,7 @@ class SwegonCasaDevice extends Homey.Device { private measurementHandler = new MeasurementHandler(this.logger); private settingsHandler = new SettingsHandler(this.logger); private modeHandler = new ModeHandler(this.logger); + private previousClimateMode: string | null = null; private async ensureInitialized(settings: any): Promise { this.logger = new Logger(this.log, this.error, settings.debugMode === true); @@ -47,6 +48,10 @@ class SwegonCasaDevice extends Homey.Device { /** Add capabilities if they do not already exist */ private async ensureCapabilities(): Promise { + if (!this.hasCapability('target_temperature')) { + await this.addCapability('target_temperature'); + } + if (!this.hasCapability(ModeType.ClimateMode)) { await this.addCapability(ModeType.ClimateMode); } @@ -110,18 +115,32 @@ class SwegonCasaDevice extends Homey.Device { private async onMeasurement(data: Measurement): Promise { try { - await this.measurementHandler.HandleMeasurement( + const triggers = await this.measurementHandler.HandleMeasurement( this.setCapabilityValue.bind(this), data, this.hasCapability.bind(this), this.addCapability.bind(this), this.removeCapability.bind(this), ); + + // Fire trigger events + for (const trigger of triggers) { + await this.fireTrigger(trigger); + } } catch (err) { this.logger.error(err); } } + private async fireTrigger(trigger: TriggerEvent): Promise { + try { + const triggerCard = this.homey.flow.getDeviceTriggerCard(trigger.triggerId); + await triggerCard.trigger(this, trigger.tokens, trigger.state); + } catch (err) { + this.logger.debug(`Trigger ${trigger.triggerId} not registered or failed: ${err}`); + } + } + private async onMode(data: Mode): Promise { try { this.logger.info(`Mode: ${data.id}=${data.value}`); @@ -132,6 +151,19 @@ class SwegonCasaDevice extends Homey.Device { this.setCapabilityValue.bind(this), this.hasCapability.bind(this), ); + + // Fire climate mode changed trigger + if (data.id === ModeType.ClimateMode) { + const currentMode = this.getCapabilityValue(ModeType.ClimateMode); + if (this.previousClimateMode !== null && this.previousClimateMode !== currentMode) { + await this.fireTrigger({ + triggerId: 'climate_mode_changed', + state: {}, + tokens: { climate_mode: currentMode }, + }); + } + this.previousClimateMode = currentMode; + } } catch (err) { this.logger.error(err); } @@ -201,6 +233,51 @@ class SwegonCasaDevice extends Homey.Device { await this.changeClimateMode(climateMode); } + public async onSetTemperatureActionTriggered( + temperature: number, + ): Promise { + this.logger.info(`target_temperature Updated from Action: ${temperature}`); + + await this.swegonClient?.setValue(SwegonObjectId.SupplyTemperatureSetpoint, temperature); + await this.setCapabilityValue('target_temperature', temperature); + } + + public async onSetSummerNightCoolingModeActionTriggered( + mode: string, + ): Promise { + this.logger.info(`summer_night_cooling_mode Updated from Action: ${mode}`); + + const modeConfig = SummerNightCoolingModes.find((x) => x.id === mode); + if (modeConfig) { + await this.swegonClient?.setValue(SwegonObjectId.SummerNightCoolingMode, modeConfig.value); + await this.setCapabilityValue(ModeType.SummerNightCoolingMode, mode); + } + } + + public async onSetAutoHumidityControlModeActionTriggered( + mode: string, + ): Promise { + this.logger.info(`auto_humidity_control_mode Updated from Action: ${mode}`); + + const modeConfig = AutoHumidityControlModes.find((x) => x.id === mode); + if (modeConfig) { + await this.swegonClient?.setValue(SwegonObjectId.AutoHumidityControlMode, modeConfig.value); + await this.setCapabilityValue(ModeType.AutoHumidityControlMode, mode); + } + } + + public async onSetAutoAirQualityControlModeActionTriggered( + mode: string, + ): Promise { + this.logger.info(`auto_air_quality_control_mode Updated from Action: ${mode}`); + + const modeConfig = AutoAirQualityControlModes.find((x) => x.id === mode); + if (modeConfig) { + await this.swegonClient?.setValue(SwegonObjectId.AutoAirQualityControlMode, modeConfig.value); + await this.setCapabilityValue(ModeType.AutoAirQualityControlMode, mode); + } + } + /** * onInit is called when the device is initialized. */ @@ -227,6 +304,15 @@ class SwegonCasaDevice extends Homey.Device { await swegonClient.login(); await swegonClient.connect(data.id); + this.registerCapabilityListener( + 'target_temperature', + async (value: number) => { + this.logger.info(`target_temperature Changed: ${value}`); + + await swegonClient.setValue(SwegonObjectId.SupplyTemperatureSetpoint, value); + }, + ); + this.registerCapabilityListener( ModeType.ClimateMode, async (value: string) => { diff --git a/drivers/swegoncasa/driver.compose.json b/drivers/swegoncasa/driver.compose.json index 3f32c1f..106a2b5 100644 --- a/drivers/swegoncasa/driver.compose.json +++ b/drivers/swegoncasa/driver.compose.json @@ -13,6 +13,7 @@ "local" ], "capabilities": [ + "target_temperature", "measure_humidity_percent", "measure_humidity_amount", "measure_return_temperature", diff --git a/locales/en.json b/locales/en.json index 2911192..323f929 100644 --- a/locales/en.json +++ b/locales/en.json @@ -5,7 +5,25 @@ "boost": "Boost", "travel": "Travel", "fireplace": "Fireplace", - "fan_off": "Fan Off" + "fan_off": "Fan Off", + "off": "Off" }, - "mode": "Mode" + "mode": "Mode", + "temperature": { + "supply": "Supply", + "intake": "Intake", + "return": "Return" + }, + "ventilation": { + "supply": "Supply", + "exhaust": "Exhaust" + }, + "control_mode": { + "off": "Off", + "user": "User", + "low": "Low", + "normal": "Normal", + "high": "High", + "full": "Full" + } } \ No newline at end of file diff --git a/locales/no.json b/locales/no.json index e0afc74..30f1e9e 100644 --- a/locales/no.json +++ b/locales/no.json @@ -4,8 +4,26 @@ "away": "Borte", "boost": "Boost", "travel": "Reise", - "fireplace": "Fyr", - "fan_off": "Vifte av" + "fireplace": "Peis", + "fan_off": "Vifte av", + "off": "Av" }, - "mode": "Modus" + "mode": "Modus", + "temperature": { + "supply": "Tilluft", + "intake": "Inntak", + "return": "Avtrekk" + }, + "ventilation": { + "supply": "Tilluft", + "exhaust": "Avtrekk" + }, + "control_mode": { + "off": "Av", + "user": "Bruker", + "low": "Lav", + "normal": "Normal", + "high": "Høy", + "full": "Full" + } } \ No newline at end of file From fc2ae42117b95be06410d0fcb76a5c3716b8d9b1 Mon Sep 17 00:00:00 2001 From: araa Date: Mon, 5 Jan 2026 18:35:04 +0100 Subject: [PATCH 3/8] Update Norwegian translations for temperature, humidity, CO2, and climate mode conditions to improve clarity and accuracy. --- .homeycompose/flow/conditions/climate_mode_is.json | 4 ++-- .homeycompose/flow/conditions/co2_is_above.json | 4 ++-- .homeycompose/flow/conditions/co2_is_below.json | 4 ++-- .homeycompose/flow/conditions/humidity_is_above.json | 4 ++-- .homeycompose/flow/conditions/humidity_is_below.json | 4 ++-- .homeycompose/flow/conditions/temperature_is_above.json | 4 ++-- .homeycompose/flow/conditions/temperature_is_below.json | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.homeycompose/flow/conditions/climate_mode_is.json b/.homeycompose/flow/conditions/climate_mode_is.json index 24b9f67..b499902 100644 --- a/.homeycompose/flow/conditions/climate_mode_is.json +++ b/.homeycompose/flow/conditions/climate_mode_is.json @@ -2,11 +2,11 @@ "id": "climate_mode_is", "title": { "en": "Climate mode !{{is|isn't}}", - "no": "Klimamodusen !{{er|er ikke}}" + "no": "Klimamodusen !{{er|ikke er}}" }, "titleFormatted": { "en": "Climate mode !{{is|isn't}} [[climate_mode]]", - "no": "Klimamodusen !{{er|er ikke}} [[climate_mode]]" + "no": "Klimamodusen !{{er|ikke er}} [[climate_mode]]" }, "hint": { "en": "Check if the climate mode equals a specific mode.", diff --git a/.homeycompose/flow/conditions/co2_is_above.json b/.homeycompose/flow/conditions/co2_is_above.json index 185638d..0c7e4dd 100644 --- a/.homeycompose/flow/conditions/co2_is_above.json +++ b/.homeycompose/flow/conditions/co2_is_above.json @@ -2,11 +2,11 @@ "id": "co2_is_above", "title": { "en": "CO2 level !{{is|isn't}} above", - "no": "CO2-nivået !{{er|er ikke}} over" + "no": "CO2-nivået !{{er over|er under}}" }, "titleFormatted": { "en": "CO2 level !{{is|isn't}} above [[threshold]] ppm", - "no": "CO2-nivået !{{er|er ikke}} over [[threshold]] ppm" + "no": "CO2-nivået !{{er over|er under}} [[threshold]] ppm" }, "hint": { "en": "Check if the CO2 level is above a specified value.", diff --git a/.homeycompose/flow/conditions/co2_is_below.json b/.homeycompose/flow/conditions/co2_is_below.json index d1c0a46..0f882c3 100644 --- a/.homeycompose/flow/conditions/co2_is_below.json +++ b/.homeycompose/flow/conditions/co2_is_below.json @@ -2,11 +2,11 @@ "id": "co2_is_below", "title": { "en": "CO2 level !{{is|isn't}} below", - "no": "CO2-nivået !{{er|er ikke}} under" + "no": "CO2-nivået !{{er under|er over}}" }, "titleFormatted": { "en": "CO2 level !{{is|isn't}} below [[threshold]] ppm", - "no": "CO2-nivået !{{er|er ikke}} under [[threshold]] ppm" + "no": "CO2-nivået !{{er under|er over}} [[threshold]] ppm" }, "hint": { "en": "Check if the CO2 level is below a specified value.", diff --git a/.homeycompose/flow/conditions/humidity_is_above.json b/.homeycompose/flow/conditions/humidity_is_above.json index cd2072a..8cdef75 100644 --- a/.homeycompose/flow/conditions/humidity_is_above.json +++ b/.homeycompose/flow/conditions/humidity_is_above.json @@ -2,11 +2,11 @@ "id": "humidity_is_above", "title": { "en": "Humidity !{{is|isn't}} above", - "no": "Luftfuktigheten !{{er|er ikke}} over" + "no": "Luftfuktigheten !{{er over|er under}}" }, "titleFormatted": { "en": "Humidity !{{is|isn't}} above [[threshold]]%", - "no": "Luftfuktigheten !{{er|er ikke}} over [[threshold]]%" + "no": "Luftfuktigheten !{{er over|er under}} [[threshold]]%" }, "hint": { "en": "Check if the humidity is above a specified value.", diff --git a/.homeycompose/flow/conditions/humidity_is_below.json b/.homeycompose/flow/conditions/humidity_is_below.json index 8639a54..b4aaeb9 100644 --- a/.homeycompose/flow/conditions/humidity_is_below.json +++ b/.homeycompose/flow/conditions/humidity_is_below.json @@ -2,11 +2,11 @@ "id": "humidity_is_below", "title": { "en": "Humidity !{{is|isn't}} below", - "no": "Luftfuktigheten !{{er|er ikke}} under" + "no": "Luftfuktigheten !{{er under|er over}}" }, "titleFormatted": { "en": "Humidity !{{is|isn't}} below [[threshold]]%", - "no": "Luftfuktigheten !{{er|er ikke}} under [[threshold]]%" + "no": "Luftfuktigheten !{{er under|er over}} [[threshold]]%" }, "hint": { "en": "Check if the humidity is below a specified value.", diff --git a/.homeycompose/flow/conditions/temperature_is_above.json b/.homeycompose/flow/conditions/temperature_is_above.json index 09c02f6..b18d385 100644 --- a/.homeycompose/flow/conditions/temperature_is_above.json +++ b/.homeycompose/flow/conditions/temperature_is_above.json @@ -2,11 +2,11 @@ "id": "temperature_is_above", "title": { "en": "Temperature !{{is|isn't}} above", - "no": "Temperaturen !{{er|er ikke}} over" + "no": "Temperaturen !{{er over|er under}}" }, "titleFormatted": { "en": "[[temperature_type]] temperature !{{is|isn't}} above [[threshold]] °C", - "no": "[[temperature_type]] temperaturen !{{er|er ikke}} over [[threshold]] °C" + "no": "[[temperature_type]] temperaturen !{{er over|er under}} [[threshold]] °C" }, "hint": { "en": "Check if the selected temperature is above a specified value.", diff --git a/.homeycompose/flow/conditions/temperature_is_below.json b/.homeycompose/flow/conditions/temperature_is_below.json index 2edc528..f1898e0 100644 --- a/.homeycompose/flow/conditions/temperature_is_below.json +++ b/.homeycompose/flow/conditions/temperature_is_below.json @@ -2,11 +2,11 @@ "id": "temperature_is_below", "title": { "en": "Temperature !{{is|isn't}} below", - "no": "Temperaturen !{{er|er ikke}} under" + "no": "Temperaturen !{{er under|er over}} " }, "titleFormatted": { "en": "[[temperature_type]] temperature !{{is|isn't}} below [[threshold]] °C", - "no": "[[temperature_type]] temperaturen !{{er|er ikke}} under [[threshold]] °C" + "no": "[[temperature_type]] temperaturen !{{er under|er over}} [[threshold]] °C" }, "hint": { "en": "Check if the selected temperature is below a specified value.", From 1488cb65039caa0e53d4257203dc9f30ff06f240 Mon Sep 17 00:00:00 2001 From: araa Date: Mon, 5 Jan 2026 18:35:10 +0100 Subject: [PATCH 4/8] Add new triggers and actions for air quality, climate, and temperature control in app.json; update build script in package.json and output directory in tsconfig.json --- app.json | 1334 +++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- tsconfig.json | 2 +- 3 files changed, 1336 insertions(+), 2 deletions(-) diff --git a/app.json b/app.json index bc6d790..84c87ae 100644 --- a/app.json +++ b/app.json @@ -61,7 +61,1206 @@ "source": "https://github.com/philipostli/com.swegon", "homeyCommunityTopicId": 137674, "flow": { + "triggers": [ + { + "id": "air_quality_changed", + "title": { + "en": "Air quality changed", + "no": "Luftkvaliteten endret seg" + }, + "hint": { + "en": "Triggers when the air quality level changes.", + "no": "Utløses når luftkvaliteten endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + } + ], + "tokens": [ + { + "name": "air_quality", + "type": "number", + "title": { + "en": "Air Quality", + "no": "Luftkvalitet" + }, + "example": 500 + } + ] + }, + { + "id": "climate_mode_changed", + "title": { + "en": "Climate mode changed", + "no": "Klimamodusen endret seg" + }, + "hint": { + "en": "Triggers when the climate control mode changes.", + "no": "Utløses når klimakontrollmodusen endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + } + ], + "tokens": [ + { + "name": "climate_mode", + "type": "string", + "title": { + "en": "Climate Mode", + "no": "Klimamodus" + }, + "example": "home" + } + ] + }, + { + "id": "co2_above_threshold", + "title": { + "en": "CO2 level went above", + "no": "CO2-nivået gikk over" + }, + "titleFormatted": { + "en": "CO2 level went above [[threshold]] ppm", + "no": "CO2-nivået gikk over [[threshold]] ppm" + }, + "hint": { + "en": "Triggers when the CO2 level goes above the specified threshold.", + "no": "Utløses når CO2-nivået går over den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "CO2 in ppm", + "no": "CO2 i ppm" + } + } + ], + "tokens": [ + { + "name": "co2", + "type": "number", + "title": { + "en": "CO2", + "no": "CO2" + }, + "example": 450 + } + ] + }, + { + "id": "co2_below_threshold", + "title": { + "en": "CO2 level went below", + "no": "CO2-nivået gikk under" + }, + "titleFormatted": { + "en": "CO2 level went below [[threshold]] ppm", + "no": "CO2-nivået gikk under [[threshold]] ppm" + }, + "hint": { + "en": "Triggers when the CO2 level goes below the specified threshold.", + "no": "Utløses når CO2-nivået går under den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "CO2 in ppm", + "no": "CO2 i ppm" + } + } + ], + "tokens": [ + { + "name": "co2", + "type": "number", + "title": { + "en": "CO2", + "no": "CO2" + }, + "example": 450 + } + ] + }, + { + "id": "co2_changed", + "title": { + "en": "CO2 level changed", + "no": "CO2-nivået endret seg" + }, + "hint": { + "en": "Triggers when the CO2 level changes.", + "no": "Utløses når CO2-nivået endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + } + ], + "tokens": [ + { + "name": "co2", + "type": "number", + "title": { + "en": "CO2", + "no": "CO2" + }, + "example": 450 + } + ] + }, + { + "id": "humidity_above_threshold", + "title": { + "en": "Humidity went above", + "no": "Luftfuktigheten gikk over" + }, + "titleFormatted": { + "en": "Humidity went above [[threshold]]%", + "no": "Luftfuktigheten gikk over [[threshold]]%" + }, + "hint": { + "en": "Triggers when the humidity goes above the specified threshold.", + "no": "Utløses når luftfuktigheten går over den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Humidity in %", + "no": "Luftfuktighet i %" + } + } + ], + "tokens": [ + { + "name": "humidity", + "type": "number", + "title": { + "en": "Humidity", + "no": "Luftfuktighet" + }, + "example": 45 + } + ] + }, + { + "id": "humidity_below_threshold", + "title": { + "en": "Humidity went below", + "no": "Luftfuktigheten gikk under" + }, + "titleFormatted": { + "en": "Humidity went below [[threshold]]%", + "no": "Luftfuktigheten gikk under [[threshold]]%" + }, + "hint": { + "en": "Triggers when the humidity goes below the specified threshold.", + "no": "Utløses når luftfuktigheten går under den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Humidity in %", + "no": "Luftfuktighet i %" + } + } + ], + "tokens": [ + { + "name": "humidity", + "type": "number", + "title": { + "en": "Humidity", + "no": "Luftfuktighet" + }, + "example": 45 + } + ] + }, + { + "id": "humidity_changed", + "title": { + "en": "Humidity changed", + "no": "Luftfuktigheten endret seg" + }, + "hint": { + "en": "Triggers when the humidity percentage changes.", + "no": "Utløses når luftfuktighetsprosenten endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + } + ], + "tokens": [ + { + "name": "humidity", + "type": "number", + "title": { + "en": "Humidity", + "no": "Luftfuktighet" + }, + "example": 45 + } + ] + }, + { + "id": "temperature_above_threshold", + "title": { + "en": "Temperature went above", + "no": "Temperaturen gikk over" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature went above [[threshold]] °C", + "no": "[[temperature_type]] temperaturen gikk over [[threshold]] °C" + }, + "hint": { + "en": "Triggers when the selected temperature goes above the specified threshold.", + "no": "Utløses når den valgte temperaturen går over den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + } + } + ], + "tokens": [ + { + "name": "temperature", + "type": "number", + "title": { + "en": "Temperature", + "no": "Temperatur" + }, + "example": 21.5 + } + ] + }, + { + "id": "temperature_below_threshold", + "title": { + "en": "Temperature went below", + "no": "Temperaturen gikk under" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature went below [[threshold]] °C", + "no": "[[temperature_type]] temperaturen gikk under [[threshold]] °C" + }, + "hint": { + "en": "Triggers when the selected temperature goes below the specified threshold.", + "no": "Utløses når den valgte temperaturen går under den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + } + } + ], + "tokens": [ + { + "name": "temperature", + "type": "number", + "title": { + "en": "Temperature", + "no": "Temperatur" + }, + "example": 21.5 + } + ] + }, + { + "id": "temperature_changed", + "title": { + "en": "Temperature changed", + "no": "Temperaturen endret seg" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature changed", + "no": "[[temperature_type]] temperaturen endret seg" + }, + "hint": { + "en": "Triggers when the selected temperature changes.", + "no": "Utløses når den valgte temperaturen endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + } + ], + "tokens": [ + { + "name": "temperature", + "type": "number", + "title": { + "en": "Temperature", + "no": "Temperatur" + }, + "example": 21.5 + } + ] + }, + { + "id": "ventilation_level_above_threshold", + "title": { + "en": "Ventilation level went above", + "no": "Ventilasjonsnivået gikk over" + }, + "titleFormatted": { + "en": "[[ventilation_type]] ventilation level went above [[threshold]]%", + "no": "[[ventilation_type]] ventilasjonsnivået gikk over [[threshold]]%" + }, + "hint": { + "en": "Triggers when the ventilation level goes above the specified threshold.", + "no": "Utløses når ventilasjonsnivået går over den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "ventilation_type", + "type": "dropdown", + "title": { + "en": "Ventilation Type", + "no": "Ventilasjonstype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "exhaust", + "label": { + "en": "Exhaust", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Level in %", + "no": "Nivå i %" + } + } + ], + "tokens": [ + { + "name": "level", + "type": "number", + "title": { + "en": "Level", + "no": "Nivå" + }, + "example": 75 + } + ] + }, + { + "id": "ventilation_level_below_threshold", + "title": { + "en": "Ventilation level went below", + "no": "Ventilasjonsnivået gikk under" + }, + "titleFormatted": { + "en": "[[ventilation_type]] ventilation level went below [[threshold]]%", + "no": "[[ventilation_type]] ventilasjonsnivået gikk under [[threshold]]%" + }, + "hint": { + "en": "Triggers when the ventilation level goes below the specified threshold.", + "no": "Utløses når ventilasjonsnivået går under den angitte grensen." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "ventilation_type", + "type": "dropdown", + "title": { + "en": "Ventilation Type", + "no": "Ventilasjonstype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "exhaust", + "label": { + "en": "Exhaust", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Level in %", + "no": "Nivå i %" + } + } + ], + "tokens": [ + { + "name": "level", + "type": "number", + "title": { + "en": "Level", + "no": "Nivå" + }, + "example": 75 + } + ] + }, + { + "id": "ventilation_level_changed", + "title": { + "en": "Ventilation level changed", + "no": "Ventilasjonsnivået endret seg" + }, + "titleFormatted": { + "en": "[[ventilation_type]] ventilation level changed", + "no": "[[ventilation_type]] ventilasjonsnivået endret seg" + }, + "hint": { + "en": "Triggers when the ventilation level (fan speed %) changes.", + "no": "Utløses når ventilasjonsnivået (viftehastighet %) endrer seg." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "ventilation_type", + "type": "dropdown", + "title": { + "en": "Ventilation Type", + "no": "Ventilasjonstype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "exhaust", + "label": { + "en": "Exhaust", + "no": "Avtrekk" + } + } + ] + } + ], + "tokens": [ + { + "name": "level", + "type": "number", + "title": { + "en": "Level", + "no": "Nivå" + }, + "example": 75 + } + ] + } + ], + "conditions": [ + { + "id": "climate_mode_is", + "title": { + "en": "Climate mode !{{is|isn't}}", + "no": "Klimamodusen !{{er|ikke er}}" + }, + "titleFormatted": { + "en": "Climate mode !{{is|isn't}} [[climate_mode]]", + "no": "Klimamodusen !{{er|ikke er}} [[climate_mode]]" + }, + "hint": { + "en": "Check if the climate mode equals a specific mode.", + "no": "Sjekk om klimamodusen er lik en spesifikk modus." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "climate_mode", + "type": "dropdown", + "title": { + "en": "Climate Mode", + "no": "Klimamodus" + }, + "values": [ + { + "id": "away", + "label": { + "en": "Away", + "no": "Borte" + } + }, + { + "id": "home", + "label": { + "en": "Home", + "no": "Hjemme" + } + }, + { + "id": "boost", + "label": { + "en": "Boost", + "no": "Boost" + } + }, + { + "id": "travel", + "label": { + "en": "Travel", + "no": "Reise" + } + }, + { + "id": "off", + "label": { + "en": "Off", + "no": "Av" + } + }, + { + "id": "fireplace", + "label": { + "en": "Fireplace", + "no": "Peis" + } + } + ] + } + ] + }, + { + "id": "co2_is_above", + "title": { + "en": "CO2 level !{{is|isn't}} above", + "no": "CO2-nivået !{{er over|er under}}" + }, + "titleFormatted": { + "en": "CO2 level !{{is|isn't}} above [[threshold]] ppm", + "no": "CO2-nivået !{{er over|er under}} [[threshold]] ppm" + }, + "hint": { + "en": "Check if the CO2 level is above a specified value.", + "no": "Sjekk om CO2-nivået er over en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "CO2 in ppm", + "no": "CO2 i ppm" + } + } + ] + }, + { + "id": "co2_is_below", + "title": { + "en": "CO2 level !{{is|isn't}} below", + "no": "CO2-nivået !{{er under|er over}}" + }, + "titleFormatted": { + "en": "CO2 level !{{is|isn't}} below [[threshold]] ppm", + "no": "CO2-nivået !{{er under|er over}} [[threshold]] ppm" + }, + "hint": { + "en": "Check if the CO2 level is below a specified value.", + "no": "Sjekk om CO2-nivået er under en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "CO2 in ppm", + "no": "CO2 i ppm" + } + } + ] + }, + { + "id": "humidity_is_above", + "title": { + "en": "Humidity !{{is|isn't}} above", + "no": "Luftfuktigheten !{{er over|er under}}" + }, + "titleFormatted": { + "en": "Humidity !{{is|isn't}} above [[threshold]]%", + "no": "Luftfuktigheten !{{er over|er under}} [[threshold]]%" + }, + "hint": { + "en": "Check if the humidity is above a specified value.", + "no": "Sjekk om luftfuktigheten er over en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Humidity in %", + "no": "Luftfuktighet i %" + } + } + ] + }, + { + "id": "humidity_is_below", + "title": { + "en": "Humidity !{{is|isn't}} below", + "no": "Luftfuktigheten !{{er under|er over}}" + }, + "titleFormatted": { + "en": "Humidity !{{is|isn't}} below [[threshold]]%", + "no": "Luftfuktigheten !{{er under|er over}} [[threshold]]%" + }, + "hint": { + "en": "Check if the humidity is below a specified value.", + "no": "Sjekk om luftfuktigheten er under en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Humidity in %", + "no": "Luftfuktighet i %" + } + } + ] + }, + { + "id": "temperature_is_above", + "title": { + "en": "Temperature !{{is|isn't}} above", + "no": "Temperaturen !{{er over|er under}}" + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature !{{is|isn't}} above [[threshold]] °C", + "no": "[[temperature_type]] temperaturen !{{er over|er under}} [[threshold]] °C" + }, + "hint": { + "en": "Check if the selected temperature is above a specified value.", + "no": "Sjekk om den valgte temperaturen er over en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + } + } + ] + }, + { + "id": "temperature_is_below", + "title": { + "en": "Temperature !{{is|isn't}} below", + "no": "Temperaturen !{{er under|er over}} " + }, + "titleFormatted": { + "en": "[[temperature_type]] temperature !{{is|isn't}} below [[threshold]] °C", + "no": "[[temperature_type]] temperaturen !{{er under|er over}} [[threshold]] °C" + }, + "hint": { + "en": "Check if the selected temperature is below a specified value.", + "no": "Sjekk om den valgte temperaturen er under en angitt verdi." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature_type", + "type": "dropdown", + "title": { + "en": "Temperature Type", + "no": "Temperaturtype" + }, + "values": [ + { + "id": "supply", + "label": { + "en": "Supply", + "no": "Tilluft" + } + }, + { + "id": "intake", + "label": { + "en": "Intake", + "no": "Inntak" + } + }, + { + "id": "return", + "label": { + "en": "Return", + "no": "Avtrekk" + } + } + ] + }, + { + "name": "threshold", + "type": "number", + "title": { + "en": "Threshold", + "no": "Grenseverdi" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + } + } + ] + } + ], "actions": [ + { + "id": "set_auto_air_quality_control_mode", + "title": { + "en": "Set auto air quality control mode", + "no": "Sett automatisk luftkvalitetsmodus" + }, + "titleFormatted": { + "en": "Set auto air quality control mode to [[mode]]", + "no": "Sett automatisk luftkvalitetsmodus til [[mode]]" + }, + "hint": { + "en": "Sets the auto air quality control mode.", + "no": "Setter automatisk luftkvalitetsmodus." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "mode", + "type": "dropdown", + "title": { + "en": "Mode", + "no": "Modus" + }, + "values": [ + { + "id": "off", + "label": { + "en": "Off", + "no": "Av" + } + }, + { + "id": "user", + "label": { + "en": "User", + "no": "Bruker" + } + }, + { + "id": "low", + "label": { + "en": "Low", + "no": "Lav" + } + }, + { + "id": "normal", + "label": { + "en": "Normal", + "no": "Normal" + } + }, + { + "id": "high", + "label": { + "en": "High", + "no": "Høy" + } + }, + { + "id": "full", + "label": { + "en": "Full", + "no": "Full" + } + } + ] + } + ] + }, + { + "id": "set_auto_humidity_control_mode", + "title": { + "en": "Set auto humidity control mode", + "no": "Sett automatisk luftfuktighetsmodus" + }, + "titleFormatted": { + "en": "Set auto humidity control mode to [[mode]]", + "no": "Sett automatisk luftfuktighetsmodus til [[mode]]" + }, + "hint": { + "en": "Sets the auto humidity control mode.", + "no": "Setter automatisk luftfuktighetsmodus." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "mode", + "type": "dropdown", + "title": { + "en": "Mode", + "no": "Modus" + }, + "values": [ + { + "id": "off", + "label": { + "en": "Off", + "no": "Av" + } + }, + { + "id": "user", + "label": { + "en": "User", + "no": "Bruker" + } + }, + { + "id": "low", + "label": { + "en": "Low", + "no": "Lav" + } + }, + { + "id": "normal", + "label": { + "en": "Normal", + "no": "Normal" + } + }, + { + "id": "high", + "label": { + "en": "High", + "no": "Høy" + } + }, + { + "id": "full", + "label": { + "en": "Full", + "no": "Full" + } + } + ] + } + ] + }, { "id": "set_climate_mode", "title": { @@ -132,6 +1331,117 @@ ] } ] + }, + { + "id": "set_summer_night_cooling_mode", + "title": { + "en": "Set summer night cooling mode", + "no": "Sett sommernatt avkjølingsmodus" + }, + "titleFormatted": { + "en": "Set summer night cooling mode to [[mode]]", + "no": "Sett sommernatt avkjølingsmodus til [[mode]]" + }, + "hint": { + "en": "Sets the summer night cooling mode.", + "no": "Setter sommernatt avkjølingsmodus." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "mode", + "type": "dropdown", + "title": { + "en": "Mode", + "no": "Modus" + }, + "values": [ + { + "id": "off", + "label": { + "en": "Off", + "no": "Av" + } + }, + { + "id": "low", + "label": { + "en": "Low", + "no": "Lav" + } + }, + { + "id": "normal", + "label": { + "en": "Normal", + "no": "Normal" + } + }, + { + "id": "high", + "label": { + "en": "High", + "no": "Høy" + } + }, + { + "id": "full", + "label": { + "en": "Full", + "no": "Full" + } + }, + { + "id": "user", + "label": { + "en": "User", + "no": "Bruker" + } + } + ] + } + ] + }, + { + "id": "set_temperature", + "title": { + "en": "Set target temperature", + "no": "Sett ønsket temperatur" + }, + "titleFormatted": { + "en": "Set target temperature to [[temperature]] °C", + "no": "Sett ønsket temperatur til [[temperature]] °C" + }, + "hint": { + "en": "Sets the supply air temperature setpoint.", + "no": "Setter temperaturinnstillingen for tilluft." + }, + "args": [ + { + "name": "device", + "type": "device", + "filter": "driver_id=swegoncasa" + }, + { + "name": "temperature", + "type": "number", + "title": { + "en": "Temperature", + "no": "Temperatur" + }, + "placeholder": { + "en": "Temperature in °C", + "no": "Temperatur i °C" + }, + "min": 12, + "max": 22, + "step": 1 + } + ] } ] }, @@ -151,6 +1461,7 @@ "local" ], "capabilities": [ + "target_temperature", "measure_humidity_percent", "measure_humidity_amount", "measure_return_temperature", @@ -1106,6 +2417,29 @@ "getable": true, "setable": true, "insights": false + }, + "target_temperature": { + "type": "number", + "uiComponent": "thermostat", + "title": { + "en": "Target Temperature", + "no": "Ønsket temperatur" + }, + "desc": { + "en": "The target supply air temperature setpoint", + "no": "Ønsket temperaturinnstilling for tilluft" + }, + "units": { + "en": "°C", + "no": "°C" + }, + "min": 12, + "max": 22, + "step": 1, + "decimals": 0, + "getable": true, + "setable": true, + "insights": true } } } \ No newline at end of file diff --git a/package.json b/package.json index afdc3c4..c610ecc 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "main": "app.ts", "scripts": { "start": "homey app run", - "build": "homey app build", + "build": "tsc", "deploy": "homey app install", "lint": "eslint . --ext js,jsx,ts,tsx --quiet", "lint-fix": "eslint . --ext js,jsx,ts,tsx --quiet --fix" diff --git a/tsconfig.json b/tsconfig.json index e89a485..02e494e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "sourceMap": true, "skipLibCheck": false, "allowJs": true, - "outDir": "build/" + "outDir": "./.homeybuild" }, "include": ["**/*.ts"], "exclude": ["node_modules"] From 1992dc2ac89d381cc69eb28860528381398af1ad Mon Sep 17 00:00:00 2001 From: AreAArseth <92016247+AreAArseth@users.noreply.github.com> Date: Mon, 5 Jan 2026 18:41:09 +0100 Subject: [PATCH 5/8] Update app.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- app.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app.ts b/app.ts index b205759..06a6f55 100644 --- a/app.ts +++ b/app.ts @@ -68,10 +68,10 @@ class SwegonCasa extends Homey.App { .registerRunListener((args, state) => { const { threshold, temperature_type } = args; const { previousValue } = state; - const currentValue = state.temperature_type === temperature_type ? args.device.getCapabilityValue( + const currentValue = args.device.getCapabilityValue( temperature_type === 'supply' ? 'measure_supply_temperature' : temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' - ) : null; + ); // Check if type matches and value crossed threshold from below return temperature_type === state.temperature_type && From d1de7aaf451e690e776b3bce70062693b03c5f36 Mon Sep 17 00:00:00 2001 From: AreAArseth <92016247+AreAArseth@users.noreply.github.com> Date: Mon, 5 Jan 2026 18:41:19 +0100 Subject: [PATCH 6/8] Update .homeycompose/flow/conditions/temperature_is_below.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .homeycompose/flow/conditions/temperature_is_below.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.homeycompose/flow/conditions/temperature_is_below.json b/.homeycompose/flow/conditions/temperature_is_below.json index f1898e0..6bcd324 100644 --- a/.homeycompose/flow/conditions/temperature_is_below.json +++ b/.homeycompose/flow/conditions/temperature_is_below.json @@ -2,7 +2,7 @@ "id": "temperature_is_below", "title": { "en": "Temperature !{{is|isn't}} below", - "no": "Temperaturen !{{er under|er over}} " + "no": "Temperaturen !{{er under|er over}}" }, "titleFormatted": { "en": "[[temperature_type]] temperature !{{is|isn't}} below [[threshold]] °C", From 803760cbe0c40b002b8c1876445c1ff4ae8ce1b6 Mon Sep 17 00:00:00 2001 From: araa Date: Mon, 5 Jan 2026 19:03:07 +0100 Subject: [PATCH 7/8] Update dependencies, enhance error handling, and improve ESLint configuration - Updated TypeScript and ESLint dependencies in package.json for better compatibility and features. - Modified ESLint configuration to extend from 'athom/homey-app' and added .eslintrc.js to ignore itself. - Enhanced error handling in SwegonCasa driver and SwegonClient by adding catch blocks to promise-based methods. - Updated app.ts to standardize temperature and ventilation type references. - Added new entries to .eslintignore for better linting control. --- .eslintignore | 3 +- .eslintrc.js | 4 +- app.json | 2 +- app.ts | 68 +- drivers/swegoncasa/ModeHandler.ts | 2 +- drivers/swegoncasa/SwegonClient.ts | 452 +++++------ drivers/swegoncasa/device.ts | 36 +- drivers/swegoncasa/driver.ts | 3 +- package-lock.json | 1149 ++++++++++++---------------- package.json | 17 +- 10 files changed, 801 insertions(+), 935 deletions(-) diff --git a/.eslintignore b/.eslintignore index b7dab5e..94d4fde 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ node_modules -build \ No newline at end of file +build +widgets/ \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 210a0f6..81f6e52 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,11 +5,11 @@ module.exports = { es6: true, jest: true, }, - extends: ['athom', 'eslint:recommended', 'plugin:prettier/recommended'], + extends: ['athom/homey-app', 'eslint:recommended', 'plugin:prettier/recommended'], parserOptions: { sourceType: 'module', }, - ignorePatterns: ['node_modules/*', 'build/*'], + ignorePatterns: ['node_modules/*', 'build/*', '.eslintrc.js'], plugins: ['@typescript-eslint', 'prettier'], settings: { node: { diff --git a/app.json b/app.json index 84c87ae..e4238a3 100644 --- a/app.json +++ b/app.json @@ -1050,7 +1050,7 @@ "id": "temperature_is_below", "title": { "en": "Temperature !{{is|isn't}} below", - "no": "Temperaturen !{{er under|er over}} " + "no": "Temperaturen !{{er under|er over}}" }, "titleFormatted": { "en": "[[temperature_type]] temperature !{{is|isn't}} below [[threshold]] °C", diff --git a/app.ts b/app.ts index 06a6f55..59842e1 100644 --- a/app.ts +++ b/app.ts @@ -59,22 +59,26 @@ class SwegonCasa extends Homey.App { this.homey.flow .getDeviceTriggerCard('temperature_changed') .registerRunListener((args, state) => { - return args.temperature_type === state.temperature_type; + return args.temperatureType === state.temperatureType; }); // Temperature Above Threshold this.homey.flow .getDeviceTriggerCard('temperature_above_threshold') .registerRunListener((args, state) => { - const { threshold, temperature_type } = args; + const { threshold, temperatureType } = args; const { previousValue } = state; + const temperatureCapabilities = { + supply: 'measure_supply_temperature', + intake: 'measure_intake_temperature', + return: 'measure_return_temperature', + } as const; const currentValue = args.device.getCapabilityValue( - temperature_type === 'supply' ? 'measure_supply_temperature' : - temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' + temperatureCapabilities[temperatureType as keyof typeof temperatureCapabilities], ); // Check if type matches and value crossed threshold from below - return temperature_type === state.temperature_type && + return temperatureType === state.temperatureType && previousValue !== undefined && previousValue <= threshold && currentValue > threshold; @@ -84,14 +88,18 @@ class SwegonCasa extends Homey.App { this.homey.flow .getDeviceTriggerCard('temperature_below_threshold') .registerRunListener((args, state) => { - const { threshold, temperature_type } = args; + const { threshold, temperatureType } = args; const { previousValue } = state; + const temperatureCapabilities = { + supply: 'measure_supply_temperature', + intake: 'measure_intake_temperature', + return: 'measure_return_temperature', + } as const; const currentValue = args.device.getCapabilityValue( - temperature_type === 'supply' ? 'measure_supply_temperature' : - temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' + temperatureCapabilities[temperatureType as keyof typeof temperatureCapabilities], ); - return temperature_type === state.temperature_type && + return temperatureType === state.temperatureType && previousValue !== undefined && previousValue >= threshold && currentValue < threshold; @@ -101,20 +109,24 @@ class SwegonCasa extends Homey.App { this.homey.flow .getDeviceTriggerCard('ventilation_level_changed') .registerRunListener((args, state) => { - return args.ventilation_type === state.ventilation_type; + return args.ventilationType === state.ventilationType; }); // Ventilation Level Above Threshold this.homey.flow .getDeviceTriggerCard('ventilation_level_above_threshold') .registerRunListener((args, state) => { - const { threshold, ventilation_type } = args; + const { threshold, ventilationType } = args; const { previousValue } = state; + const ventilationCapabilities = { + supply: 'measure_ventilation_level_in', + exhaust: 'measure_ventilation_level_out', + } as const; const currentValue = args.device.getCapabilityValue( - ventilation_type === 'supply' ? 'measure_ventilation_level_in' : 'measure_ventilation_level_out' + ventilationCapabilities[ventilationType as keyof typeof ventilationCapabilities], ); - return ventilation_type === state.ventilation_type && + return ventilationType === state.ventilationType && previousValue !== undefined && previousValue <= threshold && currentValue > threshold; @@ -124,13 +136,17 @@ class SwegonCasa extends Homey.App { this.homey.flow .getDeviceTriggerCard('ventilation_level_below_threshold') .registerRunListener((args, state) => { - const { threshold, ventilation_type } = args; + const { threshold, ventilationType } = args; const { previousValue } = state; + const ventilationCapabilities = { + supply: 'measure_ventilation_level_in', + exhaust: 'measure_ventilation_level_out', + } as const; const currentValue = args.device.getCapabilityValue( - ventilation_type === 'supply' ? 'measure_ventilation_level_in' : 'measure_ventilation_level_out' + ventilationCapabilities[ventilationType as keyof typeof ventilationCapabilities], ); - return ventilation_type === state.ventilation_type && + return ventilationType === state.ventilationType && previousValue !== undefined && previousValue >= threshold && currentValue < threshold; @@ -214,10 +230,14 @@ class SwegonCasa extends Homey.App { this.homey.flow .getConditionCard('temperature_is_above') .registerRunListener((args) => { - const { temperature_type, threshold } = args; + const { temperatureType, threshold } = args; + const temperatureCapabilities = { + supply: 'measure_supply_temperature', + intake: 'measure_intake_temperature', + return: 'measure_return_temperature', + } as const; const currentValue = args.device.getCapabilityValue( - temperature_type === 'supply' ? 'measure_supply_temperature' : - temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' + temperatureCapabilities[temperatureType as keyof typeof temperatureCapabilities], ); return currentValue > threshold; }); @@ -226,10 +246,14 @@ class SwegonCasa extends Homey.App { this.homey.flow .getConditionCard('temperature_is_below') .registerRunListener((args) => { - const { temperature_type, threshold } = args; + const { temperatureType, threshold } = args; + const temperatureCapabilities = { + supply: 'measure_supply_temperature', + intake: 'measure_intake_temperature', + return: 'measure_return_temperature', + } as const; const currentValue = args.device.getCapabilityValue( - temperature_type === 'supply' ? 'measure_supply_temperature' : - temperature_type === 'intake' ? 'measure_intake_temperature' : 'measure_return_temperature' + temperatureCapabilities[temperatureType as keyof typeof temperatureCapabilities], ); return currentValue < threshold; }); diff --git a/drivers/swegoncasa/ModeHandler.ts b/drivers/swegoncasa/ModeHandler.ts index 4af2de9..0c0dc39 100644 --- a/drivers/swegoncasa/ModeHandler.ts +++ b/drivers/swegoncasa/ModeHandler.ts @@ -59,7 +59,7 @@ class ModeHandler { this.logger.info(`AutoAirQualityControlMode: ${value} (${mode?.id})`); if (mode) { - if(hasCapability(ModeType.AutoAirQualityControlMode)) + if (hasCapability(ModeType.AutoAirQualityControlMode)) await setCapabilityValue(ModeType.AutoAirQualityControlMode, mode.id); } else { throw new Error(`Invalid mode ${value}`); diff --git a/drivers/swegoncasa/SwegonClient.ts b/drivers/swegoncasa/SwegonClient.ts index 302be5a..6017fee 100644 --- a/drivers/swegoncasa/SwegonClient.ts +++ b/drivers/swegoncasa/SwegonClient.ts @@ -30,7 +30,7 @@ class SwegonClient { private eventHandler: EventEmitter; private logger: Logger; private timestamp: Date = new Date(); - private hasInitialized: boolean = false; + private hasInitialized = false; private pingInterval: NodeJS.Timeout | null = null; constructor(username: string, password: string, logger: Logger) { @@ -41,36 +41,54 @@ class SwegonClient { } public onMode(callback: (data: Mode) => Promise): void { - this.eventHandler.on('mode', async (data) => callback(data)); + this.eventHandler.on('mode', (data) => { + callback(data).catch((err) => { + this.logger.error('Error in mode callback', err); + }); + }); } public onMeasurement(callback: (data: Measurement) => Promise): void { - this.eventHandler.on('measurement', async (data) => callback(data)); + this.eventHandler.on('measurement', (data) => { + callback(data).catch((err) => { + this.logger.error('Error in measurement callback', err); + }); + }); } public onDeviceInfo(callback: (data: DeviceInfo) => Promise): void { - this.eventHandler.on('deviceInfo', async (data) => callback(data)); + this.eventHandler.on('deviceInfo', (data) => { + callback(data).catch((err) => { + this.logger.error('Error in deviceInfo callback', err); + }); + }); } public onConnectionInfo( callback: (data: ConnectionInfo) => Promise, ): void { - this.eventHandler.on('connectionInfo', async (data) => callback(data)); + this.eventHandler.on('connectionInfo', (data) => { + callback(data).catch((err) => { + this.logger.error('Error in connectionInfo callback', err); + }); + }); } public onSetting( callback: (id: string, value: string) => Promise, ): void { - this.eventHandler.on('setting', async ({ id, value }) => - callback(id, value), - ); + this.eventHandler.on('setting', ({ id, value }) => { + callback(id, value).catch((err) => { + this.logger.error('Error in setting callback', err); + }); + }); } public async setValue(id: SwegonObjectId, value: number): Promise { if (this.ws) { const writeMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs(id, value)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs(id, value)), ]; this.logger.debug('Sending message to Swegon', writeMessage); @@ -88,8 +106,8 @@ class SwegonClient { // Reset Travel mode if currently in Travel mode if (currentValue === SwegonClimateMode.Travel) { const travelMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs('112', 0)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs('112', 0)), ]; this.logger.debug('Sending message to Swegon', travelMessage); @@ -99,12 +117,12 @@ class SwegonClient { // Reset Fireplace mode if currently in Fireplace mode if (currentValue === SwegonClimateMode.Fireplace) { const fireplaceMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs('153', 0)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs('153', 0)), ]; const fireplaceMessage2 = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs('154', 0)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs('154', 0)), ]; this.logger.debug('Sending message to Swegon', fireplaceMessage); @@ -120,8 +138,8 @@ class SwegonClient { newValue === SwegonClimateMode.Boost ) { const fanSpeedMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs(SwegonObjectId.SetFanSpeed, newValue)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs(SwegonObjectId.SetFanSpeed, newValue)), ]; this.logger.info(`Setting Fan Speed to ${newValue}`); @@ -133,14 +151,14 @@ class SwegonClient { // Turn on if (currentValue === SwegonClimateMode.Off) { const onMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs(SwegonObjectId.TurnOff, 0)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs(SwegonObjectId.TurnOff, 0)), ]; // TODO: Not sure what this does yet const onMessage2 = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs('156', 1)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs('156', 1)), ]; this.logger.debug('Sending message to Swegon', onMessage); @@ -152,8 +170,8 @@ class SwegonClient { // Turn off if (newValue === SwegonClimateMode.Off) { const offMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs(SwegonObjectId.TurnOff, 1)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs(SwegonObjectId.TurnOff, 1)), ]; this.logger.debug('Turning off', offMessage); @@ -163,8 +181,8 @@ class SwegonClient { // TODO: Not sure what this does yet, but swegoncasa.io does it so we do as well if (newValue === SwegonClimateMode.Boost) { const boostMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs('116', 1)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs('116', 1)), ]; this.logger.debug('Turning on boost', boostMessage); @@ -174,8 +192,8 @@ class SwegonClient { // TODO: Not sure what this does yet, but swegoncasa.io does it so we do as well if (newValue === SwegonClimateMode.Fireplace) { const fireplaceMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs('153', 1)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs('153', 1)), ]; this.logger.debug('Turning on fireplace', fireplaceMessage); @@ -185,13 +203,13 @@ class SwegonClient { // TODO: Not sure what this does yet, but swegoncasa.io does it so we do as well if (newValue === SwegonClimateMode.Travel) { const travelMessage = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs('112', 1)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs('112', 1)), ]; const travelMessage2 = [ - "message", - JSON.stringify(SwegonConstants.WriteArgs('154', 1)) + 'message', + JSON.stringify(SwegonConstants.WriteArgs('154', 1)), ]; this.logger.debug('Turning on travel', travelMessage); @@ -206,7 +224,7 @@ class SwegonClient { try { this.timestamp = new Date(); - const url = `wss://oulite.ouman.io/socket.io/?EIO=4&transport=websocket`; + const url = 'wss://oulite.ouman.io/socket.io/?EIO=4&transport=websocket'; this.logger.info( `Connecting to websocket - Url: ${url}, Device ID: ${deviceId}`, @@ -223,15 +241,15 @@ class SwegonClient { const connectData = { deviceid: deviceId, date: new Date().toISOString(), - token: this.token + token: this.token, }; - this.logger.debug("Sending connect data:", connectData); + this.logger.debug('Sending connect data:', connectData); ws.send(`40${JSON.stringify(connectData)}`); // Keep the connection alive with ping messages this.pingInterval = setInterval(() => { ws.send('3'); - this.logger.debug("Sending ping"); + this.logger.debug('Sending ping'); }, 25000); }); @@ -239,7 +257,7 @@ class SwegonClient { this.logger.error('WebSocket Error:', { message: err.message, code: err.code, - error: JSON.stringify(err, Object.getOwnPropertyNames(err)) + error: JSON.stringify(err, Object.getOwnPropertyNames(err)), }); }); @@ -253,32 +271,34 @@ class SwegonClient { this.logger.error('WebSocket Closed:', { code, reason: reason.toString(), - timestamp: new Date().toISOString() + timestamp: new Date().toISOString(), }); // Reconnect setTimeout(() => { - this.connect(deviceId); + this.connect(deviceId).catch((err) => { + this.logger.error('Failed to reconnect', err); + }); }, 500); }); ws.on( 'message', (data: Buffer | ArrayBuffer | Buffer[], isBinary: boolean) => { - let value = data.toString(); + const value = data.toString(); this.logger.debug('Received message from Swegon: ', value); // Håndter Socket.IO v4 handshake if (value.startsWith('0')) { try { const handshakeData = JSON.parse(value.substring(1)); - console.debug("Handshake data:", handshakeData); + console.debug('Handshake data:', handshakeData); // Send connect packet const connectData = { deviceid: deviceId, date: new Date().toISOString(), - token: this.token + token: this.token, }; ws.send(`40${JSON.stringify(connectData)}`); return; @@ -298,7 +318,7 @@ class SwegonClient { const messageData = JSON.parse(value.substring(2)); const message = JSON.parse(messageData[1]); - //this.logger.debug('Parsed message content:', message); + // this.logger.debug('Parsed message content:', message); if (messageData[1] && message?.method === 'device_connected') { @@ -315,200 +335,196 @@ class SwegonClient { // Set up subscription og read if (!this.hasInitialized) { const subscription = [ - "message", - JSON.stringify(SwegonConstants.SubscriptionArgs) + 'message', + JSON.stringify(SwegonConstants.SubscriptionArgs), ]; const read = [ - "message", - JSON.stringify(SwegonConstants.ReadArgs) + 'message', + JSON.stringify(SwegonConstants.ReadArgs), ]; ws.send(`42${JSON.stringify(read)}`); - this.logger.debug("Sent read"); + this.logger.debug('Sent read'); ws.send(`42${JSON.stringify(subscription)}`); - this.logger.debug("Sent subscription"); + this.logger.debug('Sent subscription'); this.hasInitialized = true; } } else if ( - message?.result && + message?.result && (message as SwegonDeviceMessage).result.objects && (message as SwegonDeviceMessage).result.objects.length > 0 - ) { - const messageContent = (message as SwegonDeviceMessage).result - .objects[0]; + ) { + const messageContent = (message as SwegonDeviceMessage).result + .objects[0]; - this.eventHandler.emit('deviceInfo', { - serialNumber: + this.eventHandler.emit('deviceInfo', { + serialNumber: messageContent?.properties[SwegonPropertyType.ClimateMode] ?.value, - } as DeviceInfo); + } as DeviceInfo); - } else { - - // Parse verdimeldinger - - if (message.method === 'value' && message.params?.objects) { - message.params.objects.forEach((obj: any) => { - this.logger.debug('Received value for object:', { - id: obj.id, - properties: obj.properties - }); - - const measurementValue = obj.properties[SwegonPropertyType.Measurement]?.value || '0'; - - switch (obj.id) { - case SwegonObjectId.SupplyTemperature: - this.eventHandler.emit('measurement', { - type: MeasurementType.SupplyTemperature, - value: parseFloat(measurementValue), - }); - break; - case SwegonObjectId.OutputTemperature: - this.eventHandler.emit('measurement', { - type: MeasurementType.ReturnTemperature, - value: parseFloat(measurementValue), - }); - break; - case SwegonObjectId.IntakeTemperature: - this.eventHandler.emit('measurement', { - type: MeasurementType.IntakeTemperature, - value: parseFloat(measurementValue), - }); - break; - case SwegonObjectId.CO2: - this.eventHandler.emit('measurement', { - type: MeasurementType.CO2, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.Humidity: - this.eventHandler.emit('measurement', { - type: MeasurementType.HumidityPercent, - value: parseFloat(measurementValue), - }); - break; - case SwegonObjectId.HumidityAmount: - this.eventHandler.emit('measurement', { - type: MeasurementType.HumidityAmount, - value: parseFloat(measurementValue) / 10, - }); - break; - case SwegonObjectId.CurrentFanSpeed: - this.eventHandler.emit('measurement', { - type: MeasurementType.CurrentFanSpeed, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.VentilationLevelIn: - this.eventHandler.emit('measurement', { - type: MeasurementType.VentilationLevelIn, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.VentilationLevelOut: - this.eventHandler.emit('measurement', { - type: MeasurementType.VentilationLevelOut, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.BoostCountDown: - this.eventHandler.emit('measurement', { - type: MeasurementType.BoostCountDown, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.AirQuality: - this.eventHandler.emit('measurement', { - type: MeasurementType.AirQuality, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.SetFanSpeed: - this.eventHandler.emit('mode', { - id: ModeType.ClimateMode, - value: measurementValue, - }); - break; - case SwegonObjectId.SummerNightCoolingBoost: - this.eventHandler.emit('setting', { - id: SettingType.SummerNightCoolingBoost, - value: measurementValue, - }); - break; - case SwegonObjectId.SummerNightCoolingMode: - this.eventHandler.emit('mode', { - id: ModeType.SummerNightCoolingMode, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.TemperatureControlMode: - this.eventHandler.emit('setting', { - id: SettingType.TemperatureControlMode, - value: measurementValue, - }); - break; - case SwegonObjectId.AutoHumidityControlMode: - this.eventHandler.emit('mode', { - id: ModeType.AutoHumidityControlMode, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.AutoHumidityControlBoostLimit: - this.eventHandler.emit('setting', { - id: SettingType.AutoHumidityControlBoostLimit, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.AutoHumidityControlFullBoostLimit: - this.eventHandler.emit('setting', { - id: SettingType.AutoHumidityControlFullBoostLimit, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.AutoAirQualityControlMode: - this.eventHandler.emit('mode', { - id: ModeType.AutoAirQualityControlMode, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.TravellingModeTemperatureDrop: - this.eventHandler.emit('setting', { - id: SettingType.TravellingModeTemperatureDrop, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.AwayModeTemperatureDrop: - this.eventHandler.emit('setting', { - id: SettingType.AwayModeTemperatureDrop, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.SupplyTemperatureSetpoint: - this.eventHandler.emit('setting', { - id: SettingType.SupplyTemperatureSetpoint, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.CO2HomeLimit: - this.eventHandler.emit('setting', { - id: SettingType.CO2HomeLimit, - value: parseInt(measurementValue, 10), - }); - break; - case SwegonObjectId.CO2AwayLimit: - this.eventHandler.emit('setting', { - id: SettingType.CO2AwayLimit, - value: parseInt(measurementValue, 10), - }); - break; - default: - break; - } + } else if (message.method === 'value' && message.params?.objects) { + // Parse verdimeldinger + message.params.objects.forEach((obj: any) => { + this.logger.debug('Received value for object:', { + id: obj.id, + properties: obj.properties, }); - } + + const measurementValue = obj.properties[SwegonPropertyType.Measurement]?.value || '0'; + + switch (obj.id) { + case SwegonObjectId.SupplyTemperature: + this.eventHandler.emit('measurement', { + type: MeasurementType.SupplyTemperature, + value: parseFloat(measurementValue), + }); + break; + case SwegonObjectId.OutputTemperature: + this.eventHandler.emit('measurement', { + type: MeasurementType.ReturnTemperature, + value: parseFloat(measurementValue), + }); + break; + case SwegonObjectId.IntakeTemperature: + this.eventHandler.emit('measurement', { + type: MeasurementType.IntakeTemperature, + value: parseFloat(measurementValue), + }); + break; + case SwegonObjectId.CO2: + this.eventHandler.emit('measurement', { + type: MeasurementType.CO2, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.Humidity: + this.eventHandler.emit('measurement', { + type: MeasurementType.HumidityPercent, + value: parseFloat(measurementValue), + }); + break; + case SwegonObjectId.HumidityAmount: + this.eventHandler.emit('measurement', { + type: MeasurementType.HumidityAmount, + value: parseFloat(measurementValue) / 10, + }); + break; + case SwegonObjectId.CurrentFanSpeed: + this.eventHandler.emit('measurement', { + type: MeasurementType.CurrentFanSpeed, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.VentilationLevelIn: + this.eventHandler.emit('measurement', { + type: MeasurementType.VentilationLevelIn, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.VentilationLevelOut: + this.eventHandler.emit('measurement', { + type: MeasurementType.VentilationLevelOut, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.BoostCountDown: + this.eventHandler.emit('measurement', { + type: MeasurementType.BoostCountDown, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.AirQuality: + this.eventHandler.emit('measurement', { + type: MeasurementType.AirQuality, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.SetFanSpeed: + this.eventHandler.emit('mode', { + id: ModeType.ClimateMode, + value: measurementValue, + }); + break; + case SwegonObjectId.SummerNightCoolingBoost: + this.eventHandler.emit('setting', { + id: SettingType.SummerNightCoolingBoost, + value: measurementValue, + }); + break; + case SwegonObjectId.SummerNightCoolingMode: + this.eventHandler.emit('mode', { + id: ModeType.SummerNightCoolingMode, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.TemperatureControlMode: + this.eventHandler.emit('setting', { + id: SettingType.TemperatureControlMode, + value: measurementValue, + }); + break; + case SwegonObjectId.AutoHumidityControlMode: + this.eventHandler.emit('mode', { + id: ModeType.AutoHumidityControlMode, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.AutoHumidityControlBoostLimit: + this.eventHandler.emit('setting', { + id: SettingType.AutoHumidityControlBoostLimit, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.AutoHumidityControlFullBoostLimit: + this.eventHandler.emit('setting', { + id: SettingType.AutoHumidityControlFullBoostLimit, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.AutoAirQualityControlMode: + this.eventHandler.emit('mode', { + id: ModeType.AutoAirQualityControlMode, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.TravellingModeTemperatureDrop: + this.eventHandler.emit('setting', { + id: SettingType.TravellingModeTemperatureDrop, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.AwayModeTemperatureDrop: + this.eventHandler.emit('setting', { + id: SettingType.AwayModeTemperatureDrop, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.SupplyTemperatureSetpoint: + this.eventHandler.emit('setting', { + id: SettingType.SupplyTemperatureSetpoint, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.CO2HomeLimit: + this.eventHandler.emit('setting', { + id: SettingType.CO2HomeLimit, + value: parseInt(measurementValue, 10), + }); + break; + case SwegonObjectId.CO2AwayLimit: + this.eventHandler.emit('setting', { + id: SettingType.CO2AwayLimit, + value: parseInt(measurementValue, 10), + }); + break; + default: + break; + } + }); } } catch (parseErr) { this.logger.error('Unable to parse Swegon message', parseErr); diff --git a/drivers/swegoncasa/device.ts b/drivers/swegoncasa/device.ts index 5478ab3..57e0b4d 100644 --- a/drivers/swegoncasa/device.ts +++ b/drivers/swegoncasa/device.ts @@ -30,19 +30,27 @@ class SwegonCasaDevice extends Homey.Device { // Add any missing settings if (!settings.temperatureControlMode) { - this.setSettings({ temperatureControlMode: 'comfort' }); + this.setSettings({ temperatureControlMode: 'comfort' }).catch((err) => { + this.logger.error('Failed to set temperatureControlMode', err); + }); } if (!settings.summerNightCoolingBoost) { - this.setSettings({ summerNightCoolingBoost: 'off' }); + this.setSettings({ summerNightCoolingBoost: 'off' }).catch((err) => { + this.logger.error('Failed to set summerNightCoolingBoost', err); + }); } if (!settings.co2HomeLimit) { - this.setSettings({ co2HomeLimit: 550 }); + this.setSettings({ co2HomeLimit: 550 }).catch((err) => { + this.logger.error('Failed to set co2HomeLimit', err); + }); } if (!settings.co2AwayLimit) { - this.setSettings({ co2AwayLimit: 400 }); + this.setSettings({ co2AwayLimit: 400 }).catch((err) => { + this.logger.error('Failed to set co2AwayLimit', err); + }); } } @@ -219,7 +227,9 @@ class SwegonCasaDevice extends Homey.Device { const mode = ClimateModes.find((x) => x.id === value); if (mode) { - this.swegonClient?.setClimateMode(currentMode, mode.value); + this.swegonClient?.setClimateMode(currentMode, mode.value).catch((err) => { + this.logger.error('Failed to set climate mode', err); + }); } } @@ -335,7 +345,9 @@ class SwegonCasaDevice extends Homey.Device { swegonClient.setValue( SwegonObjectId.SummerNightCoolingMode, mode.value, - ); + ).catch((err) => { + this.logger.error('Failed to set summer night cooling mode', err); + }); } }, ); @@ -353,7 +365,9 @@ class SwegonCasaDevice extends Homey.Device { swegonClient.setValue( SwegonObjectId.AutoHumidityControlMode, mode.value, - ); + ).catch((err) => { + this.logger.error('Failed to set auto humidity control mode', err); + }); } }, ); @@ -371,7 +385,9 @@ class SwegonCasaDevice extends Homey.Device { swegonClient.setValue( SwegonObjectId.AutoAirQualityControlMode, mode.value, - ); + ).catch((err) => { + this.logger.error('Failed to set auto air quality control mode', err); + }); } }, ); @@ -388,7 +404,9 @@ class SwegonCasaDevice extends Homey.Device { } async onUninit(): Promise { - this.swegonClient?.destroy(); + this.swegonClient?.destroy().catch((err) => { + this.logger.error('Failed to destroy swegon client', err); + }); } /** diff --git a/drivers/swegoncasa/driver.ts b/drivers/swegoncasa/driver.ts index 4ce32e2..07c71f8 100644 --- a/drivers/swegoncasa/driver.ts +++ b/drivers/swegoncasa/driver.ts @@ -1,5 +1,4 @@ import Homey from 'homey'; -import type PairSession from 'homey/lib/PairSession'; import Logger from '../../lib/logger'; import SwegonClient from './SwegonClient'; import { SwegonDevice } from '../../types/swegon'; @@ -7,7 +6,7 @@ import { SwegonDevice } from '../../types/swegon'; class SwegonCasaDriver extends Homey.Driver { private logger = new Logger(this.log, this.error, true); - async onPair(session: PairSession): Promise { + async onPair(session: Homey.Driver.PairSession): Promise { let username = ''; let password = ''; diff --git a/package-lock.json b/package-lock.json index 9aaaf6e..5f5586d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,15 +16,16 @@ "@types/homey": "npm:homey-apps-sdk-v3-types@^0.3.12", "@types/node": "^16.11.12", "@types/ws": "^8.2.2", - "@typescript-eslint/eslint-plugin": "4.33.0", - "@typescript-eslint/parser": "^4.33.0", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", "eslint": "^7.32.0", - "eslint-config-airbnb-typescript": "^14.0.2", - "eslint-config-athom": "^3.0.1", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^4.0.0", - "prettier": "^2.5.1", - "typescript": "^4.5.4" + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-athom": "^3.1.3", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-homey-app": "^1.0.2", + "eslint-plugin-prettier": "^4.2.1", + "prettier": "^2.8.8", + "typescript": "^4.9.5" }, "engines": { "node": ">=12.16.1" @@ -41,9 +42,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -145,9 +146,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -163,23 +164,10 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -326,23 +314,23 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "16.18.125", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.125.tgz", - "integrity": "sha512-w7U5ojboSPfZP4zD98d+/cjcN2BDW6lKH2M0ubipt8L8vUC7qUAC6ENKGSJL4tEktH2Saw2K4y1uwSjyRGKMhw==", + "version": "16.18.126", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.126.tgz", + "integrity": "sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==", "dev": true, "license": "MIT" }, "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", "dev": true, "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.14", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz", - "integrity": "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, "license": "MIT", "dependencies": { @@ -350,31 +338,33 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", - "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -382,52 +372,27 @@ } } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", - "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", - "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -436,17 +401,17 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", - "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -454,26 +419,26 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "tsutils": "^3.21.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "*" }, "peerDependenciesMeta": { "typescript": { @@ -481,137 +446,37 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, "license": "MIT", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", - "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", - "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", + "semver": "^7.3.7", "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -624,161 +489,44 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", - "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -889,18 +637,20 @@ } }, "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -920,18 +670,19 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -1043,13 +794,13 @@ } }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, @@ -1061,9 +812,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -1104,10 +855,9 @@ } }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -1118,14 +868,14 @@ } }, "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -1277,9 +1027,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { @@ -1376,7 +1126,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -1409,9 +1158,9 @@ } }, "node_modules/es-abstract": { - "version": "1.23.9", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", - "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "dev": true, "license": "MIT", "dependencies": { @@ -1419,18 +1168,18 @@ "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "call-bound": "^1.0.3", + "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.0", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", @@ -1442,21 +1191,24 @@ "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", + "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.0", + "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.3", + "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.3", + "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", @@ -1465,7 +1217,7 @@ "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.18" + "which-typed-array": "^1.1.19" }, "engines": { "node": ">= 0.4" @@ -1478,7 +1230,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -1488,7 +1239,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -1498,7 +1248,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -1511,7 +1260,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -1524,13 +1272,16 @@ } }, "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/es-to-primitive": { @@ -1624,42 +1375,55 @@ } }, "node_modules/eslint-config-airbnb-base": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", - "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", "dev": true, "license": "MIT", "dependencies": { "confusing-browser-globals": "^1.0.10", "object.assign": "^4.1.2", - "object.entries": "^1.1.2" + "object.entries": "^1.1.5", + "semver": "^6.3.0" }, "engines": { - "node": ">= 6" + "node": "^10.12.0 || >=12.0.0" }, "peerDependencies": { - "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", - "eslint-plugin-import": "^2.22.1" + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-airbnb-base/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/eslint-config-airbnb-typescript": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-14.0.2.tgz", - "integrity": "sha512-oaVR63DqpRUiOOeSVxIzhD3FXbqJRH+7Lt9GCMsS9SKgrRW3XpZINN2FO4JEsnaHEGkktumd0AHE9K7KQNuXSQ==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", + "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", "dev": true, "license": "MIT", "dependencies": { - "eslint-config-airbnb-base": "^14.2.1" + "eslint-config-airbnb-base": "^15.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^4.29.3", - "@typescript-eslint/parser": "^4.29.3" + "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", + "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" } }, "node_modules/eslint-config-athom": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/eslint-config-athom/-/eslint-config-athom-3.1.3.tgz", - "integrity": "sha512-EWh7SaDTN2NNTcrFBGLnuxHWS+PXyom/bLX+bpdq4jvvC3D5/DVCmuQhAO+r8bi4Qurc5MrGo74xkrTYUqJyZg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-athom/-/eslint-config-athom-3.1.5.tgz", + "integrity": "sha512-QPseQu6fwQph9BtRwints6+3d+e7T7SvD26ColkAh/N0NQEJfamMd4gg7qm8gHQFDQy85hKQi0JRwJD/wKpYUA==", "dev": true, "license": "ISC", "dependencies": { @@ -1715,6 +1479,19 @@ } } }, + "node_modules/eslint-config-athom/node_modules/@typescript-eslint/eslint-plugin/node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/eslint-config-athom/node_modules/@typescript-eslint/parser": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", @@ -1762,6 +1539,47 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/eslint-config-athom/node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-athom/node_modules/@typescript-eslint/type-utils/node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/eslint-config-athom/node_modules/@typescript-eslint/types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", @@ -1781,16 +1599,57 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-config-athom/node_modules/@typescript-eslint/typescript-estree/node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/eslint-config-athom/node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "license": "MIT", "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1799,10 +1658,8 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" } }, "node_modules/eslint-config-athom/node_modules/@typescript-eslint/visitor-keys": { @@ -1824,26 +1681,32 @@ } }, "node_modules/eslint-config-athom/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, - "node_modules/eslint-config-athom/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/eslint-config-athom/node_modules/eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 6" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", + "eslint-plugin-import": "^2.22.1" } }, "node_modules/eslint-config-athom/node_modules/minimatch": { @@ -1863,9 +1726,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", - "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.2.tgz", + "integrity": "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==", "dev": true, "license": "MIT", "bin": { @@ -1898,9 +1761,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", "dev": true, "license": "MIT", "dependencies": { @@ -1945,32 +1808,6 @@ "eslint": ">=4.19.1" } }, - "node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=4" - } - }, "node_modules/eslint-plugin-homey-app": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/eslint-plugin-homey-app/-/eslint-plugin-homey-app-1.0.2.tgz", @@ -1985,30 +1822,30 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", + "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", - "is-core-module": "^2.15.1", + "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", - "object.values": "^1.2.0", + "object.values": "^1.2.1", "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", + "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "engines": { @@ -2068,32 +1905,6 @@ "eslint": ">= 4.0.0" } }, - "node_modules/eslint-plugin-mocha/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-plugin-mocha/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=4" - } - }, "node_modules/eslint-plugin-node": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", @@ -2115,32 +1926,6 @@ "eslint": ">=5.16.0" } }, - "node_modules/eslint-plugin-node/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-plugin-node/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=4" - } - }, "node_modules/eslint-plugin-node/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -2152,9 +1937,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", - "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.5.tgz", + "integrity": "sha512-9Ni+xgemM2IWLq6aXEpP2+V/V30GeA/46Ar629vcMqVPodFFWC9skHu/D1phvuqtS8bJCFnNf01/qcmqYEwNfg==", "dev": true, "license": "MIT", "dependencies": { @@ -2188,58 +1973,52 @@ } }, "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "eslint-visitor-keys": "^1.1.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": ">=10" } }, "node_modules/eslint/node_modules/ignore": { @@ -2292,9 +2071,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -2403,9 +2182,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "dev": true, "funding": [ { @@ -2420,9 +2199,9 @@ "license": "BSD-3-Clause" }, "node_modules/fastq": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", - "integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, "license": "ISC", "dependencies": { @@ -2471,16 +2250,16 @@ } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -2498,9 +2277,9 @@ } }, "node_modules/for-each": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz", - "integrity": "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", "dependencies": { @@ -2514,13 +2293,15 @@ } }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -2538,7 +2319,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2582,19 +2362,28 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "get-proto": "^1.0.0", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", @@ -2611,7 +2400,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -2732,7 +2520,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2804,7 +2591,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2817,7 +2603,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -2833,7 +2618,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -2968,13 +2752,13 @@ } }, "node_modules/is-boolean-object": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", - "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", + "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" }, "engines": { @@ -3085,14 +2869,15 @@ } }, "node_modules/is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" }, @@ -3129,6 +2914,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3269,13 +3067,13 @@ } }, "node_modules/is-weakref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz", - "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -3323,9 +3121,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -3412,7 +3210,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3500,10 +3297,17 @@ "dev": true, "license": "MIT" }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true, + "license": "MIT" + }, "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", "engines": { @@ -3545,15 +3349,16 @@ } }, "node_modules/object.entries": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", - "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "es-object-atoms": "^1.1.1" }, "engines": { "node": ">= 0.4" @@ -3729,9 +3534,9 @@ } }, "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, "license": "MIT", "engines": { @@ -3765,9 +3570,9 @@ } }, "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "dev": true, "license": "MIT", "dependencies": { @@ -3899,13 +3704,13 @@ } }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -3930,9 +3735,9 @@ } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", "engines": { @@ -4037,9 +3842,9 @@ } }, "node_modules/semver": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", - "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, "license": "ISC", "bin": { @@ -4232,6 +4037,20 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4429,19 +4248,6 @@ "node": ">=8.0" } }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -4455,6 +4261,13 @@ "strip-bom": "^3.0.0" } }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", @@ -4471,13 +4284,6 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true, - "license": "0BSD" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4716,16 +4522,17 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.18", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", - "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "for-each": "^0.3.3", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, @@ -4754,9 +4561,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index c610ecc..de8f4e3 100644 --- a/package.json +++ b/package.json @@ -17,15 +17,16 @@ "@types/homey": "npm:homey-apps-sdk-v3-types@^0.3.12", "@types/node": "^16.11.12", "@types/ws": "^8.2.2", - "@typescript-eslint/eslint-plugin": "4.33.0", - "@typescript-eslint/parser": "^4.33.0", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", "eslint": "^7.32.0", - "eslint-config-airbnb-typescript": "^14.0.2", - "eslint-config-athom": "^3.0.1", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^4.0.0", - "prettier": "^2.5.1", - "typescript": "^4.5.4" + "eslint-config-airbnb-typescript": "^17.1.0", + "eslint-config-athom": "^3.1.3", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-homey-app": "^1.0.2", + "eslint-plugin-prettier": "^4.2.1", + "prettier": "^2.8.8", + "typescript": "^4.9.5" }, "dependencies": { "axios": "^1.7.9", From 5a891338aec5c3beca3dd515c35bd29d012b7be9 Mon Sep 17 00:00:00 2001 From: araa Date: Mon, 5 Jan 2026 21:08:16 +0100 Subject: [PATCH 8/8] Refactor temperature and ventilation type references in app.ts for consistency - Updated variable names from `temperatureType` and `ventilationType` to `temperature_type` and `ventilation_type` to align with naming conventions. - Ensured all related flow trigger and condition listeners reflect these changes for improved clarity and maintainability. --- app.ts | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/app.ts b/app.ts index 59842e1..ac88f57 100644 --- a/app.ts +++ b/app.ts @@ -59,15 +59,17 @@ class SwegonCasa extends Homey.App { this.homey.flow .getDeviceTriggerCard('temperature_changed') .registerRunListener((args, state) => { - return args.temperatureType === state.temperatureType; + return args.temperature_type === state.temperature_type; }); // Temperature Above Threshold this.homey.flow .getDeviceTriggerCard('temperature_above_threshold') .registerRunListener((args, state) => { - const { threshold, temperatureType } = args; + // eslint-disable-next-line @typescript-eslint/naming-convention + const { threshold, temperature_type } = args; const { previousValue } = state; + const temperatureType = temperature_type; const temperatureCapabilities = { supply: 'measure_supply_temperature', intake: 'measure_intake_temperature', @@ -78,7 +80,7 @@ class SwegonCasa extends Homey.App { ); // Check if type matches and value crossed threshold from below - return temperatureType === state.temperatureType && + return temperature_type === state.temperature_type && previousValue !== undefined && previousValue <= threshold && currentValue > threshold; @@ -88,8 +90,10 @@ class SwegonCasa extends Homey.App { this.homey.flow .getDeviceTriggerCard('temperature_below_threshold') .registerRunListener((args, state) => { - const { threshold, temperatureType } = args; + // eslint-disable-next-line @typescript-eslint/naming-convention + const { threshold, temperature_type } = args; const { previousValue } = state; + const temperatureType = temperature_type; const temperatureCapabilities = { supply: 'measure_supply_temperature', intake: 'measure_intake_temperature', @@ -99,7 +103,7 @@ class SwegonCasa extends Homey.App { temperatureCapabilities[temperatureType as keyof typeof temperatureCapabilities], ); - return temperatureType === state.temperatureType && + return temperature_type === state.temperature_type && previousValue !== undefined && previousValue >= threshold && currentValue < threshold; @@ -109,15 +113,17 @@ class SwegonCasa extends Homey.App { this.homey.flow .getDeviceTriggerCard('ventilation_level_changed') .registerRunListener((args, state) => { - return args.ventilationType === state.ventilationType; + return args.ventilation_type === state.ventilation_type; }); // Ventilation Level Above Threshold this.homey.flow .getDeviceTriggerCard('ventilation_level_above_threshold') .registerRunListener((args, state) => { - const { threshold, ventilationType } = args; + // eslint-disable-next-line @typescript-eslint/naming-convention + const { threshold, ventilation_type } = args; const { previousValue } = state; + const ventilationType = ventilation_type; const ventilationCapabilities = { supply: 'measure_ventilation_level_in', exhaust: 'measure_ventilation_level_out', @@ -126,7 +132,7 @@ class SwegonCasa extends Homey.App { ventilationCapabilities[ventilationType as keyof typeof ventilationCapabilities], ); - return ventilationType === state.ventilationType && + return ventilation_type === state.ventilation_type && previousValue !== undefined && previousValue <= threshold && currentValue > threshold; @@ -136,8 +142,10 @@ class SwegonCasa extends Homey.App { this.homey.flow .getDeviceTriggerCard('ventilation_level_below_threshold') .registerRunListener((args, state) => { - const { threshold, ventilationType } = args; + // eslint-disable-next-line @typescript-eslint/naming-convention + const { threshold, ventilation_type } = args; const { previousValue } = state; + const ventilationType = ventilation_type; const ventilationCapabilities = { supply: 'measure_ventilation_level_in', exhaust: 'measure_ventilation_level_out', @@ -146,7 +154,7 @@ class SwegonCasa extends Homey.App { ventilationCapabilities[ventilationType as keyof typeof ventilationCapabilities], ); - return ventilationType === state.ventilationType && + return ventilation_type === state.ventilation_type && previousValue !== undefined && previousValue >= threshold && currentValue < threshold; @@ -230,7 +238,9 @@ class SwegonCasa extends Homey.App { this.homey.flow .getConditionCard('temperature_is_above') .registerRunListener((args) => { - const { temperatureType, threshold } = args; + // eslint-disable-next-line @typescript-eslint/naming-convention + const { temperature_type, threshold } = args; + const temperatureType = temperature_type; const temperatureCapabilities = { supply: 'measure_supply_temperature', intake: 'measure_intake_temperature', @@ -246,7 +256,9 @@ class SwegonCasa extends Homey.App { this.homey.flow .getConditionCard('temperature_is_below') .registerRunListener((args) => { - const { temperatureType, threshold } = args; + // eslint-disable-next-line @typescript-eslint/naming-convention + const { temperature_type, threshold } = args; + const temperatureType = temperature_type; const temperatureCapabilities = { supply: 'measure_supply_temperature', intake: 'measure_intake_temperature',