Board Reference Matrix
This document is the ground truth for all CeresFlows firmware documentation. Every code example and warning in other chapters references the information here.
Before you write a single line of firmware, identify your board in the table below and understand its constraints. Ignoring these constraints is the most common cause of firmware failures.
Supported Boards
CeresFlows supports controllers in two tiers:
| Tier | Purpose | Examples |
|---|---|---|
| Main Controller | Full-featured, all commands, WiFi | Arduino UNO R4 WiFi, ESP32 WROOM-32 |
| Satellite Controller | Subset of commands, cheaper, specialized | ESP8266 NodeMCU, Arduino Nano |
[!NOTE] A “Satellite” controller is not a limitation of CeresFlows — it is a valid architectural choice. A cheap ESP8266 dedicated to a single humidity sensor is often the right engineering decision.
Board Overview
| Arduino UNO R4 WiFi | ESP32 WROOM-32 | ESP8266 NodeMCU | Arduino Nano (Classic) | |
|---|---|---|---|---|
| Chip | Renesas RA4M1 | Espressif ESP32 | Espressif ESP8266 | ATmega328P |
| Architecture | ARM Cortex-M4 | Xtensa LX6 (dual-core) | Xtensa LX106 (single-core) | AVR 8-bit |
| Flash Memory | 256 KB | 4 MB | 4 MB | 32 KB ⚠️ |
| RAM (SRAM) | 32 KB | 320 KB | 80 KB | 2 KB 🔴 |
| Clock Speed | 48 MHz | 240 MHz | 80/160 MHz | 16 MHz |
| Tier | Main | Main | Satellite | Satellite |
| Firmware Status | ✅ Tested | ⚠️ Theoretical | ⚠️ Theoretical | ⚠️ Theoretical |
[!CAUTION] The Arduino Nano has only 2 KB of RAM and 32 KB of Flash. A full-featured firmware with WiFi, ArduinoJson, and all bus commands will not fit. You must compile a stripped-down version. See the memory budget section below.
Transport Layer
How the board receives commands from the CeresFlows backend.
| Transport | Arduino UNO R4 WiFi | ESP32 WROOM-32 | ESP8266 NodeMCU | Arduino Nano |
|---|---|---|---|---|
| UDP (WiFi) | ✅ | ✅ | ✅ | ❌ No WiFi |
| MQTT (WiFi) | ✅ | ✅ | ✅ | ❌ No WiFi |
| Serial (USB/UART) | ✅ Always active | ✅ Always active | ✅ Always active | ✅ Only option |
[!IMPORTANT] Arduino Nano has no WiFi hardware. It can only receive commands via the USB Serial port. This means it cannot be used as a standalone networked controller — it must be connected directly to the computer running CeresFlows.
WiFi Library (Critical — Wrong Library = Compile Error)
| Board | Required #include | Common Mistake |
|---|---|---|
| Arduino UNO R4 WiFi | #include <WiFiS3.h> | Using <WiFi.h> — will not compile |
| ESP32 WROOM-32 | #include <WiFi.h> | Using <WiFiS3.h> or <ESP8266WiFi.h> |
| ESP8266 NodeMCU | #include <ESP8266WiFi.h> | Using <WiFi.h> |
| Arduino Nano | ❌ No WiFi library applies | N/A |
[!WARNING]
<WiFi.h>on the Arduino IDE resolves to different libraries depending on which board is selected in the Board Manager. Do not copy-paste WiFi code between board types without checking the include.
Hardware Capabilities
Analog Input
| Arduino UNO R4 WiFi | ESP32 WROOM-32 | ESP8266 NodeMCU | Arduino Nano | |
|---|---|---|---|---|
| Available pins | A0–A5 (6 pins) | GPIO34, 35, 36, 39 (4 dedicated input-only pins) | A0 (1 pin only) | A0–A5 (6 pins) |
| ADC resolution | 10-bit (0–1023) | 12-bit (0–4095) | 10-bit (0–1023) | 10-bit (0–1023) |
| Max input voltage | 5V (AREF) | 3.3V | 1.0V 🔴 | 5V (AREF) |
[!CAUTION] ESP8266 has a single analog input (A0) with a maximum input voltage of 1.0V. Connecting a standard 0–5V sensor directly to A0 will damage the ESP8266. A voltage divider is required. Additionally, there is only one analog pin — you cannot read two analog sensors simultaneously on an ESP8266.
[!WARNING] ESP32 ADC returns 0–4095, not 0–1023. If your backend template or calibration is configured for a 10-bit range, readings will appear 4× higher than expected. Always configure your device template with the correct ADC resolution for your board.
Digital I/O
| Arduino UNO R4 WiFi | ESP32 WROOM-32 | ESP8266 NodeMCU | Arduino Nano | |
|---|---|---|---|---|
| Digital pins | D0–D13 | GPIO0–GPIO39 (not all usable) | GPIO0–GPIO16 | D0–D13 |
| PWM pins | D3, D5, D6, D9, D10, D11 | Most GPIO (ledc) | GPIO4, GPIO5, GPIO12, GPIO13, GPIO14, GPIO15 | D3, D5, D6, D9, D10, D11 |
analogWrite() | ✅ Standard | ⚠️ Requires ESP32 Arduino core ≥ 3.x | ✅ Standard | ✅ Standard |
[!WARNING] ESP32 does not support the standard
analogWrite()function in older Arduino core versions (< 3.x). If you are using an older ESP32 board package, you must useledcWrite()instead. Always check your installed ESP32 Arduino core version before using PWM commands.
I2C Bus
| Arduino UNO R4 WiFi | ESP32 WROOM-32 | ESP8266 NodeMCU | Arduino Nano | |
|---|---|---|---|---|
| Hardware I2C | ✅ 1× | ✅ 2× (configurable pins) | ✅ 1× | ✅ 1× |
| Default SDA pin | A4 (pin 18) | GPIO21 | GPIO4 | A4 |
| Default SCL pin | A5 (pin 19) | GPIO22 | GPIO5 | A5 |
| Library | <Wire.h> | <Wire.h> | <Wire.h> | <Wire.h> |
[!NOTE] The
Wire.hlibrary is consistent across all boards. However, the physical pin numbers differ. I2C_TRANSFER commands always specify the I2C device address — the SDA/SCL pins are fixed by the board and cannot be changed at runtime without modifying the firmware.
UART / Serial Bus
| Arduino UNO R4 WiFi | ESP32 WROOM-32 | ESP8266 NodeMCU | Arduino Nano | |
|---|---|---|---|---|
| Hardware UART ports | 1 (Serial1: pins 0/1) | 3 (Serial, Serial1, Serial2) | 1 (Serial: pins 1/3) | 1 (Serial: pins 0/1, shared with USB) |
| SoftwareSerial | ✅ Available | ⚠️ Unofficial support | ✅ Available | ✅ Available |
| UART + Modbus simultaneously | ⚠️ Only via SoftwareSerial (risk of conflict) | ✅ Yes — different hardware UARTs | ⚠️ Only via SoftwareSerial | ⚠️ Only via SoftwareSerial |
[!WARNING] On all boards except ESP32, running
UART_TRANSFERandMODBUS_RTUat the same time on different sensors requires two SoftwareSerial instances — which is unreliable above 9600 baud and can cause data corruption. The ESP32 is the only recommended board for simultaneous UART + Modbus use due to its multiple hardware UART ports.
SPI Bus
| Arduino UNO R4 WiFi | ESP32 WROOM-32 | ESP8266 NodeMCU | Arduino Nano | |
|---|---|---|---|---|
| Hardware SPI | ✅ (pins 11/12/13) | ✅ (GPIO23/19/18) | ✅ (GPIO13/12/14) | ✅ (pins 11/12/13) |
| Library | <SPI.h> | <SPI.h> | <SPI.h> | <SPI.h> |
| CS pin | Manual (any digital pin) | Manual (any digital pin) | Manual (any digital pin) | Manual (any digital pin) |
System Functions
Critical functions that differ between chips. Getting these wrong causes silent failures or compiler errors.
| Function | Arduino UNO R4 WiFi (RA4M1) | ESP32 | ESP8266 | Arduino Nano (ATmega328P) |
|---|---|---|---|---|
| Software reset | NVIC_SystemReset() | esp_restart() | ESP.restart() | wdt_enable(WDTO_15MS); while(1); |
| Free memory | Stack/heap pointer arithmetic | ESP.getFreeHeap() | ESP.getFreeHeap() | Stack/heap pointer arithmetic |
| EEPROM write | EEPROM.write(addr, val) | Preferences library (NVS) or EEPROM.begin(N) | EEPROM.begin(N); EEPROM.write(...) | EEPROM.write(addr, val) |
| EEPROM read | EEPROM.read(addr) | Preferences library or EEPROM.read() after begin(N) | EEPROM.read(addr) after begin(N) | EEPROM.read(addr) |
[!CAUTION] ESP32 does not have a traditional EEPROM. The
EEPROM.hlibrary on ESP32 emulates EEPROM in flash. You must callEEPROM.begin(size)before any read/write operations, andEEPROM.commit()after writes — otherwise data is lost on reboot. ForgettingEEPROM.commit()is a very common bug.
[!CAUTION] ESP8266 also requires
EEPROM.begin(N)whereNis the number of bytes you intend to use. Without this call, all reads return0xFFand writes are silently ignored.
Interrupt-Capable Pins (for PULSE_COUNT)
The PULSE_COUNT command uses hardware interrupts. Not all pins support interrupts.
| Board | Interrupt-capable pins |
|---|---|
| Arduino UNO R4 WiFi | D2, D3 (primary) + others via attachInterrupt |
| ESP32 WROOM-32 | Any GPIO (except input-only pins in some configurations) |
| ESP8266 NodeMCU | GPIO0–GPIO15 (GPIO16 does NOT support interrupts) |
| Arduino Nano | D2, D3 only |
[!WARNING] On Arduino Nano, only pins D2 and D3 support hardware interrupts. If you connect a flow meter or pulse sensor to any other pin and use
PULSE_COUNT, no pulses will be counted and the command will always return 0.
Memory Budget (Arduino Nano)
The Nano’s 2 KB RAM and 32 KB Flash impose hard limits. Here is what fits:
| Feature | Flash cost (approx.) | RAM cost (approx.) | Include? |
|---|---|---|---|
| Core firmware loop | ~6 KB | ~200 B | ✅ Always |
ArduinoJson (StaticDoc 128B) | ~8 KB | 128 B static | ✅ Yes — use StaticJsonDocument only |
ArduinoJson (DynamicDoc 512B) | ~8 KB | 512 B heap | ❌ No — heap too small |
Wire.h (I2C) | ~2 KB | ~50 B | ✅ If needed |
SPI.h | ~1 KB | ~30 B | ✅ If needed |
SoftwareSerial | ~2 KB | ~64 B | ⚠️ One instance max |
WiFi* any library | +40–80 KB | +20–50 KB | ❌ Impossible — no WiFi hardware |
[!CAUTION] On Arduino Nano, never use
DynamicJsonDocument. Its heap allocation will collide with the stack. Use onlyStaticJsonDocument<N>with N ≤ 128. For complex commands likeI2C_TRANSFERorMODBUS_RTUthat require parsing multi-field JSON, the Nano may not have sufficient RAM — test carefully.
Command Compatibility Summary
| Command | Arduino UNO R4 WiFi | ESP32 WROOM-32 | ESP8266 NodeMCU | Arduino Nano |
|---|---|---|---|---|
PING | ✅ | ✅ | ✅ | ✅ |
STATUS | ✅ | ✅ | ✅ | ✅ |
INFO | ✅ | ✅ | ✅ | ✅ |
RESET | ✅ | ✅ | ✅ | ✅ (watchdog) |
HYDROPONICS_DISCOVERY | ✅ | ✅ | ✅ | ❌ No WiFi |
ANALOG | ✅ (6 pins) | ✅ (4 pins, 12-bit) | ⚠️ (1 pin, max 1V) | ✅ (6 pins) |
DIGITAL_READ | ✅ | ✅ | ✅ | ✅ |
DIGITAL_WRITE / RELAY_SET | ✅ | ✅ | ✅ | ✅ |
PWM_WRITE | ✅ | ⚠️ (core ≥ 3.x) | ✅ | ✅ |
SERVO_WRITE | ✅ | ✅ | ⚠️ Limited | ✅ |
DHT_READ | ✅ | ✅ | ✅ | ✅ |
ONEWIRE_READ_TEMP | ✅ | ✅ | ✅ | ✅ |
ONEWIRE_SCAN | ✅ | ✅ | ✅ | ✅ |
ULTRASONIC_TRIG_ECHO | ✅ | ✅ | ✅ | ✅ |
HX711_READ | ✅ | ✅ | ✅ | ✅ |
PULSE_COUNT | ✅ | ✅ | ✅ (not GPIO16) | ⚠️ D2/D3 only |
I2C_TRANSFER | ✅ | ✅ | ✅ | ⚠️ RAM limited |
UART_TRANSFER | ✅ | ✅ | ✅ | ⚠️ Shares USB port |
MODBUS_RTU | ✅ | ✅ | ✅ | ⚠️ RAM limited |
SPI_TRANSFER | ✅ | ✅ | ✅ | ⚠️ RAM limited |
| TTL Watchdog | ✅ | ✅ | ✅ | ✅ |
| EEPROM persistence | ✅ | ⚠️ EEPROM.begin(N) + .commit() | ⚠️ EEPROM.begin(N) + .commit() | ✅ |
This document is the reference baseline for all CeresFlows firmware documentation. All board-specific warnings in other chapters derive from the constraints listed here.