# esp-mcmax-example The smallest end-to-end MCMAX node. It declares two string attributes and one command, then runs a 1 Hz timer that republishes the attribute values. Use it as a starting point for your own firmware. ## What it demonstrates | Item | Name | Type | Notes | |---|---|---|---| | Attribute | `test_rw` | `str`, `READ_WRITE` | Writes from the bridge are stored and echoed back. | | Attribute | `test_ro` | `str`, `READ` | Always publishes the constant `"Read only string"`. | | Command | `toggle_led` | — | Payload `1`/`on`/`On`/`ON` drives the LED high, anything else drives it low. | The flow, in `main/esp-mcmax-example.c`: 1. Two `tango_attribute_config_t` and one `tango_command_config_t` are declared and gathered into pointer arrays. 2. `data_in_callback` reacts to `MCMAX_EVENT_DATA_IN`: it stores writes to `test_rw` and drives the LED on `toggle_led`. 3. `mcmax_config_t` is populated with only the attribute/command arrays and the callback — the connection settings come from NVS at runtime. 4. `mcmax_init()` brings up every subsystem. 5. A 1 Hz `esp_timer` calls `mcmax_post()` to publish both attribute values. ## Target board The shipped `sdkconfig.defaults` targets an **Olimex ESP32-POE-IND**: PHY `LAN87XX`, reset GPIO `12`, PHY address `0`, RMII clock output on GPIO `17`. > **GPIO 33 caveat.** `OLIMEX_LED` in `main/esp-mcmax-example.c` is set to > `GPIO_NUM_33`, which is the user LED on the Olimex **ESP32-EVB**, *not* the > POE-IND. On a POE-IND board the `toggle_led` command will toggle a pin with > nothing attached. Pick a GPIO that exists on your hardware. ## Building ```bash idf.py build idf.py -p /dev/ttyUSB0 flash monitor ``` The component is consumed in-tree via `override_path: ../../../` in `main/idf_component.yml`, so edits to the root `.c`/`.h` files are picked up without re-fetching from the Component Registry. `sdkconfig` is gitignored; it materializes from `sdkconfig.defaults` on the first build. After a deliberate `idf.py menuconfig` change, regenerate the defaults with `idf.py save-defconfig`. The partition table (`partitions.csv`) defines **factory + ota_0 + ota_1** — required so the OTA subsystem has a target partition to flash into. ## Adapting to another board 1. **Ethernet PHY.** Set the PHY type, reset GPIO, PHY address and RMII clock options in `menuconfig` under *Component config → Ethernet*, then run `idf.py save-defconfig` to capture them in `sdkconfig.defaults`. The `espressif/ethernet_init` managed component reads these. 2. **Status LED.** Change the `OLIMEX_LED` macro to a GPIO that exists on your board, or drop the LED handling entirely. 3. **Flash size / partitions.** Adjust `CONFIG_ESPTOOLPY_FLASHSIZE_*` and `partitions.csv` if your module has less than 4 MB of flash. ## Runtime configuration On first boot the device uses the hard-coded NVS defaults (broker `test-mqtt.org`, user `user`, password `password`, name `MC-MAX`). Connect to the device's IP on **port 80** to set the broker, credentials, device name and OTA endpoint via the configuration form; values persist across reboots and the device restarts to apply them. See the [component README](../../README.md) for the MQTT topic layout, the public API and the OTA server protocol.
To create a project from this example, run:
idf.py create-project-from-example "a-barta/esp-mcmax=2.1.0:esp-mcmax-example"