     if(valves != 0) delete(valves);
     valves = new Valve[numValves];
 
+    // set up staggered valve starts
+    staggerMins = cycleMins / numValves;
     long t = millis();
     long nextCycleStart = t;
     for(int i = 0; i < numValves; i++) {

    }
  }
};
int Valve::counter = 1;             // definition (the above only declares)

class FlowController { // the set of valves and their config ////////////////
  public:
  int numValves = 3;                // WARNING! call init if resetting!
  char cycleMinutes = 60;           // how long is a flood/drain cycle?
  char maxSimultaneousDrainers = 1; // how many beds can drain simultaneously
  char minBedsWet = 1;              // min beds that are full or filling
  char maxBedsWet = 2;              // max beds that are full or filling
  char staggerMins = 10;            // gap to leave between valve startups
  Valve* valves = 0;                // the valves and their states

  FlowController() { init(); }
  int getStaggerMillis() { return staggerMins * 60 * 1000; }

  Serial.begin(115200);

  pinMode(BUILTIN_LED, OUTPUT); // turn built-in LED on
  blink(3);                     // signal we're starting setup

  // read persistent config
  SPIFFS.begin();
  svrAddr = getSvrAddr();

  // start the sensors, the DNS and webserver, etc.
  startPeripherals();
  startAP();
  printIPs();
  startDNS();
  startWebServer();

  // initialise the MCP and the flow controller
  flowController.init();
  mcp.begin();                  // use default address 0 for mcp23008
  for(int i = 0; i < mcpPinsUsed; i++)
    mcp.pinMode(mcpPins[i], OUTPUT);

  // try and set the host name
  if(WiFi.hostname("waterelf"))
    Serial.println("set hostname succeeded");
  else
    Serial.println("set hostname failed");
  delay(300); blink(3);         // signal we've finished config
}

/////////////////////////////////////////////////////////////////////////////
