Привет Хабр! Я занимаюсь разработкой электроники (благо навыки охватывают большую часть этого интереснейшего увлечения). И заказали мне как-то разработку GSM-логгера для ЖКХ.

Кроме наличия требуемых входов/выходов (в том числе 4-20 ма) и источника питания 5-30 в для датчиков, основным условием было минимизация потребления дабы иметь возможность питаться от батарей.После проработки схемотехники и печатной платы во весь рост встал вопрос о используемом протоколе. Хотелось чего-то простого и стандартного.

MQTT. Но MQTT это TCP со всеми достоинствами и недостатками. А у меня аккумулятор и срок работы от 3 месяцов. Для тестов был написан примитивный протокол поверх UDP. Но поскольку не отношу себя к пионэрам, свято уверенным, что вот сейчас за 2 дня напишут что-то удобоваримое — продолжил поиски чего-то общепринятого.

Уж не помню как — попалось мне упоминание о MQTT-SN. Протокол, наследующий семантику MQTT, но приспособленный для передачи по UDP и клиентам с батарейным питанием. Оказалось, есть такой, разработан в недрах IBM и в последующем открыт для сообщества. После прочтения описания стало понятно, что вот оно, счастье, рядом.

Но нужен брокер (так в MQTT называют сервер), привычный Mosquitto (по словам Яна Крагса от 2013) когда-нибудь сможет в MQTT-SN, но не сейчас. Зато есть RSMB, и даже в исходниках на Git-хабе.

Исходники это хорошо, надо собирать. Сборка производиться CygWin-ом в Visual Studio (которую я видел последний раз лет 5 назад). Ставим фришную версию, создаём проект и — никак. На 5-10 раз (вообще в моей жизни большую роль играет случай и упрямство) прописал правильно проект — и о, чудо, собрал таки брокера. Замечу что под Linux это действие прошло гораздо проще.

Торжественно запускаем. Обидно но не работает. Может всё-таки свой протокол это выход? Представив себе объём работы по написанию и отладке сервера и клиентов — решил нет, мой выбор — MQTT-SN. Оказалось всё просто — надо было конфигурацию прописать и указать брокеру.
Минимальная выглядит таким образом:

trace_output off                # Диагностика, можно и включить
listener 1883 INADDR_ANY        # Порт для обычного MQTT
listener 1883 INADDR_ANY mqtts  # Порт для MQTT-SN протокола

И после этого брокер заработал. Вкратце отличия MQTT-SN от классического MQTT.

  1. Протокол MQTT-SN работает поверх UDP, а не TCP как обычный. Это перекладывает ответственность за контроль доставки сообщений на программиста. Зато позволяет устройству расходовать меньше энергии (а для меня это важно) на поддержание канала связи через GSM.

  2. Введён новый уровень QoS (Quality of Service, качество сервиса) -1. Означающий отсутствие контроля доставки. Устройство просыпается, делает нужную работу, отсылает результаты и тут-же засыпает не ожидая подтверждения.

  3. Появились шлюзы, позволяющие агрегировавать данные от множества устройств и пересылать их брокеру.

На git-е eclipsa лежат исходники клиента MQTT-SN с примерами. Собственно надо прописать функции работы с каналом transport_xx под свои нужды. В остальном больших проблем нет (нашёл пару ошибок, надо тестировать).

К сожалению не реализована поддержка спящих клиентов. Стоят заглушки. Кто сможет бросить в авторов протокола камень — исходники доступны, помощь приветствуется.

Что хотел сказать в итоге. Потратив некоторое (небольшое время) я получил готовую инфраструктуру для дальнейшего развития проекта. Протокол позволяет использовать STM32 на 4 МГц. Я могу использовать множество клиентов на разных платформах (что нереально было-бы сделать в одиночку при написании своего протокола). Более того, имея возможность собрать брокера под Linux я разместил его на инстансе Amazon-а и мой заказчик получил решение без необходимости держать и обслуживать сервер. Стандартные решения (не всегда, но в подавляющем количестве случаев) ускоряют исполнение задачи.

Ссылки:
MQTTSN client — Eclipse
RSMB — github
Поделиться с друзьями
-->

Комментарии (19)


  1. starius
    02.09.2016 04:46

    На git-е eclipsa лежат исходники клиента MQTT-SN с примерами.

    Не могли бы вы предоставить ссылку?


    1. elAlex
      02.09.2016 07:50

      Прописал ссылки в подвале.


  1. ittakir
    02.09.2016 05:43

    Что мешало просто просыпаться, передавать 1 UDP пакет и засыпать?
    Протокол, например, такой:
    struct
    {
    int device_id;
    int value;
    }


    1. Chulup
      02.09.2016 06:11
      +1

      Вы, видимо, не очень хорошо себе представляете конкретно протокол UDP и протоколы общения прикладного уровня вообще.
      Для первого необходимо реализовать подтверждение доставки как минимум.
      Для второго поверх UDP вам нужны ещё и механизмы аутентификации, иначе к вам начнут прилетать пакеты непонятно откуда, но вы им будете верить. Я уже не говорю о том, что сообщения явно бывают разные, и тут начинаются все прелести самописных протоколов.


      1. ittakir
        02.09.2016 17:11

        Я довольно хорошо представляю как устроен UDP. Если вы сомневаетесь в этом, прошу привести обоснованные аргументы.
        Автор также использует UDP, и не ждет подтверждения доставки. Только вместо самописной структурки, что я привел как пример, он использует реализацию MQTT. Он вынужден использовать чужой брокер, вместо простейшего UDP сервера, который пишется за 10 минут.
        Что касается аутентификации, то достаточно подписывать цифровой подписью данные в пакете. Если приватный ключ скрыт (а он будет скрыт в защищенной флеш-памяти STM), то никто не сможет подделать сообщения.


        1. elAlex
          02.09.2016 17:37

          Простейший Udp сервер реально пишется быстро. Простейший. А затем приходит очередь писать клиентов, да под разные платформы. Да интегрировать это всё. И встаёт вопрос — что выгоднее — свой протокол и вся инфраструктура или готовый протокол и готовая инфраструктура? Даже с учётом того что пришлось собирать rsmb — для меня ответ очевиден, подняв брокера я получаю доступ к куче готового софта ( на самостоятельное написание которого потратил-бы не один месяц ).


        1. Chulup
          05.09.2016 14:33

          Согласен по поводу UDP, я пропустил пример его использования в статье.

          Автор уже ответил по причинам выбора протокола MQTT, и я не могу его осуждать после того, как пришлось самому писать реализацию своего протокола. После анализа трудозатрат и выгоды я почти убедил менеджмент в отказе от него.


    1. elAlex
      02.09.2016 07:54

      Именно это я и сделал после сборки платы. Процесс написания своего тестового сервера и клиента доказал мне всю глупость ( по крайней мере в этом конкретном случае ) этой затеи.


    1. elAlex
      02.09.2016 07:58

      Собственно передача с QoS -1 и подразумевает описанное действие — проснулся, обработал, отправил и заснул. Просто данные обёрнуты в пакет позволяющий использовать готовую инфраструктуру MQTT-SN.


  1. ColdPhoenix
    02.09.2016 07:55

    Вы упомянули разницу UDP и TCP, и мне вот стало интересно, а насколько часты сейчас потери пакетов?
    вроде бы все растет в сторону надежности.


  1. Kealon
    02.09.2016 07:55
    +1

    Для первого необходимо реализовать подтверждение доставки как минимум.

    У автора как раз и используется UDP что бы не было заморочек с гарантированностью доставки, клиенты не ждут сервер — «дорого».
    Аутентификация сигнала в таком контексте завершается на цифровой подписи, максимум.
    Вопрос «обжимки» с непонятным устройством конечно более серьёзный


  1. j_wayne
    02.09.2016 09:11

    А CoAP рассматривали? http://coap.technology
    Есть RFC: 7252. Нативно применяется UDP.


    1. elAlex
      02.09.2016 16:16

      Теоретически — да. Но маловато информации, а поскольку была развёрнута инфраструктура MQTT — MQTT-SN оказался для меня находкой. Хотелось-бы почитать конечно по нему побольше.


  1. zibn
    02.09.2016 15:59
    +1

    Возник вопрос. Как по мне, то подъем GSM канала съедает столько энергии, что стоит ли уже, в этом случае, заморачиваться c передачей данных через UDP?


    1. elAlex
      02.09.2016 16:13

      Зависит от модели использования.
      Если поднимать канал раз в 24 часа и сбрасывать расходомер — большой роли TCP | UDP не играет. Включил питание модуля — отправил ( получил подтверждение если TCP ) — выключил питание модуля.
      Если-же раз в минуту поднимать датчик давления 4-20, оцифровывать и отсылать — время нахождения модуля в активном режиме играет большую роль. Тогда чем дольше будет спать GSM-модуль — тем дольше проживёт устройство. Естественно в этом случае модуль не рубиться по питанию но отправляется в сон.


      1. zibn
        02.09.2016 17:28

        А не ставили ли натурный эксперимент, по сравнению экономности работы комплекса в целом, при работе через UDP и TCP? Я, конечно, до сравнений и сам доберусь… Просто это будет много позже. А результат, как в известной рекламе про зайцев и батарейки, интересен уже ;)


        1. elAlex
          02.09.2016 17:39

          Нет, поскольку для меня ответ очевиден. Может быть позже, когда соберу установочную партию.


          1. Ivan_83
            02.09.2016 22:35
            +1

            Для меня тоже очевиден ответ — заметной разницы не будет.
            У вас гсм модуль в сети регается не мгновенно, а явно уходит пару секунд на это.
            Далее приходит очередь передавать данные.
            Даже если предположить что связь говно и слать их через всю страну то RTT вряд ли будет больше 200 мс.
            В современных реализациях TCP есть варианты когда данные уходят сразу после ответного ACK от сервера, в итоге получается на 1 RTT дольше передача.

            Модель собрать из готового барахла свой продукт имеет право на жизнь, но мне лично кажется далеко не оптимальным.
            Особенно «порадовало» размещение не весть где сервера. Как применительно к предсказуемости его там жзни так и к увеличению RTT и соответственно времени работы гсм модуля, раз уж на то пошло.

            2 ittakir
            Ты себе хотя бы примерно представляешь сколько требуется вычислений для ЭЦП? (я про RSA/ECDSA)
            Дак вот, этому несчастному контроллеру придётся не один десяток минут пахать чтобы что то подписать, хотя бы на уровне ECDSA с кривой уровня 128 бит секурности.
            Единственный выход для таких применений это подписывать используя симметричную крипту и HMAC.

            2 ColdPhoenix
            В радио пакеты как терялись так и теряются, тем паче автор юзает гсм.


            1. elAlex
              02.09.2016 22:55

              Т.е. сначала тезируется отсутствие разницы — затем выражается возмущение о расположении сервера и связанными с этим задержками TCP? Это как? Для того мне и нужен UDP что-бы не думать о задержках подтверждения.
              Из готового барахла — а продемонстрируйте-ка свою работу. Как одиночки а не части команды. Моя вот
              image