You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
3.6 KiB
98 lines
3.6 KiB
# F3 Picoclaw XMPP
|
|
|
|
An XMPP ↔ PicoClaw bridge over MQTT, built as two independent long-running
|
|
services that talk to each other over localhost HTTP. Each service owns exactly
|
|
one persistent connection (one XMPP, one MQTT), so there is no connection
|
|
contention between them.
|
|
|
|
## How it works
|
|
|
|
```
|
|
XMPP user <─> [xmpp_service.py] ──HTTP /publish──> [mqtt_service.py] <─> MQTT broker
|
|
^ XMPP conn :19080 MQTT conn :19081
|
|
└───────────────── HTTP /send ◄──────────────────┘
|
|
```
|
|
|
|
- **`src/xmpp_service.py`** (port `19080`) — one XMPP connection (receive and
|
|
send). Exposes `POST /send` `{jid, text}` to send an outgoing XMPP message
|
|
(chat, or groupchat when the JID is a known room). Every incoming XMPP
|
|
message is forwarded via `POST /publish` to the MQTT service.
|
|
- **`src/mqtt_service.py`** (port `19081`) — one MQTT connection subscribed to
|
|
`{prefix}/{agent_id}/+/response`. Exposes `POST /publish` `{jid, text}` to
|
|
publish `{"text": ...}` to `{prefix}/{agent_id}/{jid}/request`. Every MQTT
|
|
response is forwarded via `POST /send` to the XMPP service.
|
|
|
|
The `{jid}` segment is the bare JID of the XMPP sender, so PicoClaw keeps an
|
|
independent conversation per sender. PicoClaw's streamed reply chunks arrive as
|
|
separate MQTT messages and are each forwarded as their own XMPP message.
|
|
|
|
If a service cannot reach the other over HTTP, it logs the error and continues.
|
|
|
|
## Requirements
|
|
|
|
- Python >= 3.10
|
|
- [uv](https://docs.astral.sh/uv/) package manager
|
|
- An MQTT broker (e.g. Mosquitto, EMQX)
|
|
- A running [PicoClaw](https://github.com/sipeed/picoclaw) gateway with the MQTT
|
|
channel enabled (`channel_list.mqtt` with a matching `agent_id` and
|
|
`topic_prefix`)
|
|
|
|
## Setup
|
|
|
|
```bash
|
|
# Install dependencies
|
|
uv sync
|
|
|
|
# Configure environment
|
|
cp .env.example .env
|
|
# Edit .env with your XMPP credentials and MQTT settings
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Description |
|
|
|---|---|
|
|
| `XMPP_USERNAME` | Full JID for the XMPP bot account |
|
|
| `XMPP_PASSWORD` | XMPP account password |
|
|
| `XMPP_ROOMS` | Comma-separated list of MUC rooms to join |
|
|
| `MQTT_BROKER` | MQTT broker URL, e.g. `tcp://host:1883` or `ssl://host:8883` |
|
|
| `MQTT_USERNAME` | Optional broker username |
|
|
| `MQTT_PASSWORD` | Optional broker password |
|
|
| `MQTT_TOPIC_PREFIX` | Topic namespace prefix (default `/picoclaw`) |
|
|
| `MQTT_AGENT_ID` | PicoClaw agent id used in the topic path (default `assistant`) |
|
|
| `MQTT_CONN_CLIENT_ID` | Broker-level client id for MQTT connections |
|
|
| `MQTT_QOS` | MQTT QoS for publish/subscribe: `0`, `1`, or `2` (default `0`) |
|
|
| `DEBUG` | Logging level: `debug`, `info`, `warn`, `error`, `critical` |
|
|
|
|
The service ports are hardcoded: XMPP service on `127.0.0.1:19080`, MQTT
|
|
service on `127.0.0.1:19081`.
|
|
|
|
## Usage
|
|
|
|
Run both services (e.g. two terminals, or a process manager like systemd):
|
|
|
|
```bash
|
|
# Terminal 1 - XMPP side
|
|
uv run python -m src.xmpp_service
|
|
|
|
# Terminal 2 - MQTT side
|
|
uv run python -m src.mqtt_service
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/
|
|
├── xmpp_service.py # XMPP connection + HTTP :19080 (incoming -> MQTT, /send)
|
|
├── mqtt_service.py # MQTT connection + HTTP :19081 (responses -> XMPP, /publish)
|
|
├── xmpp.py # XMPP bot client (slixmpp)
|
|
├── picoclaw.py # PicoClaw MQTT client (paho-mqtt)
|
|
└── log.py # Logging configuration
|
|
```
|
|
|
|
## Tech Stack
|
|
|
|
- Python 3.14 / asyncio
|
|
- [slixmpp](https://github.com/poezio/slixmpp) for XMPP
|
|
- [paho-mqtt](https://github.com/eclipse/paho.mqtt.python) for MQTT
|
|
- [aiohttp](https://docs.aiohttp.org/) for the HTTP service APIs
|
|
|