I think the script might not be complete? ![]()
Otherwise I’d be happy to test it.
Thanks… seems the first few lines got truncated. Please see below
#!/bin/bash
send_payload () {
local cmd="${1,,}" # lowercase version of the argument
local prefix="00100001062f00000000000100010700"
local suffix="202020202020202020202020202020"
local url="http://127.0.0.1:5001/dop2leaf/oven/2/1583/0/0"
local hdr="Content-Type: application/octet-stream"
# Mapping of command → opcode (in hex)
declare -A opcodes=(
[nop]="00"
[start]="01"
[stop]="02"
[pause]="03"
[startdelay]="08"
[dooropen]="0b"
[doorclose]="0c"
[lighton]="0d"
[lightoff]="0e"
[factorysettingreset]="0f"
[switchon]="10"
[next]="11"
[back]="12"
[switchoff]="13"
[resetpincode]="14"
[keepalive]="15"
[step]="16"
[startremoteupdateinstall]="17"
[programstop]="36"
[programabort]="37"
[programfinalize]="38"
[programsave]="3d"
[motorizedfrontpanelopen]="41"
[motorizedfrontpanelclose]="42"
[holdingbreak]="44"
[holdingstart]="45"
)
# Validate input
if [ -z "$cmd" ]; then
echo "Usage: send_payload <command>"
echo "Available commands: ${!opcodes[*]}"
return 1
fi
local opcode="${opcodes[$cmd]}"
echo "Sending opcode "$opcode
if [ -z "$opcode" ]; then
echo "Unknown command: $cmd"
echo "Available commands: ${!opcodes[*]}"
return 2
fi
# Build the full hex payload
local payload="${prefix}${opcode}${suffix}"
# Send binary payload via curl
printf '%s' "$payload" | xxd -r -p | \
curl -sS -X POST -H "$hdr" --data-binary @- "$url"
}
send_payload "$1"
Apologies for the prolonged reply, please see the details for the nmap.
It doesn’t work with all 1’s as it’s 403-ing on the endpoint before it can send the data. It is almost like it is pre-provisioned to Miele, I’m not entirely convinced the “factory reset” in the manual is resetting this either as it stays connected to the network after performing it and resetting the network just seems to disconnect the wifi.
nmap
tarting Nmap 7.98 ( https://nmap.org ) at 2025-09-19 17:23 +0100
NSE: Loaded 158 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 17:23
Completed NSE at 17:23, 0.00s elapsed
Initiating NSE at 17:23
Completed NSE at 17:23, 0.00s elapsed
Initiating NSE at 17:23
Completed NSE at 17:23, 0.00s elapsed
Initiating Ping Scan at 17:23
Scanning 172.30.214.124 [2 ports]
Completed Ping Scan at 17:23, 0.07s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 17:23
Completed Parallel DNS resolution of 1 host. at 17:23, 0.01s elapsed
Initiating Connect Scan at 17:23
Scanning Miele-001D63FFFEC7FE50 (172.30.214.124) [1000 ports]
Discovered open port 80/tcp on 172.30.214.124
Completed Connect Scan at 17:23, 3.35s elapsed (1000 total ports)
Initiating Service scan at 17:23
Scanning 1 service on Miele-001D63FFFEC7FE50 (172.30.214.124)
Completed Service scan at 17:25, 159.85s elapsed (1 service on 1 host)
NSE: Script scanning 172.30.214.124.
Initiating NSE at 17:25
Completed NSE at 17:26, 13.74s elapsed
Initiating NSE at 17:26
Completed NSE at 17:26, 2.01s elapsed
Initiating NSE at 17:26
Completed NSE at 17:26, 0.00s elapsed
Nmap scan report for Miele-001D63FFFEC7FE50 (172.30.214.124)
Host is up (0.011s latency).
Not shown: 999 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
80/tcp open http
|_http-title: Site doesn't have a title (application/vnd.miele.v1+json; charset=utf-8).
|_http-cors: GET POST
| fingerprint-strings:
| DNSStatusRequestTCP:
| HTTP/1.1 400 Bad Request
| Date: Fri, 19 Sep 2025 16:23:56 GMT
| Content-Length:0
| Content-Type: application/vnd.miele.v1+json; charset=utf-8
| DNSVersionBindReqTCP:
| HTTP/1.1 400 Bad Request
| Date: Fri, 19 Sep 2025 16:23:51 GMT
| Content-Length:0
| Content-Type: application/vnd.miele.v1+json; charset=utf-8
| FourOhFourRequest:
| HTTP/1.1 404 Not Found
| Date: Fri, 19 Sep 2025 16:23:35 GMT
| Content-Length:0
| Content-Type: application/vnd.miele.v1+json; charset=utf-8
| GetRequest:
| HTTP/1.1 404 Not Found
| Date: Fri, 19 Sep 2025 16:23:15 GMT
| Content-Length:0
| Content-Type: application/vnd.miele.v1+json; charset=utf-8
| HTTPOptions:
| HTTP/1.1 200 OK
| Date: Fri, 19 Sep 2025 16:23:20 GMT
| Content-Length:0
| Access-Control-Allow-Origin:*
| Access-Control-Allow-Headers:*
| Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS
| RPCCheck:
| HTTP/1.1 400 Bad Request
| Date: Fri, 19 Sep 2025 16:23:46 GMT
| Content-Length:0
| Content-Type: application/vnd.miele.v1+json; charset=utf-8
| RTSPRequest:
| HTTP/1.1 200 OK
| Date: Fri, 19 Sep 2025 16:23:25 GMT
| Content-Length:0
| Access-Control-Allow-Origin:*
| Access-Control-Allow-Headers:*
| Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS
| SSLSessionReq:
| HTTP/1.1 400 Bad Request
| Date: Fri, 19 Sep 2025 16:24:11 GMT
| Content-Length:0
| Content-Type: application/vnd.miele.v1+json; charset=utf-8
| X11Probe:
| HTTP/1.1 400 Bad Request
| Date: Fri, 19 Sep 2025 16:23:30 GMT
| Content-Length:0
|_ Content-Type: application/vnd.miele.v1+json; charset=utf-8
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port80-TCP:V=7.98%I=7%D=9/19%Time=68CD8378%P=arm-apple-darwin24.4.0%r(G
SF:etRequest,8D,"HTTP/1\.1\x20404\x20Not\x20Found\r\nDate:\x20Fri,\x2019\x
SF:20Sep\x202025\x2016:23:15\x20GMT\r\nContent-Length:0\r\nContent-Type:\x
SF:20application/vnd\.miele\.v1\+json;\x20charset=utf-8\r\n\r\n")%r(HTTPOp
SF:tions,C8,"HTTP/1\.1\x20200\x20OK\r\nDate:\x20Fri,\x2019\x20Sep\x202025\
SF:x2016:23:20\x20GMT\r\nContent-Length:0\r\nAccess-Control-Allow-Origin:\
SF:*\r\nAccess-Control-Allow-Headers:\*\r\nAccess-Control-Allow-Methods:\x
SF:20GET,\x20PUT,\x20POST,\x20DELETE,\x20OPTIONS\r\n\r\n")%r(RTSPRequest,C
SF:8,"HTTP/1\.1\x20200\x20OK\r\nDate:\x20Fri,\x2019\x20Sep\x202025\x2016:2
SF:3:25\x20GMT\r\nContent-Length:0\r\nAccess-Control-Allow-Origin:\*\r\nAc
SF:cess-Control-Allow-Headers:\*\r\nAccess-Control-Allow-Methods:\x20GET,\
SF:x20PUT,\x20POST,\x20DELETE,\x20OPTIONS\r\n\r\n")%r(X11Probe,8F,"HTTP/1\
SF:.1\x20400\x20Bad\x20Request\r\nDate:\x20Fri,\x2019\x20Sep\x202025\x2016
SF::23:30\x20GMT\r\nContent-Length:0\r\nContent-Type:\x20application/vnd\.
SF:miele\.v1\+json;\x20charset=utf-8\r\n\r\n")%r(FourOhFourRequest,8D,"HTT
SF:P/1\.1\x20404\x20Not\x20Found\r\nDate:\x20Fri,\x2019\x20Sep\x202025\x20
SF:16:23:35\x20GMT\r\nContent-Length:0\r\nContent-Type:\x20application/vnd
SF:\.miele\.v1\+json;\x20charset=utf-8\r\n\r\n")%r(RPCCheck,8F,"HTTP/1\.1\
SF:x20400\x20Bad\x20Request\r\nDate:\x20Fri,\x2019\x20Sep\x202025\x2016:23
SF::46\x20GMT\r\nContent-Length:0\r\nContent-Type:\x20application/vnd\.mie
SF:le\.v1\+json;\x20charset=utf-8\r\n\r\n")%r(DNSVersionBindReqTCP,8F,"HTT
SF:P/1\.1\x20400\x20Bad\x20Request\r\nDate:\x20Fri,\x2019\x20Sep\x202025\x
SF:2016:23:51\x20GMT\r\nContent-Length:0\r\nContent-Type:\x20application/v
SF:nd\.miele\.v1\+json;\x20charset=utf-8\r\n\r\n")%r(DNSStatusRequestTCP,8
SF:F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nDate:\x20Fri,\x2019\x20Sep\x20
SF:2025\x2016:23:56\x20GMT\r\nContent-Length:0\r\nContent-Type:\x20applica
SF:tion/vnd\.miele\.v1\+json;\x20charset=utf-8\r\n\r\n")%r(SSLSessionReq,8
SF:F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nDate:\x20Fri,\x2019\x20Sep\x20
SF:2025\x2016:24:11\x20GMT\r\nContent-Length:0\r\nContent-Type:\x20applica
SF:tion/vnd\.miele\.v1\+json;\x20charset=utf-8\r\n\r\n");
NSE: Script Post-scanning.
Initiating NSE at 17:26
Completed NSE at 17:26, 0.00s elapsed
Initiating NSE at 17:26
Completed NSE at 17:26, 0.00s elapsed
Initiating NSE at 17:26
Completed NSE at 17:26, 0.00s elapsed
Read data files from: /opt/homebrew/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 179.33 seconds
Hi,
do I understand this correctly – you have previously connected this device to your WiFi and to the app. You then followed some steps on the control panel to reset it, but after completing the “reset”, it still retains the WiFi information and connects to the same WiFi?
If so, there is a problem with the reset. This would also explain why the key provisioning does not work – it still has the old key. I found the manual for your device, and the manufacturer is quite clear that a successful reset should delete the WiFi credentials. Were you following the reset sequence as described?
I think this is a bit more complicated and depends on the ovens state.
For example “switchon” works but gives a 500 if the oven is on already.
Vice versa with “switchoff”.
“Stop” only works if a program is running.
“lighton” and “lightoff” are working.
I think “start” needs another parameter, so the oven knows which program to start. So currently 500.
And also 500 for all the others. But I haven’t tried all states of the oven, just turned it on without a program and then tested the commands
What does “switchoff” actually do? Turning on the main screen and control board but not actually heating/running any cooking mode is what I would imagine?
Did you try to “start” an oven after it has been "pause"d, and after it has been "stop"ped?
I agree that it is likely impossible by design to “start” a device that hasn’t been programmed first. From looking at the logs, it doesn’t appear that there is any way to include a program parameter directly with the “start” command. Rather, there is a distinct programming command. Below is my attempt at programming the “hot air plus” program with default parameters. Could you kindly give it a shot?
PAYLOAD_PROGRAM_HOT_AIR_PLUS="001a00020629000000000003000107000d00020500000003040020202020"
URL="http://127.0.0.1:5001/dop2leaf/oven/2/1577/0/0"
hdr="Content-Type: application/octet-stream"
# send binary decoded from hex via stdin
printf '%s' "$PAYLOAD_PROGRAM_HOT_AIR_PLUS" | xxd -r -p | curl -sS -X POST -H "$hdr" --data-binary @- "$URL"
sleep 1
Currently I don’t know how to awake the oven if it’s in deep sleep.
The “switchon” only works, if the oven is turned off recently.
“switchon” and “switchoff” are working like I press the power button on the oven directly.
The payload you send for hot air plus does work. I sets the oven to that program. I then have to do a POST request to the “start” endpoint to actually start the program.
It also displays the message “fernsteuerung aktiv”.
Great news again. We’re almost there.
For waking up the device from deep sleep, there already exists the /wakeup endpoint, see below. This appears to use some out of band way of issuing the wakeup request to the actual device, and also works for all non-DOP2 devices I’ve seen. Does it work on yours?
If so then now we have all the steps in place to completely remotely control this device.
- Send /wakeup
- Send DOP2 “switchon”
- Send DOP2 program selection
- Send DOP2 “start”
URL="http://127.0.0.1:5001/wakeup/oven"
curl "$URL"
Wakeup does work perfectly
.
The steps you have mentioned should be correct ![]()
Hi,
thanks again for the continued help! I am still working on decent support for generating these DOP2 payloads. The Python DOP2 parsing routines were a hot mess, so I rewrote everything in Rust. This can now parse all DOP2 data structures observed in any Miele device, including yours. In the process, I think I finally discovered the data structures for the oven timer… would you mind trying the below? This should set your Timer 1 to 348 (seconds?).
PAYLOAD_TIMER="0050000100d1000000000002000121000200020001010000020b000000000000000000020001010000020b000000000000000000022100020002000104000002090000015c000200010401000209000000002020202020202020202020202020"
URL="http://127.0.0.1:5001/dop2leaf/oven/1/209/0/0"
hdr="Content-Type: application/octet-stream"
# send binary decoded from hex via stdin
printf '%s' "$PAYLOAD_TIMER" | xxd -r -p | curl -sS -X POST -H "$hdr" --data-binary @- "$URL"
sleep 1
Great work! Also rewriting the whole thing. But with Rust you should have a good choice.
Almost
- maybe ![]()
PUT 1/209, payload=b'0050000100d1000000000002000121000200020001010000020b000000000000000000020001010000020b000000000000000000022100020002000104000002090000015c000200010401000209000000002020202020202020202020202020'
Sending HTTP request to 192.168.**.**, resourcePath=Devices/************/DOP2/1/209?idx1=0&idx2=0
0E6E18EA5B12D94943B4B02FE34A4E4F69384F499618EE4BE8FB230B3306C3E3
bytearray(b'\x0en\x18\xea[\x12\xd9IC\xb4\xb0/\xe3JNO')
<Response [500]>
{'Date': 'Tue, 13 Jan 1970 22:24:45 GMT', 'Content-Length': '48', 'Content-Type': 'application/vnd.miele.v1+json; charset=utf-8', 'X-Signature': 'MieleH256 B430B5092E19BB86:1B21761EF6964445690FD93DDD7D5A0F52FCC2604F90FE29A25876614A5D6186'}
Sent PUT request to write 1/209, 96 bytes payload sent, got response [b'', <Response [500]>]
127.0.0.1 - - [20/Oct/2025 19:34:45] "POST /dop2leaf/oven/1/209/0/0 HTTP/1.1" 200 -
If you need more devices to test, I also have a fridge and stove from Miele. But it’s a bit of work to reconnect all devices from the official app to the “open” wifi mode ![]()
Appreciate it. I don’t think the fridge has a lot of meaningful programming capability (in fact, the official app appears to have none), but the stove/cooktop sure sounds interesting!
Could you also give me a rundown on what the official app lets you do with both devices in terms of features? For example, does the official app allow you to set a timer or delayed start for a program? I might be looking for functionality that doesn’t exist.
It’s the other way round in the app ![]()
With the stove you can just read values. You cannot turn the device or individual cooking fields on with the app.
With the fridge I can set the target temperature or something like “SuperKühlen” or “SuperFrost” or some special modes.
Makes sense – remote control of the stove might have a higher potential for abuse. Let’s try the fridge then?"
With the official app, are you able to set a timer/delayed start on any of the oven’s programs?
Hi,
getting to deciphering the fault codes now. It appears your device has about 20 codes stored, including F5 (water intake valve), F6 (overtemperature), F20 (inadequate heating performance), F23 (failed to reach pyrolysis), etc. All of these appear to be valid codes, I’m just unsure if this makes sense. Have you had at least some of these issues with this oven in the past, or is this just garbage decoding?
So from brand new out of the packaging, I connected it to the wifi only and had the provisioning issue. I’ve since connected it to the app.
Yes I’ve reset the network configuration which doesn’t appear to reset the keys.
I’ve blocked the device from the internet, reset the networking, factory reset it and it still 403’s
Hi,
A device that has been provisioned will normally
broadcast its GroupID every few seconds on MDNS. So the next logical step in diagnosing this would be to record traffic to/from the device, then we can understand whether it is already provisioned. Could you record about 20 seconds or so of traffic from the device, and send me the PCAP file? Please also access the /State endpoint on the device (not on the server) and include that in the PCAP?
Also, what method did you use to connect to WiFi – my script, or WPS?
Best regards
There doesn’t appear to be a /State endpoint on the device
miele-rest:~/MieleRESTServer/helpers# curl -v 172.29.18.126:80/State
* Trying 172.29.18.126:80...
* Connected to 172.29.18.126 (172.29.18.126) port 80
* using HTTP/1.x
> GET /State HTTP/1.1
> Host: 172.29.18.126
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 404 Not Found
< Date: Mon, 12 Jan 1970 22:17:56 GMT
< Content-Length:0
< Content-Type: application/vnd.miele.v1+json; charset=utf-8
<
* Connection #0 to host 172.29.18.126 left intact
see cap here TumbleDryer.pcap
And I used your script to connect the device to Wifi
Thanks. Interesting – your device reports (in packet #6) to be provisioned with a group ID of C2DB2EC520223532. Is this the group ID you were attempting to set previously, or is this this value otherwise known to you in any way? Wondering if your device might have been a returned unit and we just haven’t figured out the correct way to clear the previous owner’s configuration.
When you do the reset process I described, does the Wi-FI configuration go away, or does nothing happen?
Regarding the /State endpoint – my bad, please try the following endpoints:
Devices/
Devices/001D63FFFEC7FE50/State
