← Back to list

Praxis: The Hardware Story

How a drawer full of forgotten microcontrollers became the sensory layer for an AI swarm

Martin Suchenak · 2026-05-20 00:26 · 1 claps · 4.0 min read
#ai #microcontrollers
Open on Medium ↗
Wiki topics: AI · AI · General

Praxis: The Hardware Story

How a drawer full of forgotten microcontrollers became the sensory layer for an AI swarm

Every DIY-er has a drawer full of microcontrollers from past projects — Arduinos, ESP32s, STM32s, random RISC-V boards — that one board you bought for a prototype three years ago and never touched again. They sit there, waiting for a purpose, collecting dust alongside a tangle of jumper wires and mystery peripherals.

One evening, I was staring at that drawer, and a thought hit me: what if I could give my Praxis bots physical senses?

Praxis bots already reason, evolve, and communicate. But they live in a purely digital world — reading files, calling APIs, generating text. What if they could feel temperature? See light levels? Control a buzzer? Drive a motor?

That thought became praxis-hardware. And yes, it emptied that drawer pretty fast.

The Core Idea: Microcontrollers as Autonomous Peripherals

The architecture turned out to be surprisingly elegant. Microcontrollers join the same gossip cluster that Praxis bots use, but as peripheral nodes. They broadcast their capabilities using W3C Web of Things Thing Descriptions — a standard way for devices to declare what they can do.

The key insight was making the bot-hardware interaction completely self-describing. An AI bot doesn’t need to know what an ESP32 is. It doesn’t need to understand I2C or GPIO or SPI. It just sees capabilities:

Node: kitchen-sensor
  Peripheral: temp
    Properties: temperature (read)
  Peripheral: light
    Properties: lux (read)
  Peripheral: led_red
    Properties: brightness (read/write)
  Peripheral: buzzer
    Actions: beep

And then it can interact naturally:

# Discover what's out there
list_hardware_nodes()

# Read the temperature
read_property(node="kitchen-sensor", peripheral="temp", affordance="temperature")
# Turn on a light
write_property(node="kitchen-sensor", peripheral="led_red", affordance="brightness", value=128)
# Sound an alarm
invoke_action(node="kitchen-sensor", peripheral="buzzer", affordance="beep")

The bot doesn’t care whether the node is an ESP32, an STM32, or a Linux-based RISC-V board. It just sees what the device can do.

What’s Actually Running on These Boards?

Each hardware node runs a small C++ framework I built with several layers:

HAL (Hardware Abstraction Layer) — a Platform interface with implementations for Arduino and ESP-IDF. This is what makes the same code run on different boards without changes.

Peripheral Layer — individual peripherals (LEDs, temperature sensors, buzzers, range sensors) implement a simple interface where they declare their own WoT properties and actions. The registry auto-generates the full Thing Description from those declarations.

Gossip Node — handles joining the Praxis cluster via UDP multicast, announcing itself, and responding to commands. Communication uses MsgPack for efficient binary serialization — when you’re running on a microcontroller with limited RAM, every byte matters.

Dispatcher — routes incoming commands (read property, write property, invoke action) to the correct peripheral.

Network Transport — pluggable transport layer. WiFi for Arduino, WiFi via lwip for ESP-IDF, Ethernet, or anything custom.

One design decision I’m particularly happy with: the entire framework is header-only C++. No .cpp files in the source directory. This sounds like a minor thing, but when you're targeting multiple platforms with different build systems (Arduino IDE, PlatformIO, ESP-IDF), linker issues will eat your soul. Header-only eliminates an entire class of headaches.

Creating a Node in 60 Seconds

I wanted the developer experience to be frictionless. You can scaffold, build, and flash a new node in about a minute:

# Scaffold a new node
make new-node NODE=kitchen-light BOARD=esp32dev

# Build and flash
make build NODE=kitchen-light
make upload NODE=kitchen-light
make monitor NODE=kitchen-light

Need to add a new peripheral? One command generates a skeleton header where you just fill in the properties, actions, and their handlers:

make new-peripheral NODE=kitchen-light PERIPHERAL=water_pump

The framework handles registration, manifest generation, and command dispatch automatically.

Configuration lives in data/config.json on SPIFFS, so you can change WiFi credentials, node name, or gossip settings without recompiling:

make upload-config NODE=kitchen-light

An Example: The Sensor Node

The repo includes a reference implementation: esp32-c6-sensors. It's a full sensor node running on an ESP32-C6 with LED control, a buzzer, temperature sensor, light sensor, and range sensor.

A Praxis bot can discover this node, read environmental data, and take physical actions based on its reasoning. “The temperature is above 30 degrees? Sound the buzzer and blink the LED red.”

Why Not Just Use MQTT?

I get this question a lot. MQTT is the standard for IoT, and for good reason. But Praxis already has a gossip protocol with discovery, authentication, and message routing. Adding MQTT would mean running a broker, configuring topics, and managing yet another communication layer in a system that already has one.

By having hardware nodes speak the same gossip protocol, everything is unified. Bots discover devices the same way they discover each other. Commands flow through the same authenticated channels. No broker, no topic management, no additional infrastructure.

The W3C WoT layer on top means the interaction is standardized and self-describing. The device tells you what it can do, rather than you needing to know the topic structure or parse some custom protocol.

Supported Platforms

Right now the framework attempts to support several platforms:

  • ESP32 with Arduino or ESP-IDF frameworks
  • STM32
  • Milk-V

Adding a new platform means implementing a simple Platform interface and a NetworkTransport—everything else works unchanged.

Where Is This Going?

Right now, the nodes are reactive — they respond to bot commands. But I’m working on making them proactive: nodes that push sensor data to interested bots on a schedule, trigger alerts based on thresholds, and coordinate with each other without bot involvement.

Imagine a swarm where a temperature node detects a spike, a bot reasons about what it means, and a motor node takes corrective action — all without human intervention. That’s where this is heading.

The bigger picture is really about one thing: making the physical world as accessible to AI agents as the digital one. Bots already navigate file systems and APIs. Now they can navigate rooms.

If you’ve got a drawer full of microcontrollers and an itch to give them a purpose, come check it out: github.com/martinsuchenak/praxis-hardware


메타데이터
post_id
fae6aecc3ea6
slug
praxis-the-hardware-story-fae6aecc3ea6
url
https://medium.com/@martin.suchenak/praxis-the-hardware-story-fae6aecc3ea6
canonical_url
https://medium.com/@martin.suchenak/praxis-the-hardware-story-fae6aecc3ea6
author_url
https://medium.com/@martin.suchenak
status
ok
fetched_at
2026-06-11 21:11:36