Control your Jura coffee machine

This is something I can confirm. Without the handshake the interactions are rather limited.
Therefore we started dumping the firmware from the Bluetooth Dongle. Further, we started analysing it with Ghidra. I found the handshake part, but up until now I was unable to make sense out of it.

In case someone of you wants to try looking into the firmware with Ghidra I can give you access to our Ghidra server, or send you the firmware blob itself. Just let me know here: Discussions · Jutta-Proto/protocol-cpp · GitHub and I will provide you access to it.

In case it helps someone, here is the complete handshake:

Until we get past the handshake I suggest using the BT dongle and connecting to it. There we already have a ton of commands uncovered including custom coffee, statistics, locking the coffee maker so no button presses are allowed (e.g. until you authenticate via some kind of smart card, …)

Link to the BT docs: GitHub - Jutta-Proto/protocol-bt-cpp: C++ JURA protocol implementation for controlling a Jura coffee maker over a Bluetooth connection.

hey,

tnx fort the cool work! amazing to se how far you got with the blue version of teh hack! so do you think we could build a custom component esphome that could link to the coffee maker and publish and take commands via mqtt? and i was wondering is the machine state also showing if it needs clean? bean fills?

cheers!

TLDR: Yes! GitHub - Jutta-Proto/protocol-bt-cpp: C++ JURA protocol implementation for controlling a Jura coffee maker over a Bluetooth connection.

I’m not quite done documenting everything:

you want the pins NOT connected to the jura. Flash the ESP with ONLY the computer USB connected, nothing else. And make sure you have the right device selected in the IDE

Fabi, have you found a code to return power state?
I am reading the LED state using a digital input pin but its not the most reliable thing.

Edit
Hm your setup is for the newer machines? Probably not then

sure, that is exactly how I’m trying to do it. It is by the way quite impossible to flash it while it’s inside the Jura…


% esptool.py flash_id
esptool.py v2.8
Found 3 serial ports
Serial port /dev/cu.usbserial-210
Connecting........_____....._____....._____....._____....._____....._____....._____
/dev/cu.usbserial-210 failed to connect: Failed to connect to Espressif device: Timed out waiting for packet header

it is connected, blue light is flashing on the wifi dongle.

1 Like

Hm Im not experienced enough with this setup. I had this error when in the Jura.
THis is a general flashing issue though. Essentially your computer does not see the ESP you want to flash

Weird, because any other ESP32 / Arduino / … works perfectly.

We might be off topic at this point though

is this something custom made? might be a busted solder job?
Are the pins making proper contact?

image

It’s not custom made. It’s genuine Jura and exactly the same as on that picture. It functions because I can use the J.O.E. app from Jura to control the machine through the dongle over WiFi.

Do I need to connect EN somewhere?

oh i see this is the dongle.
I think I am at the end of my rope.
If youre positive the connections are sound, then I would try pulling EN hi or lo and see if that helps

Found the problem…

Flashing the ESP 32 WROOM 32D

  • Connect the USB to UART Converter to RX, TX and ground. RX and TX should be crossed. This mean RX from the USB to UART Converter should connect to TX from the ESP 32 and TX from the USB to UART Converter should connect to RX from the ESP 32.

Thanks to ESP 32 WROOM 32D minimal connection and nice to know – MP1993

1 Like

What LED do you mean?

In case you use the BT protocol, you can get the current power state from the coffee maker, via the alters. There it says for example “power saver”, …

The device specific alerts are noted down inside the machine files, one can find inside the Android APK.

Currently I literally have a wire soldered to one of the LEDS on the front panel.
light is on - machine is on
light is off - machine is off

My machine does not officially support the bluetooth module I dont think. Its the Jura ENA Micra 1
I am using a simple ESP that communicates directly via the serial bus.
I then send commands, such as “AN:01” or “AN:02”
I would be looking for an equivalent command that returns the power state

I will dig through your code to see if you have that

I did the decoding of the machine files and found a few commands, but nothing obvious about how to return the alerts section.

What I want I have. I just have a routine that turns the state to off after an hour. Roughly correct for the auto shutoff.

1 Like

Hello together,

i have tried everythin what i can do, and for me it is not possible to connect to my Jura E8 (EB)

Normaly it is very easy installation when i see the pictures. I use an Wemos D1 mini and use external power. I have only soldered 3 wires, GND, D1 and D2. and use this esphome yaml.

Can anyone help me.

substitutions:
  devicename: jura-e8
  friendly_name: Jura E8
  device_description: Jura Kaffeemaschine in der Küche

esphome:
  name: $devicename
  comment: ${device_description}
  platform: ESP8266
  board: d1_mini
  platformio_options:
    upload_speed: 115200
  includes:
    - jura_coffee.h

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: “${friendly_name} Fallback AP"
    password: xxxxxxxxxxxxxxxxxxxx

captive_portal:

logger:
  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxxxx"

uart:
  tx_pin: D1
  rx_pin: D2
  baud_rate: 9600
  id: uart_bus

# UART bytes below have been generated with generate_esphome_jura_yaml.py
# Tested with a Jura Impressa J6

switch:
  - platform: template
    name: 'Kaffeemaschine'
    icon: "mdi:coffee-maker"
    id: jura_on_off_switch
    turn_on_action:
      - uart.write: [0xDF, 0xDB, 0xDB, 0xDF]  ## 'A'
      - delay: 8ms
      - uart.write: [0xFB, 0xFF, 0xDB, 0xDF]  ## 'N'
      - delay: 8ms
      - uart.write: [0xFB, 0xFB, 0xFF, 0xDB]  ## ':'
      - delay: 8ms
      - uart.write: [0xDB, 0xDB, 0xFF, 0xDB]  ## '0'
      - delay: 8ms
      - uart.write: [0xDF, 0xDB, 0xFF, 0xDB]  ## '1'
      - delay: 8ms
      - uart.write: [0xDF, 0xFF, 0xDB, 0xDB]  ## '\r'
      - delay: 8ms
      - uart.write: [0xFB, 0xFB, 0xDB, 0xDB]  ## '\n'

    turn_off_action:
      - uart.write: [0xDF, 0xDB, 0xDB, 0xDF]  ## 'A'
      - delay: 8ms
      - uart.write: [0xFB, 0xFF, 0xDB, 0xDF]  ## 'N'
      - delay: 8ms
      - uart.write: [0xFB, 0xFB, 0xFF, 0xDB]  ## ':'
      - delay: 8ms
      - uart.write: [0xDB, 0xDB, 0xFF, 0xDB]  ## '0'
      - delay: 8ms
      - uart.write: [0xFB, 0xDB, 0xFF, 0xDB]  ## '2'
      - delay: 8ms
      - uart.write: [0xDF, 0xFF, 0xDB, 0xDB]  ## '\r'
      - delay: 8ms
      - uart.write: [0xFB, 0xFB, 0xDB, 0xDB]  ## '\n'
    optimistic: true
    assumed_state: true

  - platform: template
    name: 'Heißes Wasser ausgeben'
    icon: "mdi:cup-water"
    id: jura_make_hot_water
    turn_on_action:
      - uart.write: [0xFB, 0xDF, 0xDB, 0xDF]  ## 'F'
      - delay: 8ms
      - uart.write: [0xDF, 0xDB, 0xDB, 0xDF]  ## 'A'
      - delay: 8ms
      - uart.write: [0xFB, 0xFB, 0xFF, 0xDB]  ## ':'
      - delay: 8ms
      - uart.write: [0xDB, 0xDB, 0xFF, 0xDB]  ## '0'
      - delay: 8ms
      - uart.write: [0xFB, 0xDF, 0xFF, 0xDB]  ## '6'
      - delay: 8ms
      - uart.write: [0xDF, 0xFF, 0xDB, 0xDB]  ## '\r'
      - delay: 8ms
      - uart.write: [0xFB, 0xFB, 0xDB, 0xDB]  ## '\n'

  - platform: template
    name: 'Kaffee machen'
    icon: "mdi:coffee"
    id: jura_make_coffee
    turn_on_action:
      - uart.write: [0xFB, 0xDF, 0xDB, 0xDF]  ## 'F'
      - delay: 8ms
      - uart.write: [0xDF, 0xDB, 0xDB, 0xDF]  ## 'A'
      - delay: 8ms
      - uart.write: [0xFB, 0xFB, 0xFF, 0xDB]  ## ':'
      - delay: 8ms
      - uart.write: [0xDB, 0xDB, 0xFF, 0xDB]  ## '0'
      - delay: 8ms
      - uart.write: [0xDF, 0xFB, 0xFF, 0xDB]  ## '9'
      - delay: 8ms
      - uart.write: [0xDF, 0xFF, 0xDB, 0xDB]  ## '\r'
      - delay: 8ms
      - uart.write: [0xFB, 0xFB, 0xDB, 0xDB]  ## '\n'

sensor:
  - platform: uptime
    name: "${friendly_name} Uptime"

  - platform: wifi_signal
    name: "${friendly_name} WiFi Signal"
    update_interval: 60s

  - platform: template
    id: num_single_espresso
    name: "Espresso zähler"
    accuracy_decimals: 0
    lambda: "return {};"

  - platform: template
    id: num_double_espresso
    name: "Doppelter Espresso zähler"
    accuracy_decimals: 0
    lambda: "return {};"

  - platform: template
    id: num_coffee
    name: "Kaffee zähler"
    accuracy_decimals: 0
    lambda: "return {};"

  - platform: template
    id: num_double_coffee
    name: "Doppelter Kaffee zähler"
    accuracy_decimals: 0
    lambda: "return {};"

  - platform: template
    id: num_clean
    name: "Reinigungsvorgänge"
    accuracy_decimals: 0
    lambda: "return {};"

text_sensor:
  - platform: version
    name: "${friendly_name} ESPHome version"
    
  - platform: template
    id: tray_status
    name: "Kaffeesatzbehälter"
    lambda: "return {};"
    
  - platform: template
    id: tank_status
    name: "Wassertank Status"
    lambda: "return {};"

binary_sensor:
  - platform: status
    name: "${friendly_name} Status"

# Custom component to poll coffee machine counters & status
custom_component:
- lambda: |-
    auto my_jura = new JuraCoffee(id(uart_bus),id(num_single_espresso),id(num_double_espresso),id(num_coffee),id(num_double_coffee),id(num_clean),id(tray_status),id(tank_status));
    App.register_component(my_jura);
    return {my_jura};

Soo just to give something back to you guys:
What commands i have discoverd so far:
//inkasso Payment system:

@I0 means init inkasso system, answer from machine @i0 (still disable)
@I1 means init payment active, answer from machine @i1
@i2:00 means start payment without price list, answer from machine @I2
@IV:81,CREDIT    3B means send text "CREDIT    " with checksum to show text on line one, answer from machine @io
@IV:82,  5.00    83 means send text "  5.00    " with checksum on line two, answer   @io
@IV:0D  from machine means request to brew button 13
@IS  from machine means brewing finishen

just mind if you mess this up, you wont be able to make any coffe until you coreclty turn it off again :wink:

//Sniff Type identification:
@DY =>@dy:TT214D V01.59F
TY: => ty:EF567M V01.03 -> Eprom verion?
//milk cooler send
@me1    means disable milk cooler comms
@mo   means Milk temprature and amount ok
@mn   means Milk missing, not ok
//bluetooth frog (state: uncertain)
@H1 (from machine to frog) means trigger disconnect, answer @h1
@HM:80 (From machine to frog) means Connection status ?, answer @HS menas success
@HY (check for dongle version), answer @hy:TT214H V05.08F
@HPD means disconnect accessorys, [@me1 milk cooler off?] answer @hpd to confirm
@HS ????

there are also lots of commands that i scrapped out of the wifi dongle firmware, but have no clue yet, what they do, feel free to experiment :wink:

@he:error
@he:ok
@hd:error
@hd:%04X
@ho:error
@ho:ok
@hb:ok
@HD:00,01,%s
@hb:abort
@hu:800
@hu:%01X%02X
@hu:abort
@hu:wait
@hu:busy
@ht
@hr:00,%04X
@hr:05,%04X
@hr:8F,%02X,%s
@hw:80
@hw:81
@hw:82
@hw:83
@hw:84
@hw:8F,%02X
@hy:TT237W V05.26
@hl:ESP32LDRSIM TT237W V05.26
@hi:SIGNATUREF02371101103F03F
@hp4
@hp5
@hp5:00
@hp5:01
@HD:00,00,%s
@hp4:%s
@hp5:02
@TS:00
@HI
@@HL
@@HY
@@HW
@T1
@t2:818811%04X0000
@t3
@TR:37
@mn:%02X%02X
@mn
@me
@me1
@mo:%02X%02X
@mo

and many more

Here you can find the instruction.