diff --git a/.gitignore b/.gitignore index 2396616..34b0db7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,55 @@ +# PlatformIO build artifacts .pio/ .vscode/ -lib/ -include/ \ No newline at end of file +.pioenvs/ +.piolibdeps/ +.clang_complete +.gcc-flags.json + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# OS files +.DS_Store +Thumbs.db + +# IDE files +*.swp +*.swo +*~ +.idea/ +*.iml + +# Environment files (secrets) +.env +secrets.h + +# Logs +*.log diff --git a/README.md b/README.md index 2a549f3..d00e749 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,138 @@ MicroClaw is the smallest member of the Claw family — a bare-metal AI agent th └─────────┘ ``` +--- + +## Getting Started + +### Prerequisites + +- **PlatformIO** — Install via [PlatformIO IDE](https://platformio.org/install/ide?install=vscode) or [CLI](https://docs.platformio.org/en/latest/core/installation/index.html) +- **ESP32 Development Board** — ESP32-DevKitC, ESP32-C3, or compatible +- **USB Cable** — For flashing and serial monitoring + +### Installation + +1. **Clone the repository**: + ```bash + git clone https://github.com/Clawland-AI/microclaw.git + cd microclaw + ``` + +2. **Configure WiFi and MQTT**: + Edit `src/main.cpp` and replace the placeholder credentials: + ```cpp + const char* WIFI_SSID = "your_wifi_ssid"; + const char* WIFI_PASSWORD = "your_wifi_password"; + const char* MQTT_BROKER = "mqtt.example.com"; + ``` + +3. **Install dependencies** (automatic): + ```bash + pio lib install + ``` + +### Flashing Instructions + +#### Option 1: PlatformIO IDE (VS Code) + +1. Open the `microclaw` folder in VS Code with PlatformIO extension +2. Connect your ESP32 via USB +3. Click **PlatformIO: Upload** (arrow icon in the bottom toolbar) +4. Open **PlatformIO: Serial Monitor** (plug icon) to view logs + +#### Option 2: PlatformIO CLI + +1. Connect your ESP32 via USB +2. Build and upload: + ```bash + pio run --target upload + ``` +3. Monitor serial output: + ```bash + pio device monitor + ``` + +#### Option 3: Manual Flashing (esptool.py) + +If PlatformIO is unavailable, use `esptool.py`: + +```bash +# Build firmware +pio run + +# Find COM port (Linux: /dev/ttyUSB0, macOS: /dev/cu.usbserial-*, Windows: COM3) +ls /dev/tty* + +# Flash firmware +esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 \ + write_flash -z 0x1000 .pio/build/esp32/bootloader.bin \ + 0x8000 .pio/build/esp32/partitions.bin \ + 0x10000 .pio/build/esp32/firmware.bin + +# Monitor serial +minicom -D /dev/ttyUSB0 -b 115200 +``` + +### Troubleshooting + +#### ESP32 not detected + +```bash +# Check USB connection +lsusb # Linux +system_profiler SPUSBDataType # macOS + +# Add user to dialout group (Linux) +sudo usermod -a -G dialout $USER +# Log out and back in +``` + +#### Upload fails + +```bash +# Hold BOOT button on ESP32 while clicking Upload +# Or use slower baud rate +pio run --target upload --upload-port /dev/ttyUSB0 --upload-speed 115200 +``` + +#### WiFi connection fails + +- Verify SSID/password are correct +- Check 2.4GHz network (ESP32 doesn't support 5GHz) +- Ensure network allows new devices + +#### MQTT connection fails + +- Verify broker address and port +- Check firewall rules +- Test broker with `mosquitto_pub`: + ```bash + mosquitto_pub -h mqtt.example.com -t test -m "hello" + ``` + +### Project Structure + +``` +microclaw/ +├── platformio.ini # PlatformIO config (board, libraries) +├── src/ +│ └── main.cpp # Main firmware code +├── lib/ +│ └── README.md # Custom sensor driver libraries +├── .gitignore # Ignore build artifacts +└── README.md # This file +``` + +### Next Steps + +- **Add sensors**: See issue [#2 - DHT22 sensor driver](../../issues/2) +- **Enable MQTT**: Configure your broker in `main.cpp` +- **Low power mode**: See issue [#5 - Deep sleep](../../issues/5) +- **Hardware guide**: See issue [#4 - Wiring diagrams](../../issues/4) + +--- + ## Status 🚧 **Pre-Alpha** — Architecture design phase. Looking for contributors! diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..c781fad --- /dev/null +++ b/lib/README.md @@ -0,0 +1,45 @@ +# Sensor Driver Libraries + +This directory contains custom sensor driver libraries for MicroClaw. + +## Structure + +Each sensor driver should be in its own subdirectory: + +``` +lib/ +├── README.md (this file) +├── DHT22Driver/ +│ ├── DHT22Driver.h +│ ├── DHT22Driver.cpp +│ └── examples/ +├── BME280Driver/ +│ ├── BME280Driver.h +│ ├── BME280Driver.cpp +│ └── examples/ +└── ... +``` + +## Usage + +PlatformIO will automatically discover libraries in this directory and make them available to `#include` in `src/main.cpp`. + +## Creating a New Driver + +1. Create a new subdirectory with your sensor name +2. Add `.h` and `.cpp` files with your driver code +3. Optionally add an `examples/` folder with usage examples +4. Include the header in `main.cpp` with: `#include ` + +## Pre-installed Libraries + +The following libraries are installed via `platformio.ini` and don't need to be added here: + +- **PubSubClient** (MQTT client) +- **DHT sensor library** (Adafruit DHT sensors) +- **Adafruit Unified Sensor** (Common sensor interface) + +Add custom drivers here when you need: +- Modified versions of existing libraries +- Drivers for sensors not in the PlatformIO registry +- Project-specific sensor abstractions diff --git a/src/main.cpp b/src/main.cpp index f217508..50d6f99 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,21 +1,201 @@ /** - * MicroClaw 鈥?Sensor-level micro AI Agent + * MicroClaw — Sensor-level micro AI Agent * Runs on ESP32 with <1MB RAM, $2-5 hardware cost. * Part of the Clawland edge AI agent network. + * + * Features: + * - WiFi connectivity + * - MQTT client for upstream reporting + * - Sensor data aggregation + * - Low-power operation */ #include #include +#include +// Configuration (set via environment or hardcode for testing) const char* AGENT_NAME = "microclaw"; const char* VERSION = "0.1.0"; +// WiFi credentials (replace with your network) +const char* WIFI_SSID = "your_wifi_ssid"; +const char* WIFI_PASSWORD = "your_wifi_password"; + +// MQTT broker configuration (replace with your broker) +const char* MQTT_BROKER = "mqtt.example.com"; +const int MQTT_PORT = 1883; +const char* MQTT_CLIENT_ID = "microclaw-esp32"; +const char* MQTT_USERNAME = ""; // Optional +const char* MQTT_PASSWORD = ""; // Optional + +// MQTT topics +const char* MQTT_TOPIC_STATUS = "microclaw/status"; +const char* MQTT_TOPIC_SENSORS = "microclaw/sensors"; +const char* MQTT_TOPIC_COMMANDS = "microclaw/commands"; + +// Globals +WiFiClient wifiClient; +PubSubClient mqttClient(wifiClient); +unsigned long lastReconnectAttempt = 0; +unsigned long lastSensorPublish = 0; +const unsigned long SENSOR_PUBLISH_INTERVAL = 30000; // 30 seconds + +// Function declarations +void setupWiFi(); +void connectMQTT(); +void mqttCallback(char* topic, byte* payload, unsigned int length); +void publishStatus(); +void publishSensorData(); + void setup() { Serial.begin(115200); - Serial.println("馃 MicroClaw Agent v0.1.0"); + delay(100); + + Serial.println("========================================"); + Serial.println("🐾 MicroClaw Agent v" + String(VERSION)); Serial.println(" MCU-level sensor agent starting..."); - Serial.println(" Waiting for sensor configuration..."); + Serial.println("========================================"); + + // Setup WiFi + setupWiFi(); + + // Setup MQTT + mqttClient.setServer(MQTT_BROKER, MQTT_PORT); + mqttClient.setCallback(mqttCallback); + + // Initial connection + connectMQTT(); + + // Publish startup status + publishStatus(); + + Serial.println("✅ MicroClaw initialized and ready!"); } void loop() { - delay(1000); -} \ No newline at end of file + // Maintain MQTT connection + if (!mqttClient.connected()) { + unsigned long now = millis(); + if (now - lastReconnectAttempt > 5000) { + lastReconnectAttempt = now; + Serial.println("⚠️ MQTT disconnected, reconnecting..."); + connectMQTT(); + } + } else { + mqttClient.loop(); + } + + // Publish sensor data periodically + unsigned long now = millis(); + if (now - lastSensorPublish > SENSOR_PUBLISH_INTERVAL) { + lastSensorPublish = now; + publishSensorData(); + } + + delay(10); // Small delay to prevent watchdog reset +} + +void setupWiFi() { + Serial.print("📡 Connecting to WiFi: "); + Serial.println(WIFI_SSID); + + WiFi.mode(WIFI_STA); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + + int attempts = 0; + while (WiFi.status() != WL_CONNECTED && attempts < 30) { + delay(500); + Serial.print("."); + attempts++; + } + + if (WiFi.status() == WL_CONNECTED) { + Serial.println(); + Serial.println("✅ WiFi connected!"); + Serial.print(" IP address: "); + Serial.println(WiFi.localIP()); + Serial.print(" Signal strength: "); + Serial.print(WiFi.RSSI()); + Serial.println(" dBm"); + } else { + Serial.println(); + Serial.println("❌ WiFi connection failed!"); + Serial.println(" Check SSID/password and retry."); + } +} + +void connectMQTT() { + Serial.print("🔗 Connecting to MQTT broker: "); + Serial.println(MQTT_BROKER); + + // Attempt connection + bool connected; + if (strlen(MQTT_USERNAME) > 0) { + connected = mqttClient.connect(MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD); + } else { + connected = mqttClient.connect(MQTT_CLIENT_ID); + } + + if (connected) { + Serial.println("✅ MQTT connected!"); + + // Subscribe to command topic + mqttClient.subscribe(MQTT_TOPIC_COMMANDS); + Serial.print(" Subscribed to: "); + Serial.println(MQTT_TOPIC_COMMANDS); + } else { + Serial.print("❌ MQTT connection failed, rc="); + Serial.println(mqttClient.state()); + } +} + +void mqttCallback(char* topic, byte* payload, unsigned int length) { + Serial.print("📨 Message received ["); + Serial.print(topic); + Serial.print("]: "); + + String message = ""; + for (unsigned int i = 0; i < length; i++) { + message += (char)payload[i]; + } + Serial.println(message); + + // Handle commands + if (String(topic) == MQTT_TOPIC_COMMANDS) { + if (message == "status") { + publishStatus(); + } else if (message == "restart") { + Serial.println("🔄 Restarting..."); + ESP.restart(); + } + } +} + +void publishStatus() { + if (!mqttClient.connected()) return; + + String status = "{"; + status += "\"agent\":\"" + String(AGENT_NAME) + "\","; + status += "\"version\":\"" + String(VERSION) + "\","; + status += "\"uptime\":" + String(millis() / 1000) + ","; + status += "\"free_heap\":" + String(ESP.getFreeHeap()) + ","; + status += "\"wifi_rssi\":" + String(WiFi.RSSI()); + status += "}"; + + mqttClient.publish(MQTT_TOPIC_STATUS, status.c_str()); + Serial.println("📤 Published status: " + status); +} + +void publishSensorData() { + if (!mqttClient.connected()) return; + + // Placeholder sensor data (replace with actual sensor readings) + String data = "{"; + data += "\"timestamp\":" + String(millis()) + ","; + data += "\"temperature\":25.0,"; // Replace with DHT22 reading + data += "\"humidity\":60.0"; // Replace with DHT22 reading + data += "}"; + + mqttClient.publish(MQTT_TOPIC_SENSORS, data.c_str()); + Serial.println("📤 Published sensor data: " + data); +}