Decrypting the Vado Identity wired shower controller

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… :smiley:

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…

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?

Riva: 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?

It's this one: https://www.amazon.co.uk/WINGONEER-MAX485-Module-RS-485-Development/dp/B06XHHWLMW

From the looks of the schematic it's got all the resistors and the board seems to match the schematic (in terms or the number of components).

My first thought was pull up / down resistors so I tried adding a couple of 220's in parallel (so 110 ohm) across the A / B and from each as pull up / down but all I managed to do was change the "incorrect" pin to the other one. So it feels like it's in the right region but I'm not really sure how to work out what's required.

The next thing I'm going to try is to measure the resistance across everything with the controller connected to the mixer and then again with the controller connected to the arduino, both with everything powered on and off. At least that will tell me what the difference is between the 2 scenarios...

If you disconnect the mixer and just connect your logic analyser to A, B & Gnd of the MAX485 module while sending data, does it then show idle as low or still as high?

Riva: If you disconnect the mixer and just connect your logic analyser to A, B & Gnd of the MAX485 module while sending data, does it then show idle as low or still as high?

Exactly the same. Still HIGH.

Monkey3:
Exactly the same. Still HIGH.

Is the MAX485 module in RX or TX mode when you take the readings?

EDIT:
Using the simple test program below on a Mega

#define DE 2
#define RE 3
#define TEST 4
#define DELAY 100

void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);
  pinMode(DE, OUTPUT);
  pinMode(RE, OUTPUT);
  pinMode(TEST, OUTPUT);
  Serial.println("Setup End");
}

void loop()
{
  Serial.println("DE/RE High");
  digitalWrite(DE, HIGH);
  digitalWrite(RE, HIGH);
  digitalWrite(TEST, HIGH);
  delay(10);
  Serial1.print("Hello World");
  delay(DELAY);
  Serial.println("DE/RE Low");
  digitalWrite(DE, LOW);
  digitalWrite(RE, LOW);
  digitalWrite(TEST, LOW);
  delay(DELAY);
}

I get the below image on my LA. You need to put the MAX481 into receive mode to release the lines.

Clipboard-1.jpg

Riva:
Is the MAX485 module in RX or TX mode when you take the readings?

EDIT:
Using the simple test program below on a Mega

...

I get the below image on my LA. You need to put the MAX481 into receive mode to release the lines.

Using the same code I get the attached.

Monkey3:
Using the same code I get the attached.

That’s strange, when TEST is low the MAX chip should be in receive mode and the pullup resistor should hold the A line high (on my image it is low but this is probably the logic probe pulling it down) and the pulldown holds the B line low. On your trace A is behaving as expected but B is remaining high.

I used a module that looks like yours but I don’t have it with me to check the exact model and MAX chip used.
I’m at work and just happen to have a MAX485 chip (not module) to hand to connected it to using the same scheme and get the same results.
Clipboard-1.png
Maybe you should try another MAX485 module/chip.

I’ve tried a second and third module and it’s exactly the same (see attached) - although all the modules came in the same pack so that may be saying too much.

The chip is MAX485 ESA +18DN if that makes any difference.

When I look at your image versus mine, they look exactly the same but the mirror image.
With the exception that the test channel is not the mirror image.

I really don’t know what that means.

I’m looking to see if there’s another, different module I can get quickly and cheaply for comparison…

AFAIK the 3 characters after MAX485 denote the package type. ESA is 8 pin SO package. When your testing you only have them connected to the logic analyser? The Amazon link you posted has a schematic image so maybe check module matches schematic with a continuity meter Maybe the whole packet of MAX485 modules are faulty or poorly designed/built or it could just be your logic device pulls the lines high when they are floating and mine pulls them low.

Riva:
AFAIK the 3 characters after MAX485 denote the package type. ESA is 8 pin SO package.
When your testing you only have them connected to the logic analyser?
The Amazon link you posted has a schematic image so maybe check module matches schematic with a continuity meter
Maybe the whole packet of MAX485 modules are faulty or poorly designed/built or it could just be your logic device pulls the lines high when they are floating and mine pulls them low.

When testing, I’ve tried a couple of different combinations and they all give the same result.

CHANNEL CONNECTED SIGNAL AT IDLE
A arduino and logic analyser high
A arduino, controller and logic analyser high
A mixer and logic analyser low
A mixer, controller and logic analyser low

So I’ve ordered another, very different rs485 (https://www.amazon.co.uk/gp/product/B07B667STP) which should be turning up tomorrow so, with any luck, this will resolve the issue.

OK, I think this is good news.

The new module doesn't have DE / RE pins, rather it relies on the TX to tell it when to switch to send / receive mode.

It does seem to properly switch back to idle though. :D

ALSO... After some head bashing / panicking it would appear that actually the controller is working at 9600 baud with an ODD parity bit and I'm now able to immediately add a UART decoder with no frame errors!!!

It does mean that I now need to go back and re-analyse the mixer / controller traffic but that should be fairly easy.

Watch this space...

Glad you have one problem sorted and found the next hurdle to jump. Just to put the old RS485 modules problem to bed how was you connecting them up?

Riva: Glad you have one problem sorted and found the next hurdle to jump. Just to put the old RS485 modules problem to bed how was you connecting them up?

For the old modules I connected them the same way described here.

Essentially:

| Arduino | RS 485 | | - | - | | TX | DI | | RX | RO | | 3 (Direction Control) | DE / RE | | GND | GND | | 5V | VCC |

I don't know whether I got a bad batch or what but I must've re-wired the circuit about 50 times to make sure it was together correctly. So gawd knows.

Ok, so with the new RS 485 module, I’m wired back in to try to work out the sequences again and here goes…

Any lines followed by “x n” means that the lines above (until the previos blank line) are repeated n times
“x …” means the lines are repeated an unknown number of times or indefinitely

Just the mixer connected

00 00 00 00 00 00 00
x ...

Connect the controller
This just shows the handshake and then the mixer’s start up sequence

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

00 00 00 00 00 00 41  33 F2 02 36 07 02 00
00 00 00 00 00 00 B3  33 F2 02 36 07 02 00
00 00 00 00 00 00 41  33 F2 02 36 07 02 00
00 00 00 00 00 00 B3  33 F2 02 36 07 02 00
00 00 00 00 00 00 41  33 F2 02 36 07 02 00
00 00 00 00 00 00 B3  33 F2 02 36 07 02 00

00 00 00 00 00 00 1D  33 F2 02 36 07 02 00
00 00 00 00 00 00 B3  33 F2 02 36 07 02 00
x 55

00 00 00 00 00 00 1D  33 F2 02 36 07 02 00
00 00 00 00 00 00 B1  33 F2 02 36 07 02 00
x ...

Turn shower on

00 00 00 00 00 00 B1
00 00 00 00 00 00 B1
00 00 00 00 00 00 B1
//MESS
00 00 00 00 00 00 B1  32 F2 01 36 07 02 00
00 00 00 00 00 00 1D  32 F2 01 36 07 02 00

00 00 00 00 00 00 1D  32 F2 01 36 07 02 00
x ...

Turn shower off

00 00 00 00 00 00 1D
00 00 00 00 00 00 1D
00 00 00 00 00 00 1D
//MESS
00 00 00 00 00 00 1D  33 F2 02 36 07 02 00

00 00 00 00 00 00 1D  33 F2 02 36 07 02 00
00 00 00 00 00 00 B1  33 F2 02 36 07 02 00
x ...

Turn shower on then
Change to outlet 2

00 00 00 00 00 00 1D
00 00 00 00 00 00 1D
00 00 00 00 00 00 1D
MESS
00 00 00 00 00 00 1D  31 F2 01 36 07 01 00
x ...

Turn shower off

00 00 00 00 00 00 1D
00 00 00 00 00 00 1D
00 00 00 00 00 00 1D
MESS
00 00 00 00 00 00 1D  32 F2 02 36 07 01 00

00 00 00 00 00 00 1D  32 F2 02 36 07 01 00
00 00 00 00 00 00 B3  32 F2 02 36 07 01 00
x...

00 00 00 00 00 00 1D  32 F2 02 36 07 01 00
00 00 00 00 00 00 B1  32 F2 02 36 07 01 00
x...

Turn shower on then
Increase flow

//Min flow
00 00 00 00 00 00 1D  32 F2 01 36 05 02 00

//Low flow
00 00 00 00 00 00 1D  32 F2 01 36 06 02 00

//Med flow
00 00 00 00 00 00 1D  32 F2 01 36 07 02 00

//High flow
00 00 00 00 00 00 1D  32 F2 01 36 08 02 00

//Max flow
00 00 00 00 00 00 1D  32 F2 01 36 09 02 00

There was some unexpected behaviour from the mixer while all that testing was going on. At some point I noticed that the last bit from the mixer started to rise. I assume that this indicates the temperature that the water flowing through the mixer has reached but even after I turned the mixer off it continued to rise for a bit, possibly down to heat soak.

Mixer behaviour

...
00 00 00 00 00 00 23

00 00 00 00 00 00 24
x 5

00 00 00 00 00 00 25
x 7

00 00 00 00 00 00 26
x 17

00 00 00 00 00 00 27
x 11

00 00 00 00 00 00 28
x 18

00 00 00 00 00 00 29
x 6

00 00 00 00 00 00 2A
x 5

00 00 00 00 00 00 2B
x 6

00 00 00 00 00 00 2C
x 24

00 00 00 00 00 00 2D
x 11

00 00 00 00 00 00 2E
x 6

//turn off

00 00 00 00 00 00 B3
00 00 00 00 00 00 2E
x 3
00 00 00 00 00 00 B3
00 00 00 00 00 00 2F
x 4
00 00 00 00 00 00 B3
00 00 00 00 00 00 30

I'm going to test a bit further to see if the mixer's temp matches up to the temp from the controller...

Then, bizarrely, the controller's first bit changed as well. I'm yet to work out what the controller's first bit is for...

Controller strangeness

35 F2 02 36 09 02 00

ARRRRRGGGGGHHHHHH!!!

:frowning: >:( >:(

It seems the new rs485 doesn’t want to read all of the data.

the following code:

//Transmission config
long baudRate = 9600;
byte serialConfig = SERIAL_8O1;
//Transmission Details
/////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////
//Timing
long unsigned lastCom = 0;
long unsigned curMicros = 0;
const unsigned long comPeriod = 55240; //should 55240 - 55280 - Arduino is not perfect at timing so 55240 seems to equate to roughly 55260
//Timing
/////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////
//Message Length
const int MSG_LEN = 7;
/////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////
//Outgoing message details
//Outgoing messages
const byte MSG_INTRO[MSG_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//Outgoing register
byte message[MSG_LEN];
//Outgoing message details
/////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////
//Controller message details
//Incoming register
byte receivedData[MSG_LEN];
int nCurByte = 0;
//Controller message details
/////////////////////////////////////////////////////////////////

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

  memcpy(message, MSG_INTRO, MSG_LEN);
}

void loop()
{
  SendData(message);

  if (ReadData()) {
    PrintData();
  }
}

void PrintData() {
  for(int i = 0; i < MSG_LEN; i++)
  {
    Serial.print(receivedData[i], HEX);
    Serial.print(" ");
  }
  Serial.println("");
}

void SendData(byte sendMsg[]) {
  curMicros = micros();
  if ((curMicros > (lastCom + comPeriod)) || (curMicros < lastCom)) {
    lastCom = curMicros;
    Serial1.write(sendMsg, MSG_LEN);
  }
}

bool ReadData() {
  while (Serial1.available() > 0) {
    receivedData[nCurByte++] = Serial1.read();

    if (nCurByte >= MSG_LEN) {
      nCurByte = 0;
      return true;
    }
  }
  return false;
}

Prints:

...
F2 2 7 2 F2 2 7 
2 F2 2 7 2 F2 2 
7 2 F2 2 7 2 F2 
2 7 2 F2 2 7 2 
F2 2 7 2 F2 2 7 
2 F2 2 7 2 F2 2 
F2 2 7 2 F2 2 7 
2 F2 2 7 2 F2 2 
7 2 F2 2 7 2 F2 
2 7 2 F2 2 7 2 
F2 2 7 2 F2 2 7 
2 F2 2 7 2 F2 2 
7 2 F2 2 7 2 F2
...

It’s definitely reading the incoming data as I’m expecting:
33 F2 02 36 07 02 00

And the logic analyser is picking up all the data.
It’s looking like I’m going to need to use the old module to read the incoming data and the new module to write the data.
I’ve tried using ReadBytes but that just times out after about a second or something (whatever the default is).

I’m at a loss…