Электрокарнизу Akko ac-72e по rs485

Добрый день. Купил Электрокарниз. Он работает по rs485, но не modbus. Во вложении спецификация на протокол. Подключался через serial_tool. Все работает по спеке. Шторы открываются, закрываются, положение считывается.
Как вы посоветуете подключить карниз? Возможно ли определить как виртуальное устройство? Или можно определить шаблон? Можете ли вы добавить этот карниз в поддерживаемые устройства?
Спасибо заранее.
Ps. Порядок вложений обратный.

Uploading: Screenshot_20190215_194607_com.google.android.apps.docs.jpg…

Похоже для управления используется Modbus ASCII.
Хорошо уже, что работает!
Уточните пожалуйста модель карниза.
По поиску Akko ac-72e ничего не находится.

На сайте продавца он называется “Электрокарниз AM82TV с управлением по радио, RS-485 и пофазно”
В спецификации, на протокол было указано “мотор ac-72e”

Пока сделал через виртуальное устройство, которое вызывает perl скрипт, perl программа на вход принимает позицию штор и отправляет запрос в серийный порт. Позже выложу настройки и код.
Все заработало. Из минусов- виртуальное устройство пока не получает информацию об изменении положения штор, если их двигают не через wirenboard.

Вы планируете поддержать этот протокол?

costa, добрый день! к сожалению, поддержку вашего устройства мы вряд ли сможем реализовать.
Сложно разглядеть на скриншотах, можно ли получать ответную информацию о положении устройства: может, дадите ссылку на документацию?

После включения карниза отправил команду 55 00 00 02 00 02 12 34 50 7F - установка адреса устройства в “12 34” (по умолчанию был FE FE, судя по спеке, но я не проверял).
Соответственно CRC16 нужно будет пересчитать (я пользовался https://crccalc.com/), если будете использовать адрес по умолчанию.

Далее настроил виртуальное устройство в wirenboard:

файл /etc/wb-rules/wb-rules

defineVirtualDevice("akko",{
    title: "Шторы",
    cells:{
        position: {
            type: "range",
            value: 100,
            min: 0,
            max: 100,
        },
    }
});

defineRule("set_position", {
    whenChanged: "akko/position",
    then: function (newValue, devName, cellName){
        runShellCommand("./etc/wb-rules/akko.perl "+newValue);
    }
});

И perl скрипт, который устанавливает положение штор c шагом в 10%, например установить в 20 процентов:

./akko.perl 20

или считывает текущее положение штор - в ответе вернется число процентов:

./akko.perl

искать функции по расчету CRC16 для modbus мне было лень, поэтому команды все захардкодил.

файл /etc/wb-rules/akko.perl

#!/usr/bin/perl

use Device::SerialPort;
my $port = Device::SerialPort->new("/dev/ttyRS485-2");

$port->baudrate(9600); 
$port->databits(8);
$port->parity("none");
$port->stopbits(1);

$output = "";
if ($ARGV[0]==100) # команда Установить положение эл.карниза в 100% (0x64)
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x64,0x49,0x06);
    }
elsif ($ARGV[0]>=90) # .. в 90% (0x5A)
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x5A,0xC8,0xD6);
    }
elsif ($ARGV[0]>=80) # .. в 80%
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x50,0x48,0xD1);
    }
elsif ($ARGV[0]>=70) # .. в 70%
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x46,0xC9,0x1F);
    }
elsif ($ARGV[0]>=60) # .. в 60%
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x3C,0x48,0xFC);
    }
elsif ($ARGV[0]>=50)
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x32,0xC9,0x38);
    }
elsif ($ARGV[0]>=40)
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x28,0x48,0xF3);
    }
elsif ($ARGV[0]>=30)
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x1E,0xC8,0xE5);
    }
elsif ($ARGV[0]>=20)
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x14,0x48,0xE2);
    }
elsif ($ARGV[0]>=10) # .. в 10%
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x0A,0xC8,0xEA);
    }
elsif (@ARGV) # .. в 0%
    {
        $output = pack("C*",0x55,0x12,0x34,0x03,0x04,0x00,0x48,0xed);
    }
else # считать текущее положение эл.карниза
    {
        $output = pack("C*",0x55,0x12,0x34,0x01,0x02,0x01,0x2B,0x4D);
    }

$port->write($output);
sleep(1);
$in = $port->read("100");
$per = substr($in,5,1);
printf ("%s\n",ord($per)); # вывести на экран ответ от эл.карниза

$port->close;

Да, получать можно.
В ответ на команду “0x55,0x12,0x34,0x01,0x02,0x01,0x2B,0x4D”

55 - фиксированный префикс
12 34  - адрес устройства 
01 - получить данные
02 - положение карниза
01 - я не понял что это )
2B 4D - CRC16/modbus с обратным расположением байтов

В ответном сообщении (такое же по структуре) 6 байте вернет положение карниза в процентах.


Формат команды по установке положения карниза в 50%:
Команда 0x55,0x12,0x34,0x03,0x04,0x32,0xC9,0x38

55 - фиксированный префикс
12 34  - адрес устройства 
03 - отправить команду
04 - положение карниза
32 - число 50 в hex
С9 38 - CRC16/modbus с обратным расположением байтов

В ответном сообщении (такое же по структуре) 6 байте вернет положение карниза в процентах.


Подскажите, как можно сделать через виртуальные устройства в правилах (или другими штатными средствами wirenboard):

  • периодический вызов perl программы (которая возвращает на stdout текущее положение эл. карниза)
  • считывание этого значения
  • запись в topic

NB: могу конечно сделать вызов по cron скрипта, который будет писать полученное значение в топик, но как-то хочется родными средствами wirenboard’а это решить.

costa, в движке есть cron-правила, тут подробнее: https://github.com/contactless/wb-rules
При их использовании, правда, некоторые пользователи наблюдали падение движка правил.

Пытаюсь сделать нечто подобное, но не выходит. Для начала задача: 6 электрокарнизов которые открываю через панель иридиума кнопками открыть, закрыть, стоп. Карниз в рабочем состоянии это 100%, команды по 485 принимает и отрабатывает (команды отправляли с компа через преобразователь в 485)

Вопросы:

  1. perl скрипт
    где должен размещаться данный файл? Разместил его в /etc/wb-rules/wb-rules с именем sunflower.perl это верно?
  2. скрипт переписал по наитию, он для моего случае написан верно?
#!/usr/bin/perl

use Device::SerialPort;
my $port = Device::SerialPort->new("/dev/ttyRS485-2");

$port->baudrate(9600); 
$port->databits(8);
$port->parity("none");
$port->stopbits(1);

$output = "";
if ($ARGV[0]=="shade1_open") # команда shade1_open
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x01,0xB9,0x24); #55FEFE0301B924 
    }
elsif ($ARGV[0]=="shade1_close") # команда shade1_close
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x02,0xF9,0x25); #55FEFE0302F925
    }
elsif ($ARGV[0]=="shade1_stop") #  команда shade1_stop
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x03,0x38,0xE5);#55FEFE030338E5
    }

$port->write($output);
sleep(1);
$in = $port->read("100");
$per = substr($in,5,1);
printf ("%s\n",ord($per)); # вывести на экран ответ от эл.карниза

$port->close;
  1. написал вот такой вот скрипт для WB. Вывожу log(), мне недавно посоветовали бывалые - но где смотреть вывод? В консоли пусто, в var\log\messages пусто, как править код если ни черта не понимаешь как эта шайтан машина работает?
defineVirtualDevice("shade",{
    title: "shade",
    cells:{
        "shade1_open": {
            type: "switch",
            value: false,
        },
        "shade1_close": {
            type: "switch",
            value: false,
        },
        "shade1_stop": {
            type: "switch",
            value: false,
        },
        "shade2_open": {
            type: "switch",
            value: false,
        },
        "shade2_close": {
            type: "switch",
            value: false,
        },
        "shade2_stop": {
            type: "switch",
            value: false,
        },
        "shade3_open": {
            type: "switch",
            value: false,
        },
        "shade3_close": {
            type: "switch",
            value: false,
        },
        "shade3_stop": {
            type: "switch",
            value: false,
        },
        "shade4_open": {
            type: "switch",
            value: false,
        },
        "shade4_close": {
            type: "switch",
            value: false,
        },
        "shade4_stop": {
            type: "switch",
            value: false,
        },
        "shade5_open": {
            type: "switch",
            value: false,
        },
        "shade5_close": {
            type: "switch",
            value: false,
        },
        "shade5_stop": {
            type: "switch",
            value: false,
        },
        "shade6_open": {
            type: "switch",
            value: false,
        },
        "shade6_close": {
            type: "switch",
            value: false,
        },
        "shade6_stop": {
            type: "switch",
            value: false,
        },
    }
});

function sunflower(name, device_control) {
defineRule(name, { //название правила
  whenChanged: device_control,
  then: function (newValue, devName, cellName) { //выполняй следующие действия
    log("./etc/wb-rules/sunflower.perl "+cellName);  
     runShellCommand("./etc/wb-rules/sunflower.perl "+cellName);
    
  	 }
});
}

sunflower("shade1_open", "shade/shade1_open");
sunflower("shade1_close", "shade/shade1_close");
sunflower("shade1_stop", "shade/shade1_stop");

Сделал аналогично как автор описал выше, через WUI меняю положение шторы, но привод не работает. Может быть как-то хитро надо запускать perl скрипты? С чего начать диагностику?

Сделал аналогично как автор описал выше, через WUI меняю положение шторы, но привод не работает. Может быть как-то хитро надо запускать perl скрипты? С чего начать диагностику?

Запускаю из консоли и вижу что скрипт не стартует.
root@wirenboard-A3PW5UD7:~# ./akko.perl 20
-bash: ./akko.perl: No such file or directory

Побывал этот скрипт размещать:
/usr/bin/ также не видит файл
/mnt/data/root в ответ получаю отсутствует доступ.

Так как правильно запустить скрипт perl и где его хранить?

Задайте права на исполнение

chmod +x /usr/bin/akko.perl

Запустите командой

/usr/bin/akko.perl 20

Виталий на тебя вся надежда :slight_smile:
Сделал как посоветовал, получил следующий ответ:

Can’t locate Device/SerialPort.pm in @INC (you may need to install the Device::SerialPort module) (@INC contains: /etc/perl /usr/local/lib/arm-linux-gnueabihf/perl/5.24.1 /usr/local/share/perl/5.24.1 /usr/lib/arm-linux-gnueabihf/perl5/5.24 /usr/share/perl5 /usr/lib/arm-linux-gnueabihf/perl/5.24 /usr/share/perl/5.24 /usr/local/lib/site_perl /usr/lib/arm-linux-gnueabihf/perl-base) at /usr/bin/akko.perl line 3.
BEGIN failed–compilation aborted at /usr/bin/akko.perl line 3.

Порт 485-2 у меня есть, как и у всех счастливых обладателей WB6.5, на него сконфигурирован ряд устройств, но в данный момент я на шине оставил только 1 карниз

“Из коробки” модуль

не идет вместе с перлом. Его надо, как обычно, доустановить:
perl -MCPAN -e 'install Device::SerialPort'
Возможно, вам перед этим понадобится установить пакет build-essential, чтобы модуль скомпилировался.

выполнил указанную команду, что-то установилось, со всем согласился. Лог:

root@wirenboard-A3PW5UD7:~# perl -MCPAN -e ‘install Device::SerialPort’

CPAN.pm requires configuration, but most of it can be done automatically.
If you answer ‘no’ below, you will enter an interactive dialog for each
configuration option instead.

Would you like to configure as much as possible automatically? [yes] y

ALERT: ‘make’ is an essential tool for building perl Modules.
Please make sure you have ‘make’ (or some equivalent) working.

Autoconfiguration complete.

commit: wrote ‘/root/.cpan/CPAN/MyConfig.pm’

You can re-run configuration any time with ‘o conf init’ in the CPAN shell
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/01mailrc.txt.gz
Reading ‘/root/.cpan/sources/authors/01mailrc.txt.gz’
…DONE
Fetching with HTTP::Tiny:
http://www.cpan.org/modules/02packages.details.txt.gz
Reading ‘/root/.cpan/sources/modules/02packages.details.txt.gz’

Database was generated on Thu, 16 May 2019 14:17:03 GMT
HTTP::Date not available

New CPAN.pm version (v2.26) available.
[Currently running version is v2.1101]
You might want to try
install CPAN
reload cpan
to both upgrade CPAN.pm and run the new version without leaving
the current session.

…DONE
Fetching with HTTP::Tiny:
http://www.cpan.org/modules/03modlist.data.gz
Reading ‘/root/.cpan/sources/modules/03modlist.data.gz’
DONE
Writing /root/.cpan/Metadata
Running install for module ‘Device::SerialPort’
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/id/C/CO/COOK/Device-SerialPort-1.04.tar.gz
Fetching with HTTP::Tiny:
http://www.cpan.org/authors/id/C/CO/COOK/CHECKSUMS
Checksum for /root/.cpan/sources/authors/id/C/CO/COOK/Device-SerialPort-1.04.tar.gz ok
‘YAML’ not installed, will not store persistent state
Configuring C/CO/COOK/Device-SerialPort-1.04.tar.gz with Makefile.PL
To enable serial port tests, use:
perl Makefile.PL TESTPORT=
where is a specific port or ‘auto’ to autodetect.
Running ./configure …
checking for gcc… no
checking for cc… cc
checking for C compiler default output file name…
configure: error: C compiler cannot create executables
See `config.log’ for more details.
The ‘configure’ script didn’t like something. It should have told you
what went wrong, but you can check ‘config.log’ for more details.
Warning: No success on command[/usr/bin/perl Makefile.PL INSTALLDIRS=site]
COOK/Device-SerialPort-1.04.tar.gz
/usr/bin/perl Makefile.PL INSTALLDIRS=site – NOT OK
root@wirenboard-A3PW5UD7:~#
root@wirenboard-A3PW5UD7:~# /usr/bin/akko.perl 20
Can’t locate Device/SerialPort.pm in @INC (you may need to install the Device::SerialPort module) (@INC contains: /etc/perl /usr/local/lib/arm-linux-gnueabihf/perl/5.24.1 /usr/local/share/perl/5.24.1 /usr/lib/arm-linux-gnueabihf/perl5/5.24 /usr/share/perl5 /usr/lib/arm-linux-gnueabihf/perl/5.24 /usr/share/perl/5.24 /usr/local/lib/site_perl /usr/lib/arm-linux-gnueabihf/perl-base) at /usr/bin/akko.perl line 3.
BEGIN failed–compilation aborted at /usr/bin/akko.perl line 3.

Чтобы установить пакет нужно выполнить команду указанную ниже?
sudo aptitude install build-essential ?

Да, попробуйте, должно получиться.

root@wirenboard-A3PW5UD7:~# sudo aptitude install build-essential
-bash: sudo: command not found

Выполните просто
apt-get install build-essential

Понимаю что вопрос вышел за рамки WB, но мне и другим пользователям было бы полезно разобраться как управлять электрокарнизами по RS485, тем более что у всех аналогичное решение (akko, dooya, sunflower и т.д.) подозреваю что везде стоит двигатель dooya в перечисленных брендах.
Напомню скрипт:

#!/usr/bin/perl

use Device::SerialPort;
my $port = Device::SerialPort->new("/dev/ttyRS485-2");

$port->baudrate(9600); 
$port->databits(8);
$port->parity("none");
$port->stopbits(1);

$output = "";
if ($ARGV[0]==100) # команда Установить положение эл.карниза в 100% (0x64), тут широкофещательный адрес 0000
    {
        $output = pack("C*",0x55,0x00,0x00,0x03,0x04,0x64,0x35,0xFF);
    }
elsif ($ARGV[0]>=90) # .. в 90% (0x5A) далее адрес FEFE
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x5A,0x66,0xD9);
    }
elsif ($ARGV[0]>=80) # .. в 80%
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x50,0xE6,0xDE);
    }
elsif ($ARGV[0]>=70) # .. в 70%
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x46,0x67,0x10);
    }
elsif ($ARGV[0]>=60) # .. в 60%
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x3C,0xE6,0xF3);
    }
elsif ($ARGV[0]>=50)
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x32,0x67,0x37);
    }
elsif ($ARGV[0]>=40)
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x28,0xE6,0xFC);
    }
elsif ($ARGV[0]>=30)
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x1E,0x66,0xEA);
    }
elsif ($ARGV[0]>=20)
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x14,0xE6,0xED);
    }
elsif ($ARGV[0]>=10) # .. в 10%
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x0A,0x66,0xE5);
    }
elsif (@ARGV) # .. в 0%
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x03,0x04,0x00,0xE6,0xE2);
    }
else # считать текущее положение эл.карниза
    {
        $output = pack("C*",0x55,0xFE,0xFE,0x01,0x02,0x01,0x85,0x42);
    }

$port->write($output);
sleep(1);
$in = $port->read("100");
$per = substr($in,5,1);
printf ("%s\n",ord($per)); # вывести на экран ответ от эл.карниза

$port->close;

Скрипт запустил, но вот беда - он мне на все чтобы я ему не посылал возвращает положение двигателя и оно равно 0, т.е. проходит все условия скрипта perl и не срабатывает.
Как буд-то скрипт не видит аргументов которые ему даю.

root@wirenboard-A3PW5UD7:~# /usr/bin/akko.perl 20
0
root@wirenboard-A3PW5UD7:~# /usr/bin/akko.perl 100
0
root@wirenboard-A3PW5UD7:~# /usr/bin/akko.perl 35
0
root@wirenboard-A3PW5UD7:~# /usr/bin/akko.perl -35
0