Decrypting the Vado Identity wired shower controller

Ok, another step forward...

I've now set the internal pullup on the mega's rx pin and worked out that the cable that connects the mixer to the controller "crosses over" such that the pins on the mixer's connector are the same as the pins on the controller. I'm now bypassing the cable the connects the 2 which was causing me an issue with the + / - round the wrong way.

When looking at the connector face on with the notch at the bottom working in a clockwise direction from the bottom left: On the plugs, pin 2 is +ve, pin 3 is -ve On the cable, pin 3 is +ve, pin 2 is -ve

Pin 1 on the mixer connected to Serial2 on the Mega, pin 4 connected to Serial1.

I now only get a signal when power is applied to the mixer and the ground pin is connected. Thumbs up.

So, I'm investigating the mixer and, with this code:

long baudRate = 38400;
byte serialConfig = SERIAL_6E2;

void setup() {
  Serial.begin(baudRate);
  Serial1.begin(baudRate, serialConfig);
  Serial2.begin(baudRate, serialConfig);
  
  pinMode(17, INPUT_PULLUP); //Serial2
  pinMode(19, INPUT_PULLUP); //Serial1
}

void loop() {
  int inByte;
  if (Serial1.available()) {
    Serial.print("S1 - ");
    while (Serial1.available()) {
      inByte = Serial1.read();
      Serial.print(inByte, HEX);
      Serial.print(" ");
    }
    Serial.println();
  }

  if (Serial2.available()) {
    Serial.print("S2 - ");
    while (Serial2.available()) {
      inByte = Serial2.read();
      Serial.print(inByte, HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
}

My output is as follows:

S2 - 0 
S1 - 38 
S2 - 0 
S1 - 38 
S2 - 0 
S1 - 38 
S2 - 0 
S1 - 38 
S2 - 0 
S1 - 38 38 0 
S2 - 0 0 
S2 - 0 
S1 - 38 
S2 - 0 
S1 - 38 
S2 - 0 
S1 - 38 
S2 - 0 
S1 - 38 
S2 - 0 
S1 - 38 38 0 
S2 - 0 0

This pattern then repeats. I've changed the baud and config on the serials to 38400 / SERIAL_6E2 as 115200 / SERIAL_8N2 was only giving 0's. So I'm still not convinced this is the correct baud and config but at least I'm getting consistent results now. Next step is to try replaying the mixer's output to the controller and see what happens...

So, on to the controller... If I send nothing to the controller then the screen displays E1 and there is no output to the rx pin on the mega.

HOWEVER... I replayed "38" from the mega to the rx on the controller and it no longer goes into error. Rather it now displays "00" which is the normal "off" state. The backlight stays lit, however, which is not right but it's progress.

Also, it now starts singing like a bird. So, with this code:

long baudRate = 38400;
byte serialConfig = SERIAL_6E2;

void setup() {
  Serial.begin(baudRate);
  Serial1.begin(baudRate, serialConfig);
  
  pinMode(18, INPUT_PULLUP); //Serial1 tx
  pinMode(19, INPUT_PULLUP); //Serial1 rx
}

void loop() {
  int inByte;
  bool addLine = false;
  if (Serial1.available()) {
    while (Serial1.available()) {
      inByte = Serial1.read();
      if (inByte != 0) {
        addLine = true;
        Serial.print(inByte, HEX);
        Serial.print(" ");
      }
    }
    if (addLine)
      Serial.println();
  }

  inByte = Serial1.write(38);
  inByte = Serial1.write(0);

  delay(100);
}

I get the following:

38 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
3C 38 38 38 38 38 38 38 38 38 
1E 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38 
F 38 38 38 38 38 38 38 38 38 
38 38 38 38 38 38 38 38 38

And on it goes. Next I need to work out what else I should or shouldn't be sending it...

After putting this down for a little while, I did some further poking around with the controller and the transceiver chip uses RS-485 for its serial communications. So it's not quite as simple as a tx and an rx pin. This also necessitated the use of a couple of RS-485 modules for the arduino to convert the comms to something the arduino can use.

Furthermore, I'm still unsure of what the baud rate is as I seem to be able to retrieve apparently real data at a variety of bauds. I therefore thought it would be worth trying an oscilloscope to help detect the baud rate.

Using the instructions / code / app from here I managed to set up an oscilloscope using the arduino. It's certainly not perfect but it definitely appears to give some useful information.

From here it suggests measuring the shortest pulse and using a formula you can work out the baud.

I measured the shortest pulse at about 400 µs and that makes it really close to 2400 baud (allowing for errors in display and measurement).

I'm yet to test with this baud but, again, another step forwards perhaps...

Using the scope trace you should also be able to work out the number of data bits and stop bits used.

Riva: Using the scope trace you should also be able to work out the number of data bits and stop bits used.

So I've done some measurements using the arduino oscilloscope and I'm not entirely sure it has suitable resolution to be completely confident about the individual bits.

Anyway, I've attached a screenshot with what it outputs and it shows the following:

The red line measurement shows a "packet" is 8 ms long. The 2 pink dots on the red line are 1.2 ms apart. The green line measurement shows the gap between spikes is about 0.4 ms. The 2 pink dots on the green line are 3.5 ms apart - probably not that useful.

I've tried listening on Serial1 (the mixer) on the Mega and replaying any input to Serial2 (the controller) and vice versa but it's not working.

I have a feeling that there might be timing issues in that you may need to wait between bytes or something...

Any thoughts?

mixer_oscilloscope.png|659x727

As your measuring the differential signal you only need to measure either the A or B side (or the UART input to the chip) on a single channel and this should increase the scope resolution. Failing that then maybe invest in a cheap logic analyser like this that will be ideal for a job like this.

It's difficult to tell but looking at your image it looks like you will have only 7 bits per frame and assuming it includes one start and one stop bit that means only 5 data bits.

Riva:
As your measuring the differential signal you only need to measure either the A or B side (or the UART input to the chip) on a single channel and this should increase the scope resolution.
Failing that then maybe invest in a cheap logic analyser like this that will be ideal for a job like this.

It’s difficult to tell but looking at your image it looks like you will have only 7 bits per frame and assuming it includes one start and one stop bit that means only 5 data bits.

Tried only reading one channel but it didn’t seem to make any difference.
Also tried increasing the baud on the Arduino and the oscilloscope program to 250000 but, again, no dice.

I’ve ordered a logic analyser and it should turn up today or tomorrow so I’ll give that a go and see what happens…

OK, so, logic analyser here and this is what I've managed to find so far.

I'm using sigrok to interpret the data from the analyser.

The following is connecting the analyser solely to the mixer, i.e. without the controller in the picture...

The image attached (full data.png) is the full set of data captured from when I turned the mixer on to when I turned it off.

The gap between the final peak of one packet and the first peak of the next packet is 47.3 ms

All the "packets" shown are the same and a single packet can be seen in the attached image (single packet.png). Each packet is 7.9 ms long and consists of 7 peaks. Are there start and stop bits at either end that are not peaks?

The attached image (peak.png) shows that a peak is 1 ms long and a trough (trough.png) is 0.1 ms long.

full data.png|1329x170

peak.png|788x145

single packet.png|874x150

trough.png|358x212

Next installment…

Now I’ve connected the mixer and the controller to a breadboard and have the signal analyser effectively listening in to the conversation.

From the conversation, it appears that there’s a lot more going on than the single “packet” from the previous post. Having seen the data in the conversation I’ve measured the smallest pulse and it’s about 0.1 ms which (according to here) correlates with a baud of 9600.

So, with that in mind I added a UART protocol decoder (according to here, it’s the only protocol decoder that mentions RS485) and set the settings in PulseView as shown in uart.png, started reading data and then turned on the mixer. After a period of time I turned off the mixer and stopped reading data.

The attached file (sample.png) shows the first 11 chunks of data.

A couple of things of note before getting to the data:

  • There is about 39.15 ms between the end of one chunk to the start of the next chunk.
  • PulseView seems to suggest there are a lot of Frame Errors but that may be because the protocol isn’t really UART… perhaps

It looks like there are 7 bytes from the mixer (As there were 7 peaks in my last post) followed immediately by 7 bytes from the controller.
Only the final byte from the mixer ever appears to contain any data but then I haven’t pressed any buttons on the controller yet.

The data is as follows:

00 00 00 00 00 00 00    00 00 00 00 00 02 00
00 00 00 00 00 00 41    33 F2 02 16 07 02 00
00 00 00 00 00 00 B3    33 F2 02 16 07 02 00
00 00 00 00 00 00 21    33 F2 02 36 07 02 00
00 00 00 00 00 00 B3    13 72 02 36 07 02 00 
00 00 00 00 00 00 41    13 72 02 16 07 02 00
00 00 00 00 00 00 B3    33 F2 02 16 07 02 00
00 00 00 00 00 00 04    33 F2 02 16 07 02 00
00 00 00 00 00 00 53    33 F2 02 36 07 02 00
00 00 00 00 00 00 24    13 F2 02 36 07 02 00
00 00 00 00 00 00 B3    13 72 02 36 07 02 00

I can definitely see a pattern there but I’m unsure what it means just yet.

The next thing I’ll be trying is to see if I can replicate the data sent by the mixer using an arduino or it’ll all be for nothing…

uart.png

sample.png

UART decoder is probably the one to use.
RS485/RS422 describe the electrical differential signal to reduce/cancel noise induced in the cables so you can transmit signals further in electrically noisy environments.

Does the protocol decoder have an auto mode to determine the correct baud rate, start/stop bits, data bits and parity or did you select them manually.
Assuming it is Serial data then it looks like it could be configured as 9600,6N1 is this what you was using?
That’s 1 start bit, 6 data bits and one stop bit. Other options could be 5N2, 5E1, 5O1

UART signals are normally high in an idle state so you might have the logic probe connected to the wrong leg of the RS485 A/B line as your captures show the signal as idle low. You might be able to invert the logic in the protocol decoder instead.

There's no auto mode that I can find so I had to select everything manually.

I've tried loads of different options and the closest I've come to a match is the one I've got to here which is 9600, 8N1. I think it's more likely 8N2 as when I add a parity bit (of any type) and set 1 stop bit the length is perfect but the parity bit is often wrong but there's no option to add 2 stop bits in PulseView.

I'm actually monitoring both the A and B but was only showing 1 of them in the images to save space. Both signals are the same, as you'd expect, except being the opposite. The idle high signal shows exactly the same data.

You will know if the data is correct if you never get UART framing errors. I mentioned about the A/B high idle as adding a UART protocol decoder to the wrong one may cause wrong data values and framing errors to be returned in the decode data.

This is just the sort thing I like working on and even looks at the Vado unit for playing with but it would be too expensive for just the fun of it.

Riva: You will know if the data is correct if you never get UART framing errors. I mentioned about the A/B high idle as adding a UART protocol decoder to the wrong one may cause wrong data values and framing errors to be returned in the decode data.

This is just the sort thing I like working on and even looks at the Vado unit for playing with but it would be too expensive for just the fun of it.

Had to put this down for a bit again as I've been really struggling with it.

When I use the RS485 modules I can't seem to replicate the unit's initial pattern in a sensible way. I set the baud to 9600 but when I send a character it's so much shorter than the pattern from the unit.

The only way I've managed to get close is with the following but it's not using the RS485 module at all so I don't think it'll work with the unit:

long unsigned lastCom = 0;
long unsigned curMicros = 0;

const int digPinHigh = 30;
const int digPinLow = 31;
const int byteLen = 7;

bool valArray[] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};

const int bitLen = 104;
const unsigned long comPeriod = 55000;

void setup() {
  pinMode(digPinHigh, OUTPUT);
  pinMode(digPinLow, OUTPUT);
  digitalWrite(digPinHigh, LOW);
  digitalWrite(digPinLow, HIGH);
}

void loop()
{
  curMicros = micros();
  if ((curMicros > (lastCom + comPeriod)) || (curMicros < lastCom)) {
    lastCom = curMicros;

    for (int j = 0; j < byteLen; ++j) {
      for (int i = 0; i < sizeof(valArray); ++i) {
        digitalWrite(digPinHigh, valArray[i]);
        digitalWrite(digPinLow, valArray[i] == HIGH ? LOW : HIGH);
        delayMicroseconds(bitLen);
      }
      digitalWrite(digPinHigh, LOW);
      digitalWrite(digPinLow, HIGH);
      delayMicroseconds(bitLen);
    }
  }
}

Monkey3: When I use the RS485 modules I can't seem to replicate the unit's initial pattern in a sensible way. I set the baud to 9600 but when I send a character it's so much shorter than the pattern from the unit.

What if you use a lower baud rate, 300, 1200, 2400 and 4800 are standard rates below 9600 but it could also be custom. Does your logic analyser protocol decoder have an auto baud option where it will try to figure out the baud rate for its self?

Riva: What if you use a lower baud rate, 300, 1200, 2400 and 4800 are standard rates below 9600 but it could also be custom. Does your logic analyser protocol decoder have an auto baud option where it will try to figure out the baud rate for its self?

Firstly, thank you Riva for your help on this. It's very much appreciated and is really keeping me invested.

ok, another step forwards perhaps...

I changed the arduino code that utlilises the rs485 module to the following:

long baudRate = 9600;
byte serialConfig = SERIAL_8N1;

#define TxControlMixer      3   //RS485 Direction control
#define RS485Transmit       HIGH
#define RS485Receive        LOW

long unsigned lastCom = 0;
long unsigned curMicros = 0;
const unsigned long comPeriod = 55000;
const int bitLen = 104;

byte message[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

void setup() {
  Serial1.begin(baudRate, serialConfig);

  // Init Transceiver
  pinMode(TxControlMixer, OUTPUT);  
  digitalWrite(TxControlMixer, RS485Receive);
}

void loop()
{
  curMicros = micros();
  if ((curMicros > (lastCom + comPeriod)) || (curMicros < lastCom)){
    lastCom = curMicros;
    digitalWrite(TxControlMixer, RS485Transmit);  // Enable RS485 Transmit
    for (int i = 0; i < sizeof(message); ++i) {
      Serial1.write(message[i]);
      delayMicroseconds(bitLen);
    }
  }
}

The main point being I've removed the line that sets the RS485 module to receive. This means that the arduino is constantly in transmit which could be a problem when I connect the controller up but I'll get to that later.

This gave the right sort of pattern, as shown on the top line in the attached image.

Once I got to there I then changed the baud to 8750 (with some trial and error) which gave me the middle line.

The bottom line is the mixer.

Note:

  • the scale is not the same on each line
  • rather the measure at the top of each line shows the duration

So the overall length of a packet looks right but the individual segments look a little too short.

real vs arduino.png|1900x650

I ran the mixer again and read the data in sigrok and then added a UART decoder at a baud of 8750.

I now get some clean packets but also still some frame errors... (see attachments).

However, if I increase the sample rate in sigrok to 50kHz then the frame errors pretty much go away entirely... :D

ard 8750 frame error.png|1424x154

ard 8750 success.png|1424x154

ok, I've now sampled both the mixer and the controller together and am seeing zero frame errors.

Looks like it's a baud of 8752... :\

Strange, but ok.

And with that I get the following data:

I'm certain the left is the mixer and the right is the controller.

The mixer sends 7 00's until the controller is connected at which point the controller sends a single 02 in response.

00 00 00 00 00 00 00   00 00 00 00 00 02 00

The following 6 packets are then exchanged:

00 00 00 00 00 00 21   13 72 02 16 07 02 00
00 00 00 00 00 00 53   13 72 02 16 07 02 00
00 00 00 00 00 00 21   13 72 02 16 07 02 00
00 00 00 00 00 00 53   13 72 02 16 07 02 00
00 00 00 00 00 00 21   13 72 02 16 07 02 00
00 00 00 00 00 00 53   13 72 02 16 07 02 00

There are then a whole load of the following packet pairs are exchanged until the mixer has finished its start up (making whirring noises - to reset the proportioning valve I would guess):

00 00 00 00 00 00 16   13 72 02 16 07 02 00
00 00 00 00 00 00 53   13 72 02 16 07 02 00

After the mixer's start up completes, the following pairs are exchanged ad infinitum:

00 00 00 00 00 00 16   13 72 02 16 07 02 00
00 00 00 00 00 00 51   13 72 02 16 07 02 00

so now to try to replicate the mixer pattern with arduino...

Bit more messing with the controller...

If I press the power button, there's a bit of mess where it looks like the controller stops talking for a few packets while the mixer sends the following:

00 00 00 00 00 00 16

The controller then talks over the mixer for a couple of packets until it settles into the following:

00 00 00 00 00 00 16   12 72 01 16 07 02 00

After that I pressed the button to switch to a different shower outlet at which point there was some mess again followed by:

00 00 00 00 00 00 16   12 72 01 16 07 01 00

They then settled into the following:

00 00 00 00 00 00 16   11 72 01 16 07 01 00

I then hit the pause button, there was mess, then:

00 00 00 00 00 00 16   12 7A 02 16 07 01 00
00 00 00 00 00 00 53   12 72 02 16 07 01 00

I think the first line above may be a read error and 7A should in fact be 72

Then they settle into the following:

00 00 00 00 00 00 16   12 72 02 16 07 01 00
00 00 00 00 00 00 53   12 72 02 16 07 01 00

At some point thereafter they settle into the following:

00 00 00 00 00 00 16   12 72 02 16 07 01 00
00 00 00 00 00 00 51   12 72 02 16 07 01 00

New update!

I'm sort of talking to the controller. Certainly it knows I'm talking and is responding.

I rewrote the code to replicate the 3 stage start up sequence (from post 21) and then connected the controller to the arduino and it seems to be responding. As far as the data being received from the controller in response to the data I'm sending, it looks identical to what's received when it's connected to the arduino.

The only difference in the data, and the main issue I seem to be having, is that on one of the 2 rs485 data pins the idle is HIGH whereas on the mixer it's LOW (see attached).

I'd like to resolve the data issue in order to eliminate it from the investigation (plus I think the arduino's signal is wrong as per the rs485 spec / requirements / guidelines / whatever).

Aside from the data issue I've found that when I connect the controller to the arduino and power everything on, the screen stays on the "00", the backlight stays lit and the buttons are unresponsive. However, if I start everything up and then move the controller connections to the mixer (which is powered on patiently waiting) the backlight then goes out which is the appropriate standby mode and the buttons are responsive. Better yet, if I then move the connections back to the arduino, the buttons remain responsive. I can perform all of the usual actions on the buttons until I attempt to put it back into standby at which point the buttons then become unresponsive once more.

Clearly the unresponsive buttons is a blocker for real use but I may continue to work on the code that handles the state, temp, pressure, etc. until I have a breakthrough or somebody points out the glaringly obvious mistake to me...

arduino_vs_mixer.png|1305x700

What RS485 module are you using and does it have the relevant/correct pullup/pulldown resistors on the A/B lines and maybe the 120 ohm terminator?