QDY30A Water Level [Pressure] Sensor

QDY30A-B Water Level [Pressure] Sensor

This type of water level/pressure sensor comes in several variations, differing in the way in which readings are made—via a current loop (4~20mA), a voltage (0~3.3V or 0~5V) or an RS485 interface. The present example deals with the [4-wire] RS485 version. Configuration of the [2‑wire] current loop and [3-wire] voltage versions are discussed elsewhere on this site.

To date, I have used the manual for a similar sensor, retrieved from the ComWinTop website, as a guide in forumlating the necessary Modbus RTU queries.

Testing Notes
  • The sensor specifications indicate that it requires a 24V supply—this is what is inscribed on the sensor that I have—but will operate with a supply voltage of 12~36V. Based on comments that some variants of these sensors would operate on a 5V supply, I hooked it up to the 5V Vin pin on the CubeCell Plus Dev-Board and it all seems to work. I have read one report that indicated problems with a similar [QDY30A] sensor, but not with an RS485 interface, when operating at 12V, even though the specs suggested that 12V~36V should be OK. In the present case, however, the RS485 probe, operating at 5V, is consistently reporting the same levels as a [0~3.3V] 3-wire probe I have in the same tank.
  • Supplied with a default baud rate setting of 9600.
  • Responds to a Modbus RTU broadcast address of 0x00.
  • As supplied, when queried this sensor reports a Slave ID of 0x01. It will respond to queries directed either to this address or the broadcast address. Like the SHT30 sensor, the Water Level sensor would not comply with any attempt to change its Slave ID, although it did correctly report its Slave ID of 0x01 when so queried. Once again, it may be that I am doing something wrong here, but I am following the same process that I used to successfully change the Slave ID of the Soil Condition sensor.

CubeCell Plus RS485 QDY30A Sensor Hardware Configuration

QDY30A Sensor [RS485] Configuration Circuit
Pin Configuration
CubeCell Plus UART-to-RS485 QDY30A
GND GND
UART_TX2 Tx
UART_RX2 Rx
Vext Vcc
Vin Red
A+ Blue
B- Yellow
Sig-GND Black

Note that the colours of the RS485 wires on the various probes that I have tested have all been different so it is important to verify which wire is which on any given probe and not rely on any idea of standardised colouring of wires. In particular, the RS485 A+/B- signal wires are often the exact opposite of those illustrated here for the QDY30A probe—yellow and blue respectively, rather than blue and yellow. Thankfully, there has always been some form of identification, apart from colour, on the wires of RS485 probes that I have purchased—a card included with the probe or tags on relevant wires.

Software


RS485 QDY30A Sensor Test Sketch
/*
   A simple sketch to test RS485 communications between a CubeCell Dev-Board Plus and a
   [4-wire] QDY30A water level sensor. It uses SoftwareSerial, and assumes that we have a
   TTL-to-RS485 adaptor connected to the second CubeCell Dev-Board Plus UART
   (UART_TX2/UART_RX2) and the QDY30A sensor. Output is sent to the serial Monitor and the
   CubeCell Dev-Board Plus onboard display.
*/

#include <HT_SH1107Wire.h>        // CubeCell Plus display library
#include <softSerial.h>

#define RS485BaudRate 9600

SH1107Wire  plusDisplay(0x3c, 500000, SDA, SCL, GEOMETRY_128_64, GPIO10); // addr, freq, sda, scl, resolution, rst

int counter = 0;
String receiveString, sendString;

// Water Level Query
byte queryData[]{ 0x01, 0x03, 0x00, 0x04, 0x00, 0x01, 0xC5, 0xCB }; // Water Level
// Range Zero Query
byte queryZeroData[]{ 0x01, 0x03, 0x00, 0x05, 0x00, 0x01, 0x94, 0x0B }; // Zero point value
// Full Range Query
byte queryFullData[]{ 0x01, 0x03, 0x00, 0x06, 0x00, 0x01, 0x64, 0x0B }; // Max measurable value

/*
	The Water Level Query responses (actual, zero point and range) will be of the form:
	
		0x01, 0x03, 0x02, [0x01, 0x65], 0x79, 0xFF
		
	with the value returned in the 4th (receivedData[3]) and 5th (receivedData[4]) bytes :
	
		0165 HEX => 357 DEC
*/

byte receivedData[19];
// Define the serial entity for connection to the RS485 adaptor
softSerial RS485(UART_TX2, UART_RX2);

void setup() {

  // Supply power to the RS485 adaptor

  pinMode(Vext, OUTPUT);
  digitalWrite(Vext, LOW);

  // Initialise the display

  plusDisplay.init();
  plusDisplay.setFont(ArialMT_Plain_10);
  plusDisplay.screenRotate(ANGLE_180_DEGREE);
    
  plusDisplay.clear();
  plusDisplay.setFont(ArialMT_Plain_10);
  plusDisplay.setTextAlignment(TEXT_ALIGN_LEFT);
  plusDisplay.drawString(5,5,"Water Level Sensor");
  plusDisplay.display();
  delay(1000);
 
  // Open the serial ports

  Serial.begin(115200);
  RS485.begin(RS485BaudRate);

  Serial.println("[setup] CubeCell Plus RS485 QDY30A Water Level Sensor Test");
  Serial.println("[setup] Reading sensor range...");

  RS485.write(queryZeroData, sizeof(queryZeroData));
  delay(100);
  // If we've received anything...
  if ( RS485.available() > 0 ) {
    // Report anything we receive on the RS485 bus
    RS485.readBytes(receivedData, sizeof(receivedData));
    Serial.print("[setup] Received Data : ");
    for ( int i = 0; i <= sizeof(receivedData); i++ ) {
      Serial.print("0x");

      Serial.print(receivedData[i],HEX);
      if ( i < sizeof(receivedData) ) {
        Serial.print(", ");
      }
    }
    Serial.println("\n");
    // Parse and print the received data in decimal format
    unsigned int zeroPoint = (receivedData[3] << 8) | receivedData[4];

    Serial.print("Zero Point : ");
    Serial.println(zeroPoint);
    Serial.println();
  } else {
    Serial.println("No response to Zero Point query");
  }

  RS485.write(queryFullData, sizeof(queryFullData));
  delay(100);
  // If we've received anything...
  if ( RS485.available() > 0 ) {
    // Report anything we receive on the RS485 bus
    RS485.readBytes(receivedData, sizeof(receivedData));
    Serial.print("[setup] Received Data : ");
    for ( int i = 0; i <= sizeof(receivedData); i++ ) {
      Serial.print("0x");

      Serial.print(receivedData[i],HEX);
      if ( i < sizeof(receivedData) ) {
        Serial.print(", ");
      }
    }
    Serial.println("\n");
    // Parse and print the received data in decimal format
    unsigned int fullScale = (receivedData[3] << 8) | receivedData[4];

    Serial.print("Full Scale : ");
    Serial.println(fullScale);
    Serial.println();
  } else {
    Serial.println("No response to Full Scale query");
  }
}

void loop() {
  // Send the query...
  Serial.println("[loop] Sending depth query...");
  RS485.write(queryData, sizeof(queryData));
  delay(100);
  // If we've received anything...
  if ( RS485.available() > 0 ) {
    // Report anything we receive on the RS485 bus
    RS485.readBytes(receivedData, sizeof(receivedData));
    Serial.print("[loop] Received Data : ");
    for ( int i = 0; i <= sizeof(receivedData); i++ ) {
      Serial.print("0x");

      Serial.print(receivedData[i],HEX);
      if ( i < sizeof(receivedData) ) {
        Serial.print(", ");
      }
    }
    Serial.println("\n");
    /*
    	Parse and print the received data in decimal format.
   		The [RS485] sensor takes a pressure reading, does the necessary calculations to
    	determine the height of the column of water above it, and simply returns the
    	calculated water level.
    */
    unsigned int pressure = (receivedData[3] << 8) | receivedData[4];

    Serial.print("Water Pressure : ");
    Serial.println(pressure);
    Serial.println();

    displayData(pressure);

		/*
			We still need to calculate the water level in the vessel under test, which
			will involve the height of the vessel and some calibration factor
		*/

  } else {
    Serial.println("[loop] No response...");
    displayData(9999);
  }
  delay(5000);
}

void displayData(unsigned int data) {
  plusDisplay.clear();
  plusDisplay.setFont(ArialMT_Plain_10);
  plusDisplay.setTextAlignment(TEXT_ALIGN_LEFT);
  plusDisplay.drawString(5,0,"Water Level Sensor");

  plusDisplay.setTextAlignment(TEXT_ALIGN_RIGHT);
  plusDisplay.drawString(40,24,"Probe");

  plusDisplay.setFont(ArialMT_Plain_24);
  plusDisplay.setTextAlignment(TEXT_ALIGN_LEFT);
  plusDisplay.drawString(50,24,String(data));

  plusDisplay.display();
}

Further details pending

19-07-2026