DeLonghi Magnifica now with Alexa

Introduction

I’ve have a DeLonghi Magnifica (ESAM 4200) bean-to-cup coffee machine and the most irritating part is turning it on and waiting for the cleaning cycle to complete – the unit turns on, heats up the water and then pumps a little through to make sure everything is clean.

Since getting an iKettle and being able to groggily say, ‘Alexa, turn on kettle’ in the morning to make the girlfriends tea, I’ve felt embarrassed by my stone-age coffee machine…

So, first things first, figure out what I want to achieve and the scope.

  • Turn on the machine using Alexa
  • Determine the state of the machine – is it already on?
  • No need to be able to actually make a cup. You need to be in front of the machine to place your coffee cup so doing it remotely is unnecessary
  • Machine automatically turns off after a certain amount of time so no need to turn off

The first point seems straightforward; solder a relay between the pins of the on button and call it a day. However, if you press the On button while the machine is already on, you’ll turn it off which runs another cleaning cycle. So we’ll need a method of determining the current state of the machine.

Now we know what we want, it’s time to tear apart the machine and see what we’re working with.

Tear-down

Removing side panels

The two side panels slide off easily, and the rear panel is held on with a few more screws. The top comes off, and then we have access to the front panel.

Front panel PCB – rear
Front panel PCB – front

There are two PCBs in the machine. One (power PCB) sits around the side at the rear and contains all the mains switching and intelligence, and the second (control PCB) sits up front holding the buttons and the indication LEDs.

The control panel is connected to the power board with an 8-core ribbon cable, although only 6 of the strands seems to be used. Presumably the additional 2 cores are used in a higher-end machine as there are also unpopulated areas on the power board for additional connectors and passives. Some of the other Magnifica machines use a milk tank and can automatically froth milk for a cappuccino.

Power board

The power board itself is the smarts of the operation and its brain is in the form of a PIC18LF2520 which is a 5v MCU meaning interfacing with it should be straightforward. Nearby is a ST ULN2004 seven Darlington array chip, and a HC14A Hex Schmitt-Trigger 

The PIC is powered by a LNK364GN 9W off-line switcher which provides non-isolated 5v supply. There are two relays, one ST BTB16 triac, two ST T4 3570 triacs, and a single ACS108-6S AC switch.

Functional diagram of NXP 74HC 4051

The front control board contains 8 LEDs, two potentiometers and 6 push buttons. How are they connecting this to the power board with only 4 wires? The beauty of the the NXP 74HC4051 8-channel analog multiplexer/demultiplexer. The chip uses 3 pins (S0, S1, S2) to decide which of the 8 I/O pins (Y0 – Y7) to connect to the common I/O (Z). The four wires from the power board are S0, S1, S2 and Z. The power board can now choose which of the 8 I/O it wants to write to or read from. In this setup, the Z line is only used for reading.

Functional diagram of 74HC 4094

The LEDs are connected to a NXP 74HC4094D 8-stage shift-and-store bus register. The shift register shares the S0, S1 and S2 pins with the multiplexer with S0 -> STR, S1 -> D and S2 -> CP.

Schematic

Magnifica button schematic
Magnifica LED schematic

I reverse engineered the control board schematic as above. I determined that the buttons are read using a square wave generated by QP6 and QP7 and the results are sampled by the multiplexer. QP6 and QP7 are also responsible for enabling one of two PNP transistors (Q1 and Q2). The transistors send current to the LEDs whose state is determined by the other shift register outputs.

While attempting to decipher the signals, I connected my Micsig tBook mini oscilloscope which is a battery powered touchscreen meter. Once I noticed that there were digital signals sent, I figured it’s time to break out the Saleae Logic knock-off and read all the signals at once. *POOF*, the control board no longer worked 🙁

A recreation of the fateful mistake

It seems when I connected the USB device, I managed to fry the control board. Connecting the grounds must have damaged some of the circuitry and the front panel no longer lit. Off to eBay for a new board… It appears as though ground in the Magnifica is not referenced to earth, so connecting the ground from my laptop causes a voltage potential damaging the chips on the control board.

Fortunately the power board seemed to have survived the ordeal and I continued testing.

While waiting for the new board to arrive, I wanted to confirm that the coffee machine was capable of powering a Particle Photon board. After soldering some test leads on to the front panel board, I was able to successfully power the board and confirm that power remained available even when the machine was in standby.

The Particle Photon is my preferred development board which I’ll be using here. While relatively costly, they’re much easier to use than say an ESP8266. They have WiFi, OTA, along with 5v tolerance and a REST API. All of these things can be added to an ESP8266 but it is more work than I was willing to take on.

Decoding the protocol

While waiting for the new part to arrive, I figured I could crack on with understanding the protocol used to communicate with the power board.

To save myself the embarrassment of breaking something else, I made sure my laptop was on battery power and not connected to anything with a ground (no external monitors). This allowed me to use the logic analyser with no further mishaps.

First pulse high with S0, S1 and S2 HIGH at the end

The control board sends 8 clock pulses, and alternates the first two data pulses. The ‘packet’ is finished by sending a strobe pulse. As the output enable pin is constantly held high, once the strobe pulse is sent, the outputs are enabled immediately. This process happens every 2ms.

If the first pulse is high, then QP7 will be HIGH and QP6 is LOW. This means that Q1 is active and LEDs 1, 2 and 3 can be lit by QP0, QP1 and QP2. If QP7 is LOW and QP6 is HIGH, the remaining LEDs, 5 through 9, can be controlled. Therefore the LEDs have a duty cycle of 500Hz which is much faster than the human eye can resolve.

QP7 and QP6 also send a square wave through the switch matrix. It’s interesting that the multiplexer has 8 inputs, and there are 6 buttons plus 2 pots. Why DeLonghi didn’t directly wire each of the switches and pots to it directly I don’t know. Instead, Y0, Y1, Y3 and Y4 are all connected together and half the switches are read on each part of the square wave.

Once the shift register is set, the multiplexer is read, cycling through every 4ms so it can read both halves of the switch matrix.

Because the shift register acts on a clock pulse edge, as long as the clock pulse doesn’t change while setting the S0 – 2 pins the shift register state won’t be affected. Once the S lines are set, the Z line is sampled by the MCU.

Now we know the protocol, lets try and turn the machine on!

Interfacing

Code

You can view my code here: https://go.particle.io/shared_apps/5afd6cb004e419a654000e3f

Shift register

The first step is to be able to read the LED values and derive the machines state. The Delonghi manual goes into some detail on what these LEDs mean which will be a helpful reference.

Delonghi Magnifica ESAM 4200 light description

I set the Photon up to trigger on a rising pulse from the CP line and immediately sample the D line. This gives an array of the shift register bits. A second interrupt is configured for the STR line. Once a rising interrupt occurs, the process of reading the S lines occurs.

/**
 * Get the shift register data
 */
void clockPulse() {
 data[clock_pulse] = pinReadFast(DATA_PIN);
 clock_pulse++;
}

void strobePulse() {
 clock_pulse = 0;
}

As it turns out, getting the shift register values was very easy and I now had the LED state available in my sketch.

Multiplexor

The multiplexer was a little more involved…

I had hoped that there would be a regular time between the STR line pulse finishing, and the capture of the Z line. This was not the case… The timing appears inconsistent and there wasn’t a reliable way to determine when the PIC is sampling the Z line.

All S lines HIGH after shift-register is set

Instead, I captured all of the S line patterns with my logic analyser, and there was a repeating pattern to which lines were being checked.

Signal State
S0 H L H L L H
S1 H H L L L H
S2 H H H H/L? L H
Z result Y7 Y6 Y5 Y4/Y0 Y0 Y7

For each state, the pattern is repeated, so there are 10 distinct sequences. For the sequence pairs, the shift register is changing the polarity on QP7 and QP6.

Fortunately, the triple HIGH sequence is easy to identify, so I check for this sequence with QP6 HIGH and count the remaining sequences out. The triple HIGH and QP6 HIGH becomes sequence 1. It’s pair is 2 and so on. This removes the need to sample the S lines after each CP clocking.

/**
 * Get the multiplexer data
 */
void strobePulse() {
 detachInterrupt(STROBE_PIN);
 detachInterrupt(CLOCK_PIN);
 
 sequence_number++;
 
 S0 = S1 = S2 = 0;
 for (uint8_t i = 0; i < 35; i++) {
  S0 = (pinReadFast(STROBE_PIN) || S0);
 
  if (S0 == 1) {
   S1 = (pinReadFast(DATA_PIN) || S1);
   S2 = (pinReadFast(CLOCK_PIN) || S2);
  }
 }
 
 clock_pulse = 0; // Reset clock pulse count
 strobe_pulse = 1;
}

Control

Now I know the machine state, and have the ability to tell when the PIC is sampling the Z line for a specific switch. Lets see if I can turn this thing on…

SW1 is the on/off switch, and looking at the schematic, we need to set the Z line HIGH when QP6 is HIGH and Y5 is being sampled.

1 2 3 4 5 6 7 8 9 10
QP6 H L H L H L H L H L
QP7 L H L H L H L H L H
S0 H H L L H H L L L L
S1 H H H H L L L L L L
S2 H H H H H H H H L L
Z Y7 Y7 Y6 Y6 Y5 Y5 Y4 Y4 Y0 Y0
Switch 3 6 2 5 1 4 POT1 POT1 POT1 POT1

Note: Above you can see that POT1 is sampled twice. I’m not sure why, but that is what it looks like. Y2 needs to be sampled to get the POT2 (brew strength) value. I can only assume that the machine reads it once a cup has been requested to be vended although I haven’t investigated further. Once the control panel is in place, the only signal I need to emulate is the on/off switch.

Emulating a SW1 button press

As the S lines are being read by the Photon while the Z line is being sampled by the PIC, I don’t have enough time to react to the current sequence. Instead I set the Z line up when I know the sequence is going to be repeated. So if I request SW1 to be pressed, I wait until sequence 4 and set the Z line HIGH and turn it off after sequence 5 has occurred. The Z line reverts to an input when its not outputting a value otherwise it affects the control board operation.

I let this repeat a few times so that it appears to be a human touch and not fall foul of any debounce logic in the PIC.

While there is no control board connected, I emulate the result of POT1 by setting the Z line high on sequence 7 and 8. 3.3v from the Photon should give a slightly larger than half cup. I added a push switch which would turn the machine on if off, and if on, make a cup of coffee.

Photon piggybacking on the control board

In the end, the control board was taking too long to arrive, so I purchased a new multiplexer and shift register chip, and soldering them in place. This seemed to do the trick and the board burst back into life.

Analysing the signals again, it looks like both potentiometers are being read so my decoding of the S lines must have been incorrect.

External control

I can now remotely press any of the control panel (although I only want on/off)! I added some Particle functions to allow usage with the Particle API:

`setButton` accepts an integer for the button press to emulate

`turnOn` takes no argument, and will turn on the machine if its off, otherwise the request is ignored

int turnOn(String button) {
 if (m_state == 0) { // Machine is off
  button_int = 1;
  return 2;
 }
 return 1;
}

int setButton(String button) {
 button_int = button.toInt();
 
 if (button_int < 1 || button_int > 6) {
  button_int = -1;
  return 0;
 }
 
 if (ready == 0) {
  return 0;
 } else {
  return 1;
 }
}

The final step is to determine the state and assign it on of the following names; off, busy, ready, vending, grounds full, no water, error.

Most of these are easy as they are identified by a steady light. The busy state is not so easy as its exposed to the user as alternating flashing 1 cup and 2 cup lights. To test for flashing lights, I constantly poll the LED state and add the state to a counter, along with the number of times I’ve polled. Every few seconds I check whether the LED counter is 0, equal to the total poll count, or less than the total before resetting the counters for the next run.

If it’s 0, it was off for the entire period. If it’s equal to the total, it was on for the entire period. And if its less than the total, but not 0 it was flashing.

LED 1 state LED 1 counter LED 2 state LED 2 counter LED 3 state LED 3 counter Total counter
0 0 1 1 0 0 1
1 1 1 2 0 0 2
0 1 1 3 0 0 3
1 2 1 4 0 0 4

This method isn’t full-proof; if the machine changes state between the periodic check, it’ll lead to some LEDs being marked as flashing. This means the state will be undefined (and therefore ‘error’) when the state is changing, although this isn’t normally noticeable.

I expose the machine state in a Particle variable.

Untear-down

Before we complete the project, its the hardest step; putting it back together.

I first patched the ribbon cable back together with a healthy amount of heatshrink. I figured the best place for the Photon was behind the front panel. Next to the power board may have introduced some noise and affected WiFi signal or it could fall off and short out live connections.

I made a kapton tape sarcophagus for the Photon before adding some hot glue as stand-in conformal coating. I didn’t see any need to be neat at this point so the usual spider-web glue strings are everywhere.

Alexa

I personally prefer to use the Smart Home Skill API instead of a full Alexa skill as most of the basics are covered for you. I only want to say, ‘Alexa, turn on coffee machine’ and the SHS API will do that.

Setting up an Alexa skill is somewhat out of scope of this article, but all you need to call to get the Photon to react is:

 POST https://api.particle.io/v1/devices/{device id}/turnOn?access_token={access token}

The responsive check could involve the machine state, and if it’s in an error state, mark the machine as unresponsive.

And the final result:

Thanks for reading!

5 comments on “DeLonghi Magnifica now with Alexa

  1. -

    […] Thus began [Steve]’s adventure in trying to turn the thing on with Alexa via Particle Photon. Because of the way the machine is designed, simply adding a relay wouldn’t do—the machine would just turn off and back on, only to start the self-clean again. Once inside, he found it’s controlled by a PIC18LF2520. Further research indicated that it is powered by an off-line switcher that combines a power MOSFET with a power supply controller. [Steve] figured out that the buttons are read via square wave and interpreted by a multiplexer. […]

  2. -

    […] Thus began [Steve]’s adventure in trying to turn the thing on with Alexa via Particle Photon. Because of the way the machine is designed, simply adding a relay wouldn’t do—the machine would just turn off and back on, only to start the self-clean again. Once inside, he found it’s controlled by a PIC18LF2520. Further research indicated that it is powered by an off-line switcher that combines a power MOSFET with a power supply controller. [Steve] figured out that the buttons are read via square wave and interpreted by a multiplexer. […]

  3. -

    […] Thus began [Steve]’s adventure in trying to turn the thing on with Alexa via Particle Photon. Because of the way the machine is designed, simply adding a relay wouldn’t do—the machine would just turn off and back on, only to start the self-clean again. Once inside, he found it’s controlled by a PIC18LF2520. Further research indicated that it is powered by an off-line switcher that combines a power MOSFET with a power supply controller. [Steve] figured out that the buttons are read via square wave and interpreted by a multiplexer. […]

  4. -

    Hey Steve,

    Did you work out a way to stop the cleaning cycle? I did the same thing to my Delonghi a few months ago using some MOSFETS on the buttons and a ESP8266. I can control all the buttons, but leaving a cup there for the next morning would be ideal. Also, there’s another blog article floating around the internet about a similar mod with txt messages, I think that talked about the GND references in there.

    • - Post author

      I wouldn’t want to stop the cleaning cycle as it flushes out some dirty looking water, and I’m far too lazy to clean it manually… If you wanted to bypass it, you could probably reprogram the PIC as it seems to have a programming header above it on the power board. As I now have a spare, I might look into doing that.

      I have noticed that the machine won’t run the cleaning cycle if you turn off the machine and turn it back on within a short period. Perhaps it tests the temperature of the heating element to determine whether a clean is needed. This would be pretty easy to fake on power on.

      And its worth noting that SMS article as I did read it while working on this project: https://www.zipwhip.com/blog/zipwhip-text-enabling-of-the-delonghi-magnifica-espresso-machine/

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.