Results 1 to 10 of 40

Thread: web server; sending events and polling lua variables

Hybrid View

  1. #1
    Join Date
    Jul 2007
    Location
    Netherlands
    Posts
    370

    Default web server; sending events and polling lua variables

    While creating some JQuery webpages using Girder I ran into the update and polling issues that many have run into before. I collected all the bits and pieces together to get my thingy to work. But figured I might better make something reusable.






    So here's the result, from several other posts;
    So it simplifies polling for updates, added to Shauns code the full 4 payloads for events created from javascript, included the 'cache : false' option for the ajax request to get a lua value (ran into the browser serving lua values from its cache, which obviously don't change)

    Any way this is the javascript I created;


    Creates a 'girder' namespace with the following methods/functions
    GetLuaValue
    Gets a Lua variable from Girder, independent of the recurring update
    Takes 2 parameters;
    1) string with the name of the lua variable to get from Girder
    2) callback function for the returned results. This will be the callback
    for the JQuery $.ajax method, see JQuery docs for parameters for this callback.
    SendEvent
    Sends an event to Girder. Takes 6 parameters;
    1) string with the eventstring
    2) integer with the Device ID for which the event is raised (optional, defaults to 18, Girder)
    3) 4 strings with the 4 payloads (optional, absence results in string value 'undefined' )
    NewUpdater
    Returns a new updater object, see below
    Updater object
    Runs a recurring update sequence (polling) that gets data from Girder and calls a callback function if the returned data was changed since the last request. Multiple updaters can run simultaneously, but if you get more than a few, you're better of using JSON to store a table in a single lua varaiable and get updates for the entire table at once.
    Object methods;
    Start
    Starts the polling sequence according to the provided parameters.
    Takes 3 parameters;
    1) string with the name of the lua variable to get from Girder
    2) integer with the interval in milliseconds between updates
    3) callback function when an updated value arrives, has 2 parameters
    a) data received during last update
    b) previously received data
    Stop
    Stops the previously started updater
    REQUIREMENTS
    2 additional files are required (these are NOT the standard distributed ones);
    - ajaxreq.lhtml
    - ajax_sendevent.lhtml


    The shortest possible way to get polling lua variables from Girder going;
    Code:
     
    $(document).ready(function() {
     var GoUpdate = function (newData, oldData) {
      // do what needs to be done here, will only be called when the data has changed
     };
     
     girder.NewUpdater().Start( 'mytest.value', 5000, GoUpdate );
    });
    This will poll the value of 'mytest.value' every 5 seconds and if the value changed from the previous poll, the GoUpdate function will be executed


    I hope it can be made into something generically usefull. So please comment on this, see the attachment for an example.
    Last edited by Tieske8; May 18th, 2011 at 01:58 PM. Reason: Removed the attachment, added an updated version in a later post.
    Using: Win7 MCE, Girder, xPL, RFXcom, HomeEasy

    http://www.thijsschreijer.nl

  2. #2
    Join Date
    Oct 2005
    Posts
    307

    Default

    Until browsers support an open UDP or TCP socket (dream that probably isn't too far out there), I would suggest returning a JSON string on anything more than a single variable. ajaxreqjson.lhtml at the bottom of http://www.promixis.com/forums/showt...face-with-JSON really simplifies things (bringing back complete tables with keys) and increases the speed for complex data polling (by decreasing the number of reoccurring requests).

    For me in its most complex implementation, it means one request returning 3 tables with a total of ~50 keys vs. 50 individual requests. This happens every second from every client accessing the same control (before it would bog down Girder with just 2 clients). I don't know what my current client limit is, I suspect it is 5x more efficient..

    Actually I would recommend using it from the beginning to eliminate changing when you decide you want to poll another variable...

  3. #3
    Join Date
    Oct 2005
    Posts
    307

    Default

    Also, I have found it necessary to stop data polling during actual control sequences and/or delay restart of polling until a control gets settled. This can be due to waiting on the user to finish interacting with the client side browser and/or Girder (which may be at the mercy of downstream gear)...

  4. #4
    Join Date
    Jul 2007
    Location
    Netherlands
    Posts
    370

    Default

    Thx for your comments

    Quote Originally Posted by shaun5 View Post
    Actually I would recommend using it from the beginning to eliminate changing when you decide you want to poll another variable...
    OK, that's a post I missed. So what I figured is update my code, such that if the first request returns a value '[table]', it will switch to using JSON for all future requests. Shouldn't be very hard to add.

    Quote Originally Posted by shaun5 View Post
    Also, I have found it necessary to stop data polling during actual control sequences and/or delay restart of polling until a control gets settled. This can be due to waiting on the user to finish interacting with the client side browser and/or Girder (which may be at the mercy of downstream gear)...
    I'm not sure what you mean exactly, the code in the timer I created allows for the polling to be stopped by calling the 'Stop' method. But I assume that's not what you meant?

    The code executes on a callback for the timer, which posts the ajax request (creating another callback with the data returned) and then restarts the timer. To be sure that no polling is done while stuff is being updated I should then change the code to only restart the timer on the callback of the ajax request instead of at the end of the timer callback. Is that what you meant by it?

    This still does not take into account any processing on Girder side... any ideas on that? Can it even be solved on the client side?
    Using: Win7 MCE, Girder, xPL, RFXcom, HomeEasy

    http://www.thijsschreijer.nl

  5. #5
    Join Date
    Oct 2005
    Posts
    307

    Default

    I just want to make you and anyone else adding this kind of functionality aware of some of the issues I have come across. I'll give an example:

    My preamp is controlled via rs232. Like most rs232 gear, the protocol allows a query for power status. The power button on the client side is a different color when the unit is on or off. "Onclick", I change the color, stop polling, sendevent, and set a timer to restart polling. The timer is long enough that the preamp should have had time to power on or off and update power status to Girder. When polling resumes, ALL 2 way button status/colors are updated every second. That way if a second client changes the status or the preamp simply didn't respond to the command - ALL clients know. I change the color initially "onclick", because the user needs feedback and that is what you would expect to happen. It may seam overly complicated (my volume control is at least 4x more involved...), but for me this method provides the best functionality I have found to date.

    A 1000ms polling interval may seam too often to someone thinking about adding this functionality, but anything more you will notice a physical change (like the lights dimming) before the client reacts. The delay will make the client feel like a cheap add on vs. an integrated system.

    I also only use one repeating client side polling function and request/process return data based on what is going on. Some portions of my lighting system control have trouble with the 1000ms interval, so I just have a counter in the timer that resets every 4th cycle for that portion. I only have one actual .lhtml page that has layers of hidden div tags for my different devices...
    Last edited by shaun5; May 15th, 2011 at 09:31 AM.

  6. #6
    Join Date
    Jul 2007
    Location
    Netherlands
    Posts
    370

    Default

    Thanks for the feedback, I already ran into the update cycle myself, click to turn light on (button selected, changes color), incedentally the poll immediately follows, (unselecting the button again, because the light didn't switch yet), meanwhile the light actually switches, at next poll the button gets selected again.
    So I made some adjustments, now the timer gets restarted not at the end of the timer callback, but at the end of the 'Update' callback (the client code that executes when some value actually changed). This allowed me to let the 'Update' function optionally return the time for the next poll interval. So if a regular poll goes every second, returning 3000, will have a 3 second poll interval (once), enough to make the Girder side do what it needs to do. Additionally added a Resume method (next to the Stop method), so the Updater can be stopped and then resumed again.

    I also updated the code to only use JSON as you suggested, made a change to your .lhtml file though. Check the zip, I added a "type (v) == 'table' " check to the getfield function to prevent some nasty errors when requested values do not exist or are non-tables.

    The function GetLuaValue will get a single variable value, table or multiple values and returns it as regular javascript variables/objects/arrays, it adds some processing of the results on top of the GetLuaValuaAsJSON, which will simply return the JSON string (easy to compare for changes)

    Regarding the updates and multiple clients; I don't know whether you're familiar with the UPnP protocol. Its a bit daunting to get into, but its a rather simple concept. Each device publishes 'state variables' (which can, but don't need to be, evented) and several methods to manipulate the device (and hence its state variables). What they came up with to solve the latency issue is using two variables for each value. For example the Dimming service defines LoadLevelTarget and LoadLevelStatus, the target can be set using the SetLoadLevelTarget method and the device will then initiate the change. Once complete the LoadLevelStatus value will change (which is evented) and hence clients will be informed.

    I documented the use in the code, so check the 'girder.js' file in the zip on how to use.
    Last edited by Tieske8; May 20th, 2011 at 01:23 AM. Reason: removed attachment (updated version in another post)
    Using: Win7 MCE, Girder, xPL, RFXcom, HomeEasy

    http://www.thijsschreijer.nl

  7. #7
    Join Date
    Jul 2007
    Location
    Netherlands
    Posts
    370

    Default

    I had a logic error there, the return value from the 'update' callback is only usefull for an extra delay in polling after a server-side change (detected after a poll), but can't be used with a client-side change (eg. button click, etc.). Hence I added a Delay method that can be called upon a client-side change.
    Attached Files Attached Files
    Using: Win7 MCE, Girder, xPL, RFXcom, HomeEasy

    http://www.thijsschreijer.nl

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •