JeroenVdb / homebridge-daikin-cloud

This Homebrige plugin connects to the Daikin Cloud and loads all your devices to be controled via Homebridge and Homekit.
https://www.npmjs.com/package/homebridge-daikin-cloud
Apache License 2.0
40 stars 11 forks source link

Plugin breaks when dealing with a Perfera unit in dry mode #66

Closed jacoscaz closed 4 months ago

jacoscaz commented 4 months ago

Describe The Bug: The plugin breaks with the following error when interrogating a Daikin Perfera unit in dry mode:

TypeError: Cannot read properties of null (reading 'minStep')
    at new daikinAirConditioningAccessory (/homebridge/node_modules/homebridge-daikin-cloud/src/daikinAirConditioningAccessory.ts:73:164)
    at /homebridge/node_modules/homebridge-daikin-cloud/src/platform.ts:131:25
    at Array.forEach (<anonymous>)
    at DaikinCloudPlatform.discoverDevices (/homebridge/node_modules/homebridge-daikin-cloud/src/platform.ts:95:17)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at HomebridgeAPI.<anonymous> (/homebridge/node_modules/homebridge-daikin-cloud/src/platform.ts:70:13)

To Reproduce:

  1. Get a Daikin Perfera unit
  2. Set it to dry mode using the remote
  3. Start homebridge with this plugin

Expected behavior: The plugin should start correctly without breaking, even though dry mode is not natively supported by HomeKit and therefore can't be supported by this plugin as the more "normal" modes auto, heating and cooling.

Logs:

[7/5/2024, 6:04:31 PM] [DaikinCloud] Adding new accessory: Study (Downstairs)
[7/5/2024, 6:04:31 PM] [DaikinCloud] Device found with id: 0ad5a1ab-0dd4-47ed-9fdf-3c6fc22262cf
[7/5/2024, 6:04:31 PM] [DaikinCloud]     id: 0ad5a1ab-0dd4-47ed-9fdf-3c6fc22262cf
[7/5/2024, 6:04:31 PM] [DaikinCloud]     name: Study (Downstairs)
[7/5/2024, 6:04:31 PM] [DaikinCloud]     last updated: Fri Jul 05 2024 18:04:31 GMT+0200 (Central European Summer Time)
[7/5/2024, 6:04:31 PM] [DaikinCloud]     modelInfo: BRP069C4x
[7/5/2024, 6:04:31 PM] [DaikinCloud]     deviceModel: dx4
[7/5/2024, 6:04:31 PM] [DaikinCloud]     config.showExtraFeatures: true
[7/5/2024, 6:04:31 PM] [DaikinCloud]     config.excludedDevicesByDeviceId: true
[Study (Downstairs)@@Cooling Threshold Temperature] characteristic was supplied illegal value: number 10 exceeded minimum of 18
[Study (Downstairs)@@Heating Threshold Temperature] characteristic was supplied illegal value: number 0 exceeded minimum of 10
TypeError: Cannot read properties of null (reading 'minStep')
    at new daikinAirConditioningAccessory (/homebridge/node_modules/homebridge-daikin-cloud/src/daikinAirConditioningAccessory.ts:73:164)
    at /homebridge/node_modules/homebridge-daikin-cloud/src/platform.ts:131:25
    at Array.forEach (<anonymous>)
    at DaikinCloudPlatform.discoverDevices (/homebridge/node_modules/homebridge-daikin-cloud/src/platform.ts:95:17)
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at HomebridgeAPI.<anonymous> (/homebridge/node_modules/homebridge-daikin-cloud/src/platform.ts:70:13)
[7/5/2024, 6:04:31 PM] [DaikinCloud] Failed to create HeaterCooler accessory from device, only HeaterCooler is supported at the moment: Cannot read properties of null (reading 'minStep'), device JSON: {"_events":{},"_eventsCount":1,"desc":{"_id":"f66cc777-6aa6-4aa0-9a8b-45c35d20f38d","id":"f66cc777-6aa6-4aa0-9a8b-45c35d20f38d","deviceModel":"dx4","isCloudConnectionUp":{"settable":false,"value":true},"managementPoints":[{"embeddedId":"gateway","managementPointType":"gateway","managementPointCategory":"secondary","errorCode":{"settable":false,"value":""},"firmwareVersion":{"settable":false,"value":"1_31_0"},"isFirmwareUpdateSupported":{"settable":false,"value":true},"isInErrorState":{"settable":false,"value":false},"ipAddress":{"settable":false,"value":"192.168.1.91"},"macAddress":{"settable":false,"value":"fc:84:a7:66:88:38"},"modelInfo":{"settable":false,"value":"BRP069C4x"}},{"embeddedId":"climateControl","managementPointType":"climateControl","managementPointSubType":"mainZone","managementPointCategory":"primary","consumptionData":{"ref":"#consumptionData","settable":false,"value":{"electrical":{"unit":"kWh","heating":{"d":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"w":[0,0,0,0,0,0,0,0,0,0,0,0,null,null],"m":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"cooling":{"d":[0,0,0,0.1,0,0,0,0,0,0,0,0,0,0.1,0,0,0,0,0,0,0,0,0,0],"w":[0,0,0.2,0.1,0.1,0.1,0.2,0.1,0.1,0.1,0.1,0.1,null,null],"m":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.7,0.5,0,0,0,0,0]}}}},"errorCode":{"settable":false,"value":"00-00"},"fanControl":{"ref":"#fanControl","settable":true,"value":{"operationModes":{"heating":{"fanSpeed":{"currentMode":{"value":"auto","settable":true,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"value":1,"stepValue":1,"minValue":1,"maxValue":5,"settable":true}}},"fanDirection":{"horizontal":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing"]}},"vertical":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing","windNice"]}}}},"cooling":{"fanSpeed":{"currentMode":{"value":"auto","settable":true,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"value":1,"stepValue":1,"minValue":1,"maxValue":5,"settable":true}}},"fanDirection":{"horizontal":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing"]}},"vertical":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing","windNice"]}}}},"auto":{"fanSpeed":{"currentMode":{"value":"auto","settable":true,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"value":1,"stepValue":1,"minValue":1,"maxValue":5,"settable":true}}},"fanDirection":{"horizontal":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing"]}},"vertical":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing","windNice"]}}}},"dry":{"fanSpeed":{"currentMode":{"value":"auto","settable":true,"values":["auto"]}},"fanDirection":{"horizontal":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing"]}},"vertical":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing","windNice"]}}}},"fanOnly":{"fanSpeed":{"currentMode":{"value":"auto","settable":true,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"value":1,"stepValue":1,"minValue":1,"maxValue":5,"settable":true}}},"fanDirection":{"horizontal":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing"]}},"vertical":{"currentMode":{"value":"stop","settable":true,"values":["stop","swing"]}}}}}}},"holidayMode":{"ref":"#holidayMode","settable":true,"value":{"enabled":false}},"isHolidayModeActive":{"settable":false,"value":false},"isInCautionState":{"settable":false,"value":false},"isInErrorState":{"settable":false,"value":false},"isInWarningState":{"settable":false,"value":false},"name":{"settable":false,"maxLength":20,"value":"Study (Downstairs)"},"onOffMode":{"settable":true,"values":["on","off"],"value":"off"},"operationMode":{"settable":true,"value":"dry","values":["fanOnly","heating","cooling","auto","dry"]},"powerfulMode":{"settable":true,"values":["on","off"],"value":"off"},"isPowerfulModeActive":{"settable":false,"value":false},"schedule":{"ref":"#schedule","settable":true,"value":{"currentMode":{"value":"any","settable":true,"values":["any"]},"nextAction":{},"modes":{"any":{"currentSchedule":{"value":"0","settable":true,"values":["0"]},"enabled":{"value":false,"settable":true},"meta":{"minIntervalBetweenActions":"00:01:00","maxSchedules":1,"maxActionsPerActionPeriod":6,"consecutiveActionsAllowed":true,"actionTypes":{"operationMode":{"settable":false,"values":["fanOnly","heating","cooling","auto","dry","off"]},"roomTemperature":{"heating":{"settable":false,"stepValue":0.5,"minValue":10,"maxValue":30},"cooling":{"settable":false,"stepValue":0.5,"minValue":18,"maxValue":32},"auto":{"settable":false,"stepValue":0.5,"minValue":18,"maxValue":30}},"fanSpeed":{"heating":{"currentMode":{"settable":false,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"stepValue":1,"minValue":1,"maxValue":5,"settable":false}}},"cooling":{"currentMode":{"settable":false,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"stepValue":1,"minValue":1,"maxValue":5,"settable":false}}},"auto":{"currentMode":{"settable":false,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"stepValue":1,"minValue":1,"maxValue":5,"settable":false}}},"dry":{"currentMode":{"settable":false,"values":["auto"]}},"fanOnly":{"currentMode":{"settable":false,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"stepValue":1,"minValue":1,"maxValue":5,"settable":false}}}},"econoMode":{"settable":false,"values":["on","off"]}}},"schedules":{"0":{"name":{"maxLength":32,"settable":false,"value":""},"meta":{"actionPeriods":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],"isReadOnly":false},"actions":{},"settable":false}}}}}},"sensoryData":{"ref":"#sensoryData","settable":false,"value":{"roomTemperature":{"settable":false,"unit":"°C","value":27,"stepValue":1,"minValue":-25,"maxValue":48},"outdoorTemperature":{"settable":false,"unit":"°C","value":28,"stepValue":0.5,"minValue":-25,"maxValue":50}}},"temperatureControl":{"ref":"#temperatureControl","settable":true,"value":{"operationModes":{"heating":{"setpoints":{"roomTemperature":{"settable":true,"value":25,"unit":"°C","stepValue":0.5,"minValue":10,"maxValue":30}}},"cooling":{"setpoints":{"roomTemperature":{"settable":true,"value":25,"unit":"°C","stepValue":0.5,"minValue":18,"maxValue":32}}},"auto":{"setpoints":{"roomTemperature":{"settable":true,"value":25,"unit":"°C","stepValue":0.5,"minValue":18,"maxValue":30}}}}}}},{"embeddedId":"indoorUnit","managementPointType":"indoorUnit","managementPointCategory":"secondary","modelInfo":{"settable":false,"value":"FTXM20A2V1B"},"softwareVersion":{"settable":false,"value":"2201B701"}},{"embeddedId":"outdoorUnit","managementPointType":"outdoorUnit","managementPointCategory":"secondary","modelInfo":{"settable":false,"value":"5MXM90A2V1B9"},"errorCode":{"settable":false,"value":"00-00"},"isInErrorState":{"settable":false,"value":false},"isInWarningState":{"settable":false,"value":false},"isInCautionState":{"settable":false,"value":false},"softwareVersion":{"settable":false,"value":"2200AF11"}}],"type":"dx4","embeddedId":"1762979","timestamp":"2024-07-05T16:04:31.342Z"},"managementPoints":{"gateway":{"errorCode":{"settable":false,"value":""},"firmwareVersion":{"settable":false,"value":"1_31_0"},"isFirmwareUpdateSupported":{"settable":false,"value":true},"isInErrorState":{"settable":false,"value":false},"ipAddress":{"settable":false,"value":"192.168.1.91"},"macAddress":{"settable":false,"value":"fc:84:a7:66:88:38"},"modelInfo":{"settable":false,"value":"BRP069C4x"}},"climateControl":{"consumptionData":{"/electrical":{"unit":"kWh","heating":{"d":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"w":[0,0,0,0,0,0,0,0,0,0,0,0,null,null],"m":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"cooling":{"d":[0,0,0,0.1,0,0,0,0,0,0,0,0,0,0.1,0,0,0,0,0,0,0,0,0,0],"w":[0,0,0.2,0.1,0.1,0.1,0.2,0.1,0.1,0.1,0.1,0.1,null,null],"m":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.7,0.5,0,0,0,0,0]}}},"errorCode":{"settable":false,"value":"00-00"},"fanControl":{"/operationModes/heating/fanSpeed/currentMode":{"value":"auto","settable":true,"values":["auto","quiet","fixed"]},"/operationModes/heating/fanSpeed/modes/fixed":{"value":1,"stepValue":1,"minValue":1,"maxValue":5,"settable":true},"/operationModes/heating/fanDirection/horizontal/currentMode":{"value":"stop","settable":true,"values":["stop","swing"]},"/operationModes/heating/fanDirection/vertical/currentMode":{"value":"stop","settable":true,"values":["stop","swing","windNice"]},"/operationModes/cooling/fanSpeed/currentMode":{"value":"auto","settable":true,"values":["auto","quiet","fixed"]},"/operationModes/cooling/fanSpeed/modes/fixed":{"value":1,"stepValue":1,"minValue":1,"maxValue":5,"settable":true},"/operationModes/cooling/fanDirection/horizontal/currentMode":{"value":"stop","settable":true,"values":["stop","swing"]},"/operationModes/cooling/fanDirection/vertical/currentMode":{"value":"stop","settable":true,"values":["stop","swing","windNice"]},"/operationModes/auto/fanSpeed/currentMode":{"value":"auto","settable":true,"values":["auto","quiet","fixed"]},"/operationModes/auto/fanSpeed/modes/fixed":{"value":1,"stepValue":1,"minValue":1,"maxValue":5,"settable":true},"/operationModes/auto/fanDirection/horizontal/currentMode":{"value":"stop","settable":true,"values":["stop","swing"]},"/operationModes/auto/fanDirection/vertical/currentMode":{"value":"stop","settable":true,"values":["stop","swing","windNice"]},"/operationModes/dry/fanSpeed/currentMode":{"value":"auto","settable":true,"values":["auto"]},"/operationModes/dry/fanDirection/horizontal/currentMode":{"value":"stop","settable":true,"values":["stop","swing"]},"/operationModes/dry/fanDirection/vertical/currentMode":{"value":"stop","settable":true,"values":["stop","swing","windNice"]},"/operationModes/fanOnly/fanSpeed/currentMode":{"value":"auto","settable":true,"values":["auto","quiet","fixed"]},"/operationModes/fanOnly/fanSpeed/modes/fixed":{"value":1,"stepValue":1,"minValue":1,"maxValue":5,"settable":true},"/operationModes/fanOnly/fanDirection/horizontal/currentMode":{"value":"stop","settable":true,"values":["stop","swing"]},"/operationModes/fanOnly/fanDirection/vertical/currentMode":{"value":"stop","settable":true,"values":["stop","swing"]}},"holidayMode":{"ref":"#holidayMode","settable":true,"value":{"enabled":false}},"isHolidayModeActive":{"settable":false,"value":false},"isInCautionState":{"settable":false,"value":false},"isInErrorState":{"settable":false,"value":false},"isInWarningState":{"settable":false,"value":false},"name":{"settable":false,"maxLength":20,"value":"Study (Downstairs)"},"onOffMode":{"settable":true,"values":["on","off"],"value":"off"},"operationMode":{"settable":true,"value":"dry","values":["fanOnly","heating","cooling","auto","dry"]},"powerfulMode":{"settable":true,"values":["on","off"],"value":"off"},"isPowerfulModeActive":{"settable":false,"value":false},"schedule":{"/currentMode":{"value":"any","settable":true,"values":["any"]},"/modes/any/currentSchedule":{"value":"0","settable":true,"values":["0"]},"/modes/any/enabled":{"value":false,"settable":true},"/modes/any/meta":{"minIntervalBetweenActions":"00:01:00","maxSchedules":1,"maxActionsPerActionPeriod":6,"consecutiveActionsAllowed":true,"actionTypes":{"operationMode":{"settable":false,"values":["fanOnly","heating","cooling","auto","dry","off"]},"roomTemperature":{"heating":{"settable":false,"stepValue":0.5,"minValue":10,"maxValue":30},"cooling":{"settable":false,"stepValue":0.5,"minValue":18,"maxValue":32},"auto":{"settable":false,"stepValue":0.5,"minValue":18,"maxValue":30}},"fanSpeed":{"heating":{"currentMode":{"settable":false,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"stepValue":1,"minValue":1,"maxValue":5,"settable":false}}},"cooling":{"currentMode":{"settable":false,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"stepValue":1,"minValue":1,"maxValue":5,"settable":false}}},"auto":{"currentMode":{"settable":false,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"stepValue":1,"minValue":1,"maxValue":5,"settable":false}}},"dry":{"currentMode":{"settable":false,"values":["auto"]}},"fanOnly":{"currentMode":{"settable":false,"values":["auto","quiet","fixed"]},"modes":{"fixed":{"stepValue":1,"minValue":1,"maxValue":5,"settable":false}}}},"econoMode":{"settable":false,"values":["on","off"]}}},"/modes/any/schedules/0":{"name":{"maxLength":32,"settable":false,"value":""},"meta":{"actionPeriods":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],"isReadOnly":false},"actions":{},"settable":false}},"sensoryData":{"/roomTemperature":{"settable":false,"unit":"°C","value":27,"stepValue":1,"minValue":-25,"maxValue":48},"/outdoorTemperature":{"settable":false,"unit":"°C","value":28,"stepValue":0.5,"minValue":-25,"maxValue":50}},"temperatureControl":{"/operationModes/heating/setpoints/roomTemperature":{"settable":true,"value":25,"unit":"°C","stepValue":0.5,"minValue":10,"maxValue":30},"/operationModes/cooling/setpoints/roomTemperature":{"settable":true,"value":25,"unit":"°C","stepValue":0.5,"minValue":18,"maxValue":32},"/operationModes/auto/setpoints/roomTemperature":{"settable":true,"value":25,"unit":"°C","stepValue":0.5,"minValue":18,"maxValue":30}}},"indoorUnit":{"modelInfo":{"settable":false,"value":"FTXM20A2V1B"},"softwareVersion":{"settable":false,"value":"2201B701"}},"outdoorUnit":{"modelInfo":{"settable":false,"value":"5MXM90A2V1B9"},"errorCode":{"settable":false,"value":"00-00"},"isInErrorState":{"settable":false,"value":false},"isInWarningState":{"settable":false,"value":false},"isInCautionState":{"settable":false,"value":false},"softwareVersion":{"settable":false,"value":"2200AF11"}}}}
[7/5/2024, 6:04:31 PM] [DaikinCloud] --------------- End Daikin info for debugging reasons --------------------

Plugin Config:

{
    "clientId": "REMOVED",
    "clientSecret": "REMOVED",
    "callbackServerExternalAddress": "192.168.1.38",
    "callbackServerPort": "8582",
    "oidcCallbackServerBindAddr": "0.0.0.0",
    "showExtraFeatures": true,
    "updateIntervalInMinutes": 15,
    "platform": "DaikinCloud"
}

Daikin Environment:

Homebridge Environment:

Additional Info:

The problem seems to be that the object at climateControl/fanDirection/operationModes/dry differs from its equivalent within one of the supported modes (auto, heating or cooling) in that it is missing the fanSpeed.modes.fixed path.

This is for dry mode:

                "fanSpeed": {
                  "currentMode": {
                    "value": "auto",
                    "settable": true,
                    "values": [
                      "auto"
                    ]
                  }
                },

This is for auto mode:

                 "fanSpeed": {
                  "currentMode": {
                    "value": "auto",
                    "settable": true,
                    "values": [
                      "auto",
                      "quiet",
                      "fixed"
                    ]
                  },
                  "modes": {
                    "fixed": {
                      "value": 1,
                      "stepValue": 1,
                      "minValue": 1,
                      "maxValue": 5,
                      "settable": true
                    }
                  }
                },

This breaks the following lines: https://github.com/JeroenVdb/homebridge-daikin-cloud/blob/e3c321c267b12f964f0003bb498a465e84e9cc94/src/daikinAirConditioningAccessory.ts#L73-L75

because

accessory.context.device.getData('climateControl', 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanSpeed/modes/fixed`)

returns null due to the non-existent path.

A quick'n'dirty workaround for this which I've already verified locally is to change that entire block as follows:

if (accessory.context.device.getData('climateControl', 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanSpeed/modes/fixed`)) {
        this.service.getCharacteristic(this.platform.Characteristic.RotationSpeed)
            .setProps({
                minStep: accessory.context.device.getData('climateControl', 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanSpeed/modes/fixed`).minStep,
                minValue: accessory.context.device.getData('climateControl', 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanSpeed/modes/fixed`).minValue,
                maxValue: accessory.context.device.getData('climateControl', 'fanControl', `/operationModes/${this.getCurrentOperationMode()}/fanSpeed/modes/fixed`).maxValue,
            })
            .onGet(this.handleRotationSpeedGet.bind(this))
            .onSet(this.handleRotationSpeedSet.bind(this));
}

If this is the way to go I can open a PR accordingly, though I suspect there might be better ways to sort this out.

JeroenVdb commented 4 months ago

@jacoscaz can you check and validate homebridge-daikin-cloud@2.4.0-beta0?

jacoscaz commented 4 months ago

@JeroenVdb I can't test exhaustively right now but I did install 2.4.0-beta0 and the plugin now starts normally without crashing and appears to work normally. Thank you so much!

JeroenVdb commented 4 months ago

Ok, get back to me if it would not work.

jacoscaz commented 4 months ago

@JeroenVdb did a few more tests switching back and forth between cooling mode and dry mode, everything works as intended.

fdegier commented 4 months ago

@JeroenVdb could you publish the beta version to NPM for easier installation?