 #include <OneWire.h>
 
 /////////////////////////////////////////////////////////////////////////////
-// wifi management stuff
+// resource management stuff ////////////////////////////////////////////////
+byte loopCounter = 0;
+const byte TICK_WIFI_DEBUG = 0;
+const byte TICK_HEAP_DEBUG = 0;
+const byte TICK_MONITOR = 100;
+
+/////////////////////////////////////////////////////////////////////////////
+// wifi management stuff ////////////////////////////////////////////////////
 const byte DNS_PORT = 53;
 IPAddress apIP(192, 168, 1, 1);
 IPAddress netMsk(255, 255, 255, 0);
 DNSServer dnsServer;
-ESP8266WebServer server(80);
+ESP8266WebServer webServer(80);
 const char* ssid = "WaterElf";
 
 /////////////////////////////////////////////////////////////////////////////
-// page generation stuff
+// page generation stuff ////////////////////////////////////////////////////
 const char* pageTop =
   "<html><head><title>WaterElf Aquaponics Helper";
 const char* pageTop2 = "</title>\n"

void printMonitorEntry(monitor_t m, String* buf);

/////////////////////////////////////////////////////////////////////////////
// temperature sensor stuff
OneWire ds(2); // DS1820 on pin 2 (a 4.7K resistor is necessary)
void getTemperature(float* celsius, float* fahrenheit);

/////////////////////////////////////////////////////////////////////////////
// misc utils
int ledState = LOW;     
void ledOn();
void ledOff();
String ip2str(IPAddress address);

/////////////////////////////////////////////////////////////////////////////
// init and main loop ///////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);
  // Serial.setDebugOutput(true);
  if(false) // TODO this interferes with the serial line it seems :-(
    pinMode(BUILTIN_LED, OUTPUT);

  WiFi.mode(WIFI_AP_STA);
  WiFi.softAPConfig(apIP, apIP, netMsk);
  WiFi.softAP(ssid);

  Serial.print("SSID: ");
  Serial.println(ssid);
  Serial.print("IP address(es): local=");
  Serial.print(WiFi.localIP());
  Serial.print("; AP=");
  Serial.println(WiFi.softAPIP());

  dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
  dnsServer.start(DNS_PORT, "*", apIP);

  Serial.println("DNS Server started");

  server.on("/", handle_root);
  server.on("/generate_204", handle_root); // Android support
  server.on("/L0", handle_root);
  server.on("/L2", handle_root);
  server.on("/ALL", handle_root);
  server.onNotFound(handleNotFound);

  server.on("/wifi", handle_wifi);
  server.on("/wifistatus", handle_wifistatus);
  server.on("/chz", handle_chz);
  server.on("/data", handle_data);
  server.begin();
  Serial.println("HTTP server started");

// TODO
//  if(WiFi.hostname("waterelf00001"))
//    Serial.println("set hostname succeeded");
}

void loop() {
  Serial.print("free heap=");
  Serial.println(ESP.getFreeHeap());

// TODO better resource manageme: perhaps
/*
  int ticks = 0;
  const int MONITOR_FREQUENCY = 100; // once every 100 ticks
  ...
  if(++ticks % MONITOR_FREQUENCY == 0) {
    updateSensorData(monitorData);
    delay(100);
  }

*/

  dnsServer.processNextRequest();
  server.handleClient();
  delay(100);

  //int m = monitorCursor;
  ledOn();
  updateSensorData(monitorData);
  // Serial.print("monitorData[monitorCursor].celsius:" );
  // Serial.println(monitorData[m].celsius);
  delay(100);
  ledOff();
}

/////////////////////////////////////////////////////////////////////////////
// wifi management stuff ////////////////////////////////////////////////////
void handleNotFound() {
  Serial.print("URI Not Found: ");
  Serial.println(server.uri());
  // TODO send redirect to /? or just use handle_root?
  server.send(200, "text/plain", "URI Not Found");
}

void handle_root() {

  const char *checked = " checked";

  int n = WiFi.scanNetworks();
  Serial.print("scan done: ");
  if(n == 0) {
    Serial.println("no networks found");
    f += "No wifi access points found :-( ";
