# Tunable Sirens

A programmable, tunable siren system using BLDC motors with FOC (Field-Oriented Control).

## Overview

This project implements a tunable siren where the frequency is controlled remotely via OSC (Open Sound Control) messages over WiFi. The system uses a DJI 2212 920KV BLDC motor driven by a B-G431B-ESC1 controller running SimpleFOC. Multiple stations can be controlled independently or simultaneously.

## Hardware

| Component | Part |
|-----------|------|
| Motor | DJI 2212 920KV BLDC |
| Motor Controller | STMicroelectronics B-G431B-ESC1 |
| Processors | ESP32 WROOM (one per station, one for remote) |
| Display | SSD1306 128x64 OLED (on both remote and station) |
| Input | AiEsp32 Rotary Encoder (on both remote and station) |

## Architecture

```
                                    ┌──────────────────────┐
                                    │   Remote Control     │
                                    │   (ESP32 + OLED)     │
 ┌─────────────────┐   OSC (WiFi)   │  192.168.4.200      │
 │  External OSC  │ ───────────────┤  Port: 54001        │
 │  (Any client)  │                │  - Acts as WiFi AP  │
 └─────────────────┘                │  - Routes to stations│
                                   └──────────┬───────────┘
                                              │ OSC forward
                                              │ (optional path)
                                              ▼
   ┌────────────────┐         ┌────────────────┐
   │ Station 1      │         │ Station N      │
   │ 192.168.4.201  │   ...   │ 192.168.4.20X  │
   │ Port: 54000    │         │ Port: 54000    │
   └───────┬────────┘         └────────┬────────┘
           │                           │
           │         ┌─────────────────┴─────────┐
           └────────►│  B-G431B-ESC1             │
                     │  SimpleFOC                 │
                     │  DJI 2212 920KV BLDC      │
                     └────────────────────────────┘
```

## Communication Modes

### 1. Via Remote Control (Router Mode)

The remote control acts as a WiFi access point and forwards OSC messages to stations. This allows controlling multiple sirens from a single entry point.

- **Remote IP**: `192.168.4.200`
- **Port**: `54001` (receives commands)

### 2. Direct to Station

Send OSC messages directly to each station's IP address:

- **Station 1**: `192.168.4.201:54000`
- **Station 2**: `192.168.4.202:54000`
- And so on...

### WiFi Setup

- **SSID**: `sirening`
- **Password**: `alarm_11735`
- **IP Range**: `192.168.4.200` (remote) + `201-208` (stations)

## OSC Protocol

### Messages

| Address | Arguments | Description |
|---------|-----------|-------------|
| `/freq` | `motorIndex, frequency` | Set frequency in Hz (0-500) |
| `/kill` | — | Stop siren (set frequency to 0) |
| `/state` | `motorIndex, frequency` | Station reports current state |

### Example (Python)

```python
from pythonosc import osc_message_builder
from pythonosc.udp_client import SimpleUDPClient

client = SimpleUDPClient("192.168.4.201", 54000)

# Set frequency to 100Hz for motor 1
msg = osc_message_builder.OscMessageBuilder(address="/freq")
msg.add_arg(1)        # motorIndex (1-indexed)
msg.add_arg(100.0)    # frequency in Hz
client.send(msg.build())

# Kill/stop the siren
msg = osc_message_builder.OscMessageBuilder(address="/kill")
client.send(msg.build())
```

### Station Response

The station reports its state back on port `54001`:

```python
# Incoming message: /state motorIndex frequency
# Example: /state 1 100.0
```

## Local Controls

Both the remote control and station controllers have a local interface:

### Rotary Encoder

| Action | Function |
|--------|----------|
| Rotate | Change frequency (or navigate menus) |
| Press | Select siren / confirm selection |
| Double-press (remote) | Kill all sirens |

### OLED Display

- Shows current frequency
- Shows selected siren number
- Shows connection status (WiFi)

## Directory Structure

```
sirens/
├── README.md              # This file
├── AGENTS.md              # Developer notes for AI agents
├── src/                   # Current firmware (v2)
│   ├── siren_remote_control_esp32_v2/      # Remote control unit
│   ├── siren_controller_esp32_*/           # Station controller
│   └── B_G431B_ESC1_motor_controller/      # Motor controller (SimpleFOC)
├── v1/                    # Legacy hardware and firmware
│   ├── src/               # Old versions of controller code
│   └── designs/          # Legacy CAD files (FreeCAD)
├── designs/               # Current CAD files
│   ├── openscad/          # OpenSCAD source files
│   │   ├── siren_redesign.scad   # Main siren design
│   │   └── box_snap.scad         # Controller box
│   ├── stl/              # 3D print files
│   └── 3mf/              # 3MF print files
```

## CAD Files

- **Main siren**: `designs/openscad/siren_redesign.scad`
- **Controller box**: `designs/openscad/box_snap.scad`
- **STL files**: `designs/stl/`

## Building & Flashing

Uses Arduino framework. For development, [PlatformIO](https://platformio.org/) is recommended for command-line builds.

See `AGENTS.md` for details on libraries and coding conventions.

## Version History

| Version | Description |
|---------|-------------|
| v1 | Legacy system (FreeCAD) |
| v2 (current) | Programmatic CAD design (OpenSCAD), improved code structure |
