Skip to the content
PCBKitNew board
2 layers33.5 × 20 mmJURA WiFi Dongle, the printed circuit board in 3D

C++ JURA protocol implementation for controlling a Jura coffee maker over a serial (UART) connection.

Size
33.5 × 20 mm
Copper layers
2
Thickness
1.6 mm
Parts
31
Nets
62
Pads
145
Tracks, vias
54, 3
Routed
Yes
KiCad
KiCad 7 (file 20221018)
Created
25 Feb 2021
Updated
20 Mar 2023

Overview

JURA WiFi Dongle is an open-source printed circuit board by Jutta-Proto, from the Jutta-Proto/protocol-cpp repository on GitHub, published under the GPL-3.0 licence. It is a 2-layer board of 33.5 × 20 mm with 31 parts on 62 nets, routed with 54 tracks and 3 vias.

It is built around the ESP32-WROOM-32D, ICL7667CPA+ and TSAL4400. Its parts include 15 resistors, 9 capacitors, 3 ICs, 1 diode and 1 connector. It belongs with the interfaces and adapters and radio and wireless boards and the ESP32 boards of this library.

Main components

3

README

README.md

JURA Protocol

C++ JURA protocol implementation for controlling a Jura coffee maker over a serial (UART) connection.

This work is based on the excellent work done by the people over at Protocol JURA. They were able to figure out the basic protocol used for communication with older JURA coffee makers.

Since newer models do not use this old V1-Protocol any more I started this project to understand the new one and create a reference implementation for it.

Table of Contents

  1. Example
  2. Protocol
  3. JURA Commands
  4. Requirements
  5. Building

Example

The following example shows the interaction with a JURA coffee maker over XMPP. The complete implementation for this demo can be found here. Watch the video

Protocol

General

There are several steps of obfuscation being done by the JURA coffee maker to prevent others from reading the bare protocol.

Connecting to an JURA coffee maker

To connect to an JURA coffee maker we are using a 5V UART signal with the following configuration:

  • Baud Rate: 9600
  • Data Bits: 8
  • Parity: Disabled
  • Stop Bits: 1
  • Flow Control: Hardware flow control disabled
  • RX Flow Control Threshold: 0
Deobfuscating

Once a connection has been established we can start sending and receiving data.
But all data send and received is obfuscated. The following description shows how to deobfuscate data received from the coffee maker.
To obfuscate data just follow the steps in reverse.

Step 0 The coffee maker always sends 4 "raw" byte per one byte of data with a break of 8ms in between each "raw" byte. This looks something like this:

text
01011011 <8ms break> 01011111 <8ms break> 01011111 <8ms break> 01011111 <8ms break>
01011111 <8ms break> 01111011 <8ms break> 01011111 <8ms break> 01011111 <8ms break>
01111011 <8ms break> 01111011 <8ms break> 01111111 <8ms break> 01011011 <8ms break>
01011111 <8ms break> 01111111 <8ms break> 01011011 <8ms break> 01011011 <8ms break>
01111011 <8ms break> 01111011 <8ms break> 01011011 <8ms break> 01011011 <8ms break>

Each line corresponds to one actual data byte.

Step 1
Each of our 4 "raw" bytes (each line) contains only 2 bits of our resulting data bit.
Bit 2 and 5.
All other bits (except 0) are set to 1.

text
0b01011011
    ^  ^
  DB1  DB2

DB1 and DB2 are our actual data bits here. We have to combine alle 8 (of our 4 "raw" bytes) into a single data byte.

Examples:

C++
const std::array<uint8_t, 4> encData{0b01011011, 0b01011111, 0b01011111, 0b01011111};

// Bit mask for the 2. bit from the left:
constexpr uint8_t B2_MASK = (0b10000000 >> 2);

// Bit mask for the 5. bit from the left:
constexpr uint8_t B5_MASK = (0b10000000 >> 5);

uint8_t decData = 0;
decData |= (encData[0] & B2_MASK) << 2;
decData |= (encData[0] & B5_MASK) << 4;
decData |= (encData[1] & B2_MASK);
decData |= (encData[1] & B5_MASK) << 2;
decData |= (encData[2] & B2_MASK) >> 2;
decData |= (encData[2] & B5_MASK);
decData |= (encData[3] & B2_MASK) >> 4;
decData |= (encData[3] & B5_MASK) >> 2; // 0b00010101
text
Input            -> Output
0 0 0 1  0 1 0 1 -> 0 1 0 1  0 0 0 1
0 1 1 0  0 1 0 1 -> 0 1 0 1  0 1 1 0
1 0 1 0  1 1 0 0 -> 1 1 0 0  1 0 1 0
0 1 1 1  0 0 0 0 -> 0 0 0 0  0 1 1 1
1 0 1 0  0 0 0 0 -> 0 0 0 0  1 0 1 0

Step 2
In this step we switch both nibbles (4 bit) of each byte. Examples: 1100 1100 -> 0011 0011

C++
uint8_t in = 0b00010101;
uint8_t out = ((in & 0xF0) >> 4) | ((in & 0x0F) << 4); // 0b01010001
text
Input                                                                               -> Output
01011011 <8ms break> 01011111 <8ms break> 01011111 <8ms break> 01011111 <8ms break> -> 0 1 0 1  0 0 0 1
01011111 <8ms break> 01111011 <8ms break> 01011111 <8ms break> 01011111 <8ms break> -> 0 1 0 1  0 1 1 0
01111011 <8ms break> 01111011 <8ms break> 01111111 <8ms break> 01011011 <8ms break> -> 1 1 0 0  1 0 1 0
01011111 <8ms break> 01111111 <8ms break> 01011011 <8ms break> 01011011 <8ms break> -> 0 0 0 0  0 1 1 1
01111011 <8ms break> 01111011 <8ms break> 01011011 <8ms break> 01011011 <8ms break> -> 0 0 0 0  1 0 1 0

Step 3
A last time we have to shift all bits in our byte around. Here we have to split up our byte into two nibbles (4 bit) and switch two bits each.
Examples: 1100 1100 -> 0011 0011

C++
uint8_t in = 0b01010001;
uint8_t out = ((in & 0xC0) >> 2) | ((in & 0x30) << 2) | ((in & 0x0C) >> 2) | ((in & 0x03) << 2); // 0b01010100
text
Input            -> Output           -> Output_Hex Output_Dec Output_Char
0 1 0 1  0 0 0 1 -> 0 1 0 1  0 1 0 0 -> 54	84	T 
0 1 0 1  0 1 1 0 -> 0 1 0 1  1 0 0 1 -> 59	89	Y 
1 1 0 0  1 0 1 0 -> 0 0 1 1  1 0 1 0 -> 3A	58	:
0 0 0 0  0 1 1 1 -> 0 0 0 0  1 1 0 1 -> 0d	13	'\r'
0 0 0 0  1 0 1 0 -> 0 0 0 0  1 0 1 0 -> 0a	10	'\n'

Which results in the message TY:\r\n.

JURA Commands

Every message/command send from or to the coffee maker has to end with \r\n to be valid. For simplicity reasons we omit the \r\n from all of the following messages and examples.

Command Structure

In general for every valid command a response will be send from the coffee maker. The actual command is always uppercase (e.g. TY:) and the response send back is lowercase (ty:EF532M V02.03).

Available Commands

The following list of commands has been tested on an Jura E6 2019 platin (15326).

NameCommandResponseDescription
UNKNOWNAN:01ok:-
Turn offAN:02ok:Turns off the coffee maker.
Erase EPROMAN:0AUNKNOWNUntested! Erases the EPROM. Do not use.
Test UCHIAN:0Cok:Test the UCHI steam plate.
Test Mode onAN:20ok:Turns on the test mode.
Test Mode offAN:21ok:Turns off the test mode.
UNKNOWNAN:40an:40-
UNKNOWNAN:AAok:-
Get Type of MachineTY:ty: (e.g. ty:EF532M V02.03)Returns the type of the machine.
UNKNOWNFA:01ok:-
(Button 1)FA:04ok:Simulates the button 1 press (left top).
(Button 2)FA:05ok:Simulates the button 2 press (left center).
(Button 3)FA:06ok:Simulates the button 3 press (left bottom).
(Button 4)FA:07ok:Simulates the button 4 press (right top).
(Button 5)FA:08ok:Simulates the button 5 press (right center).
(Button 6)FA:09ok:Simulates the button 6 press (right bottom).
Coffee Pump onFN:01ok:Turns on the coffee pump.
Coffee Pump offFN:02ok:Turns off the coffee pump.
Coffee Heater onFN:03ok:Turns on the coffee heater.
Coffee Heater offFN:04ok:Turns off the coffee heater.
Grinder onFN:07ok:Turns on the coffee grinder.
Grinder offFN:08ok:Turns off the coffee grinder.
Brew Group Something onFN:09ok:Turns something in relation to the brew group on.
Brew Group Something offFN:0Aok:Turns something in relation to the brew group off.
Coffee press onFN:0Bok:Turns on the coffee press.
Coffee press offFN:0Cok:Turns off the coffee press.
Init Brew GroupFN:0Dok:Initializes the brew group.
Brew Group to open PostionFN:0Eok:Moves the brew group into the "open" position.
Brew Group to grinding PostionFN:0Fok:Moves the brew group into the grinding position.
Brew Group to unknown Postion XYZFN:13ok:Moves the brew group into an currently unknown position.
Brew Group to unknown Postion XYZFN:1Bok:Moves the brew group into an currently unknown position.
Brew Group to throw out position?! Postion XYZFN:1Cok:Moves the brew group into the throw out position.
Brew Group to brewing PositionFN:22ok:Moves the brew group into the brewing position.
UNKNOWNFN:24ok:-
UNKNOWNFN:25ok:-
UNKNOWNFN:26ok:-
UNKNOWNFN:27ok:-
UNKNOWNFN:44ok:-
UNKNOWNFN:45ok:-
UNKNOWNFN:50ok:-
Turn offFN:51ok:Turns off the coffee maker.
UNKNOWNFN:54ok:-
UNKNOWNFN:55ok:-
UNKNOWNFN:60ok:-
UNKNOWNFN:61ok:-
UNKNOWNFN:62ok:-
UNKNOWNFN:63ok:-
UNKNOWNFN:64ok:-
UNKNOWNFN:65ok:-
UNKNOWNFN:66ok:-
UNKNOWNFN:67ok:-
UNKNOWNFN:70ok:-
UNKNOWNFN:71ok:-
UNKNOWNFN:72ok:-
UNKNOWNFN:73ok:-
UNKNOWNFN:80ok:-
UNKNOWNFN:81ok:-
UNKNOWNFN:88ok:-
UNKNOWNFN:89ok:-
Debug mode onFN:89ku:, Ku: pause ku:, Ku:, ...Enables the debug mode. Sends continuously ku:, Ku:, ... Once an action like opening the hot water valve accrues, outputs information like percentage done. To disable it again disconnect the coffee maker from power.
UNKNOWNFN:90ok:-
UNKNOWNFN:99ok:-

Coffee Brewing Sequence

  • FN:07 # Grind on
  • Sleep 3 seconds # Determines how strong the coffee will be
  • FN:08 # Grind off
  • FN:22 # Brew group to brewing position
  • FN:0B # Coffee press on
  • Sleep 0.5 seconds # Compress the coffee
  • FN:0C # Coffee press off
  • FN:03 # Turn on the coffee water heater
  • FN:01 # Coffee water pump on
  • Sleep 2 seconds # Initial amount of water
  • FN:02 # Coffee water pump off
  • FN:04 # Turn off the coffee water heater
  • Sleep 2 seconds # Allow the water to run everywhere
  • FN:03 # Turn on the coffee water heater
  • FN:01 # Coffee water pump on
  • Sleep 40 seconds # 40 seconds of water result in 200 ml of coffee
  • FN:02 # Coffee water pump off
  • FN:04 # Turn off the coffee water heater
  • FN:0D # Reset the brew group and throw out the old coffee grain

Requirements

The following requirements are required to build this project.

  • A C++20 compatible compiler like gcc or clang
  • The build system is written using CMake
  • For managing dependencies in CMake, we are using conan

Fedora

To install those dependencies on Fedora, run the following commands:

bash
sudo dnf install -y gcc clang cmake python3 python3-pip
pip install --user conan==1.59.0 # conan 2.x.x is not supported right now

Raspberry Pi

To install those dependencies on a Raspberry Pi, running the Raspberry Pi OS, run the following commands:

bash
sudo apt install -y cmake python3 python3-pip
pip3 install --user conan==1.59.0 # conan 2.x.x is not supported right now

For all the other requirements, head over here: https://github.com/Jutta-Proto/hardware-pi#raspberry-pi-os

Building

Run the following commands to build this project:

bash
# Clone the repository:
git clone https://github.com/Jutta-Proto/protocol-cpp.git
# Switch into the newly cloned repository:
cd protocol-cpp
# Build the project:
mkdir build
cd build
cmake ..
cmake --build .

[1]: https://uk.jura.com/en/homeproducts/accessories/SmartConnect-Main-72167

Parts

31
QtyValueFootprintReferences
7CCapacitor_Tantalum_SMD:CP_EIA-1608-08_AVX-JC1, C2, C3, C4, C5, C7, C9
30Resistor_SMD:R_0201_0603MetricR7, R10, R11
3100Resistor_SMD:R_0201_0603MetricR1, R8, R9
310KResistor_SMD:R_0201_0603MetricR13, R14, R15
1131,7KResistor_SMD:R_0201_0603MetricR3
11KResistor_SMD:R_0201_0603MetricR5
12KResistor_SMD:R_0201_0603MetricR6
13,9KResistor_SMD:R_0201_0603MetricR4
1480uFCapacitor_Tantalum_SMD:CP_EIA-1608-08_AVX-JC6
17.4KResistor_SMD:R_0201_0603MetricR2
18,4 KResistor_SMD:R_0201_0603MetricR12
1CCapacitor_Tantalum_SMD:CP_EIA-1608-08_AVX-J_Pad1.25x1.05mm_HandSolderC8
1Conn_01x05_MountingPinConnector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_Vertical_SMD_Pin1RightJ1
1ESP32-WROOM-32DRF_Module:ESP32-WROOM-32U1
1GL2576-5.0TA5RPackage_TO_SOT_SMD:SOT-553U2
1ICL7667Package_TO_SOT_SMD:SOT-563U3
1SW_PushButton_Switch_SMD:SW_Push_SPST_NO_Alps_SKRKSW1
1TSAL4400LED_SMD:LED_0201_0603MetricD1

The 30 most common of 31 parts.

Questions

How big is the JURA WiFi Dongle PCB?

It measures 33.5 × 20 mm and has 2 copper layers, 1.6 mm thick.

What parts does the JURA WiFi Dongle use?

31 parts, built around the ESP32-WROOM-32D, ICL7667CPA+ and TSAL4400. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the JURA WiFi Dongle KiCad files?

From the Jutta-Proto/protocol-cpp repository on GitHub, at the commit this page was made from: the board is JURA WiFi/JURA WiFi Dongle/JURA WiFi Dongle.kicad_pcb and its schematic JURA WiFi/JURA WiFi Dongle/JURA WiFi Dongle.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the JURA WiFi Dongle design in my own project?

Its repository publishes it under the GPL-3.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

Similar boards

  • 2 layers44.6 × 53.7 mmNO2C, the printed circuit board in 3D

    NO2C

    turboedge/SpeedyBoards

    EMS boards powered by Speeduino

    88 parts110GPL-2.0
  • 2 layers105.4 × 76.5 mmDimmer, the printed circuit board in 3D

    Dimmer

    edwindertien/foundscape

    midi control of things that tap and go boink

    101 parts
  • 4 layers30 × 45 mmBbk, the printed circuit board in 3D

    Bbk

    dotcypress/bbk

    🚜 Tiny printable robot platform

    61 parts1
  • 2 layers106 × 156 mmEssaie, the printed circuit board in 3D

    Essaie

    bejaouihamza/https-github.com-bejaouihamza-IR-Interruption-Detector

    This project is a complete PCB-based system that detects interruptions between an IR emitter and receiver. When an object blocks the IR beam: - A buzzer/speaker is triggered, - A 7-segment display counter is…

    77 parts
  • 2 layers98.5 × 47 mmMedivault, the printed circuit board in 3D

    Medivault

    chislonljoseph/Medivault

    ESP32-based smart medicine storage and reminder PCB designed in KiCad 10 with complete manufacturing files and documentation.

    32 parts
  • 2 layers80.5 × 53.8 mmBlynk, the printed circuit board in 3D

    Blynk

    DynamicWhiteHat/Blynk

    A feature-rich LED controller

    110 parts
  • 2 layers155 × 129.4 mmPlane, the printed circuit board in 3D

    Plane

    julia-laine-11/plane_pcb_3d

    small project/christmas gift for my dad :)

    10 parts