0
Under review

Requesting feedback at regular intervals and JSON parsing

Iain Brew 10 months ago in Bugs and problems updated by Vladimir Ovchinnikov 9 months ago 10

Hello all

I am working on a small task to use the Philips Hue lighting system ecosystem in a project in a different way. One of their products is a 4 button wireless light switch. When buttons are pressed, it sends commands to a Hue Bridge (base station) which then talks to lights etc. Instead, I want to use those four buttons to trigger iRidium commands (i.e. send data to a driver, write a value to a token etc). 

I have made some progress with my project however am stuck with two things:

1) Request status every 100ms

Currently, I can only gain feedback once when I land on the page which contains the text box which the feedback is attached too. For this to work, I need iRidium to be checking the status of the buttons constantly so that it can be responsive within 100 or maybe 200ms. Is this possible?

2) Parsing JSON

I am a bit stuck on this. I have been working on a small javascript file which uses an 'SendEx' request to GET a response from the button (in the system it is known as a 'sensor' and its current ID is '12'). This is using JSON.

IR.AddListener(IR.EVENT_START, 0, function()
   
{
   IR.GetDevice("hue");
   // ***get Hue driver***
   sendRequests();
   // ***send request for API***  
   // ***Code to go here to request status every 100ms regardless of active page or popup***         
});

function sendRequests()
{
   // ***request status of Sensor 12 - Buttons***
   IR.GetDevice("hue").SendEx({ 
         Type: "GET",                                                                    
         Url:  "/api/a8CaS3oaTHN0mL-1IgKZgYRzXTLL3kIbJVApJukm/sensors/12",      
         cbReceiveText:       function(text)  

For now in my testing phase, I have the output of the text response go into a text box on my page:

IR.GetPage("Page 1").GetItem("buttonstate").Text = text;


The response from the Philips Hue system when requesting the status of Sensor 12 is:

hello

{
"state": {
"buttonevent": 4002,
"lastupdated": "2018-12-15T01:23:33"
},
"config": {
"on": true,
"battery": 100,
"reachable": true,
"pending": []
},
"name": "DimmerDemo",
"type": "ZLLSwitch",
"manufacturername": "Philips",
"swversion": "5.45.1.17846",
"uniqueid": "00:17:88:01:04:af:cb:12-02-fc00"
}

What is important to me is the first number after "state" > "button event". These numbers refer to the button pressed (1000, 2000, 3000, 4000). The last digit refers to the kind of press (long, short, release etc). 


Only the first number is important to me. This tells me simply which button has been triggered (1, 2, 3 or 4). This is the area I am struggling with most is the JSON Parse to extract just that first number. 


From here, depending on the number, it would then trigger something. For example:


}    
//switch goes here I think???!??
    case "1": 
    //button number '1'
    IR.GetPage("Page 1").GetItem("response").Text = Button 1 Pressed;
// ***trigger a command to a device i.e. Turn Light 5 ON
    IR.GetDevice("hue").Set("Light ID 5 = On, "");
break;
case "2":
IR.GetPage("Page 1").GetItem("response").Text = Button 2 Pressed;
    // ***do the things***
break;
case "3":
IR.GetPage("Page 1").GetItem("response").Text = Button 3 Pressed;
// ***do the things***
break;
case "4":
IR.GetPage("Page 1").GetItem("response").Text = Button 4 Pressed;
// ***do the things***
// break;


If anyone could advise on how to properly parse this JSON response and then have it trigger events in iRidium I would be very grateful.  

+1
Under review

Hello.

You can use a recursive Settimeout() to execute the function every 200 MS. Use SetIntertval() with this value is not recommended because will surely get a memory leak. You can use the following code to get the pre-known value of an element from JSON:


var tmp = '{ "qwerty": "1234567890" }';

IR.Log(JSON.parse(tmp).qwerty); // 1234567890

Thanks Vladimir

I will try this now!

The bit from the JSON I need is

LEVEL 1 = 0

LEVEL 2 = state

LEVEL 3 = buttonevent: XXXX

HI Vladimir

Focusing on the JSON stuff, I think I may have your syntax a bit wrong. Is this on the right track?

function sendRequests()
{
// ***request status of Sensor 12 - Buttons - eventually these scripts will need to listen to 10x buttons***
IR.GetDevice("hue").SendEx({
Type: "GET",
Url: "/api/a8CaS3oaTHN0mL-1IgKZgYRzXTLL3kIbJVApJukm/sensors/12",
cbReceiveText: function(text),
var tmp = '{"state": "buttonevent"}';
IR.Log("JSON.parse(tmp).buttonevent");
str.charAt(1);
}

{
switch (buttonevent)
// ***Code to go here to parse response data and extract state > buttonstate > XXXX***
IR.GetPage("Page 1").GetItem("buttonstate").Text = text;

Hello.

Example of our project:

JSON.irpz

In your case, the code should be:

var tmp = '{"state": "buttonevent"}';
var result = JSON.Parse(tmp).state;
IR.Log("Result = " + result);

Hi Vladimir - thanks for your awesome support. I tried to insert this code but it either breaks my code, or it still shows the old results. I have attached my project for your reference. Hue Dimmer Button Demo

In the presented project, you send a GET request script and get a string. Give an example of the string you are getting. In the editor you have incorrectly configured sending commands. If you want to access the server via a script, remove the bindings to the buttons. So it will be more clear what is happening.

Now we would like to start with this:

IR.AddListener(IR.EVENT_START, 0, function()
{
IR.GetDevice("hue");
sendRequests();

});

function sendRequests()
{
IR.GetDevice("hue").SendEx({
Type: "GET",
Url: "/api/4pIBQMqs2Nib6JgK9XtBsaACKKClGAUTKrOtjivg/sensors/14",
cbReceiveText: function(text, code, headers)
{
IR.Log("Text: " + text);
IR.Log("Code: " + code);
IR.Log("Headers" + headers);
}
});
}

Somebody find the log output of iRidium.

Please to share that a clever colleague has solved the parsing problem for me. Only thing left is for it to poll the bridge every 100ms for a status change.

IR.AddListener(IR.EVENT_START, 0, function()
   
{
   IR.GetDevice("hue");
   // ***get Hue driver***
   sendRequests();
   // ***send request for API***  
   // ***Code to go here to request status every 100ms regardless of active page or popup***         
});

function sendRequests()
{
   // ***request status of Sensor 14 - Buttons ¬ eventually these scripts will need to listen to 10x buttons***
   IR.GetDevice("hue").SendEx({ 
         Type: "GET",                                                                    
         Url:  "/api/4pIBQMqs2Nib6JgK9XtBsaACKKClGAUTKrOtjivg/sensors/14",      
         cbReceiveText:       function(text)  
         {
            var response = JSON.Parse(text);
            var buttonEvent = response.state["buttonevent"];
            var numberToString = buttonEvent.toString();
            var firstNumber = numberToString.charAt(0);
            // Takes the first number of the button event response which correlates to the button press.
            // This is then parsed allowing the button to trigger something in iRidium unstead.
            switch (firstNumber)
            {
              case '1':
                        IR.GetPage("Page 1").GetItem("buttonstate").Text = "number 1 has been pushed.";    
              break;
              case '2':
                     IR.GetPage("Page 1").GetItem("buttonstate").Text = "number 2 has been pushed.";
              
              break;
              case '3':
                     IR.GetPage("Page 1").GetItem("buttonstate").Text = "number 3 has been pushed.";
              
              break;
              case '4':
                     IR.GetPage("Page 1").GetItem("buttonstate").Text = "number 4 has been pushed.";
                            
              break;
              default:
                            
              break;
            }
              
         },
   
   });
}

// The current response without parsing is as follows. What is important
// is the first number after state > button event > XXXX

// *start of response from API for Sensor = 12*
//{
//    "state": {
//        "buttonevent": 4002,
//        "lastupdated": "2018-12-15T01:23:33"
//    },
//    "config": {
//        "on": true,
//        "battery": 100,
//        "reachable": true,
//        "pending": []
//    },
//    "name": "DimmerDemo",
//    "type": "ZLLSwitch",
//    "manufacturername": "Philips",
//    "swversion": "5.45.1.17846",
//    "uniqueid": "00:17:88:01:04:af:cb:12-02-fc00"
//}
// *end of response from API for Sensor = 12*

Hello.

The poll can be done through a recursive IR.SetTimeout. If done through IR.SetInterval, the interval of 100 MS can be critical for the stable operation of the server.

Thank you - this is working beautifully. I inserted:

IR.SetTimeout(200, sendRequests);

However I am now finding it repeating the result every 200ms (display text, play a sound). Next task is to have it query the device and if nothing has changed since last time, do not issue a command. 

Hello.

You can save the last received value to a variable and compare it when you get a new value. If they are not equal, then call some function. See attached example.

TC.sirpz