Metadata-Version: 2.4
Name: sensorylab-smeller
Version: 0.1.83
Summary: Python library for Neuroair device control
Home-page: http://10.10.0.20:3000/SensoryLAB/smeller
Author: SensoryLAB
Author-email: fox@sensorylab.ru
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: future>=1.0.0
Requires-Dist: iso8601>=2.1.0
Requires-Dist: pybluez2>=0.46
Requires-Dist: pyserial>=3.5
Requires-Dist: PyYAML>=6.0.2
Requires-Dist: paho-mqtt==2.1.0
Provides-Extra: gui
Requires-Dist: PyQt6; extra == "gui"
Requires-Dist: PyQtGraph; extra == "gui"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license
Dynamic: license-file
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# Smeller: Python Library for Neuroair Device Control

[![PyPI version](https://badge.fury.io/py/smeller.svg)](https://badge.fury.io/py/smeller)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Documentation Status](https://readthedocs.org/projects/smeller-python-lib/badge/?version=latest)](https://smeller-python-lib.readthedocs.io/en/latest/?badge=latest)
[![Tests](https://github.com/yourusername/smeller-python-lib/actions/workflows/test.yml/badge.svg)](https://github.com/yourusername/smeller-python-lib/actions/workflows/test.yml)

## Описание

`Smeller` – это Python библиотека, разработанная для **управления устройствами Neuroair**, предлагая как **API для программного управления**, так и **графический интерфейс пользователя (GUI) для интерактивной работы с устройством**.  Она предоставляет полный набор инструментов для **взаимодействия с устройством через последовательный порт (Serial) или Bluetooth, позволяя разработчикам интегрировать управление Neuroair в свои приложения или использовать готовое GUI приложение.**


**Основные возможности:**

* **Комплексное управление устройством:**  Предлагает как программное управление через API, так и интуитивно понятный GUI.
* **Управление каналами (API и GUI):**  Настройка параметров каналов, включение/выключение, активация/деактивация. В GUI предусмотрена визуализация и удобное управление параметрами.
* **Арома контроль (API и GUI):** Управление ароматическими каналами, настройка параметров, включение/выключение, активация/деактивация. GUI обеспечивает визуальное представление настроек и состояний.
* **Управление генератором (API и GUI):** Контроль мощности и логики работы генератора. GUI предоставляет элементы управления для быстрого доступа к настройкам генератора.
* **Динамическое управление ароматами (GUI):** Пользователь может создавать сложные ароматические сценарии, используя вейпоинты и различные типы интерполяции (линейная, экспоненциальная, синусоидальная, ступенчатая) для плавного изменения интенсивности ароматов со временем.
* **Визуализация и редактирование (GUI):** Графическое отображение интенсивности каналов в реальном времени, возможность интерактивного редактирования вейпоинтов непосредственно на графике.
* **Сохранение и загрузка аромаблоков (GUI):** Пользователи могут сохранять созданные ароматические конфигурации в виде "аромаблоков" и загружать их для повторного использования или редактирования.
* **Интеграция с медиа (GUI):** Возможность синхронизации ароматических сценариев с медиа-контентом, таким как видео или аудио, для создания мультисенсорных впечатлений.
* **Разнообразные команды (API):** Поддержка широкого спектра команд для настройки и управления различными функциями устройства, включая watchdog, Bluetooth имя, режимы работы (MOD), вентилятор, и многое другое.
* **Гибкость подключения (API):** Поддержка подключения через Serial порт и Bluetooth для **управления устройством**.
* **Асинхронная архитектура (API и GUI):**  Использование асинхронности для обеспечения неблокирующей работы и отзывчивости вашего приложения, особенно при работе с GUI.
* **Событийно-ориентированная модель (API):**  Основана на событиях для удобного взаимодействия между компонентами вашего приложения и библиотекой `smeller`.
* **Надежная обработка ошибок (API и GUI):**  Комплексная система обработки ошибок и исключений для стабильной работы и информативных сообщений об ошибках как в API, так и в GUI.
* **Чистый и тестируемый код (API и GUI):**  Разработана в соответствии с лучшими практиками Python, с акцентом на читаемость, модульность и тестируемость.
* **Логирование (API и GUI):** Встроенная система логирования для отслеживания работы библиотеки и облегчения отладки.
* **Тёмная и светлая темы оформления (GUI):** GUI поддерживает смену тем оформления для комфортной работы в различных условиях освещения.

**Технологический стек:**

* **Python 3.10+:**
* **PyQt6 (GUI):** Современный и мощный фреймворк для создания кросс-платформенных GUI приложений.
* **PyQtGraph (GUI):**  Библиотека для визуализации данных и графиков в реальном времени, используется для отображения и редактирования вейпоинтов.
* **PySerial (API):** Обеспечивает надежное и эффективное взаимодействие с устройством через последовательный порт.
* **Bluetooth (bluetooth/pybluez) (API):**  (Опционально) Для беспроводного подключения (если поддерживается устройством).
* **threading и asyncio (API и GUI):** Используются для многопоточности и асинхронных операций, обеспечивая неблокирующий интерфейс.
* **logging (API и GUI):** Встроенная система логирования для отслеживания работы библиотеки.

## Структура проекта
```

📦 smeller
└── 📂 smeller  # Основной код приложения 
    ├── 📄 __init__.py # Инициализация основного пакета smeller. Определяет пакет.
    ├── 📂 commands # Реализации команд управления устройством
    │   ├── 📄 __init__.py # Инициализация пакета commands. Определяет пакет и задает пространство имен для команд управления устройством.
    │   ├── 📄 base.py # Базовые классы для команд управления устройством, такие как Command и CommunicationInterface. Определяет абстрактные интерфейсы для команд и коммуникации.
    │   ├── 📄 channel_control.py # Команды управления отдельными каналами устройства: включение, выключение, установка параметров. Реализует классы команд для управления каналами.
    │   ├── 📄 command_factory.py # Фабрика создания объектов команд на основе строковых идентификаторов команд. Отвечает за создание экземпляров команд по запросу.
    │   ├── 📄 get_help.py # Команда запроса справки или списка доступных команд от устройства. Реализует команду получения справки от устройства.
    │   ├── 📄 misc_commands.py # Различные команды общего назначения, не попадающие в другие категории: перезагрузка логов, watchdog, bluetooth имя и т.д. Содержит набор разнообразных управляющих команд.
    │   ├── 📄 restart_device.py # Команда для перезапуска устройства. Реализует команду перезагрузки устройства.
    │   ├── 📄 set_aroma_params.py # Команды для установки параметров, связанных с ароматическими картриджами или арома-генератором. Реализует команды для настройки ароматизации.
    │   ├── 📄 set_channel_params.py # Команды для установки параметров отдельных каналов, таких как tick_on, tick_off. Реализует команды для детальной настройки каналов.
    │   └── 📄 set_generator.py # Команды для управления общими параметрами генератора, например, мощность или логика работы. Реализует команды управления генератором воздушного потока/распыления.
    ├── 📂 communication # Модули для обмена данными с устройством
    │   ├── 📄 __init__.py # Инициализация пакета communication. Определяет пакет и задает пространство имен для модулей связи.
    │   ├── 📄 base.py # Базовые абстрактные классы и интерфейсы для различных протоколов коммуникации. Содержит базовые классы для коммуникационных интерфейсов.
    │   ├── 📄 bluetooth_com.py # Реализация коммуникационного интерфейса для Bluetooth соединения. Обеспечивает связь с устройством через Bluetooth.
    │   ├── 📄 factory.py # Фабрика для создания объектов коммуникационных интерфейсов (SerialCommunication, BluetoothCommunication). Отвечает за создание коммуникационных объектов.
    │   ├── 📄 mqtt_com.py # Реализация коммуникационного интерфейса для Bluetooth соединения. Обеспечивает связь с устройством через MQTT.
    │   └── 📄 serial_com.py # Реализация коммуникационного интерфейса для последовательного порта (Serial/COM). Обеспечивает связь с устройством через последовательный порт.
    ├── 📂 config # Конфигурация приложения
    │   ├── 📄 __init__.py # Инициализация пакета config. Определяет пакет и задает пространство имен для конфигурации приложения.
    │   ├── 📄 config.py # Data classes для хранения конфигурации приложения, включая DeviceConfig, SerialConfig, AppConfig и др. Определяет структуру конфигурационных данных приложения.
    │   ├── 📄 config_manager.py # Менеджер для загрузки, сохранения и применения конфигурации приложения из файла (JSON). Отвечает за управление конфигурацией приложения.
    │   └── 📄 constants.py # Объявление глобальных констант, используемых в приложении, таких как размеры графиков, лимиты каналов и типы интерполяции. Содержит статические константы приложения.
    ├── 📂 controllers # Контроллеры бизнес-логики, связующее звено между GUI/API и моделями/коммуникацией
    │   ├── 📄 __init__.py # Инициализация пакета controllers. Определяет пакет и задает пространство имен для контроллеров приложения.
    │   ├── 📄 aromablock_model_controller.py # Контроллер, управляющий логикой AromaBlock (загрузка, сохранение, удаление, применение конфигураций). Управляет моделями аромаблоков и взаимодействием с БД.
    │   ├── 📄 cartridge_manager.py # Контроллер для управления информацией о картриджах, их именами и ID, получаемыми с устройства и из базы данных. Управляет информацией о картриджах и их каталогом.
    │   └── 📄 device_controller.py # Основной контроллер для управления устройством, отправки команд и обработки ответов через communication package.  Ядро управления устройством и обработки команд.
    ├── 📂 database # Модули для работы с базой данных (если используется)
    │   ├── 📄 __init__.py # Инициализация пакета database. Определяет пакет и задает пространство имен для работы с базой данных.
    │   └── 📄 db_manager.py # Менеджер для взаимодействия с базой данных, выполняющий операции CRUD для моделей данных. Отвечает за операции с базой данных и ORM.
    ├── 📂 dynamic_control # Логика динамического управления ароматами (например, по временной шкале)
    │   ├── 📄 __init__.py # Инициализация пакета dynamic_control. Определяет пакет и задает пространство имен для динамического управления.
    │   ├── 📄 aroma_table_model.py # Модель таблицы PyQt для отображения списка AromaBlock в графическом интерфейсе. Обеспечивает представление данных AromaBlock в табличном виде.
    │   ├── 📄 dynamic_block_controller.py # Контроллер, реализующий логику динамического управления интенсивностью каналов по заданным временным точкам (вейпоинтам). Управляет динамическим изменением параметров каналов по времени.
    │   └── 📄 view_model.py # ViewModel для динамического управления, связывающий данные и логику динамического контроля с GUI. Обеспечивает связь между GUI и логикой динамического управления.
    ├── 📂 gui # Графический пользовательский интерфейс (PyQt6)
    │   ├── 📄 __init__.py # Инициализация основного пакета GUI. Определяет пакет и задает пространство имен для графического интерфейса.
    │   ├── 📂 aromablocks # Компоненты GUI, связанные с аромаблоками
    │   │   ├── 📄 __init__.py # Инициализация пакета gui.aromablocks. Определяет пакет и задает пространство имен для GUI компонентов аромаблоков.
    │   │   ├── 📄 aroma_block_delegate.py # Делегат для отображения элементов AromaBlock в списках или таблицах, настраивающий внешний вид элементов. Кастомизирует отображение элементов AromaBlock в GUI.
    │   │   ├── 📄 aroma_block_dialog.py # Диалоговое окно для создания и редактирования AromaBlock, включающее поля ввода имени, описания и параметров. Предоставляет интерфейс для создания/редактирования AromaBlock.
    │   │   └── 📄 aroma_block_list.py # Виджет для отображения списка AromaBlock, позволяющий пользователю выбирать, загружать и управлять аромаблоками. Отображает список AromaBlock в GUI.
    │   ├── 📂 cartridges # Компоненты GUI, связанные с картриджами
    │   │   ├── 📄 __init__.py # Инициализация пакета gui.cartridges. Определяет пакет и задает пространство имен для GUI компонентов картриджей.
    │   │   └── 📄 cartridge_info_dialog.py # Диалоговое окно для отображения информации о картридже и, возможно, для его настройки. Предоставляет интерфейс для просмотра информации о картриджах.
    │   ├── 📂 channels # Компоненты GUI, связанные с каналами устройства
    │   │   ├── 📄 __init__.py # Инициализация пакета gui.channels. Определяет пакет и задает пространство имен для GUI компонентов каналов.
    │   │   ├── 📄 channel_button.py # Кастомная кнопка для управления каналом, отображающая его статус и позволяющая переключать канал.  Интерактивный элемент GUI для управления каналом.
    │   │   └── 📄 channel_manager.py # Виджет, управляющий отображением и взаимодействием с набором ChannelButton, организуя их компоновку. Управляет группой ChannelButton и их представлением в GUI.
    │   ├── 📂 control_panel # Компоненты панели управления воспроизведением
    │   │   ├── 📄 __init__.py # Инициализация пакета gui.control_panel. Определяет пакет и задает пространство имен для GUI компонентов панели управления.
    │   │   ├── 📄 control_panel.py # Основная панель управления с кнопками плей/пауза/стоп и таймлайном для управления воспроизведением ароматов.  Содержит виджеты управления воспроизведением.
    │   │   ├── 📄 seconds_time_edit.py # Виджет для ввода и отображения времени в секундах, специализированный для установки общей длительности воспроизведения.  Виджет ввода времени в секундах.
    │   │   └── 📄 timeline_player.py # Виджет таймлайна (слайдер) для визуализации прогресса воспроизведения и управления текущим временем. Виджет для управления и отображения прогресса воспроизведения по времени.
    │   ├── 📂 mediacenter # Компоненты для интеграции с медиа (видео/аудио)
    │   │   ├── 📄 __init__.py # Инициализация пакета gui.mediacenter. Определяет пакет и задает пространство имен для GUI компонентов медиацентра.
    │   │   ├── 📄 aromablock_timeline_widget.py # Виджет временной шкалы для отображения и управления аромаблоками в контексте медиа-воспроизведения.  Виджет таймлайна для интеграции с медиа и аромаблоками.
    │   │   ├── 📄 integrated_player.py # Планировался, но отсутствует; возможно, интеграция медиаплеера и управления ароматами. (Файл отсутствует, описание placeholder).
    │   │   └── 📄 media_view.py # Виджет для отображения медиа-контента, например, видео, синхронизированного с воспроизведением ароматов. Отображает медиа контент в GUI.
    │   ├── 📂 menu_bar # Компоненты для строки меню
    │   │   ├── 📄 __init__.py # Инициализация пакета gui.menu_bar. Определяет пакет и задает пространство имен для GUI компонентов меню.
    │   │   └── 📄 menu_bar_manager.py # Менеджер для создания и управления меню приложения (Файл, Вид, Настройки и т.д.). Управляет строкой меню приложения.
    │   ├── 📂 waypoints # Компоненты для работы с точками на временной шкале/графике
    │   │   ├── 📄 __init__.py # Инициализация пакета gui.waypoints. Определяет пакет и задает пространство имен для GUI компонентов вейпоинтов.
    │   │   ├── 📄 waypoint.py # Класс или структура данных для представления вейпоинта на графике, содержащая время и интенсивность. Определяет структуру данных вейпоинта.
    │   │   └── 📄 waypoint_plot_widget.py # Виджет для отображения графика интенсивности и вейпоинтов, позволяющий пользователю редактировать вейпоинты. Визуализирует график интенсивности и обеспечивает интерактивное управление вейпоинтами.
    │   ├── 📄 connectors.py # Модуль, устанавливающий связи (сигналы и слоты) между различными компонентами GUI и ViewModel. Отвечает за установку соединений между компонентами GUI.
    │   ├── 📄 main_window.py # Главное окно приложения, объединяющее все компоненты GUI и ViewModel. Основное окно приложения, контейнер для всех GUI компонентов.
    │   ├── 📄 theme_manager.py # Менеджер для применения тем оформления к GUI приложения (светлая, темная и т.д.). Управляет темами оформления GUI.
    │   └── 📄 ui_manager.py # Главный менеджер UI, отвечающий за создание, компоновку и управление всеми виджетами GUI.  Координирует создание и управление всеми элементами GUI.
    ├── 📂 models # Модели данных приложения
    │   ├── 📄 __init__.py # Инициализация пакета models. Определяет пакет и задает пространство имен для моделей данных.
    │   ├── 📄 aroma_block.py # Модель данных для AromaBlock, представляющая собой контейнер конфигураций каналов для определенного арома-сценария. Определяет структуру данных AromaBlock.
    │   ├── 📄 aroma_event.py # Модель данных для единичного ароматического события, содержащая параметры команды и время срабатывания. Определяет структуру данных AromaEvent.
    │   ├── 📄 aroma_track.py # Модель данных для AromaTrack, представляющая собой последовательность AromaBlock, формирующую полный ароматический трек.  Определяет структуру данных AromaTrack.
    │   ├── 📄 base.py # Базовый класс для моделей данных, предоставляющий общую функциональность или поля. Содержит базовые классы для моделей данных.
    │   ├── 📄 cartridge.py # Модель данных для картриджа, содержащая информацию о типе аромата, ресурсе и идентификаторе. Определяет структуру данных Cartridge.
    │   ├── 📄 channel_control_config.py # Модель данных для конфигурации управления каналом, включая вейпоинты, тип интерполяции и другие параметры. Определяет структуру данных ChannelControlConfig.
    │   └── 📄 interpolation.py # Enum, определяющий типы интерполяции для динамического управления интенсивностью ароматов. Определяет перечисление InterpolationType.
    ├── 📂 services 
    │   └── 📄 mqtt_client.py.py # MQTT клиент
    ├── 📂 tests # Модульные и интеграционные тесты
    │   ├── 📄 __init__.py # Инициализация пакета tests. Определяет пакет и задает пространство имен для тестов.
    │   ├── 📄 test.py # Общий файл для запуска тестов или определения базовых тестовых классов.  Содержит общие тестовые функции или настройки.
    │   ├── 📄 test_db_aromablock.py # Тесты для проверки корректности работы с AromaBlock в базе данных (CRUD операции). Содержит тесты для модели AromaBlock и базы данных.
    │   ├── 📄 test_db_connection.py # Тесты для проверки соединения с базой данных и основных функций db_manager. Содержит тесты для проверки соединения с БД.
    │   ├── 📄 test_device_functionality.py # Интеграционные тесты для проверки функциональности устройства через DeviceController. Содержит интеграционные тесты для DeviceController и устройства.
    │   └── 📄 test_dynamic.py # Тесты для проверки логики динамического управления ароматами и DynamicBlockController. Содержит тесты для динамического управления.
    └── 📂 utils # Вспомогательные утилиты и функции
        ├── 📄 __init__.py # Инициализация пакета utils. Определяет пакет и задает пространство имен для утилитных функций.
        ├── 📄 comport_manager.py # Утилита для управления COM-портами, их обнаружения и кэширования списка портов.  Содержит утилиты для работы с COM-портами.
        ├── 📄 events.py # Реализация системы событий для асинхронного уведомления компонентов приложения о различных событиях. Реализует систему обработки событий в приложении.
        └── 📄 exceptions.py # Определение кастомных исключений, используемых в приложении для обработки ошибок и исключительных ситуаций. Определяет иерархию исключений приложения.

```

## Установка API

Для установки библиотеки `smeller` используйте `pip`:

```bash
pip install sensorylab-smeller
```

## Установка API и GUI

```bash
pip install sensorylab-smeller[gui]
```

**Предварительные требования:**

* **Python 3.10 или выше:** Убедитесь, что у вас установлена подходящая версия Python.
* **PySerial:** Устанавливается автоматически как зависимость при любой установке.
* ***PyQt6 и PyQtGraph (опционально, для GUI):*** Устанавливаются автоматически при установке с опцией `[gui]`.

## Интеграция в ваше приложение

### 1. Импорт необходимых модулей

В вашем Python скрипте импортируйте классы из библиотеки `smeller`:

```bash
from smeller.config import DeviceConfig
from smeller.controllers.device_controller import DeviceController
from smeller.communication.factory import create_communication
from smeller.utils.events import EventHandler
import asyncio
import logging
```
### 2. Настройка логирования (рекомендуется)

Настройте логирование для отслеживания работы библиотеки и отладки:
```bash
logging.basicConfig(level=logging.DEBUG) # Или logging.INFO для менее подробного вывода
```
### 3. Инициализация компонентов

Создайте экземпляры `DeviceConfig`, `EventHandler`, и `DeviceController`:
```bash
config = DeviceConfig() # Можно настроить параметры в DeviceConfig, если необходимо
event_handler = EventHandler()
communication = create_communication(config, 'serial') # Или 'bluetooth' для Bluetooth подключения
controller = DeviceController(communication, config, event_handler)
```


### 4. Подключение к устройству


### Перечисление доступных COM-port устройств
Вы можете использовать `COMPortManager` из библиотеки `smeller` для получения списка доступных Serial портов.

```bash
from smeller.utils.manager import COMPortManager

def list_serial_ports():
    port_manager = COMPortManager()
    available_ports = port_manager.get_com_ports()
    if available_ports:
        print("Доступные Serial порты:")
        for port_info in available_ports:
            print(f"  - Порт: {port_info.device}, Описание: {port_info.description}, HWID: {port_info.hwid}")
    else:
        print("Serial порты не найдены.")

# ... в вашем asyncio main() или в отдельной функции ...
list_serial_ports()
```

**Bluetooth подключение (если поддерживается устройством):**

Для Bluetooth подключения библиотека `smeller` предоставляет возможность поиска и перечисления доступных устройств Neuroair. Вы можете использовать `BluetoothDeviceController` для обнаружения устройств и получения информации о них.

Пример кода для поиска и списка Bluetooth устройств:

```bash
import asyncio
import logging
from smeller.communication.bluetooth_com import BluetoothDeviceController # Импорт контроллера Bluetooth

logging.basicConfig(level=logging.DEBUG)

async def list_bluetooth_devices():
    bt_controller = BluetoothDeviceController()
    print("Начинаем поиск Bluetooth устройств...")
    devices = await bt_controller.discover_devices()
    if devices:
        print("Найденные Bluetooth устройства:")
        for device_info in devices:
            print(f"  - Имя: {device_info.name}, MAC: {device_info.mac}, COM-порт: {device_info.com_port}, Сопряжено: {device_info.is_paired}")
        return devices
    else:
        print("Bluetooth устройства не найдены.")
        return []

async def main():
    available_devices = await list_bluetooth_devices() # Получаем список устройств

    if not available_devices:
        print("Невозможно подключиться: Bluetooth устройства не найдены.")
        return

    # Даем пользователю выбрать устройство (пример - можно сделать GUI выбор)
    selected_device = available_devices[0] # По умолчанию - первое устройство
    print(f"Попытка подключения к устройству: {selected_device.name} ({selected_device.mac}), COM-порт: {selected_device.com_port}")

    # ... дальнейший код подключения с использованием controller.connect(connection_type='bluetooth', device_info=selected_device) ...

if __name__ == "__main__":
    asyncio.run(main())
```
> для Bluetooth discovery требуется, чтобы Bluetooth на компьютере был включен и устройство Neuroair было в режиме обнаружения (если это необходимо для вашей модели устройства).
>Используйте асинхронный метод `controller.connect()` для установки соединения. Укажите COM-порт для Serial подключения или MAC-адрес для Bluetooth (если необходимо).

**Serial подключение:**
```bash
async def main():
    # ... инициализация компонентов как в шаге 3 ...

    com_port = "COM3" # Замените на ваш COM-порт
    if await controller.connect(com_port=com_port):
        print(f"Успешно подключено к {com_port}")
        # Дальнейшая работа с устройством
    else:
        print("Не удалось подключиться к устройству.")

if __name__ == "__main__":
    asyncio.run(main())
```
### 5. Отправка команд и обработка ответов

Используйте методы `DeviceController` для отправки команд.  Большинство методов соответствуют командам устройства и возвращают разобранный ответ в виде списка строк.

**Пример: Получение справки (команда 'h')**
```bash
async def main():
    # ... инициализация и подключение ...

    if controller.is_connected():
        help_response = await controller.get_help()
        if help_response:
            print("Ответ на команду 'help':")
            for line in help_response:
                print(line)
        else:
            print("Ошибка при выполнении команды 'help'.")

    await controller.disconnect() # Важно не забывать отключаться

if __name__ == "__main__":
    asyncio.run(main())
```
**Пример: Установка параметров канала 1 (команда 'p')**
```bash
async def main():
    # ... инициализация и подключение ...

    if controller.is_connected():
        channel_params_response = await controller.set_channel_parameters(channel=0, on_tick=100, off_tick=50)
        if channel_params_response:
            print("Ответ на команду 'set_channel_parameters':", channel_params_response)
        else:
            print("Ошибка при выполнении команды 'set_channel_parameters'.")

    await controller.disconnect()

if __name__ == "__main__":
    asyncio.run(main())
```
### 6. Подписка на события (опционально, но рекомендуется)

Библиотека `smeller` использует систему событий для уведомления о различных состояниях и ответах устройства. Вы можете подписаться на события, чтобы реагировать на них в вашем приложении.

**Пример подписки на события 'device_connected', 'device_disconnected', и 'error':**
```bash
async def on_device_connected(event):
    print(f"Устройство подключено! Данные события: {event.data}")

async def on_device_disconnected(event):
    print("Устройство отключено.")

async def on_error(event):
    print(f"Произошла ошибка: {event.data}")

async def main():
    # ... инициализация компонентов ...

    event_handler.subscribe("device_connected", on_device_connected)
    event_handler.subscribe("device_disconnected", on_device_disconnected)
    event_handler.subscribe("error", on_error)

    # ... подключение и работа с устройством ...

    event_handler.unsubscribe("device_connected", on_device_connected) # Отписка, когда больше не нужно
    event_handler.unsubscribe("device_disconnected", on_device_disconnected)
    event_handler.unsubscribe("error", on_error)

if __name__ == "__main__":
    asyncio.run(main())
```
## Режимы работы устройства (Neuroair)


* **Режим управления каналами:** Предназначен для точной настройки параметров отдельных каналов. Включает команды для установки `on_tick`, `off_tick` и дополнительных параметров, а также для включения, выключения, активации и деактивации каналов (`channel_on`, `channel_off`, `channel_enable`, `channel_disable`). Этот режим позволяет детально контролировать интенсивность и длительность воздействия каждого канала.
* **Режим арома контроля:** Специализирован для управления ароматическими каналами. Предоставляет команды для установки параметров арома-каналов (`set_aroma_parameters`), а также для включения, выключения, активации и деактивации ароматов (`aroma_on`, `aroma_off`, `aroma_enable`, `aroma_disable`). Режим позволяет создавать и контролировать ароматические сценарии.
* **Режим управления генератором:** Обеспечивает контроль над общими параметрами генератора воздушного потока, включая управление питанием (`set_generator_power`) и логикой работы (`set_generator_logic`). Этот режим влияет на общую работу устройства, обеспечивая основу для работы каналов и ароматов.
* **Режим конфигурации и обслуживания:** Включает команды для настройки общих параметров устройства и выполнения сервисных функций. К этому режиму относятся команды для установки watchdog таймера (`set_watchdog`), Bluetooth имени (`set_bluetooth_name`), управления режимами работы MOD (`set_mod`, `get_mod`), настройки WiFi (`set_wifi`), и сброса параметров каналов (`reset_channel_parameters`, `reset_channels`).
* **Режим отладки и диагностики:** Предоставляет инструменты для диагностики и отладки устройства. Включает команды для получения отладочной информации (`debug`, `htop`, `i2c_list`, `crGetI`), просмотра логов перезагрузки (`reboot_log`), и запуска тестов каналов (`test_channels`). Эти команды полезны для разработчиков и для диагностики состояния устройства.
* **Режим управления вентилятором:** Позволяет управлять вентилятором устройства, настраивая его параметры, такие как максимальная мощность PWM (`set_fan`) и конфигурацию PWM (`set_fan_config`). Этот режим позволяет контролировать охлаждение и воздушный поток устройства.

## Доступные команды

Библиотека `smeller` предоставляет методы для отправки следующих команд устройству Neuroair:
| Команда (метод Python) | Описание | Синтаксис команды устройства | Параметры метода Python | Возвращаемый ответ |
| --------------------------------------- | -------------------------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `get_help()` | Запрос справки по командам | `h` | Нет | `List[str]` - Список строк справки |
| `set_channel_parameters(channel, on_tick, off_tick, **kwargs)` | Установка параметров канала | `p <channel> <on_tick> <off_tick> [kwargs]` | `channel: int`, `on_tick: int`, `off_tick: int`, `kwargs: Dict[str, Any]` (доп. параметры) | `List[str]` - Ответ устройства (например, `['OK']`) |
| `restart()` | Перезагрузка устройства | `restart` | Нет | `List[str]` - Ответ устройства |
| `set_aroma_parameters(idAroma, onTick, offTick, **kwargs)` | Установка параметров арома канала | `cp <idAroma> <onTick> <offTick> [kwargs]` | `idAroma: int`, `onTick: int`, `offTick: int`, `kwargs: Dict[str, Optional[int]]` | `List[str]` - Ответ устройства |
| `aroma_on(idAroma, mod=None)` | Включить арома канал | `ce <idAroma> [mod]` | `idAroma: int`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `aroma_off(idAroma, mod=None)` | Выключить арома канал | `cd <idAroma> [mod]` | `idAroma: int`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `aroma_enable(idAroma, mod=None)` | Активировать арома канал | `cS <idAroma> [mod]` | `idAroma: int`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `aroma_disable(idAroma, mod=None)` | Деактивировать арома канал | `cs <idAroma> [mod]` | `idAroma: int`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `set_generator_power(state)` | Установить состояние питания генератора (0/1) | `g <state>` | `state: int (0 или 1)` | `List[str]` - Ответ устройства |
| `set_generator_logic(state)` | Установить логическое состояние генератора (0/1) | `G <state>` | `state: int (0 или 1)` | `List[str]` - Ответ устройства |
| `channel_on(n_channel, mod=None)` | Включить канал | `e <n_channel> [mod]` | `n_channel: int`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `channel_off(n_channel, mod=None)` | Выключить канал | `d <n_channel> [mod]` | `n_channel: int`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `channel_enable(n_channel, mod=None)` | Активировать канал | `S <n_channel> [mod]` | `n_channel: int`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `channel_disable(n_channel, mod=None)` | Деактивировать канал | `s <n_channel> [mod]` | `n_channel: int`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `reset_channels()` | Сбросить все каналы | `r` | Нет | `List[str]` - Ответ устройства |
| `test_channels(delay=5000, onTick=500, offTick=2000)` | Запустить тестовый режим каналов | `test <delay> <onTick> <offTick>` | `delay: int`, `onTick: int`, `offTick: int` | `List[str]` - Ответ устройства |
| `set_watchdog(n_channel, watchdog)` | Установить watchdog таймер для канала | `W <n_channel> <watchdog>` | `n_channel: int`, `watchdog: int` | `List[str]` - Ответ устройства |
| `set_bluetooth_name(bluetoothName)` | Установить имя Bluetooth устройства | `btn <bluetoothName>` | `bluetoothName: str` (макс. 16 символов) | `List[str]` - Ответ устройства |
| `reboot_log(n)` | Получить логи перезагрузки | `reboot_log <n>` | `n: int` | `List[str]` - Лог перезагрузки |
| `set_mod(mod, n_channel=None)` | Установить режим работы (MOD) для устройства или канала | `set_mod [n_channel] <mod>` | `mod: int`, `n_channel: Optional[int]` | `List[str]` - Ответ устройства |
| `get_mod(n_channel=None)` | Получить режим работы (MOD) для устройства или канала | `get_mod [n_channel]` | `n_channel: Optional[int]` | `List[str]` - Ответ устройства |
| `i2c_list()` | Получить список I2C устройств | `i2c_list` | Нет | `List[str]` - Список I2C устройств |
| `set_wifi(SSID, password)` | Настроить WiFi подключение | `set_wifi <SSID> <password>` | `SSID: str` (макс. 32 символа), `password: str` (макс. 63 символа) | `List[str]` - Ответ устройства |
| `htop()` | Получить информацию о процессах (htop) | `htop` | Нет | `List[str]` - Вывод команды htop |
| `set_mqtt_sub(MQTT_SUB)` | Установить MQTT topic для подписки | `setMqttSub <MQTT_SUB>` | `MQTT_SUB: str` | `List[str]` - Ответ устройства |
| `cr_get_info()` | Получить информацию CR | `crGetI` | Нет | `List[str]` - Информация CR |
| `reset_channel_parameters()` | Сбросить параметры всех каналов | `R` | Нет | `List[str]` - Ответ устройства |
| `reset_parameters_for_mod(flag, mod=None)` | Сбросить параметры для режима MOD | `Rs [mod] <flag>` | `flag: int (0 или 1)`, `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `reinit_status(mod=None)` | Реинициализировать статус | `Rg [mod]` | `mod: Optional[int]` | `List[str]` - Ответ устройства |
| `set_fan(pwmMax)` | Установить максимальную PWM для вентилятора | `f <pwmMax>` | `pwmMax: int` | `List[str]` - Ответ устройства |
| `set_fan_config(pwmMax, pwmMin, pwmMode, period)` | Установить конфигурацию вентилятора | `x <pwmMax> <pwmMin> <pwmMode> <period>` | `pwmMax: int`, `pwmMin: int`, `pwmMode: int`, `period: int` | `List[str]` - Ответ устройства |
| `debug()` | Включить режим отладки | `debug` | Нет | `List[str]` - Ответ устройства |

## Статус разработки и известные ограничения

На данный момент библиотека `smeller` находится в активной разработке.  Некоторые функции могут быть еще не полностью реализованы или находиться в стадии тестирования.

**Временно отключенные или разрабатываемые функции:**

* **Команды, связанные с расширенными функциями мониторинга и диагностики:**  Некоторые команды, такие как, `reset_parameters_for_mod`, `reinit_status`, `set_mod (on chanel)`, `get_mod (on chanel)` могут быть временно отключены или работать нестабильно.  Их функциональность будет дорабатываться в следующих версиях библиотеки.
* **Bluetooth подключение:**  Функциональность Bluetooth подключения может быть ограничена для `mac os` и находится на стадии тестирования. Рекомендуется использовать Serial подключение для наиболее стабильной работы.
* **Полная документация:**  Полная документация по всем функциям и классам библиотеки находится в процессе создания.

**Известные ограничения:**

* **Обработка ошибок ответов:** В текущей версии библиотеки реализована базовая обработка ошибок, но в будущем планируется ее расширение для более детального анализа ответов устройства и предоставления более информативных сообщений об ошибках.
* **Совместимость устройств:** Библиотека разрабатывалась для определенной модели Neuroair устройства. Совместимость с другими моделями Neuroair не гарантируется и требует дополнительного тестирования.

## Вклад в разработку

Приветствуются любые вклады в развитие библиотеки `smeller`! Если вы хотите помочь, вы можете:

* Сообщать об ошибках и предложениях по улучшению.
* Предлагать исправления кода (pull requests).
* Улучшать документацию.
* Расширять функциональность библиотеки.

## Лицензия

Распространяется под лицензией ***.  Смотрите файл [LICENSE](LICENSE) для получения подробной информации.

## Контакты

Для связи и вопросов по библиотеке `smeller` вы можете использовать:

* [Ссылка на ваш репозиторий GitTea Issues] (для сообщений об ошибках и предложений)
* fox@sensorylab.ru

---

**Спасибо за использование библиотеки `smeller`!**
**Что нужно сделать дальше:**

1. **Заполнить описание режимов работы устройства.**  Подумайте, какие режимы реально есть или можно выделить из функциональности команд. Если режимов как таковых нет, можно просто описать функциональные блоки.
2. **Проверьте таблицу команд на точность и полноту.** Убедитесь, что все команды и параметры описаны правильно, и таблица легко читается.
3. **В секции "Статус разработки" точно перечислите команды, которые сейчас не работают.**  Основывайтесь на результатах ваших тестов.
4. **Создайте файлы LICENSE и README.md** в корне вашего проекта и скопируйте это содержимое в README.md.
5. **Подготовьте проект к публикации на PyPI.**  Вам потребуется файл `setup.py` или `pyproject.toml` для описания пакета.
6. **Зарегистрируйтесь на PyPI** и опубликуйте пакет командой `python setup.py sdist bdist_wheel upload` (или аналогичной, в зависимости от вашего setup-файла).

```
https://pypi.org/project/smeller/0.1.0/
```
