Как-то я рассказывал о своем 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 параметры. Облако парсит ответ и передает фронту.


Задача весьма специфичная. Надеюсь мой опыт окажется кому-то полезным.