5.2. Servicing Protocol (RS-232)#

The servicing protocol is used to read and modify the operating parameters of the flow meter. Device settings such as filtering parameters, measurement units selection, interface configuration, and other internal parameters are adjusted using this protocol.

Since the NMEA-like measurement protocol is unidirectional (measurement data is transmitted only from the device to the host), the servicing protocol provides independent two-way configuration and maintenance access on the same RS-232 interface when the device is awake. To simplify device setup and parameter adjustment, Geolux provides the Geolux Instrument Configurator software tool. End users typically do not need to interact directly with the servicing protocol, as all configuration tasks are performed through the Configurator application. A detailed description of the software is provided in 6. Geolux Instrument Configurator.

Each command must begin with the ‘#’ character and be terminated with a newline character. All standard combinations of carriage return (CR) and line feed (LF) characters (CR, LF, or CR+LF) are accepted as valid line termination.

Reading All Parameters at Once#

To read all parameters at once, send the following command to the device:

#get_info

The device will respond with a structured list of all current parameters and system information in the following format:

#device_type: 10003
#firmware: 1.2.3
#serial_number: 12345
#<parameter_name_1>: <value1>
#<parameter_name_2>: <value2>
...
#update_status: 0

The response includes device identification information (such as device type, firmware version, and serial number), followed by all configurable and status parameters. A complete description of all available parameters is provided later in this chapter.

Reading Single Parameter#

Any configuration parameter can be read individually:

#get_<parameter_name>

The device will respond:

#<parameter_name>: <value>

Writing Single Parameter#

Any configuration parameter that is not read-only can be changed by the following command format:

#set_<parameter_name>=<value>

The device will respond, depending on success or failure:

#set_<parameter_name>:OK
#set_<parameter_name>:ERR

Enumerated parameters accept both the string name and the numeric index, for example:

#set_direction=incoming
#set_direction=1

List of Parameters#

Maximum Velocity Treshold#

Defines the upper bound for valid surface velocity measurements. Velocity readings above this threshold are rejected. The numeric value parameter is interpreted in the unit defined by max_velocity_unit.

See Maximum Velocity for the detailed setting description.

Parameter name: max_velocity
Read command: #get_max_velocity
Write command: #set_max_velocity=<value>

Maximum Velocity Unit#

Defines the physical unit used by max_velocity command. The accepted units are:

See Maximum Velocity for the detailed setting description.

mms = mm/s,
ms = m/s,
mph = mph,
kmh = km/h,
fps = ft/s,
fpm = ft/min,
cms = cm/s.
Parameter name: max_velocity_unit
Read command: #get_max_velocity_unit
Write command: #set_max_velocity_unit=<value>

Direction Filter#

Defines the direction filter configuration. The accepted values are:

See Direction Filter for the detailed setting description.

both = measure both directions,
incoming = incoming flow only,
outgoing = outgoing flow only.
Parameter name: direction
Read command: #get_direction
Write command: #set_direction=<value>

SNR Threshold#

Defines the SNR threshold value for the surface velocity radar. See SNR Threshold for the detailed setting description.

Parameter name: snr_threshold
Read command: #get_snr_threshold
Write command: #set_snr_threshold=<value>

Filter Length#

Defines the number of seconds used for internal smoothing. Higher values reduce noise but increase response lag. The valid range is between 1 and 120.

See Filter Length for the detailed setting description.

Parameter name: filter_len
Read command: #get_filter_len
Write command: #set_filter_len=<value>

Discharge Unit#

Defines the unit used for the discharge value in the SDI-12 measurement response, NMEA and on Modbus output. See Discharge Output Unit for the detailed setting description.

The accepted units are:

m3/s = m³/s,
m3/h = m³/h,
l/s = l/s,
l/h = l/h,
cfs = ft³/s,
gal/min = gal/min,
ML/day = ML/day.
Parameter name: discharge_unit
Read command: #get_discharge_unit
Write command: #set_discharge_unit=<value>

Water Level Unit#

Defines the unit used for the water level value in the SDI-12 measurement response, NMEA and on Modbus output. See Water Level Output Unit for the detailed setting description.

The accepted units are:

mm = millimeters,
cm = centimeters,
m = meters,
ft = feet,
in = inches.
Parameter name: level_unit
Read command: #get_level_unit
Write command: #set_level_unit=<value>

Velocity Output Unit#

Defines the unit used for the velocity value in the SDI-12 measurement response, NMEA and on Modbus output. See Surface Velocity Output Unit for the detailed setting description.

The accepted units are:

mms = mm/s,
ms = m/s,
mph = mph,
kmh = km/h,
fps = ft/s,
fpm = ft/min,
cms = cm/s.
Parameter name: units
Read command: #get_units
Write command: #set_units=<value>

Volume Output Unit#

Defines the unit used for the total flow volume value in the SDI-12 measurement response, NMEA and on Modbus output. See Volume Output Unit for the detailed setting description.

The accepted units are:

m3 = cubic meters,
l = liters,
ft3 = cubic feet,
gal = galons,
ML = mega (million) liters.
Parameter name: volume_unit
Read command: #get_volume_units
Write command: #set_volume_units=<value>

Beam Width#

Defines the radar beam width pattern for the surface velocity radar. Wide beam covers a larger area; narrow beam is more focused and rejects off-axis targets. The accepted values are:

See Beam Width for the detailed setting description.

wide,
narrow.
Parameter name: beam_width
Read command: #get_beam_width
Write command: #set_beam_width=<value>

Beam Offset#

Defines the near or far measurement zone placed along the radar beam used for target detection, for the surface velocity radar. The accepted values are:

See Beam Position for the detailed setting description.

near,
far.
Parameter name: beam_offset
Read command: #get_beam_offset
Write command: #set_beam_offset=<value>

DFP Enable#

Defines the enable status of Dynamic Flow Profiler algorithm, which tracks and accumulates flow history for improved accuracy in low-flow conditions. The accepted values are:

See Dynamic Flow Profiler for the detailed setting description.

off,
on.
Parameter name: use_dfp
Read command: #get_use_dfp
Write command: #set_use_dfp=<value>

Radar Height#

Gets / sets the vertical distance between the instrument and the water level reference point (gauge zero). The instrument uses this value to calculate and report the water level relative to the gauge zero. The corresponding measurement unit is defined by radar_height_unit parameter.

Parameter name: radar_height
Read command: #get_radar_height
Write command: #set_radar_height=<value>

Radar Height Unit#

Defines the measurement unit for the radar_height parameter.

The accepted units are:

mm = millimeters,
cm = centimeters,
m = meters,
ft = feet,
in = inches.
Parameter name: radar_height_unit
Read command: #get_radar_height_unit
Write command: #set_radar_height_unit=<value>

Minimum Valid Distance#

Defines the minimum valid distance to water surface. Reflections detected closer than this distance are ignored. Use this parameter to exclude near-field returns e.g., mounting hardware, bridge elements, or other objects close to the sensor. The corresponding measurement unit is defined by min_distance_unit parameter.

See Minimum Distance for the detailed setting description.

Parameter name: min_distance
Read command: #get_min_distance
Write command: #set_min_distance=<value>

Minimum Valid Distance Unit#

Defines the measurement unit used by min_distance parameter. The accepted units are:

See Minimum Distance for the detailed setting description.

mm,
cm,
m,
ft,
in.
Parameter name: min_distance_unit
Read command: #get_min_distance_unit
Write command: #set_min_distance_unit=<value>

Maximum Valid Distance#

Gets / sets the maximum valid distance to water surface. Reflections detected beyond this distance are ignored. Use this parameter to exclude far-field returns outside the intended measurement zone e.g., opposite bank, structures, or background targets. The corresponding measurement unit is defined by max_distance_unit parameter.

See Maximum Distance for the detailed setting description.

Parameter name: max_distance
Read command: #get_max_distance
Write command: #set_max_distance=<value>

Maximum Valid Distance Unit#

Gets / sets the measurement unit used by max_distance parameter. The accepted units are:

See Maximum Distance for the detailed setting description.

mm,
cm,
m,
ft,
in.
Parameter name: max_distance_unit
Read command: #get_max_distance_unit
Write command: #set_max_distance_unit=<value>

RS-232 Baud Rate#

Gets / sets the baud rate of the RS-232 serial interface. The change takes effect immediately. The accepted values for baud rates are:

See RS-232 Baud Rate for the detailed setting description.

4800,
9600,
14400,
19200,
38400,
57600,
115200.
Parameter name: baud_rate
Read command: #get_baud_rate
Write command: #set_baud_rate=<value>

Modbus Baud Rate#

Gets / sets the baud rate of the RS-485/Modbus serial interface. The change takes effect immediately. The accepted values for baud rates are:

See RS-485 Baud Rate for the detailed setting description.

4800,
9600,
14400,
19200,
38400,
57600,
115200.
Parameter name: modbus_baud_rate
Read command: #get_modbus_baud_rate
Write command: #set_modbus_baud_rate=<value>

Modbus Device ID#

Gets / sets the Modbus RTU slave address. Must be unique on the RS485 bus. The accepted value range for Modbus RTU slave address is 1 - 247.

See Modbus ID for the detailed setting description.

Parameter name: modbus_id
Read command: #get_modbus_id
Write command: #set_modbus_id=<value>

Modbus Serial Line Parity#

Gets / sets the serial line parity for RS-485 / Modbus connection. The change takes place immediately. The accepted values are:

See Modbus Parity for the detailed setting description.

none,
odd,
even.
Parameter name: modbus_parity
Read command: #get_modbus_parity
Write command: #set_modbus_parity=<value>

Modbus Serial Line Stop Bits#

Gets / sets the number of stop bits for the serial line of RS-485 / Modbus connection. The change takes place immediately. The accepted values are:

See RS-485 Stop Bits for the detailed setting description.

one,
two.
Parameter name: modbus_stopbits
Read command: #get_modbus_stopbits
Write command: #set_modbus_stopbits=<value>

SDI-12 Address#

Address of the device on the SDI-12 bus. Valid range is 0-61, which will be converted to characters 0-9, A-Z and a-z.

See SDI-12 ID for the detailed setting description.

Parameter name: sdi_id
Read command: #get_sdi_id
Write command: #set_sdi_id=<value>

Disable NMEA Output#

Gets / sets the parameters that disables NMEA sentence output on RS-232. The accepted values are:

off,
on.
Parameter name: disable_nmea
Read command: #get_disable_nmea
Write command: #set_disable_nmea=<value>

Analog Output Type#

Gets / sets the which device measurement will be used to drive the analog output.

See 4 - 20 mA Output Type for the detailed setting description.

The accepted values are:

none,
discharge,
level,
distance,
velocity,
volume.
Parameter name: analog_output
Read command: #get_analog_output
Write command: #set_analog_output=<value>

Analog Output Minimum Value#

Gets / sets the measurement value that corresponds to the minimum output on the analog current interface (4 mA). The corresponding measurement unit is defined by analog_min_unit parameter.

See 4 - 20 mA Minimum Value for the detailed setting description.

Parameter name: analog_min
Read command: #get_analog_min
Write command: #set_analog_min=<value>

Analog Output Minimum Unit#

Gets / sets the measurement unit for the value defined by analog_min parameter. The accepted units depend on the analog_output parameter.

If the analog_output is set to discharge:

m3/s = m³/s,
m3/h = m³/h,
l/s = l/s,
l/h = l/h,
cfs = ft³/s,
gal/min = gal/min,
ML/day = ML/day.

If the analog_output is set to level or distance:

mm = millimeters,
cm = centimeters,
m = meters,
ft = feet,
in = inches.

If the analog_output is set to velocity:

mms = mm/s,
ms = m/s,
mph = mph,
kmh = km/h,
fps = ft/s,
fpm = ft/min,
cms = cm/s.

If the analog_output is set to volume:

m3 = cubic meters,
l = liters,
ft3 = cubic feet,
gal = galons,
ML = mega (million) liters.

See 4 - 20 mA Minimum Value for the detailed setting description.

Parameter name: analog_min_unit
Read command: #get_analog_min_unit
Write command: #set_analog_min_unit=<value>

Analog Output Maximum Value#

Gets / sets the measurement value that corresponds to the maximum output on the analog current interface (20 mA). The corresponding measurement unit is defined by analog_max_unit parameter.

See 4 - 20 mA Maximum Value for the detailed setting description.

Parameter name: analog_max
Read command: #get_analog_max
Write command: #set_analog_max=<value>

Analog Output Maximum Unit#

Gets / sets the measurement unit for the value defined by analog_max parameter. The accepted units depend on the analog_output parameter.

If the analog_output is set to discharge:

m3/s = m³/s,
m3/h = m³/h,
l/s = l/s,
l/h = l/h,
cfs = ft³/s,
gal/min = gal/min,
ML/day = ML/day.

If the analog_output is set to level or distance:

mm = millimeters,
cm = centimeters,
m = meters,
ft = feet,
in = inches.

If the analog_output is set to velocity:

mms = mm/s,
ms = m/s,
mph = mph,
kmh = km/h,
fps = ft/s,
fpm = ft/min,
cms = cm/s.

If the analog_output is set to volume:

m3 = cubic meters,
l = liters,
ft3 = cubic feet,
gal = galons,
ML = mega (million) liters.

See 4 - 20 mA Maximum Value for the detailed setting description.

Parameter name: analog_max_unit
Read command: #get_analog_max_unit
Write command: #set_analog_max_unit=<value>

Configure Power Management Mode (SDI-12 Sleep Mode)#

Gets / sets the automatic SDI-12 sleep mode parameter. When sleep is enabled, the device enters low-power sleep between SDI-12 transactions. When disabled, the sensor runs continuously and is ready at all times. The accepted values are:

See Power Management for the detailed setting description.

on = sleep enabled,
off = sleep disabled (continuous scanning).
Parameter name: sdi_sleep
Read command: #get_sdi_sleep
Write command: #set_sdi_sleep=<value>

Configure Operation Mode#

Gets / sets the operation mode parameter. When the operation mode is set to standby, the device will go to standby mode. In standby mode, it will communicate on all communication interfaces, but the radar transmitters will be turned off to reduce the power, and the instrument will not be making any measurements. The accepted values are:

See Operation Mode for the detailed setting description.

off = normal operation,
on = standby operation.
Parameter name: power_save
Read command: #get_power_save
Write command: #set_power_save=<value>

Configure Wi-Fi Operation Mode#

Gets / sets the WiFi hotspot status:

off = default setting, the WiFi access point on the instrument is disabled,
on = WiFi hotspot on the instrument is active.

See Enable WiFi for the detailed setting description.

Parameter name: enable_wifi
Read command: #get_enable_wifi
Write command: #set_enable_wifi=<value>

Configure Wi-Fi Password#

Gets / sets the WiFi hotspot password. The password must be at least 8 characters long.

See WiFi Password for the detailed setting description.

Parameter name: wifi_password
Read command: #get_wifi_password
Write command: #set_wifi_password=<value>

Configure LiDAR Mode#

Gets / sets the automatic LiDAR scanning mode. The accepted values are:

off = automatic scanning is disabled,
automatic = the channel cross-section is scanned periodically.

See LiDAR Mode for the detailed setting description.

Parameter name: lidar_mode
Read command: #get_lidar_mode
Write command: #set_lidar_mode=<value>

Configure LiDAR Scan Period#

Gets / sets the interval between two consecutive automatic LiDAR scans, in minutes. The valid range is between 1 and 1440 minutes. This parameter is used only when lidar_mode is set to automatic.

See LiDAR Scan Period for the detailed setting description.

Parameter name: lidar_scan_period_min
Read command: #get_lidar_scan_period_min
Write command: #set_lidar_scan_period_min=<value>

Configure LiDAR Left Limit Angle#

Gets / sets how far the LiDAR sweep extends towards the left side of the channel, in degrees measured from the vertical axis of the instrument. The default value of 70 corresponds to the full mechanical sweep range of the sensor.

See Left Limit Angle for the detailed setting description.

Parameter name: lidar_left_limit_angle
Read command: #get_lidar_left_limit_angle
Write command: #set_lidar_left_limit_angle=<value>

Configure LiDAR Right Limit Angle#

Gets / sets how far the LiDAR sweep extends towards the right side of the channel, in degrees measured from the vertical axis of the instrument. The default value of 70 corresponds to the full mechanical sweep range of the sensor.

See Right Limit Angle for the detailed setting description.

Parameter name: lidar_right_limit_angle
Read command: #get_lidar_right_limit_angle
Write command: #set_lidar_right_limit_angle=<value>

Configure Fixed Mounting Angle#

Override measured forward angle with a fixed value (degrees). Changing this parameter will affect the reported velocity as cosine correction behaviour will be changed. Use this parameter only during tow-tank testing. Set 0 to use real measured angle. The accepted value range for fixed angle is: 0 - 89.

Parameter name: fixed_angle
Read command: #get_fixed_angle
Write command: #set_fixed_angle=<value>

Show Data on Error#

Continue reporting velocity data even when angle errors are detected. The accepted values are:

off = clear velocity on error (send 0 as velocity instead of the measured value),
on = keep velocity.
Parameter name: show_data_on_error
Read command: #get_show_data_on_error
Write command: #set_show_data_on_error=<value>

List of Commands#

Perform Soft Reset#

Restarts the device firmware. All settings are retained (stored in non-volatile memory). The device will be unresponsive for a few seconds after issuing this command.

Command: #reset

Reset DFP#

Clears all accumulated DFP history data. Use this after a significant change in site conditions or sensor placement.

Command: #reset_dfp

Factory Reset#

Restores all settings to their factory defaults and restarts the device. This is irreversible.

Command: #factory_reset

Set Staff Gauge Reading#

Takes current reading from the staff gage to automatically adjust the radar_height parameter according to the given value and current measurement of the distance to water surface.

Command: #set_staff_gauge=<value>

Reset Totalizer#

Resets the volume totalizer which keeps track of the total accumulated volume over time.

Command: #reset_totalizer

Start Manual LiDAR Scan#

Starts a single LiDAR scan of the channel cross-section. The command can be used regardless of the configured LiDAR mode. The scan takes 30 to 45 seconds to complete. If a scan is already running, the command is ignored.

See Manual LiDAR Scan for the detailed description.

Command: #start_manual_scan

Check LiDAR Scan Status#

The status of the LiDAR scanning is reported in the #get_info response, in the #lidar_scan_status line:

off = no scan is currently running,
manual = a manually started scan is in progress,
automatic = an automatic scan is in progress.

Send #get_info and read the reported value to check whether a scan is still ongoing:

#lidar_scan_status: manual

Reading LiDAR Scan#

The channel cross-section produced by the most recent manual LiDAR scan (the same data shown on the LiDAR page of the configurator, see 6.3. Using LiDAR) can be read out over the servicing protocol.

Unlike the simple text parameters, the scan is a relatively large data set (up to 1000 measured points). To transfer it efficiently it is serialized to a compact binary form, compressed, and returned in a single dedicated response rather than as a plain #<name>: <value> line.

Request#

#read_lidarscan=manual

Response#

The device replies with a single line:

#lidarscan=<length>,<data>,<crc>\r\n
  • <length> – the number of bytes in the <data> field, as a decimal number.

  • <data> – the scan payload (see below), byte-stuffed so that it does not contain any character that would break the line-based protocol.

  • <crc> – a four-character uppercase hexadecimal CRC-16 (see CRC) computed over the compressed payload before byte-stuffing.

If the scan cannot be prepared (for example, no scan is stored or the device is out of memory), the device responds with:

#lidarscan:ERR

Payload encoding#

The <data> field is produced in three steps:

  1. Serialization. The scanned profile is encoded as a CBOR (RFC 8949) map. The relevant keys are:

    Key

    Type

    Description

    unt

    text string

    Unit of the coordinates. Always mm.

    x

    array of float32

    X coordinates of the profile points, left to right.

    y

    array of float32

    Y coordinates of the profile points. Values are negative, measured downward from the sensor.

    xof, yof

    float32

    X and Y offsets applied to the coordinates. 0 for a raw scan.

    lvl, kfc, shp, sld, sdp, shn

    array / bool / uint

    Discharge and channel-shape metadata. Empty / zero for a raw scan. Can be ignored.

    The x and y arrays have the same length and together define the cross-section points.

  2. Compression. The CBOR byte stream is compressed with Zstandard (zstd).

  3. Byte-stuffing. The compressed bytes are escaped so that no reserved character remains in the payload. Each reserved byte is replaced by the = character followed by a single digit:

    Original byte

    Escaped as

    # (0x23)

    =0

    = (0x3D)

    =1

    , (0x2C)

    =2

    CR (0x0D)

    =3

    LF (0x0A)

    =4

    NUL (0x00)

    =5

    $ (0x24)

    =6

    To recover the compressed payload, reverse this mapping: whenever a = is found, read the following digit and substitute the corresponding byte.

CRC#

The CRC is a CRC-16 with polynomial 0x8005, initial value 0, and input and output reflected. This is the algorithm commonly known as CRC-16/ARC. It is computed over the compressed payload before byte-stuffing (i.e. over the same bytes obtained after un-escaping the received <data> field).

Python example#

The following example reads the scan over the serial port and saves the profile as a CSV file with x and y columns in millimeters. It requires the pyserial, zstandard, and cbor2 packages (pip install pyserial zstandard cbor2).

import csv
import serial
import zstandard
import cbor2

PORT = "COM3"          # serial port of the FX200 (e.g. "/dev/ttyUSB0")
BAUD = 115200
OUTPUT_CSV = "lidar_profile.csv"

# Byte-stuffing table: index -> original byte (see the escaping table above).
SUBS = b"#=,\r\n\x00$"

def unescape(data: bytes) -> bytes:
    out = bytearray()
    i = 0
    while i < len(data):
        if data[i] == ord("="):
            i += 1
            idx = data[i] - ord("0")
            if 0 <= idx <= 6:
                out.append(SUBS[idx])
        else:
            out.append(data[i])
        i += 1
    return bytes(out)

def crc16_arc(data: bytes) -> int:
    """CRC-16/ARC: polynomial 0x8005, init 0, reflected in/out."""
    crc = 0
    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 1:
                crc = (crc >> 1) ^ 0xA001   # 0xA001 = bit-reversed 0x8005
            else:
                crc >>= 1
    return crc

with serial.Serial(PORT, BAUD, timeout=5) as port:
    port.write(b"#read_lidarscan=0\r\n")

    # Read lines until the "#lidarscan=" response arrives.
    line = b""
    while True:
        line = port.readline()
        if not line:
            raise TimeoutError("no response from device")
        if line.startswith(b"#lidarscan"):
            break

if line.startswith(b"#lidarscan:ERR"):
    raise RuntimeError("device could not provide a LiDAR scan")

body = line[len("#lidarscan="):].rstrip(b"\r\n")
length_str, rest = body.split(b",", 1)
length = int(length_str)
escaped = rest[:length]
crc_received = int(rest[length + 1:], 16)

compressed = unescape(escaped)
if crc16_arc(compressed) != crc_received:
    raise ValueError("CRC mismatch")

cbor_bytes = zstandard.ZstdDecompressor().decompress(compressed)
profile = cbor2.loads(cbor_bytes)

with open(OUTPUT_CSV, "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["x_mm", "y_mm"])
    for x, y in zip(profile["x"], profile["y"]):
        writer.writerow([x, y])

print(f"Saved {len(profile['x'])} points to {OUTPUT_CSV}")