Skip to content

Instantly share code, notes, and snippets.

@FlorianDessloch
Last active December 13, 2023 21:23
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FlorianDessloch/32ab59e2399e1b99f786fd40bfa0835a to your computer and use it in GitHub Desktop.
Save FlorianDessloch/32ab59e2399e1b99f786fd40bfa0835a to your computer and use it in GitHub Desktop.
Node Red Miele@Home Integration

These Flows use the exec node embedded in a few subflows to log into your miele@home account, to get information about and to control your Miele device. For commands, status lists and an account to use the API check out https://www.miele.com/developer/index.html Also check the FAQ-tab.

It seams to me, like the API is still buggy. Some actions shown by "get action" are not supported by my device (yet) and some actions like START and STOP result in an error but are carried out anyways.

[{
"id": "1d4d5eda.0ea591",
"type": "subflow",
"name": "put Action",
"info": "",
"category": "miele",
"in": [{
"x": 60,
"y": 100,
"wires": [{
"id": "7f552f3.aa2dad"
}
]
}
],
"out": [{
"x": 680,
"y": 160,
"wires": [{
"id": "7ed3f9c8.27e698",
"port": 0
}
]
}
],
"env": [{
"name": "bearer",
"type": "str",
"value": ""
}, {
"name": "device",
"type": "str",
"value": ""
}, {
"name": "action",
"type": "str",
"value": ""
}, {
"name": "parameter",
"type": "str",
"value": ""
}
],
"color": "#DDAA99",
"status": {
"x": 680,
"y": 80,
"wires": [{
"id": "7f552f3.aa2dad",
"port": 0
}, {
"id": "7ed3f9c8.27e698",
"port": 1
}
]
}
}, {
"id": "e459c4f9.d32338",
"type": "exec",
"z": "1d4d5eda.0ea591",
"command": "",
"addpay": true,
"append": "",
"useSpawn": "false",
"timer": "",
"oldrc": false,
"name": "get devices",
"x": 310,
"y": 140,
"wires": [["9af5b8fa.2292b8"], [], []]
}, {
"id": "9af5b8fa.2292b8",
"type": "json",
"z": "1d4d5eda.0ea591",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 450,
"y": 140,
"wires": [["7ed3f9c8.27e698"]]
}, {
"id": "7f552f3.aa2dad",
"type": "function",
"z": "1d4d5eda.0ea591",
"name": "",
"func": "let bearer = \"\";\nlet action = \"\";\nlet device = \"\";\nlet parameter = \"\";\n\n//node.send({payload: {fill:\"green\",shape:\"dot\",text:\"OK\"}});\n\nbearer = env.get(\"bearer\");\nif(msg.hasOwnProperty('bearer')) bearer=msg.bearer;\nif (bearer === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"bearer missing\"}});\n\naction = env.get(\"action\");\nif(msg.hasOwnProperty('action')) action=msg.action;\nif (action === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"actionuage missing\"}});\n\ndevice = env.get(\"device\");\nif(msg.hasOwnProperty('device')) lang=msg.device;\nif (device === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"device missing\"}});\n\nparameter = env.get(\"parameter\");\nif(msg.hasOwnProperty('parameter')) client_id=msg.parameter;\nif (parameter === \"\") node.send({payload: {fill:\"green\",shape:\"dot\",text:\"parameter fehlt\"}});\n\nvar msg2;\nmsg2={payload: \"curl -X PUT \\\"https:\\/\\/api.mcs3.miele.com\\/v1\\/devices\\/\"+device+\"\\/actions\\\" -H \\\"accept: *\\/*\\\" -H \\\"Authorization: Bearer \"+bearer+\"\\\" -H \\\"Content-Type: application\\/json\\\" -d \\\"{\\\\\\\"\"+action+\"\\\\\\\":\"+parameter+\"}\\\"\"};\nmsg1=null;\nreturn [[msg1],[msg2]];\n",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 150,
"y": 100,
"wires": [[], ["e459c4f9.d32338"]]
}, {
"id": "7ed3f9c8.27e698",
"type": "function",
"z": "1d4d5eda.0ea591",
"name": "",
"func": "var msg1={topic:msg.topic, payload: msg.payload};\nvar msg2;\n//if(msg.payload.status.hasOwnProperty(\"value_raw\")) msg2={payload:{fill:\"green\",shape:\"dot\",text:\"OK\"}};\n\nreturn [[msg1],[msg2]];",
"outputs": 2,
"noerr": 0,
"x": 570,
"y": 140,
"wires": [[], []]
}, {
"id": "b4c5c5ea.b2a928",
"type": "subflow",
"name": "get Action",
"info": "",
"category": "miele",
"in": [{
"x": 160,
"y": 100,
"wires": [{
"id": "98e5b950.6a2c58"
}
]
}
],
"out": [{
"x": 920,
"y": 160,
"wires": [{
"id": "3a80d692.13ff1a",
"port": 0
}
]
}
],
"env": [{
"name": "bearer",
"type": "str",
"value": ""
}, {
"name": "lang",
"type": "str",
"value": ""
}, {
"name": "device",
"type": "str",
"value": ""
}
],
"color": "#DDAA99",
"status": {
"x": 840,
"y": 80,
"wires": [{
"id": "98e5b950.6a2c58",
"port": 0
}, {
"id": "3a80d692.13ff1a",
"port": 1
}
]
}
}, {
"id": "da26411a.dd69c",
"type": "exec",
"z": "b4c5c5ea.b2a928",
"command": "",
"addpay": true,
"append": "",
"useSpawn": "false",
"timer": "",
"oldrc": false,
"name": "get devices",
"x": 430,
"y": 140,
"wires": [["eac26908.58f308"], [], []]
}, {
"id": "eac26908.58f308",
"type": "json",
"z": "b4c5c5ea.b2a928",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 570,
"y": 140,
"wires": [["3a80d692.13ff1a"]]
}, {
"id": "98e5b950.6a2c58",
"type": "function",
"z": "b4c5c5ea.b2a928",
"name": "",
"func": "let bearer = \"\";\nlet device = \"\";\n\n//node.send({payload: {fill:\"green\",shape:\"dot\",text:\"OK\"}});\n\nbearer = env.get(\"bearer\");\nif(msg.hasOwnProperty('bearer')) bearer=msg.bearer;\nif (bearer === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"bearer missing\"}});\n\ndevice = env.get(\"device\");\nif(msg.hasOwnProperty('device')) lang=msg.device;\nif (device === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"device missing\"}});\n\nvar msg2;\nmsg2={payload: \"curl -X GET \\\"https://api.mcs3.miele.com/v1/devices/\"+device+\"/actions\\\" -H \\\"accept: application/json; charset=utf-8\\\" -H \\\"Authorization: Bearer \" + bearer + \"\\\"\"};\nmsg1=null;\nreturn [[msg1],[msg2]];\n",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 270,
"y": 100,
"wires": [[], ["da26411a.dd69c"]]
}, {
"id": "3a80d692.13ff1a",
"type": "function",
"z": "b4c5c5ea.b2a928",
"name": "",
"func": "var msg1={topic:msg.topic, payload: msg.payload};\nvar msg2;\nif(msg.payload.hasOwnProperty(\"powerOn\")) msg2={payload:{fill:\"green\",shape:\"dot\",text:\"OK\"}};\n\nreturn [[msg1],[msg2]];",
"outputs": 2,
"noerr": 0,
"x": 690,
"y": 140,
"wires": [[], []]
}, {
"id": "8755d135.de6bf",
"type": "subflow",
"name": "get device state",
"info": "",
"category": "miele",
"in": [{
"x": 100,
"y": 120,
"wires": [{
"id": "98292c27.d877"
}
]
}
],
"out": [{
"x": 820,
"y": 160,
"wires": [{
"id": "1e7270f4.3abf8f",
"port": 0
}
]
}
],
"env": [{
"name": "bearer",
"type": "str",
"value": ""
}, {
"name": "lang",
"type": "str",
"value": ""
}, {
"name": "device",
"type": "str",
"value": ""
}
],
"color": "#DDAA99",
"status": {
"x": 700,
"y": 40,
"wires": [{
"id": "98292c27.d877",
"port": 0
}, {
"id": "1e7270f4.3abf8f",
"port": 1
}
]
}
}, {
"id": "7466cfd7.a3fcd",
"type": "exec",
"z": "8755d135.de6bf",
"command": "",
"addpay": true,
"append": "",
"useSpawn": "false",
"timer": "",
"oldrc": false,
"name": "get devices",
"x": 370,
"y": 160,
"wires": [["fff7f619.892af8"], [], []]
}, {
"id": "fff7f619.892af8",
"type": "json",
"z": "8755d135.de6bf",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 510,
"y": 160,
"wires": [["1e7270f4.3abf8f"]]
}, {
"id": "98292c27.d877",
"type": "function",
"z": "8755d135.de6bf",
"name": "",
"func": "let bearer = \"\";\nlet lang = \"\";\nlet device = \"\";\n\n//node.send({payload: {fill:\"green\",shape:\"dot\",text:\"OK\"}});\n\nbearer = env.get(\"bearer\");\nif(msg.hasOwnProperty('bearer')) bearer=msg.bearer;\nif (bearer === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"bearer missing\"}});\n\nlang = env.get(\"lang\");\nif(msg.hasOwnProperty('lang')) lang=msg.lang;\nif (lang === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"language missing\"}});\n\ndevice = env.get(\"device\");\nif(msg.hasOwnProperty('device')) lang=msg.device;\nif (device === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"device missing\"}});\n\nvar msg2;\nmsg2={payload: \"curl -X GET \\\"https://api.mcs3.miele.com/v1/devices/\"+device+\"/state?language=\" + lang +\"\\\" -H \\\"accept: application/json; charset=utf-8\\\" -H \\\"Authorization: Bearer \" + bearer + \"\\\"\"};\nmsg1=null;\nreturn [[msg1],[msg2]];\n",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 210,
"y": 120,
"wires": [[], ["7466cfd7.a3fcd"]]
}, {
"id": "1e7270f4.3abf8f",
"type": "function",
"z": "8755d135.de6bf",
"name": "",
"func": "var msg1={topic:msg.topic, payload: msg.payload};\nvar msg2;\nif(msg.payload.status.hasOwnProperty(\"value_raw\")) msg2={payload:{fill:\"green\",shape:\"dot\",text:\"OK\"}};\n\nreturn [[msg1],[msg2]];",
"outputs": 2,
"noerr": 0,
"x": 630,
"y": 160,
"wires": [[], []]
}, {
"id": "bcad6a16.fbc798",
"type": "subflow",
"name": "get device ident",
"info": "",
"category": "miele",
"in": [{
"x": 140,
"y": 80,
"wires": [{
"id": "81c0a717.e9f738"
}
]
}
],
"out": [{
"x": 840,
"y": 80,
"wires": [{
"id": "b462fa37.689438",
"port": 0
}
]
}
],
"env": [{
"name": "bearer",
"type": "str",
"value": ""
}, {
"name": "lang",
"type": "str",
"value": ""
}, {
"name": "device",
"type": "str",
"value": ""
}
],
"color": "#DDAA99",
"status": {
"x": 760,
"y": 40,
"wires": [{
"id": "81c0a717.e9f738",
"port": 0
}, {
"id": "b462fa37.689438",
"port": 1
}
]
}
}, {
"id": "245908be.c28b58",
"type": "exec",
"z": "bcad6a16.fbc798",
"command": "",
"addpay": true,
"append": "",
"useSpawn": "false",
"timer": "",
"oldrc": false,
"name": "get devices",
"x": 410,
"y": 120,
"wires": [["2e2c716e.8292ee"], [], []]
}, {
"id": "2e2c716e.8292ee",
"type": "json",
"z": "bcad6a16.fbc798",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 550,
"y": 120,
"wires": [["b462fa37.689438"]]
}, {
"id": "81c0a717.e9f738",
"type": "function",
"z": "bcad6a16.fbc798",
"name": "",
"func": "let bearer = \"\";\nlet lang = \"\";\nlet device = \"\";\n\n//node.send({payload: {fill:\"green\",shape:\"dot\",text:\"OK\"}});\n\nbearer = env.get(\"bearer\");\nif(msg.hasOwnProperty('bearer')) bearer=msg.bearer;\nif (bearer === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"bearer missing\"}});\n\nlang = env.get(\"lang\");\nif(msg.hasOwnProperty('lang')) lang=msg.lang;\nif (lang === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"language missing\"}});\n\ndevice = env.get(\"device\");\nif(msg.hasOwnProperty('device')) lang=msg.device;\nif (device === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"device missing\"}});\n\nvar msg2;\nmsg2={payload: \"curl -X GET \\\"https://api.mcs3.miele.com/v1/devices/\"+device+\"/ident?language=\" + lang +\"\\\" -H \\\"accept: application/json; charset=utf-8\\\" -H \\\"Authorization: Bearer \" + bearer + \"\\\"\"};\nmsg1=null;\nreturn [[msg1],[msg2]];\n",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 250,
"y": 80,
"wires": [[], ["245908be.c28b58"]]
}, {
"id": "b462fa37.689438",
"type": "function",
"z": "bcad6a16.fbc798",
"name": "",
"func": "var msg1={topic:msg.topic, payload: msg.payload};\nvar msg2;\nif(msg.payload.deviceIdentLabel.hasOwnProperty(\"fabNumber\")) msg2={payload:{fill:\"green\",shape:\"dot\",text:\"OK\"}};\n\nreturn [[msg1],[msg2]];",
"outputs": 2,
"noerr": 0,
"x": 670,
"y": 120,
"wires": [[], []]
}, {
"id": "390beeb8.8a5162",
"type": "subflow",
"name": "get device info",
"info": "",
"category": "miele",
"in": [{
"x": 260,
"y": 80,
"wires": [{
"id": "fdbbe7f7.00ba18"
}
]
}
],
"out": [{
"x": 940,
"y": 100,
"wires": [{
"id": "70e93124.23da5",
"port": 0
}
]
}
],
"env": [{
"name": "bearer",
"type": "str",
"value": ""
}, {
"name": "lang",
"type": "str",
"value": ""
}, {
"name": "device",
"type": "str",
"value": ""
}
],
"color": "#DDAA99",
"status": {
"x": 680,
"y": 40,
"wires": [{
"id": "fdbbe7f7.00ba18",
"port": 0
}, {
"id": "70e93124.23da5",
"port": 1
}
]
}
}, {
"id": "e8cbb2ba.6bc16",
"type": "exec",
"z": "390beeb8.8a5162",
"command": "",
"addpay": true,
"append": "",
"useSpawn": "false",
"timer": "",
"oldrc": false,
"name": "get devices",
"x": 530,
"y": 120,
"wires": [["ee0f6d14.6f4c3"], [], []]
}, {
"id": "ee0f6d14.6f4c3",
"type": "json",
"z": "390beeb8.8a5162",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 670,
"y": 120,
"wires": [["70e93124.23da5"]]
}, {
"id": "fdbbe7f7.00ba18",
"type": "function",
"z": "390beeb8.8a5162",
"name": "",
"func": "let bearer = \"\";\nlet lang = \"\";\nlet device = \"\";\n\n//node.send({payload: {fill:\"green\",shape:\"dot\",text:\"OK\"}});\n\nbearer = env.get(\"bearer\");\nif(msg.hasOwnProperty('bearer')) bearer=msg.bearer;\nif (bearer === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"bearer missing\"}});\n\nlang = env.get(\"lang\");\nif(msg.hasOwnProperty('lang')) lang=msg.lang;\nif (lang === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"language missing\"}});\n\ndevice = env.get(\"device\");\nif(msg.hasOwnProperty('device')) device=msg.device;\nif (device === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"device missing\"}});\n\nvar msg2;\nmsg2={payload: \"curl -X GET \\\"https://api.mcs3.miele.com/v1/devices/\"+device+\"?language=\" + lang +\"\\\" -H \\\"accept: application/json; charset=utf-8\\\" -H \\\"Authorization: Bearer \" + bearer + \"\\\"\"};\nmsg1=null;\nreturn [[msg1],[msg2]];\n",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 370,
"y": 80,
"wires": [[], ["e8cbb2ba.6bc16"]]
}, {
"id": "70e93124.23da5",
"type": "function",
"z": "390beeb8.8a5162",
"name": "",
"func": "var msg1={topic:msg.topic, payload: msg.payload};\nvar msg2;\nif(msg.payload.ident.hasOwnProperty(\"deviceName\")) msg2={payload:{fill:\"green\",shape:\"dot\",text:\"OK\"}};\n\nreturn [[msg1],[msg2]];",
"outputs": 2,
"noerr": 0,
"x": 790,
"y": 120,
"wires": [[], []]
}, {
"id": "d79e6968.80ffa8",
"type": "subflow",
"name": "get devices",
"info": "",
"category": "miele",
"in": [{
"x": 50,
"y": 30,
"wires": [{
"id": "9c6730e2.d8dcd"
}
]
}
],
"out": [{
"x": 680,
"y": 140,
"wires": [{
"id": "3c9ff92.07e6c06",
"port": 0
}
]
}
],
"env": [{
"name": "bearer",
"type": "str",
"value": ""
}, {
"name": "lang",
"type": "str",
"value": ""
}
],
"color": "#DDAA99",
"status": {
"x": 700,
"y": 20,
"wires": [{
"id": "9c6730e2.d8dcd",
"port": 0
}
]
}
}, {
"id": "1cd22b3c.108b05",
"type": "exec",
"z": "d79e6968.80ffa8",
"command": "",
"addpay": true,
"append": "",
"useSpawn": "false",
"timer": "",
"oldrc": false,
"name": "get devices",
"x": 430,
"y": 140,
"wires": [["3c9ff92.07e6c06"], [], []]
}, {
"id": "3c9ff92.07e6c06",
"type": "json",
"z": "d79e6968.80ffa8",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 590,
"y": 140,
"wires": [[]]
}, {
"id": "9c6730e2.d8dcd",
"type": "function",
"z": "d79e6968.80ffa8",
"name": "",
"func": "let bearer = \"\";\nlet lang = \"\";\n\n//node.send({payload: {fill:\"green\",shape:\"dot\",text:\"OK\"}});\n\nbearer = env.get(\"bearer\");\nif(msg.hasOwnProperty('bearer')) bearer=msg.bearer;\nif (bearer === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"bearer missing\"}});\n\nlang = env.get(\"lang\");\nif(msg.hasOwnProperty('lang')) lang=msg.lang;\nif (lang === \"\") node.send({payload: {fill:\"red\",shape:\"dot\",text:\"language missing\"}});\n\nvar msg2;\nmsg2={payload: \"curl -X GET \\\"https://api.mcs3.miele.com/v1/devices/?language=\" + lang +\"\\\" -H \\\"accept: application/json; charset=utf-8\\\" -H \\\"Authorization: Bearer \" + bearer + \"\\\"\"};\nmsg1=null;\nreturn [[msg1],[msg2]];\n",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 270,
"y": 100,
"wires": [[], ["1cd22b3c.108b05"]]
}, {
"id": "8b7bf7f.119a308",
"type": "subflow",
"name": "get Bearer",
"info": "This node uses your client_id, client_secret, username and password to get an autorization token, a so called Bearer (output 1) and a refresh token (output 2).\nAll parameters can be set using the incoming message.\nmsg.client_id, msg.client_secret, msg.[variable_name]...\ncoun_lang requires a combination of language and country, for germany it's DE-de.",
"category": "miele",
"in": [{
"x": 60,
"y": 80,
"wires": [{
"id": "272cb16.f5f164e"
}
]
}
],
"out": [{
"x": 720,
"y": 40,
"wires": [{
"id": "9af0fd2c.9426c",
"port": 0
}
]
}, {
"x": 720,
"y": 100,
"wires": [{
"id": "9af0fd2c.9426c",
"port": 1
}
]
}
],
"env": [{
"name": "client_id",
"type": "str",
"value": ""
}, {
"name": "client_secret",
"type": "str",
"value": ""
}, {
"name": "username",
"type": "str",
"value": ""
}, {
"name": "password",
"type": "str",
"value": ""
}, {
"name": "coun_lang",
"type": "str",
"value": ""
}
],
"color": "#DDAA99",
"outputLabels": ["Authorization Token", "Refresh Token"],
"status": {
"x": 720,
"y": 160,
"wires": [{
"id": "9af0fd2c.9426c",
"port": 2
}, {
"id": "272cb16.f5f164e",
"port": 0
}
]
}
}, {
"id": "1e9930fe.bf0faf",
"type": "exec",
"z": "8b7bf7f.119a308",
"command": "curl",
"addpay": true,
"append": "",
"useSpawn": "false",
"timer": "",
"oldrc": false,
"name": "get Bearer",
"x": 290,
"y": 40,
"wires": [["127e4047.65cb3"], [], []]
}, {
"id": "127e4047.65cb3",
"type": "json",
"z": "8b7bf7f.119a308",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 440,
"y": 40,
"wires": [["9af0fd2c.9426c"]]
}, {
"id": "9af0fd2c.9426c",
"type": "function",
"z": "8b7bf7f.119a308",
"name": "",
"func": "var msg1={topic:\"access_token\", payload: msg.payload.access_token};\nvar msg2={topic:\"refresh_token\", payload: msg.payload.refresh_token};\nvar msg3=null;\nif(msg.payload.hasOwnProperty('access_token') && msg.payload.hasOwnProperty('refresh_token')) msg3={payload:{fill:\"green\",shape:\"dot\",text:\"OK\"}};\n\nreturn [[msg1],[msg2],[msg3]];",
"outputs": 3,
"noerr": 0,
"x": 570,
"y": 40,
"wires": [[], [], []]
}, {
"id": "272cb16.f5f164e",
"type": "function",
"z": "8b7bf7f.119a308",
"name": "",
"func": "let client_id = \"\";\nlet client_secret = \"\";\nlet username = \"\";\nlet password = \"\";\nlet coun_lang = \"\";\n\nnode.send({payload: {fill:\"green\",shape:\"dot\",text:\"OK\"}});\n\nclient_id = env.get(\"client_id\");\nif(msg.hasOwnProperty('client_id')) client_id=msg.client_id;\nif (client_id === \"\") node.send({payload: {fill:\"green\",shape:\"dot\",text:\"Client_id fehlt\"}});\n\nclient_secret = env.get(\"client_secret\");\nif(msg.hasOwnProperty('client_secret')) client_secret=msg.client_secret;\nif (client_secret === \"\") node.send({payload: {fill:\"green\",shape:\"dot\",text:\"Client_secret fehlt\"}});\n\nusername = env.get(\"username\");\nif(msg.hasOwnProperty('username')) client_id=msg.username;\nif (username === \"\") node.send({payload: {fill:\"green\",shape:\"dot\",text:\"Username fehlt\"}});\n\npassword = env.get(\"password\");\nif(msg.hasOwnProperty('password')) client_id=msg.password;\nif (password === \"\") node.send({payload: {fill:\"green\",shape:\"dot\",text:\"Password fehlt\"}});\n\ncoun_lang = env.get(\"coun_lang\");\nif(msg.hasOwnProperty('coun_lang')) client_id=msg.coun_lang;\nif (coun_lang === \"\") node.send({payload: {fill:\"green\",shape:\"dot\",text:\"Country-Language fehlt\"}});\n\nvar msg2;\nmsg2={payload:\" -d \\\"grant_type=password\\\" -d \\\"client_id=\"+client_id+\n \"\\\" -d \\\"client_secret=\"+client_secret+\"\\\" -d \\\"username=\"+username+\n \"\\\" -d \\\"password=\"+password+\"\\\" -d \\\"vg=\"+coun_lang+\n \"\\\" https://api.mcs3.miele.com/thirdparty/token/\"};\nmsg1=null;\nreturn [[msg1],[msg2]];",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 150,
"y": 80,
"wires": [[], ["1e9930fe.bf0faf"]]
}, {
"id": "8cc73ce4.b2345",
"type": "inject",
"z": "8c044ad3.6aa2e8",
"name": "",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 240,
"y": 300,
"wires": [["4315b3b4.009d8c"]]
}, {
"id": "32015fbe.2f516",
"type": "function",
"z": "8c044ad3.6aa2e8",
"name": "set var",
"func": "global.set(\"mielebearer\",msg.payload);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 550,
"y": 300,
"wires": [[]]
}, {
"id": "3cffc84c.a8b748",
"type": "inject",
"z": "8c044ad3.6aa2e8",
"name": "",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 240,
"y": 360,
"wires": [["d073836.dc6fb8"]]
}, {
"id": "d073836.dc6fb8",
"type": "function",
"z": "8c044ad3.6aa2e8",
"name": "set var",
"func": "msg.lang=\"de\";\nmsg.bearer=global.get(\"mielebearer\");\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 370,
"y": 360,
"wires": [["2b0c40f3.cc07c"]]
}, {
"id": "ac0d4f3c.3f422",
"type": "debug",
"z": "8c044ad3.6aa2e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 650,
"y": 360,
"wires": []
}, {
"id": "e0817a83.3638c8",
"type": "inject",
"z": "8c044ad3.6aa2e8",
"name": "",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 240,
"y": 420,
"wires": [["91b577ba.e11378"]]
}, {
"id": "91b577ba.e11378",
"type": "function",
"z": "8c044ad3.6aa2e8",
"name": "set var",
"func": "msg.lang=\"de\";\nmsg.bearer=global.get(\"mielebearer\");\n//msg.device=\"XXXXXXXXXXXX\";\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 370,
"y": 420,
"wires": [["679210e5.bb4a1"]]
}, {
"id": "84b603eb.7fb6d",
"type": "debug",
"z": "8c044ad3.6aa2e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 670,
"y": 420,
"wires": []
}, {
"id": "2d89999e.2e6c96",
"type": "inject",
"z": "8c044ad3.6aa2e8",
"name": "",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 240,
"y": 480,
"wires": [["b331d5f2.a1c138"]]
}, {
"id": "b331d5f2.a1c138",
"type": "function",
"z": "8c044ad3.6aa2e8",
"name": "set var",
"func": "msg.lang=\"de\";\nmsg.bearer=global.get(\"mielebearer\");\n//msg.device=\"XXXXXXXXXXXX\";\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 370,
"y": 480,
"wires": [["69058e24.4db0e"]]
}, {
"id": "fc3b7cc5.0ac43",
"type": "debug",
"z": "8c044ad3.6aa2e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 670,
"y": 480,
"wires": []
}, {
"id": "4d8b4405.b609cc",
"type": "comment",
"z": "8c044ad3.6aa2e8",
"name": "Returns all information about appliances linked to an user account.",
"info": "",
"x": 1040,
"y": 360,
"wires": []
}, {
"id": "37d27f0d.8c6b8",
"type": "comment",
"z": "8c044ad3.6aa2e8",
"name": "Returns all information about a single appliance linked to an user account",
"info": "",
"x": 1060,
"y": 420,
"wires": []
}, {
"id": "4f0c966b.5c13e8",
"type": "comment",
"z": "8c044ad3.6aa2e8",
"name": "Returns your access token / Bearer",
"info": "",
"x": 940,
"y": 300,
"wires": []
}, {
"id": "2940a41f.6a1dec",
"type": "inject",
"z": "8c044ad3.6aa2e8",
"name": "",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 240,
"y": 600,
"wires": [["8d502f9a.9cfae"]]
}, {
"id": "8d502f9a.9cfae",
"type": "function",
"z": "8c044ad3.6aa2e8",
"name": "set var",
"func": "msg.lang=\"de\";\nmsg.bearer=global.get(\"mielebearer\");\n//msg.device=\"XXXXXXXXXXXX\";\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 370,
"y": 600,
"wires": [["29bb8380.76988c"]]
}, {
"id": "1903fd7b.0d45a3",
"type": "debug",
"z": "8c044ad3.6aa2e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 670,
"y": 600,
"wires": []
}, {
"id": "791c55db.267dcc",
"type": "comment",
"z": "8c044ad3.6aa2e8",
"name": "Returns the ident information of a single device",
"info": "",
"x": 980,
"y": 480,
"wires": []
}, {
"id": "a3209786.dafdc8",
"type": "comment",
"z": "8c044ad3.6aa2e8",
"name": "The GET action is used to request a device so send the currently supported actions",
"info": "",
"x": 1090,
"y": 600,
"wires": []
}, {
"id": "87379dd7.af663",
"type": "inject",
"z": "8c044ad3.6aa2e8",
"name": "",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 240,
"y": 540,
"wires": [["75c4daa.7552024"]]
}, {
"id": "75c4daa.7552024",
"type": "function",
"z": "8c044ad3.6aa2e8",
"name": "set var",
"func": "msg.lang=\"de\";\nmsg.bearer=global.get(\"mielebearer\");\n//msg.device=\"XXXXXXXXXXXX\";\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 370,
"y": 540,
"wires": [["22cd4a84.feb3f6"]]
}, {
"id": "d47b12a8.4c8ab",
"type": "debug",
"z": "8c044ad3.6aa2e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 670,
"y": 540,
"wires": []
}, {
"id": "b4a6a8cf.4e9628",
"type": "comment",
"z": "8c044ad3.6aa2e8",
"name": "Returns the state information of a single device",
"info": "",
"x": 980,
"y": 540,
"wires": []
}, {
"id": "1c6f442f.16a17c",
"type": "inject",
"z": "8c044ad3.6aa2e8",
"name": "",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 240,
"y": 660,
"wires": [["322386e.eaa967a"]]
}, {
"id": "322386e.eaa967a",
"type": "function",
"z": "8c044ad3.6aa2e8",
"name": "set var",
"func": "msg.bearer=global.get(\"mielebearer\");\n//msg.device=\"XXXXXXXXXXXX\";\nmsg.action=\"processAction\";\nmsg.parameter=\"2\";\n//msg.action=\"deviceName\";\n//msg.parameter=\"\\\\\\\"myDevice\\\\\\\"\";\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 370,
"y": 660,
"wires": [["bf22df68.b3972"]]
}, {
"id": "4686037.45bf3fc",
"type": "debug",
"z": "8c044ad3.6aa2e8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"x": 670,
"y": 660,
"wires": []
}, {
"id": "8909e20.acfb22",
"type": "comment",
"z": "8c044ad3.6aa2e8",
"name": "The PUT action is used invoke an action on a single device",
"info": "",
"x": 1010,
"y": 660,
"wires": []
}, {
"id": "4315b3b4.009d8c",
"type": "subflow:8b7bf7f.119a308",
"z": "8c044ad3.6aa2e8",
"name": "",
"env": [],
"x": 390,
"y": 300,
"wires": [["32015fbe.2f516"], []]
}, {
"id": "2b0c40f3.cc07c",
"type": "subflow:d79e6968.80ffa8",
"z": "8c044ad3.6aa2e8",
"name": "",
"env": [],
"x": 510,
"y": 360,
"wires": [["ac0d4f3c.3f422"]],
"info": "This node uses your autorization token, or Bearer your desired language (de and en are supported) to give you information about all of your devices as describes in https://www.miele.com/developer/swagger-ui/index.html#/.\nAll parameters can be set using the incoming message.\nmsg.bearer, msg.lang, basically it's msg.[variable_name]..."
}, {
"id": "679210e5.bb4a1",
"type": "subflow:390beeb8.8a5162",
"z": "8c044ad3.6aa2e8",
"name": "",
"env": [],
"x": 520,
"y": 420,
"wires": [["84b603eb.7fb6d"]],
"info": "This node uses your autorization token, or Bearer your desired language (de and en are supported) to give you information about one specific devices as describes in https://www.miele.com/developer/swagger-ui/index.html#/.\nAll parameters can be set using the incoming message.\nmsg.bearer, msg.lang, basically it's msg.[variable_name]..."
}, {
"id": "69058e24.4db0e",
"type": "subflow:bcad6a16.fbc798",
"z": "8c044ad3.6aa2e8",
"name": "",
"env": [],
"x": 520,
"y": 480,
"wires": [["fc3b7cc5.0ac43"]],
"info": "This node uses your autorization token, or Bearer your desired language (de and en are supported) to give you id-information about one specific devices as describes in https://www.miele.com/developer/swagger-ui/index.html#/.\nAll parameters can be set using the incoming message.\nmsg.bearer, msg.lang, basically it's msg.[variable_name]..."
}, {
"id": "22cd4a84.feb3f6",
"type": "subflow:8755d135.de6bf",
"z": "8c044ad3.6aa2e8",
"name": "",
"env": [],
"x": 520,
"y": 540,
"wires": [["d47b12a8.4c8ab"]],
"info": "This node uses your autorization token, or Bearer your desired language (de and en are supported) to give you the status of one specific devices as describes in https://www.miele.com/developer/swagger-ui/index.html#/.\nAll parameters can be set using the incoming message.\nmsg.bearer, msg.lang, basically it's msg.[variable_name]..."
}, {
"id": "29bb8380.76988c",
"type": "subflow:b4c5c5ea.b2a928",
"z": "8c044ad3.6aa2e8",
"name": "",
"env": [],
"x": 500,
"y": 600,
"wires": [["1903fd7b.0d45a3"]],
"info": "This node uses your autorization token, or Bearer your desired language (de and en are supported) to give you the availible actions of one specific devices in it's current status as describes in https://www.miele.com/developer/swagger-ui/index.html#/.\nAll parameters can be set using the incoming message.\nmsg.bearer, msg.lang, basically it's msg.[variable_name]..."
}, {
"id": "bf22df68.b3972",
"type": "subflow:1d4d5eda.0ea591",
"z": "8c044ad3.6aa2e8",
"name": "",
"env": [],
"x": 500,
"y": 660,
"wires": [["4686037.45bf3fc"]]
}
]
@ChutneyMary
Copy link

I think something has changed in the Miele API. I see the following message now -

"TypeError: Cannot read property 'hasOwnProperty' of undefined"

At least one other person is seeing the same problem on their installation (noted on a forum thread).

@FlorianDessloch
Copy link
Author

I think something has changed in the Miele API. I see the following message now -

"TypeError: Cannot read property 'hasOwnProperty' of undefined"

At least one other person is seeing the same problem on their installation (noted on a forum thread).

Can you be more specific?
Which node gives you that message?
Do you have a link to that forum thread?

@ChutneyMary
Copy link

I see the error message - "TypeError: Cannot read property 'hasOwnProperty' of undefined" - in the debug console of Node-Red.

If I inject the Timestamp for the first line (get Bearer) - I successfully see the access token in the debug console.
If I inject the Timestamp for the second line (get devices) - I see the payload object is empty.
If I inject the Timestamp for the third line (get device info) - I see the message "TypeError: Cannot read property 'hasOwnProperty' of undefined"

The following post refers to a question I placed -
https://www.loxforum.com/forum/projektforen/loxberry/plugins/176967-miele-mqtt-loxberry-mqtt?p=252298#post252298

@ChutneyMary
Copy link

Please ignore the previous comments. I installed the latest version of the Miele app on iOS, then re-added my appliance.
I see the payload object is now being populated and the subsequent 'get device info' is successful.
It seems like it may have been an issue with my end. I'll advise the other person to go through the same steps.
Thanks for the great implementation on Node-Red!

@JohaGit
Copy link

JohaGit commented Jan 27, 2021

Hi Florian, thank you. Good Job.

  1. ca. 71,4% of your flows functions works (get Bearer, get Devices, get Device Info, get Device Ident, get Action)

  2. I belief there is a problem with your subfunction script for "get Device State" , because your parameters (bearers etc.) are not defined or passed. So the Miele 3rd Party API Server rightfully throws an error on your call.

  3. With "put Action" though the API does look very buggy still, since even a direct execute on the server (https://www.miele.com/developer/swagger-ui/swagger.html#/) results in unexpeced results & errors. ie Calling PowerOff response returns results for "PowerOn" : {
    "message": "Device can't be powered on from its current state." } The precondition for start is status=4. Maybe there API level logic bug, since after selecting the washprogramme the machine status is only at 3

  4. Probably the biggest omission from the Miele API is that the consumables (Ultraphase 1 &2 levels - and the reason is it of primary interest for me to automate it) cannot be monitored, since the status cannot be retrieved from the API. However, Since the Mobile APP displays this levels, it is likely that the features are hidden in the 3rd Party API.

  5. The a useful feature for your script could be "eventing" ie receiving direct events from the machine (washmachine). This will make it useful to know for example when the washing is finished.

@FlorianDessloch
Copy link
Author

Hi Florian, thank you. Good Job.

  1. ca. 71,4% of your flows functions works (get Bearer, get Devices, get Device Info, get Device Ident, get Action)
  2. I belief there is a problem with your subfunction script for "get Device State" , because your parameters (bearers etc.) are not defined or passed. So the Miele 3rd Party API Server rightfully throws an error on your call.
  3. With "put Action" though the API does look very buggy still, since even a direct execute on the server (https://www.miele.com/developer/swagger-ui/swagger.html#/) results in unexpeced results & errors. ie Calling PowerOff response returns results for "PowerOn" : {
    "message": "Device can't be powered on from its current state." } The precondition for start is status=4. Maybe there API level logic bug, since after selecting the washprogramme the machine status is only at 3
  4. Probably the biggest omission from the Miele API is that the consumables (Ultraphase 1 &2 levels - and the reason is it of primary interest for me to automate it) cannot be monitored, since the status cannot be retrieved from the API. However, Since the Mobile APP displays this levels, it is likely that the features are hidden in the 3rd Party API.
  5. The a useful feature for your script could be "eventing" ie receiving direct events from the machine (washmachine). This will make it useful to know for example when the washing is finished.

Hi JohaGit,
thanks for your feedback.

  1. Well, I hope it's a little more ;-)
  2. "Get Device State" acepts those parameters (lang, bearer and device) via the input message properties msg. This made the most sense to me, since your bearer changes fequently, but I'll add the option it when I get around to.
  3. I know that does not work, what I do is, I set up the machine to a delayed start and when our solar battery is full or we feed more then 2kW into the grid, the programme is started. That work fine and you can't postpone washing indefinetly.
  4. I assume you're right, but I don't have the time to analyse all the traffic, so if you find out, let me know. I haven't felt the need for this information, since the machine alerts you and you'll allways have to prepare it manually, so I don't see the point in that.
  5. This allready works just fine, I get the status every 30 seconds, if it changes from 5 to 7 I get an alert and that is always quicker, then the app notofication. Since I explained under2, how to get the state, I'm sure, you'll get it to work for you as well.

Thanks for your constructive criticism, I really find it helpfull.
I assume, you forgot to mention my lack of documetation, but right now I don't have the time to improve that.
If you want to make any changes, the nodes are just subflows, so you can see what's inside and improve upon it.
If you do, I'd appreciate it if you'd let me know, maybe with a link to your fork.

@JohaGit
Copy link

JohaGit commented Jan 28, 2021

Hi Florian, no problem.

  1. That % was simply the functions that delivered working results by following your description.
  2. Ah. It is a slightly different pattern than how the rest is triggered. Simply refer to this in your description and it should be fine and at 86% 🥇 The last 14% problems are caused by Miele development bugs which are outside your control. btw the token expires only after 30 days. Of course, if you want, you can recreate the token every 2 seconds.
  3. thanks for the workaround suggestion. Good tip
  4. Yes, it alerts you on the display of the machine, but only when it is empty. My workaround was to buy 2 years of supply in advance, but since I found out that Twindos Ultraphase 2 is 15% peroxide and 4% phosphoric acid (stabilisor), it is better to predict levels and have a steady supply based on consumption. We love the twindos, because it clogs up less which means less washmachine maintenance, washes clean, less chemical because of ensymes used with Ultraphase 1. It takes a while to deliver, though, and cannot be bought at a local store. So if you don't use Twindos, I agree with you that this feature is not a benefit to you.
  5. Yes that can also work. I meant push events not pull/poll events. Your method is to polling the state every 30s continuously has a traffic overhead, but is pragmatic .

Here below is an alternative Miele json/node-red script that saves the token once off as global variables. (requires node-red credentials to work). Benefit is that a) the token is reused automatically as global variables in subsequent scripts : so a timer can refresh the token every 30 days (Miele timeout policy) b) the code will continue to work without much maintenance c) the shared published script omits your private details d) easier for noobs like me to know what to fill where in the multiple scripts :

[{"id":"ad607e01.511ea","type":"subflow","name":"set` action","info":"Set (execute) an action for the given appliance. Valid action depend on kind of appliance and state!","category":"Miele","in":[{"x":40,"y":75,"wires":[{"id":"2542e5f6.b0fd8a"}]}],"out":[{"x":1011,"y":74,"wires":[{"id":"21b0eeb.798de12","port":0}]}],"env":[],"color":"#A70625","inputLabels":["appliance id in payload and an action "],"outputLabels":["result"],"icon":"font-awesome/fa-angle-double-right","status":{"x":1010,"y":240,"wires":[{"id":"e4fefa21.402038","port":0},{"id":"9ebcdded.4fad9","port":0},{"id":"ebacb8a0.327d58","port":0}]}},{"id":"dafbb889.fb7f58","type":"http request","z":"ad607e01.511ea","name":"PUT to Miele","method":"PUT","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":499,"y":188,"wires":[["21b0eeb.798de12"]]},{"id":"8bbd1614.6e5288","type":"change","z":"ad607e01.511ea","name":"url, body","rules":[{"t":"set","p":"url","pt":"msg","to":"\"https://api.mcs3.miele.com/v1/devices/\" & payload & \"/actions/\"","tot":"jsonata"},{"t":"move","p":"action","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":389,"y":68,"wires":[["47b32910.93a498"]]},{"id":"2542e5f6.b0fd8a","type":"function","z":"ad607e01.511ea","name":"verify input","func":"// verify bearer & msg properties\nif (!global.get('system_bearerMiele')) {\n    node.error('global variable system_bearerMiele not defined', msg)\n    return [null, {payload:'invalid global variable'}]\n}\nif (!msg.payload){\n    node.error('invalid msg.payload - device id', msg)\n    return [null, {payload:\"invalid msg.payload - device id\"}]\n}\nif (!msg.action){\n    node.error('invalid msg.action - action', msg)\n    return [null, {payload:\"invalid msg.action - action\"}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":193,"y":75,"wires":[["8bbd1614.6e5288"],["ebacb8a0.327d58"]]},{"id":"f7de50c4.54625","type":"template","z":"ad607e01.511ea","name":"header with authorization","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"Authorization\":\"bearer {{global.system_bearerMiele}}\", \"Accept\": \"application/json\", \"Accept-Charset\": \"utf-8\"}","output":"json","x":459,"y":146,"wires":[["dafbb889.fb7f58"]]},{"id":"21b0eeb.798de12","type":"switch","z":"ad607e01.511ea","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":693,"y":80,"wires":[["e4fefa21.402038"],["6ad0d242.05cb5c"]]},{"id":"6ad0d242.05cb5c","type":"function","z":"ad607e01.511ea","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":716,"y":160,"wires":[["9ebcdded.4fad9"]]},{"id":"9ebcdded.4fad9","type":"template","z":"ad607e01.511ea","name":"error  http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":863,"y":160,"wires":[[]]},{"id":"e4fefa21.402038","type":"template","z":"ad607e01.511ea","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":873,"y":120,"wires":[[]]},{"id":"ebacb8a0.327d58","type":"template","z":"ad607e01.511ea","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":330,"y":240,"wires":[[]]},{"id":"47b32910.93a498","type":"json","z":"ad607e01.511ea","name":"","property":"payload","action":"obj","pretty":false,"x":399,"y":108,"wires":[["f7de50c4.54625"]]},{"id":"4ae29caa.8056e4","type":"subflow","name":"get actions","info":"Get an object with all valid actions for the given appliance id at the current appliance state.\n\nPrereq: bearer in global variable system_bearerMiele","category":"Miele","in":[{"x":40,"y":88,"wires":[{"id":"d3015191.5633d"}]}],"out":[{"x":1099,"y":38,"wires":[{"id":"c8655abf.93b328","port":0}]}],"env":[],"color":"#A70625","inputLabels":["appliance id"],"outputLabels":["all actions"],"icon":"node-red/debug.svg","status":{"x":1099,"y":158,"wires":[{"id":"2c02bcd4.dc63d4","port":0},{"id":"1455fb1d.b32055","port":0},{"id":"d9bc2537.715df8","port":0}]}},{"id":"a2806ac3.d3a2d8","type":"http request","z":"4ae29caa.8056e4","name":"GET from Miele","method":"GET","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":460,"y":118,"wires":[["c8655abf.93b328"]]},{"id":"e9e5b981.24d568","type":"change","z":"4ae29caa.8056e4","name":"msg.url, no payload","rules":[{"t":"set","p":"url","pt":"msg","to":"\"https://api.mcs3.miele.com/v1/devices/\" & payload & \"/actions/\"","tot":"jsonata"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":430,"y":78,"wires":[["a2806ac3.d3a2d8"]]},{"id":"f2707f72.38a2f","type":"template","z":"4ae29caa.8056e4","name":"msg.headers with authorization","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"Authorization\":\"bearer {{global.system_bearerMiele}}\", \"Accept\": \"application/json\", \"Accept-Charset\": \"utf-8\"}","output":"json","x":429,"y":38,"wires":[["e9e5b981.24d568"]]},{"id":"d3015191.5633d","type":"function","z":"4ae29caa.8056e4","name":"verify input","func":"// verify bearer & msg properties\nif (!global.get('system_bearerMiele')) {\n    node.error('global variable system_bearerMiele not defined', msg)\n    return [null, {payload:'invalid global variable'}]\n}\nif (!msg.payload){\n    node.error('invalid msg.payload - device id', msg)\n    return [null, {payload:\"invalid msg.payload - device id\"}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":198,"y":88,"wires":[["f2707f72.38a2f"],["d9bc2537.715df8"]]},{"id":"c8655abf.93b328","type":"switch","z":"4ae29caa.8056e4","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":703,"y":38,"wires":[["2c02bcd4.dc63d4"],["52535782.315028"]]},{"id":"52535782.315028","type":"function","z":"4ae29caa.8056e4","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":815,"y":118,"wires":[["1455fb1d.b32055"]]},{"id":"1455fb1d.b32055","type":"template","z":"4ae29caa.8056e4","name":"error  http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":962,"y":118,"wires":[[]]},{"id":"2c02bcd4.dc63d4","type":"template","z":"4ae29caa.8056e4","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":972,"y":78,"wires":[[]]},{"id":"d9bc2537.715df8","type":"template","z":"4ae29caa.8056e4","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":310,"y":158,"wires":[[]]},{"id":"aeba9414.6f40a8","type":"subflow","name":"get appliance","info":"Get an object with identification and state data for the given appliance id.\n\nPrereq: bearer in global variable system_bearerMiele","category":"Miele","in":[{"x":40,"y":97,"wires":[{"id":"a260e272.ea783"}]}],"out":[{"x":1143,"y":33,"wires":[{"id":"3da93881.b6e868","port":0}]}],"env":[{"name":"language","type":"str","value":"en","ui":{"label":{"en-US":"Language"},"type":"select","opts":{"opts":[{"l":{"en-US":"English"},"v":"en"},{"l":{"en-US":"Deutsch"},"v":"de"}]}}}],"color":"#A70625","inputLabels":["appliance id as payload"],"outputLabels":["appliance identification and state"],"icon":"font-awesome/fa-info","status":{"x":1140,"y":164,"wires":[{"id":"dd906f4c.1361a","port":0},{"id":"fd32a717.878c28","port":0},{"id":"96a3026.b505b","port":0}]}},{"id":"88aafd6a.c0982","type":"http request","z":"aeba9414.6f40a8","name":"GET from Miele","method":"GET","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":460,"y":120,"wires":[["3da93881.b6e868"]]},{"id":"3f0996d.8ed756a","type":"change","z":"aeba9414.6f40a8","name":"msg.url, no payload","rules":[{"t":"set","p":"url","pt":"msg","to":"\"https://api.mcs3.miele.com/v1/devices/\" & payload & \"/?language=\" & $env('language')","tot":"jsonata"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":80,"wires":[["88aafd6a.c0982"]]},{"id":"98d65a27.8020b8","type":"template","z":"aeba9414.6f40a8","name":"msg.headers with authorization","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"Authorization\":\"bearer {{global.system_bearerMiele}}\", \"Accept\": \"application/json\", \"Accept-Charset\": \"utf-8\"}","output":"json","x":410,"y":40,"wires":[["3f0996d.8ed756a"]]},{"id":"a260e272.ea783","type":"function","z":"aeba9414.6f40a8","name":"verify input","func":"// verify bearer & msg properties\nif (!global.get('system_bearerMiele')) {\n    node.error('global variable system_bearerMiele not defined', msg)\n    return [null, {payload:'invalid global variable'}]\n}\nif (!msg.payload){\n    node.error('invalid msg.payload - device id', msg)\n    return [null, {payload:\"invalid msg.payload - device id\"}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":192,"y":97,"wires":[["98d65a27.8020b8"],["fd32a717.878c28"]]},{"id":"3da93881.b6e868","type":"switch","z":"aeba9414.6f40a8","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":670,"y":40,"wires":[["96a3026.b505b"],["6a599077.f8081"]]},{"id":"6a599077.f8081","type":"function","z":"aeba9414.6f40a8","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":830,"y":120,"wires":[["dd906f4c.1361a"]]},{"id":"dd906f4c.1361a","type":"template","z":"aeba9414.6f40a8","name":"error  http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":980,"y":120,"wires":[[]]},{"id":"fd32a717.878c28","type":"template","z":"aeba9414.6f40a8","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":350,"y":164,"wires":[[]]},{"id":"96a3026.b505b","type":"template","z":"aeba9414.6f40a8","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":990,"y":80,"wires":[[]]},{"id":"ea970db4.5106b","type":"subflow","name":"get all appliances","info":"Get a list of all appliances with indentification and state.\n\nPrereq: bearer in global variable system_bearerMiele","category":"Miele","in":[{"x":40,"y":80,"wires":[{"id":"eaf22f71.d9969"}]}],"out":[{"x":1119,"y":74,"wires":[{"id":"a35f8dee.9f18f","port":0}]}],"env":[{"name":"language","type":"str","value":"en","ui":{"label":{"en-US":"Language"},"type":"select","opts":{"opts":[{"l":{"en-US":"English"},"v":"en"},{"l":{"en-US":"Deutsch"},"v":"de"}]}}}],"color":"#A70625","inputLabels":["just trigger"],"outputLabels":["appliance list in household"],"icon":"font-awesome/fa-list-ul","status":{"x":1120,"y":220,"wires":[{"id":"fe83c7a3.1ef478","port":0},{"id":"84b66c9d.f62ef","port":0},{"id":"681dd18d.1baa4","port":0}]}},{"id":"1cb172b5.14d9cd","type":"http request","z":"ea970db4.5106b","name":"GET from Miele","method":"GET","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":480,"y":160,"wires":[["a35f8dee.9f18f"]]},{"id":"93008453.2d0988","type":"change","z":"ea970db4.5106b","name":"define url delete payload","rules":[{"t":"set","p":"url","pt":"msg","to":"\"https://api.mcs3.miele.com/v1/devices/?language=\" & $env('language')","tot":"jsonata"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":120,"wires":[["1cb172b5.14d9cd"]]},{"id":"d7fd649a.9ff818","type":"template","z":"ea970db4.5106b","name":"header with authorization","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"Authorization\":\"bearer {{global.system_bearerMiele}}\", \"Accept\": \"application/json\", \"Accept-Charset\": \"utf-8\"}","output":"json","x":429,"y":80,"wires":[["93008453.2d0988"]]},{"id":"eaf22f71.d9969","type":"function","z":"ea970db4.5106b","name":"verify input","func":"// verify token\nif (!global.get('system_bearerMiele')) {\n    node.error('global variable system_bearerMiele not defined', msg)\n    return [null, {payload:'invalid global variable'}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":218,"y":80,"wires":[["d7fd649a.9ff818"],["681dd18d.1baa4"]]},{"id":"a35f8dee.9f18f","type":"switch","z":"ea970db4.5106b","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":650,"y":80,"wires":[["84b66c9d.f62ef"],["8c52e1d0.35a7c"]]},{"id":"8c52e1d0.35a7c","type":"function","z":"ea970db4.5106b","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":810,"y":160,"wires":[["fe83c7a3.1ef478"]]},{"id":"fe83c7a3.1ef478","type":"template","z":"ea970db4.5106b","name":"error http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":963,"y":160,"wires":[[]]},{"id":"84b66c9d.f62ef","type":"template","z":"ea970db4.5106b","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":954,"y":120,"wires":[[]]},{"id":"681dd18d.1baa4","type":"template","z":"ea970db4.5106b","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":390,"y":218,"wires":[[]]},{"id":"24092027.ab82","type":"subflow","name":"get bearer","info":"Get a new bearer and refresh token and stores it in global variables. \n\nThe global variables system_bearerMiele and system_refreshMiele are being used.","category":"Miele","in":[{"x":30,"y":63,"wires":[{"id":"85119bed.21b168"}]}],"out":[{"x":1221,"y":43,"wires":[{"id":"430fd0da.a6602","port":0}]}],"env":[{"name":"vg","type":"str","value":"de-DE","ui":{"label":{"en-US":"Country"},"type":"select","opts":{"opts":[{"l":{"en-US":"Germany"},"v":"de-DE"}]}}},{"name":"doRefresh","type":"bool","value":"false","ui":{"label":{"en-US":"Use refresh token"},"type":"checkbox","opts":{}}}],"color":"#A70625","inputLabels":["client and user credentials"],"outputLabels":["Miele reponse object"],"icon":"font-awesome/fa-key","status":{"x":1221,"y":254,"wires":[{"id":"ccdd1aa3.d7afe8","port":0},{"id":"afceb2f2.d18f3","port":0},{"id":"4400b51a.44eacc","port":0}]}},{"id":"7742f9f5.4a43e8","type":"change","z":"24092027.ab82","name":"get env","rules":[{"t":"set","p":"vg","pt":"msg","to":"vg","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":63,"wires":[["cbba5ff0.57a32"]]},{"id":"e44fd735.4b89a8","type":"switch","z":"24092027.ab82","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":774,"y":143,"wires":[["ccdd1aa3.d7afe8","430fd0da.a6602"],["32c1a07f.b3aaa"]]},{"id":"32c1a07f.b3aaa","type":"function","z":"24092027.ab82","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":934,"y":223,"wires":[["afceb2f2.d18f3"]]},{"id":"afceb2f2.d18f3","type":"template","z":"24092027.ab82","name":"error  http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":1081,"y":223,"wires":[[]]},{"id":"ccdd1aa3.d7afe8","type":"template","z":"24092027.ab82","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":1091,"y":183,"wires":[[]]},{"id":"4400b51a.44eacc","type":"template","z":"24092027.ab82","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":360,"y":258,"wires":[[]]},{"id":"85119bed.21b168","type":"function","z":"24092027.ab82","name":"verify input","func":"// verify bearer & msg properties\nif (!msg.username) {\n    node.error('msg.username not defined', msg)\n    return [null, {payload:'msg.username not defined'}]\n}\nif (!msg.password){\n    node.error('msg.password not defined', msg)\n    return [null, {payload:\"msg.password not definedd\"}]\n}\nif (!msg.clientId){\n    node.error('msg.clientId not defined', msg)\n    return [null, {payload:\"msg.clientId not defined\"}]\n}\nif (!msg.clientSecret){\n    node.error('msg.clientSecret not defined', msg)\n    return [null, {payload:\"msg.clientSecret not defined\"}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":160,"y":63,"wires":[["7742f9f5.4a43e8"],["4400b51a.44eacc"]]},{"id":"994c115f.0117b","type":"template","z":"24092027.ab82","name":"create body new","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"grant_type=password&username={{username}}&password={{password}}&client_id={{clientId}}&client_secret={{clientSecret}}&vg={{vg}}","output":"str","x":527,"y":103,"wires":[["a1d20301.4f124"]]},{"id":"a1d20301.4f124","type":"change","z":"24092027.ab82","name":"define url, headers","rules":[{"t":"set","p":"url","pt":"msg","to":"https://api.mcs3.miele.com/thirdparty/token/","tot":"str"},{"t":"set","p":"headers","pt":"msg","to":"{\"Content-Type\":\"application/x-www-form-urlencoded\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":754,"y":63,"wires":[["d782c3de.6219"]]},{"id":"d782c3de.6219","type":"http request","z":"24092027.ab82","name":"","method":"POST","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":774,"y":103,"wires":[["e44fd735.4b89a8"]]},{"id":"98c0b90e.acfad8","type":"comment","z":"24092027.ab82","name":"Miele only supports form encoded","info":"","x":530,"y":23,"wires":[]},{"id":"430fd0da.a6602","type":"change","z":"24092027.ab82","name":"","rules":[{"t":"set","p":"system_bearerMiele","pt":"global","to":"payload.access_token","tot":"msg"},{"t":"set","p":"system_refreshMiele","pt":"global","to":"payload.refresh_token","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1001,"y":136,"wires":[[]]},{"id":"6fe89867.753478","type":"template","z":"24092027.ab82","name":"create body refresh","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"grant_type=refresh_token&refresh_token={{global.system_refreshMiele}}&client_id={{clientId}}&client_secret={{clientSecret}}&vg={{vg}}","output":"str","x":537,"y":63,"wires":[["a1d20301.4f124"]]},{"id":"cbba5ff0.57a32","type":"switch","z":"24092027.ab82","name":"","property":"doRefresh","propertyType":"env","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":360,"y":103,"wires":[["6fe89867.753478"],["994c115f.0117b"]]},{"id":"dea3f134.ddc37","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":91,"y":150,"wires":[["6ac23f94.dc3d"]]},{"id":"feb96bef.d13c48","type":"comment","z":"91448cef.2efc9","name":"B. get information about all devices","info":"","x":147,"y":117,"wires":[]},{"id":"df69bc9f.4c2d5","type":"debug","z":"91448cef.2efc9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":748,"y":400,"wires":[]},{"id":"754625fb.8865fc","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":323,"wires":[["33b22f76.f4038"]]},{"id":"2ecedcf0.da0db4","type":"comment","z":"91448cef.2efc9","name":"C. get all information about one specifc device","info":"","x":175,"y":289,"wires":[]},{"id":"7a654d71.f942e4","type":"comment","z":"91448cef.2efc9","name":"D. get all actions of one specific device - depend on the current state of the device","info":"","x":285,"y":615,"wires":[]},{"id":"45bd620f.4b086c","type":"comment","z":"91448cef.2efc9","name":"A. get new bearer  - also do refresh token","info":"","x":165,"y":20,"wires":[]},{"id":"fed8fd9e.68c2d","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":87,"y":53,"wires":[["f5ecdf57.03ab1"]]},{"id":"a048c655.ec1f78","type":"subflow:24092027.ab82","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"},{"name":"clientId","value":"xx","type":"str"},{"name":"clientSecret","value":"xxx","type":"str"},{"name":"username","value":"xxxxx","type":"str"},{"name":"password","value":"xxxxxx","type":"str"}],"x":391,"y":53,"wires":[["df69bc9f.4c2d5"]]},{"id":"f5ecdf57.03ab1","type":"credentials","z":"91448cef.2efc9","name":"","props":[{"value":"username","type":"msg"},{"value":"password","type":"msg"},{"value":"clientId","type":"msg"},{"value":"clientSecret","type":"msg"}],"x":230,"y":53,"wires":[["a048c655.ec1f78"]]},{"id":"6ac23f94.dc3d","type":"subflow:ea970db4.5106b","z":"91448cef.2efc9","name":"","env":[],"x":254,"y":150,"wires":[["df69bc9f.4c2d5"]]},{"id":"33b22f76.f4038","type":"subflow:aeba9414.6f40a8","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":305,"y":323,"wires":[["df69bc9f.4c2d5"]]},{"id":"bc574599.2b5938","type":"comment","z":"91448cef.2efc9","name":"C. get current status of a specifc device","info":"","x":155,"y":443,"wires":[]},{"id":"8912f7bb.095be8","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":476,"wires":[["9100eaf.d08d818"]]},{"id":"9100eaf.d08d818","type":"subflow:aeba9414.6f40a8","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":305,"y":476,"wires":[["ffb4b516.d45be8"]]},{"id":"d4f62349.a5a59","type":"comment","z":"91448cef.2efc9","name":"C. get current device type of a specifc device","info":"","x":175,"y":367,"wires":[]},{"id":"3eee5c2a.855a04","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":400,"wires":[["2640e37d.d5b69c"]]},{"id":"2640e37d.d5b69c","type":"subflow:aeba9414.6f40a8","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":305,"y":400,"wires":[["35daca5.d3adb36"]]},{"id":"1e76a8e5.b32bc7","type":"comment","z":"91448cef.2efc9","name":"B. get device id of first device","info":"","x":125,"y":191,"wires":[]},{"id":"4590828c.8b3f2c","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":224,"wires":[["472d288e.030668"]]},{"id":"472d288e.030668","type":"subflow:ea970db4.5106b","z":"91448cef.2efc9","name":"","env":[],"x":251,"y":224,"wires":[["d960c503.4130c8"]]},{"id":"d960c503.4130c8","type":"function","z":"91448cef.2efc9","name":"id first object","func":"msg.payload = msg.payload[Object.keys(msg.payload)[0]].ident.deviceIdentLabel.fabNumber\nreturn msg;","outputs":1,"noerr":0,"x":433,"y":224,"wires":[["df69bc9f.4c2d5"]]},{"id":"80c862b8.062ff","type":"comment","z":"91448cef.2efc9","name":"C. get remaining time of specific device","info":"","x":155,"y":520,"wires":[]},{"id":"c47bb64d.541918","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":553,"wires":[["77c1288.984c0d8"]]},{"id":"77c1288.984c0d8","type":"subflow:aeba9414.6f40a8","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":305,"y":553,"wires":[["5dfa60dc.87fc8"]]},{"id":"5dfa60dc.87fc8","type":"change","z":"91448cef.2efc9","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.state.remainingTime[0]*60 + payload.state.remainingTime[1] &  \" min\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":491,"y":553,"wires":[["df69bc9f.4c2d5"]]},{"id":"35daca5.d3adb36","type":"change","z":"91448cef.2efc9","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.ident.type.value_localized","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":491,"y":400,"wires":[["df69bc9f.4c2d5"]]},{"id":"ffb4b516.d45be8","type":"change","z":"91448cef.2efc9","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.state.status.value_localized","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":491,"y":476,"wires":[["df69bc9f.4c2d5"]]},{"id":"f278936b.e797","type":"subflow:4ae29caa.8056e4","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":295,"y":648,"wires":[["df69bc9f.4c2d5"]]},{"id":"9c8e0be2.1c8a58","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":648,"wires":[["f278936b.e797"]]},{"id":"c0e959c7.d684f8","type":"comment","z":"91448cef.2efc9","name":"E. execute command set name {\"deviceName\":\"My_Devicename\"}","info":"","x":245,"y":708,"wires":[]},{"id":"b7906361.bd13b","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":94,"y":740,"wires":[["21e8e59.be3271a"]]},{"id":"bba95584.0ba288","type":"subflow:ad607e01.511ea","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":423,"y":740,"wires":[["df69bc9f.4c2d5"]]},{"id":"6f3d8c02.c4ff64","type":"subflow:ad607e01.511ea","z":"91448cef.2efc9","name":"","env":[],"x":423,"y":821,"wires":[["df69bc9f.4c2d5"]]},{"id":"488026b0.68fa38","type":"comment","z":"91448cef.2efc9","name":"E. execute command stop {\"processAction\":2}","info":"","x":175,"y":788,"wires":[]},{"id":"21e8e59.be3271a","type":"change","z":"91448cef.2efc9","name":"machine id, action","rules":[{"t":"set","p":"payload","pt":"msg","to":"000149287451","tot":"str"},{"t":"set","p":"action","pt":"msg","to":"{\"deviceName\":\"hkMiele\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":249,"y":740,"wires":[["bba95584.0ba288"]]},{"id":"7ab1b56e.a9c78c","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":94,"y":821,"wires":[["c54123db.3130e"]]},{"id":"c54123db.3130e","type":"change","z":"91448cef.2efc9","name":"machine id, action","rules":[{"t":"set","p":"payload","pt":"msg","to":"000149287451","tot":"str"},{"t":"set","p":"action","pt":"msg","to":"{\"processAction\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":249,"y":821,"wires":[["6f3d8c02.c4ff64"]]}]

@FlorianDessloch
Copy link
Author

Hi Florian, no problem.

  1. That % was simply the functions that delivered working results by following your description.
  2. Ah. It is a slightly different pattern than how the rest is triggered. Simply refer to this in your description and it should be fine and at 86% 🥇 The last 14% problems are caused by Miele development bugs which are outside your control. btw the token expires only after 30 days. Of course, if you want, you can recreate the token every 2 seconds.
  3. thanks for the workaround suggestion. Good tip
  4. Yes, it alerts you on the display of the machine, but only when it is empty. My workaround was to buy 2 years of supply in advance, but since I found out that Twindos Ultraphase 2 is 15% peroxide and 4% phosphoric acid (stabilisor), it is better to predict levels and have a steady supply based on consumption. We love the twindos, because it clogs up less which means less washmachine maintenance, washes clean, less chemical because of ensymes used with Ultraphase 1. It takes a while to deliver, though, and cannot be bought at a local store. So if you don't use Twindos, I agree with you that this feature is not a benefit to you.
  5. Yes that can also work. I meant push events not pull/poll events. Your method is to polling the state every 30s continuously has a traffic overhead, but is pragmatic .

Here below is an alternative Miele json/node-red script that saves the token once off as global variables. (requires node-red credentials to work). Benefit is that a) the token is reused automatically as global variables in subsequent scripts : so a timer can refresh the token every 30 days (Miele timeout policy) b) the code will continue to work without much maintenance c) the shared published script omits your private details d) easier for noobs like me to know what to fill where in the multiple scripts :

[{"id":"ad607e01.511ea","type":"subflow","name":"set` action","info":"Set (execute) an action for the given appliance. Valid action depend on kind of appliance and state!","category":"Miele","in":[{"x":40,"y":75,"wires":[{"id":"2542e5f6.b0fd8a"}]}],"out":[{"x":1011,"y":74,"wires":[{"id":"21b0eeb.798de12","port":0}]}],"env":[],"color":"#A70625","inputLabels":["appliance id in payload and an action "],"outputLabels":["result"],"icon":"font-awesome/fa-angle-double-right","status":{"x":1010,"y":240,"wires":[{"id":"e4fefa21.402038","port":0},{"id":"9ebcdded.4fad9","port":0},{"id":"ebacb8a0.327d58","port":0}]}},{"id":"dafbb889.fb7f58","type":"http request","z":"ad607e01.511ea","name":"PUT to Miele","method":"PUT","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":499,"y":188,"wires":[["21b0eeb.798de12"]]},{"id":"8bbd1614.6e5288","type":"change","z":"ad607e01.511ea","name":"url, body","rules":[{"t":"set","p":"url","pt":"msg","to":"\"https://api.mcs3.miele.com/v1/devices/\" & payload & \"/actions/\"","tot":"jsonata"},{"t":"move","p":"action","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":389,"y":68,"wires":[["47b32910.93a498"]]},{"id":"2542e5f6.b0fd8a","type":"function","z":"ad607e01.511ea","name":"verify input","func":"// verify bearer & msg properties\nif (!global.get('system_bearerMiele')) {\n    node.error('global variable system_bearerMiele not defined', msg)\n    return [null, {payload:'invalid global variable'}]\n}\nif (!msg.payload){\n    node.error('invalid msg.payload - device id', msg)\n    return [null, {payload:\"invalid msg.payload - device id\"}]\n}\nif (!msg.action){\n    node.error('invalid msg.action - action', msg)\n    return [null, {payload:\"invalid msg.action - action\"}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":193,"y":75,"wires":[["8bbd1614.6e5288"],["ebacb8a0.327d58"]]},{"id":"f7de50c4.54625","type":"template","z":"ad607e01.511ea","name":"header with authorization","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"Authorization\":\"bearer {{global.system_bearerMiele}}\", \"Accept\": \"application/json\", \"Accept-Charset\": \"utf-8\"}","output":"json","x":459,"y":146,"wires":[["dafbb889.fb7f58"]]},{"id":"21b0eeb.798de12","type":"switch","z":"ad607e01.511ea","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":693,"y":80,"wires":[["e4fefa21.402038"],["6ad0d242.05cb5c"]]},{"id":"6ad0d242.05cb5c","type":"function","z":"ad607e01.511ea","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":716,"y":160,"wires":[["9ebcdded.4fad9"]]},{"id":"9ebcdded.4fad9","type":"template","z":"ad607e01.511ea","name":"error  http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":863,"y":160,"wires":[[]]},{"id":"e4fefa21.402038","type":"template","z":"ad607e01.511ea","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":873,"y":120,"wires":[[]]},{"id":"ebacb8a0.327d58","type":"template","z":"ad607e01.511ea","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":330,"y":240,"wires":[[]]},{"id":"47b32910.93a498","type":"json","z":"ad607e01.511ea","name":"","property":"payload","action":"obj","pretty":false,"x":399,"y":108,"wires":[["f7de50c4.54625"]]},{"id":"4ae29caa.8056e4","type":"subflow","name":"get actions","info":"Get an object with all valid actions for the given appliance id at the current appliance state.\n\nPrereq: bearer in global variable system_bearerMiele","category":"Miele","in":[{"x":40,"y":88,"wires":[{"id":"d3015191.5633d"}]}],"out":[{"x":1099,"y":38,"wires":[{"id":"c8655abf.93b328","port":0}]}],"env":[],"color":"#A70625","inputLabels":["appliance id"],"outputLabels":["all actions"],"icon":"node-red/debug.svg","status":{"x":1099,"y":158,"wires":[{"id":"2c02bcd4.dc63d4","port":0},{"id":"1455fb1d.b32055","port":0},{"id":"d9bc2537.715df8","port":0}]}},{"id":"a2806ac3.d3a2d8","type":"http request","z":"4ae29caa.8056e4","name":"GET from Miele","method":"GET","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":460,"y":118,"wires":[["c8655abf.93b328"]]},{"id":"e9e5b981.24d568","type":"change","z":"4ae29caa.8056e4","name":"msg.url, no payload","rules":[{"t":"set","p":"url","pt":"msg","to":"\"https://api.mcs3.miele.com/v1/devices/\" & payload & \"/actions/\"","tot":"jsonata"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":430,"y":78,"wires":[["a2806ac3.d3a2d8"]]},{"id":"f2707f72.38a2f","type":"template","z":"4ae29caa.8056e4","name":"msg.headers with authorization","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"Authorization\":\"bearer {{global.system_bearerMiele}}\", \"Accept\": \"application/json\", \"Accept-Charset\": \"utf-8\"}","output":"json","x":429,"y":38,"wires":[["e9e5b981.24d568"]]},{"id":"d3015191.5633d","type":"function","z":"4ae29caa.8056e4","name":"verify input","func":"// verify bearer & msg properties\nif (!global.get('system_bearerMiele')) {\n    node.error('global variable system_bearerMiele not defined', msg)\n    return [null, {payload:'invalid global variable'}]\n}\nif (!msg.payload){\n    node.error('invalid msg.payload - device id', msg)\n    return [null, {payload:\"invalid msg.payload - device id\"}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":198,"y":88,"wires":[["f2707f72.38a2f"],["d9bc2537.715df8"]]},{"id":"c8655abf.93b328","type":"switch","z":"4ae29caa.8056e4","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":703,"y":38,"wires":[["2c02bcd4.dc63d4"],["52535782.315028"]]},{"id":"52535782.315028","type":"function","z":"4ae29caa.8056e4","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":815,"y":118,"wires":[["1455fb1d.b32055"]]},{"id":"1455fb1d.b32055","type":"template","z":"4ae29caa.8056e4","name":"error  http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":962,"y":118,"wires":[[]]},{"id":"2c02bcd4.dc63d4","type":"template","z":"4ae29caa.8056e4","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":972,"y":78,"wires":[[]]},{"id":"d9bc2537.715df8","type":"template","z":"4ae29caa.8056e4","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":310,"y":158,"wires":[[]]},{"id":"aeba9414.6f40a8","type":"subflow","name":"get appliance","info":"Get an object with identification and state data for the given appliance id.\n\nPrereq: bearer in global variable system_bearerMiele","category":"Miele","in":[{"x":40,"y":97,"wires":[{"id":"a260e272.ea783"}]}],"out":[{"x":1143,"y":33,"wires":[{"id":"3da93881.b6e868","port":0}]}],"env":[{"name":"language","type":"str","value":"en","ui":{"label":{"en-US":"Language"},"type":"select","opts":{"opts":[{"l":{"en-US":"English"},"v":"en"},{"l":{"en-US":"Deutsch"},"v":"de"}]}}}],"color":"#A70625","inputLabels":["appliance id as payload"],"outputLabels":["appliance identification and state"],"icon":"font-awesome/fa-info","status":{"x":1140,"y":164,"wires":[{"id":"dd906f4c.1361a","port":0},{"id":"fd32a717.878c28","port":0},{"id":"96a3026.b505b","port":0}]}},{"id":"88aafd6a.c0982","type":"http request","z":"aeba9414.6f40a8","name":"GET from Miele","method":"GET","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":460,"y":120,"wires":[["3da93881.b6e868"]]},{"id":"3f0996d.8ed756a","type":"change","z":"aeba9414.6f40a8","name":"msg.url, no payload","rules":[{"t":"set","p":"url","pt":"msg","to":"\"https://api.mcs3.miele.com/v1/devices/\" & payload & \"/?language=\" & $env('language')","tot":"jsonata"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":80,"wires":[["88aafd6a.c0982"]]},{"id":"98d65a27.8020b8","type":"template","z":"aeba9414.6f40a8","name":"msg.headers with authorization","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"Authorization\":\"bearer {{global.system_bearerMiele}}\", \"Accept\": \"application/json\", \"Accept-Charset\": \"utf-8\"}","output":"json","x":410,"y":40,"wires":[["3f0996d.8ed756a"]]},{"id":"a260e272.ea783","type":"function","z":"aeba9414.6f40a8","name":"verify input","func":"// verify bearer & msg properties\nif (!global.get('system_bearerMiele')) {\n    node.error('global variable system_bearerMiele not defined', msg)\n    return [null, {payload:'invalid global variable'}]\n}\nif (!msg.payload){\n    node.error('invalid msg.payload - device id', msg)\n    return [null, {payload:\"invalid msg.payload - device id\"}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":192,"y":97,"wires":[["98d65a27.8020b8"],["fd32a717.878c28"]]},{"id":"3da93881.b6e868","type":"switch","z":"aeba9414.6f40a8","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":670,"y":40,"wires":[["96a3026.b505b"],["6a599077.f8081"]]},{"id":"6a599077.f8081","type":"function","z":"aeba9414.6f40a8","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":830,"y":120,"wires":[["dd906f4c.1361a"]]},{"id":"dd906f4c.1361a","type":"template","z":"aeba9414.6f40a8","name":"error  http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":980,"y":120,"wires":[[]]},{"id":"fd32a717.878c28","type":"template","z":"aeba9414.6f40a8","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":350,"y":164,"wires":[[]]},{"id":"96a3026.b505b","type":"template","z":"aeba9414.6f40a8","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":990,"y":80,"wires":[[]]},{"id":"ea970db4.5106b","type":"subflow","name":"get all appliances","info":"Get a list of all appliances with indentification and state.\n\nPrereq: bearer in global variable system_bearerMiele","category":"Miele","in":[{"x":40,"y":80,"wires":[{"id":"eaf22f71.d9969"}]}],"out":[{"x":1119,"y":74,"wires":[{"id":"a35f8dee.9f18f","port":0}]}],"env":[{"name":"language","type":"str","value":"en","ui":{"label":{"en-US":"Language"},"type":"select","opts":{"opts":[{"l":{"en-US":"English"},"v":"en"},{"l":{"en-US":"Deutsch"},"v":"de"}]}}}],"color":"#A70625","inputLabels":["just trigger"],"outputLabels":["appliance list in household"],"icon":"font-awesome/fa-list-ul","status":{"x":1120,"y":220,"wires":[{"id":"fe83c7a3.1ef478","port":0},{"id":"84b66c9d.f62ef","port":0},{"id":"681dd18d.1baa4","port":0}]}},{"id":"1cb172b5.14d9cd","type":"http request","z":"ea970db4.5106b","name":"GET from Miele","method":"GET","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":480,"y":160,"wires":[["a35f8dee.9f18f"]]},{"id":"93008453.2d0988","type":"change","z":"ea970db4.5106b","name":"define url delete payload","rules":[{"t":"set","p":"url","pt":"msg","to":"\"https://api.mcs3.miele.com/v1/devices/?language=\" & $env('language')","tot":"jsonata"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":120,"wires":[["1cb172b5.14d9cd"]]},{"id":"d7fd649a.9ff818","type":"template","z":"ea970db4.5106b","name":"header with authorization","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"Authorization\":\"bearer {{global.system_bearerMiele}}\", \"Accept\": \"application/json\", \"Accept-Charset\": \"utf-8\"}","output":"json","x":429,"y":80,"wires":[["93008453.2d0988"]]},{"id":"eaf22f71.d9969","type":"function","z":"ea970db4.5106b","name":"verify input","func":"// verify token\nif (!global.get('system_bearerMiele')) {\n    node.error('global variable system_bearerMiele not defined', msg)\n    return [null, {payload:'invalid global variable'}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":218,"y":80,"wires":[["d7fd649a.9ff818"],["681dd18d.1baa4"]]},{"id":"a35f8dee.9f18f","type":"switch","z":"ea970db4.5106b","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":650,"y":80,"wires":[["84b66c9d.f62ef"],["8c52e1d0.35a7c"]]},{"id":"8c52e1d0.35a7c","type":"function","z":"ea970db4.5106b","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":810,"y":160,"wires":[["fe83c7a3.1ef478"]]},{"id":"fe83c7a3.1ef478","type":"template","z":"ea970db4.5106b","name":"error http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":963,"y":160,"wires":[[]]},{"id":"84b66c9d.f62ef","type":"template","z":"ea970db4.5106b","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":954,"y":120,"wires":[[]]},{"id":"681dd18d.1baa4","type":"template","z":"ea970db4.5106b","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":390,"y":218,"wires":[[]]},{"id":"24092027.ab82","type":"subflow","name":"get bearer","info":"Get a new bearer and refresh token and stores it in global variables. \n\nThe global variables system_bearerMiele and system_refreshMiele are being used.","category":"Miele","in":[{"x":30,"y":63,"wires":[{"id":"85119bed.21b168"}]}],"out":[{"x":1221,"y":43,"wires":[{"id":"430fd0da.a6602","port":0}]}],"env":[{"name":"vg","type":"str","value":"de-DE","ui":{"label":{"en-US":"Country"},"type":"select","opts":{"opts":[{"l":{"en-US":"Germany"},"v":"de-DE"}]}}},{"name":"doRefresh","type":"bool","value":"false","ui":{"label":{"en-US":"Use refresh token"},"type":"checkbox","opts":{}}}],"color":"#A70625","inputLabels":["client and user credentials"],"outputLabels":["Miele reponse object"],"icon":"font-awesome/fa-key","status":{"x":1221,"y":254,"wires":[{"id":"ccdd1aa3.d7afe8","port":0},{"id":"afceb2f2.d18f3","port":0},{"id":"4400b51a.44eacc","port":0}]}},{"id":"7742f9f5.4a43e8","type":"change","z":"24092027.ab82","name":"get env","rules":[{"t":"set","p":"vg","pt":"msg","to":"vg","tot":"env"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":63,"wires":[["cbba5ff0.57a32"]]},{"id":"e44fd735.4b89a8","type":"switch","z":"24092027.ab82","name":"ok?","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":774,"y":143,"wires":[["ccdd1aa3.d7afe8","430fd0da.a6602"],["32c1a07f.b3aaa"]]},{"id":"32c1a07f.b3aaa","type":"function","z":"24092027.ab82","name":"throw error","func":"node.error('http error: ' + msg.payload.message, msg)\nreturn msg\n","outputs":1,"noerr":0,"x":934,"y":223,"wires":[["afceb2f2.d18f3"]]},{"id":"afceb2f2.d18f3","type":"template","z":"24092027.ab82","name":"error  http","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload.message}}\"}","output":"json","x":1081,"y":223,"wires":[[]]},{"id":"ccdd1aa3.d7afe8","type":"template","z":"24092027.ab82","name":"ok!","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"green\",\"shape\":\"dot\",\"text\":\"ok!\"}","output":"json","x":1091,"y":183,"wires":[[]]},{"id":"4400b51a.44eacc","type":"template","z":"24092027.ab82","name":"error input","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"fill\":\"red\",\"shape\":\"dot\",\"text\":\"error: {{payload}}\"}","output":"json","x":360,"y":258,"wires":[[]]},{"id":"85119bed.21b168","type":"function","z":"24092027.ab82","name":"verify input","func":"// verify bearer & msg properties\nif (!msg.username) {\n    node.error('msg.username not defined', msg)\n    return [null, {payload:'msg.username not defined'}]\n}\nif (!msg.password){\n    node.error('msg.password not defined', msg)\n    return [null, {payload:\"msg.password not definedd\"}]\n}\nif (!msg.clientId){\n    node.error('msg.clientId not defined', msg)\n    return [null, {payload:\"msg.clientId not defined\"}]\n}\nif (!msg.clientSecret){\n    node.error('msg.clientSecret not defined', msg)\n    return [null, {payload:\"msg.clientSecret not defined\"}]\n}\nreturn [msg, null]","outputs":2,"noerr":0,"x":160,"y":63,"wires":[["7742f9f5.4a43e8"],["4400b51a.44eacc"]]},{"id":"994c115f.0117b","type":"template","z":"24092027.ab82","name":"create body new","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"grant_type=password&username={{username}}&password={{password}}&client_id={{clientId}}&client_secret={{clientSecret}}&vg={{vg}}","output":"str","x":527,"y":103,"wires":[["a1d20301.4f124"]]},{"id":"a1d20301.4f124","type":"change","z":"24092027.ab82","name":"define url, headers","rules":[{"t":"set","p":"url","pt":"msg","to":"https://api.mcs3.miele.com/thirdparty/token/","tot":"str"},{"t":"set","p":"headers","pt":"msg","to":"{\"Content-Type\":\"application/x-www-form-urlencoded\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":754,"y":63,"wires":[["d782c3de.6219"]]},{"id":"d782c3de.6219","type":"http request","z":"24092027.ab82","name":"","method":"POST","ret":"obj","paytoqs":false,"url":"","tls":"","persist":false,"proxy":"","authType":"","x":774,"y":103,"wires":[["e44fd735.4b89a8"]]},{"id":"98c0b90e.acfad8","type":"comment","z":"24092027.ab82","name":"Miele only supports form encoded","info":"","x":530,"y":23,"wires":[]},{"id":"430fd0da.a6602","type":"change","z":"24092027.ab82","name":"","rules":[{"t":"set","p":"system_bearerMiele","pt":"global","to":"payload.access_token","tot":"msg"},{"t":"set","p":"system_refreshMiele","pt":"global","to":"payload.refresh_token","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1001,"y":136,"wires":[[]]},{"id":"6fe89867.753478","type":"template","z":"24092027.ab82","name":"create body refresh","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"grant_type=refresh_token&refresh_token={{global.system_refreshMiele}}&client_id={{clientId}}&client_secret={{clientSecret}}&vg={{vg}}","output":"str","x":537,"y":63,"wires":[["a1d20301.4f124"]]},{"id":"cbba5ff0.57a32","type":"switch","z":"24092027.ab82","name":"","property":"doRefresh","propertyType":"env","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":360,"y":103,"wires":[["6fe89867.753478"],["994c115f.0117b"]]},{"id":"dea3f134.ddc37","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":91,"y":150,"wires":[["6ac23f94.dc3d"]]},{"id":"feb96bef.d13c48","type":"comment","z":"91448cef.2efc9","name":"B. get information about all devices","info":"","x":147,"y":117,"wires":[]},{"id":"df69bc9f.4c2d5","type":"debug","z":"91448cef.2efc9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":748,"y":400,"wires":[]},{"id":"754625fb.8865fc","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":323,"wires":[["33b22f76.f4038"]]},{"id":"2ecedcf0.da0db4","type":"comment","z":"91448cef.2efc9","name":"C. get all information about one specifc device","info":"","x":175,"y":289,"wires":[]},{"id":"7a654d71.f942e4","type":"comment","z":"91448cef.2efc9","name":"D. get all actions of one specific device - depend on the current state of the device","info":"","x":285,"y":615,"wires":[]},{"id":"45bd620f.4b086c","type":"comment","z":"91448cef.2efc9","name":"A. get new bearer  - also do refresh token","info":"","x":165,"y":20,"wires":[]},{"id":"fed8fd9e.68c2d","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":87,"y":53,"wires":[["f5ecdf57.03ab1"]]},{"id":"a048c655.ec1f78","type":"subflow:24092027.ab82","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"},{"name":"clientId","value":"xx","type":"str"},{"name":"clientSecret","value":"xxx","type":"str"},{"name":"username","value":"xxxxx","type":"str"},{"name":"password","value":"xxxxxx","type":"str"}],"x":391,"y":53,"wires":[["df69bc9f.4c2d5"]]},{"id":"f5ecdf57.03ab1","type":"credentials","z":"91448cef.2efc9","name":"","props":[{"value":"username","type":"msg"},{"value":"password","type":"msg"},{"value":"clientId","type":"msg"},{"value":"clientSecret","type":"msg"}],"x":230,"y":53,"wires":[["a048c655.ec1f78"]]},{"id":"6ac23f94.dc3d","type":"subflow:ea970db4.5106b","z":"91448cef.2efc9","name":"","env":[],"x":254,"y":150,"wires":[["df69bc9f.4c2d5"]]},{"id":"33b22f76.f4038","type":"subflow:aeba9414.6f40a8","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":305,"y":323,"wires":[["df69bc9f.4c2d5"]]},{"id":"bc574599.2b5938","type":"comment","z":"91448cef.2efc9","name":"C. get current status of a specifc device","info":"","x":155,"y":443,"wires":[]},{"id":"8912f7bb.095be8","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":476,"wires":[["9100eaf.d08d818"]]},{"id":"9100eaf.d08d818","type":"subflow:aeba9414.6f40a8","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":305,"y":476,"wires":[["ffb4b516.d45be8"]]},{"id":"d4f62349.a5a59","type":"comment","z":"91448cef.2efc9","name":"C. get current device type of a specifc device","info":"","x":175,"y":367,"wires":[]},{"id":"3eee5c2a.855a04","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":400,"wires":[["2640e37d.d5b69c"]]},{"id":"2640e37d.d5b69c","type":"subflow:aeba9414.6f40a8","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":305,"y":400,"wires":[["35daca5.d3adb36"]]},{"id":"1e76a8e5.b32bc7","type":"comment","z":"91448cef.2efc9","name":"B. get device id of first device","info":"","x":125,"y":191,"wires":[]},{"id":"4590828c.8b3f2c","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":224,"wires":[["472d288e.030668"]]},{"id":"472d288e.030668","type":"subflow:ea970db4.5106b","z":"91448cef.2efc9","name":"","env":[],"x":251,"y":224,"wires":[["d960c503.4130c8"]]},{"id":"d960c503.4130c8","type":"function","z":"91448cef.2efc9","name":"id first object","func":"msg.payload = msg.payload[Object.keys(msg.payload)[0]].ident.deviceIdentLabel.fabNumber\nreturn msg;","outputs":1,"noerr":0,"x":433,"y":224,"wires":[["df69bc9f.4c2d5"]]},{"id":"80c862b8.062ff","type":"comment","z":"91448cef.2efc9","name":"C. get remaining time of specific device","info":"","x":155,"y":520,"wires":[]},{"id":"c47bb64d.541918","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":553,"wires":[["77c1288.984c0d8"]]},{"id":"77c1288.984c0d8","type":"subflow:aeba9414.6f40a8","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":305,"y":553,"wires":[["5dfa60dc.87fc8"]]},{"id":"5dfa60dc.87fc8","type":"change","z":"91448cef.2efc9","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.state.remainingTime[0]*60 + payload.state.remainingTime[1] &  \" min\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":491,"y":553,"wires":[["df69bc9f.4c2d5"]]},{"id":"35daca5.d3adb36","type":"change","z":"91448cef.2efc9","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.ident.type.value_localized","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":491,"y":400,"wires":[["df69bc9f.4c2d5"]]},{"id":"ffb4b516.d45be8","type":"change","z":"91448cef.2efc9","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.state.status.value_localized","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":491,"y":476,"wires":[["df69bc9f.4c2d5"]]},{"id":"f278936b.e797","type":"subflow:4ae29caa.8056e4","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":295,"y":648,"wires":[["df69bc9f.4c2d5"]]},{"id":"9c8e0be2.1c8a58","type":"inject","z":"91448cef.2efc9","name":"","topic":"","payload":"000149287451","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":124,"y":648,"wires":[["f278936b.e797"]]},{"id":"c0e959c7.d684f8","type":"comment","z":"91448cef.2efc9","name":"E. execute command set name {\"deviceName\":\"My_Devicename\"}","info":"","x":245,"y":708,"wires":[]},{"id":"b7906361.bd13b","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":94,"y":740,"wires":[["21e8e59.be3271a"]]},{"id":"bba95584.0ba288","type":"subflow:ad607e01.511ea","z":"91448cef.2efc9","name":"","env":[{"name":"language","value":"de","type":"str"}],"x":423,"y":740,"wires":[["df69bc9f.4c2d5"]]},{"id":"6f3d8c02.c4ff64","type":"subflow:ad607e01.511ea","z":"91448cef.2efc9","name":"","env":[],"x":423,"y":821,"wires":[["df69bc9f.4c2d5"]]},{"id":"488026b0.68fa38","type":"comment","z":"91448cef.2efc9","name":"E. execute command stop {\"processAction\":2}","info":"","x":175,"y":788,"wires":[]},{"id":"21e8e59.be3271a","type":"change","z":"91448cef.2efc9","name":"machine id, action","rules":[{"t":"set","p":"payload","pt":"msg","to":"000149287451","tot":"str"},{"t":"set","p":"action","pt":"msg","to":"{\"deviceName\":\"hkMiele\"}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":249,"y":740,"wires":[["bba95584.0ba288"]]},{"id":"7ab1b56e.a9c78c","type":"inject","z":"91448cef.2efc9","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":94,"y":821,"wires":[["c54123db.3130e"]]},{"id":"c54123db.3130e","type":"change","z":"91448cef.2efc9","name":"machine id, action","rules":[{"t":"set","p":"payload","pt":"msg","to":"000149287451","tot":"str"},{"t":"set","p":"action","pt":"msg","to":"{\"processAction\":2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":249,"y":821,"wires":[["6f3d8c02.c4ff64"]]}]

Hi,
I don't consider the bearer to be so vital, that it needs to be encrypted, so I just write it to a global variable, as I did in the example I give.
In my setup I do that once a week, so there is no problem there but you can use node-red credentials with my stuff, too.

@christopher-lambe
Copy link

For both flows here I get {"message":"username/password is invalid"}
My user/password /client id/client secret are all fine and work on https://www.miele.com/developer/swagger-ui/swagger.html#/
The same credential work fine with a home assistant integration

Any clues what is going on? Can you guys still get in?

The lack of Twindos levels from the miele API is very annoying. This is also my main motivation to use the API.
I guess they don't want anyone to make a app that automatically orders miele consumables from somwhere.
Guess I might have to install fiddler everwhere and see how my phone gets this levels information.

@FlorianDessloch
Copy link
Author

I just got myself a new bearer, no problem there.

Is this your first time trying it with my flows, or has it worked before?
What do you enter for your country/language information?

Since my wife has to load the maschine anyways the missind Twindos information isn't that bad, plus we're not using Twindow anymore, just regular liquid detergent in the universal cartriges and we always have a bottle of that around ;-)

@christopher-lambe
Copy link

christopher-lambe commented Jan 30, 2022

Hi Florian,

Thanks for the fast response. Just solved it with your tip about the country/language.
Using one that does not exist like en-UK will produce a "no vg given" error in the Bearer node.
en-GB, en-IE, de-DE, en-US all produce a {"message":"username/password is invalid"}

However it appears to be essential to remember which country you chose in the miele app/login.
de-CH works fine for me.

Cheers,
Chris

(EDIT: fixed the typo in your name)

@selfmade01
Copy link

selfmade01 commented Dec 12, 2023

Hi Florian,
I have the same problems as @christopher-lambe
I get
"{"message":"username/password is invalid"}"
at the first flow when I want to get an access token.
When I access Home Assistant everything works. This shows that my login information is ok.

I also have under vg=de-DE
but it doesn't bring any success either.

@FlorianDessloch
Copy link
Author

Hi @selfmade01,
I'm not sure, but this might be a problem with a limit to the interval you can use the bearer to refresh itself.
I switched over to using the refresh token a while ago, but I haven't uploaded that flow yet.
Maybe I'll get around to this later today.

@FlorianDessloch
Copy link
Author

FlorianDessloch commented Dec 13, 2023

Hi @selfmade01 ,
is has to be DE-de to work,
at least thats what I use ;-)

@selfmade01
Copy link

@FlorianDessloch
thank you a lot, i will try it , at evening

@selfmade01
Copy link

selfmade01 commented Dec 13, 2023

@FlorianDessloch
sorry, DE-de not help

nr-2

@FlorianDessloch
Copy link
Author

@selfmade01 I delete your first pic, because you forgot to delete the user and password from the debug bar.
Actually that helped a little. your username is supposed to be your e-mail, maybe that's the problem.

@selfmade01
Copy link

selfmade01 commented Dec 13, 2023

@FlorianDessloch oooohh Thanks a lot. Thank you for delete the pics.. but if i not post this misstake maybe i never find this problem...
now run my first step in that miele node
Thank you for help

was the Username... need my mail-adress

What means the Bearer Value? what i have to fill out there

@FlorianDessloch
Copy link
Author

@selfmade01 The bearer is part of your authentication towards miele., You only use your username and so on to get the bearer, all other functions can be called using the bearer, it's basically your api-key.
My flows store it to a variable in the global context and use it, when needed.
It's a bit hard to explain this way, so if you want more info let me know and maybe we can have a teams meeting or something.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment