Metadata-Version: 2.4
Name: nova-rbm
Version: 0.5.0
Summary: Python SDK to control NOVA A1 Robot — AP & WiFi mode, auto-discovery, live status
Home-page: https://github.com/nadhilrobomiracle/nova_rbm
Author: robomiracle
Keywords: robot,nova,esp32,websocket,robotics,sdk
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Requires-Dist: websocket-client>=1.6.0
Requires-Dist: requests>=2.28.0
Dynamic: author
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# NOVA RBM â€” Robot Base Module

Python SDK to control the **NOVA A1** robot via WebSocket.  
Supports **AP mode**, **WiFi mode** (mDNS), **Scan mode** (auto-discovers robot by scanning your local network), and features a **Built-in AI Assistant** powered by `litert-lm`.

## Installation

```bash
pip install nova-rbm
```

Or install from source:

```bash
git clone https://github.com/nadhilrobomiracle/nova_rbm.git
cd nova_rbm
pip install -e .
```

*Note: For the AI Assistant features, you will also need to install `litert-lm`: `pip install litert-lm`*

---

## ðŸ¤– NEW: AI Assistant Integration

You can now chat with your NOVA A1 robot directly! The `nova_rbm` library includes a built-in wrapper that connects your robot's functions to a local, GPU-accelerated LLM (`gemma-4-E2B-it-litert-lm`) via the LiteRT-LM CLI.

### Starting the Assistant

```python
from nova_rbm import start_ai_assistant

# Launches an interactive CLI chat session where the AI can control the robot!
start_ai_assistant(
    robot_mode="scan",  
    system_prompt="You are a helpful robot assistant. Introduce yourself.",
    backend="gpu",
    enable_mtp=True
)
```

**What happens?**
- It dynamically creates a preset allowing the AI to call tools like `move_forward`, `set_color`, `set_servo`, etc.
- It launches the interactive `litert-lm` CLI.
- You type commands like *"Spin left and turn your lights pink"* and the robot obeys!

---

## Quick Start

### Scan Mode â€” Auto Network Discovery (Recommended)

The SDK **automatically detects your PC's current IP**, strips the last number, then scans every address on your subnet (`.1` to `.254`) using **WebSocket** (primary) and **HTTP `/status`** (secondary fallback) in parallel:

```python
from nova_rbm import NovaRobot

bot = NovaRobot(mode="scan")
bot.connect()   # Finds robot automatically â€” no IP needed!
print(bot.ip)   # e.g. '192.168.29.47'
bot.forward()
bot.stop()
bot.disconnect()
```

### Standalone Scan (returns IP string)

```python
from nova_rbm import scan_network

ip = scan_network()               # auto-detect subnet from your device IP
print(ip)                         # e.g. '192.168.29.47'

# With progress tracking
def progress(scanned, total, current_ip):
    print(f"[{scanned}/{total}] Checking {current_ip}...")

ip = scan_network(on_progress=progress)
```

### WiFi Mode (mDNS + automatic scan fallback)

Tries `nova-robot.local` first. If mDNS fails, **automatically falls back to subnet scan**:

```python
from nova_rbm import NovaRobot

bot = NovaRobot(mode="wifi")
bot.connect()   # mDNS first â†’ subnet scan fallback if mDNS fails
print(bot.status())
bot.disconnect()
```

### AP Mode (robot's own hotspot)

Connect your computer to the `NOVA_A1` WiFi, then:

```python
from nova_rbm import NovaRobot

bot = NovaRobot(mode="ap")   # Fixed IP: 192.168.4.1
bot.connect()
print(bot.status())
bot.disconnect()
```

### Manual IP Override

```python
bot = NovaRobot(ip="192.168.29.47")
bot.connect()
```

---

## Context Manager

Auto-connects, stops motors, and disconnects cleanly:

```python
with NovaRobot(mode="scan") as bot:
    bot.forward()
    bot.set_speed(200)
    import time; time.sleep(2)
    # stop() and disconnect() called automatically
```

---

## API Reference

### 1. Connection & Setup (`NovaRobot`)

| Method | Description |
|--------|-------------|
| `bot.connect()` | Open WebSocket â€” auto-discovers IP based on the selected mode. |
| `bot.disconnect()` | Close the WebSocket connection cleanly. |
| `bot.reconnect()` | Drop and re-establish the connection (re-runs network discovery if needed). |

### 2. Discovery Modes

| Mode | Strategy |
|------|----------|
| `"ap"` | Fixed IP `192.168.4.1` (connect to robot's own hotspot). |
| `"wifi"` | mDNS `nova-robot.local/status` â†’ falls back to full subnet scan if mDNS fails. |
| `"scan"` | Detects your device IP, parallel scans the entire subnet (WebSocket + HTTP). |

#### `scan_network()` Parameters
```python
scan_network(
    subnet=None,        # e.g. '192.168.29' â€” auto-detected if None
    start=1,            # first host octet
    end=254,            # last host octet
    ws_timeout=1.5,     # WebSocket probe timeout per host
    http_timeout=1.5,   # HTTP probe timeout per host
    max_workers=64,     # parallel threads
    on_progress=None,   # callback fn(scanned, total, ip)
)
```

### 3. Movement Control

| Method | Description |
|--------|-------------|
| `bot.forward()` | Drive forward indefinitely until stopped. |
| `bot.backward()` | Drive backward indefinitely. |
| `bot.left()` | Spin left. |
| `bot.right()` | Spin right. |
| `bot.stop()` | Stop all wheel motors. |
| `bot.set_speed(speed)` | Set motor speed (an integer between `0` and `255`). |

### 4. Servo Control

| Method | Description |
|--------|-------------|
| `bot.set_servo(servo, angle)` | Move servo (1â€“5) to an angle (enforces firmware limits). |
| `bot.set_all_servos(angles)` | Set multiple servos at once (e.g. `{1: 60, 3: 100}`). |
| `bot.reset_servos()` | Reset all servos to their default starting positions. |
| `NovaRobot.get_servo_limits()` | Returns min/max/default limits for each servo. |

**Servo limits (from firmware):**

| Servo | Min | Max | Default | Function typically mapped |
|-------|-----|-----|---------|---------------------------|
| S1 | 50 | 75 | 75 | Head Pan |
| S2 | 90 | 145 | 90 | Head Tilt |
| S3 | 35 | 150 | 85 | Arm 1 |
| S4 | 20 | 80 | 80 | Arm 2 |
| S5 | 110 | 135 | 110 | Gripper |

### 5. LED Control

| Method | Description |
|--------|-------------|
| `bot.set_rgb(r, g, b)` | Set LED strip exact color (0â€“255 each). |
| `bot.set_color("red")` | Set by name: `red`, `green`, `blue`, `white`, `off`, `cyan`, `magenta`, `yellow`, `orange`, `purple`, `pink`. |

### 6. Status & Telemetry

| Method | Returns |
|--------|---------|
| `bot.status()` | Full status dict containing motor, LED, servos, and WiFi data. |
| `bot.servo_angles()` | Dictionary of current angles: `{1: 75, 2: 90, ..., 5: 110}`. |
| `bot.motor_state()` | Dictionary of motor state: `{'state': 'stop', 'speed': 180}`. |
| `bot.led_color()` | Dictionary of RGB values: `{'r': 0, 'g': 0, 'b': 255}`. |
| `bot.wifi_info()` | Dictionary of network stats: `{'wifi_mode': ..., 'rssi_dbm': ...}`. |

### 7. AI Assistant API (`start_ai_assistant`)

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `system_prompt` | `str` | `"You are NOVA AI..."` | The behavior/personality instructions for the Gemma LLM. |
| `robot_mode` | `str` | `"wifi"` | Connection mode to find the robot (`"scan"`, `"wifi"`, `"ap"`). |
| `robot_ip` | `str` | `None` | Manual override for robot IP address. |
| `model_repo` | `str` | `"litert-community/...` | HuggingFace repo containing the LitertLM model. |
| `model_name` | `str` | `"gemma-4-E2B-it..."` | The name of the downloaded `.litertlm` file. |
| `backend` | `str` | `"gpu"` | The execution backend to run the model on (`"gpu"`, `"cpu"`). |
| `enable_mtp`| `bool` | `True` | Enable Speculative Decoding for faster token generation. |

### 8. WiFi Provisioning

| Method | Description |
|--------|-------------|
| `bot.set_wifi(ssid, pass)` | Saves WiFi credentials to the robot, which then reboots into Station Mode. |
| `bot.forget_wifi()` | Clears saved WiFi credentials, causing the robot to reboot back into AP Mode (`NOVA_A1` hotspot). |

---

## Full Status Response Example

Calling `bot.status()` returns the complete state of the robot directly from the physical hardware:

```json
{
  "status": "ok",
  "device": "NOVA_A1",
  "wifi_mode": "station",
  "connected_ssid": "MyWiFi",
  "ip_address": "192.168.29.47",
  "rssi_dbm": -45,
  "uptime_s": 1234,
  "ws_clients": 1,
  "motor": { "state": "stop", "speed": 180 },
  "led": { "r": 0, "g": 0, "b": 255 },
  "servos": { "s1": 75, "s2": 90, "s3": 85, "s4": 80, "s5": 110 }
}
```

---

## Changelog

### v0.4.0
- **New AI Assistant (`start_ai_assistant`)** â€” Integrates `litert-lm` for local, GPU-accelerated LLM function calling directly with your robot.
- **New `scan_network()`** â€” scans local subnet automatically by reading device IP.
- **New `mode="scan"`** in `NovaRobot` â€” fully automatic robot discovery.
- **`mode="wifi"` fallback** â€” if mDNS fails, auto-falls back to subnet scan.
- Parallel WebSocket + HTTP probes per host for maximum reliability.

### v0.3.0
- WiFi mode discovery via mDNS (`nova-robot.local`).
- AP mode support.
- Full servo, motor, LED control.

---

## License

MIT
