v1.9.0: Phase 0 — инфраструктура CRM/лидов, миграции БД, расширение моделей

This commit is contained in:
2026-06-04 14:38:43 +03:00
parent e29e2984da
commit f06ecaabe3
15 changed files with 3315 additions and 10 deletions
+541
View File
@@ -0,0 +1,541 @@
# Yeastar S20 — Интеграция с AegisOne
> Дата последнего обновления: 03.06.2026
---
## 1. Подключение к АТС
### Сетевая схема
```
┌─────────────────────┐ ┌──────────────────────────┐
│ Сервер AegisOne │ │ Локальная сеть (офис) │
│ 81.177.141.34 │ │ 192.168.1.0/24 │
│ │ │ │
│ ┌───────────────┐ │ VPN/ │ ┌──────────────────┐ │
│ │ py_service │──┼──port───┼──│ Yeastar S20 │ │
│ │ max_bot │ │ forward │ │ 192.168.1.150 │ │
│ └───────────────┘ │ │ │ │ │
│ │ │ │ WAN: │ │
│ │ │ │ 185.105.171.187 │ │
└─────────────────────┘ │ └──────────────────┘ │
└──────────────────────────┘
```
### IP-адреса и порты
| Ресурс | Локальный IP | Белый IP | Порт (локал) | Порт (проброс) | Протокол |
|--------|-------------|----------|-------------|----------------|----------|
| **АТС (Web UI)** | 192.168.1.150 | 185.105.171.187 | 8088 | 45088 | HTTPS |
| **AMI** | 192.168.1.150 | 185.105.171.187 | 5038 | 45038 | TCP |
| **MySQL (CDR)** | 192.168.1.150 | 185.105.171.187 | 3306 | 43306 | TCP |
| **FTP** | 192.168.1.150 | 185.105.171.187 | 21 | 45021 | TCP |
| **SSH** | 192.168.1.150 | 185.105.171.187 | 8022 | — | TCP |
### Проброс портов (на роутере/ файрволе офиса)
| Направление | Протокол | Внешний порт → Внутренний IP:порт |
|-------------|----------|----------------------------------|
| Internet → АТС | TCP | 45038 → 192.168.1.150:5038 (AMI) |
| Internet → АТС | TCP | 45021 → 192.168.1.150:21 (FTP) |
| Internet → АТС | TCP | 43306 → 192.168.1.150:3306 (MySQL) |
| Internet → АТС | TCP | 45088 → 192.168.1.150:8088 (Web UI) |
---
## 2. Учётные данные и параметры устройства
### Параметры устройства (актуально на 03.06.2026)
| Параметр | Значение | Источник |
|----------|----------|----------|
| Модель | Yeastar S20 | FTP `/support/tmp/deviceinfo.txt` |
| Серийный номер | `3691C1453100` | FTP `/support/tmp/deviceinfo.txt` |
| Прошивка (software) | `30.15.0.206` | FTP `/support/tmp/deviceinfo.txt` |
| Железо (hardware) | V1.30 0005-0000 | FTP `/support/tmp/deviceinfo.txt` |
| OEM | Yeastar S20 | FTP `/support/tmp/deviceinfo.txt` |
| Asterisk | 13.7.0 | AMI `CoreSettings` |
| AMI версия | 2.8.0 | AMI `CoreSettings` |
| MySQL | 5.1.61 | MySQL greeting |
| PBX Center | 1.24.2 | Web UI App Center |
| SSH-сервер | dropbear 2019.78 | SSH banner (порт 8022) |
| FTP-сервер | vsFTPd 3.0.2 | FTP banner (порт 21) |
| CDR | Включён | AMI `CoreSettings` |
| Max звонков | 10 | AMI `CoreSettings` |
| REST API | Не поддерживается на S20 | Документация Yeastar |
### Web UI (админ-панель АТС)
| Параметр | Значение |
|----------|----------|
| URL | `https://192.168.1.150:8088` (локально) или `https://185.105.171.187:45088` (интернет) |
| Логин | `admin` |
| Пароль | `.-SHGWa_12` |
### AMI (Asterisk Manager Interface)
| Параметр | Значение |
|----------|----------|
| Хост | `192.168.1.150` (локально) или `81.177.141.34` (из сервера, через проброс) |
| Порт | `5038` (проброс: `45038`) |
| Логин | `1cuser` |
| Пароль | `1csecret` |
| Привилегии | Ограниченные (нет `Command`, `Originate`) |
| Разрешённые IP | `81.177.141.34/255.255.255.255` + `192.168.1.0/255.255.255.0` |
### MySQL (доступ к CDR)
| Параметр | Значение |
|----------|----------|
| Хост | `192.168.1.150` (локально) или через проброс `43306` |
| Порт | `3306` (проброс: `43306`) |
| Логин | `1cuser` |
| Пароль | `1csecret` |
| **ВАЖНО** | `charset='utf8'` (MySQL 5.1.61 не поддерживает `utf8mb4`!) |
| БД | `cdr` |
### FTP (записи звонков)
| Параметр | Значение |
|----------|----------|
| Порт | `21` (проброс: `45021`) |
| Логин | `support` |
| Пароль | `T4oQSU_?` |
| Статус | ✅ **Работает!** |
| Доступ | Корневая ФС (чroot), `/tmp` недоступен |
Доступные каталоги через FTP:
- `/sounds/record/` — звуки (пусто)
- `/storage_share/mmc1` — симлинк → `/tmp/media/mmc1` (нерезолвящийся через FTP)
- `/support/tmp/deviceinfo.txt`**информация об устройстве**
- `/support/` — системные файлы, bin
- `/gui_backups/` — бэкапы
- `/fax/`, `/www/`, `/var/`, `/etc/`, `/boot/`, `/cache/` — системные каталоги
**Ограничение**: записи звонков в `/tmp/media/mmc1/autorecords/` **недоступны**`/tmp` за пределами FTP-чroot. Для доступа к записям нужен SSH.
### SSH (файловая система)
| Параметр | Значение |
|----------|----------|
| Порт | `8022` |
| SSH-сервер | dropbear 2019.78 |
| Пароль | `T4oQSU_?` |
| Логин | **НЕ ИЗВЕСТЕН** |
| Статус | ✅ Порт открыт, но логин не найден |
| **Рекомендация** | Не использовать SSH — только MySQL + AMI |
### Хранилище данных (в Web UI)
| Параметр | Значение |
|----------|----------|
| Имя файла | `share` |
| Логин | `share` |
| Пароль | `9tktYfM2` |
| Назначение | Сетевая папка (симлинк `mmc1 -> /tmp/media/mmc1` в `/storage_share/`) |
---
## 3. Где найти информацию об АТС
### Серийный номер, модель, прошивка
| Источник | Способ |
|----------|--------|
| **FTP** `/support/tmp/deviceinfo.txt` | Содержит: hardware, software, sn, product, oem |
| **Web UI** `Dashboard` или `Settings > System > General > Preferences` | Отображается на главной странице |
| **Web UI** `Settings > System > General > About` | Версия прошивки и модель |
Содержимое `deviceinfo.txt`:
```
hardware: V1.30 0005-0000
software: 30.15.0.206
sn: 3691C1453100
product: Yeastar S20
oem: Yeastar S20
```
### Версия Asterisk и компонентов
| Источник | Способ |
|----------|--------|
| **AMI** команда `CoreSettings` | AsteriskVersion, AMIversion, CoreCDRenabled |
| **AMI** команда `ListCommands` | Список доступных AMI-команд с привилегиями |
| **Web UI** `Settings > System > General > About` | Версия PBX Center, прошивки |
### Конфигурация (абоненты, очереди, транки)
| Источник | Что даёт |
|----------|----------|
| **AMI** `QueueStatus` | Очереди, участники, стратегии |
| **AMI** `VoicemailUsersList` | Абоненты, голосовая почта |
| **AMI** `PJSIPQualify` | Статус SIP-абонента |
| **MySQL** БД `cdr` | История звонков, абоненты (из CDR) |
| **Web UI** `Extensions` | Список расширений |
| **Web UI** `Trunks` | SIP-транки |
| **Web UI** `Call Queue` | Очереди |
### Записи звонков
| Источник | Способ |
|----------|--------|
| **MySQL** колонки `recordpath`, `monitorfile` | Путь и имя WAV-файла на PBX |
| **Web UI** `CDR and Recordings` | Ручное скачивание через браузер |
| **FTP** `/storage_share/mmc1` | Симлинк на `/tmp/media/mmc1` (нерезолвится через FTP) |
| **SSH** порт 8022 | Прямой доступ к файловой системе (логин неизвестен) |
---
## 4. Абоненты и очереди
### Внутренние номера (расширения)
| Номер | Назначение |
|-------|-----------|
| 1001 | Основной (Инженер) |
| 1002 | Второй (Инженер) |
| 1003 | Дополнительный |
| 1000 | Тестовый |
### Очереди (Queue)
| Номер очереди | Стратегия | Расширения |
|---------------|-----------|------------|
| 6700 | ringall | 1001, 1002 |
| 6701 | rrmemory | 1001 |
| 6702 | ringall | 1002 |
### Транки (линии)
| Транк | Тип | Назначение |
|-------|-----|-----------|
| Mango | VoIP-провайдер | Исходящие/входящие через SIP |
| Tele2 | VoIP-провайдер | Исходящие/входящие через SIP |
| YSGSM | GSM-модуль | Исходящие через GSM-SIM |
---
## 5. База данных CDR
### Структура
БД: `cdr`, таблицы: `cdr` (текущая) + `cdr_YYYYMM` (архивные).
### Колонки таблицы `cdr`
| Колонка | Тип | Описание |
|---------|-----|----------|
| `id` | int | ID записи |
| `datetime` | datetime | Дата и время звонка |
| `clid` | varchar | Caller ID (кто звонит) |
| `src` | varchar | Номер отправителя |
| `dst` | varchar | Номер получателя |
| `dcontext` | varchar | Контекст диалплана |
| `srctrunk` | varchar | Транк отправителя |
| `dstrunk` | varchar | Транк получателя |
| `lastapp` | varchar | Последнее приложение (Dial, Queue, BackGround...) |
| `lastdata` | varchar | Данные последнего приложения (номер, очередь) |
| `duration` | int | Общая длительность (секунды) |
| `billable` | int | Биллируемая длительность (секунды) |
| `disposition` | varchar | Статус: ANSWERED, NO ANSWER, BUSY, VOICEMAIL, FAILED |
| `calltype` | varchar | Тип: Inbound, Outbound, Internal |
| `accountcode` | varchar | Код аккаунта |
| `uniqueid` | varchar | Уникальный ID звонка |
| `recordfile` | varchar | Имя файла записи (WAV) |
| `recordpath` | varchar | Путь к записи на PBX |
| `monitorfile` | varchar | Имя файла мониторинга |
| `monitorpath` | varchar | Путь к мониторингу на PBX |
| `extfield1-5` | varchar | Дополнительные поля |
| `didnumber` | varchar | DID-номер (входящий номер) |
| `srcchanurl` | varchar | SIP URL канала отправителя |
| `dstchanurl` | varchar | SIP URL канала получателя |
| `companycontact` | varchar | Имя контакта компании |
| `personalcontact` | varchar | Имя личного контакта |
| `contactnumber` | varchar | Контактный номер |
### Примеры запросов
```sql
-- Все звонки за сегодня
SELECT datetime, src, dst, duration, billable, disposition, calltype
FROM cdr.cdr
WHERE DATE(datetime) = CURDATE()
ORDER BY datetime DESC;
-- Звонки за конкретный месяц
SELECT * FROM cdr.cdr_202606 ORDER BY datetime DESC;
-- Входящие звонки на очередь 6700
SELECT datetime, src, dst, duration, disposition
FROM cdr.cdr
WHERE dst LIKE '6700%' AND calltype = 'Inbound'
ORDER BY datetime DESC;
-- Звонки с записями
SELECT datetime, src, dst, duration, recordfile, recordpath
FROM cdr.cdr
WHERE recordfile != ''
ORDER BY datetime DESC;
-- Статистика по дням
SELECT DATE(datetime) as day, COUNT(*) as calls,
SUM(CASE WHEN disposition='ANSWERED' THEN 1 ELSE 0 END) as answered
FROM cdr.cdr
WHERE datetime >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY DATE(datetime)
ORDER BY day DESC;
```
### Таблица `queue_log`
Содержит логи событий очередей (поступление, ответ, ожидание, сброс).
---
## 6. Записи звонков
### Где хранятся
На файловой системе PBX: `/tmp/media/mmc1/autorecords/YYYYMM/`
Формат имени файла:
```
YYYYMMDDHHMMSS-UNIQUEID-SRC-DST-Direction.wav
```
Примеры из CDR:
```
20260110164821-1768052891.15-1001-+79531116788-Outbound.wav
20260402105623-1775116571.13-1001-89531116788-Outbound.wav
20260512162645-1778592395.0-+79898250183-1001-Inbound.wav
```
### Как получить
1. **Путь в CDR**: колонки `recordpath`, `monitorpath` (путь на PBX)
2. **FTP** (`support`/`T4oQSU_?`): записи **недоступны**`/tmp` за пределами FTP-чroot
3. **SSH** (порт 8022, пароль `T4oQSU_?`, логин неизвестен): теоретически доступен, но логин не найден
4. **Web UI**: `CDR and Recordings` — ручное скачивание через браузер
---
## 7. AMI — Доступные команды
### Работает с 1cuser/1csecret
| Команда | Описание | Статус |
|---------|----------|--------|
| `Ping` | Проверка соединения | ✅ |
| `CoreStatus` | Статус ядра (uptime, кол-во звонков) | ✅ |
| `CoreShowChannels` | Список активных каналов | ✅ |
| `CoreSettings` | Настройки ядра (Asterisk, CDR) | ✅ |
| `QueueStatus` | Статус очередей + участников | ✅ |
| `VoicemailUsersList` | Список абонентов голосовой почты | ✅ |
| `PJSIPQualify` | Пинг SIP-абонента | ✅ |
| `Status` | Статус всех каналов | ✅ |
| `ListCommands` | Список доступных команд | ✅ |
### Не работает (Permission denied)
| Команда | Описание |
|---------|----------|
| `Command` | Выполнение CLI-команд (`cdr show` и т.д.) |
| `Originate` | Исходящий звонок |
| `ShowDialPlan` | Просмотр диалплана |
| `Hangup` | Завершение звонка |
| `Redirect` | Переадресация звонка |
### Real-time события
При включённых `Events: On` AMI автоматически отправляет:
- `Event: Cdr` — при завершении звонка (содержит CDR-данные)
- `Event: Newchannel` — при начале звонка
- `Event: Dial` — при наборе номера
- `Event: Hangup` — при завершении
---
## 8. Пример подключения (Python)
### MySQL — запрос CDR
```python
import pymysql
conn = pymysql.connect(
host="192.168.1.150", # или внешний IP через проброс
port=3306, # или 43306 через проброс
user="1cuser",
password="1csecret",
database="cdr",
charset="utf8", # ВАЖНО: не utf8mb4!
connect_timeout=5
)
cursor = conn.cursor()
cursor.execute("SELECT * FROM cdr ORDER BY datetime DESC LIMIT 10")
for row in cursor.fetchall():
print(row)
conn.close()
```
### AMI — real-time события
```python
import socket
import time
def ami_connect(host, port, username, password):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
# Читаем приветствие
greeting = sock.recv(4096).decode()
# Логин
login_msg = (
f"Action: Login\r\n"
f"Username: {username}\r\n"
f"Secret: {password}\r\n"
f"Events: On\r\n"
f"\r\n"
)
sock.send(login_msg.encode())
time.sleep(1)
response = sock.recv(16384).decode()
return sock
# Использование
sock = ami_connect("192.168.1.150", 5038, "1cuser", "1csecret")
# Слушаем события
while True:
data = sock.recv(16384).decode()
if data:
print(data)
```
### AMI — из сервера (через проброс)
```python
# Подключение через проброс портов с сервера
sock = ami_connect("81.177.141.34", 45038, "1cuser", "1csecret")
# Или напрямую (если сервер в локальной сети)
sock = ami_connect("192.168.1.150", 5038, "1cuser", "1csecret")
```
---
## 9. Схема интеграции с AegisOne
```
┌──────────────────┐ MySQL:3306 ┌──────────────────┐
│ py_service │◄────────────────────│ Yeastar S20 │
│ (CDR polling) │ │ (cdr БД) │
│ │ AMI:5038 │ │
│ (real-time) │◄────────────────────│ (события) │
│ │ │ │
│ ┌──────────────┐ │ │ ┌──────────────┐ │
│ │ /service/ │ │ │ │ Записи WAV │ │
│ │ phone/ │ │ FTP:21 │ │ /tmp/media/ │ │
│ │ history │ │◄──(когда будет)────│ │ │ │
│ │ playback │ │ │ └──────────────┘ │
│ └──────────────┘ │ └──────────────────┘
└──────────────────┘
┌──────────────────┐
│ max_bot │
│ (уведомления о │
│ пропущенных) │
└──────────────────┘
```
---
## 10. План интеграции (TODO)
### Фаза 1: CDR (готово к реализации)
- [ ] Модель БД для хранения звонков
- [ ] Периодический опрос MySQL (каждые 5 мин)
- [ ] Страница истории звонков в сервисном портале
- [ ] Фильтры: по дате, номеру, типу, статусу
### Фаза 2: Real-time
- [ ] AMI-клиент для получения событий
- [ ] Уведомления о пропущенных звонках (в max_bot)
- [ ] Статус абонентов (online/offline)
- [ ] Мониторинг очередей
### Фаза 3: Записи
- [x] FTP логин найден: `support` / `T4oQSU_?`
- [ ] FTP-чroot не даёт доступ к `/tmp/media/mmc1/autorecords/` — нужен SSH или другой способ
- [ ] Разобраться с SSH-логином (пароль `T4oQSU_?` известен)
- [ ] Скачивание записей
- [ ] Плеер для прослушивания в портале
### Фаза 4: Управление
- [ ] Исходящие звонки из портала (если AMI получит права)
- [ ] Переключение звонков
- [ ] Статистика и отчёты
---
## 11. Известные проблемы
1. **Записи звонков недоступны через FTP** — логин `support` работает, но `/tmp/media/mmc1/autorecords/` за пределами FTP-чroot. Нужен SSH (порт 8022, пароль `T4oQSU_?`, логин неизвестен)
2. **AMI ограниченные права** — на S20 нельзя расширить привилегии AMI-пользователя через Web UI. Доступны только readonly-команды
3. **REST API не поддерживается** — только для S50/S100/S300
4. **MySQL 5.1.61** — старая версия, не поддерживает `utf8mb4`. Использовать `charset='utf8'`
5. **Кириллица в CDR** — имена контактов отображаются в кодировке CP1251/garbage (проблема кодировки MySQL-клиента)
---
## 12. Ссылки
- [Yeastar S-Series AMI Documentation](https://help.yeastar.com/en/s-series/topic/asterisk-manager-interface-ami.html)
- [Yeastar Developer Guide](https://support.yeastar.com/hc/en-us/articles/235972668)
- [Asterisk AMI Protocol](https://docs.asterisk.org/languages/en/Asterisk_18_Documentation/DAHDI_DAHDI_Hardware_Digium_Interface_Hardware/Administering/Asterisk_Manager_Interface_AMI/)
---
## 13. FTP — Структура каталогов
```
/ (корень FTP, доступен как support)
├── boot/
├── cache/
├── etc/
├── fax/
├── ftp_media/ (пусто)
├── gui_backups/
├── imageupdate/
├── lost+found/
├── rcstop/
├── sounds/
│ ├── moh/ (музыка на удержании)
│ └── record/ (пусто)
├── storage_share/
│ └── mmc1 → /tmp/media/mmc1 (симлинк, нерезолвящийся)
├── support/
│ ├── tmp/
│ │ ├── deviceinfo.txt ← ИНФОРМАЦИЯ ОБ УСТРОЙСТВЕ
│ │ └── testsysmailbox.eml
│ ├── autoptemplate/
│ ├── bin/
│ ├── customcfg/
│ └── fxotune/
├── syslog/
├── syslog_backup/
├── tftpboot/
├── var/
├── webupload/
├── www/
└── ysapps/
```
### Ключевые файлы
| Путь | Содержимое |
|------|-----------|
| `/support/tmp/deviceinfo.txt` | Серийный номер, модель, прошивка |
| `/support/tmp/testsysmailbox.eml` | Тестовый шаблон почты |
| `/storage_share/mmc1` | Симлинк на записанные файлы (недоступен через FTP) |