Apollon77 / daikin-controller-cloud

Connect and Control Daikin Cloud devices
MIT License
96 stars 26 forks source link

Schedule - how? #108

Open DIY-Blub opened 1 year ago

DIY-Blub commented 1 year ago

Hi, I'm using the Node-Red plugin from DrHauss (https://github.com/DrHauss/node-red-contrib_BRP069C4) and would like to be able to enable/disable the schedule. I have already created the schedule via the Daikin Onecta app, it's really just a matter of activating it.

To enable/disable schedule it should work to set the schedule/modes/any/enabled value to true/false: setData('climateControl', 'schedule', '/modes/any/enabled', true)

Obviously it works a little differently on schedule, can you tell me how?

Error output
Mar 29 10:28:12 raspberrypi Node-RED[29715]: <-- BODY {"value":false,"path":"/modes/any/enabled"} Mar 29 10:28:12 raspberrypi Node-RED[29715]: --> 422 FROM PATCH https://api.prod.unicloud.edc.dknadmin.be/v1/gateway-devices/XXXX/management-points/climateControl/characteristics/schedule Mar 29 10:28:12 raspberrypi Node-RED[29715]: --> HEADERS {

Mar 29 10:28:12 raspberrypi Node-RED[29715]: --> BODY {"code":"INVALID_REQUEST","message":"[schedule] characteristic has its own endpoint. PUT /gateway-devices/{gatewayDeviceId}/management-points/{embeddedId}/schedule. Refer to API manual for detailed information."} Mar 29 10:28:12 raspberrypi Node-RED[29715]: 29 Mar 10:28:12 - [error] [Daikin-Cloud-Controller:472df65b815d75d5] Error: Communication failed 422

Specs
controller: BRP069B4x (Local transmission does not work, only the cloud works.)

Apollon77 commented 1 year ago

The error message lets assume that there are special endpoints for schedule. These were not yet discovered and this would need to be done first - so someone need to snif the App HTTPS traffic to see what the app sends and which API to use. Then it can be added.

I would need access to such devices and time to do it

DIY-Blub commented 1 year ago

snif the App HTTPS traffic to see what the app sends and which API to use

Do you know of an app for Android? German Kennst du eine geeignete/einfache App für Android die den Onecta Traffic auslesen kann? Dann kann ich das gerne übernehmen :)

Apollon77 commented 1 year ago

I would not use an app. In the past best results were ddone by using CharlesProxy on a PC as proxy. The main magic for charles and android is on how to setup that root certificate correctly for all that to work correctly. In fact see https://www.charlesproxy.com/documentation/using-charles/ssl-certificates/ ... on ios it always works without any issues ... Android is a bit tricky sometimes :-(

But in fact do that, register and enable the root cert and proxy. Then open the app. if you see errors in Onecta app then something is wrong, if you only see "CONNECT" entries in charles then the ssl root cert is not effective, then something else is wrong in setting on phone.

If you see GET/POST calls in charles and when clicking on it you also see some "text content" and JSONs then the sniffing works. You can also try with a browser app or such.

Then stop/kill the Onecta app on phone, start a fresh session in charles, open zthe app, so all relevant actions by noting the time you did it and maybe make 30s breaks in between two actions and note down the times and action and pot. what else happened in the app. At the end save the charles file, send the file and the "when was what" infos in an email to iobroker@fischer-ka.de with reference to this github issue. Then I can have a look (might need some days because right now deep in other projects!)

Apollon77 commented 1 year ago

PS: Charles and android migth not be good described on the linked page, but should work comparable to https://github.com/Apollon77/ioBroker.tuya/blob/master/PROXY.md#android (when it comes to the certificate and proxy setup püart)

DIY-Blub commented 1 year ago

Thank you for the detailed explanation. I'm afraid I won't be able to do that, but I'll give it a try over the coming weekends. I could also try it with my company cell phone (Apple) if it's more possible. :-D

DrHauss commented 1 year ago

This is how ONECTA App enables the scheduler 0:

:method: PUT
:scheme: https
:path: /v1/gateway-devices/XXXX/management-points/climateControl/schedule/any/current
:authority: api.prod.unicloud.edc.dknadmin.be
accept: application/json
content-type: application/json
content-length: 33
accept-encoding: gzip, deflate, br
x-api-key: XXXXX
user-agent: Daikin/3.14.0.22147 CFNetwork/1406.0.4 Darwin/22.4.0
accept-language: de-DE,de;q=0.9
authorization: XXXXX

{"scheduleId":"0","enabled":true}

Normal value changing is using PATCH, this is using PUT with a JSON object

Apollon77 commented 1 year ago

Thank you, will try to find some time to check soon

Apollon77 commented 10 months ago

@DrHauss Please deliver a debug log by uncommenting https://github.com/Apollon77/daikin-controller-cloud/blob/main/example/example.js#L85 v... I need to see the structure of the device your used there

ppattard commented 9 months ago

Hello,

I've been hitting the same problem trying to update schedules with PATCH, until I found this thread... happy to see other people are trying as well :-)

The PUT example given above is probably just to enable the schedule #0, right ? What we'd need is the request to append/remove actions to the schedule. It's probably a PUT as well so one can hope the whole schedule is sent back each time...

I haven't tried the proxy setup and unfortunately don't have an iOS available. Perhaps will give a try too when time permits.

Thanks.

ppattard commented 9 months ago

I haven't tried the proxy setup and unfortunately don't have an iOS available. Perhaps will give a try too when time permits.

Unfortunately I either have Android >= N where it's no longer possible to use Charles (without controlling the app) or Android < N where Onecta seems incompatible. So no mean to test...

ppattard commented 9 months ago

So ... after fighting quite a lot with Android to make it accept my tampered APK, I finally managed to run the capture. So indeed, the schedule API works by simply replacing PATCH with PUT:

You need to pass back the whole schedules as a single resource and they get overwritten. So in my example the "1" and "2" sections are absolutely required even if empty else you get a 400. You can see ONECTA also passes the empty days, I haven't tried to omit those.

The initial value appears when you do the GET in the "climateControl" object under the "schedule" key (I attach a full example so you can see):

{"embeddedId": "climateControl", "managementPointType": "climateControl", "managementPointSubType": "mainZone", "managementPointCategory": "primary", "onOffMode": {"settable": true, "values": ["on", "off"], "value": "on"}, "name": {"settable": true, "maxLength": 32, "value": "S\u00e9jour"}, "iconId": {"settable": true, "value": 1}, "isHolidayModeActive": {"settable": false, "value": false}, "isInErrorState": {"settable": false, "value": false}, "isInModeConflict": {"settable": false, "value": false}, "errorCode": {"settable": false, "value": "00"}, "operationMode": {"settable": true, "values": ["auto", "dry", "cooling", "heating", "fanOnly"], "value": "cooling"}, "temperatureControl": {"ref": "#temperatureControl", "settable": true, "value": {"operationModes": {"auto": {"setpoints": {"roomTemperature": {"settable": true, "value": 25, "minValue": 18, "maxValue": 30, "stepValue": 0.5}}}, "cooling": {"setpoints": {"roomTemperature": {"settable": true, "value": 26, "minValue": 18, "maxValue": 32, "stepValue": 0.5}}}, "heating": {"setpoints": {"roomTemperature": {"settable": true, "value": 25, "minValue": 10, "maxValue": 30, "stepValue": 0.5}}}}}}, "sensoryData": {"ref": "#sensoryData", "settable": false, "value": {"roomTemperature": {"settable": false, "value": 25}, "outdoorTemperature": {"settable": false, "value": 25}}}, "fanControl": {"ref": "#fanControl", "settable": true, "value": {"operationModes": {"auto": {"fanDirection": {"horizontal": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}, "vertical": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}}, "fanSpeed": {"currentMode": {"settable": true, "value": "fixed", "values": ["quiet", "auto", "fixed"]}, "modes": {"fixed": {"value": 3, "settable": true, "maxValue": 5, "minValue": 1, "stepValue": 1}}}}, "dry": {"fanDirection": {"horizontal": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}, "vertical": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}}, "fanSpeed": {"currentMode": {"settable": true, "value": "auto", "values": ["auto"]}}}, "cooling": {"fanDirection": {"horizontal": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}, "vertical": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}}, "fanSpeed": {"currentMode": {"settable": true, "value": "auto", "values": ["quiet", "auto", "fixed"]}, "modes": {"fixed": {"value": 1, "settable": true, "maxValue": 5, "minValue": 1, "stepValue": 1}}}}, "heating": {"fanDirection": {"horizontal": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}, "vertical": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}}, "fanSpeed": {"currentMode": {"settable": true, "value": "fixed", "values": ["quiet", "auto", "fixed"]}, "modes": {"fixed": {"value": 3, "settable": true, "maxValue": 5, "minValue": 1, "stepValue": 1}}}}, "fanOnly": {"fanDirection": {"horizontal": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}, "vertical": {"currentMode": {"settable": true, "value": "stop", "values": ["stop", "swing"]}}}, "fanSpeed": {"currentMode": {"settable": true, "value": "fixed", "values": ["quiet", "auto", "fixed"]}, "modes": {"fixed": {"value": 3, "settable": true, "maxValue": 5, "minValue": 1, "stepValue": 1}}}}}}}, "schedule": {"ref": "#schedule", "settable": true, "value": {"currentMode": {"value": "any", "settable": true, "values": ["any"]}, "nextAction": {"operationMode": "heating", "roomTemperature": 20, "fanSpeed": {"currentMode": "fixed", "modes": {"fixed": 3}}, "startTime": "10:00:00", "actionPeriod": "monday"}, "modes": {"any": {"currentSchedule": {"value": "0", "settable": true, "values": ["0", "1", "2"]}, "enabled": {"value": true, "settable": true}, "meta": {"minIntervalBetweenActions": "00:01:00", "maxSchedules": 1, "maxActionsPerActionPeriod": 6, "consecutiveActionsAllowed": true, "actionTypes": {"operationMode": {"settable": false, "values": ["auto", "dry", "cooling", "heating", "fanOnly", "off"]}, "roomTemperature": {"auto": {"settable": false, "stepValue": 0.5, "minValue": 18, "maxValue": 30}, "cooling": {"settable": false, "stepValue": 0.5, "minValue": 18, "maxValue": 32}, "heating": {"settable": false, "stepValue": 0.5, "minValue": 10, "maxValue": 30}}, "fanSpeed": {"auto": {"currentMode": {"values": ["quiet", "auto", "fixed"], "settable": false}, "modes": {"fixed": {"settable": false, "maxValue": 5, "minValue": 1, "stepValue": 1}}}, "dry": {"currentMode": {"values": ["auto"], "settable": false}}, "cooling": {"currentMode": {"values": ["quiet", "auto", "fixed"], "settable": false}, "modes": {"fixed": {"settable": false, "maxValue": 5, "minValue": 1, "stepValue": 1}}}, "heating": {"currentMode": {"values": ["quiet", "auto", "fixed"], "settable": false}, "modes": {"fixed": {"settable": false, "maxValue": 5, "minValue": 1, "stepValue": 1}}}, "fanOnly": {"currentMode": {"values": ["quiet", "auto", "fixed"], "settable": false}, "modes": {"fixed": {"settable": false, "maxValue": 5, "minValue": 1, "stepValue": 1}}}}}}, "schedules": {"0": {"name": {"settable": true, "value": "", "maxLength": 32}, "meta": {"isReadOnly": false, "actionPeriods": ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]}, "actions": {"monday": {"12:00:00": {"operationMode": "off"}, "10:00:00": {"operationMode": "heating", "roomTemperature": 20, "fanSpeed": {"currentMode": "fixed", "modes": {"fixed": 3}}}}}, "settable": true}, "1": {"name": {"settable": true, "value": "", "maxLength": 32}, "meta": {"isReadOnly": false, "actionPeriods": ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]}, "actions": {}, "settable": true}, "2": {"name": {"settable": true, "value": "", "maxLength": 32}, "meta": {"isReadOnly": false, "actionPeriods": ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]}, "actions": {}, "settable": true}}}}}}, "econoMode": {"settable": true, "values": ["on", "off"], "value": "off"}, "isPowerfulModeActive": {"settable": false, "value": false}, "powerfulMode": {"settable": true, "values": ["on", "off"], "value": "off"}, "streamerMode": {"settable": true, "values": ["off", "on"], "value": "off"}, "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": [266.9, 112.4, 204.9, 107.6, 1.9, 0, 0, 0, 0, 3.6, 166.7, 245.2, 320, 188.5, 189.9, 86, 19, 1.1, 0, 0, 0, 0, 0, 0]}, "cooling": {"d": [0, 0, 0, 0, 0, 0, 0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1, 0, 0, 0, 0, 0, 0], "w": [0.2, 0.1, 0.1, 0.1, 0, 0.1, 0.2, 0.6, 0.6, 0.1, 0.1, 0.1, null, null], "m": [0, 0, 0, 0, 1.9, 14.3, 21.3, 19.7, 8.2, 0.7, 0, 0, 0, 0, 0, 0, 0, 13.7, 32.5, 3.4, 2.6, 0, 0, 0]}}}}, "holidayMode": {"ref": "#holidayMode", "settable": true, "value": {"enabled": false}}, "demandControl": {"ref": "#demandControl", "settable": true, "value": {"currentMode": {"value": "off", "settable": true, "values": ["off", "auto", "fixed", "scheduled"]}, "modes": {"fixed": {"stepValue": 5, "value": 100, "minValue": 40, "maxValue": 100, "settable": true}, "scheduled": {"settable": true, "meta": {"minIntervalBetweenActions": "00:01:00", "maxActionsPerActionPeriod": 4, "consecutiveActionsAllowed": true, "actionPeriods": ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"], "actionTypes": {"currentMode": {"settable": true, "values": ["off", "fixed"]}, "modes": {"fixed": {"stepValue": 5, "minValue": 40, "maxValue": 100, "settable": true}}}}, "value": {"actions": {}}}}}}}

Hope this helps. Let me know in case you'd need more.