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

Знакомство с Биткоином

Меня всегда привлекали современные технологии, и криптовалюта — не исключение. Как техническому специалисту, мне было интересно узнать какие механизмы скрыты у неё под капотом, и как они работают. Захотелось детально изучить принципы криптографии а также протоколы и алгоритмы, что там используются.

Я был знаком с концепцией блокчейна на базовом уровне, но как он применяется в криптовалюте, и какие функции выполняют другие элементы системы, такие как майнинг-ноды и spv-ноды, представлял довольно опосредованно. А начать изучение решил с первой криптовалюты и прародителя индустрии — Биткоина. Я убежден, что фундаментальные знания о криптовалютах будут полезными и ценными в будущем в целом и в частности при решении технических задач. Возможно, эти знания будут полезны и вам, в вашей работе, или в проектах, которые решите начать.

Стоит обмолвиться, что во многих материалах в интернете (как русскоязычных так и зарубежных) объяснение этой темы идёт довольно обтекаемо, со множеством допущений, избегая ключевых нюансов. После прочтения дюжины статей и просмотра лекций, вопросов оставалось не меньше, чем было получено ответов. Окончательно расставить всё по местам помогли две книги, идеально дополняющие друг друга (1 и 2). Если бы они попались мне с самого начала, то сэкономил бы немало времени. Настоятельно рекомендую всем, кто хочет разобраться что такое SegWit, Coinbase, UTXO, p2sh, p2pkh, фильтр Блума и прочие составляющие Биткоина. Там подробно рассказывается про это и многое другое на доступном языке.

После освоения технических аспектов я сразу начал искать применение своим знаниям. Ну что ж, теперь как минимум могу пользоваться Биткоином для себя, с уверенностью что меня не разведут на вольную интерпретацию его работы. Конечно, это не плохо, но хочется чего-то большего. Было бы интересно самому реализовать что-то, чем смогут пользоваться другие люди. Придумать проект, одним из механизмов которого станет эта криптовалюта, в устройстве которой я теперь неплохо разбираюсь.

Генерация идеи

Хотя сейчас много хайпа вокруг NFT, свопов, бриджей и других решений на основе блокчейна, использовать я хотел именно Биткоин. Использовать его можно для разных технических задач, он даже на каком-то уровне поддерживает смарт-контракты (внезапно). Однако есть нюанс, который мешает его интеграции в пользовательские системы. Речь про скорость работы сети. А вернее даже не скорость работы, а скорость исполнения транзакции (фиксации её в блоке). Новая запись (новый платёж) может быть сохранена сразу, а может зависнуть в зоне ожидания на неопределённый срок. Эта особенность не позволяет делать молниеносные платежи, так важные при деловом взаимодействии. Следовательно, любая интерактивность в режиме реального времени практически исключена, что существенно сужает границы применения.

Когда запушил транзакцию с минимальной комиссией в перегруженный mempool
Когда запушил транзакцию с минимальной комиссией в перегруженный mempool

Но, как оказалось, ситуация не безвыходная. Существует технология под названием Lightning Network. Это протокол второго уровня над сетью Биткоина. Небольшой FAQ по ней можно почитать здесь. Скажу вкратце, что Lightning использует только одну транзакцию оригинальной сети чтобы внести баланс и одну чтобы вывести его. Но когда этот баланс залочен внутри, он может перемещаться по сети Lightning почти без ограничений скорости. Т.е. наши средства приходят из сети Биткоина и уходят обратно в неё, но мы получаем преимущество быстрой передачи, пока они внутри «второго уровня». Оплата по Lightning похожа на оплату смс-сообщениями: имея специальный кошелёк можно за считанные секунды перевести деньги другому держателю аналогичного кошелька. Ok, значит в моём проекте тоже будет Lightning.

В интернете я нашел множество проектов, использующих Lightning Network для целей, связанных только с финансами. Однако же мне хотелось сделать что-то менее прямолинейное.

Среди прочих есть два проекта, которые отличаются от большинства. Первый — это онлайн доска для рисования, где любой пользователь может вносить свои изменения за плату: 1 закрашенный пиксель = 10−8 биткоина. Второй — куриная кормушка на частной ферме в Мексике, где вы можете за довольно символическую плату покормить птиц, и понаблюдать прямую трансляцию, как они едят. Эта идея мне понравилась больше всего!

«Вдохновившись» примером, было решено сделать нечто подобное, но не с курами. Мой коллега предложил идею подкармливать животных в приюте, и мне она очень понравилась. Идея заключается в том, что существуют приюты для собак или другие места содержания животных, где их регулярно кормят и ухаживают за ними. А моё устройство будет давать дополнительные вкусности, например, порцию супер-элитного корма или другое лакомство в строго ограниченном количестве. Любой человек сможет в «прямом эфире» угостить вкусняшкой собачку или котика)

Предполагается, что система работает по принципу куриной фермы: есть устройство (кормушка), которое получает сигнал с сервера и выдаёт корм, когда происходит оплата. За прием платежей отвечает Lightning-нода, которая взаимодействует с сервером, запускающим кормушку. Все эти действия будут транслироваться на моей WEB-странице. А ещё туда можно добавить чат для комментариев, похожий на гостевую книгу (привет из 2000-ых), который также будет работать на криптовалютных платежах. Just for fun :)

Архитектура проекта

Итак, идея проекта зафиксирована, приступаю к реализации. Что же для этого понадобится?

Так как в схеме присутствует трансляция видео, нужна IP-камера. Для передачи информации с камеры на клиентское приложение нужен сервер для декодирования и ретрансляции. Для Bitcoin Core и Lightning Network нужен ещё один сервер.

Из-за потенциальной мобильности проекта нецелесообразно подвязываться на сеть места установки, так как это потребует постоянных перенастроек роутера при перемещении. Чтобы такого избежать, следует объединить устройства в одну локальную сеть через свой роутер, обеспечивающий доступ в интернет посредством 4G-модема. Такая схема позволяет быть мобильным и гибко настраивать сеть для подключения к специфическим устройствам или приложениям. Как раз мой случай.

Бэкэнд будет в виде нескольких микросервисов: один для взаимодействия с девайсами, второй для работы с сетью Lightning, третий — объединять их, а также ходить в базу и связываться с клиентом. Клиентское приложение — SPA на каком-нибудь современном js-фреймворке. Отдельно я добавлю базу данных для сохранения чата и информации о платежах.

Так как я использую свой роутер, а BTC-нода и камера находятся в его локальной сети, то не имеет смысла размещать микросервисы и базу на VDS или AWS, потому что для отдачи данных клиенту, эти данные всё равно будут собираться на моём сервере и проходить через бутылочное горлышко 4G, что плохо скажется на производительности. Ставя во главу угла именно перфоманс, я понимаю что такой подход порождает ряд проблем с надежностью, сложностью масштабирования и безопасностью. Такая архитектура, мягко говоря, не совершенна. Но учитывая издержки, а также то, что это прототип идеи, которая может оказаться вовсе нерабочей, считаю допустимым первую версию реализовать именно так. Зная лучшие практики также важно знать, когда можно их и не использовать)

Высокоуровневый Архитектурный план
Высокоуровневый архитектурный план

В итоге принято решение установить два физических сервера — один для BTC-ноды, другой сразу для всего остального: базы данных, микросервисов и хостинга frontend-статики (durability, scalability, isolation, сарказм).

Выбор железа

В качестве базы для BTC-ноды я буду использовать микрокомпьютер Raspberry Pi 4B — хорошее компактное решение. В комплект вошли сама плата, microsd на 32Гб, активное охлаждение, корпус, зарядное устройство. Для хранения блокчейна используется SSD накопитель в стильном кейсе от Baseus.

Для application-сервера моим коллегой пожертвован ноутбук 2009-го года с частично повреждённой платой, 2Gb оперативной памяти и без батарейки. То что нужно, подумал я: как раз хватит и докер развернуть и highload-тестирование сделать (сарказм). Отдельно пришлось купить донорскую плату и произвести небольшой ремонт, но это оказалось довольно незатратно.

Ремонтирую будущий сервер
Ремонтирую будущий сервер

Сама кормушка сначала была в виде простого аналогового кормового диспенсера, а потом заменена на устройства от PetKit с чипом Arduino для программного управления.

Итого:
Сервер №1: Raspberry Pi 4 Model B 4Gb (+ корпус, microsd, зарядка, кулер)
Сервер №2: ноутбук HP 615 Compaq 2009
IP-камера: V380 Pro
Роутер: ZBT WE-1626
4G-модем: Huawei E3372h-153
SSD-накопитель: Sandisk Ultra 3D NAND 1TB
Кормушка: PetKit FreshElement Solo
Контроллер: Arduino Uno от Keystudio

Подготовка железа и реализация софта

Пока часть деталей едет почтой, чтобы не терять времени, я настроил виртуальную машину и принялся за софт. Первым делом купил SSD, установил Bitcoin Core и запустил синхронизацию блокчейна. Bitcoin Core — это официальное программное обеспечение, которое содержит полный набор функций, необходимых для участия в работе сети этой криптовалюты.

Стоит отметить, что в интернете существует несколько решений на основе Bitcoin Core, которые можно скачать и развернуть в один клик. Эти решения (в теории) содержат оригинальное ПО под капотом, но с обновлённым UI или другими улучшениями. Однако что касается криптовалют, то подобные варианты я стараюсь не использовать, и вот несколько причин, почему я считаю это важным:

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

  2. Сложно контролировать версию и своевременно обновлять ПО.

  3. Если использовать готовое решение, оно может быть предназначено для определенной операционной системы или аппаратной платформы, которая не подойдёт под мою аппаратно-программную конфигурацию.

Исходя из вышесказанного, я решил собрать Bitcoin Core из исходников в взятых с официального репозитория. После установки нужно задать свои настройки в

~/.bitcoin/bitcon.conf

txindex=1
assumevalid=0
uacomment=my_alias
datadir=/media/user/SSD/.bitcoin
listen=1
maxconnections=20
rpcuser=my_user
rpcpassword=my_pass
zmqpubrawblock=tcp://127.0.0.1:28332
zmqpubrawtx=tcp://127.0.0.1:28333

Установка и настройка прошли без эксцессов и не заняли много времени. Далее перезапускаем клиент и даём системе время настояться.

Загрузка блокчейна Биткоина в Bitcoin Core
Загрузка блокчейна Биткоина в Bitcoin Core

Процесс загрузки и синхронизации занял почти полную неделю беспрерывной работы сети, но в итоге всё завершилось успешно.

Далее можно научиться пользовать лайтнингом. В плане исходников тут есть пространство для маневра, потому что, в отличие от Bitcoin Core, Lightning — это протокол, где нет каноничного варианта финального программного продукта. Существует несколько реализаций, каждая из которых имеет свои преимущества и недостатки. Вот наиболее популярные:

  1. LND (Lightning Network Daemon) — реализация протокола Lightning Network от компании Lightning Labs. LND написан на языке Go, имеет открытый исходный код и поддерживает как Bitcoin, так и Litecoin. Есть хорошая документация и активное сообщество разработчиков.

  2. Core lightning — реализация на языке C, созданная компанией Blockstream. Core lightning также имеет открытый исходный код и поддерживает как Bitcoin, так и Litecoin. Он имеет хорошую производительность и надежность, а также удобный интерфейс командной строки.

  3. Eclair — это реализация протокола Lightning Network на языке Scala, созданная компанией ACINQ. Eclair также имеет открытый исходный код и поддерживает только Bitcoin. Он имеет легковесный дизайн и быстрое развертывание, а также хорошую производительность и безопасность.

Каждая из этих реализаций имеет свои особенности, поэтому выбор зависит от ваших потребностей и предпочтений. Почитав описания, а также оценив размер сообщества и наличие документации, я остановил свой выбор на LND.

Установить его и настроить оказалось также несложно. Настройка производится через conf-файл, как и в BTC Core. Для связывания сетей BTC и LND прописываются данные пользователя, хост и пароль. В моем случае ещё пришлось столкнуться с разблокировкой кошелька, но это нюансы.

~/.lnd/lnd.conf

alias=https://617-btc.com
color=#a354d9
gc-canceled-invoices-on-startup=true
gc-canceled-invoices-on-the-fly=true
accept-amp=true
accept-keysend=true
bitcoin.active=true
bitcoin.mainnet=true
bitcoin.node=bitcoind
bitcoind.rpcuser=my_user
bitcoind.rpcpass=my_pass
bitcoind.zmqpubrawblock=tcp://127.0.0.1:28332
bitcoind.zmqpubrawtx=tcp://127.0.0.1:28333
rpclisten=0.0.0.0:10009
listen=0.0.0.0:9735
listen=[::1]:9736
wallet-unlock-password-file=/etc/lnd/pwd
externalip=my_ip
autopilot.active=1
autopilot.maxchannels=20
autopilot.allocation=0.6
autopilot.minchansize=200000
autopilot.maxchansize=16777215
Завершённая синхронизация LND
Завершённая синхронизация LND

Также как и на виртуальной машине, на реальном устройстве эти приложения будут работать на одном хосте, поэтому конфиги можно потом скопировать туда, подключив уже готовый SDD с блокчейном, без необходимости настраивать всё с нуля.

Блокчейн Биткоина скачан и синхронизирован c LND, значит теперь можно написать микросервис, который будет принимать запросы пользователя и контактировать с сетью Lightning. В качестве платформы для бэкэнда я выбрал Node.js.

К моему удобству, в LND по умолчанию встроен gRPC-сервер, где доступны сервисы для работы с инвойсами — то что нужно. Мой бэкэнд будет создавать инвойс через вызов соответствующей gRPC-процедуры по запросу клиента. После создания инвойса на него вешается подписка, и как только пройдёт оплата, мой микросервис об этом узнает.

// Параметры инвойса: описание, размер платежа, время жизни
const invoiceBody = {
  memo: 'Payment for feeder',
  value: 1,
  expiry: 180,
};

// Вызов gRPC-процедуры создания инвойса
lightningService.addInvoice(invoiceBody, (invoiceErr, invoiceRes) => {
  if (invoiceErr) {
    return 'Oops! Something went wrong...';
  }

  const createdInvoiceCall = invoicesService.subscribeSingleInvoice({ r_hash: invoiceRes.r_hash });

  // Подписка на созданный инвойс
  createdInvoiceCall.on('data', async (currentInvoice) => {
    if (currentInvoice.state === 'OPEN') {
      // Здесь на клиент отправляется свойство currentInvoice.payment_request,
      // содержащее данные для оплаты, котрые будут отображаться в приложении
      // в виде QR-кода для кошелька Lightning

    } else if (currentInvoice.state === 'SETTLED') {
      // Здесь происходит запись операции в базу и отправка сокета на клиент,
      // когда оплата состоялась

    } else if (currentInvoice.state === 'CANCELED') {
      /* ... */
    } else {
      /* ... */
    }
  });
});

Пока я программировал микросервис, приехала камера. Теперь можно научиться получать с неё видео в браузере. Большинство IP-камер используют протокол RTSP, и вы можете просматривать поток только с помощью медиаплеера (такого как VLC, например). В браузерах нет встроенной поддержки RTSP-потоков, но передать туда видео, разумеется, возможно. В данной статье рассказывается какими способами это можно сделать.

Сперва я пробовал передавать стрим через встроенную функцию VLC. Поэксперементировав с кодеками даже удалось добиться маломальски меняющейся картинки в HTML-плеере.

vlc.exe rtsp://192.168.1.117/live/ch00_1 :network-caching=1000 :sout=#transcode{vcodec=theo,vb=1600,scale=1,acodec=none}:http{mux=ogg,dst=:8181/stream} :no-sout-rtp-sap :no-sout-standard-sap :sout-keep
<video controls autoplay muted>
  <source src="http://localhost:8181" type="video/ogg; codecs=theora" />
</video>

Однако это решение оказалось не кроссбраузерным и слегка тормознутым, к тому же VLC то и дело безосновательно вылетал, чем вызывал у меня бурю негодования. От него пришлось отказаться и я пошел по пути использования FFMPEG. Поискав среди npm-пакетов, нашёл вариант, который делает как раз то, что мне нужно.

Примерил это решение, и оно идеально подошло: у меня появился кроссбраузерный live-stream с вменяемой задержкой. Убрав из настроек обработку звука, удалось сократить эту задержку ещë больше. Однако и без минусов тут не обошлось: в пакете реализована неоптимальная подгрузка скрипта, которым обрабатывается видео на клиенте (к этому я вернусь позже). Уверен, в будущем можно сделать ещё лучше, но сейчас крайне доволен тем, чего удалось достичь. Двигаемся дальше.

Камнем преткновения стало создание кормушки. В качестве основы самого устройства сперва взят обычный диспенсер корма, и к нему придуман отпирающий механизм, распечатанный на 3D-принтере по примеру этой статьи.

Кормушка
Кормушка
Элементы отпираюшего механизма
Элементы отпираюшего механизма

Приводился в движение он моторчиком с редуктором из комплекта keystudio. Сама же плата Arduino управляется микросервисом device-api, тем же самым, который отвечает и за камеру.

Для работы с Arduino из-под Node.js используется пакет johny five.

import { Request, Response } from 'express';
import { Servo, Board } from 'johnny-five';

export const activateFeederHandler = (board: Board) =>
  (req: Request, res: Response) => {
      const servo = new Servo({
          pin: 9,
          range: [10, 57],
      });
      let i = 0;

      if (!board.isReady) {
          return res.sendStatus(500);
      }

      const feed = () => {
          setTimeout(() => {
              servo.sweep({
                  range: [45, 57],
                  interval: 50
              });

              board.wait(3000, () => {
                  servo.stop();
                  servo.max();

                  servo.sweep({
                      range: [25, 40],
                      interval: 50
                  });

                  board.wait(500, () => {
                      servo.stop();
                      servo.max();

                  });
              });
              i++;

          if (i < 1) {
            feed();
          }

          }, 0);
      };

      servo.max();
      feed();

      res.sendStatus(200);
  };
Устройство в работе
Устройство в работе

С виду всё выглядело жизнеспособно, но как оказалось первое впечатление обманчиво. Проблемой стало слипание корма, когда его слишком много. Устройство не подразумевало механизм перемешивания, а лишь только отпирания и запирания с лёгкой вибрацией. Этого достаточно на небольшом объёме корма, но на полной банке, увы — нет.

Доработать устройство оказалось затруднительно, и я стал искать другой вариант в виде готового решения. Может возникнуть вопрос, почему же я сразу так не сделал? А ответ прост: был уверен, что получится сделать самому, и что готовые решения не имеют открытого API, через который удастся управлять этой самой кормушкой.

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

Ага, значит всё-таки API не такой уж и закрытый. Не долго думая покупаю это устройство и приступаю сетевому реверс-инженирингу по примеру автора статьи.

Фэйл ждал на первом же шагу. Мобильное приложение отказалось сотрудничать с нашим регионом, поэтому проследить запросы с токеном и device id не предоставлялось возможным ????. Обмануть систему тяжело, ведь регион дополнительно проверяется через геолокацию телефона.

Беспроводное соединение на порядок эргономичнее, но не имея такой возможности я нашёл обходной путь с использованием транзистора, который замыкает и размыкает цепь, управляясь всё с той же Arduino. На данной модели кормушки есть физическая кнопка, которая активирует устройство при нажатии, заставляя его работать до тех пор, пока кнопка не будет отпущена. Именно туда я и подключил транзистор.

Схема подключения
Схема подключения

Элементы цепи:

  • Транзистор TIP120

  • Резистор 1 кОм

  • Диод 1N4004

Апгрейд микросхемы кормушки
Апгрейд микросхемы кормушки
Провода удалось аккуратно вывести через отверстие светового индикатора Wi-Fi
Провода удалось аккуратно вывести через отверстие светового индикатора Wi-Fi

В итоге я финализировал микросервис device-api, поменяв управление Arduino с моторчика на базу транзистора. Посылать сигнал к программируемому пину на заданное время — наверное самое простое, что там можно сделать.

import { Request, Response } from 'express';
import { Board, Led } from 'johnny-five';

export const activateFeederHandler = (board: Board) => {
    return (req: Request, res: Response) => {
        if (!board.isReady) {
            return res.sendStatus(500);
        }

        const base = new Led(9);

        // Посылаем сигнал на базу транзистора
        base.on();
        // Даём кормушке поработать 20 секунд и выключаем
        setTimeout(() => base.off(), 20000);
        res.sendStatus(200);
    };
};

История с девайсами завершена, осталось написать третий микросервис, который будет выступать в роли посредника между payment, device, базой. Он принимает ws-соединение с клиента и отдаёт все имеющиеся сообщения для чата при инициализации, а затем посылает сокет, если вдруг кто-то отправил новое сообщение или оплатил инвойс. Описывать его в деталях не вижу особого смысла.

Итак, бэкэнд и девайсы готовы, впереди самое интересное — клиентское приложение. Его я решил реализовать как SPA, а в качестве фреймворка выбрал React.js. Дизайн приложения был состряпан на коленке, лишь бы было. Но в целом получилось неплохо, как мне кажется.

UI
UI

Приложение состоит из чата и видеострима, плюс несколько страниц со статической информацией. Чат будет использовать websocket-соединение для отображения новых сообщений и анимированного уведомления пользователей, что их инвойс оплачен.
За отображение видео с камеры отвечает всё тот же пакет, но уже его клиентская часть.
Получение инвойса (currentInvoice.payment_request) для генерации QR-кода оплаты будет происходит путем отправки http-запроса на payment-api.

Сборка и тестирование

Начинаем сборку с настройки сети. В моем случае сеть организуется при помощи роутера и подключённого к нему 4G-модема. Для начала нужно купить статический IP-адрес, ведь для удобства настройки сервисов должен быть публичный, «белый» IP. Не отходя от кассы покупаем доменное имя и привязываем его к этому адресу.

Некоторые USB-модемы (мой именно такой) являются маршрутизатором с NAT и выдают себя основным шлюзом для роутера. Роутер же, в свою очередь, выдает себя основным шлюзом для конечных сетевых устройств. Отсюда необходимость открыть порты на обоих шлюзах. В шлюзе модема на IP-адрес роутера, в шлюзе роутера — на конечный адрес каждого сетевого устройства.

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

Это замедлило мой прогресс, но поискав версию прошивки поновее, я обновил её, попутно накатив новый веб-интерфейс (если кому интересно, использовал firmware 22.333.01.00 и web оболочку 17.100.18.03.143 mod 1.21). После обновления всё заработало: порты пробрасываются, сигнал идёт.

Отлично, переходим к другим устройствам. Собираем Raspeberry Pi, ставим операционку, Bitcoin Core и LND, включаем фаерволл, открываем необходимые для работы порты и переносим конфиги с виртуальной машины.

До установки в корпус палочка от дженги выполняла роль пассивного охлаждения
До установки в корпус палочка от дженги выполняла роль пассивного охлаждения

Даëм системе время на проверку и синхронизацию и убеждаемся, что всё работает.

Ceти BTC и Lightning повторно успещно синхронизированы
Ceти BTC и Lightning повторно успешно синхронизированы

Проделываем то же со вторым сервером: cтавим linux + node.js + mongodb и включаем фаерволл. Как выяснилось в процессе, ноутбук 2009-го года не совсем соответствует требованиям предъявляемыми программным обеспечением в 2023-ем (внезапно). В частности mongoDb от версии 5 и выше требует архитектуру процессора Intel не старше Sandy Bridge, из-за чего я долго не мог понять причину отказов при установке этой базы данных. Заработала только версия 4.4.18.

Настройка софта на application-сервере
Настройка софта на application-сервере

После установки операционной системы я настроил SSH для удобства дальнейшего взаимодействия. Далее ставлю git, спуливаю микросервисы и стартую их через PM2.

Микросервисы запущены и работают
Микросервисы запущены и работают

Хотя часть запросов между микросервисами будет происходить локально, есть и эндпойнты торчащие наружу (создание инвойса, ws-соединение). Идея оставить голый Node.js открытым во внешний мир не очень уж привлекательная по ряду причин, поэтому закрываю публичные эндпойнты с помощью nginx, реализуя таким образом реверс-прокси.

Делаем пару контрольных запросов из IDE на уже реальный IP, чтобы убедиться, что всё подключено правильно и работает.

Получение инвойса для создания QR-кода
Получение инвойса для создания QR-кода

Последним шагом готовим front-end. Устанавливаю HTTPS-сертификат с помощью certbot, настраиваю nginx под http2, а для отдачи статики завожу brotli. Далее запуливаю собранное приложение в одну из директорий nginx через scp, ввожу в адресную строку доменное имя и радуюсь тому, что в итоге всё получилось!

Результат сборки программной части
Результат сборки программной части

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

Результат сборки аппаратной части
Результат сборки аппаратной части

Предрелизная подготовка и релиз

Всё готово для релиза, но для удобства неплохо бы организовать CI/CD-pipeline, ведь не буду же я каждый раз заходить на сервер по SSH вручную чтобы подлить фиксы или новые фичи. Вся кодовая база лежит на Github, а там есть мощный встроенной инструмент под название actions. Github actions стартует linux машину, с которой можно пересылать собранный код на целевой сервер или подключаться к серверу для выполнения команд.

Работая с actions я использовал scp-action и ssh-action. Первая, в моём случае, прекрасно подходит для фронта (билд статики и отправка на сервер), второй — для бэка (тут я хожу на свой сервер, делаю git pull, собираю на месте микросервисы и перезапускаю PM2).

Можно было бы рассмотреть и вариант с Jenkins, но прошу не забывать технические характеристики моего сервера.

Что же касается касается клиентского приложения, то после проверки на PageSpeed Insights я увидел слегка удручающую картину.

Профилирование фронтенда
Профилирование фронтенда

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

Профилирование фронтенда
Профилирование фронтенда

Скриншоты взяты с десктопа. На мобильном устройстве первый параметр проседает немного больше, и это от части связано с неоптимальной загрузкой скрипта библиотекой для видеоплеера, — тот самый минус, который я вскользь упомянул выше. В будущем постараюсь придумать как улучшить и этот момент.

Послесловие

Процесс создания кормушки управляемой Bitcoin-платежами завершён, и мы можем подвести итог. Проект сформировался спонтанно от идеи изучить новую технологию до реализации реального устройства. Теперь остаётся найти желающих поставить кормушку у себя и применить её по назначению. Надеюсь всё пойдёт по плану, и за этим дело не станет.

Что же касается железа и софта, то в ближайшее время я займусь мелкими улучшениями, а если проект продвинется дальше, то обязательно обновлю железо и перепишу скрипты, завязанные на нём.

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

Спасибо всем, кто принял участие в создании и тестировании кормушки. И спасибо тем, кто дочитал эту статью до конца.

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


  1. Jennysin
    19.04.2023 11:05
    +2

    Осталось только подрубить интеграцию с Dogecoin и завести сиба-ину