Skip to content
Ilia Maslakov edited this page Sep 18, 2026 · 1 revision

Release notes for the pump controller

The controller keeps a tank between two levels. It reads the float switches ten times a second, drives the pump through a relay, and writes a line to the journal whenever anything changes. This release makes the dry run guard work on cold starts, replaces the old SET LEVEL command with a proper config file, and drops the serial console in favour of the network one.

Read the migration notes before you flash a controller that has been in the field.

What changed

Area Before Now Note
Guard 2 s 30 s cold start is covered
Config SET command /etc/pump.conf reload without a reboot
Console serial, 9600 TCP on port 4004 serial header removed
Journal one file one file per day 14 days are kept

Upgrading

  1. Read the current settings and keep them somewhere safe.
  2. Flash the firmware.
  3. Write the settings into /etc/pump.conf.
  4. Watch the first two cycles with the journal open.
#!/bin/sh
# save the settings of a controller before flashing it
host=${1:?usage: dump-settings HOST}

for key in level.low level.high guard.seconds pump.max_run; do
    printf '%s = %s\n' "$key" "$(pumpctl --host "$host" get "$key")"
done > "settings-$host.conf"

The guard is what keeps the pump from running dry.

Do not set guard.seconds below the time the intake pipe needs to fill, or the pump will start into an empty line.

Checklist

  • settings of every controller are saved
  • firmware built from the tag, not from the branch
  • spare controller flashed and put in the van
  • the crew knows the new console port

How a cycle runs

flowchart LR
    Start((Idle)) -->|low float| Check{Water?}
    Check -->|yes| Run[Run pump]
    Check -->|no| Guard(Hold 30 s)
    Run --> Stop((Idle))
    Guard --> Stop
Loading

The controller, the relay and the journal talk in this order:

sequenceDiagram
    Controller->>Relay: close
    Relay-->>Controller: closed
    Controller->>Journal: pump started
    Controller->>Relay: open
    Journal-->>Controller: written
Loading

Inside the firmware

/* One pass of the control loop: read the floats, decide, drive the relay. */
static void
pump_step (struct pump *p, unsigned now)
{
    # inline comment
    int low = gpio_read (p->pin_low);
    int high = gpio_read (p->pin_high);

    if (!low && now - p->stopped_at < p->guard)
        return;                 /* the intake pipe is still filling */
    if (high)
        pump_stop (p, now);
    else if (low)
        pump_start (p, now);
}

The classes behind it:

classDiagram
    Device <|-- Relay
    Device <|-- Floats
    Device <|-- Journal
    Device : +int pin
    Device : +setup()
    class Relay{
      +bool closed
      +close()
      +open()
    }
    class Floats{
      +bool low
      +bool high
      +read()
    }
    class Journal{
      +string path
      +write()
    }
Loading

Sizing the tank

The pump has to move what the field takes over a day, so the run time per cycle is $t = V / Q$, with the tank volume $V$ and the flow $Q$. Round the guard up to the next whole minute.

$$ \begin{cases} Q = 1.2 \cdot \pi r^2 v, & \text{full pipe} \\ Q = 0.7 \cdot \pi r^2 v, & \text{silted pipe} \end{cases} $$

The panel draws the state of the twenty lamps as one matrix, a row per float board and a column per channel:

$$ \begin{pmatrix} 1 & 0 & 0 & 1 & 0 \\ 0 & 1 & 1 & 0 & 0 \\ 1 & 1 & 0 & 0 & 1 \\ 0 & 0 & 1 & 1 & 1 \end{pmatrix} $$

Angles in the sump

The intake sits in a corner, so the pipe, the wall and the floor make the right triangle $\triangle ABC$, with the right angle at $B$. The wall gives $AB$, the fitter measures $\angle BAC$, and the run along the floor follows:

$$ BC = AB \cdot \tan \angle BAC, \quad \angle ACB = 90^\circ - \angle BAC $$

For $AB = 1.4$ m and $\angle BAC = 35^\circ$ that is $BC \approx 0.98$ m and $\angle ACB = 55^\circ$. Two checks on site: $AB \perp BC$, and the bracket runs $\parallel$ to the floor. A sump with the same corner and the same angle takes the same pipe, because $\triangle ABC \cong \triangle A'B'C'$.

Field data

Term : a word the manual uses in a sense of its own.

Dry run : the pump turning with no water in the line. It ruins the seal in about forty seconds.

Cold start : power applied to a controller whose tank state is unknown.


Two sites report the sensor drift described in the maintenance note[^drift], and one of them runs the old relay board[^board]. Both are on the list for the next visit. The parts come from the supplier, and the pressure sensor from Nord Instruments.

Signs on the panel: 高 for the high float, 低 for the low one, and the pump shows 💧 while it runs.

[^drift]: Sensors older than three seasons drift by up to 4 cm. Re-seat the float and set level.low from the measured value, not from the drawing.

[^board]: The A2 board answers the open command but not the close one when it is cold. Swap it.

Clone this wiki locally