Удаленное управление.

Надо что-то тут написать, а то совсем сайт вымер.

Сразу прошу извинить, если стиль написания плохой. не писатель я совсем :)

Дело было вечером, делать было нечего. От нечего делать взял да и купил себе железку на базе ARM. На самом деле хотел построить на ней танк.
Ну а так как не хотелось пользовать всякие node.js и прочие готовые инструменты, решил немного повелосипедить. Так что про то, что «Есть же вот такая штука!» или на худой конец «ssh», я вкурсе. Велосипедил я Just For Fun

Тут еще один товарищ очень хороший озадачил идеей автоматизации парников его жены (биолог она, выращивает всякую экзотику, которой требуется много особых условий от температуры и влажности, до интенсивности освещения). Задача осложнялась тем, что хотел он сие поднять на своем сервере и автоматизировать оповещения от датчиков. Но топик не про это… Про эту систему с автополивом и нотификациями для алармов на сотовый, может быть напишу позже, если товарищ пустит меня с фотоаппаратом в его парники :D
В общем так родился проект, который я, недолго думая, назвал 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. Умеет работать с консолью

Думаю, напишу еще примеров в следующих блогах. Если кому-то пригодится, буду рад замечаниями и предложениям.
  • 0

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

0
Очень интересно! Еще один способ управления Малиной удаленно.
Интересно было бы почитать сравнения способов удаленного управления Малиной, а конкретно GPIO.
Единственное что останавливает меня от исполнения всего этого, базовое знание Pascal да JavaScript (
P.S.
А сайт то действительно вымер…
P.P.S.
Пиши пожалуйста еще)
0
ИМХО: Спорная вещь с точки зрения целесообразности такого управления для RPi. Она ведь (RPi) может выдавать вполне себе визуальный WEB-интерфейс, а это универсально для клиента. Такие интерфейсы для микроконтроллеров, а не для компьютера со своей вполне полноценной ОС. Но как пример для обучения — ОТЛИЧНО. Автору — респект!
P.S. Не в тему, но написать бы как про свою «борьбу» на RPi с постоянно падающим GSM-оператором 3G. Не писатель я ни разу, да и времени пока нет. Может вот зима настанет…
0
Я тоже не писатель =) Пишу вот в свой блог, чтоб было.
У меня, кста, тож почему-то с 3G какая-то хрень на малине.
комментарий был удален
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.