Controlling Delonghi Primadonna Elite through ST

Hey guys,

As mentioned earlier in this thread, here are the service and characteristic that you need to scan and read from:

const SERVICE = "00035b03-58e6-07dd-021a-08123a000300";
const CHARACTERISTIC = "00035b03-58e6-07dd-021a-08123a000301";

Note that you need to enable both notifications and indications for the characteristic, before writing to it.

Here are the commands I managed to intercept so far (I am using a JSON format as an example):

{
  "turn_on":                                ["0d 07 84 0f 02 01 55 12",
                                             "0d 07 84 0f 02 01 55 12",
                                             "0d 07 84 0f 02 01 55 12",
                                             "0d 07 84 0f 02 01 55 12",
                                             "0d 07 84 0f 02 01 55 12",
                                             "0d 07 84 0f 02 01 55 12"],
  "health_check":                           ["0d 05 75 0f da 25"],
  "machine_status":                         ["0d 08 95 0f 00 32 01 5d df", "0d 08 95 0f 00 3f 01 2b 83"],


  "settings_cup_lighting_on":               ["0d 0b 90 0f 00 3f 00 00 00 99 39 22"],
  "settings_cup_lighting_off":              ["0d 0b 90 0f 00 3f 00 00 00 91 b8 2a"],
  "settings_cup_warmer_on":                 ["0d 0b 90 0f 00 3f 00 00 00 b1 9c 48"],
  "settings_cup_warmer_off":                ["0d 0b 90 0f 00 3f 00 00 00 91 b8 2a"],
  "settings_energy_saving_on":              ["0d 0b 90 0f 00 3f 00 00 00 91 b8 2a"],
  "settings_energy_saving_off":             ["0d 0b 90 0f 00 3f 00 00 00 81 aa 1b"],
  "settings_beep_sound_on":                 ["0d 0b 90 0f 00 3f 00 00 00 91 b8 2a"],
  "settings_beep_sound_off":                ["0d 0b 90 0f 00 3f 00 00 00 95 f8 ae"],
  "settings_show_time":                     ["0d 08 95 0f 00 5f 03 00 eb"],
  "settings_water_hardness_1":              ["0d 0b 90 0f 00 32 00 00 00 00 0a c8"],
  "settings_water_hardness_2":              ["0d 0b 90 0f 00 32 00 00 00 02 2a 8a"],
  "settings_water_hardness_3":              ["0d 0b 90 0f 00 32 00 00 00 02 2a 8a"],
  "settings_water_hardness_4":              ["0d 0b 90 0f 00 32 00 00 00 03 3a ab"],

  "beverages_setting_a1_q20_t1":            ["0d 11 83 f0 01 00 01 00 14 02 01 08 00 00 00 05 bb fd"],
  "beverages_setting_a2_q20_t1":            ["0d 11 83 f0 01 00 01 00 14 02 02 08 00 00 00 05 75 1d"],
  "beverages_setting_a3_q20_t1":            ["0d 11 83 f0 01 00 01 00 14 02 03 08 00 00 00 05 30 bd"],
  "beverages_setting_a4_q20_t1":            ["0d 11 83 f0 01 00 01 00 14 02 04 08 00 00 00 05 f8 fc"],
  "beverages_setting_a5_q20_t1":            ["0d 11 83 f0 01 00 01 00 14 02 05 08 00 00 00 05 bd 5c"],
  
  "beverages_setting_a2_q40_t2":            ["0d 11 83 f0 01 00 01 00 28 02 02 08 00 00 00 05 22 76"],
  
  "beverage_espresso_1_a1_q20_t1":          ["0d 11 83 f0 01 01 01 00 14 02 01 08 00 00 00 06 53 d7",     "0d 08 83 f0 01 02 06 9d e1"],

  "beverage_espresso_1_a2_q40_t2":          ["0d 11 83 f0 01 01 01 00 28 02 02 08 00 00 00 06 ca 5c",     "0d 08 83 f0 01 02 06 9d e1"],
  "beverage_espresso_1_a3_q40_t2":          ["0d 11 83 f0 01 01 01 00 28 02 03 08 00 00 00 06 8f fc",     "0d 08 83 f0 01 02 06 9d e1"],
  "beverage_espresso_2":                    ["0d 11 83 f0 01 01 01 00 28 02 03 08 01 00 00 06 f9 48",     "0d 08 83 f0 01 02 06 9d e1"],
  "beverage_coffee":                        ["0d 0f 83 f0 02 01 01 00 67 02 02 00 00 06 77 ff",           "0d 08 83 f0 02 02 06 c4 b1"],
  "beverage_doppio_plus":                   ["0d 0d 83 f0 05 01 01 00 78 00 00 06 c4 7e",                 "0d 08 83 f0 05 02 06 41 21"],
  "beverage_steam":                         ["0d 0d 83 f0 11 01 09 03 84 1c 01 06 c0 7b",                 "0d 08 83 f0 11 02 06 de 82"],
  "beverage_hot_water":                     ["0d 0d 83 f0 10 01 0f 00 fa 1c 01 06 04 b4",                 "0d 08 83 f0 10 02 06 e9 b2"],
  "beverage_2_espressos":                   ["0d 0f 83 f0 04 01 01 00 28 02 02 00 00 06 ab 53",           "0d 08 83 f0 04 02 06 76 11"],
  "beverage_americano":                     ["0d 12 83 f0 06 01 01 00 28 02 03 0f 00 6e 00 00 06 47 8b",  "0d 08 83 f0 06 02 06 18 71"],
  "beverage_coffee_long":                   ["0d 0f 83 f0 03 01 01 00 a0 02 03 00 00 06 18 7f",           "0d 08 83 f0 03 02 06 f3 81"],
}

NOTES:
The packets are sent by chunks (each entry in the arrays above corresponds to one chunck). For example, the turn_on commands need to send 6 times the following packet: “0d 07 84 0f 02 01 55 12”.

For the machine_status, we need to send “0d 08 95 0f 00 32 01 5d df” followed by “0d 08 95 0f 00 3f 01 2b 83”.

Explanation about the arbitrary beverage naming I am using above (ie. beverage_espresso_1_a3_q40_t2):

  • a is for Aroma: 5 levels
  • q is for quantity: from 20 to 120ml
  • t is for temperature: 4 levels
  • espresso_1 is one cup of espresso
  • espresso_2 is two cups of espresso

I still need to figure all the other combinations! I am just short on time :sweat_smile:

Also, sending commands to the machine should be easy to do now. However, I am still figuring out the correct protocol that the machine is using. I am looking into decoding the responses coming from the machine. But it’s a little bit challenging, since De’longhi seems to be using a proprietary protocol. But I am working on it :slight_smile:

I will keep you updated here once I have more news!

Cheers.

2 Likes

@manekinekko

wow that’s a neat work. thanks.

I have a few questions:

  1. what is health check ? is it useful ?
  2. what is “machine_status” ? can we get statistics with this command ?
  3. about power on ; I just use "0d07840f02015512 " once and it works all the time.
    but you say we need to send it 6 times. why do you think so ?
  4. is there a correlation between t1-t4 and the hex codes ? so for example how can we change beverages_setting_a1_q20_t1 to beverages_setting_a1_q20_t2 ?
  5. I understand that 9th byte is for quantity (q) , is that correct ?
  6. I also see that 11th byte is for aroma level (a) , is it ?
  7. is the 13th byte for setting 2 cups ? (00 means 1 cup, 01 means 2 cups ) ?
  8. how the beverage_2_espressos and beverage_espresso_2 differs ?

Hi. Here are my assumptions (I am still trying to figure out the protocol)…

  1. the health check ping is done by the mobile app to maintain a connection with the machine, and disconnect the app if the machine is not reachable anymore. These packets are sent every 5 seconds. This is also used to monitor the status of the machine. After each ping, the machine responds with 19 bytes packets which look like this: d0 12 75 0f 01 05 00 08 00 07 00 00 00 00 00 00 00 d7 2a

De’Longhi seems to use a proprietary protocol to decode these packets. I managed to extract this information (half decoded) from the assembly code:

    MonitorDataV2:
      - AccessoryPresent      = 1
      - ActiveAlarms          = 3
      - BeverageType          = undefined
      - CoffeeInfuserPos      = 0
      - CoffeePowderQty       = -1
      - CoffeeWasteCounter    = undefined
      - DispensingPercentage  = 0
      - FunctionOngoing       = 7
      - HeaterTemp            = undefined
      - MachineModelId        = -1
      - MainBoardSwRelease    = 0
      - OnLoads               = 
      - OnSwitches            = 0,2
      - OnSwitchesToShowUser  = 
      - PressedKeys           = 
      - RequestedWaterQty     = -1
      - SteamerTemp           = undefined
      - Timestamp             = undefined
      - Type                  = 2
      - WaterFlowQty          = 10752
  1. The machine status packets are used to retrieve Parameters from the machine, which the app would use to trigger other commands (like reading the serial number, model, etc…). I guess these values are also used for the settings. I managed to decode some parts of these Parameter. The 12 bytes packets sent by the machines look like this: d0 0b 95 0f 00 3f 00 00 00 9d bb 9b
    Parameter:
      - Index             = 63
      - Value             = 0,0,0,-99
      - CountryType       = -1
      - SelectedLanguage  = -1
      - AutoOffOn         = false
      - AutoStartOn       = false
      - BuzzerOn          = true
      - CupLightOn        = true
      - CupWarmerOn       = true
      - EnergySaving      = true
      - FilterOn          = true
      - FirstStartEnabled = false
      - LanguageSet       = false
      - TimeSet24hFormat  = true
      - WriteDone         = true
  1. The mobile app does send 6 times the tun on packet. I suspect it’s because to make sure the machine receives the turn on command (BLE is not really reliable).

  2. I am still in the process of mapping all the different combinations for beverages (aroma, qty, temperature, water, milk). After which I would be able to figure the correct packets. But for the beverages_setting_aXX_qYY_t1, it seems that the 11th byte controls the aroma level and the 9th controls the quantity: 0d 11 83 f0 01 00 01 00 YY 02 XX 08 00 00 00 05 bb fd

  3. Yes

  4. Yes

  5. I need to finish the mapping and figure this out.

  6. In the ECAM65075MS machine menu, these are two different beverage IDs. beverage_2_espressos will automatically serves 2 espresso cups (in one command). beverage_espresso_2_XXYY would split 1 espresso across 2 different cups. I think that is why they have different commands.

Cheers.

1 Like

please also let us know if you find how to read stats from the machine (how many beverages made so far etc.)

Sure buddy :wink:

Hey,

If you guys want to contribute to the project, I pushed my work in progress code on my GitHub: https://github.com/manekinekko/cafy

Join me and let’s try to decode the protocol together :wink:

2 Likes

did you advance in your project ?
I checked the github page now but I am not sure if you found out how to read stats from the machine.

@manekinekko hi

did you achieve any improvement ?
I didn’t understand the “stop command” you wrote in your Github project.
What is it for ?

Hi @mrmrmrmr unfortunately, I hadn’t had time to explore the stats command.

When it comes to the stop commands, I assume you’re referring to the packet of each beverage_*, these are commands that allow you to cancel serving a beverage (the machine will stop brewing and cancel the beverage).

does that make sense?

@manekinekko

thanks. it does make sense. But in your previous explanation you had written that some beverages(or other commands) require 2 BLE packets to be sent.
Now I don’t see such explanation on your Github page.
it seems simpler now, why ?

I am sorry I didn’t mean to say two packets at the same time, as I show here in the readme file, you have to send the 1st packet to trigger the beverage, and then, if you need to, you can send the stop packet. The stop packet is somehow different for each beverage operation (I still don’t know why), that’s why there is different stop packets, one for each beverage.

@manekinekko

thanks for clarifying.

lastly, how can we change the amount of the beverage ?
for example, we want an americano bot XL size. How do we get it ?

Hey,

Here is what I managed to decode for now. So, let’s imagine that you want to have an espresso with the following settings:

  • Aroma (A): Low
  • Temperature (T): Low
  • Water Quantity (W): 20ml

Here is the packet that get sent:

0d 11 83 f0 01 01 01 00 14 02 01 08 00 00 00 06 53 d7
                        ^  ^  ^
                        |  |  |
                        W  T  A

Note: values are in hexadecimal

However, if you need to change these values, you will have to compute the CRC (last 2 octets= “53d7”). That’s my plan for the next iteration.

Let me know if you wanna help out with this work.

Cheers.

@manekinekko

thanks for clarifying that.
Actually I was hoping to have a standalone command to increase Aroma or Quantity
Like we select quantity on the machine itself then select the beverage type.

So 2 commands for a large espresso:

  1. set size to large
  2. prepare espresso

is that available ?

if not, that means we’ll have to arrange several predefined commands for each drink type that we need.
example:

  1. small espresso , low aroma
  2. mid espresso, low aroma
  3. large espresso, low aroma
  4. small espresso , mid aroma
  5. mid espresso, mid aroma
  6. large espresso, mid aroma
  7. small espresso , high aroma
  8. mid espresso, high aroma
  9. large espresso, high aroma

so it means with only quantity and aroma options, we’ll have more then 9 predefined commands for 1 drink. (actually there’s 5 aroma, 4 quantity selection , so it is 20 predefined commands)

currently I am using alexa commands to get coffee from the machine.
example:
“Alexa, prepare capuccino” -> it makes standard size, standard aroma capuccino
how can I arrange commands so that I can select quantity and aroma ?

Hey,

So there is already a command for setting beverage options. I haven’t documented it yet, but you can find a few examples in the src/commands.ts#L29-L47 file (I haven’t decoded all settings).

Basically, the packets for changing a beverage setting look like, and I’ve identified the 3 packets responsible for setting Water, Temperature, and Aroma:

0d 11 83 f0 01 00 01 00 14 02 01 08 00 00 00 05 xx xx
                        ^  ^  ^
                        |  |  |
                    Water  |  |
                 Temperature  |
                              Aroma

Also, same as my previous comment, the last 2 packets xx xx is the CRC check.

The only problem is that when sending the command to trigger the beverage, they seem to also pass the WAT settings:

0d 11 83 f0 01 01 01 00 14 02 01 08 00 00 00 06 xx xx
                        ^  ^  ^
                        |  |  |
                    Water  |  |
                 Temperature  |
                              Aroma

So to recap, if you want to set (C1) then trigger (C2) an espresso with A1, W20, and T2:

C1= 0d 11 83 f0 01 00 01 00 14 02 01 08 00 00 00 05 xx xx
C2= 0d 11 83 f0 01 01 01 00 14 02 01 08 00 00 00 06 xx xx
                   ^        ^  ^  ^              ^
                   |        |  |  |              |
                   ??       W  T  A              ??

Cheers

so it is not useful ?

TBH, I still need to figure this out. I do believe that this might be somehow useful, otherwise, I assume they would not have implemented it. There might be some sort of “global” settings to be defined before triggering a beverage?

ok. in any case, I would like to change my americano setting to a large one.
now on my implementation, I send the following command for an americano :
0d1283f0060101003202030f00640005066cb3
and it serves a standard one.
now I want to have the large size americano.
I guess , I have to change the byte with “32” to a higher setting. but , would it only increase the water amount ?
is there a way to increase coffee amount as well ?

0d1283f0060101006402030f00640005066cb3

Let’s try this command:

0d 12 83 f0 06 01 01 00 64 02 04 0f 00 64 00 05 06 23 58
                        ^     ^
                        |     |
                    Water     |
                              |
                              Aroma

If this works, you should have an Americano with 100ml (0x64) of water and a high aroma (coffee amount) (0x04).

Can you tell me if this works for you?

@manekinekko

it worked !
thanks.

now I need to find out how to make a double espresso.
For a single, I use:
0d1183f00101010028020308000005067009

For double , I had traced this one:
0d0f83f0040100050100500203060f2e

however, the latter gives more than a double when I use on my app.

what would you use for a double espresso ?