Здравствуйте.
Можем отправить актуальную версию привода для экспериментов.
О, было бы здорово, если вы наладите внутреннее общение с производителем и организуете поддержку
@BrainRoot Андрей, возьмете в работу?
Технический специалист от Onviz Андрей готов предоставить самую популярную модель бренда и быть на связи для выпуска официального шаблона для wirenboard.
думаю не я один в этом заинтересован
Добрый день.
Есть ли официальное описание протокола?
Он один для любых устройств бренда? Я видел как минимум две реализации, нам не особо интересно писать под сложноидентифицируемые по отличиям устройства.
Проверен ли скрипт выше в этой теме?
Доброго дня!
и нет проблемы с инверсией?
сейчас установил еще один мотор от Onviz и проблема та же - инверсия самопроизвольно включается при управлении по RS
У меня проблема с инверсией стабильно есть. Сама скачет. Что может на это влиять?
Опрашиваю мотор на предмет инверсии по командам из инструкции от Onviz, а ответ на запрос инверсии каждый раз отличается (включена- выключена)
>> 55 01 01 01 03 01 A0 D2
<< 55 01 01 01 01 00 60 72
<< 55 01 01 01 01 01 A1 B2
Остальное работает
Пожалуйста опишите что именно (какую команду) отправляете. Какого результата ожидаете и чем получаемый отличается от ожидаемого.
Сейчас - совершенно непонятно.
То есть описываете поведение которое требует, как минимум, вдумчивого анализа обмена с устройством несколькими словами.
Если вы используете привод, выпущенный под брендом Onviz - то даже если на нем указана идентичная модель - нельзя сказать что протокол совершенно точно такой же.
Я вот тут задавал вопрос:
Мы точно не будем (официально) поддерживать устройства, которые могут иметь разные протоколы без возможности их идентифицировать.
Вот это - вполне хорошее и годное описание.
А почему ответа - два?
Привод на шине один?
И - какое именно описание протокола используете?
Через команды для этой модели инверсию не получилось сходу установить
Монтажники устанавливали инверсию с пульта
Пользовательский путь такой:
- Подключаем к мотору питание
- Подключаем к мотору штатный радио-пульт
- Гоняем мотор в крайние положения. Это необходимо чтобы он запомнил крайние значения и можно было выставить % открытия
- Подключаем шину RS. Три провода A, B, GND
- Добавляем мотор в WB через шаблон Dooya
- Присваиваем через serial_tool мотору адрес и проверяем что мотор выполняет команды. В моем случае адрес 0101, команды открыть и стоп
serial_tool -b 9600 -p N -d 8 -s 1 -t 1 /dev/ttyRS485-1
>> 55 00 00 02 00 02 01 01 9D 58
<< 55 FE FE 04 01 BB 14 55 01 01 02 00 02 10 23
>> 5501010301B900
<< 55 01 01 03 01 B9 00
>> 550101030338C1
<< 55 01 01 03 03 38 C1
^^^ до этого места все адекватно и предсказуемо
7. Смотрим на мотор в разделе “устройства”. Кнопки есть, кнопки работают.
8. Видим что с инверсией что-то не то. Красная… Если ей выставить время опроса в порядке очереди, то начинает скакать “вкл-выкл” несколько раз в секунду. Соответственно нажимая кнопку “открыть”, потом “стоп”, потом снова “открыть” получим что штора поедет в одну сторону, потом в другую.
Вот пунктом 8 полученный опыт и отличается от ожидаемого
Вот это?
Вы уже отвечали на подобный вопрос в июле:
Но после этого меня смутил ответ от Flagman:
Решил попробовать еще раз.
Привод один. Запрос направляю один и тот же, ответ получаю разный.
Да, именно ппро это я и говорю. Судя по той документации - протокол отличается от dooya.
Для примера:
И при ручной отправке:
55 01 01 01 03 01 A0 D2
01 - читать.
03 - “направление”
Если верить документации - то должно возвращаться какое-то значение. Одно и тоже (ведь между запросами оно ничем не меняется). А возвращается - разное.
Ну, то есть уже на этом моменте.
Возможно - это другая партия приводов с той же маркировкой.
Но с другими внутренностями. И да, такое уже видел.

Привод один. Запрос направляю один и тот же, ответ получаю разный.
Ну нельзя делать поддержку устройств без полного описания его работы.
Для того чтобы запустить устройство - начните с того скрипта, который выше в этой теме. Попробуйте реализовать в нем известный и работающий функционал.
Для начала - попробуйте просто получить текущее положение.
Зафиксируйте этот ответ как РЕШЕНИЕ вопроса.
Мотор для раздвижных штор ONVIZ MR-2234F
Пункт 1. Их действительно два.
Очень похожи и внутри и снаружи. Шильдик на них клеят один.
Справа Dooya DT82
Слева модификация, которая прошивкой очень похожа на Dooya DT82.
Если вы столкнулись с тем, что мотор ONVIZ MR-2234F при использовании шаблона от Dooya DT82 постоянно переключает инверсию - значит у вас мотор, который на фото слева.
Пункт 2.
Для WB используйте шаблон WB config-Onviz.json (2,8 КБ)
Скопировать в папку /etc/wb-mqtt-serial.conf.d/templates
Пункт 3.
В настройках WB выставить параметры
Опрос инверсии не включать
Пункт 4.
Для СХ используйте шаблон SH config-Onviz.json (2,5 КБ)
Скопировать в папку /mnt/data/makesimple/.SprutHub/data/Templates/MQTT/Custom
Пункт 5.
При необходимости можно включить инверсию на моторе:
- Короткое нажатие на кнопку
- Нажать и удерживать кнопку пока мотор не дернется.
Благодарю за помощь в решении вопроса @Onviz
Ковыряюсь с вашим скриптом, не могу понять почему, если dataBlind = 0x02 , то вываливается ошибка
ECMAScript error: TypeError: invalid base value
duk_hobject_props.c:2000
anon /etc/wb-rules/Onviz.js:72 preventsyield
//Путь к RPC
var pathRPC = “/rpc/v1/wb-mqtt-serial/port/Load/”;function createBlind(NameBlind, portBlind, speedPortBlind, pariryBlid, stopBitBlind, blindCh_L, blindCh_H){
//Создаем виртуальное устройство
makeNewVirtualControl(NameBlind, “position”, {type: “range”, value: 0, min: 0, max: 200, readonly: false});
makeNewVirtualControl(NameBlind, “position_in”, {type: “range”, value: 0, min: 0, max: 200, readonly: false});
// кнопка “Открыть” (работает)
makeNewVirtualControl(NameBlind, “open”, {type: “pushbutton”, readonly: false});
// кнопка “Стоп”(Работает)
makeNewVirtualControl(NameBlind, “Stop”, {type: “pushbutton”, readonly: false});
// кнопка “Закрыть” (работает)
makeNewVirtualControl(NameBlind, “close”, {type: “pushbutton”, readonly: false});
// Активность мотора (1 - вращается)
makeNewVirtualControl(NameBlind, “MotorRun”, {type: “switch”, readonly: true});
// временный для отладки
makeNewVirtualControl(NameBlind, “reply”, {type: “text”, value: “”, readonly: false});//open:
defineRule(NameBlind+“_rule_open”,{
whenChanged: NameBlind+“/open”,
then: function () {
log.info(NameBlind+“_open”)
//Формируем запрос 0a dd
var req = blindRequestMsg(blindCh_L, blindCh_H, 0x03, 0x01);
log.info(“open=”, req)
//Вызовем запрос
requestRPC(portBlind, speedPortBlind, pariryBlid, stopBitBlind, NameBlind, 1, “HEX”, req, 0 );
}
});
//Stop:
defineRule(NameBlind+“_rule_Stop”,{
whenChanged: NameBlind+“/Stop”,
then: function () {
//Формируем запрос 0a 0d
var req = blindRequestMsg(blindCh_L, blindCh_H, 0x03, 0x03);
log.info(“req_Stop=”, req)
//Вызовем запрос, не ожидая ответ. На команды ответа нет.
requestRPC(portBlind, speedPortBlind, pariryBlid, stopBitBlind, NameBlind, 1, “HEX”, req, 0 );
}
});
//close:
defineRule(NameBlind+“_rule_close”,{
whenChanged: NameBlind+“/close”,
then: function () {
//Формируем запрос 0a ee
var req = blindRequestMsg(blindCh_L, blindCh_H, 0x03, 0x02);
//log.info(“close=”, req)
requestRPC(portBlind, speedPortBlind, pariryBlid, stopBitBlind, NameBlind, 1, “HEX”, req, 0 );
}
});
//Сделаем таймер, который будет опрашивать позицию, возвращая ее в контрол.
/* startTicker(NameBlind+“_timer”, 6000);
//И правило, работающее по срабатыванию таймера
defineRule(NameBlind+“_rule”,{
when: function () { return timers[NameBlind+“_timer”].firing; },
then: function () {
var req = blindRequestMsg(blindCh_L, blindCh_H, 0x03, 0x04);
//log.info(“req_timer “+NameBlind+”=”, req)
//Вызовем запрос, ожидая 9 байт в ответ
requestRPC(portBlind, speedPortBlind, pariryBlid, stopBitBlind, NameBlind, 1, “HEX”, req, 9 );
}
});
*/trackMqtt(pathRPC+NameBlind+“/reply”, function(message){
log.info(“from “+NameBlind+” name: {}, value: {}”.format(message.topic, message.value))
var replyObj = JSON.parse(message.value);
//log.info("from “+NameBlind+” replyObj.error: ", replyObj.error)
//log.info(“from “+NameBlind+” replyObj.result.response: {}”.format(replyObj.result.response))
dev[NameBlind][“reply”] = replyObj.result.response;
});return 0
}function requestRPC(modbusPort, modbusSpeed, modbusParity, reqStopbit, clientID, requiestID, messageType, message, responseSize){
//Формируем JSON запрос. Должно быть что-то такое:
//{“params”: {“response_size”: 8, “format”: “HEX”, “path”: “/dev/ttyRS485-1”, “baud_rate”: 9600, “parity” : “N”, “data_bits” : 8, “stop_bits” : 1, “msg”: “0A03008000018499”}, “id” : 1}
var strJson = JSON.stringify({params: {response_size: responseSize, format: messageType, path: modbusPort, “baud_rate”: modbusSpeed, parity: modbusParity, “data_bits” : 8, “stop_bits” : reqStopbit, “msg”: message}, “id” : requiestID})
publish(pathRPC+clientID, strJson, 2, false);
}function blindRequestMsg(blindCh_L, blindCh_H, commandBlind, dataBlind){
//Сформируем набор байт команды. Первый байт всегда 55.
//отсутствует для текущего - blindID
//Второй - blindCh_L
//третий - blindCh_H
//четыертый - функция
//пятый - данные функции
//шестой - crc16_l
//седьмой - crc16_h
//Для “открыть”, проверочный 55 fe fe 03 01 AD 8A
//на входе ожидаем целые без знака.//Вычисляем CRC.
var verify = crc16modbus([0x55,toHexStr(blindCh_L),toHexStr(blindCh_H),toHexStr(commandBlind),toHexStr(dataBlind)])
// CRC16 возвращается, но он может быть короче двух байт (меньше 256) и перым надо отправлять его младший байт.
verify=toHexStr(verify)
//log.info(“verifyHEX=”, verify)
verify_L = “0x”+verify & 0x00FF
//log.info(“verifyHEX_L=”, “0x”+verify & 0x00FF)
verify_H = “0x”+verify & 0xFF00
//log.info(“verifyHEX_H=”, “0x”+verify & 0xFF00)//Готовим строку
return “55”+toHexStr(blindCh_L)+toHexStr(blindCh_H)+toHexStr(commandBlind)+toHexStr(dataBlind)+toHexStr(verify_L)+toHexStr(verify_H);
}function crc16modbus(buffer) {
var crc = 0xFFFF;
var odd;for (var i = 0; i < buffer.length; i++) { crc = crc ^ buffer[i]; for (var j = 0; j < 8; j++) { odd = crc & 0x0001; crc = crc >> 1; if (odd) { crc = crc ^ 0xA001; } } } return crc;
};
function toHexStr(inArg){
//На входе int, на выходе hex строка дополненные нулями спереди
var tmp = inArg.toString(16);
if (tmp.length < 2) {tmp = “0”+tmp};
return tmp;
}function makeNewVirtualControl(vdName, nameControl, typeControl){
//log.info(“GetDevice”, getDevice(“vdName”))
if (getDevice(vdName) === undefined) {
log.info(“Define new”)
defineVirtualDevice(vdName, {
title: vdName,
cells: {},
})
}
//Тут проверим есть ли уже контрол и если нет - создадим.
if (!getDevice(vdName).isControlExists(nameControl)) {
log.debug(“Контрола “+nameControl+” нет, создаем.”)
getDevice(vdName).addControl(nameControl, typeControl);
}
}//Создаем виртуальное устройство, с контролами для шторы. По строчке на одну штору.
// имя порт bod parity stopbit ID_L ID_H
createBlind(“ONVIZ MR2234F”, “/dev/ttyRS485-1”, 9600, “N”, 1, 1, 1, 1)

anon /etc/wb-rules/Onviz.js:72 preventsyield
Потому что для комбинации verify возвращает 0x1f9
Забыл сдвинуть со старшего на младшее слово.
verify_H = “0x”+verify & 0xFF00
//log.info(“verifyHEX_H=”, “0x”+verify & 0xFF00)
поменять на
verify_H = ("0x"+verify & 0xFF00)>>8
//log.info("verifyHEX_H1=", verify_H)
Да, это старая тема. Если есть вопросы - то создавайте новую.