@mp-consulting/homebridge-daikin-cloud 1.5.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -27
- package/config.schema.json +66 -12
- package/dist/src/accessories/air-conditioning-accessory.js +1 -1
- package/dist/src/accessories/air-conditioning-accessory.js.map +1 -1
- package/dist/src/accessories/altherma-accessory.js +1 -1
- package/dist/src/accessories/altherma-accessory.js.map +1 -1
- package/dist/src/accessories/base-accessory.d.ts +5 -4
- package/dist/src/accessories/base-accessory.d.ts.map +1 -1
- package/dist/src/accessories/base-accessory.js +9 -10
- package/dist/src/accessories/base-accessory.js.map +1 -1
- package/dist/src/api/daikin-api.d.ts +22 -6
- package/dist/src/api/daikin-api.d.ts.map +1 -1
- package/dist/src/api/daikin-api.js +49 -23
- package/dist/src/api/daikin-api.js.map +1 -1
- package/dist/src/api/daikin-controller.d.ts +4 -48
- package/dist/src/api/daikin-controller.d.ts.map +1 -1
- package/dist/src/api/daikin-controller.js +14 -84
- package/dist/src/api/daikin-controller.js.map +1 -1
- package/dist/src/api/daikin-mobile-oauth.d.ts +11 -40
- package/dist/src/api/daikin-mobile-oauth.d.ts.map +1 -1
- package/dist/src/api/daikin-mobile-oauth.js +36 -160
- package/dist/src/api/daikin-mobile-oauth.js.map +1 -1
- package/dist/src/api/daikin-oauth.d.ts +10 -37
- package/dist/src/api/daikin-oauth.d.ts.map +1 -1
- package/dist/src/api/daikin-oauth.js +36 -166
- package/dist/src/api/daikin-oauth.js.map +1 -1
- package/dist/src/api/daikin-schemas.d.ts +20 -22
- package/dist/src/api/daikin-schemas.d.ts.map +1 -1
- package/dist/src/api/daikin-schemas.js +17 -49
- package/dist/src/api/daikin-schemas.js.map +1 -1
- package/dist/src/api/daikin-types.d.ts +11 -23
- package/dist/src/api/daikin-types.d.ts.map +1 -1
- package/dist/src/api/daikin-types.js.map +1 -1
- package/dist/src/api/daikin-websocket.d.ts +4 -5
- package/dist/src/api/daikin-websocket.d.ts.map +1 -1
- package/dist/src/api/daikin-websocket.js +62 -34
- package/dist/src/api/daikin-websocket.js.map +1 -1
- package/dist/src/api/http-defaults.d.ts +3 -2
- package/dist/src/api/http-defaults.d.ts.map +1 -1
- package/dist/src/api/http-defaults.js.map +1 -1
- package/dist/src/api/http-transport.d.ts +14 -2
- package/dist/src/api/http-transport.d.ts.map +1 -1
- package/dist/src/api/http-transport.js +32 -9
- package/dist/src/api/http-transport.js.map +1 -1
- package/dist/src/api/token-client.d.ts +82 -0
- package/dist/src/api/token-client.d.ts.map +1 -0
- package/dist/src/api/token-client.js +188 -0
- package/dist/src/api/token-client.js.map +1 -0
- package/dist/src/api/token-storage.d.ts +6 -0
- package/dist/src/api/token-storage.d.ts.map +1 -1
- package/dist/src/api/token-storage.js +27 -1
- package/dist/src/api/token-storage.js.map +1 -1
- package/dist/src/config/config-manager.d.ts +69 -125
- package/dist/src/config/config-manager.d.ts.map +1 -1
- package/dist/src/config/config-manager.js +288 -225
- package/dist/src/config/config-manager.js.map +1 -1
- package/dist/src/constants/api.constants.d.ts +6 -0
- package/dist/src/constants/api.constants.d.ts.map +1 -1
- package/dist/src/constants/api.constants.js +7 -1
- package/dist/src/constants/api.constants.js.map +1 -1
- package/dist/src/constants/auth.constants.d.ts +11 -0
- package/dist/src/constants/auth.constants.d.ts.map +1 -1
- package/dist/src/constants/auth.constants.js +12 -1
- package/dist/src/constants/auth.constants.js.map +1 -1
- package/dist/src/constants/device.constants.d.ts +1 -7
- package/dist/src/constants/device.constants.d.ts.map +1 -1
- package/dist/src/constants/device.constants.js +2 -11
- package/dist/src/constants/device.constants.js.map +1 -1
- package/dist/src/constants/time.constants.d.ts +0 -2
- package/dist/src/constants/time.constants.d.ts.map +1 -1
- package/dist/src/constants/time.constants.js +1 -3
- package/dist/src/constants/time.constants.js.map +1 -1
- package/dist/src/device/accessory-factory.d.ts +0 -5
- package/dist/src/device/accessory-factory.d.ts.map +1 -1
- package/dist/src/device/accessory-factory.js +0 -7
- package/dist/src/device/accessory-factory.js.map +1 -1
- package/dist/src/device/capability-detector.d.ts +9 -1
- package/dist/src/device/capability-detector.d.ts.map +1 -1
- package/dist/src/device/capability-detector.js +32 -28
- package/dist/src/device/capability-detector.js.map +1 -1
- package/dist/src/device/capability-docs.d.ts.map +1 -1
- package/dist/src/device/capability-docs.js +3 -0
- package/dist/src/device/capability-docs.js.map +1 -1
- package/dist/src/device/data-paths.d.ts +18 -0
- package/dist/src/device/data-paths.d.ts.map +1 -0
- package/dist/src/device/data-paths.js +20 -0
- package/dist/src/device/data-paths.js.map +1 -0
- package/dist/src/device/profiles/device-profile.d.ts +0 -5
- package/dist/src/device/profiles/device-profile.d.ts.map +1 -1
- package/dist/src/device/profiles/device-profile.js +0 -21
- package/dist/src/device/profiles/device-profile.js.map +1 -1
- package/dist/src/features/base-feature.d.ts +53 -9
- package/dist/src/features/base-feature.d.ts.map +1 -1
- package/dist/src/features/base-feature.js +93 -40
- package/dist/src/features/base-feature.js.map +1 -1
- package/dist/src/features/feature-manager.d.ts +27 -15
- package/dist/src/features/feature-manager.d.ts.map +1 -1
- package/dist/src/features/feature-manager.js +27 -24
- package/dist/src/features/feature-manager.js.map +1 -1
- package/dist/src/features/index.d.ts +1 -0
- package/dist/src/features/index.d.ts.map +1 -1
- package/dist/src/features/index.js +1 -0
- package/dist/src/features/index.js.map +1 -1
- package/dist/src/features/modes/auto-fan-mode.feature.d.ts +16 -10
- package/dist/src/features/modes/auto-fan-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/auto-fan-mode.feature.js +16 -40
- package/dist/src/features/modes/auto-fan-mode.feature.js.map +1 -1
- package/dist/src/features/modes/dry-operation-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/dry-operation-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/dry-operation-mode.feature.js +11 -30
- package/dist/src/features/modes/dry-operation-mode.feature.js.map +1 -1
- package/dist/src/features/modes/econo-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/econo-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/econo-mode.feature.js +11 -31
- package/dist/src/features/modes/econo-mode.feature.js.map +1 -1
- package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/fan-only-operation-mode.feature.js +11 -30
- package/dist/src/features/modes/fan-only-operation-mode.feature.js.map +1 -1
- package/dist/src/features/modes/firmware-update.feature.d.ts +7 -6
- package/dist/src/features/modes/firmware-update.feature.d.ts.map +1 -1
- package/dist/src/features/modes/firmware-update.feature.js +15 -22
- package/dist/src/features/modes/firmware-update.feature.js.map +1 -1
- package/dist/src/features/modes/holiday-mode.feature.d.ts +2 -1
- package/dist/src/features/modes/holiday-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/holiday-mode.feature.js +5 -15
- package/dist/src/features/modes/holiday-mode.feature.js.map +1 -1
- package/dist/src/features/modes/indoor-silent-mode.feature.d.ts +15 -12
- package/dist/src/features/modes/indoor-silent-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/indoor-silent-mode.feature.js +15 -39
- package/dist/src/features/modes/indoor-silent-mode.feature.js.map +1 -1
- package/dist/src/features/modes/oscillation-mode.feature.d.ts +5 -6
- package/dist/src/features/modes/oscillation-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/oscillation-mode.feature.js +14 -36
- package/dist/src/features/modes/oscillation-mode.feature.js.map +1 -1
- package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/outdoor-silent-mode.feature.js +11 -31
- package/dist/src/features/modes/outdoor-silent-mode.feature.js.map +1 -1
- package/dist/src/features/modes/powerful-mode.feature.d.ts +14 -10
- package/dist/src/features/modes/powerful-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/powerful-mode.feature.js +13 -32
- package/dist/src/features/modes/powerful-mode.feature.js.map +1 -1
- package/dist/src/features/modes/streamer-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/streamer-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/streamer-mode.feature.js +11 -31
- package/dist/src/features/modes/streamer-mode.feature.js.map +1 -1
- package/dist/src/features/on-off-data-point-feature.d.ts +43 -0
- package/dist/src/features/on-off-data-point-feature.d.ts.map +1 -0
- package/dist/src/features/on-off-data-point-feature.js +49 -0
- package/dist/src/features/on-off-data-point-feature.js.map +1 -0
- package/dist/src/platform.d.ts +56 -9
- package/dist/src/platform.d.ts.map +1 -1
- package/dist/src/platform.js +248 -128
- package/dist/src/platform.js.map +1 -1
- package/dist/src/services/climate-control/fan-speed.d.ts +45 -0
- package/dist/src/services/climate-control/fan-speed.d.ts.map +1 -0
- package/dist/src/services/climate-control/fan-speed.js +104 -0
- package/dist/src/services/climate-control/fan-speed.js.map +1 -0
- package/dist/src/services/climate-control/separate-fan.service.d.ts +45 -0
- package/dist/src/services/climate-control/separate-fan.service.d.ts.map +1 -0
- package/dist/src/services/climate-control/separate-fan.service.js +82 -0
- package/dist/src/services/climate-control/separate-fan.service.js.map +1 -0
- package/dist/src/services/climate-control/setpoint-resolver.d.ts +68 -0
- package/dist/src/services/climate-control/setpoint-resolver.d.ts.map +1 -0
- package/dist/src/services/climate-control/setpoint-resolver.js +170 -0
- package/dist/src/services/climate-control/setpoint-resolver.js.map +1 -0
- package/dist/src/services/climate-control/swing-controller.d.ts +28 -0
- package/dist/src/services/climate-control/swing-controller.d.ts.map +1 -0
- package/dist/src/services/climate-control/swing-controller.js +65 -0
- package/dist/src/services/climate-control/swing-controller.js.map +1 -0
- package/dist/src/services/climate-control.service.d.ts +39 -48
- package/dist/src/services/climate-control.service.d.ts.map +1 -1
- package/dist/src/services/climate-control.service.js +223 -554
- package/dist/src/services/climate-control.service.js.map +1 -1
- package/dist/src/services/hot-water-tank.service.d.ts +17 -8
- package/dist/src/services/hot-water-tank.service.d.ts.map +1 -1
- package/dist/src/services/hot-water-tank.service.js +102 -157
- package/dist/src/services/hot-water-tank.service.js.map +1 -1
- package/dist/src/types/daikin-enums.d.ts +0 -5
- package/dist/src/types/daikin-enums.d.ts.map +1 -1
- package/dist/src/types/daikin-enums.js +1 -7
- package/dist/src/types/daikin-enums.js.map +1 -1
- package/dist/src/types/device-capabilities.d.ts +1 -0
- package/dist/src/types/device-capabilities.d.ts.map +1 -1
- package/dist/src/utils/errors.d.ts +9 -0
- package/dist/src/utils/errors.d.ts.map +1 -0
- package/dist/src/utils/errors.js +25 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/hap-write.d.ts +22 -0
- package/dist/src/utils/hap-write.d.ts.map +1 -0
- package/dist/src/utils/hap-write.js +33 -0
- package/dist/src/utils/hap-write.js.map +1 -0
- package/dist/src/utils/sleep.d.ts +5 -0
- package/dist/src/utils/sleep.d.ts.map +1 -0
- package/dist/src/utils/sleep.js +10 -0
- package/dist/src/utils/sleep.js.map +1 -0
- package/homebridge-ui/README.md +25 -2
- package/homebridge-ui/public/index.html +19 -17
- package/homebridge-ui/public/script.js +95 -32
- package/homebridge-ui/public/styles.css +109 -0
- package/homebridge-ui/server.js +321 -125
- package/package.json +2 -3
- package/dist/src/utils/log-context.d.ts +0 -105
- package/dist/src/utils/log-context.d.ts.map +0 -1
- package/dist/src/utils/log-context.js +0 -206
- package/dist/src/utils/log-context.js.map +0 -1
- package/dist/src/utils/update-mapper.d.ts +0 -59
- package/dist/src/utils/update-mapper.d.ts.map +0 -1
- package/dist/src/utils/update-mapper.js +0 -192
- package/dist/src/utils/update-mapper.js.map +0 -1
|
@@ -3,82 +3,60 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ClimateControlService = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const features_1 = require("../features");
|
|
6
|
+
const hap_write_1 = require("../utils/hap-write");
|
|
7
|
+
const errors_1 = require("../utils/errors");
|
|
6
8
|
const constants_1 = require("../constants");
|
|
9
|
+
const fan_speed_1 = require("./climate-control/fan-speed");
|
|
10
|
+
const swing_controller_1 = require("./climate-control/swing-controller");
|
|
11
|
+
const setpoint_resolver_1 = require("./climate-control/setpoint-resolver");
|
|
12
|
+
const separate_fan_service_1 = require("./climate-control/separate-fan.service");
|
|
13
|
+
const DEFAULT_COOLING_TEMPERATURE = 25;
|
|
7
14
|
class ClimateControlService {
|
|
8
15
|
platform;
|
|
9
16
|
accessory;
|
|
10
17
|
managementPointId;
|
|
11
18
|
name;
|
|
12
19
|
service;
|
|
13
|
-
fanService;
|
|
14
20
|
featureManager;
|
|
21
|
+
swing;
|
|
22
|
+
fanSpeed;
|
|
23
|
+
setpoints;
|
|
24
|
+
autoSetpointSync;
|
|
25
|
+
separateFan;
|
|
26
|
+
lastOperationMode;
|
|
15
27
|
constructor(platform, accessory, managementPointId) {
|
|
16
28
|
this.platform = platform;
|
|
17
29
|
this.accessory = accessory;
|
|
18
30
|
this.managementPointId = managementPointId;
|
|
19
31
|
this.name = this.accessory.displayName;
|
|
20
|
-
|
|
32
|
+
const getDevice = () => this.device;
|
|
33
|
+
this.swing = new swing_controller_1.SwingController(getDevice, managementPointId);
|
|
34
|
+
this.fanSpeed = new fan_speed_1.FanSpeedController(getDevice, managementPointId, () => this.getCurrentOperationMode());
|
|
35
|
+
this.setpoints = new setpoint_resolver_1.SetpointResolver(getDevice, managementPointId, accessory.UUID);
|
|
36
|
+
this.autoSetpointSync = new setpoint_resolver_1.AutoSetpointSync(getDevice, managementPointId, this.setpoints, platform.log, this.name);
|
|
37
|
+
this.separateFan = new separate_fan_service_1.SeparateFanService(platform, accessory, this.name);
|
|
38
|
+
const { Characteristic } = this.platform;
|
|
21
39
|
this.featureManager = new features_1.FeatureManager(platform, accessory, managementPointId);
|
|
22
|
-
this.service = this.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
40
|
+
this.service = this.accessory.getService(this.platform.Service.HeaterCooler)
|
|
41
|
+
|| this.accessory.addService(this.platform.Service.HeaterCooler);
|
|
42
|
+
this.service.setCharacteristic(Characteristic.Name, this.name);
|
|
43
|
+
// Required characteristics
|
|
44
|
+
this.service.getCharacteristic(Characteristic.Active)
|
|
26
45
|
.onSet(this.handleActiveStateSet.bind(this))
|
|
27
46
|
.onGet(this.handleActiveStateGet.bind(this));
|
|
28
|
-
|
|
29
|
-
this.service.getCharacteristic(this.platform.Characteristic.CurrentTemperature)
|
|
47
|
+
this.service.getCharacteristic(Characteristic.CurrentTemperature)
|
|
30
48
|
.onGet(this.handleCurrentTemperatureGet.bind(this));
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
.setProps({
|
|
34
|
-
minStep: 1,
|
|
35
|
-
minValue: 0,
|
|
36
|
-
maxValue: 2,
|
|
37
|
-
})
|
|
49
|
+
this.service.getCharacteristic(Characteristic.TargetHeaterCoolerState)
|
|
50
|
+
.setProps({ minStep: 1, minValue: 0, maxValue: 2 })
|
|
38
51
|
.onGet(this.handleTargetHeaterCoolerStateGet.bind(this))
|
|
39
52
|
.onSet(this.handleTargetHeaterCoolerStateSet.bind(this));
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const coolingChar = this.service.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature);
|
|
43
|
-
// Set value within default HomeKit range first to avoid warning when setProps narrows the range
|
|
44
|
-
const coolingValue = typeof roomTemperatureControlForCooling.value === 'number' ? roomTemperatureControlForCooling.value : constants_1.COOLING_TEMP_CLAMP_MAX;
|
|
45
|
-
const clampedCoolingValue = Math.max(constants_1.HOMEKIT_TEMP_MIN, Math.min(constants_1.COOLING_TEMP_CLAMP_MAX, coolingValue));
|
|
46
|
-
coolingChar.updateValue(clampedCoolingValue);
|
|
47
|
-
coolingChar
|
|
48
|
-
.setProps({
|
|
49
|
-
minStep: roomTemperatureControlForCooling.stepValue,
|
|
50
|
-
minValue: roomTemperatureControlForCooling.minValue,
|
|
51
|
-
maxValue: roomTemperatureControlForCooling.maxValue,
|
|
52
|
-
})
|
|
53
|
-
.onGet(this.handleCoolingThresholdTemperatureGet.bind(this))
|
|
54
|
-
.onSet(this.handleCoolingThresholdTemperatureSet.bind(this));
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
this.service.removeCharacteristic(this.service.getCharacteristic(this.platform.Characteristic.CoolingThresholdTemperature));
|
|
58
|
-
}
|
|
59
|
-
const roomTemperatureControlForHeating = accessory.context.device.getData(this.managementPointId, 'temperatureControl', `/operationModes/${types_1.DaikinOperationModes.HEATING}/setpoints/${this.getSetpoint(types_1.DaikinOperationModes.HEATING)}`);
|
|
60
|
-
if (roomTemperatureControlForHeating) {
|
|
61
|
-
const heatingChar = this.service.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature);
|
|
62
|
-
// Set value within default HomeKit range first to avoid warning when setProps narrows the range
|
|
63
|
-
const heatingValue = typeof roomTemperatureControlForHeating.value === 'number' ? roomTemperatureControlForHeating.value : constants_1.DEFAULT_ROOM_TEMPERATURE;
|
|
64
|
-
const clampedHeatingValue = Math.max(constants_1.HEATING_TEMP_CLAMP_MIN, Math.min(constants_1.HEATING_TEMP_CLAMP_MAX, heatingValue));
|
|
65
|
-
heatingChar.updateValue(clampedHeatingValue);
|
|
66
|
-
heatingChar
|
|
67
|
-
.setProps({
|
|
68
|
-
minStep: roomTemperatureControlForHeating.stepValue,
|
|
69
|
-
minValue: roomTemperatureControlForHeating.minValue,
|
|
70
|
-
maxValue: roomTemperatureControlForHeating.maxValue,
|
|
71
|
-
})
|
|
72
|
-
.onGet(this.handleHeatingThresholdTemperatureGet.bind(this))
|
|
73
|
-
.onSet(this.handleHeatingThresholdTemperatureSet.bind(this));
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
this.service.removeCharacteristic(this.service.getCharacteristic(this.platform.Characteristic.HeatingThresholdTemperature));
|
|
77
|
-
}
|
|
53
|
+
this.setupThreshold(Characteristic.CoolingThresholdTemperature, types_1.DaikinOperationModes.COOLING, constants_1.COOLING_TEMP_CLAMP_MAX, constants_1.HOMEKIT_TEMP_MIN, constants_1.COOLING_TEMP_CLAMP_MAX, this.handleCoolingThresholdTemperatureGet, this.handleCoolingThresholdTemperatureSet);
|
|
54
|
+
this.setupThreshold(Characteristic.HeatingThresholdTemperature, types_1.DaikinOperationModes.HEATING, constants_1.DEFAULT_ROOM_TEMPERATURE, constants_1.HEATING_TEMP_CLAMP_MIN, constants_1.HEATING_TEMP_CLAMP_MAX, this.handleHeatingThresholdTemperatureGet, this.handleHeatingThresholdTemperatureSet);
|
|
78
55
|
this.addOrUpdateCharacteristicRotationSpeed();
|
|
79
|
-
|
|
56
|
+
this.lastOperationMode = this.getCurrentOperationMode();
|
|
57
|
+
if (this.swing.isSupported()) {
|
|
80
58
|
this.platform.log.debug(`[${this.name}] Device has SwingMode, add Characteristic`);
|
|
81
|
-
this.service.getCharacteristic(
|
|
59
|
+
this.service.getCharacteristic(Characteristic.SwingMode)
|
|
82
60
|
.onGet(this.handleSwingModeGet.bind(this))
|
|
83
61
|
.onSet(this.handleSwingModeSet.bind(this));
|
|
84
62
|
}
|
|
@@ -87,82 +65,43 @@ class ClimateControlService {
|
|
|
87
65
|
// Set up the optional standalone Fan service (fan speed + oscillation tile)
|
|
88
66
|
this.setupSeparateFanService();
|
|
89
67
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* Active characteristic mirrors the unit on/off state, and its RotationSpeed /
|
|
102
|
-
* SwingMode reuse the same handlers as the HeaterCooler so both services stay
|
|
103
|
-
* in sync.
|
|
104
|
-
*/
|
|
105
|
-
setupSeparateFanService() {
|
|
106
|
-
if (!this.service) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
const subtype = 'separate_fan';
|
|
110
|
-
const existing = this.accessory.getServiceById(this.platform.Service.Fanv2, subtype);
|
|
111
|
-
const fanControl = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanSpeed/modes/fixed`);
|
|
112
|
-
const hasFanSpeed = fanControl.value !== undefined;
|
|
113
|
-
const hasSwing = this.hasSwingModeFeature();
|
|
114
|
-
const enabled = this.platform.config.showSeparateFanControl === true;
|
|
115
|
-
if (!enabled || (!hasFanSpeed && !hasSwing)) {
|
|
116
|
-
if (existing) {
|
|
117
|
-
this.platform.log.debug(`[${this.name}] Removing separate Fan service`);
|
|
118
|
-
this.accessory.removeService(existing);
|
|
119
|
-
}
|
|
120
|
-
this.fanService = undefined;
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const fanName = `${this.name} Fan`;
|
|
124
|
-
this.platform.log.debug(`[${this.name}] Adding separate Fan service`);
|
|
125
|
-
this.fanService = existing || this.accessory.addService(this.platform.Service.Fanv2, fanName, subtype);
|
|
126
|
-
this.fanService.setCharacteristic(this.platform.Characteristic.Name, fanName);
|
|
127
|
-
this.fanService.addOptionalCharacteristic(this.platform.Characteristic.ConfiguredName);
|
|
128
|
-
this.fanService.setCharacteristic(this.platform.Characteristic.ConfiguredName, fanName);
|
|
129
|
-
// Active mirrors the unit on/off (same handlers as the HeaterCooler Active).
|
|
130
|
-
this.fanService.getCharacteristic(this.platform.Characteristic.Active)
|
|
131
|
-
.onGet(this.handleActiveStateGet.bind(this))
|
|
132
|
-
.onSet(this.handleActiveStateSet.bind(this));
|
|
133
|
-
if (hasFanSpeed) {
|
|
134
|
-
this.fanService.getCharacteristic(this.platform.Characteristic.RotationSpeed)
|
|
135
|
-
.setProps({
|
|
136
|
-
minStep: percentStep(fanControl.maxValue),
|
|
137
|
-
minValue: 0,
|
|
138
|
-
maxValue: 100,
|
|
139
|
-
})
|
|
140
|
-
.onGet(this.handleRotationSpeedGet.bind(this))
|
|
141
|
-
.onSet(this.handleRotationSpeedSet.bind(this));
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
this.fanService.removeCharacteristic(this.fanService.getCharacteristic(this.platform.Characteristic.RotationSpeed));
|
|
145
|
-
}
|
|
146
|
-
if (hasSwing) {
|
|
147
|
-
this.fanService.getCharacteristic(this.platform.Characteristic.SwingMode)
|
|
148
|
-
.onGet(this.handleSwingModeGet.bind(this))
|
|
149
|
-
.onSet(this.handleSwingModeSet.bind(this));
|
|
150
|
-
}
|
|
68
|
+
get device() {
|
|
69
|
+
return this.accessory.context.device;
|
|
70
|
+
}
|
|
71
|
+
getData(dataPoint, path) {
|
|
72
|
+
return this.device.getData(this.managementPointId, dataPoint, path);
|
|
73
|
+
}
|
|
74
|
+
setData(dataPoint, pathOrValue, value) {
|
|
75
|
+
return this.device.setData(this.managementPointId, dataPoint, pathOrValue, value);
|
|
76
|
+
}
|
|
77
|
+
write(characteristic, op) {
|
|
78
|
+
return (0, hap_write_1.withHapWrite)(this.platform, `[${this.name}] ${characteristic}`, op);
|
|
151
79
|
}
|
|
152
80
|
/**
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
* so HomeKit shows "No Response" instead of Homebridge logging "plugin threw an error".
|
|
81
|
+
* Threshold characteristics. getData() always returns a wrapper, so these are
|
|
82
|
+
* always present; the props come from the device's setpoint constraints.
|
|
156
83
|
*/
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
84
|
+
setupThreshold(characteristic, operationMode, fallback, clampMin, clampMax, onGet, onSet) {
|
|
85
|
+
const setpoint = this.setpoints.read(operationMode);
|
|
86
|
+
const char = this.service.getCharacteristic(characteristic);
|
|
87
|
+
// Set value within default HomeKit range first to avoid warning when setProps narrows the range
|
|
88
|
+
const value = typeof setpoint.value === 'number' ? setpoint.value : fallback;
|
|
89
|
+
char.updateValue(Math.max(clampMin, Math.min(clampMax, value)));
|
|
90
|
+
char
|
|
91
|
+
.setProps({ minStep: setpoint.stepValue, minValue: setpoint.minValue, maxValue: setpoint.maxValue })
|
|
92
|
+
.onGet(onGet.bind(this))
|
|
93
|
+
.onSet(onSet.bind(this));
|
|
94
|
+
}
|
|
95
|
+
setupSeparateFanService() {
|
|
96
|
+
const fixed = this.fanSpeed.fixed();
|
|
97
|
+
this.separateFan.setup({ hasFanSpeed: fixed.value !== undefined, fanSpeedMax: fixed.maxValue, hasSwing: this.swing.isSupported() }, {
|
|
98
|
+
getActive: this.handleActiveStateGet.bind(this),
|
|
99
|
+
setActive: this.handleActiveStateSet.bind(this),
|
|
100
|
+
getRotationSpeed: this.handleRotationSpeedGet.bind(this),
|
|
101
|
+
setRotationSpeed: this.handleRotationSpeedSet.bind(this),
|
|
102
|
+
getSwing: this.handleSwingModeGet.bind(this),
|
|
103
|
+
setSwing: this.handleSwingModeSet.bind(this),
|
|
104
|
+
});
|
|
166
105
|
}
|
|
167
106
|
/**
|
|
168
107
|
* Push current device state to all HAP characteristics via updateValue().
|
|
@@ -171,91 +110,57 @@ class ClimateControlService {
|
|
|
171
110
|
* scene commands before they ever reach onSet.
|
|
172
111
|
*/
|
|
173
112
|
refreshValues() {
|
|
174
|
-
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
113
|
+
const { Characteristic } = this.platform;
|
|
177
114
|
try {
|
|
178
|
-
const
|
|
115
|
+
const isOn = this.getData('onOffMode').value === types_1.DaikinOnOffModes.ON;
|
|
179
116
|
const operationMode = this.getCurrentOperationMode();
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
.
|
|
185
|
-
|
|
117
|
+
// The fixed fan speed range (or its existence) depends on the operation
|
|
118
|
+
// mode, so re-evaluate the RotationSpeed characteristic only when it changes.
|
|
119
|
+
if (operationMode !== this.lastOperationMode) {
|
|
120
|
+
this.lastOperationMode = operationMode;
|
|
121
|
+
this.addOrUpdateCharacteristicRotationSpeed();
|
|
122
|
+
}
|
|
123
|
+
this.service.getCharacteristic(Characteristic.Active)
|
|
124
|
+
.updateValue(isOn ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE);
|
|
125
|
+
this.separateFan.updateActive(isOn);
|
|
126
|
+
let currentState = Characteristic.CurrentHeaterCoolerState.IDLE;
|
|
186
127
|
if (!isOn) {
|
|
187
|
-
currentState =
|
|
128
|
+
currentState = Characteristic.CurrentHeaterCoolerState.INACTIVE;
|
|
188
129
|
}
|
|
189
130
|
else if (operationMode === types_1.DaikinOperationModes.COOLING) {
|
|
190
|
-
currentState =
|
|
131
|
+
currentState = Characteristic.CurrentHeaterCoolerState.COOLING;
|
|
191
132
|
}
|
|
192
133
|
else if (operationMode === types_1.DaikinOperationModes.HEATING) {
|
|
193
|
-
currentState =
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
currentState = this.platform.Characteristic.CurrentHeaterCoolerState.IDLE;
|
|
197
|
-
}
|
|
198
|
-
this.service.getCharacteristic(this.platform.Characteristic.CurrentHeaterCoolerState)
|
|
199
|
-
.updateValue(currentState);
|
|
200
|
-
let targetState;
|
|
201
|
-
switch (operationMode) {
|
|
202
|
-
case types_1.DaikinOperationModes.COOLING:
|
|
203
|
-
targetState = this.platform.Characteristic.TargetHeaterCoolerState.COOL;
|
|
204
|
-
break;
|
|
205
|
-
case types_1.DaikinOperationModes.HEATING:
|
|
206
|
-
targetState = this.platform.Characteristic.TargetHeaterCoolerState.HEAT;
|
|
207
|
-
break;
|
|
208
|
-
default:
|
|
209
|
-
targetState = this.platform.Characteristic.TargetHeaterCoolerState.AUTO;
|
|
134
|
+
currentState = Characteristic.CurrentHeaterCoolerState.HEATING;
|
|
210
135
|
}
|
|
211
|
-
this.service.getCharacteristic(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
this.
|
|
215
|
-
.updateValue(typeof temperature === 'number' && isFinite(temperature) ? temperature : constants_1.DEFAULT_ROOM_TEMPERATURE);
|
|
216
|
-
const coolingTemp = this.accessory.context.device.getData(this.managementPointId, 'temperatureControl', `/operationModes/${types_1.DaikinOperationModes.COOLING}/setpoints/${this.getSetpoint(types_1.DaikinOperationModes.COOLING)}`).value;
|
|
136
|
+
this.service.getCharacteristic(Characteristic.CurrentHeaterCoolerState).updateValue(currentState);
|
|
137
|
+
this.service.getCharacteristic(Characteristic.TargetHeaterCoolerState).updateValue(this.targetHeaterCoolerState(operationMode));
|
|
138
|
+
this.service.getCharacteristic(Characteristic.CurrentTemperature).updateValue(this.currentTemperature());
|
|
139
|
+
const coolingTemp = this.setpoints.read(types_1.DaikinOperationModes.COOLING).value;
|
|
217
140
|
if (coolingTemp !== undefined) {
|
|
218
|
-
this.service.getCharacteristic(
|
|
219
|
-
.updateValue(
|
|
141
|
+
this.service.getCharacteristic(Characteristic.CoolingThresholdTemperature)
|
|
142
|
+
.updateValue(finiteOr(coolingTemp, DEFAULT_COOLING_TEMPERATURE));
|
|
220
143
|
}
|
|
221
|
-
const heatingTemp = this.
|
|
144
|
+
const heatingTemp = this.setpoints.read(types_1.DaikinOperationModes.HEATING).value;
|
|
222
145
|
if (heatingTemp !== undefined) {
|
|
223
|
-
this.service.getCharacteristic(
|
|
224
|
-
.updateValue(
|
|
146
|
+
this.service.getCharacteristic(Characteristic.HeatingThresholdTemperature)
|
|
147
|
+
.updateValue(finiteOr(heatingTemp, constants_1.DEFAULT_ROOM_TEMPERATURE));
|
|
225
148
|
}
|
|
226
|
-
// Only push RotationSpeed
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const fanSpeedData = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${operationMode}/fanSpeed/modes/fixed`);
|
|
237
|
-
if (fanSpeedData.value !== undefined) {
|
|
238
|
-
const percent = deviceSpeedToPercent(fanSpeedData.value, fanSpeedData.maxValue);
|
|
239
|
-
this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed)
|
|
240
|
-
.updateValue(percent);
|
|
241
|
-
if (this.fanService?.testCharacteristic(this.platform.Characteristic.RotationSpeed)) {
|
|
242
|
-
this.fanService.getCharacteristic(this.platform.Characteristic.RotationSpeed).updateValue(percent);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
149
|
+
// Only push RotationSpeed when the device is in 'fixed' fan mode. In 'auto'
|
|
150
|
+
// or 'quiet' the stored `fixed` value doesn't represent the actual speed;
|
|
151
|
+
// pushing it would seed the HomeKit cache with a value the home hub may
|
|
152
|
+
// replay (as a "cache verification") when another characteristic changes,
|
|
153
|
+
// accidentally switching the device out of auto/quiet. handleRotationSpeedSet
|
|
154
|
+
// guards against that replay too, but an accurate cache prevents it entirely.
|
|
155
|
+
const percent = this.fanSpeed.percentIfFixed(operationMode);
|
|
156
|
+
if (percent !== undefined) {
|
|
157
|
+
this.service.getCharacteristic(Characteristic.RotationSpeed).updateValue(percent);
|
|
158
|
+
this.separateFan.updateRotationSpeed(percent);
|
|
245
159
|
}
|
|
246
|
-
if (this.
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const horizontalSwingMode = this.hasSwingModeHorizontalFeature()
|
|
251
|
-
? this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${operationMode}/fanDirection/horizontal/currentMode`).value
|
|
252
|
-
: null;
|
|
253
|
-
const swingEnabled = horizontalSwingMode !== types_1.DaikinFanDirectionHorizontalModes.STOP
|
|
254
|
-
&& verticalSwingMode !== types_1.DaikinFanDirectionVerticalModes.STOP;
|
|
255
|
-
this.service.getCharacteristic(this.platform.Characteristic.SwingMode)
|
|
256
|
-
.updateValue(swingEnabled ? this.platform.Characteristic.SwingMode.SWING_ENABLED : this.platform.Characteristic.SwingMode.SWING_DISABLED);
|
|
257
|
-
this.fanService?.getCharacteristic(this.platform.Characteristic.SwingMode)
|
|
258
|
-
.updateValue(swingEnabled ? this.platform.Characteristic.SwingMode.SWING_ENABLED : this.platform.Characteristic.SwingMode.SWING_DISABLED);
|
|
160
|
+
if (this.swing.isSupported()) {
|
|
161
|
+
const swingMode = this.swing.isSwinging() ? Characteristic.SwingMode.SWING_ENABLED : Characteristic.SwingMode.SWING_DISABLED;
|
|
162
|
+
this.service.getCharacteristic(Characteristic.SwingMode).updateValue(swingMode);
|
|
163
|
+
this.separateFan.updateSwing(swingMode);
|
|
259
164
|
}
|
|
260
165
|
// Push feature switches (PowerfulMode, EconoMode, etc.) so toggling
|
|
261
166
|
// these from the Daikin app reaches HomeKit on the next WebSocket update
|
|
@@ -263,417 +168,181 @@ class ClimateControlService {
|
|
|
263
168
|
this.featureManager.refreshAll();
|
|
264
169
|
}
|
|
265
170
|
catch (e) {
|
|
266
|
-
this.platform.log.debug(`[${this.name}] refreshValues error: ${
|
|
171
|
+
this.platform.log.debug(`[${this.name}] refreshValues error: ${(0, errors_1.toMessage)(e)}`);
|
|
267
172
|
}
|
|
268
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Add/refresh RotationSpeed for the current operation mode's fixed fan speed,
|
|
176
|
+
* or remove it when that mode has none (getData() returns `{ value: undefined }`
|
|
177
|
+
* for a missing path; setting it would fail at the API).
|
|
178
|
+
*
|
|
179
|
+
* The characteristic stays in percentage space (see fan-speed.ts). setProps
|
|
180
|
+
* runs FIRST to widen any narrow range left over from a prior session, or the
|
|
181
|
+
* updateValue below trips HAP's validateUserInput; minValue=0 (not
|
|
182
|
+
* stepPercent) keeps HAP happy for cached values below one step —
|
|
183
|
+
* percentToDeviceSpeed clamps writes up to the device minValue anyway.
|
|
184
|
+
*/
|
|
269
185
|
addOrUpdateCharacteristicRotationSpeed() {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
// (with undefined min/max/step) even for devices that don't support a fixed fan
|
|
276
|
-
// speed in the current operation mode. Setting it would then fail at the API.
|
|
277
|
-
const fanControl = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanSpeed/modes/fixed`);
|
|
278
|
-
if (fanControl.value !== undefined) {
|
|
279
|
-
// Daikin units expose a small integer fan-speed scale (typically 1-5 or 1-3).
|
|
280
|
-
// iOS Home renders RotationSpeed as a 0-100% slider regardless of setProps,
|
|
281
|
-
// so we keep the characteristic in percentage space and map both directions:
|
|
282
|
-
// device 5/5 → HomeKit 100% (full bar), device 1/5 → 20%, etc.
|
|
283
|
-
// minStep = 100/maxValue gives the discrete positions that round-trip cleanly.
|
|
284
|
-
//
|
|
285
|
-
// Order matters: setProps FIRST to widen any narrow range left over from a
|
|
286
|
-
// prior session (e.g. an old build that capped at maxValue=5). Otherwise the
|
|
287
|
-
// updateValue below trips HAP's validateUserInput. minValue=0 (not stepPercent)
|
|
288
|
-
// keeps HAP happy when the cached value is below stepPercent — the slider's
|
|
289
|
-
// 0 position is harmless since percentToDeviceSpeed clamps writes up to the
|
|
290
|
-
// device minValue anyway.
|
|
291
|
-
const rotationChar = this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed);
|
|
292
|
-
const stepPercent = percentStep(fanControl.maxValue);
|
|
293
|
-
const percent = deviceSpeedToPercent(fanControl.value, fanControl.maxValue);
|
|
294
|
-
rotationChar
|
|
295
|
-
.setProps({
|
|
296
|
-
minStep: stepPercent,
|
|
297
|
-
minValue: 0,
|
|
298
|
-
maxValue: 100,
|
|
299
|
-
})
|
|
300
|
-
.onGet(this.handleRotationSpeedGet.bind(this))
|
|
301
|
-
.onSet(this.handleRotationSpeedSet.bind(this));
|
|
302
|
-
// Only seed the HomeKit cache with the stored fixed percentage when the
|
|
303
|
-
// device is actually in 'fixed' fan mode. During construction this runs
|
|
304
|
-
// before refreshValues() — without this guard, the initial seed would
|
|
305
|
-
// push a misleading value (e.g. 100% when the device is in auto mode)
|
|
306
|
-
// that the home hub may later replay as a "cache verification" write.
|
|
307
|
-
const operationMode = this.getCurrentOperationMode();
|
|
308
|
-
const currentMode = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${operationMode}/fanSpeed/currentMode`);
|
|
309
|
-
if (currentMode.value === types_1.DaikinFanSpeedModes.FIXED) {
|
|
310
|
-
rotationChar.updateValue(percent);
|
|
311
|
-
}
|
|
186
|
+
const { RotationSpeed } = this.platform.Characteristic;
|
|
187
|
+
const fanControl = this.fanSpeed.fixed();
|
|
188
|
+
if (fanControl.value === undefined) {
|
|
189
|
+
this.service.removeCharacteristic(this.service.getCharacteristic(RotationSpeed));
|
|
190
|
+
return;
|
|
312
191
|
}
|
|
313
|
-
|
|
314
|
-
|
|
192
|
+
const rotationChar = this.service.getCharacteristic(RotationSpeed);
|
|
193
|
+
rotationChar
|
|
194
|
+
.setProps({ minStep: (0, fan_speed_1.percentStep)(fanControl.maxValue), minValue: 0, maxValue: 100 })
|
|
195
|
+
.onGet(this.handleRotationSpeedGet.bind(this))
|
|
196
|
+
.onSet(this.handleRotationSpeedSet.bind(this));
|
|
197
|
+
// Only seed the cache in 'fixed' fan mode — during construction this runs
|
|
198
|
+
// before refreshValues(), and a misleading seed (e.g. 100% while in auto)
|
|
199
|
+
// may later be replayed by the home hub as a "cache verification" write.
|
|
200
|
+
const percent = this.fanSpeed.percentIfFixed();
|
|
201
|
+
if (percent !== undefined) {
|
|
202
|
+
rotationChar.updateValue(percent);
|
|
315
203
|
}
|
|
316
204
|
}
|
|
317
205
|
async handleActiveStateGet() {
|
|
318
|
-
const state = this.
|
|
319
|
-
this.platform.log.debug(`[${this.name}] GET ActiveState, state: ${state}, last update: ${this.
|
|
206
|
+
const state = this.getData('onOffMode').value;
|
|
207
|
+
this.platform.log.debug(`[${this.name}] GET ActiveState, state: ${state}, last update: ${this.device.getLastUpdated()}`);
|
|
320
208
|
return state === types_1.DaikinOnOffModes.ON;
|
|
321
209
|
}
|
|
322
210
|
async handleActiveStateSet(value) {
|
|
323
211
|
// HAP sends Active as 0 (INACTIVE) or 1 (ACTIVE), not a boolean
|
|
324
212
|
const desired = value === this.platform.Characteristic.Active.ACTIVE;
|
|
325
|
-
|
|
326
|
-
if ((current === types_1.DaikinOnOffModes.ON) === desired) {
|
|
213
|
+
if ((this.getData('onOffMode').value === types_1.DaikinOnOffModes.ON) === desired) {
|
|
327
214
|
this.platform.log.debug(`[${this.name}] SET ActiveState skipped — already ${desired ? 'on' : 'off'}`);
|
|
328
215
|
return;
|
|
329
216
|
}
|
|
330
217
|
this.platform.log.debug(`[${this.name}] SET ActiveState, state: ${value}`);
|
|
331
|
-
await this.
|
|
332
|
-
await this.accessory.context.device.setData(this.managementPointId, 'onOffMode', desired ? types_1.DaikinOnOffModes.ON : types_1.DaikinOnOffModes.OFF, undefined);
|
|
333
|
-
});
|
|
218
|
+
await this.write('ActiveState', () => this.setData('onOffMode', desired ? types_1.DaikinOnOffModes.ON : types_1.DaikinOnOffModes.OFF, undefined));
|
|
334
219
|
}
|
|
335
220
|
async handleCurrentTemperatureGet() {
|
|
336
|
-
const temperature = this.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
221
|
+
const temperature = this.currentTemperature();
|
|
222
|
+
this.platform.log.debug(`[${this.name}] GET CurrentTemperature, temperature: ${temperature}, last update: ${this.device.getLastUpdated()}`);
|
|
223
|
+
return temperature;
|
|
224
|
+
}
|
|
225
|
+
currentTemperature() {
|
|
226
|
+
return finiteOr(this.getData('sensoryData', '/' + this.getCurrentControlMode()).value, constants_1.DEFAULT_ROOM_TEMPERATURE);
|
|
341
227
|
}
|
|
342
228
|
async handleCoolingThresholdTemperatureGet() {
|
|
343
|
-
|
|
344
|
-
const path = `/operationModes/${types_1.DaikinOperationModes.COOLING}/setpoints/${setpoint}`;
|
|
345
|
-
const temperature = this.accessory.context.device.getData(this.managementPointId, 'temperatureControl', path).value;
|
|
346
|
-
const lastUpdate = this.accessory.context.device.getLastUpdated();
|
|
347
|
-
this.platform.log.debug(`[${this.name}] GET CoolingThresholdTemperature, temperature: ${temperature}, last update: ${lastUpdate}`);
|
|
348
|
-
return typeof temperature === 'number' && isFinite(temperature) ? temperature : 25;
|
|
229
|
+
return this.thresholdGet('cooling', DEFAULT_COOLING_TEMPERATURE);
|
|
349
230
|
}
|
|
350
231
|
async handleCoolingThresholdTemperatureSet(value) {
|
|
232
|
+
await this.thresholdSet('cooling', value);
|
|
233
|
+
}
|
|
234
|
+
async handleHeatingThresholdTemperatureGet() {
|
|
235
|
+
return this.thresholdGet('heating', constants_1.DEFAULT_ROOM_TEMPERATURE);
|
|
236
|
+
}
|
|
237
|
+
async handleHeatingThresholdTemperatureSet(value) {
|
|
238
|
+
await this.thresholdSet('heating', value);
|
|
239
|
+
}
|
|
240
|
+
thresholdGet(kind, fallback) {
|
|
241
|
+
const temperature = this.setpoints.read(thresholdMode(kind)).value;
|
|
242
|
+
const label = kind === 'cooling' ? 'CoolingThresholdTemperature' : 'HeatingThresholdTemperature';
|
|
243
|
+
this.platform.log.debug(`[${this.name}] GET ${label}, temperature: ${temperature}, last update: ${this.device.getLastUpdated()}`);
|
|
244
|
+
return finiteOr(temperature, fallback);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Write a threshold, then mirror the heating/cooling midpoint to Daikin's
|
|
248
|
+
* single AUTO setpoint — once, after concurrent threshold writes settle
|
|
249
|
+
* (see AutoSetpointSync).
|
|
250
|
+
*/
|
|
251
|
+
async thresholdSet(kind, value) {
|
|
351
252
|
const temperature = Math.round(value * 2) / 2;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
253
|
+
const label = kind === 'cooling' ? 'CoolingThresholdTemperature' : 'HeatingThresholdTemperature';
|
|
254
|
+
const operationMode = thresholdMode(kind);
|
|
255
|
+
if (this.setpoints.read(operationMode).value === temperature) {
|
|
256
|
+
this.platform.log.debug(`[${this.name}] SET ${label} skipped — already ${temperature}`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
this.platform.log.debug(`[${this.name}] SET ${label}, temperature to: ${temperature}`);
|
|
260
|
+
await this.write(label, () => this.autoSetpointSync.writeThreshold(kind, temperature, () => this.setData('temperatureControl', this.setpoints.path(operationMode), temperature)));
|
|
357
261
|
}
|
|
358
262
|
async handleRotationSpeedGet() {
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
const percent = typeof speed === 'number' && isFinite(speed)
|
|
362
|
-
? deviceSpeedToPercent(speed, fanSpeedData.maxValue)
|
|
363
|
-
: percentStep(fanSpeedData.maxValue);
|
|
364
|
-
this.platform.log.debug(`[${this.name}] GET RotationSpeed, device speed: ${speed} → ${percent}%, ` +
|
|
365
|
-
`last update: ${this.accessory.context.device.getLastUpdated()}`);
|
|
263
|
+
const { speed, percent } = this.fanSpeed.read();
|
|
264
|
+
this.platform.log.debug(`[${this.name}] GET RotationSpeed, device speed: ${speed} → ${percent}%, last update: ${this.device.getLastUpdated()}`);
|
|
366
265
|
return percent;
|
|
367
266
|
}
|
|
368
267
|
async handleRotationSpeedSet(value) {
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
// respond with a 422 (visible to the user as "No Response" in HomeKit).
|
|
373
|
-
const fixedFanSpeed = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${operationMode}/fanSpeed/modes/fixed`);
|
|
374
|
-
if (fixedFanSpeed.value === undefined) {
|
|
375
|
-
this.platform.log.debug(`[${this.name}] SET RotationSpeed skipped — operationMode ${operationMode} does not support fixed fan speed`);
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
const deviceSpeed = percentToDeviceSpeed(value, fixedFanSpeed.minValue, fixedFanSpeed.maxValue);
|
|
379
|
-
this.platform.log.debug(`[${this.name}] SET RotationSpeed, ${value}% → device speed ${deviceSpeed}`);
|
|
380
|
-
const currentMode = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${operationMode}/fanSpeed/currentMode`);
|
|
381
|
-
// Guard: skip when the device is in auto or quiet fan mode and the incoming
|
|
382
|
-
// speed matches the stored fixed value. HomeKit may replay the cached
|
|
383
|
-
// RotationSpeed when another characteristic (e.g. temperature setpoint)
|
|
384
|
-
// changes on the same service. Without this guard, a simple temperature
|
|
385
|
-
// adjustment would accidentally switch the fan from auto/quiet to fixed mode
|
|
386
|
-
// at the stored speed (often 5/5).
|
|
387
|
-
if (currentMode.value !== undefined &&
|
|
388
|
-
currentMode.value !== types_1.DaikinFanSpeedModes.FIXED &&
|
|
389
|
-
deviceSpeed === fixedFanSpeed.value) {
|
|
390
|
-
this.platform.log.debug(`[${this.name}] SET RotationSpeed skipped — device is in "${currentMode.value}" mode ` +
|
|
391
|
-
`and speed ${deviceSpeed} already matches the stored fixed value. ` +
|
|
392
|
-
'This is likely a HomeKit cache replay, not a user fan-speed change.');
|
|
268
|
+
const plan = this.fanSpeed.plan(value);
|
|
269
|
+
if ('skip' in plan) {
|
|
270
|
+
this.platform.log.debug(`[${this.name}] SET RotationSpeed skipped — ${plan.skip}`);
|
|
393
271
|
return;
|
|
394
272
|
}
|
|
395
|
-
|
|
396
|
-
await this.
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if (currentMode.value !== types_1.DaikinFanSpeedModes.FIXED && allowedModes.includes(types_1.DaikinFanSpeedModes.FIXED)) {
|
|
400
|
-
await this.accessory.context.device.setData(this.managementPointId, 'fanControl', `/operationModes/${operationMode}/fanSpeed/currentMode`, types_1.DaikinFanSpeedModes.FIXED);
|
|
273
|
+
this.platform.log.debug(`[${this.name}] SET RotationSpeed, ${value}% → device speed ${plan.deviceSpeed}`);
|
|
274
|
+
await this.write('RotationSpeed', async () => {
|
|
275
|
+
for (const { path, value: speedValue } of plan.writes) {
|
|
276
|
+
await this.setData('fanControl', path, speedValue);
|
|
401
277
|
}
|
|
402
|
-
await this.accessory.context.device.setData(this.managementPointId, 'fanControl', `/operationModes/${operationMode}/fanSpeed/modes/fixed`, deviceSpeed);
|
|
403
278
|
});
|
|
404
|
-
// Moving the slider flips fanSpeed/currentMode to 'fixed',
|
|
405
|
-
//
|
|
406
|
-
//
|
|
407
|
-
// — setData has already updated the in-memory cache optimistically.
|
|
279
|
+
// Moving the slider flips fanSpeed/currentMode to 'fixed', so the fan-mode
|
|
280
|
+
// switches (Auto fan mode, Indoor silent) are now off. Push their state now —
|
|
281
|
+
// setData has already updated the in-memory cache optimistically.
|
|
408
282
|
this.featureManager.refreshAll();
|
|
409
283
|
}
|
|
410
|
-
async handleHeatingThresholdTemperatureGet() {
|
|
411
|
-
const setpoint = this.getSetpoint(types_1.DaikinOperationModes.HEATING);
|
|
412
|
-
const path = `/operationModes/${types_1.DaikinOperationModes.HEATING}/setpoints/${setpoint}`;
|
|
413
|
-
const temperature = this.accessory.context.device.getData(this.managementPointId, 'temperatureControl', path).value;
|
|
414
|
-
const lastUpdate = this.accessory.context.device.getLastUpdated();
|
|
415
|
-
this.platform.log.debug(`[${this.name}] GET HeatingThresholdTemperature, temperature: ${temperature}, last update: ${lastUpdate}`);
|
|
416
|
-
return typeof temperature === 'number' && isFinite(temperature) ? temperature : constants_1.DEFAULT_ROOM_TEMPERATURE;
|
|
417
|
-
}
|
|
418
|
-
async handleHeatingThresholdTemperatureSet(value) {
|
|
419
|
-
const temperature = Math.round(value * 2) / 2;
|
|
420
|
-
this.platform.log.debug(`[${this.name}] SET HeatingThresholdTemperature, temperature to: ${temperature}`);
|
|
421
|
-
await this.setDeviceData('HeatingThresholdTemperature', async () => {
|
|
422
|
-
await this.accessory.context.device.setData(this.managementPointId, 'temperatureControl', `/operationModes/${types_1.DaikinOperationModes.HEATING}/setpoints/${this.getSetpoint(types_1.DaikinOperationModes.HEATING)}`, temperature);
|
|
423
|
-
await this.syncAutoSetpointIfSupported({ heating: temperature });
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Daikin's auto operationMode uses a SINGLE setpoint, not a range like
|
|
428
|
-
* HomeKit's HeaterCooler (heating threshold + cooling threshold). Without
|
|
429
|
-
* this sync the Daikin app keeps showing whatever auto setpoint was there
|
|
430
|
-
* when the device was last in auto mode, regardless of what the user picks
|
|
431
|
-
* in HomeKit. Mirror the midpoint of the current heating/cooling thresholds
|
|
432
|
-
* to /operationModes/auto/setpoints/roomTemperature whenever either
|
|
433
|
-
* threshold is set, so the Daikin app and HomeKit stay in sync.
|
|
434
|
-
*
|
|
435
|
-
* No-op when the device doesn't expose an auto setpoint (e.g. devices
|
|
436
|
-
* without an auto operationMode at all).
|
|
437
|
-
*/
|
|
438
|
-
async syncAutoSetpointIfSupported(overrides = {}) {
|
|
439
|
-
// Best-effort. Failures here (e.g. getSetpoint throwing for Altherma's
|
|
440
|
-
// weatherDependentHeatingFixedCooling + leavingWaterTemperature combo, or
|
|
441
|
-
// any PATCH error) must not propagate — the primary heating/cooling write
|
|
442
|
-
// already succeeded by this point, and a missing auto-sync just leaves
|
|
443
|
-
// the Daikin app showing a slightly stale auto setpoint.
|
|
444
|
-
try {
|
|
445
|
-
const autoSetpointKey = this.getSetpoint(types_1.DaikinOperationModes.AUTO);
|
|
446
|
-
const autoPath = `/operationModes/${types_1.DaikinOperationModes.AUTO}/setpoints/${autoSetpointKey}`;
|
|
447
|
-
const autoData = this.accessory.context.device.getData(this.managementPointId, 'temperatureControl', autoPath);
|
|
448
|
-
if (autoData.value === undefined) {
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
const heatingKey = this.getSetpoint(types_1.DaikinOperationModes.HEATING);
|
|
452
|
-
const coolingKey = this.getSetpoint(types_1.DaikinOperationModes.COOLING);
|
|
453
|
-
const heating = overrides.heating ?? this.accessory.context.device.getData(this.managementPointId, 'temperatureControl', `/operationModes/${types_1.DaikinOperationModes.HEATING}/setpoints/${heatingKey}`).value;
|
|
454
|
-
const cooling = overrides.cooling ?? this.accessory.context.device.getData(this.managementPointId, 'temperatureControl', `/operationModes/${types_1.DaikinOperationModes.COOLING}/setpoints/${coolingKey}`).value;
|
|
455
|
-
if (typeof heating !== 'number' || typeof cooling !== 'number') {
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
// Midpoint rounded to nearest 0.5° — matches the step used by the
|
|
459
|
-
// heating/cooling setters above, and the stepValue Daikin returns.
|
|
460
|
-
let midpoint = Math.round(heating + cooling) / 2;
|
|
461
|
-
if (typeof autoData.minValue === 'number') {
|
|
462
|
-
midpoint = Math.max(autoData.minValue, midpoint);
|
|
463
|
-
}
|
|
464
|
-
if (typeof autoData.maxValue === 'number') {
|
|
465
|
-
midpoint = Math.min(autoData.maxValue, midpoint);
|
|
466
|
-
}
|
|
467
|
-
if (typeof autoData.value === 'number' && Math.abs(autoData.value - midpoint) < 0.01) {
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
this.platform.log.debug(`[${this.name}] SYNC AutoSetpoint, heating=${heating} cooling=${cooling} → auto=${midpoint}`);
|
|
471
|
-
await this.accessory.context.device.setData(this.managementPointId, 'temperatureControl', autoPath, midpoint);
|
|
472
|
-
}
|
|
473
|
-
catch (e) {
|
|
474
|
-
this.platform.log.debug(`[${this.name}] AutoSetpoint sync skipped: ${e instanceof Error ? e.message : e}`);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
284
|
async handleTargetHeaterCoolerStateGet() {
|
|
478
285
|
const operationMode = this.getCurrentOperationMode();
|
|
479
|
-
|
|
480
|
-
this.
|
|
286
|
+
this.platform.log.debug(`[${this.name}] GET TargetHeaterCoolerState, operationMode: ${operationMode}, last update: ${this.device.getLastUpdated()}`);
|
|
287
|
+
return this.targetHeaterCoolerState(operationMode);
|
|
288
|
+
}
|
|
289
|
+
targetHeaterCoolerState(operationMode) {
|
|
290
|
+
const { TargetHeaterCoolerState } = this.platform.Characteristic;
|
|
481
291
|
switch (operationMode) {
|
|
482
292
|
case types_1.DaikinOperationModes.COOLING:
|
|
483
|
-
return
|
|
293
|
+
return TargetHeaterCoolerState.COOL;
|
|
484
294
|
case types_1.DaikinOperationModes.HEATING:
|
|
485
|
-
return
|
|
486
|
-
case types_1.DaikinOperationModes.DRY:
|
|
487
|
-
this.addOrUpdateCharacteristicRotationSpeed();
|
|
488
|
-
return this.platform.Characteristic.TargetHeaterCoolerState.AUTO;
|
|
295
|
+
return TargetHeaterCoolerState.HEAT;
|
|
489
296
|
default:
|
|
490
|
-
return
|
|
297
|
+
return TargetHeaterCoolerState.AUTO;
|
|
491
298
|
}
|
|
492
299
|
}
|
|
493
300
|
async handleTargetHeaterCoolerStateSet(value) {
|
|
494
|
-
const
|
|
301
|
+
const { TargetHeaterCoolerState } = this.platform.Characteristic;
|
|
495
302
|
this.platform.log.debug(`[${this.name}] SET TargetHeaterCoolerState, OperationMode to: ${value}`);
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
case this.platform.Characteristic.TargetHeaterCoolerState.AUTO:
|
|
505
|
-
daikinOperationMode = types_1.DaikinOperationModes.AUTO;
|
|
506
|
-
break;
|
|
303
|
+
const daikinOperationMode = value === TargetHeaterCoolerState.HEAT ? types_1.DaikinOperationModes.HEATING
|
|
304
|
+
: value === TargetHeaterCoolerState.AUTO ? types_1.DaikinOperationModes.AUTO
|
|
305
|
+
: types_1.DaikinOperationModes.COOLING;
|
|
306
|
+
// Compared against the Daikin mode, not the HomeKit state: AUTO while the
|
|
307
|
+
// unit is in dry/fanOnly (which read back as AUTO) must still switch to auto.
|
|
308
|
+
if (this.getCurrentOperationMode() === daikinOperationMode) {
|
|
309
|
+
this.platform.log.debug(`[${this.name}] SET TargetHeaterCoolerState skipped — already ${daikinOperationMode}`);
|
|
310
|
+
return;
|
|
507
311
|
}
|
|
508
312
|
this.platform.log.debug(`[${this.name}] SET TargetHeaterCoolerState, daikinOperationMode to: ${daikinOperationMode}`);
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
// (e.g. a "turn off" scene) and can leave devices ON.
|
|
515
|
-
});
|
|
313
|
+
// Note: onOffMode is intentionally NOT set here — the Active characteristic
|
|
314
|
+
// exclusively controls on/off. iOS always sends Active=1 alongside a mode
|
|
315
|
+
// change, so forcing onOffMode=ON here races against a concurrent Active=0
|
|
316
|
+
// (e.g. a "turn off" scene) and can leave devices ON.
|
|
317
|
+
await this.write('TargetHeaterCoolerState', () => this.setData('operationMode', daikinOperationMode, undefined));
|
|
516
318
|
}
|
|
517
319
|
async handleSwingModeSet(value) {
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
if (this.hasSwingModeVerticalFeature()) {
|
|
526
|
-
await this.accessory.context.device.setData(this.managementPointId, 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanDirection/vertical/currentMode`, daikinSwingMode);
|
|
527
|
-
}
|
|
528
|
-
});
|
|
320
|
+
const enabled = value === this.platform.Characteristic.SwingMode.SWING_ENABLED;
|
|
321
|
+
if (this.swing.axesToWrite(enabled).length === 0) {
|
|
322
|
+
this.platform.log.debug(`[${this.name}] SET SwingMode skipped — already ${enabled ? 'swinging' : 'stopped'}`);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
this.platform.log.debug(`[${this.name}] SET SwingMode, swingmode to: ${value}`);
|
|
326
|
+
await this.write('SwingMode', () => this.swing.set(enabled));
|
|
529
327
|
}
|
|
530
328
|
async handleSwingModeGet() {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
this.platform.log.debug(`[${this.name}] GET SwingMode, horizontalSwingMode: ${horizontalSwingMode}, last update: ${lastUpdate}`);
|
|
536
|
-
if (horizontalSwingMode === types_1.DaikinFanDirectionHorizontalModes.STOP || verticalSwingMode === types_1.DaikinFanDirectionVerticalModes.STOP) {
|
|
537
|
-
return this.platform.Characteristic.SwingMode.SWING_DISABLED;
|
|
538
|
-
}
|
|
539
|
-
return this.platform.Characteristic.SwingMode.SWING_ENABLED;
|
|
329
|
+
this.platform.log.debug(`[${this.name}] GET SwingMode, ${this.swing.describe()}, last update: ${this.device.getLastUpdated()}`);
|
|
330
|
+
return this.swing.isSwinging()
|
|
331
|
+
? this.platform.Characteristic.SwingMode.SWING_ENABLED
|
|
332
|
+
: this.platform.Characteristic.SwingMode.SWING_DISABLED;
|
|
540
333
|
}
|
|
541
334
|
getCurrentOperationMode() {
|
|
542
|
-
return this.
|
|
335
|
+
return this.getData('operationMode').value;
|
|
543
336
|
}
|
|
544
337
|
getCurrentControlMode() {
|
|
545
|
-
|
|
546
|
-
// Only Altherma devices have a controlMode, others have a fixed controlMode of ROOM_TEMPERATURE AFAIK
|
|
547
|
-
if (!controlMode.value) {
|
|
548
|
-
return types_1.DaikinControlModes.ROOM_TEMPERATURE;
|
|
549
|
-
}
|
|
550
|
-
return controlMode.value;
|
|
551
|
-
}
|
|
552
|
-
getSetpointMode() {
|
|
553
|
-
const setpointMode = this.accessory.context.device.getData(this.managementPointId, 'setpointMode', undefined);
|
|
554
|
-
if (!setpointMode.value) {
|
|
555
|
-
return null;
|
|
556
|
-
}
|
|
557
|
-
return setpointMode.value;
|
|
558
|
-
}
|
|
559
|
-
getSetpoint(operationMode) {
|
|
560
|
-
// depending on the settings of the device the temperatureControl can be set in different ways "DaikinTemperatureControlSetpoints"
|
|
561
|
-
// Docs: https://developer.cloud.daikineurope.com/docs/b0dffcaa-7b51-428a-bdff-a7c8a64195c0/supported_features
|
|
562
|
-
// Looks like the setpointMode is the most important one to determine the setpoint,
|
|
563
|
-
// then the controleMode and in case of weatherDependentHeatingFixedCooling also the operation mode
|
|
564
|
-
// If the setpointMode is not available (in case on non-Althermas), we can use the controlMode to determine the setpoint
|
|
565
|
-
const setpointMode = this.getSetpointMode();
|
|
566
|
-
const controlMode = this.getCurrentControlMode();
|
|
567
|
-
if (setpointMode) {
|
|
568
|
-
switch (setpointMode) {
|
|
569
|
-
case types_1.DaikinSetpointModes.FIXED:
|
|
570
|
-
switch (controlMode) {
|
|
571
|
-
case types_1.DaikinControlModes.LEAVING_WATER_TEMPERATURE:
|
|
572
|
-
return types_1.DaikinTemperatureControlSetpoints.LEAVING_WATER_TEMPERATURE;
|
|
573
|
-
default:
|
|
574
|
-
return types_1.DaikinTemperatureControlSetpoints.ROOM_TEMPERATURE;
|
|
575
|
-
}
|
|
576
|
-
case types_1.DaikinSetpointModes.WEATHER_DEPENDENT:
|
|
577
|
-
switch (controlMode) {
|
|
578
|
-
case types_1.DaikinControlModes.LEAVING_WATER_TEMPERATURE:
|
|
579
|
-
return types_1.DaikinTemperatureControlSetpoints.LEAVING_WATER_OFFSET;
|
|
580
|
-
default:
|
|
581
|
-
return types_1.DaikinTemperatureControlSetpoints.ROOM_TEMPERATURE;
|
|
582
|
-
}
|
|
583
|
-
case types_1.DaikinSetpointModes.WEATHER_DEPENDENT_HEATING_FIXED_COOLING:
|
|
584
|
-
switch (controlMode) {
|
|
585
|
-
case types_1.DaikinControlModes.ROOM_TEMPERATURE:
|
|
586
|
-
return types_1.DaikinTemperatureControlSetpoints.ROOM_TEMPERATURE;
|
|
587
|
-
case types_1.DaikinControlModes.LEAVING_WATER_TEMPERATURE:
|
|
588
|
-
switch (operationMode) {
|
|
589
|
-
case types_1.DaikinOperationModes.HEATING:
|
|
590
|
-
return types_1.DaikinTemperatureControlSetpoints.LEAVING_WATER_OFFSET;
|
|
591
|
-
case types_1.DaikinOperationModes.COOLING:
|
|
592
|
-
return types_1.DaikinTemperatureControlSetpoints.LEAVING_WATER_TEMPERATURE;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
throw new Error(`Could not determine the TemperatureControlSetpoint for operationMode: ${operationMode}, `
|
|
597
|
-
+ `setpointMode: ${setpointMode}, controlMode: ${controlMode}, deviceId: ${this.accessory.UUID}`);
|
|
598
|
-
}
|
|
599
|
-
switch (controlMode) {
|
|
600
|
-
case types_1.DaikinControlModes.LEAVING_WATER_TEMPERATURE:
|
|
601
|
-
return types_1.DaikinTemperatureControlSetpoints.LEAVING_WATER_OFFSET;
|
|
602
|
-
default:
|
|
603
|
-
return types_1.DaikinTemperatureControlSetpoints.ROOM_TEMPERATURE;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
hasSwingModeVerticalFeature() {
|
|
607
|
-
// getData() returns { value: undefined } when the path is missing — checking the
|
|
608
|
-
// wrapper for truthiness always succeeds. We need to confirm the value itself is set.
|
|
609
|
-
const verticalSwing = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanDirection/vertical/currentMode`);
|
|
610
|
-
return verticalSwing.value !== undefined;
|
|
611
|
-
}
|
|
612
|
-
hasSwingModeHorizontalFeature() {
|
|
613
|
-
const horizontalSwing = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanDirection/horizontal/currentMode`);
|
|
614
|
-
return horizontalSwing.value !== undefined;
|
|
615
|
-
}
|
|
616
|
-
hasSwingModeFeature() {
|
|
617
|
-
return this.hasSwingModeVerticalFeature() || this.hasSwingModeHorizontalFeature();
|
|
618
|
-
}
|
|
619
|
-
hasPowerfulModeFeature() {
|
|
620
|
-
const powerfulMode = this.accessory.context.device.getData(this.managementPointId, 'powerfulMode', undefined);
|
|
621
|
-
this.platform.log.debug(`[${this.name}] hasPowerfulModeFeature, powerfulMode: ${Boolean(powerfulMode)}`);
|
|
622
|
-
return Boolean(powerfulMode);
|
|
623
|
-
}
|
|
624
|
-
hasEconoModeFeature() {
|
|
625
|
-
const econoMode = this.accessory.context.device.getData(this.managementPointId, 'econoMode', undefined);
|
|
626
|
-
this.platform.log.debug(`[${this.name}] hasEconoModeFeature, econoMode: ${Boolean(econoMode)}`);
|
|
627
|
-
return Boolean(econoMode);
|
|
628
|
-
}
|
|
629
|
-
hasStreamerModeFeature() {
|
|
630
|
-
const streamerMode = this.accessory.context.device.getData(this.managementPointId, 'streamerMode', undefined);
|
|
631
|
-
this.platform.log.debug(`[${this.name}] hasStreamerModeFeature, streamerMode: ${Boolean(streamerMode)}`);
|
|
632
|
-
return Boolean(streamerMode);
|
|
633
|
-
}
|
|
634
|
-
hasOutdoorSilentModeFeature() {
|
|
635
|
-
const OutdoorSilentMode = this.accessory.context.device.getData(this.managementPointId, 'outdoorSilentMode', undefined);
|
|
636
|
-
this.platform.log.debug(`[${this.name}] hasOutdoorSilentModeFeature, outdoorSilentMode: ${Boolean(OutdoorSilentMode)}`);
|
|
637
|
-
return Boolean(OutdoorSilentMode);
|
|
638
|
-
}
|
|
639
|
-
hasIndoorSilentModeFeature() {
|
|
640
|
-
const currentModeFanControl = this.accessory.context.device.getData(this.managementPointId, 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanSpeed/currentMode`);
|
|
641
|
-
if (!currentModeFanControl) {
|
|
642
|
-
return false;
|
|
643
|
-
}
|
|
644
|
-
const fanSpeedValues = currentModeFanControl.values || [];
|
|
645
|
-
this.platform.log.debug(`[${this.name}] hasIndoorSilentModeFeature, indoorSilentMode: ${fanSpeedValues.includes(types_1.DaikinFanSpeedModes.QUIET)}`);
|
|
646
|
-
return fanSpeedValues.includes(types_1.DaikinFanSpeedModes.QUIET);
|
|
647
|
-
}
|
|
648
|
-
hasOperationMode(operationMode) {
|
|
649
|
-
const operationModeValues = this.accessory.context.device.getData(this.managementPointId, 'operationMode', undefined).values || [];
|
|
650
|
-
this.platform.log.debug(`[${this.name}] has ${operationMode}: ${operationModeValues.includes(operationMode)}`);
|
|
651
|
-
return operationModeValues.includes(operationMode);
|
|
652
|
-
}
|
|
653
|
-
hasDryOperationModeFeature() {
|
|
654
|
-
return this.hasOperationMode(types_1.DaikinOperationModes.DRY);
|
|
655
|
-
}
|
|
656
|
-
hasFanOnlyOperationModeFeature() {
|
|
657
|
-
return this.hasOperationMode(types_1.DaikinOperationModes.FAN_ONLY);
|
|
338
|
+
return this.setpoints.getControlMode();
|
|
658
339
|
}
|
|
659
340
|
}
|
|
660
341
|
exports.ClimateControlService = ClimateControlService;
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
// same math and the same fallback for missing maxValue.
|
|
664
|
-
const DEFAULT_FAN_MAX = 5;
|
|
665
|
-
function percentStep(maxValue) {
|
|
666
|
-
return 100 / (maxValue && maxValue > 0 ? maxValue : DEFAULT_FAN_MAX);
|
|
667
|
-
}
|
|
668
|
-
function deviceSpeedToPercent(speed, maxValue) {
|
|
669
|
-
const max = maxValue && maxValue > 0 ? maxValue : DEFAULT_FAN_MAX;
|
|
670
|
-
const percent = Math.round((speed / max) * 100);
|
|
671
|
-
return Math.max(0, Math.min(100, percent));
|
|
342
|
+
function thresholdMode(kind) {
|
|
343
|
+
return kind === 'cooling' ? types_1.DaikinOperationModes.COOLING : types_1.DaikinOperationModes.HEATING;
|
|
672
344
|
}
|
|
673
|
-
function
|
|
674
|
-
|
|
675
|
-
const max = maxValue && maxValue > 0 ? maxValue : DEFAULT_FAN_MAX;
|
|
676
|
-
const raw = Math.round((percent / 100) * max);
|
|
677
|
-
return Math.max(min, Math.min(max, raw));
|
|
345
|
+
function finiteOr(value, fallback) {
|
|
346
|
+
return typeof value === 'number' && isFinite(value) ? value : fallback;
|
|
678
347
|
}
|
|
679
348
|
//# sourceMappingURL=climate-control.service.js.map
|