Удаленное управление (Ferro-Remote)
-
Сразу прошу извинить, если стиль написания плохой. не писатель я совсем
Дело было вечером, делать было нечего. От нечего делать взял да и купил себе железку на базе ARM. На самом деле хотел построить на ней танк.
Ну а так как не хотелось пользовать всякие node.js и прочие готовые инструменты, решил немного повелосипедить. Так что про то, что "Есть же вот такая штука!" или на худой конец "ssh", я вкурсе. Велосипедил я Just For Fun
Тут еще один товарищ очень хороший озадачил идеей автоматизации парников его жены (биолог она, выращивает всякую экзотику, которой требуется много особых условий от температуры и влажности, до интенсивности освещения). Задача осложнялась тем, что хотел он сие поднять на своем сервере и автоматизировать оповещения от датчиков. Но топик не про это...Про эту систему с автополивом и нотификациями для алармов на сотовый, может быть напишу позже, если товарищ пустит меня с фотоаппаратом в его парники
В общем так родился проект, который я, недолго думая, назвал ferro-remote. Все исходники проекта можно взять тут
Проект состоит из 2 частей:
- agent - часть, работающая на стороне железки (малина, или другая). Агент собирается только под системы Linux;
- Client - часть, которая соединяется с агентом и может получить доступ к ресурсам (fs, gpio, i2c...) вышеозначенной железки. Клиент, вообще, это библиотека, на основе которой можно написать что-то свое. Вполне собирается под linux, windows и не вижу причин, почему бы ей не собраться под какую-нибудь MacOS. Для примера использования я начинал делать lua-client, который оказался полезен не только как пример, но и как вполне рабочий инструмент. На это примере я и собираюсь показать что можно сделать при помощи lua и ferro-remote
Агент.
Агент это один исполняемый бинарник, который запускается на стороне RPi (раз уж на сайте raspberrypi пишу), открывает один или несколько серверных точек и предоставляет доступ к:
- os: запуск консольной команды (вызов system)
- fs: доступ к файловой системе. Итерация содержимого директорий. Доступ к содержимому файлов (чтение/запись)
- gpio: доступ к пинам. Возвожность получения нотификаций об изменении состояния пина (разумеется для пинов, которые поддерживают данный механизм).
- i2c: доступ к шине
Вообще, чтоб не повторяться тут дам ссылку на ключи запуска агента. Когда есть время, наполняю wiki
А например...
тут напишу пару примеров работы
Кто не хочет сам собирать агента и клиента, если готовая сборка тут.
Там агент для малины, клиент для малины и клиент для windows. Сборки статические. Для малины нужна glibc 2.6, так что на старой прошивке работать не будет, сборка для windows не будет работать на XP, скорее всего, потому как собиралась на VS2013, которая не поддерживает XP. Скрипты будет одинаково работать как на клиенте Windows, так и на клиенте Linux.И так:
Запустим агента на стороне малины:
$ ./ferro_remote_agent -s 0.0.0.0:12345 -l- 2015-Aug-31 13:19:07.734228 [INF] [log] Started. 2015-Aug-31 13:19:07.734344 [INF] [lua] Started. 2015-Aug-31 13:19:07.734842 [INF] [fs] Started. 2015-Aug-31 13:19:07.735115 [INF] [gpio] Started 2015-Aug-31 13:19:07.735427 [INF] [i2c] Started. 2015-Aug-31 13:19:07.735619 [INF] [listener] tcp://0.0.0.0:12345 started 2015-Aug-31 13:19:07.735628 [INF] [listener] Started. 2015-Aug-31 13:19:07.735633 [INF] [main] Agent started.
агент откроет 1 сервер и будет выводить логи в текущую консоль.
А теперь я напишу скрипт, который покажет содержимое, например директории /home/data/pi
fs = fr.client.fs -- алиасы iter = fs.iterator function main(argv) local dir = "/home/data/pi" local i, err = iter.begin( dir ) if not err then while i:has_next( ) do local path = i:get( ) local stat = fs.stat( path ) print( path, stat.size, "bytes" ) i:next( ) end else print( err ) end end
Сохраню этот файл рядом с lua_client в dir.lua, например и выполню (малинка висит на 192.168.1.11):
$ ./lua_client -s 192.168.1.11:12345 -e dir.lua /home/data/pi/r.txt 0 bytes /home/data/pi/hello.txt 15 bytes /home/data/pi/img1.jpg 90540 bytes /home/data/pi/diff1.txt 15746 bytes
Все просто. Клиент подключился, экспортировал таблицы с вызовами в lua, исполнил скрипт. В скрипте работа происходит с удаленной системой, как с локальной.
Еще один пример - скачивание файла, чтоб показать что работа с удаленным файлом не отличается от работы с локальным:
function main( argv ) local path = argv[1] -- параметр первый - что скачать local out = argv[2] -- параметр второй - куда скачать if not path then return end if not out then out = "pulled.file" end local fs = fr.client.fs -- локальные local file = fs.file -- алиасы чтоб удобнее было local f, e = file.open( path, "rb" ) -- откроем удаленный файл (на малинке) local out, eout = io.open( out, "wb" ) -- локальный файл, куда будет писать if f and out then f:seek( 0, "end" ) -- определение размера print( "file size:", f:tell( ) ) -- просто для примера работы f:seek( 0 ) local d = f:read( ) -- читаем удаленный файл while d do -- пока он не кончился out:write( d ) -- пишем в локальный d = f:read( ) -- снова читаем удаленный end else print( "remote error:", e, "local error:", eout ) end end
исполним: (параметры в скрипт передаются ключами -p клиента)
$ ./lua_client -s 192.168.1.11:12345 -e file-pull.lua -p /home/data/pi/img1.jpg -p img.jpg file size: 90540 $ ls -la total 13224 drwxrwxr-x 3 nwnclv nwnclv 4096 авг. 31 14:14 . drwxrwxr-x 10 nwnclv nwnclv 4096 авг. 31 11:01 .. ................... -rw-rw-r-- 1 nwnclv nwnclv 1205 авг. 31 14:14 dir.lua -rw-rw-r-- 1 nwnclv nwnclv 90540 авг. 31 14:14 img.jpg -rwxrwxr-x 1 nwnclv nwnclv 3775064 авг. 31 13:46 lua_client ...................
Вот как-то так. Все довольно просто получилось.
Ну и раз уж в тегах стоит GPIO, пример с GPIO: Возмем схему из топика GPIO для чайников (часть 1)
Включить диод в этом случае можно примерно так:
function main( ) local g, e = fr.client.gpio.export( 3, "out" ) -- получим доступ к GPIO3 if not e then g:set( 0 ) -- установим значение в 0. диодик горит. else print( "export error:", e ) end end
Помимо этого можно отлавливать события с GPIO (изменения значения с 1 на 0 и наоборот) тут описал как
А еще клиент умеет таймер, умеет внутренние события, умеет работать с I2c пример работы с акселерометром mma7660fc. Умеет работать с консолью
Думаю, напишу еще примеров в следующих блогах. Если кому-то пригодится, буду рад замечаниями и предложениям.