question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Combine Control Widgets with Latest Values

See original GitHub issue

Hello Everyone,

I’m trying to create a custom widget in which I can get the latest values from a device updating periodically (everytime they change) and from the same widget have a button or some buttons that send RPC commands to the device.

I tried mixing the code from the RPC Commands widget with the Attribute Card widget code, both from the tutorial on how to develop widgets. For some reason I cant send the RPC command, it seems that it needs a “success(response)” and “fail(rejection)”, but when I run the RPC code from within the Attribute Card widget, these response and rejection dont seem to be generating.

### This is what im trying to build:

image

### This is my Javascript code:


`self.onInit = function() {

self.ctx.$scope.sendCommand = function() {
        console.log("0");
    // var rpcMethod = self.ctx.$scope.rpcMethod;
    var rpcMethod = "setValue";
    // var rpcParams = self.ctx.$scope.rpcParams;
    var rpcParams = "True";
    var timeout = self.ctx.settings.requestTimeout;
    var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ? true : false;
    
    var commandPromise;
    if (oneWayElseTwoWay) {
        commandPromise = self.ctx.controlApi.sendOneWayCommand(rpcMethod, rpcParams, timeout);
            console.log("1");
            console.log(timeout)
            console.log(commandPromise);
    } else {
        commandPromise = self.ctx.controlApi.sendTwoWayCommand(rpcMethod, rpcParams, timeout);
            console.log("2");
    }
    
    // console.log("Response:" + response);
    commandPromise.then(
        function success(response) {
            
            if (oneWayElseTwoWay) {
                self.ctx.$scope.rpcCommandResponse = "Command was successfully received by device.<br/> No response body because of one way command mode.";
                console.log("3");
            } else {
                self.ctx.$scope.rpcCommandResponse = "Response from device:<br/>";                    
                self.ctx.$scope.rpcCommandResponse += angular.toJson(response);
                console.log("4");
            }
        },
        
        function fail(rejection) {
            console.log("Rejection:" + rejection);
            console.log("5");
            self.ctx.$scope.rpcCommandResponse = "Failed to send command to the device:<br/>"
            console.log("6");
            self.ctx.$scope.rpcCommandResponse += "Status: " + rejection.status + "<br/>";
            self.ctx.$scope.rpcCommandResponse += "Status text: '" + rejection.statusText + "'";
            console.log("7");
        }
        
    );
}

var button = document.getElementById("THEbutton");
button.addEventListener("click", changeOwnText);

function changeOwnText(){
    button.innerHTML += "CLICK!";
}

self.ctx.datasourceTitleCells = [];
self.ctx.valueCells = [];
self.ctx.labelCells = [];

for (var i=0; i < self.ctx.datasources.length; i++) {
    var tbDatasource = self.ctx.datasources[i];

    var datasourceId = 'tbDatasource' + i;
    self.ctx.$container.append(
        "<div id='" + datasourceId +
        "' class='tbDatasource-container'></div>"
    );

    var datasourceContainer = $('#' + datasourceId,
        self.ctx.$container);

    datasourceContainer.append(
        "<div class='tbDatasource-title'>" +
        tbDatasource.name + "</div>"
    );
    
    var datasourceTitleCell = $('.tbDatasource-title', datasourceContainer);
    self.ctx.datasourceTitleCells.push(datasourceTitleCell);
    
    var tableId = 'table' + i;
    datasourceContainer.append(
        "<table id='" + tableId +
        "' class='tbDatasource-table'><col width='30%'><col width='70%'></table>"
    );
    var table = $('#' + tableId, self.ctx.$container);

    for (var a = 0; a < tbDatasource.dataKeys.length; a++) {
        var dataKey = tbDatasource.dataKeys[a];
        var labelCellId = 'labelCell' + a;
        var cellId = 'cell' + a;
        table.append("<tr><td id='" + labelCellId + "'>" + dataKey.label +
            "</td><td id='" + cellId +
            "'></td></tr>");
        var labelCell = $('#' + labelCellId, table);
        self.ctx.labelCells.push(labelCell);
        var valueCell = $('#' + cellId, table);
        self.ctx.valueCells.push(valueCell);
    }
}    

self.onResize();

}

self.onDataUpdated = function() { for (var i = 0; i < self.ctx.valueCells.length; i++) { var cellData = self.ctx.data[i]; if (cellData && cellData.data && cellData.data.length > 0) { var tvPair = cellData.data[cellData.data.length - 1]; var value = tvPair[1]; var textValue; //toDo -> + IsNumber

        if (isNumber(value)) {
            var decimals = self.ctx.decimals;
            var units = self.ctx.units;
            if (cellData.dataKey.decimals || cellData.dataKey.decimals === 0) {
                decimals = cellData.dataKey.decimals;
            }
            if (cellData.dataKey.units) {
                units = cellData.dataKey.units;
            }
            txtValue = self.ctx.utils.formatValue(value, decimals, units, true);
        } else {
            txtValue = value;
        }
        self.ctx.valueCells[i].html(txtValue);
        document.getElementById("demo").innerHTML = "datasources[0].name: " + self.ctx.datasources[0].name;
        document.getElementById("demo2").innerHTML = "datasources[0].entityName: " + self.ctx.datasources[0].entityName;
        document.getElementById("demo3").innerHTML = "datasources[0].entityType: " + self.ctx.datasources[0].entityType;
        document.getElementById("demo4").innerHTML = "datasources[0].dataKeys: " + String(self.ctx.data[0].data[0]);
        document.getElementById("demo5").innerHTML = "datasources[0].dataKeys: " + String(self.ctx.datasources[0].dataKeys[0].label + ": " + self.ctx.data[0].data[0][1]);
        // console.log("datasources[0].dataKeys: " + self.ctx.utils.formatValue(self.ctx.datasources[0].dataKeys[0].label, decimals, units, true));
    }
}

function isNumber(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

}

self.onResize = function() { var datasoirceTitleFontSize = self.ctx.height/8; if (self.ctx.width/self.ctx.height <= 1.5) { datasoirceTitleFontSize = self.ctx.width/12; } datasoirceTitleFontSize = Math.min(datasoirceTitleFontSize, 20); for (var i = 0; i < self.ctx.datasourceTitleCells.length; i++) { self.ctx.datasourceTitleCells[i].css(‘font-size’, datasoirceTitleFontSize+‘px’); } var valueFontSize = self.ctx.height/9; var labelFontSize = self.ctx.height/9; if (self.ctx.width/self.ctx.height <= 1.5) { valueFontSize = self.ctx.width/15; labelFontSize = self.ctx.width/15; } valueFontSize = Math.min(valueFontSize, 18); labelFontSize = Math.min(labelFontSize, 18);

for (i = 0; i < self.ctx.valueCells; i++) {
    self.ctx.valueCells[i].css('font-size', valueFontSize+'px');
    self.ctx.valueCells[i].css('height', valueFontSize*2.5+'px');
    self.ctx.valueCells[i].css('padding', '0px ' + valueFontSize + 'px');
    self.ctx.labelCells[i].css('font-size', labelFontSize+'px');
    self.ctx.labelCells[i].css('height', labelFontSize*2.5+'px');
    self.ctx.labelCells[i].css('padding', '0px ' + labelFontSize + 'px');
}    

}

self.onDestroy = function() { } `




### This is what i get when i console.log(commandPromise), and the general error(in red):

image

### And this is the error i get when trying to console.log(“Rejection” + rejection):

Rejection:undefined


I hope someone can guide me in the right direction, I have tried it all but I dont know what Im missing.

THANKS A LOT IN ADVANCE

Daniel

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:11

github_iconTop GitHub Comments

1reaction
PeterMaircommented, Dec 13, 2020

Hi @paolofrs,

it isn’t possible to use self.ctx.controlApi.sendTwoWayCommand on a time/last value widget. I use this solution for sendOneWayCommand, but you can replace sendOneWayRpcCommand with sendTwoWayRpcCommand:

// Get deviceid from first datasource

var deviceid = self.ctx.datasources[0].entityId;

// Get deviceService 

var $injector = self.ctx.$scope.$injector;
var $deviceservice = $injector.get(self.ctx.servicesMap.get('deviceService'));

// Send oneWay RPC-Command, with requestBody like {"method": "methodname", "params": 1} 
      
commandPromise  = $deviceservice.sendOneWayRpcCommand(deviceid, requestBody, { ignoreErrors: true  });
commandPromise.subscribe(
  function success(response) {
   console.log("Command was successfully received by device. No response body because of one way command mode.");       
  },
  
  function fail(rejection) {
      
      console.log("Failed to send command to the device:");
      console.log(rejection);
      
  }
);
1reaction
lvojpcommented, Sep 9, 2019

Hello everyone. I’m just worried about this issue right now.

Specifically, I want to press the button, wait for the device to respond, and display the data returned from the device in the widget.

Is there a way to solve this specification?

Thank you for your teaching.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Control Widgets | 20|20 Help Center
Control widgets have two primary functions: They let you quickly adjust systems from your home screen. They link to control pages where you ......
Read more >
Widgets - System experiences - Human Interface Guidelines
A widget elevates a small amount of timely, personally relevant information from your app or game, displaying it where people can see it...
Read more >
App widgets overview - Android Developers
Widgets are a great mechanism to attract a user to your app by "advertising" new and interesting content that is available for consumption...
Read more >
3.3. Mastering widgets in the Jupyter Notebook
The ipywidgets package provides many common user interface controls for ... decorator displays a slider to control the value passed to the function:....
Read more >
Add and connect widgets—ArcGIS Experience Builder
Duplicating or copying a widget preserves all its settings except for the position on the page and the label. New widget labels follow...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found