This directory contains the Python-based implementation of MIA for Raspberry Pi, following the Lean Architecture specified in TODO.md.
- ZeroMQ Broker (
core/messaging/broker.py): Message routing using ROUTER-DEALER pattern - FastAPI Server (
api/main.py): REST API and WebSocket endpoints - GPIO Worker (
hardware/gpio_worker.py): Hardware control via GPIO pins - Serial Bridge (
hardware/serial_bridge.py): ESP32/Arduino serial to ZeroMQ bridge - OBD Worker (
services/obd_worker.py): ELM327 OBD-II simulator with dynamic PID responses
This repository follows a structured workspace organization to separate development and deployment environments:
- Development Repository:
~/projects/mia/- Contains the full source code, documentation, and build tools - Configuration:
config/paths.json- Defines configurable paths for different environments - Path Management:
core/paths.py- Python utility for resolving relative and configurable paths
- Installed Code:
/opt/mia/- Contains deployed/running code (symlinked to development repo during development) - System Services:
/etc/systemd/system/mia-*.service- Systemd service definitions - Configuration:
/etc/mia/- System-wide configuration files - Data:
/var/lib/mia/- Persistent data and logs
- Development: Work in
~/projects/mia/with full access to source and tools - Testing: Use relative paths and path configuration for environment-independent code
- Deployment: Copy or symlink code to
/opt/mia/for production use - Services: Use systemd services that reference
/opt/mia/as the working directory
This separation ensures clean development workflows while maintaining proper system integration for production deployments.
- Listens on port 5555
- Routes messages between FastAPI server and workers
- Handles worker registration and message distribution
- REST API on port 8000
- Endpoints:
GET /devices- List connected devicesPOST /command- Send device commandsGET /telemetry- Get sensor readingsGET /status- System healthPOST /gpio/configure- Configure GPIO pinPOST /gpio/set- Set GPIO pin valueGET /gpio/{pin}- Get GPIO pin valueWS /ws- WebSocket for real-time telemetry
- Connects to ZeroMQ broker
- Controls Raspberry Pi GPIO pins
- Supports digital input/output
- Falls back to simulation mode if GPIO libraries unavailable
- Reads JSON telemetry from ESP32/Arduino via USB Serial
- Publishes telemetry to ZeroMQ PUB socket (port 5556) on topic
mcu/telemetry - Auto-detects serial ports (
/dev/ttyUSB0,/dev/ttyACM0, etc.) - Handles reconnection logic for robust operation
- Falls back to mock data generation when hardware unavailable
- Implements Digital Twin architecture for OBD-II simulation
- Subscribes to hardware telemetry via PUB/SUB (port 5556)
- Registers with ZeroMQ broker (port 5555) for command/control
- Runs ELM327 emulator with dynamic PID responses based on real-time hardware input
- Maps MCU potentiometer values to engine parameters (RPM, speed, coolant temp)
The Citroën bridge connects to PSA vehicles via ELM327 OBD-II adapter.
# Deploy service
sudo cp rpi/services/mia-citroen-bridge.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable mia-citroen-bridge
# Test with mock mode
ELM_MOCK=1 python3 agents/citroen_bridge.py
# Start real service
sudo systemctl start mia-citroen-bridge- Standard: RPM, Speed, Coolant Temp
- PSA-specific: DPF Soot, Oil Temp, Eolys Level
See docs/automotive/citroen-integration.md for full documentation.
sudo apt-get update
sudo apt-get install -y \
python3 \
python3-pip \
python3-dev \
libzmq3-devpip3 install -r requirements.txtUse the main deployment script:
sudo ./scripts/deploy-raspberry-pi.shThis will:
- Install all dependencies
- Build C++ components
- Install Python services
- Create systemd services
- Enable services to start on boot
pip3 install -r rpi/requirements.txtsudo mkdir -p /opt/mia
sudo cp -r . /opt/mia/sudo cp rpi/services/*.service /etc/systemd/system/
sudo systemctl daemon-reload# Core services
sudo systemctl enable zmq-broker mia-api mia-gpio-worker
sudo systemctl start zmq-broker mia-api mia-gpio-worker
# OBD Simulator services (optional)
sudo systemctl enable mia-serial-bridge mia-obd-worker
sudo systemctl start mia-serial-bridge mia-obd-workersudo systemctl start zmq-broker
sudo systemctl start mia-api
sudo systemctl start mia-gpio-worker
sudo systemctl start mia-serial-bridge
sudo systemctl start mia-obd-workersudo systemctl stop zmq-broker
sudo systemctl stop mia-api
sudo systemctl stop mia-gpio-worker
sudo systemctl stop mia-obd-worker
sudo systemctl stop mia-serial-bridgesudo systemctl status zmq-broker
sudo systemctl status mia-api
sudo systemctl status mia-gpio-worker
sudo systemctl status mia-serial-bridge
sudo systemctl status mia-obd-workersudo journalctl -u zmq-broker -f
sudo journalctl -u mia-api -f
sudo journalctl -u mia-gpio-worker -f
sudo journalctl -u mia-serial-bridge -f
sudo journalctl -u mia-obd-worker -f# Health check
curl http://localhost:8000/status
# List devices
curl http://localhost:8000/devices
# Configure GPIO pin 18 as output
curl -X POST http://localhost:8000/gpio/configure \
-H "Content-Type: application/json" \
-d '{"pin": 18, "direction": "output"}'
# Set GPIO pin 18 to HIGH
curl -X POST http://localhost:8000/gpio/set \
-H "Content-Type: application/json" \
-d '{"pin": 18, "value": true}'
# Get GPIO pin 18 value
curl http://localhost:8000/gpio/18The OBD simulator creates a "Digital Twin" where physical controls (ESP32/Arduino potentiometers) drive OBD-II PID values in real-time.
- Flash ESP32/Arduino with the following firmware:
void setup() {
Serial.begin(115200);
}
void loop() {
int pot1 = analogRead(A0); // RPM Input (0-1023)
int pot2 = analogRead(A1); // Speed Input (0-1023)
// Send JSON formatted line
Serial.print("{\"pot1\":");
Serial.print(pot1);
Serial.print(", \"pot2\":");
Serial.print(pot2);
Serial.println("}");
delay(100); // 10Hz update rate
}-
Connect ESP32/Arduino to Raspberry Pi via USB
-
Start services (serial bridge will auto-detect the device):
sudo systemctl start zmq-broker
sudo systemctl start mia-serial-bridge
sudo systemctl start mia-obd-workerCheck that serial bridge is receiving data:
sudo journalctl -u mia-serial-bridge -fYou should see log entries showing telemetry being published.
The ELM327 emulator creates a virtual serial port (PTY). Check logs to find the PTY path:
sudo journalctl -u mia-obd-worker | grep -i ptyConnect your OBD diagnostic tool to this PTY. As you turn the potentiometers on the ESP32, the RPM and speed values in the OBD responses will update in real-time.
Test serial bridge directly:
python3 rpi/hardware/serial_bridge.py --port /dev/ttyUSB0Test OBD worker directly:
python3 rpi/services/obd_worker.pyimport asyncio
import websockets
import json
async def test_websocket():
uri = "ws://localhost:8000/ws"
async with websockets.connect(uri) as websocket:
while True:
message = await websocket.recv()
data = json.loads(message)
print(f"Received: {data}")
asyncio.run(test_websocket())Once the FastAPI server is running, visit:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
- Project structure
- ZeroMQ messaging broker (ROUTER-DEALER)
- Message handlers
- GPIO control worker
- Hardware abstraction layer
- REST API endpoints
- WebSocket server
- Request validation (Pydantic)
- Systemd services
- Auto-start on boot
- Deployment script
- Serial bridge for ESP32/Arduino communication
- OBD worker with ELM327 emulator integration
- Dynamic PID responses based on hardware telemetry
- ZeroMQ PUB/SUB telemetry distribution
- Hardware-in-the-loop simulation architecture
- Complete ELM327-emulator library integration (PTY creation)
- Add FlatBuffers schema support
- Add sensor drivers (I2C/SPI)
- Implement device registry
- Add authentication/authorization
- Add comprehensive logging
- Performance optimization
- OBD-II PID response validation
Check logs:
sudo journalctl -u zmq-broker -n 50
sudo journalctl -u mia-api -n 50
sudo journalctl -u mia-gpio-worker -n 50- Check permissions:
ls -l /dev/gpiochip*- Ensure running as root or user in gpio group:
sudo usermod -a -G gpio $USER- Check if GPIO libraries are installed:
python3 -c "import RPi.GPIO; print('RPi.GPIO available')"
python3 -c "import gpiozero; print('gpiozero available')"sudo netstat -tulpn | grep -E "5555|8000"Ensure broker is running before starting other services:
sudo systemctl start zmq-broker
sleep 2
sudo systemctl start mia-api mia-gpio-worker- Check if device is connected:
ls -l /dev/ttyUSB* /dev/ttyACM*- Check permissions:
sudo usermod -a -G dialout $USER
# Log out and back in, or use newgrp dialout- Specify port manually:
sudo systemctl edit mia-serial-bridge
# Add:
# [Service]
# ExecStart=
# ExecStart=/usr/bin/python3 /opt/ai-servis/rpi/hardware/serial_bridge.py --port /dev/ttyUSB0- Test serial connection manually:
python3 -c "import serial; s=serial.Serial('/dev/ttyUSB0', 115200); print(s.readline())"- Verify serial bridge is publishing:
sudo journalctl -u mia-serial-bridge | grep "Published telemetry"- Check ZeroMQ PUB socket is bound:
sudo netstat -tulpn | grep 5556- Verify OBD worker is subscribed:
sudo journalctl -u mia-obd-worker | grep "Subscribed to telemetry"- Test ZMQ subscription manually:
import zmq
ctx = zmq.Context()
sub = ctx.socket(zmq.SUB)
sub.connect("tcp://localhost:5556")
sub.subscribe("mcu/telemetry")
while True:
topic, msg = sub.recv_multipart()
print(f"Topic: {topic}, Message: {msg}")