Логика работы коннектора
------------------------
Предполагаем, что коннектор зарегистрирован в платформе и имеет идентификатор: ``<connector_id>``.

#.  На устройстве, на котором будет работать конфигуратор, создаём конфигурационный файл
    вида:

    .. code-block:: python

        {
            id: "<connector_id>",
            url: "mqtts://<peresvet_server>"
            ssl: {
                certFile: "<path_to_certificate_file>", # путь к файлу сертификата
                keyFile: "<path_to_key_file>", # путь к файлу с приватным ключом
                caFile: "<path_to_ca_file>", # путь к файлу сертификата удостоверяющего центра
                certsRequired: "CERT_NONE" # CERTS_NONE | CERTS_OPTIONAL | CERTS_REQUIRED
            }
        }

    где:
        * **id** - идентификатор коннектора в платформе.
        * **url** - строка коннекта к платформе. В случае, если протокол ``mqtts``, то необходим раздел
          конфигурации ``ssl``.
        * **ssl** - параметры безопасности для работы по протоколу SSL.

    .. note::

        Файл конфигурации содержит необходимый минимум информации для связи коннектора с платформой.

        Полную информацию для работы коннектор получает от платформы.

        Этим достигается централизация управления системой: настроить работу коннектора можно,
        исправив его конфигурацию в платформе. Внесённые изменения будут применены коннектором
        в режиме онлайн.

#.  Запускаем коннектор в работу:

    .. code-block:: bash

        $ python <connector>.py <path_to_config_file>

    В случае, если в строке запуска не указан путь к файлу конфигурации, то
    по умолчанию принимается, что файл конфигурации называется ``config.json``
    и находится в текущем каталоге.

#.  Коннектор читает сохранённую на диске конфигурацию, полученную от платформы при предыдущем
    сеансе запуска и начинает работать согласно этой конфигурации.

    Если это первый запуск коннектора до этого связи с платформой не было, этот шаг пропускается.

#.  Коннектор запускает на исполнение четыре независимых задачи,
    которые исполняются как бесконечные циклы:

    * `Обработка сообщений от платформы`_
    * `Чтение данных из источника`_
    * `Отправка данных в платформу`_
    * `Обработка буфера данных`_

#.  Основной цикл работы коннектора также бесконечен:
    коннектор пытается установить связь с платформой. Каждый раз, когда связь устанавливается,
    коннектор посылает в платформу запрос на получение полной конфигурации.

    Если полученная конфигурация отличается от старой, то задача чтения данных из источника
    останавливается, и запускается по-новой, в соответствии с новой конфигурацией.

Подключение по MQTT и Last Will (LWT)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Связь с платформой осуществляется по протоколу MQTT. При подключении к брокеру коннектор
настраивает **Last Will and Testament (LWT)** — сообщение, которое брокер публикует при
нештатном отключении коннектора (обрыв сети, аварийное завершение, таймаут keepalive).

Платформа подписана на это сообщение и при его получении записывает во все теги,
привязанные к данному коннектору, значение ``null`` с **кодом качества 100** (потеря связи
с коннектором). Так в платформе различают «нет данных из-за отключения коннектора» и
«нет данных по другой причине».

Параметры LWT задаются в базовом классе автоматически:

* **Топик:** ``prsConnector/connection_lost/<connector_id>``
* **Тело (payload):** JSON ``{"id": "<connector_id>"}``

Дополнительная настройка в коннекторе не требуется. Подробнее о кодах качества тегов
при работе с коннекторами см. документацию платформы Пересвет: раздел «Коннекторы» →
«Связь по MQTT и коды качества тегов».

Описание задач
~~~~~~~~~~~~~~
Обработка сообщений от платформы
""""""""""""""""""""""""""""""""
Коннектор может принимать от платформы сообщения, связанные с изменением его конфигурации:

* изменение параметров подключения к источнику данных,
* изменения в конфигурации журнала логов,
* изменения списка привязанных тегов,
* изменения параметров привязанных тегов.

Чтение данных из источника
""""""""""""""""""""""""""
Это единственный метод, который необходимо полностью определять в каждой реализации коннектора.
Метод чтения данных должен помещать прочитанные данные в очередь данных. Вся обработка данных
будет проводиться базовым классом коннектора в зависимости от указанных в конфигурации параметров.

Отправка данных в платформу
"""""""""""""""""""""""""""
При наличии в очереди данных сообщений коннектор обрабатывает каждое сообщение.

Каждое сообщение - это массив данных тега(-ов).

Если у значения нет метки времени, коннектор добавит текущую метку времени.

Каждое значение тега:

#.  Конвертируется с помощью JSONata.
#.  Преобразуется к нужному типу данных, хранимых в теге.
#.  Если разница между последним посланным в платформу значением и текущим больше указанного
    в параметре ``maxDev`` предела, то значение будет отправлено в платформу, если связь с платформой разорвана,
    то значение будет помещено в буфер.

Обработка буфера данных
"""""""""""""""""""""""
Коннектор периодически проверяет наличие буфера данных. Если буфер есть и есть связь с платформой, то
данные из буфера отсылаются в платформу.