Как-то я рассказывал о своем pet-проекте. В нем контроллеры ESP8266 управляются через Интернет. Пользователь создает программу и сохраняет ее в облаке. Контроллеры периодически ходят в него и забирают новую программу, которую исполняют.
Недавно вышла статья “Картинка, которая одновременно является кодом на Javascript” где автор “достает кролика из шляпы”. Забавно, но в своем проекте я делал что-то отдаленно похожее. Учитывая то, что тема оказалась интересной, решил поделиться и своим опытом в “фокусах”.
Как выше упоминалось, контроллеры с определенным интервалом ходят в облако, чтобы забрать свежую программу. Выглядит транспорт примерно так:
Голубые стрелки демонстрируют путь передачи программы на контроллер.
Проблема такой схемы заключается в том, что есть заметные задержки между сохранением программы в облаке и непосредственным исполнением ее контроллером. Задержка зависит от настроек облака и обычно составляет около 10 секунд.
Это не криминально для загрузки программы долгосрочного исполнения. Но при настройке и калибровке контроллеров возникает необходимость менять программу гораздо чаще. В идеале, она должна меняться online.
Чтобы обойти это ограничение, была реализована такая схема:
Теперь контроллер передает свой локальный IP облаку (зеленые стрелки). Этот IP имеет смысл только в контексте локальной сети. Но, FrontEnd запускается как раз в ней. И теоретически, может выполнить http запрос непосредственно к контроллеру (розовая стрелка).
К сожалению, эта схема не работает без “магии”. Очередная проблема в том, что FrontEnd запущен под https а контроллеры в локальной сети не могут себе это позволить. Они работают по http. И возникает ошибка “Mixed Content”.
Познакомиться детально с проблемой можно тут и тут.
Но если бы это был тупик, статья бы не появилась. Обратите внимание, что загружаемый контент делится на два типа: активный и пассивный. К пассивному контенту отношение браузеров более лояльное. Например, можно встроить картинку с http сайта в https сайт. Проверено на Chrome (76.0.3809.132) и Firefox (80.0.1). Думаю, вы уже понимаете на что я намекаю.
Магия заключается в том, что вместо запросов через XMLHttpRequest, можно обойтись средствами пассивного контента. Для этого достаточно в тег img установить src с GET параметрами. В моем случае это выглядит так:
<img src=”http://192.168.0.33/stdin?raw=$LTSTL,10,10,19840,80,100,70,40,20*5f”>
И чудесным образом получилось достичь желаемого. FrontEnd смог в режиме реального времени отсылать на контроллеры в локальной сети команды управления. Более того, использование PWA позволило создать offline приложение, которое не требовало связи с Интернет. Условно, конечно.
Видео-демонстратор. Происходит управление спектром светильника в реальном времени:
Недостаток технологии заключалась в том, что ответ от контроллера не возвращается в классическом понимании. Но и тут есть выходы:
Во-первых, результатом ответа может быть успех или провал. Т.е. код ответа от контроллера выраженный в поведении img. Согласен, весьма посредственное решение. Но в моем случае этого достаточно — необходимо просто знать был выполнен запрос или нет.
Во-вторых, картинка возвращается с характеристиками — размером. В них можно передавать закодированный результат. Сложнее, но надежнее.
В-третьих, картинка может иметь графическое кодирование. Его может парсить FrontEnd. К сожалению, img не умеет отдавать бинарные данные самой картинки. Придется сначала вывести ее на canvas, а затем декодировать.
Последний вариант, который я рассматривал — redirect на сайт облака с параметрами ответа. Т.е. картинка запрашивается с локального IP контроллера, тот получает параметры GET и выполняет программу. В ответ он перенаправляет запрос на сайт облака. В редиректе содержатся ответ контроллера как GET параметры. Облако парсит ответ и передает фронту.
Задача весьма специфичная. Надеюсь мой опыт окажется кому-то полезным.
Alexufo
Вы изобрели jsonp
На localhost вроде можно делать ajax запросы с https на http, сначала было нельзя, а лет 5 назад стало можно, на сколько я помню.
rpiontik Автор
Специально перепроверил. Вы неправы.
При попытке встроить скрипт в https сайт и http сайта контент блокируется. Это можно проверить прям тут в консоле разработчика:
Результат:
Статья не про localhost. А про локальную сеть. И Вы путаете лояльность браузеров к самовыпущеным сертификатам на localhost.
Alexufo
А, верно, там обход кроссдомена, а не переход на незащищенный коннект. Суть примерно такая же, передавать по разрешенным запросам добавочную инфу в get параметрах, потому попутал.
rpiontik Автор
Ну суть та же, но контекст совсем иной. Конечно, фокус с встраиванием параметров в src далеко не нов. Да и не фокус вообще.
В моем проекте с IoT проблема с шифрованием локального трафика прям остро стоит. К сожалению, просто невозможно выпустить сертификат на локальные домены. Раньше такое было, теперь нет. И приходится извращаться.
Самовыпущенные сертификаты, даже для локальной сети, вызывают у барузеров истерику. И применяться не могут. По классику — голь ны выдумки хитра.
Alexufo
А зачем вам фронтент вообще? Только управлять устройством в локалке? Открыл сайт и получил доступ к устройству? Выходит без интернета нет сайта и не настроить устройства?
Тут лучше использовать свой клиент, чтобы не упираться в ограничения публичных браузеров. Наверняка электрон может не рубить http запросы и работать будет в офлайне.
Как происходит привязка устройств? каким образом пользователь должен знать какие у девайсов ip локальные?
rpiontik Автор
Если кратко — ресурсов у ESP8266 нет. Их нет даже на реализацию https. Более подробно в моей статье про этот проект
Свой, нативный клиент не вариант для всех платформ. Я не имею таких ресурсов. Вынужден идти по пути универсального решения — WEB.
Всякие кодровы, вуенэтив и т.п. не рассматриваю по причине глючности. И потому, что как только я выхожу за рамки функций из примеров, начинаются костыли еще похлеще выше описанных.
Обратите внимание, что:
1. Все работает;
2. Это не потребовало от меня ни инфраструктуры, ни каких-то существенных затрат на разработку софта.
Alexufo
Как привязка устройств происходит? как адреса устройств прописываются для управления?
rpiontik Автор
О… это отдельная песня. Чуть позже отпишу. Требует много букв.
Alexufo
Вот тут и кроется с моей точки зрения корень остальных проблем. Если для себя то ок, пингуй локалку. Привязывай роутером статические адреса по mac-у. Чтобы не убегало. Это все легко, когда ты разбираешься примерно как устроены сети. А вот если масштабировать для потребителя, то увы. Придется устройству самостоятельно себя регистрировать в облаке и сообщать свой локальный адрес, если не хотеть общаться только онлайн. Много проблем с NAT и… выходит так что рабочее решение либо все через интернет с авторизацией по https или на каждое устройтсво свой клиент, который прошивку будет заливать уметь сам.
Хорошая аналогия с ip камерами, они работают в локалке, которую приложение умеет сканировать. Вероятно по порту вещания (rtsp) пробить подсеть можно быстро. Но как это точно реализовано не знаю.
Я смотрю, что есть для IoT еще протокол для общения MQTT. Есть реализация для node.js значит можно проксировать фронтенд. не смотрели что за зверь? Да, будет больше софта но архитектурно может быть коректнее.