ESP smart сoffee machine Philips 5400 Series

Good news

The code has been decrypted, now you can control the coffee machine. I have published the full ESP Philips 5400 Coffee Machine project here

Quick access to posts

I have never been engaged in reverse engineering and I am not a programmer and radio engineer. I invite you to take part in the reverse engineering of the Philips Series 5400 coffee machine. At the moment, I have done what I could, so far it is not possible to decrypt the data for controlling the coffee machine.

For reference. There are ready-made projects for Philips Series 2000 coffee machines

The service diagram in russian for the motherboard 1.9.30.330.00._v10 can be downloaded here. This is what I managed to find. You can translate into your language through an online translator

My created theme on the ESPHome-Philips-Smart-Coffee project


So, what do I know and what have I done?

On this board, to simplify the control circuits of the triacs and the circuit of the mains voltage transition detector through zero, the output of the power supply +5 volts of the low-voltage part is connected to one of the mains wires (contact JP4, terminal “N”), that is, the low-voltage part does not have a galvanic isolation from the mains. Be careful, do not connect the coffee machine directly to the computer via a USB cable, do not connect an oscilloscope powered by 220 volts, this will disable the coffee machine and even the computer. You can connect an oscilloscope powered by a battery. I used the FNIRSI 1013D oscilloscope

Philips Series 1000/2000/3000/5000 coffee machines are identical. They all have almost the same motherboard, but different controls.

Motherboard of the 1000/2000/3000/5000 series coffee machine


I checked the 8-wire wire with a multimeter and an oscilloscope and drew the actual circuit


Using an oscilloscope , I determined the data rate

According to the calculation, the speed is 116279 bits / s, which is very close to 115200

I used the calculation formula F = 1/T

  1. 8,6/1.000.000 = 0,0000086
  2. 1/0,0000086=116 279,0697674419 = 116279 bits / s

For debugging in ESPHome enabled UART

uart:
  rx_pin: GPIO3
  baud_rate: 115200
  stop_bits: 1
  data_bits: 8
  parity: none
  debug:
    dummy_receiver: true

I see the following data in the log and don’t understand how to decrypt it

Log entries
19:14:47	[D]	[uart_debug:114]	
<<< 12:FA:EE:41:0A:55:AA:AA:AA:FF:13:01:13:5B:B4:84:7C:55:AA:AA:AA:FF:14:01:14:7D:37:AF:E7:55:AA:AA:AA:FF:15:01:15:DC:6D:6A:91:55:AA:AA:AA:FF:16:01:16:3F:82:25:0A:55:AA:AA:AA:FF:16:01:16:3F:82:25:0A:55:AA:AA:AA:FF:17:01:17:9E:D8:E0:7C:55:AA:AA:AA:FF:18:01:18:32:82:03:E7:55:AA:AA:AA:FF:18:01:18:32:82:03:E7:55:AA:AA:AA:FF:19:01:19:93:D8:C6:91:55:AA:AA:AA:FF:19:01:19:93:D8:C6:91:55:AA:AA:AA:FF:1A:01:1A:70:37:89:0A:55:AA:AA:AA:FF:1B:01:1B:D1:6D:4C:7C:55
19:14:47	[D]	[uart_debug:114]	
<<< AA:AA:AA:FF:1C:01:1C:F7:EE:67:E7:55:AA:AA:AA:FF:1D:01:1D:56:B4:A2:91:55:AA:AA:AA:FF:1E:01:1E:B5:5B:ED:0A:55:AA:AA:AA:FF:1F:01:1F:14:01:28:7C:55:AA:AA:AA:FF:20:01:20:84:8E:79:E5:55:AA:AA:AA:FF:21:01:21:25:D4:BC:93:55:AA:AA:AA:FF:22:01:22:C6:3B:F3:08:55:AA:AA:AA:FF:23:01:23:67:61:36:7E:55:AA:AA:AA:FF:24:01:24:41:E2:1D:E5:55:AA:AA:AA:FF:25:01:25:E0:B8:D8:93:55:AA:AA:AA:FF:26:01:26:03:57:97:08:55:AA:AA:AA:FF:27:01:27:A2:0D:52:7E:55:AA:AA:AA:FF:28:01
19:14:47	[D]	[uart_debug:114]	
<<< 28:0E:57:B1:E5:55:AA:AA:AA:FF:29:01:29:AF:0D:74:93:55:AA:AA:AA:FF:2A:01:2A:4C:E2:3B:08:55:AA:AA:AA:FF:2B:01:2B:ED:B8:FE:7E:55:AA:AA:AA:FF:2C:01:2C:CB:3B:D5:E5:55:AA:AA:AA:FF:2D:01:2D:6A:61:10:93:55:AA:AA:AA:FF:2E:01:2E:89:8E:5F:08:55:AA:AA:AA:FF:2F:01:2F:28:D4:9A:7E:55:AA:AA:AA:FF:30:01:30:90:3D:E8:E4:55:AA:AA:AA:FF:31:01:31:31:67:2D:92:55:AA:AA:AA:FF:32:01:32:D2:88:62:09:55:AA:AA:AA:FF:33:01:33:73:D2:A7:7F:55:AA:AA:AA:FF:34:01:34:55:51:8C:E4:55
19:14:48	[D]	[uart_debug:114]	
<<< AA:AA:AA:FF:35:01:35:F4:0B:49:92:55:AA:AA:AA:FF:36:01:36:17:E4:06:09:55:AA:AA:AA:FF:37:01:37:B6:BE:C3:7F:55:AA:AA:AA:FF:38:01:38:1A:E4:20:E4:55:AA:AA:AA:FF:39:01:39:BB:BE:E5:92:55:AA:AA:AA:FF:3A:01:3A:58:51:AA:09:55:AA:AA:AA:FF:3B:01:3B:F9:0B:6F:7F:55:AA:AA:AA:FF:3C:01:3C:DF:88:44:E4:55:AA:AA:AA:FF:3D:01:3D:7E:D2:81:92:55:AA:AA:AA:FF:3E:01:3E:9D:3D:CE:09:55:AA:AA:AA:FF:3F:01:3F:3C:67:0B:7F:55:AA:AA:AA:FF:40:01:40:FC:24:1C:E0:55:AA:AA:AA:FF:41:01
19:14:48	[D]	[uart_debug:114]	
<<< 41:5D:7E:D9:96:55:AA:AA:AA:FF:42:01:42:BE:91:96:0D:55:AA:AA:AA:FF:43:01:43:1F:CB:53:7B:55:AA:AA:AA:FF:44:01:44:39:48:78:E0:55:AA:AA:AA:FF:45:01:45:98:12:BD:96:55:AA:AA:AA:FF:46:01:46:7B:FD:F2:0D:55:AA:AA:AA:FF:47:01:47:DA:A7:37:7B:55:AA:AA:AA:FF:48:01:48:76:FD:D4:E0:55:AA:AA:AA:FF:49:01:49:D7:A7:11:96:55:AA:AA:AA:FF:4A:01:4A:34:48:5E:0D:55:AA:AA:AA:FF:4B:01:4B:95:12:9B:7B:55:AA:AA:AA:FF:4C:01:4C:B3:91:B0:E0:55:AA:AA:AA:FF:4D:01:4D:12:CB:75:96:55
19:14:48	[D]	[uart_debug:114]	
<<< AA:AA:AA:FF:4E:01:4E:F1:24:3A:0D:55:AA:AA:AA:FF:4F:01:4F:50:7E:FF:7B:55:AA:AA:AA:FF:50:01:50:E8:97:8D:E1:55:AA:AA:AA:FF:51:01:51:49:CD:48:97:55:AA:AA:AA:FF:52:01:52:AA:22:07:0C:55:AA:AA:AA:FF:53:01:53:0B:78:C2:7A:55:AA:AA:AA:FF:54:01:54:2D:FB:E9:E1:55:AA:AA:AA:FF:55:01:55:8C:A1:2C:97:55:AA:AA:AA:FF:56:01:56:6F:4E:63:0C:55:AA:AA:AA:FF:57:01:57:CE:14:A6:7A:55:AA:AA:AA:FF:58:01:58:62:4E:45:E1:55:AA:AA:AA:FF:59:01:59:C3:14:80:97:55:AA:AA:AA:FF:5A:01
19:14:48	[D]	[uart_debug:114]	
<<< 5A:20:FB:CF:0C:55:AA:AA:AA:FF:5B:01:5B:81:A1:0A:7A:55:AA:AA:AA:FF:5C:01:5C:A7:22:21:E1:55:AA:AA:AA:FF:5D:01:5D:06:78:E4:97:55:AA:AA:AA:FF:5E:01:5E:E5:97:AB:0C:55:AA:AA:AA:FF:5F:01:5F:44:CD:6E:7A:55:AA:AA:AA:FF:60:01:60:D4:42:3F:E3:55:AA:AA:AA:FF:61:01:61:75:18:FA:95:55:AA:AA:AA:FF:62:01:62:96:F7:B5:0E:55:AA:AA:AA:FF:63:01:63:37:AD:70:78:55:AA:AA:AA:FF:64:01:64:11:2E:5B:E3:55:AA:AA:AA:FF:65:01:65:B0:74:9E:95:55:AA:AA:AA:FF:66:01:66:53:9B:D1:0E:55
19:14:49	[D]	[uart_debug:114]	
<<< AA:AA:AA:FF:67:01:67:F2:C1:14:78:55:AA:AA:AA:FF:68:01:68:5E:9B:F7:E3:55:AA:AA:AA:FF:69:01:69:FF:C1:32:95:55:AA:AA:AA:FF:6A:01:6A:1C:2E:7D:0E:55:AA:AA:AA:FF:6B:01:6B:BD:74:B8:78:55:AA:AA:AA:FF:6C:01:6C:9B:F7:93:E3:55:AA:AA:AA:FF:6D:01:6D:3A:AD:56:95:55:AA:AA:AA:FF:6E:01:6E:D9:42:19:0E:55:AA:AA:AA:FF:6F:01:6F:78:18:DC:78:55:AA:AA:AA:FF:70:01:70:C0:F1:AE:E2:55:AA:AA:AA:FF:71:01:71:61:AB:6B:94:55:AA:AA:AA:FF:72:01:72:82:44:24:0F:55:AA:AA:AA:FF:73:01
19:14:49	[D]	[uart_debug:114]	
<<< 73:23:1E:E1:79:55:AA:AA:AA:FF:74:01:74:05:9D:CA:E2:55:AA:AA:AA:FF:75:01:75:A4:C7:0F:94:55:AA:AA:AA:FF:76:01:76:47:28:40:0F:55:AA:AA:AA:FF:77:01:77:E6:72:85:79:55:AA:AA:AA:FF:78:01:78:4A:28:66:E2:55:AA:AA:AA:FF:79:01:79:EB:72:A3:94:55:AA:AA:AA:FF:7A:01:7A:08:9D:EC:0F:55:AA:AA:AA:FF:7B:01:7B:A9:C7:29:79:55:AA:AA:AA:FF:7C:01:7C:8F:44:02:E2:55:AA:AA:AA:FF:7D:01:7D:2E:1E:C7:94:55:AA:AA:AA:FF:7E:01:7E:CD:F1:88:0F:55:AA:AA:AA:FF:7F:01:7F:6C:AB:4D:79:55
19:14:49	[D]	[uart_debug:114]	
<<< AA:AA:AA:FF:80:01:80:0C:70:D7:EA:55:AA:AA:AA:FF:81:01:81:AD:2A:12:9C:55:AA:AA:AA:FF:82:01:82:4E:C5:5D:07:55:AA:AA:AA:FF:83:01:83:EF:9F:98:71:55:AA:AA:AA:FF:84:01:84:C9:1C:B3:EA:55:AA:AA:AA:FF:85:01:85:68:46:76:9C:55:AA:AA:AA:FF:86:01:86:8B:A9:39:07:55:AA:AA:AA:FF:87:01:87:2A:F3:FC:71:55:AA:AA:AA:FF:88:01:88:86:A9:1F:EA:55:AA:AA:AA:FF:89:01:89:27:F3:DA:9C:55:AA:AA:AA:FF:8A:01:8A:C4:1C:95:07:55:AA:AA:AA:FF:8B:01:8B:65:46:50:71:55:AA:AA:AA:FF:8C:01
19:14:49	[D]	[uart_debug:114]	

There is an example of how this is done, but it is not suitable for this

3 Likes

Damn ! you linked my post :relaxed:
I think … you will be able to help me more than i can help you :laughing: because i have no material more than a soldering iron, a multimeter and a console to read logs.

The link about my post is finaly about tuya compatible heater BUT :scream: I have an other heater which not works as a tuya component and :crossed_fingers: seems to have a similar MCU as yours.

The post is this one : mc96f6432Q + tywe1s how to read the doc and i finaly see in your log some Header with a similar address 0xFA is this i2c protocol ?

Pressing button on the heater permits me to recover values but i don’t know how to write to the register.

edit:
So reading more your Log it seem to reapeate the 55:AA…as header

I must have stumbled upon the necessary data. Here 's what I roughly came up with

55:AA:AA:AA:BA - this is data from the motherboard
55:AA:AA:AA:B0 - this is data from the motherboard
55:AA:AA:AA:B5 - this is data from the motherboard
55:AA:AA:AA:FF - this is data from the control panel

Previously found commands for buttons

55:AA:AA:AA:FF:07:01:07:8A:6B:71:7D - this is standby mode, do not press the buttons
55:AA:AA:AA:FF:0F:01:0F:00:B2:B9:7D - this is standby mode, do not press the buttons
55:AA:AA:AA:FF:07:01:07:B1:AD:F5 - this is the "Espresso" button
55:AA:AA:AA:FF:07:01:07:8A:AD:F5 - this is the "Espresso" button
55:AA:AA:AA:FF:07:01:90:6C:2B:F5 - this is the "Coffee" button - one serving
55:AA:AA:AA:FF:07:40:90:6C:2B:F5 - this is the "Coffee" button - a double portion

To see the data from the control panel when we press the buttons, you need to enable debugging from the motherboard

uart:
   rx_pin: GPIO13
   baud_rate: 115200
   id: uart_mainboard
   stop_bits: 1
   data_bits: 8
   parity: none
   debug:
    dummy_receiver: true

ESP8266 connection diagram for reading data from the motherboard

If we catch data from the control panel, then a lot of garbage arrives, which was thrown off earlier and the sequence was not traced. Therefore, we will comment it out or delete it

#uart:
# - rx_pin: GPIO3
#   baud_rate: 115200
#   id: uart_display
#   stop_bits: 1
#   data_bits: 8
#   parity: none
#   debug:
#    dummy_receiver: true

When I started reading data from the motherboard, I found a sequence and even probably found button commands. I made log entries several times, pressed the “Coffee” button, and every time I find this data

[02:21:57][D][uart_debug:114]: <<< 02:00:03:00:DE:26:E8:03:01:04:03:05:00:01:00:00:00:00:2B:B2:02:6D:55:AA:AA:AA:B0:32:07:06:00:00:00:00:00:64:79:92:71:4E:55:AA:AA:AA:FF:07:01:07:8A:AD:F5:55:FF:AA:AA:AA:B5:33:06:1D:00:00:00:00:00:9D:E1:20:33:55:AA:AA:AA:BA:34:18:DD:7B:01:00:EE:68:02:00:03:00:DE:12:6F:01:04:03:05:00:01:00:00:00:00:62:82:8B:A0:55:AA:AA:AA:B0:35:07:06:00:00:00:00:00:64:B0:FF:10:2A:55:AA:AA:AA:B5:36:06:1D:00:00:00:00:00:F9:EF:C0:7B:55:AA:AA:AA:BA:37:18:DD:7B:01:00:EE


If you translate the commands for the buttons into an array of bytes

Standby mode, do not press the buttons
55:AA:AA:AA:FF:07:01:07:8A:6B:71:7D = {0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0x07, 0x01, 0x07, 0x8A, 0x6B, 0x71, 0x7D}

Standby mode, do not press the buttons
55:AA:AA:AA:FF:0F:01:0F:00:B2:B9:7D = { 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0x0F, 0x01, 0x0F, 0x00, 0xB2, 0xB9, 0x7D}

The “Espresso” button
55:AA:AA:AA:FF:07:01:07:B1:AD:F5 = {0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0x07, 0x01, 0x07, 0xB1, 0xAD, 0xF5}

The “Espresso” button
55:AA:AA:AA:FF:07:01:07:8A:AD:F5 = {0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0x07, 0x01, 0x07, 0x8A, 0xAD, 0xF5}

"Coffee" button - one serving
55:AA:AA:AA:FF:07:01:90:6C:2B:F5 = {0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0x07, 0x01, 0x90, 0x6C, 0x2B, 0xF5}

The “Coffee” button is a double portion
55:AA:AA:AA:FF:07:40:90:6C:2B:F5 = {0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0x07, 0x40, 0x90, 0x6C, 0x2B, 0xF5}


How do I create a sensor so that when I press the button on the coffee machine, it displays that I have chosen Espresso or Coffee? This will be useful to check if I found the bytes correctly. If true, then when you click on the control panel, the sensor will display which button I pressed Espresso or Coffee. Can you help?

1 Like

Just for example On Tuya devices the frames are like that :
serial protocol tuya

Frame format

Field Bytes Description
Header 2 It is fixed to 0x55aa.
Version 1 It is used for updates and extensions.
Command 1 Frame type
Data length 2 Big-endian
Data N Entity data
Checksum 1 Start from the header, add up all the bytes, and then divide the sum by 256 to get the remainder.

In my case, I press all buttons 1 by 1 multiples times each, modifying sensors values when possible (like temperature sensor … ) between 2 press to be sure which values shown are always the same for one action. from that i deduce the usage of each bytes.
I Would need more datas to deduce :stuck_out_tongue:

It seems that the one whodebunk the 2200 did the same 2200 protocol

What is the identification written on the chip next to the buzzer.
And why are you taking datas between the MCU and the screen and not on some serial UART/i2c/spi port. I see a rx/tx port on the top of the board.

Watch this video of the author who was able to crack the coffee machine and decrypt the code. I repeat his experience

1 Like

I have little understanding of ESPHome and I can write something easy or use the options that are here on the forum, but there is nothing like what I need. I turned to ChatGPT and began to try everything he offered me, most of it was just useless and not working, and it kind of went, it doesn’t give an error when compiling, but it doesn’t work

- rx_pin: GPIO13
  baud_rate: 115200
  id: uart_mainboard
  stop_bits: 1
  data_bits: 8
  parity: none
  debug:
   dummy_receiver: true
   sequence:
    - lambda: |-
        UARTDebug::log_hex(direction, bytes, ':'); //The data will look like this <<< 55:AA:AA:AA:FF:07:01:90:6C:2B:F5
        std::vector<uint8_t> b {0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0x07, 0x01, 0x90, 0x6C, 0x2B, 0xF5};
        if (bytes == b)
        { 
          ESP_LOGD("custom", "Coffee Button");
        } 

This option also does not work, although the compilation was successfully completed and flooded on esp

Here is the data 55:AA:AA:AA:FF:10:01:10:B8:5B:CB:E7 which consists of 12 bytes, I specifiedbytes.size() == 12 && bytes[10] == 0x5B && bytes[11] == 0xCB && bytes[12] == 0xE7

- rx_pin: GPIO13
  baud_rate: 115200
  id: uart_mainboard
  stop_bits: 1
  data_bits: 8
  parity: none
  debug:
   dummy_receiver: true
   sequence:
      - lambda: |-
          UARTDebug::log_hex(direction, bytes, ':');
          if (bytes.size() == 12 && bytes[10] == 0x5B && bytes[11] == 0xCB && bytes[12] == 0xE7) {
            id(uart_sensor).publish_state(true);
          }

sensor:
  - platform: template
    name: "Coffee Button"
    id: uart_sensor

How do I make it so that if there are 55 in the logs:AA:AA:AA:FF:07:01:90:6 C:2B:F5, then he will publish the event in the blog?

1 Like

Datas in your log is not frame separated.
Did you try to put some delimiter un your log? Justo after ‘dummy_receiver = true’

after:
      delimiter: "\n" // or 0x55 ?

And what will append if your frame is between 2 lines of log?

I’ve tried it. The code is below, but I abandoned delimiter: [0x55, 0xAA, 0xAA, 0xFF], since it cuts after 55:AA:AA:AA:FF and empty lines remain

- rx_pin: GPIO13
  baud_rate: 115200
  id: uart_mainboard
  stop_bits: 1
  data_bits: 8
  parity: none
  debug:
   dummy_receiver: true
   after:
     timeout: 100ms
     delimiter: [0x55, 0xAA, 0xAA, 0xAA, 0xFF]
   sequence:
     - lambda: |-
          UARTDebug::log_hex(direction, bytes, ':');
          if(bytes[10]==0x71 && bytes[11]==0x7D)
            id(idButtonSensor).publish_state("Waiting (07)");
          if(bytes[10]==0xB9 && bytes[11]==0x7D)
            id(idButtonSensor).publish_state("Waiting (FF)");
          if(bytes[10]==0xFB && bytes[11]==0x90)
            id(idButtonSensor).publish_state("Waiting (05)");
          if(bytes[8]==0xB1 && bytes[9]==0xAD && bytes[10]==0xF5)
            id(idButtonSensor).publish_state("Espresso X1");
          if(bytes[8]==0x6C && bytes[9]==0x2B && bytes[10]==0xF5)
            id(idButtonSensor).publish_state("Coffee X1");
          if(bytes[8]==0x8A && bytes[9]==0xAD && bytes[10]==0xF5)
            id(idButtonSensor).publish_state("Button (8A AD)");


text_sensor:
  - platform: template
    id: idButtonSensor
    name: Sensor button coffee
    update_interval: 60s

I’m using another option. It works, but only partially. There is an expectation with different codes, but when you click on the coffee buttons, for some reason there is no record of the buttons in the logs, although there are bytes themselves. Apparently the condition and - if I have written incorrectly. I took an example from here

uart:
- rx_pin: GPIO13
  baud_rate: 115200
  id: uart_mainboard
  stop_bits: 1
  data_bits: 8
  parity: none
  debug:
   dummy_receiver: true
   sequence:
     - lambda: |-
          UARTDebug::log_hex(direction, bytes, ':'); //we specify this if we want to see debugging logs, if it is not necessary, then delete or comment out
          if (bytes[0]==0x55 && bytes[1]==0xAA && bytes[2]==0xAA && bytes[3]==0xAA && bytes[4]==0xFF) {
            if(bytes[5]==0x00 && bytes[7]==0x00 && bytes[11]==0xE6)
              id(idButtonSensor).publish_state("OFF");            
            if(bytes[8]==0xB1 && bytes[9]==0xAD && bytes[10]==0xF5)
              id(idButtonSensor).publish_state("Espresso X1");
            if(bytes[8]==0x6C && bytes[9]==0x2B && bytes[10]==0xF5)
              id(idButtonSensor).publish_state("Coffee X1");
            if(bytes[8]==0x8A && bytes[9]==0xAD && bytes[10]==0xF5)
              id(idButtonSensor).publish_state("Button (8A AD)");  
           }

text_sensor:
  - platform: template
    id: idButtonSensor
    name: Sensor button coffee
    update_interval: 60s

I created a table in Excel, it became a little clear, although I still continue to understand

I also used this source

1 Like

I understood what the problem was. The problem is that I had one sensor and the “Waiting” record was overwriting the other records, so I created a second sensor. In a good way, it will be necessary to separate the sensor state from the buttons, but I can do this when I fill the table with enough data, and now I have little data. Thanks to the status sensor, I saw that the Modes (I renamed Waiting to Mode) are changing. When you turn on the coffee machine and make coffee, the modes change and, accordingly, the commands for mode 1 are not visible if mode 3. I don’t understand the logic yet, what it is and why it happens, and it’s not yet clear why pressing the buttons is not always in the logs, as if a failure occurs and commands are not sent to the motherboard or the esp does not have time to catch them. There are a lot of questions so far.

- rx_pin: GPIO13
  baud_rate: 115200
  id: uart_mainboard
  stop_bits: 1
  data_bits: 8
  parity: none
  debug:
   dummy_receiver: true
   sequence:
    - lambda: |-
        UARTDebug::log_hex(direction, bytes, ':');
        if (bytes[0]==0x55 && bytes[1]==0xAA && bytes[2]==0xAA && bytes[3]==0xAA && bytes[4]==0xFF) {
          if (bytes[9]==0x6B && bytes[10]==0x71 && bytes[11]==0x7D) id(idSystemNum).publish_state("Mode 1");
          if (bytes[9]==0xB2 && bytes[10]==0xB9 && bytes[11]==0x7D) id(idSystemNum).publish_state("Mode 2");
          if (bytes[9]==0xDE && bytes[10]==0xFB && bytes[11]==0x90) id(idSystemNum).publish_state("Mode 3");
          if (bytes[9]==0xDE && bytes[10]==0xDD && bytes[11]==0x7D) id(idSystemNum).publish_state("Mode 4");
          if (bytes[9]==0x6B && bytes[10]==0x57 && bytes[11]==0x90) id(idSystemNum).publish_state("Mode 5");
          if (bytes[5]==0x00 && bytes[7]==0x00 && bytes[11]==0xE6) id(idButtonSensor).publish_state("OFF");
          if (bytes[8]==0xB1 && bytes[9]==0xAD && bytes[10]==0xF5) id(idButtonSensor).publish_state("Espresso X1");
          if (bytes[8]==0x6C && bytes[9]==0x2B && bytes[10]==0xF5) id(idButtonSensor).publish_state("Coffee X1");
          if (bytes[8]==0x8A && bytes[9]==0xAD && bytes[10]==0xF5) id(idButtonSensor).publish_state("Button (8A AD)");
          if (bytes[8]==0xC8 && bytes[9]==0xB7 && bytes[10]==0x90) id(idButtonSensor).publish_state("Button (С8 B7)");
          if (bytes[8]==0xCE && bytes[9]==0xB7 && bytes[10]==0x90) id(idButtonSensor).publish_state("Button (CE B7)");
        }



text_sensor:
  - platform: template
    id: idButtonSensor
    name: Sensor button coffee
    update_interval: 1s

  - platform: template
    id: idSystemNum
    name: System Number
    update_interval: 30s

I supplement the table and decorated it. On the table that is highlighted in orange, these are commands caught when the coffee machine is in mode 1, but if the coffee machine is in a different mode, then the commands are different and I don’t see them yet. For example, for Mode 3, which is green, I managed to find something and I marked them as buttons with bytes, but it is not yet clear what they are responsible for

1 Like

delimiter seems to define the end of the line it’s why you have nothing after
maybe you could set the delimiter to

55:AA:AA:AA

then test if
FF
if you want to detect datas from the control panel.

 dummy_receiver: true
 delimiter: [0x55, 0xAA, 0xAA, 0xAA]
   sequence:
    - lambda: |-
        UARTDebug::log_hex(direction, bytes, ':');
        if ( bytes[0]==0xFF) {
          if (bytes[4]==0x6B && bytes[5]==0x71 && bytes[6]==0x7D) {
             id(idSystemNum).publish_state("Mode 1");
          }
          ...
        }

I think about something. In networking world FF is the broadcast address. I feel that the control panel is the slave sending to all component on the bus waiting for the master to receive thoses datas.
In the other side BA, B0, B5, should be the address of a specific component where master “motherbord” sens specific data to specific component.

  • maybe role between slave and master is reverted i did’nt think well about that.

you did a great job but screen captures are not very usable to help you. maybe you can use some tools like privatebin, or lufi (if you have your own server better :wink: )…

This is the wrong option, since delimiter removes everything after and there will be no FF bytes, we will not be able to see the bytes we need

- rx_pin: GPIO13
  baud_rate: 115200
  id: uart_mainboard
  stop_bits: 1
  data_bits: 8
  parity: none
  debug:
   dummy_receiver: true
   after:
     delimiter: [0x55, 0xAA, 0xAA, 0xAA]
   sequence:
        - lambda: |-
            UARTDebug::log_hex(direction, bytes, ':');
            if ( bytes[0]==0xFF) {
              if (bytes[8]==0xB1 && bytes[9]==0xAD && bytes[10]==0xF5) { id(idButtonSensor).publish_state("Espresso"); }
            }

In the screenshot I show how delimiter cuts out everything that goes after 55:AA:AA:AA and we are losing bytes. Therefore, it cannot be used

If you need to search for everything after 55:AA:AA:AA:FF, then it is better to use this code. In it we indicate that if there is 55:AA:AA:AA:FF and if such bytes are still found, then report. In fact

- rx_pin: GPIO13
  baud_rate: 115200
  id: uart_mainboard
  stop_bits: 1
  data_bits: 8
  parity: none
  debug:
   dummy_receiver: true
   sequence:
    - lambda: |-
        UARTDebug::log_hex(direction, bytes, ':'); //if there is no need to output all bytes, then you can remove them from the code
        if (bytes[0]==0x55 && bytes[1]==0xAA && bytes[2]==0xAA && bytes[3]==0xAA && bytes[4]==0xFF) {
          if (bytes[8]==0xB1 && bytes[9]==0xAD && bytes[10]==0xF5) id(idButtonSensor).publish_state("Espresso");
          if (bytes[8]==0x6C && bytes[9]==0x2B && bytes[10]==0xF5) id(idButtonSensor).publish_state("Coffee");
        }

And yet, I tried to send commands in the form of buttons and it doesn’t work and I think it won’t work and you don’t even have to try. Here the principle of operation is like an air conditioner. When we press the remote control button, a command is sent in the form of packets with a set of commands. I will try to search for packages.

button:
  - platform: template
    name: "Coffee X1"
    on_press:
      - uart.write:
          id: uart_display
          data: [0x55, 0xFF, 0x6C, 0x2B, 0xF5]


  - platform: template
    name: "Espresso X1"
    on_press:
      - uart.write:
          id: uart_display
          data: [0x55, 0xFF, 0xB1, 0xAD, 0xF5]
1 Like

For convenience, I created a table with data decryption, this may help to better understand the management of the coffee machine in the future

Table of decrypted commands

Why are you trying to write to uart_display?

The ESP should function as a man-in-the-middle. All uart data should pass through it.

Like in the original project…

When you want to issue commands, you should send data to the mainboard and not to the display. (And only to the main board!)

So, can you explain how is your wiring currently?

i thought that it should be
if (bytes[**4**]==0xB1 && bytes[**5**]==0xAD && bytes[**6**]==0xF5) {
as i understand the new bytes are written on a new line and start with:

BA - this is data from the motherboard
B0 - this is data from the motherboard
B5 - this is data from the motherboard
FF - this is data from the control panel

I dont undestand you but does not matter if you find a way.

what i understant is that display send command X pressing a button then motherboard send command to actors on the bus. let me know if i’m right

Because I have connected it in parallel so far and there is a reason for that. If you cut the esp into the wiring, the control panel goes out after a few seconds, and since the commands have not yet been defined, there was no point in cutting the esp into the wiring. In addition, this method made it impossible to operate the coffee machine normally. I can’t make coffee because the screen goes off all the time. The author gave me a link to uart_mitm and I will try this option as soon as I have free time.

Now I have it connected as in this diagram. I laid out this scheme above, you can scroll up and there I also indicated the code that reads from the motherboard. I can change the rx to tx, but the control does not work. Here is written the reason why the control may not work

@rosbeefandino

I am not sure that this option will work, since I have not seen asterisks indicated, usually bytes are closed with square brackets, but not asterisks

I decided to go the other way. Search for commands not from the screen, but a complete package that sends a recipe for making coffee. The 4000/5000 series coffee machine has a touch screen and a menu display, and unlike push-button models, the control is different. Here the option will not work as with the push-button, i.e. it will simply not be possible to send a signal to press the buttons. Here, most likely, you need to send a whole package of commands, such as a recipe. That’s what I’m looking for now. Maybe I can find the complete package. What does the author of the esphome philips smart coffee project write about this

Ok, you need to clear your wording…

First of all you need to make sure which line transmits data to which direction. You should be listening for both lines and log the data together to see how is it communicates. (Timestamping each message an log it to the same file differenating the two lines.)
It doesn’t matter if it looks gibberish, but you should see that the machine does a ping/pong with messages. When something happens on the screen the machine reacts to it.

If you make a coffee first the screen will tell the machine what to do and not the opposite way around. (Unless the machine asks periodically the screen has anything changed…)

Don’t waste your time splitting up the messages, log everything.

Start with basics, turn on the machine, log it, turn off the machine, log it. Make just one kind of coffee, always the same way, log it. Log times manually when you pressed buttons, etc to have a time second reference where to look for data.

Do the same things multiple times, and log every time all the communication. And share the logs, not images.
If people can look at the logs they can help you to identify what is happening.

1 Like

@GSzabados
That’s what I did. I started recording logs, fixed the time and pressed the coffee button. Then I interrupted the recording of logs and looked through the records. Then I repeated this process many times. So I found these bytes and after checking they were repeated and confirmed by my records. Only I got hung up on bytes from the display, and now I’m going to view everything. Good. I will then write down a few logs again and post them as a text file so that you and others can view them. Now I have added a couple of screenshots above the post, as an example of how I allocate bytes for the motherboard and display. This method makes it easier for me to find the necessary bytes.

Share long logs, not just a few lines what you think might be the ones. Time stamp all the logs. And share which log represents what and how many times you repeated it.
Don’t jump to conclusions straight ahead, and don’t try to reinvent the wheel with ChatGPT.
Share what you logged and what was happening meanwhile (everything, including how the machine state changes on the screen what comes up when you press, etc with approximate timing), and after there will easy to build it up.

Start with turning on and turning off the machine. Then coffee…

And think that way, that the communication is as simple as possible, until it is proved to be not. If you think of an over complicated communication protocol, then you will loose all your time reverse engineering it. All of this stuff built on previous things and should be as simple as possible otherwise it would be hard for the programer to debug it. So simplicity is important.

And really, no pictures, the text files are always more useful for anybody. It can be easily formated and it can be cut into messages later once the basics are figured out.

PS.: You are lucky that you are building on a previous model’s knowledge. Imagine if the communication wouldn’t be uart, but something exotic, like with tue Lay-Z-Spa jacuzzis. You would have to do bitbanging to decode all the messages.