TillFleisch / ESPHome-Philips-Smart-Coffee

ESPHome components which implement a Philips Series 2200/3200 Coffee Machine into HomeAssistant. Capable of brewing automatic coffee.
Other
162 stars 26 forks source link

Coffee machine Philips EP5444/90 5400 Series LatteGo #6

Closed DivanX10 closed 1 year ago

DivanX10 commented 1 year ago

image

23.04.2023 purchased a new Philips EP5444/90 5400 Series LatteGo coffee machine and I'm going to repeat your experience. The withdrawal of the warranty does not frighten me, I can repair it myself if something happens to it. I would like to clarify about connecting the display to the ESP8266 WeMos D1 Mini. You write about the transistor, but you did not specify which transistor to connect.

image

Which transistor should I connect? I have a TIP120 transistor

image

This is how the wiring to the display looks, just like you do, which may have a chance to control remotely. Do you think it will work?

image

Do I understand correctly that it is necessary to disconnect this cable from the display, connect some of the wires to the ESP8266 WeMos D1 Mini, and already pull the wiring from the ESP8266 WeMos D1 Mini to the connector?

nighteagle1974 commented 1 year ago

So do you cut the line from Dispaly to motherboard? That makes no sense - because you cut the communications between the two parts. Why do you think there is communication when one part is missing the other? I don't think there is only a simple do that and do this communication - it will be more like - say me what going on and then i send do that -. like water empty so i can not make coffee. If the communication is broken then they will go into error-mode or something like this and the machine make nothing - like you see. Hope you understand what i mean. It can also be there is a simple Base64 encoding for failure detect - because some characters not the same on your logging.

TillFleisch commented 1 year ago

Side note: It looks like on both sides the 5th byte (AA AA AA .. XX) is a counter. The value increase continuously but duplicates are present. I don't know why this is necessary or what the purpose of this is. The counter counts up to 0xFF and then wraps around back to 0x00.

DivanX10 commented 1 year ago

So do you cut the line from Dispaly to motherboard? That makes no sense - because you cut the communications between the two parts. Why do you think there is communication when one part is missing the other? I don't think there is only a simple do that and do this communication - it will be more like - say me what going on and then i send do that -. like water empty so i can not make coffee. If the communication is broken then they will go into error-mode or something like this and the machine make nothing - like you see. Hope you understand what i mean. It can also be there is a simple Base64 encoding for failure detect - because some characters not the same on your logging.

I specifically severed the connection between the screen and the motherboard. This was necessary in order to see what data the screen would send when the enable button was pressed, and I was also interested to find out if the screen would turn on without communication from the motherboard. As I learned by experience, the control panel will not turn on without communication with the motherboard. I also found out what bytes the control panel sends when turned on and checked these bytes when connected to the motherboard and embedded ESP32. The bytes are exactly the same as they were before I severed the connection between the screen and the motherboard.

image image

Hope you understand what i mean. It can also be there is a simple Base64 encoding for failure detect - because some characters not the same on your logging. I don't quite understand you. Try to explain in more detail and preferably with examples

DivanX10 commented 1 year ago

Side note: It looks like on both sides the 5th byte (AA AA AA .. XX) is a counter. The value increase continuously but duplicates are present. I don't know why this is necessary or what the purpose of this is. The counter counts up to 0xFF and then wraps around back to 0x00.

Do you have any thoughts on what kind of command you can send? Can you give me a few command options and I'll try, but what if it works? )

TillFleisch commented 1 year ago

Maybe convincing the mainboard to turn on requires multiple messages. Can you try to run a little replay attack? Send the two messages: AA AA .... 40 55 follwed by AA AA .... E6 55. from this image Wait for the mainboard to respond with AA AA .. 40 55. from this image Send the response from the display AA AA .... E0 55.

Sending this sequence multiple times may not work due to the counter. Maybe the mainboard keeps track. Removing power in-between attempts may be necessary.

What happens if you send the first two messages from the image above? If the mainboard sends an answer, that is probably a good thing. The display unit may not respond to this answer as it has not been turned on via the button. There is a similar problem on the EP2220. If the machine is turned on via command injection the mainboard turns on, but the communication stops as the display is responsibe for requesting updates (if I remember correcly). Removing the power shortly from the display tricks it into booting and subsequently requesting updates.

DivanX10 commented 1 year ago

Maybe convincing the mainboard to turn on requires multiple messages. Can you try to run a little replay attack? Send the two messages: AA AA .... 40 55 follwed by AA AA .... E6 55. from this image Wait for the mainboard to respond with AA AA .. 40 55. from this image Send the response from the display AA AA .... E0 55.

Sending this sequence multiple times may not work due to the counter. Maybe the mainboard keeps track. Removing power in-between attempts may be necessary.

What happens if you send the first two messages from the image above? If the mainboard sends an answer, that is probably a good thing. The display unit may not respond to this answer as it has not been turned on via the button. There is a similar problem on the EP2220. If the machine is turned on via command injection the mainboard turns on, but the communication stops as the display is responsibe for requesting updates (if I remember correcly). Removing the power shortly from the display tricks it into booting and subsequently requesting updates.

I hasten to please you, the coffee machine turned off at this command 🥳. I will try as you wrote and will definitely unsubscribe later.

  - platform: template
    name: "Turn off"
    on_press:
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0xFE, 0x00, 0x00, 0xC8, 0x87, 0x1B, 0x40, 0x55]
DivanX10 commented 1 year ago

There is a similar problem on the EP2220. If the machine is turned on via command injection the mainboard turns on, but the communication stops as the display is responsibe for requesting updates (if I remember correcly). Removing the power shortly from the display tricks it into booting and subsequently requesting updates.

Below are the working buttons for turning off and turning on the coffee machine. I can turn off the coffee machine, but I can't turn it on and it turns on exactly as you wrote. I can solder a transistor, but how do I make a switch then?

button:
  - platform: template
    name: "Turn off"
    on_press:
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0xFE, 0x00, 0x00, 0xC8, 0x87, 0x1B, 0x40, 0x55]

  - platform: template
    name: "Turn on"
    on_press:
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0xFE, 0x00, 0x00, 0xC8, 0x87, 0x1B, 0x40, 0x55]
      - delay: 1s  
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0xFF, 0x00, 0x01, 0x00, 0xAC, 0xE8, 0x5A, 0xE6, 0x55] 

This is how it starts when I click on the enable button, but then the activation process stops

image

TillFleisch commented 1 year ago

I would suggest using a momentary GPIO switch. The power-trick may not work on your machine, as the display (with the built in display) may be built differently.

DivanX10 commented 1 year ago

@TillFleisch

It's still worth a try, maybe it will work. I don't quite understand about the switch and there are questions. I'm not a programmer, so I apologize for the fact that I can't figure out how to do this correctly. Here is your component and power_pin: GPIO12 is used here. I can't turn off your component, because without it the coffee machine does not turn on at all, and the uart_mitm component is not suitable.

philips_series_2200:
  display_uart: uart_display
  mainboard_uart: uart_mainboard
  power_pin: GPIO12
  id: philip

Do I understand correctly that I can not use power_pin: GPIO12, but specify another pin, for example GPIO14? What should I do first, turn it off and then turn it on, or turn it on first and then turn it off? Did I write the code correctly? Could you write the right code?

switch:
  - platform: gpio
    pin: GPIO14
    id: switch_display
    name: "Display"
    on_turn_on:
    - delay: 500ms
    - switch.turn_off: relay

And more. I can't comment out power_pin: GPIO12, ESPHome starts reporting errors, so I can't delete it

image

DivanX10 commented 1 year ago

Connected the BS170 transistor. About the scheme in a little more detail will be below.

image image

The output voltage is +5V, so it should be image

I added a switch to control the transistor, which, in theory, should interrupt the power supply to the screen and feed it again. When we do this, we see from the logs that the coffee machine is trying to start, but this does not happen. The coffee machine does not turn on and the screen does not turn on either.

switch:
  - platform: gpio
    pin: GPIO14
    name: Display
    internal: False
    id: id_switch_display
    restore_mode: ALWAYS_ON
    on_turn_off:
    - delay: 500ms
    - switch.turn_on: id_switch_display

image

I created a button to turn on the coffee machine, through which commands are sent every 18.536000000ms, and then a command is sent to restart the display. The coffee machine does not turn on because there is no answer about the motherboard

I made a lot of different combinations for the test. Here is an example of two commands

Option 1

  - platform: template
    name: "Turn on 1"
    on_press:
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0xFE, 0x00, 0x00, 0xC8, 0x87, 0x1B, 0x40, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0x00, 0x01, 0x00, 0xAC, 0xE8, 0x5A, 0xE6, 0x55]
      - delay: !lambda "18.536 ms;"
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0x93, 0x00, 0x01, 0x01, 0x81, 0x90, 0xAD, 0xE0, 0x55]
      - delay: !lambda "18.536;"
      - switch.turn_off: id_switch_display

Option 2

  - platform: template
    name: "Turn on 2"
    on_press:
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0xFE, 0x00, 0x00, 0xC8, 0x87, 0x1B, 0x40, 0x55]
      - delay: !lambda "return 18.536;"
      - switch.turn_off: id_switch_display

Where did I get the delay of 18.536 ms? When I was taking data through a logic analyzer and viewing data through the Pulse View program, I decided to measure the time between sending a command from the screen and receiving a response from the motherboard, and this time was 18.536000000 ms

image

When we press the touch button on the coffee machine, I see the following data

The command being sent is AA:AA:AA:FE:00:00:C8:87:1B:40:55:AA:AA:AA:FF:00:01:00:AC:E8:5A:E6:55 image

Answer AA:AA:AA:FE:00:00:C8:87:1B:40:55 from the motherboard after 18.536000000 ms and after that the coffee machine turns on image

This is the data from the logs when the coffee machine is turned on from the touch button and I highlighted in red where the screen sends a command and receives a response from the motherboard, and in blue, after a successful greeting, the coffee machine turns on

image

I tried to repeat this case, but it turns out unsuccessfully, the coffee machine does not turn on, because it does not respond. When sending a command from ESPHome AA:AA:AA:FE:00:00:C8:87:1B:40:55:AA:AA:AA:FF:00:01:00:AC:E8:5A:E6:55, then there is no response from the motherboard image

Now about the scheme itself. Where did this data come from? I took it from here Motherboard diagram 1.9.30.330.00_v10.pdf

image

Based on this scheme, I redid the wiring pinout scheme. image

I decided to check the 4 wire that WakeUP, assuming that he could somehow turn on the coffee machine and decided to measure the signals through an oscilloscope and a logic analyzer, and that's what I saw.

Voltage up to 200mv is supplied only when the coffee machine is turned on, and when the coffee machine is turned off, there is no voltage

Measurement through an oscilloscope I managed to fix a signal where the voltage is applied up to 200 mv ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/6d066cfc-76b6-4a4e-8351-46ac89fc27f3) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/c5a6ec2f-581f-4b71-86ed-d2ed8ac1810b) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/8bec5931-0d77-4113-9739-9069154a062a) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/05a06cce-5f06-4f74-a663-4bc140ba72e8) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/06747bc2-f65c-46b4-a116-09074577dd12) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/92841fcd-b37d-4efb-9dc2-f73b9344fb72) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/e6d33a78-7b53-42bb-8916-c6e0f8d5345e) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/83b7c1ef-cfdf-4bf6-a1fe-b36f5e1fff6d) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/7c35d3d2-a6e6-4542-90e7-9f87a7779393)
Measurement of data through a logic analyzer As you can see, there is no data, there are only 0, which means that only voltage up to 200mv is supplied via 4 wires ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/8f21faf0-51a3-475c-a57f-545ed5274815) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/0e326949-6f76-4a0c-b8bd-57ca8b70c8f4) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/dcaadd0b-e975-4569-9346-2ed6548082a2)

In general, I can't figure out how to make the coffee machine turn on. I will be glad if you offer options on how to do this.

DivanX10 commented 1 year ago

If you do not send commands, but simply restart the screen with a switch, then this is what will happen. The coffee machine does not turn on Reloading the screen.txt


According to my observations from all logs, when we turn on the coffee machine with the touch button, it looks like this

The control panel sends the command

»»» AA:AA:AA:FE:00:00:C8:87:1B:40:55:AA:AA:AA:FF:00:01:00:AC:E8:5A:E6:55

next, the motherboard should answer us as well

««« AA:AA:AA:FE:00:00:C8:87:1B:40:55:AA:AA:AA:FF:00:01:00:AC:E8:5A:E6:55

then there is an exchange

>>> 00:AA:AA:AA:FE:00:00:C8:87:1B:40:55
<<< 00:AA:AA:AA:FE:00:00:C8:87:1B:40:55

and the final stage, after that the coffee machine starts to turn on

>>> AA:AA:AA:93:00:01:01:81:90:AD:E0:55:AA:AA:AA:93:00:01:01:81:90:AD:E0:55
<<< AA:AA:AA:93:00:01:01:81:90:AD:E0:55:AA:AA:AA:93:00:01:01:81:90:AD:E0:55
TillFleisch commented 1 year ago

Here are a couple ideas in no particular order:

Is there something happening on the RX2/TX2 lines? This could be some sort of debug port.

Where is the wake up Signal coming from? Does the Mainboard wake up the display or vice versa?

In the image where you tried to repeat the turn on commands the last one is not duplicated. Multiple copies may be necessary.

Can you verify that the transistors removes the power using you switch configuration on gpio14? This component requires a pin to be configured which is used for flipping the transistor.

The response message of the Mainboard starts after 18.5ms. Assuming the timing is always the same, you are sending the your second message at the same time at which the Mainboard is sending its first request. You should send the second message from the display after the first acknowledgement of the Mainboard has arrived entirely. The delay may be different from run to run. I would recommend waiting for the acknowledgement and then sending the second command to ensure the delay is correct.

You could also choose a larger delay (22 ms for instance). If the Mainboard isn't to picky about the timing this may work as well.

DivanX10 commented 1 year ago

Is there something happening on the RX2/TX2 lines? This could be some sort of debug port.

Judging by the scheme, this is a programmable port, I will check it and try to look through the analyzer


Where is the wake up Signal coming from? Does the Mainboard wake up the display or vice versa?

It comes from both sides, both from the screen and from the motherboard. If you break the wire, then the coffee machine turns on, so it put me in doubt that this wire makes any sense. I broke the wire and measured both from the screen and from the motherboard and they both showed the same voltage up to 200 mv


Can you verify that the transistors removes the power using you switch configuration on gpio14? This component requires a pin to be configured which is used for flipping the transistor.

Yes, it turns off the power. If I turn off the transistor, there will be no voltage and the coffee machine will not turn on through the touch button


As for the rest of the questions, they are still open, as I am going through various options for sending commands. I know that there are only 4 of them

AA:AA:AA:FE:00:00:C8:87:1B:40:55:AA:AA:AA:FF:00:01:00:AC:E8:5A:E6:55 AA:AA:AA:FE:00:00:C8:87:1B:40:55 AA:AA:AA:FF:00:01:00:AC:E8:5A:E6:55 AA:AA:AA:93:00:01:01:81:90:AD:E0:55

nighteagle1974 commented 1 year ago

If you break the wire, then the coffee machine turns on, so it put me in doubt that this wire makes any sense. I broke the wire and measured both from the screen and from the motherboard and they both showed the same voltage up to 200 mv<

So it looks like this wire is an Interrupt-Wire? Can you log this wire all the time on your Analyzer?

DivanX10 commented 1 year ago

If you break the wire, then the coffee machine turns on, so it put me in doubt that this wire makes any sense. I broke the wire and measured both from the screen and from the motherboard and they both showed the same voltage up to 200 mv<

So it looks like this wire is an Interrupt-Wire? Can you log this wire all the time on your Analyzer?

It is unlikely that we will see something with a logic analyzer, since the logic analyzer does not measure the voltage of the controlled signals, the logic analyzer shows in what state a particular node is in, in the state of logical 1 or logical 0. There are no controlled signals on the 4th wire, so it makes no sense to measure with a logic analyzer, if only with an oscilloscope to see what will happen at that moment, when the coffee machine goes into standby mode. When the coffee machine goes into standby mode, the voltage drops.

I disassembled the control panel and examined it, and also removed the sticker from the chip and found out what kind of chip. I published the details here

DivanX10 commented 1 year ago

I figured out a bit about the bytes and found the bytes responsible for the sensors of the drink counter. Here's what happened

image image

AA:AA:AA:FF:B0:01:B0:30:A5:65:E8:55 - Drinks counter (Cappuccino) - number 65 AA:AA:AA:FF:CB:01:CB:35:8A:16:77:55 - Drink counter (Latte ma.) - digit 16 AA:AA:AA:FF:2D:01:2D:6A:61:10:93:55 - Drinks counter (Hot) - digit 10 AA:AA:AA:FF:B4:01:B4:F5:C9:01:E8:55 - Drinks counter (Coffee with mo.) - digit 01 AA:AA:AA:FF:18:01:18:32:82:03:E7:55 - Drink counter (Espresso) - digit 03 AA:AA:AA:FF:36:01:36:17:E4:06:09:55 - Drinks counter (Dairy) - digit 6 AA:AA:AA:FF:23:01:23:67:61:36:7E:55 - The drinks counter (Coffee with m.) is the number 36 AA:AA:AA:FF:D1:01:D1:E9:55:C5:9B:55 - Drinks counter (Express) - digit 197 AA:AA:AA:FF:66:01:66:53:9B:D1:0E:55 - Beverage counter (America.) - digit 521 AA:AA:AA:FF:A5:01:A5:40:20:55:9F:55 - Drinks counter (Coffee) - number 55

image

Now I have another problem, I do not know how to write sensors with variables for bytes in esphome. Bytes that carry information on the coffee counter, they change as we make a cup of coffee and it is wrong to use static conditions.

Now my code looks like this

uart:
 - id: uart_display
   rx_pin: GPIO16
   tx_pin: GPIO17
   baud_rate: 115200
   stop_bits: 1
   data_bits: 8
   parity: NONE
#   rx_buffer_size: 256
#   debug:
#    direction: BOTH
#    dummy_receiver: false

 - id: uart_mainboard
   rx_pin: GPIO3
   tx_pin: GPIO1
   baud_rate: 115200
   stop_bits: 1
   data_bits: 8
   parity: NONE
   rx_buffer_size: 256
   debug:
     direction: BOTH
     dummy_receiver: false
     sequence: 
      - lambda: |-
          UARTDebug::log_hex(direction, bytes, ':');
            if (bytes[0]==0xAA && bytes[3]==0xFF && bytes[4]==0xD1 && bytes[5]==0x01 && bytes[9]==0xC5 && bytes[11]==0x55) { id(idDrinkscountEspress).publish_state("197"); }
            else if (bytes[0]==0xAA && bytes[3]==0xFF && bytes[4]==0x18 && bytes[5]==0x01 && bytes[9]==0x03 && bytes[11]==0x55) { id(idDrinkscounterEspresso).publish_state("03"); }
            else if (bytes[0]==0xAA && bytes[3]==0xFF && bytes[4]==0x23 && bytes[5]==0x01 && bytes[9]==0x36 && bytes[11]==0x55) { id(idDrinkscounterCoffeeMilk).publish_state("36"); }
            else if (bytes[0]==0xAA && bytes[3]==0xFF && bytes[4]==0xA5 && bytes[5]==0x01 && bytes[9]==0x55 && bytes[11]==0x55) { id(idDrinkscounterCoffee).publish_state("55"); }
            else if (bytes[0]==0xAA && bytes[3]==0xFF && bytes[4]==0x66 && bytes[5]==0x01 && bytes[9]==0xD1 && bytes[11]==0x55) { id(idDrinkscounterAmerica).publish_state("521"); }

text_sensor:
##### Drinks counter
#Drink counter: Espresso 1
  - platform: template
    id: idDrinkscountEspress
    name: "Espress counter"
    update_interval: 30s

#Drink counter: Espresso 2
  - platform: template
    id: idDrinkscounterEspresso
    name: "Espresso counter"
    update_interval: 30s

#Beverage Counter: Coffee
  - platform: template
    id: idDrinkscounterCoffee
    name: "Coffee Counter"
    update_interval: 30s

#Beverage counter: Coffee with milk (Coffee with m.)
  - platform: template
    id: idDrinkscounterCoffeeMilk
    name: "Coffee Counter with Milk"
    update_interval: 30s

#Drinks counter: America.
  - platform: template
    id: idDrinkscounterAmerica
    name: "Counter Americano"
    update_interval: 30s

Below I made a config with the iron-specified bits. For example bytes[9]==0xC5 is the number 197 if translated from HEX to a number. So the data bytes[7]==XX && bytes[8]==XX && bytes[9]==XX && bytes[10]==XX change here, but it needs to be displayed in the sensor as numbers

That's what GhatGPT offers me, utter nonsense. I will give examples to understand why I don't trust GhatGPT

text_sensor:
  - platform: template
    id: idDrinkscounterEspresso1
    name: "Drink counter: Espresso 1"
    update_interval: 60s
    lambda: |-
      if (id(uart_mainboard).state.length() >= 12 &&
          id(uart_mainboard).state[0] == 0xAA &&
          id(uart_mainboard).state[3] == 0xFF &&
          id(uart_mainboard).state[9] == 0xE0 &&
          id(uart_mainboard).state[11] == 0x55) {
        char byte4Str[3];
        snprintf(byte4Str, sizeof(byte4Str), "%02X", id(uart_mainboard).state[4]);
        return std::string(byte4Str);
      } else {
        return std::string("");
      }
text_sensor:
  - platform: template
    id: idDrinkscounterEspresso1
    name: "Drink counter: Espresso 1"
    update_interval: 60s
    lambda: |-
      if (bytes[0] == 0xAA && bytes[3] == 0xFF && bytes[9] == 0xE0 && bytes[11] == 0x55) {
        char byte4Str[3];
        snprintf(byte4Str, sizeof(byte4Str), "%02X", bytes[4]);
        return std::string(byte4Str);
      } else {
        return std::string("");
      }

and when you try to upload the firmware, I get this error

/config/esphome/esp32-smart-coffee-philips.yaml: In lambda function:
/config/esphome/esp32-smart-coffee-philips.yaml:135:11: error: 'bytes' was not declared in this scope
       if (bytes[0] == 0xAA && bytes[3] == 0xFF && bytes[9] == 0xE0 && bytes[11] == 0x55) {
           ^~~~~
/config/esphome/esp32-smart-coffee-philips.yaml:135:11: note: suggested alternative: 'byte'
       if (bytes[0] == 0xAA && bytes[3] == 0xFF && bytes[9] == 0xE0 && bytes[11] == 0x55) {
           ^~~~~
           byte
/config/esphome/esp32-smart-coffee-philips.yaml:142:3: warning: control reaches end of non-void function [-Wreturn-type]

   ^
*** [/data/esp32-smart-coffee-philips/.pioenvs/esp32-smart-coffee-philips/src/main.cpp.o] Error 1
========================== [FAILED] Took 7.20 seconds ==========================
DivanX10 commented 1 year ago

I managed to partially decrypt the protocol. I found almost all the sensors and they work.

image

I wrote the code as best I could, I can't do more, since I don't know these lambdas and I can't use custom sensors. Those interested can use this data and write a working project. You can read how I decoded the protocol here. I tried to describe in detail how to search for the necessary bytes

Function Description

AA:AA:AA:83 - at the moment it is unclear what it is AA:AA:AA:91 - at the moment it is unclear what it is AA:AA:AA:93 - at the moment it is unclear what it is AA:AA:AA:B0 - sensors of water container, tray, coffee grounds, coffee preparation statuses AA:AA:AA:B5 - counters for making coffee and milk drinks AA:AA:AA:BA - apparently service information, firmware version, date AA:AA:AA:BB - rarely comes across AA:AA:AA:FF - data from the control panel AA:AA:AA:FE - turning off the coffee machine

substitutions:
  board_name: ESP32 Smart Coffee Philips
  node_name: esp32-smart-coffee-philips

esphome:
  name: ${node_name}
  friendly_name: esp32-smart-coffee-philips
  comment: ESP32 Smart Coffee Philips

esp32:
  board: esp32dev
  framework:
    type: arduino

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: on
  reboot_timeout: 10min
  ap:
    ssid: ESP SmartCoffeePhilips
    password: !secret ap_esp_password

captive_portal:

web_server:
  port: 80

logger:
  level: DEBUG
  baud_rate: 0

ota:
  password: "esphome"

api:
  encryption:
    key: !secret api_key

external_components:
  - source: github://TillFleisch/ESPHome-Philips-Smart-Coffee@main

uart:
 - id: uart_mainboard
   rx_pin: GPIO3
   tx_pin: GPIO1
   baud_rate: 115200
   stop_bits: 1
   data_bits: 8
   parity: NONE
   rx_buffer_size: 256
   debug:
     direction: TX
     dummy_receiver: false

 - id: uart_display
   rx_pin: GPIO16
   tx_pin: GPIO17
   baud_rate: 115200
   stop_bits: 1
   data_bits: 8
   parity: NONE
   rx_buffer_size: 256
   debug:
     direction: TX
     dummy_receiver: false
     sequence: 
      - lambda: |-
          UARTDebug::log_hex(direction, bytes, ':');
          //AA:AA:AA:B0
          if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[6]==0x06 && bytes[9]==0x00) { 
            id(idWater).publish_state("There is water");
            id(idCoffeeGroundsContainer).publish_state("Inserted");
            id(idMakingCoffee).publish_state("Choose a drink");
            }
          //AA:AA:AA:B0 "Took out the container with water"
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[6]==0x0E && bytes[9]==0x40) { id(idWater).publish_state("There is no water"); }
          //AA:AA:AA:B0 "Removed the pallet"  
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[6]==0x0E && bytes[9]==0x80) { id(idCoffeeGroundsContainer).publish_state("Retrieved"); }

          //AA:AA:AA:B0 "The pallet and the container with water were taken out"
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[6]==0x0E && bytes[9]==0xC0) { 
            id(idWater).publish_state("There is no water"); 
            id(idCoffeeGroundsContainer).publish_state("Retrieved");
            }

          //AA:AA:AA:B0 "Making coffee"
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x0C && bytes[7]==0x01) { id(idMakingCoffee).publish_state("Enjoy (01)"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x07 && bytes[7]==0x0E) { id(idMakingCoffee).publish_state("Pause (0E)"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x07 && bytes[7]==0x0D) { id(idMakingCoffee).publish_state("Grinding grains (0D)"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x07 && bytes[7]==0x10) { id(idMakingCoffee).publish_state("Pour milk (10)"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x07 && bytes[7]==0x11) { id(idMakingCoffee).publish_state("Pour coffee (11)"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x07 && bytes[7]==0x12) { id(idMakingCoffee).publish_state("12"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x07 && bytes[7]==0x13) { id(idMakingCoffee).publish_state("Creating pressure for milk (13)"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x07 && bytes[7]==0x14) { id(idMakingCoffee).publish_state("14"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB0 && bytes[5]==0x07 && bytes[6]==0x07 && bytes[7]==0x15) { id(idMakingCoffee).publish_state("15"); }

          //AA:AA:AA:B5 "Status 1"
          if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 && bytes[10]==0x00 && bytes[11]==0x00) { id(idStatusUnknown1).publish_state("00"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 && bytes[10]==0x00 && bytes[11]==0x0B) { id(idStatusUnknown1).publish_state("0B"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 && bytes[10]==0x00 && bytes[11]==0xE6) { id(idStatusUnknown1).publish_state("E6"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 && bytes[10]==0x00 && bytes[11]==0x80) { id(idStatusUnknown1).publish_state("80"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 && bytes[10]==0x00 && bytes[11]==0xCB) { id(idStatusUnknown1).publish_state("CB"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 &&& bytes[10]==0x00 & bytes[11]==0xFF) { id(idStatusUnknown1).publish_state("FF"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 && bytes[10]==0x00 && bytes[11]==0xA0) { id(idStatusUnknown1).publish_state("A0"); }

          //AA:AA:AA:B5 "Status 2"
          else if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 && bytes[10]==0x00) { id(idStatusUnknown2).publish_state("00"); }
          else if (bytes[0]==0xAA && bytes[3]==0xB5 && bytes[5]==0x06 && bytes[10]==0x01) { id(idStatusUnknown2).publish_state("01"); }

philips_series_2200:
  display_uart: uart_display
  mainboard_uart: uart_mainboard
  power_pin: GPIO12
  id: philip

text_sensor:
  - platform: template
    id: idWater
    name: "Water"
    update_interval: 10s

  - platform: template
    id: idCoffeeGroundsContainer
    name: "Coffee Grounds Container"
    update_interval: 10s

  - platform: template
    id: idUnknown
    name: "Unknown"
    update_interval: 10s

  - platform: template
    id: idStatusCoffee
    name: "Status Coffee"
    update_interval: 10s

  - platform: template
    id: idMakingCoffee
    name: "Stages of coffee preparation"
    update_interval: 10s

button:
  - platform: restart
    name: Restart
    icon: mdi:restart

  - platform: template
    name: "Turn off" 
    on_press:
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0xFE, 0x00, 0x00, 0xC8, 0x87, 0x1B, 0x40, 0x55] #AA:AA:AA:FE:00:00:C8:87:1B:40:55
DivanX10 commented 1 year ago

Hooray 🥳, I found how to operate a coffee machine. To make coffee, we look in the logs for the address and functions that are listed below, this is the command to start making coffee. Start recording in the log, select the parameters we need (strength, amount of water, number of cups) to make coffee and run, then we find the command in the logs. Why is that? Because then we run what we set in the settings, so you can create a lot of different scripts with different parameters.

AA AA AA 93 
AA AA AA 90 
AA AA AA 91

The commands must go strictly in this order, although they may be scattered in the logs, but in ESPHome we specify in this sequence

AA AA AA 93 07 01 01 04 86 E2 E5 55 
AA AA AA 90 08 0A 00 02 00 02 03 00 1E 00 00 00 98 80 81 70 55
AA AA AA 91 09 01 03 A9 02 7B AB 55
This is how the commands in the logs look like ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/ac08cb0b-9ae9-4599-8a4a-9269c4a11ded) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/33559199-561f-4c89-8672-57e574f1d5c3) ![image](https://github.com/TillFleisch/ESPHome-Philips-Smart-Coffee/assets/64090632/f03e55e1-2104-47a9-880e-aed867c12c5d)

Example of a button to run a command from a log in ESPHome

button:
  - platform: template
    name: "Espresso X1" 
    on_press:
      - uart.write:
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0x93, 0x07, 0x01, 0x01, 0x04, 0x86, 0xE2, 0xE5, 0x55]
      - uart.write:    
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0x90, 0x08, 0x0A, 0x00, 0x02, 0x00, 0x02, 0x03, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x98, 0x80, 0x81, 0x70, 0x55]
      - uart.write:    
          id: uart_mainboard
          data: [0xAA, 0xAA, 0xAA, 0x91, 0x09, 0x01, 0x03, 0xA9, 0x02, 0x7B, 0xAB, 0x55]
Sandst4 commented 9 months ago

@DivanX10 Thanks for your awesome work! I've just received my 5400 and can't wait to connect everything. I appreciate the work you have put into the 3d print for a part that will keep the cleaning water away from the cup. However, I was wondering if you ever tried to capture the command that is send from the control panel to the main board when the on button is pressed not to long after a shutdown. Since if the temperature is still high the machine will startup without a cleaning cycle.

If I understand correctly from @TillFleisch this works for the 2200 version. I've tested and if I turn the 5400 on after waiting not to long after a shutdown it will indeed start without a cleaning cycle, so this should be possible. Would be great if you could help. I'm still waiting for some parts before I can connect everything but do appreciate your feedback/insights,

Thanks!

DivanX10 commented 9 months ago

Thanks for your awesome work! I've just received my 5400 and can't wait to connect everything. I appreciate the work you have put into the 3d print for a part that will keep the cleaning water away from the cup. However, I was wondering if you ever tried to capture the command that is send from the control panel to the main board when the on button is pressed not to long after a shutdown. Since if the temperature is still high the machine will startup without a cleaning cycle.

I have tried many times to find a way to turn on the coffee machine remotely without using a relay to turn on the coffee machine. Then I was helped with this question by a person who is well versed in electronics and he is also a C++ programmer. He wrote the code to control the coffee machine and thanks to him a project appeared.

https://community.home-assistant.io/t/esp-smart-offee-machine-philips-5400-series/568545/35?u=divanx10

I was offered this connection option, but I didn't try it, because I made the relay before I met him and before he offered me this option https://community.home-assistant.io/t/esp-smart-offee-machine-philips-5400-series/568545/86?u=divanx10

Sandst4 commented 9 months ago

Thanks! I'll give it a try once all parts have arrived

DivanX10 commented 9 months ago

Thanks! I'll give it a try once all parts have arrived

If you manage to turn on/off remotely and save the operation of the touch button of the coffee machine, let me know

Sandst4 commented 9 months ago

I'm connecting an ESP32 using the below mentioned diagram as mentioned on this project with an IRLZ44N Mosfet. Of course the gpio pins are different.

image

The code you (@DivanX10 ) have for power on and off at the moment (for the 5400) is this:

#Turn on the coffee machine
  - platform: template
    name: "Power ON"
    icon: mdi:power
    on_press:
      - switch.turn_on: idRelaySwitch
      - delay: 1s
      - switch.turn_off: idRelaySwitch

#Turn off the coffee machine
  - platform: template
    name: "Power OFF"
    icon: mdi:power
    on_press:
      #Turn on the relay
      - switch.turn_on: idRelaySwitch
      #Delay of 2 seconds
      - delay: 2s
      #Turn off the relay
      - switch.turn_off: idRelaySwitch

#Additional switch-off button of the coffee machine, in case it does not turn off via the main switch-off button
  - platform: template
    name: "Power OFF AA:FE"
    icon: mdi:power
    on_press:
      #We send a command to turn off the coffee machine
      - lambda: |-
          {
            uint8_t data[]={0xFE,0,0};
            id(philip)->send_packet_main(data,3);
          }

I need to change the power on to send the packets with and without cleaning cycle. For this project (the 2200) the code used is this (written bij @TillFleisch ):

            void Power::write_state(bool state)
            {
                if (state)
                {
                    // Send pre-power on message
                    for (unsigned int i = 0; i <= MESSAGE_REPETITIONS; i++)
                        mainboard_uart_->write_array({0xD5, 0x55, 0x0A, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0E, 0x12});

                    // Send power on message
                    if (cleaning_)
                    {
                        // Send power on command with cleaning
                        for (unsigned int i = 0; i <= MESSAGE_REPETITIONS; i++)
                            mainboard_uart_->write_array({0xD5, 0x55, 0x02, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x38, 0x15});
                    }
                    else
                    {
                        // Send power on command without cleaning
                        for (unsigned int i = 0; i <= MESSAGE_REPETITIONS; i++)
                            mainboard_uart_->write_array({0xD5, 0x55, 0x01, 0x01, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x25, 0x27});
                    }

                    mainboard_uart_->flush();

                    // Perform power trip (invert state twice)
                    power_pin_->digital_write(!power_pin_->digital_read());
                    delay(power_trip_delay_);
                    power_pin_->digital_write(!power_pin_->digital_read());
                }
                else
                {
                    // Send power off message
                    for (unsigned int i = 0; i <= MESSAGE_REPETITIONS; i++)
                        mainboard_uart_->write_array({0xD5, 0x55, 0x00, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00, 0x00, 0x1D, 0x3B});
                    mainboard_uart_->flush();
                }

                // The state will be published once the display starts sending messages
            }

TillFleisch states the following on how he found the startup with and without cleaning commands:

I found out about the cleaning/non-cleaning power-on by logging the communication using the UART debug functionality. The machine skips the cleaning cycle, if it has been pre-heated recently (the display unit issues the command, therefore it also decides when to perform cleaning).

@DivanX10 Could you help me in the right direct how to implement this for the 5400 in your code? How would you go on finding these packets for startup without cleaning since the 5400 seems to have a different protocol? I don't mind testing it out if you could help with finding the command and giving an example on how to adjust your power on/off code.

Thanks!

DivanX10 commented 9 months ago

I described all my actions on the Home Assistant forum. He also showed how to decrypt the protocol. I described in detail all the protocols on the ESP Philips 5400. You will not be able to turn it on via mosfet and this method is not suitable for the 5400. To wake up the coffee machine, you must first apply voltage to the chip, and after the processor wakes up, it begins to communicate with the motherboard. When we pull the mosfet, we wake up the motherboard, but the chip itself continues to sleep and the coffee machine does not turn on.

I used this code for a relay to simulate pressing a touch button. I empirically determined the time to turn on and off the coffee machine. If you touch the touch button that turns on the coffee machine with your finger and hold it for more than 2 seconds, it will reset to default settings; if you hold it for 1 second, it turns on; if you hold it for 2 seconds, it turns off.

#Turn on the coffee machine
  - platform: template
    name: "Power ON"
    icon: mdi:power
    on_press:
      - switch.turn_on: idRelaySwitch
      - delay: 1s
      - switch.turn_off: idRelaySwitch

#Turn off the coffee machine
  - platform: template
    name: "Power OFF"
    icon: mdi:power
    on_press:
      #Turn on the relay
      - switch.turn_on: idRelaySwitch
      #Delay of 2 seconds
      - delay: 2s
      #Turn off the relay
      - switch.turn_off: idRelaySwitch
Sandst4 commented 9 months ago

@DivanX10 Thanks for the quick reply. I have missed that information while reading through your posts. I might go experimenting a bit with it in January. In the mean time, using the relay switch will that break the manual usage of the power button? Or can you still use the power button as normal after implementing that?

Thanks!

DivanX10 commented 9 months ago

@DivanX10 Thanks for the quick reply. I have missed that information while reading through your posts. I might go experimenting a bit with it in January. In the mean time, using the relay switch will that break the manual usage of the power button? Or can you still use the power button as normal after implementing that?

Thanks!

I can't turn on the coffee machine via a physical button. Having soldered a wire to a resistor R110 with a nominal value of 4.7 kOhm, I inadvertently tore off the resistor along with the track. Somehow I managed to restore the track and solder a softer wire. I damaged resistor R110, so I replaced it with another 10 kOhm one that I had on hand. I'm not very good at soldering and I'm afraid of ruining everything again. That's why I don't want to touch the board. I was offered a scheme where you can keep the physical button working and at the same time be able to turn it on remotely, but this is in theory, and I have not tested it, and no one has yet unsubscribed whether this scheme works or not. So I don't know. The diagram can be found here

Stenan11 commented 5 months ago

изображение

23.04.2023 приобрел новую кофемашину Philips EP5444 /90 серии 5400 LatteGo и собираюсь повторить ваш опыт. Отзыв гарантии меня не пугает, я могу отремонтировать ее сам, если с ней что-то случится. Я хотел бы уточнить насчет подключения дисплея к ESP8266 WeMos D1 Mini. Вы пишете о транзисторе, но не указали, какой транзистор подключать.

изображение

Какой транзистор мне следует подключить? У меня есть транзистор TIP120

изображение

Вот так выглядит проводка к дисплею, как у вас, которым можно управлять удаленно. Как вы думаете, это сработает?

изображение

Правильно ли я понимаю, что необходимо отсоединить этот кабель от дисплея, подсоединить часть проводов к ESP8266 WeMos D1 Mini и уже подсоединить проводку от ESP8266 WeMos D1 Mini к разъему?

IMG_20240324_225532 Й

Stenan11 commented 5 months ago

![Uploading IMG_20240324_225532.jpg…]() Привет 👋

DivanX10 commented 5 months ago

1) A transistor is not needed here at all 2) ESP8266 WeMos D1 Mini is rather weak and will not cope with fast data processing, since the protocol involves a counter. ESP32 only 3) Cut the wire in the middle so that it is convenient to solder the wires and extend them to connect to the ESP32 4) You can view the finished project here


1) Транзистор здесь не нужен вообще 2) ESP8266 WeMos D1 Mini слабоват, не справится с быстрой обработкой данных, так как в протоколе задействован счетчик. Только ESP32 3) Провод разрезать по середине, чтобы удобно было подпаять провода и нарастить их для подключения к ESP32 4) С готовым проектом можете ознакомиться здесь

Stenan11 commented 3 months ago

Привет 👋Screenshot_20240602_142151.png

Что?

DivanX10 commented 3 months ago

I don't know what kind of connector it is. You can try to find out what kind of connector it is from a PHILIPS service center or contact PHILIPS technical support if they tell you, but, as usual, PHILIPS will recommend contacting a service center, and the service center is unlikely to tell you what kind of connector it is.

image

TillFleisch commented 3 months ago

The more interesting "connector"/pads would be the one on the left labeled TX/RX/GND/5V. Could be a debugging/programming port for some chip on the PCB. Maybe, this can provide more fine-grained access.