Qt5 - QML - AirLink RV50 - JavaScript:如何在第三方路由器上自动触发组合框和按钮

Posted

技术标签:

【中文标题】Qt5 - QML - AirLink RV50 - JavaScript:如何在第三方路由器上自动触发组合框和按钮【英文标题】:Qt5 - QML - AirLink RV50 - JavaScript : How to automatically trigger combobox & button on a third party router 【发布时间】:2019-12-04 14:43:51 【问题描述】:

我正在使用第三方路由器AirLink RV50 登录我构建的小型机器人。该机器人将使用由combobox 和相关button 触发的继电器启动,该继电器将应用combobox 选项。这个过程发生在AirLink RV50 路由器的用户界面内。

应用启动后的目标:

1) 在路由器内部登录,

2) 自动触发组合框和

3) 使用Apply 按钮自动应用组合框选项。

combobox下方:

下面还有Apply 按钮:

问题:为了访问路由器,有一个外部接口我没有写,因为它来自路由器。我浏览了界面并到达了Apply 按钮和combobox,如html 代码所示:

所以操作如下:

1)我使用组合框触发继电器

2) 使用鼠标我必须将鼠标悬停在Apply 按钮上

3)鼠标在按钮上后(按钮悬停)我可以点击并应用选择

什么不起作用:我可以触发组合框,但我无法自动悬停并单击应用按钮。 最重要的是我注意到combobx有两个主要功能:

a)onblur=onBE(this);

b)onfocus=setPrevVal(this)

我相信,以我对javascript 的有限了解,为了让Button“感觉”并接受这种变化,combobox 的那些功能需要被触发。

我在界面的调试器控制台中导航,成功拿到了负责感受这个变化的两个函数。我抓住它们并在下面发布。 所以我的问题的解决方案是通过触发这两个函数来“强制”这个点击:

function onBE(a) 
  var b = $(a);
  if (b.val() != gsPreviousValue || b.is(':checkbox')) 
    if ('25301' === b.attr('name') || '25501' === b.attr('name')) b = $('[name="22001-d1"]'),
    b.prop('disabled', !0),
    b.removeClass('fbtn');
    if ('checkbox' == a.type && - 1 == a.name.indexOf('2160') && - 1 == a.name.indexOf('2050') && - 1 == a.name.indexOf('55053') && - 1 == a.name.indexOf('55056')) 
      if ('0' == gV(a)) selAll(a, !0);
       else 
        var c = gEBN(a.name);
        isIE ? c[1].checked = !1 : c[0].checked = !1
      
      c = gcbd(a);
      highlightChange(a, c);
      gTT(a) != c ? wvtt(a.name, c, !0)  : wvtt(a.name, c, !1)
     else 
      b = $(a).parent() [0].id;
      if ('' != b) 
        for (inobjcnt = 0; inobjcnt < a.length; inobjcnt++) a[inobjcnt].selected && (b = b + '-' + a[inobjcnt].value);
        showhidetables(b)
      
      b = getParent(a, 'TABLE');
      if (b.id == a.name.split('-') [0] || b.id == a.name.split('-') [0].replace('bin', '') || - 1 != b.title.indexOf('-')) 
        var d = '',
        e = [
        ],
        f = gEBTN(b, 'TR');
        $(b).find('tr');
        for (irowcnt = 2; irowcnt < f.length - 1; irowcnt++) 
          var g = $(f[irowcnt]).find('td');
          if ('21601' <= b.id && '21605' >= b.id || '55053' == b.id || '55056' == b.id) 
            for (var j = [
            ], h = 0; h < g.length; h++) g[h].childNodes[0].checked && j.push(gV(g[h].childNodes[0]));
            0 < j.length && (d += j.join(',') + ',')
           else if ('20501' <= b.id && '20505' >= b.id) 
            for (h = 0; h < g.length; h++) g[h].childNodes[0].checked ? e.push(1)  : e.push(0);
            0 < e.length && (d = BintoDec(e.join('')))
           else if (!1 == bhelix || '9061' == b.id || '9010' == b.id || '8010002' == b.id) 
            h = getcurtbl().id.replace('TB_', 'TL_G_');
            h = $(parseID(h)).val().split('|');
            for (j = 0; j < h.length; j++) if ( - 1 != h[j].indexOf('tlid=' + b.id + '&')) 
              c = h[j].split('&') [4].replace('defaultval=', '').split('-');
              break
            
            if ('t0' != g[0].className) for (h = 0; h < g.length; h++) j = gV(g[h].childNodes[0]),
            1 < g[h].children.length && (j = gV(g[h].childNodes[1])),
            '' != j && (c[h] = j);
             else for (h = 1; h < g.length; h++) '' != encodeSpecialChars(gV(g[h].childNodes[0])) && (c[h - 1] = encodeSpecialChars(gV(g[h].childNodes[0])));
            d += c.join(cdlm) + (irowcnt == f.length - 2 ? '' : rdlm)
           else 
            if ('t0' != g[0].className) for (h = 0; h < g.length; h++) j = gV(g[h].childNodes[0]),
            1 < g[h].children.length && (j = gV(g[h].childNodes[1])),
            d = d + (0 == h ? '' : cdlm) + j;
             else for (h = 1; h < g.length; h++) d = d + (1 == h ? '' : cdlm) + encodeSpecialChars(gV(g[h].childNodes[0]));
            d += irowcnt == f.length - 2 ? '' : rdlm
          
        
        b.title == d ? setTLvalue(b.id, d, !1)  : setTLvalue(b.id, d, !0);
        highlightChange(a, gV(a))
       else highlightChange(a, gV(a)),
      wtta(a)
    
  

及以下第二个功能:

function createselect(a, b, c, d) 
b = b.split(ssep);
var e = $('<select/>');
'' !== !c && e.attr('name', c);
e.attr(
onblur: 'onBE(this);',
onfocus: 'setPrevVal(this);'
);
'' != b[1] && e.attr('onchange', 'showHideTablesOnChange(this);');
for (c = 2; c < b.length; c++) 
var f = b[c];
if (null != f) 
var f = RegExp(f),
g = $('<option/>');
if ('' == b[c] || !1 == f.test(_global.deviceID.toUpperCase()) && !1 == f.test(enumFlag) && !1 == f.test(enumWiFlag)) 
c++;
var f = b[c],
j = f.indexOf('-'),
h = f.substr(j + 1);
g.val(f.substr(0, j));
g.html(h);
e.append(g)
 else c++


'hidden' ==
d && e.css('visibility', 'hidden');
$(a).append($(e));
'hidden' == d && $('<label/>').html('').insertBefore(e)

function setPrevVal(a) 
gsPreviousValue = $(a).val()

function configInput(a, b, c, d, e) 
'button' != d && 'cfgchk' != d && a.attr('onblur', 'onBE(this);');
'cfgchk' == d && (d = 'checkbox', a.attr('class', 'non'));
a.attr(
name: c,
type: d,
onfocus: 'setPrevVal(this);'
);
null != b && a.val(b);
e && a.attr('onclick', 'selAll(this, true);');
return a

function sAIC(a, b, c, d, e, f) 
'button' != e && 'cfgchk' != e && (e == scbx && isIE ? a.onblur = function () 
onBE(a)

 : sAtt(a, 'onblur', 'onBE(this);'));
'cfgchk' == e && (e = scbx, sCLN(a, 'non'));
sAtt(a, 'name', c);
sAtt(a, 'type', e);
null != b && sV(a, b);
f && sAtt(a, 'onclick', 'selAll(this,true);')

如果需要JavaScript 中的ApplyChange() 函数,也可以在下面:

function applyChange(a) 
_global.applyChangeClicked = !0;
a = void 0 == a ? !0 : !1;
var b = !1,
c = getcurtbl(),
d = $('#' + sCAT + ''),
e = $('#' + sTLCAT + '');
if ('' == d.val() && '' == e.val()) return !1;
d = gV(docEId(sCAT)).replace('&', '');
if ( - 1 != c.id.indexOf('TB_1024_Events Reporting_Events_Event ') && !chkLoad.checked && (e = c.id.replace('TB_1024_Events Reporting_Events_Event ', ''), e = parseInt(e.substring(0, 1)), !validateName('Event', 20900 + e))) return !1;
if ( - 1 != c.id.indexOf('TB_1024_I/O_Configuration_') && !chkLoad.checked) 
for (e = 2; 6 >= e; e++) for (var f = 2; 4 >= f; f++) 
var g = $('input[name="821-' + e + '-' + f + '"]');
if (0 !== g.length) 
var j = g.val(),
j = encodeSpecialChars(j);
g.val(j);
onBE(g[0])


for (e = 2; 6 >= e; e++) for (f = 2; 4 >= f; f++) g = $('input[name="821-' + e + '-' + f + '"]'),
0 !== g.length && (j = g.val(), j = decodeSpecialChars(j), g.val(j))

if ( - 1 != c.id.indexOf('TB_1024_Events Reporting_Actions_Action ') && !chkLoad.checked) 
if ( - 1 != d.indexOf('25301') || - 1 != d.indexOf('25501')) 
var h = $('[name="22001-d1"]'),
m = $('<img/>');
m.attr('src', 'images/loader.gif');
m.addClass('loaderimg');
h.after(m);
setTimeout(function () 
h.addClass('fbtn');
h.prop('disabled', !1);
m.remove()
, 20000)

c = c.id.replace('TB_1024_Events Reporting_Actions_Action ', '');
c = parseInt(c.substring(0, 1));
if (!validateName('Action', 21900 + c)) return !1

if ('' != d) 
d += '&';
c = d.split('&');
e = 0;
for (f = ''; e < c.length; ) 
f = '';
for (b = 0; b <= _constant.MAX_AMT_TO_SEND && !(e >= c.length); b++, e++) 0 < c[e].length && (f += c[e] + '&');
b = GenReq('Embedded_Ace_Set_Task', f, !0, '', '', 'Changes')

a && (b ? alert(_message.APPLY_SUCCESSFUL)  : alert(_message.APPLY_FAILED));
if (_global.deviceID ===
_constant.MP70_WIFI || _global.deviceID === _constant.GX450_WIFI) b = d.match(/^5560\d1/g),
null != b && updateWifiSideMenu(b);
chkLoad.checked || ( - 1 != d.indexOf('2090') && getEventList(), - 1 != d.indexOf('2190') && getReportList())

b = gV(docEId(sTLCAT));
$(parseID(sTLCAT)).val();
b = b.split('|');
if (0 < b.length) for (c = 0; c < b.length; c++) if (e = b[c], '' != e) if (f = e.split('&'), g = e.split('&').slice(0, 5), j = '', '1857' == f[0].split('=') [1]) 
f[5].split('=');
var l = f[6].replace('data=', '').split(' ');
if (10 < l.length) 
for (var n = 0; n < l.length; n++) '' !=
l[n] && (j += l[n] + ' '),
0 == (n + 1) % 10 && (j = j.slice(0, - 1), f[0] = 'tlid=' + (1857 + (n - 9)), f[2] = 'incby=1', f[3] = 'colsid=' + (1857 + (n - 9)), f[5] = 'datarowcnt=10', f[6] = 'data=' + j, e = f.join('&'), GenReq('Embedded_Ace_TLSet_Task', e, !1, a && n == l.length - 1 ? _message.APPLY_SUCCESSFUL : '', _message.APPLY_FAILED, 'Changes'), j = '');
GenReq('Embedded_Ace_TLGet_Task', g.join('&'), !0, '', _message.DATA_FAILED, 'Get')
 else GenReq('Embedded_Ace_TLSet_Task', e, !1, a && '' == d && c == b.length - 1 ? _message.APPLY_SUCCESSFUL : '', _message.APPLY_FAILED, 'Changes')
 else GenReq('Embedded_Ace_TLSet_Task', e, !1, a && '' == d && c == b.length - 1 ? _message.APPLY_SUCCESSFUL : '', _message.APPLY_FAILED, 'Changes');
chkLoad.checked && (applyCancel(!1), sV(docEId(sCAT), ''), showNOTSET = chkLoad.checked = !1, getEventList(), getReportList(), docEId(sbAY).disabled = !1, docEId(sbRf).disabled = !1, _global.templateInProgress = !1, chkLoad.click());
setTimeout(Refreshtab(), 0);
$('#curAppCT').val('')

代码

到目前为止,我使用的实际代码是下面的简单代码,它可以完成这项工作,但不幸的是,我不能对上面的 JavaScript 函数说同样的话,这对我来说很难理解:

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtWebEngine 1.8

ApplicationWindow
    id: root
     width: 1640
     height: 880
     visible: true
     property string username: "user"
     property string password: "xxxxxxx"
     property string tabs: "#"
    QtObject
        id: internals
        property string login_script: "
                var input_username = document.getElementById('username');
                input_username.value = '%1';
                var input_password = document.getElementById('password');
                input_password.value = '%2';
                LSubmit();
            ".arg(username).arg(password);

        property string get_tabs: "
                    var obtain_tabClick = document.getElementById('I/OM1');
                    obtain_tabClick.value = '%1';
                    M1C('SM1_I/O','CT_1024_I/O_Current State_!TD_1024_I/O_Current State_','I/OM1!SM1_I/O_Current StateM1','1');
                ".arg(tabs);

        property string get_relay_comboBox: "
              var comboBox = document.getElementsByName('859-2-2')[0];
              if (comboBox) 
                // Add event listener for combobx
                comboBox.addEventListener('change', function (e) 
                  console.log('Change event detected:', e);
                );
                // Get new option index by flipping the current selected index
                var newIdx = (comboBox.selectedIndex + 1) % 2;
                console.log(comboBox, comboBox.selectedIndex, newIdx);  // debug
                // set the new index
                comboBox.selectedIndex = newIdx;
                // fire change event
                comboBox.dispatchEvent(new Event('change'));
              
              else 
                console.error('comboBox not found!');
              
            ";
// This is one solution but did not work
//        var applyBtn = document.getElementById('btn_Apply');
//        applyBtn.value = '%1';
//        applyChange();


// This is a second solution but didn't work 
//        property string applyBtn: "
//            console.log('start')
//            var btnApply = document.getElementById('btn_Apply');
//            console.log('btnApply')
////            function fun('btnb btnhov') 
////              document.getElementById('btn_Apply').click();
////            
//            if(btnApply) 
//                // Try add event listener for buttons
//                btnApply.addEventListener('change', function(e) 
//                    console.log('Change event detected:', e);
//                );
//              // Push button
//              // Here the button should be pushed (or hovered first????)
//            
//            else 
//                console.error('btnApply not found!');
//            
//        ";
    

        Timer 
            id: timer
            interval: 5000; repeat: false
            onTriggered: view.runJavaScript(internals.login_script)
        
        Timer 
            id: timer2
            interval: 20000; repeat: false
            onTriggered: view.runJavaScript(internals.get_tabs)
        
        Timer 
            id: timer3
            interval: 30000; repeat: false
            onTriggered: view.runJavaScript(internals.get_relay_comboBox)
           
//        Timer 
//            id: timer4
//            interval: 30000; repeat: false
//            onTriggered: view.runJavaScript(internals.applyBtn)
//        

        WebEngineView 
            id: view
            anchors.fill: parent
            onUrlChanged: 
                console.log(url)
                if(url == Qt.resolvedUrl("https://166.xxx.xx.x:xxxx/"))
                    timer.running = true
                    timer2.running = true
                    timer3.running = true
//                    timer4.running = true
                
            
            onCertificateError: function(error) 
                error.ignoreCertificateError();
            
            Component.onCompleted: view.url = "https://166.xxx.xx.x:xxxx"
        
    

到目前为止我尝试过的研究了很长时间如何绕过这些功能并强制点击应用按钮。不幸的是,我尝试的一切都不成功。

我什至尝试通过sshtelnet 访问以检查我是否能够绕过命令并使用路由器专有的AT 命令。但也访问不成功。 我认为使用三个AT 命令会更容易编写一个小的JavaScript 函数来完成这项工作。到目前为止,我的主要问题是我无法理解完全触发comboboxJavaScript 函数,因此无法轻松模拟点击。

剩下要做的最后一件事是完全重置路由器,但希望将其保留为最后一个选项。

感谢任何可以就这个问题提供一些指导的人。我的想法不多了,如果有更简单的方法或其他方法可以继续前进,请告诉我。

【问题讨论】:

您运行代码的操作系统是什么?也许你可以使用 AutoHotKey 软件。 @SoheilArmin,非常感谢您阅读这个问题。我正在使用Ubuntu 19.04 目前已解释,主要问题是我无法找到一种简单的方法来触发JavaScriptcombobx 正在使用的两个JavaScript 函数。 所以,打开你的浏览器(chrome)。打开 Ctrl-Shift-I 打开开发者工具。在网络选项卡中,查看Embedded_Ace_TLSet_Task 发送到后端的网络请求是什么。您可以通过这条路径摆脱这种肮脏的黑客攻击。 好的,我正在检查 【参考方案1】:

一般来说,对于这种类型的 hack,它可能是解决 GUI 端问题的最后解决方案。

最合适的方式是要求原厂商/开发商提供API文档,通过其他方式控制目标设备。

既然我认为这不是一个选项,您可以调查提交命令后发生的网络请求/回复。 希望这将使您了解 GUI后端通信背后发生的事情。

如通过cmets发送的图片和原始代码所示,这两个js函数只是创建一个Embedded_Ace_TLSet_Task请求发送到设备内部的HTTP服务器。

通过调查这些 HTTP 请求,您可以使用 QNetworkAccessManager 甚至在 QML 代码中使用 XMLHttpRequest 来模拟相同的行为,而无需编写 C++ 代码。

编辑: AirLink RV50 支持 RAP(远程访问协议)。有关如何获取 RAP 协议指南副本的信息,请联系公司的销售代表。

【讨论】:

以上是关于Qt5 - QML - AirLink RV50 - JavaScript:如何在第三方路由器上自动触发组合框和按钮的主要内容,如果未能解决你的问题,请参考以下文章

Qt5 / PyQt5 : 带有 QML 前端和 Python 后端的自定义 QML 组件

从 C++ (Qt5) 向 QML 项目发送信号

Qt5.8 QML 为啥只读的 Controls2.TextArea 有 ibeam 光标?

使用 qml 从 qt5 发布 HTTP 请求

Q_INVOKABLE 是不是需要在 Qt5 中从 QML 调用公共 QObject 函数?

Qt5快速qml测试和opengl渲染的问题