Was spricht gegen einen anderen Prozessor?
Wieviel Speicher bräuchtest du denn noch?
Ich habe Halterungen sowohl für das angesprochene i2c-Zeugs als auch den Uno, die sind gleich groß und sollen als Stapel übereinander montiert werden. Die i2c-Platinen hätten nen Steckplatz für einen Nano 
Aber mit dem Uno könnte ich zur Not leben.
Größer wäre nicht so optimal.
Meiner Erfahrung nach kosten viele Serial.print()s reichlich Speicher kosten.
Die Serials raus bringen "nur" 1K. Und ein wenig Debug, wenn irgendwas nicht geht wäre schon nicht schlecht. Hatte schon überlegt nur mit ner Art Kennziffern zu arbeiten, dann müsste ich mir aber einen Parser auf PC-Seite bauen, der mir das dann wieder "übersetzt".
Allerdings blieben die Serials dennoch und nur die zeichenketten würden ggfs. kleiner.
Kannst Du evtl. die Texte von dort in den Flash verlagern und durch ein passendes Konstrukt mit einer Serial.print()-Anweisung zurecht kommen?
Ich dachte mit F() und PROGMEM das getan zu haben.
Der Code sieht sehr schön aus, stilistisch und inhaltlich, viel Optimierungspotential kann ich da leider nicht finden,
Das ist schön zu hören, aber auch schade 
Vermutlich wird der meiste Speicher von den Bibliotheken verbraten?
Das mag sein, aber ich bin leider nicht in der Lage die vielleicht für mich nur relevanten Sachen rauszunehmen und ggfs. durch Assembler oder durch eigene Konstrukte zu ersetzen. 
Ich hatte angenommen, bei den strcat z.b. noch ein wenig sparen zu können, hatte das zwar weitgehend mal gegen s(n)printf ersetzt, das machte es nur noch größer.
Mir ist auch etwas aufgefallen, um Zeile 173 rum. dort steht:
MAC2String(ethernet_mac, cStringMac);
Ethernet.begin(ethernet_mac); // DHCP // , ethernet_lip, ethernet_dns, ethernet_gateway, ethernet_netmask);
Sketch kompiliert:
Program size: 31.966 bytes (used 99% of a 32.256 byte maximum) (5,16 secs)
Minimum Memory Usage: 1736 bytes (85% of a 2048 byte maximum)
ändere ich das in:
Ethernet.begin(ethernet_mac); // DHCP // , ethernet_lip, ethernet_dns, ethernet_gateway, ethernet_netmask);
MAC2String(ethernet_mac, cStringMac);
Sketch kompiliert:
Program size: 31.978 bytes (used 99% of a 32.256 byte maximum) (5,21 secs)
Minimum Memory Usage: 1736 bytes (85% of a 2048 byte maximum)
Das ist bspw. etwas, was ich so gar nicht verstehen kann.
Oder bei den Vergleichen in der mqtt_callback, da stehen recht lange Zeichenketten, da dachte ich evtl. auch an Pointer auf diese und Mehrfachverwendung der Zeichenketten, aber habe dafür keine Lösung gefunden.
Zum Thema Switches: Alternative?
Zum String: Ich habe sie weitgehend draußen, habe aber noch eine Function drin als String, da Serial mir sonst mein Byte-Array nicht als ASCII-Werte anzeigt.
Überhaupt so bei den Konvertierungsfunktionen im Pragma Allgemeine Funktionen, da hoffte ich auf ein wenig Potenzial.
Bezügl. noch erforderlichem Speicherplatz, sagen kann ich das nicht, wollen würde ich gern in etwa das.
(Das ist nur eine Brain-flash-liste, die mir so während des Codens in den Sinn kam. Über Sinn und Unsinn der einzelnen Punkte habe ich noch nicht abschließend entschieden.):
- Abfrage via MQTT von GPIO-Ports und einzelnen Pins ==> PININ
- LED-Status überarbeiten
- LED 13 auf anderen GPIO setzen mit eigener LED?
- ext. Taster am Arduino als Testknopf, ggfs. mit long-press-erkennung oder über 2. button
- per mqtt kompletten reboot auslösen
- Idee: DHCP o. feste ip "irgendwie" von außen konfigurierbar machen
- via mqtt einstellungen schicken, ins eeprom speichern
- wenn dort daten da sind entsprechend starten, ggfs. über o.g. buttons die werte setzen
- wenn der button gedrückt, dann dhcp bspw.
- ggfs auf mac erweitern, starten mit einheitlicher standard-mac, dann wechseln via mqtt und eeprom
- ggfs. konfigurationsoptionen auch via serial coden
- Broker IP + Zugangsdaten müsste man auch tauschen können
- zumindest via serial