esp-mcmax-example

Example of the component a-barta/esp-mcmax v2.1.0
# 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"

or download archive (~5.32 KB)