Metadata-Version: 2.4
Name: simotel-connect
Version: 1.0.5
Summary: A professional Django/Python client for the Simotel PBX API
License: MIT
Keywords: simotel,pbx,voip,django,api,asterisk
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Framework :: Django
Classifier: Topic :: Communications :: Telephony
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28.0
Provides-Extra: django
Requires-Dist: django>=3.2; extra == "django"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-django; extra == "dev"
Requires-Dist: responses>=0.23; extra == "dev"
Requires-Dist: django>=3.2; extra == "dev"
Dynamic: license-file

# 📞 Simotel Connect (Python & Django Client for Simotel PBX API v4)

[![PyPI version](https://img.shields.io/pypi/v/simotel-connect.svg)](https://pypi.org/project/simotel-connect/)
[![Python Versions](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue)](https://pypi.org/project/simotel-connect/)
[![Django](https://img.shields.io/badge/django-%3E%3D3.2-green)](https://www.djangoproject.com/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A professional, modern, and reusable Python and Django client library for communicating with the **Simotel PBX API (v4)**.

---

## 🌟 Features

- 🔐 **Full Dual Authentication Support**: Seamlessly manages both `X-APIKEY` and HTTP Basic Auth headers required by Simotel.
- ⚙️ **Flexible 3-Tier Configuration Chain**:
  `Direct arguments` > `Django settings.SIMOTEL` > `Environment variables (.env)`
- 🏗️ **Modular Facade & Manager Pattern**: Clean, categorized, and intuitive API namespaces (`sm.call`, `sm.pbx`, `sm.reports`, `sm.autodialer`, etc.).
- 🔄 **Session Pooling & Auto Retry**: Stable connection management with `urllib3` retry adapters.
- 🛡️ **Comprehensive Exception Hierarchy**: Clear error types for auth failures, network issues, timeouts, and PBX API errors.
- 📊 **Over 80+ Simotel Endpoints Supported**:
  - **Call Origination (Click-to-Call)**: Initiate calls via `POST /call/originate/act`
  - **PBX Users & Extensions**: Add, search, edit, and remove PBX users
  - **Queues & Agents**: Queue management, single and batch agent assignment, pause/resume
  - **Trunks**: Trunk configuration and status
  - **Blacklists & Whitelists**: Block or permit numbers with ease
  - **Announcements & Music on Hold**: Upload and manage audio files
  - **Faxes**: Send, receive, and download incoming/outgoing faxes
  - **Voicemails**: Download voicemail recordings and manage boxes
  - **Reports & CDR**: Search call detail records, queue stats, agent performance, and download single/dual-channel audio recordings
  - **Autodialer**: High-volume automated outbound calling campaigns and contact groups
  - **System Health**: Ping and connectivity verification

---

## 📦 Installation

Install the package via `pip`:

```bash
pip install simotel-connect
```

For development and local testing:

```bash
git clone git@github.com:mraminrzn/simotel-connect.git
cd simotel-connect
pip install -e ".[dev]"
```

---

## ⚙️ Configuration

### Option 1: Django `settings.py` (Recommended for Django projects)

Add `simotel_connect` to your `INSTALLED_APPS` and define the `SIMOTEL` dictionary:

```python
# settings.py

INSTALLED_APPS = [
    ...,
    "simotel_connect",
]

SIMOTEL = {
    "HOST": "192.168.1.10",             # Simotel IP address or hostname
    "API_KEY": "YOUR_SIMOTEL_API_KEY",  # From Maintenance > API Accounts
    "USERNAME": "admin",                # Simotel web panel username
    "PASSWORD": "your_password",        # Simotel password
    "PORT": 80,                         # Optional (default: 80)
    "SCHEME": "http",                   # Optional: "http" or "https" (default: "http")
    "TIMEOUT": 30,                      # Optional: request timeout in seconds (default: 30)
    "VERIFY_SSL": True,                 # Optional (default: True)
}
```

Then use the client anywhere in your project (views, services, Celery tasks):

```python
from simotel_connect import Simotel

# Automatically reads configuration from settings.py
sm = Simotel()
```

---

### Option 2: Environment Variables (`.env`)

```env
SIMOTEL_HOST=192.168.1.10
SIMOTEL_API_KEY=YOUR_SIMOTEL_API_KEY
SIMOTEL_USERNAME=admin
SIMOTEL_PASSWORD=your_password
SIMOTEL_TIMEOUT=30
SIMOTEL_VERIFY_SSL=false
```

```python
from simotel_connect import Simotel

sm = Simotel()
```

---

### Option 3: Direct Initialization (Standalone scripts or multi-tenant PBX)

```python
from simotel_connect import Simotel

sm = Simotel(
    host="192.168.1.10",
    api_key="YOUR_SIMOTEL_API_KEY",
    username="admin",
    password="your_password",
    timeout=20,
    verify_ssl=False,
)
```

---

## 🚀 Usage & Examples

### 1. Connection Health Check (Ping)

```python
response = sm.setting.ping()
if response.success:
    print("Successfully connected to Simotel:", response.message)
```

---

### 2. Call Origination (Click-to-Call)

Sends a `POST` request to `/call/originate/act`:

```python
# Call between an internal extension and an external phone number
resp = sm.call.originate(
    caller="1001",
    callee="09121234567",
    context="default",
    caller_id="1001",
    timeout=30,
)

# Call between two internal extensions
resp = sm.call.originate(
    caller="1001",
    callee="1002",
    context="default",
)
```

---

### 3. Users & Extensions Management

```python
# Create a new extension
sm.pbx.users.add(
    extension="1001",
    name="John Doe",
    password="StrongPassword123",
    email="john@example.com",
    mobile="09121234567",
)

# Search users
users = sm.pbx.users.search(extension="1001")
print(users.data)

# Update a user
sm.pbx.users.update(extension="1001", name="John Doe (Support Lead)")

# Remove a user
sm.pbx.users.remove(extension="1001")
```

---

### 4. Queues & Call Center Agents

```python
# Create a call queue
sm.pbx.queues.add(name="2000", strategy="leastrecent", timeout=30)

# Add an agent to the queue
sm.pbx.queues.add_agent(queue="2000", agent="1001", penalty=0)

# Pause agent (e.g. lunch break)
sm.pbx.queues.pause_agent(queue="2000", agent="1001", reason="Lunch break")

# Resume agent
sm.pbx.queues.resume_agent(queue="2000", agent="1001")

# Batch add agents to queue
sm.pbx.queues.batch_add_agent(queue="2000", agents=["1001", "1002", "1003"])

# Batch pause agents
sm.pbx.queues.batch_pause_agent(queue="2000", agents=["1001", "1002"])

# Remove agent from queue
sm.pbx.queues.remove_agent(queue="2000", agent="1001")
```

---

### 5. Reports & Call Audio Downloads

```python
# Search Call Detail Records (CDR)
cdr = sm.reports.cdr_search(
    from_date="2026-01-01 00:00:00",
    to_date="2026-01-31 23:59:59",
    limit=50,
)
for call in cdr.data:
    print(call)

# Queue reports
queue_report = sm.reports.queue_search(queue="2000")

# Agent activity reports
agent_report = sm.reports.agent_search(agent="1001")

# Download recorded call audio (.mp3 / .wav)
audio_bytes = sm.reports.download_audio(file="20260914_v2.1789362850.25437.mp3")
with open("recorded_call.mp3", "wb") as f:
    f.write(audio_bytes)

# Download dual-channel call recording (agent & customer split)
dual_audio = sm.reports.download_audio_dual_channel(file="20260914_v2.1789362850.25437.mp3")
with open("dual_channel_call.mp3", "wb") as f:
    f.write(dual_audio)
```

---

### 6. Blacklists & Whitelists

```python
# Block unwanted incoming number
sm.pbx.blacklists.add(number="09999999999", description="Spam caller")

# Remove from blacklist
sm.pbx.blacklists.remove(number="09999999999")

# Add VIP contact to whitelist
sm.pbx.whitelists.add(number="09120000000", description="Executive VIP")
```

---

### 7. Autodialer & Automated Campaigns

```python
# Upload campaign audio file
sm.autodialer.announcements.upload(
    file_path="/path/to/promo.wav",
    name="promotional_announcement",
)

# Create contact group
sm.autodialer.groups.add(name="special_customers")

# Add contact to group
sm.autodialer.contacts.add(
    number="09121234567",
    name="David Miller",
    group="special_customers",
)

# Create and start campaign
sm.autodialer.campaigns.add(
    name="Autumn Festival Campaign",
    announcement="promotional_announcement",
    group="special_customers",
    trunk="main_trunk",
)

# Query campaign results
campaign_stats = sm.autodialer.reports.search(campaign="Autumn Festival Campaign")
```

---

## ⚠️ Exception Handling

All custom exceptions inherit from `SimotelError`:

```python
from simotel_connect import (
    Simotel,
    SimotelError,
    SimotelAuthError,
    SimotelAPIError,
    SimotelConnectionError,
    SimotelTimeoutError,
)

sm = Simotel()

try:
    sm.call.originate(caller="1001", callee="1002")
except SimotelAuthError:
    print("Authentication failed: Check API Key, username, or password.")
except SimotelAPIError as e:
    print(f"Simotel returned an API error: {e.args[0]}")
    print(f"Details: {e.data}")
except SimotelConnectionError:
    print("Connection error: Unable to reach Simotel server.")
except SimotelTimeoutError:
    print("Request timed out.")
except SimotelError as e:
    print(f"Simotel error: {e}")
```

---

## 🖥️ Interactive Web Demo

An interactive Django test panel is provided under `demo_project/`. It allows you to visually test audio downloading and call origination:

```bash
cd demo_project
python manage.py runserver
```

Open `http://127.0.0.1:8000/` in your browser.

---

## 🧪 Running Tests

```bash
pip install -e ".[dev]"
pytest
```

---

## 📄 License

This project is licensed under the **MIT License**.
