Jump to content
The simFlight Network Forums

Best way to make browser interface with FSUIPC?


Recommended Posts

What is the best way to make a browser web page interface with FSUIPC? So that we can easily design our own panels with buttons and information from the aircraft/simulator using HTML/CSS/Javascript? How could that be done?

It seems like it should utilize websockets since that provides two-way instant communication and the WebSocket API is supported by any modern browser. But FSUIPC doesn't have a websocket server in-built I presume... Plain requests via the HTTP protocol could be an alternative but would only be optimal for button presses...

I'm aware of WideFS button capabilities - it would be some similar to that but just done in the browser instead so that it will have many more options for layout and information. Seems with today's browsers it should be doable performance-wise and therefore an obvious feature to have.

Link to post
Share on other sites
1 hour ago, Firefly said:

What is the best way to make a browser web page interface with FSUIPC?

There is no web browser interface to FSUIPC as far as I'm aware. Please check the SDK for the available interfaces.

I guess, for example, you could write a java plug-in that runs in the browser and communicates to FSUIPC via one of the Java SDKs. Or one of the other SDKs (e.g. python) if that is supported by the browser.

There are no plans to add a HTTP or websockets interface directly to FSUIPC. 

Link to post
Share on other sites

Actually, I'll put this on my list to investigate at some point. i.e add a http (or maybe websockets) interface to FSUIPC. However, I don't expect to have time to look into this for quite some time. Any such interface would only expose reading and writing to the offset data area, as is supported by the current SDK.

John

Link to post
Share on other sites

I've been thinking about this a bit and it should actually be pretty simple to implement, so I'll add it to my 'to be implemented' list. However, with FSUIPC7 for MSFS being the priority at the moment, it will take some time before I can get around to looking at this in detail. I will implement as a plug-in dll, so I can add extra features not available in the SDK, such as a direct 'control/event' interface, not via offsets.

Also, it should be reasonably straightforward to implement as a separate process,  using one of the provided SDKs. All that is needed is to add an embedded http/websockets server, and then exposed the FSUIPC SDK functions as endpoints. The most developed/used SDK at the moment seems to be Paul Henty's .net client. Maybe @Paul Henty has already considered this?

John

Link to post
Share on other sites

Hi John,

Yes I've thought about it as I've seen some other requests for this in past but I didn't have the time for new project.

As you say, a small application that runs in the system tray that provides an http interface should be fairly straight forward. As well as the basic offset read/write I could also expose the helper classes in the DLL like accessing weather and AI traffic.

I guess the main advantage of a separate program is that it'll work with all version of FSUIPC/Flight Sims.

I'll investigate his week as I don't think it'll be too big a project and I'll report back.

Paul

Link to post
Share on other sites

Guys, that's great to hear! I really think this could be very useful and open up for a lot of possibilities - as there are a lot of people who know how to work with the web technologies but don't how to use lower level languages, do compiling and all that stuff. But simple web APIs is what is tying systems together nowadays.

Looking forward to see what you can come up with!

Link to post
Share on other sites

I have a proof of concept working.

It uses HTTP requests. I can't see any advantage in using WebSockets as FSUIPC itself does not have duplex communication. It's only one-way poll & response from client to FSUIPC.

Just to make sure I'm on the right track, and check if this this would be useful, I've posted some javascript below that I've used for testing. This runs directly in a browser, completely client-side.

It talks to the HTTP server program that is located on the flight sim PC (or can be on a different PC if connecting to the flight sim over WideFS).

The URL consists of the IP of the server and port number (setup in the server program) followed by /fsuipc/ and then the type of request you are making. e.g. to request offset data it might look like this:

 

http://localhost:2048/fsuipc/offsets

You'll make an AJAX POST request to this URL, passing a JSON stringified array of offset requests (details in the code below). Then you'll get back another JSON string containing the values which you can turn into a Javascript object to use.

Here's the Javascript for reading three offsets:

var fsuipcURL = "http://localhost:2048/fsuipc/";

function btnReadOffsetsClick(e) {
    // make a request to the sever to read offset data
    // First setup a data structure containing the offset requests

    // This is an array of offset objects. Each object contains:
    // name: used to identify the value when the response comes back (can be anything)
    // address: Hexadecimal address of the offset
    // type: the type of data in the offset. Must be:
    //       'int'   (signed integer)
    //       'uint'  (unsigned integer)
    //       'string'
    //       'float'
    // size: The size of the offset in bytes 

    offsets = [
        { name: 'avionicsMaster', address: '2E80', type: 'uint', size: 4},
        { name: 'heading', address: '0580', type: 'uint', size: 4},
        { name: 'aircraftName', address: '3D00', type: 'string', size: 256 },
    ];

    // create the URL
    var offsetsURL = fsuipcURL + "offsets";
    // create a new AJAX request object
    var xhttp = new XMLHttpRequest();

    // setup a function to execute when the data is returned
    xhttp.onreadystatechange = function () {
        showOffsetData(this);
    };
    // make the request
    xhttp.open("POST", offsetsURL, true);
    xhttp.send(JSON.stringify(offsets));
}

function showOffsetData(e) {
    // clear error display
    document.getElementById('fsuipcReadOffsets').innerHTML = '';
    var displayHTML = "";
    if (e.readyState >= 3 && e.status == 200) {
        // decode the JSON response 
        var response = JSON.parse(e.responseText);
        if (response.Success) {
            var data = response.Data;
            // display each offset value on the page
            document.getElementById('aircraftName').innerText = data['aircraftName'];
            document.getElementById('avionicsMaster').innerText = data['avionicsMaster'] > 0 ? 'ON' : 'OFF';
            // convert heading from FS units to degrees
            var headingDegrees = data['heading'] * 360 / (65536 * 65536);
            document.getElementById('headingTrue').innerText = headingDegrees.toFixed(2);
        }
        else {
            displayHTML = "Request failed with error code: " + response.ErrorCode + " " + response.ErrorMessage;
        }
    }
    else {
        displayHTML = "Error communicating with FSUIPC Web Services. ";
    }
    // set any error HTML into the div
    document.getElementById('fsuipcReadOffsets').innerHTML = displayHTML;
}

This is the result:

image.png.4259b5ec955d99146b6145035a7f3e02.png

Do you think this would work?

Thanks,

Paul

Link to post
Share on other sites

Hi Paul,

You're fast! This is great - it's exactly what I had in mind for HTTP communication. It can certainly work in a lot of scenarios - I'm just thinking that in case you for example wanted to do a gauge you would want very frequent updates, at least every 50-100 ms, and in that case there would be quite a bit of overhead in constantly opening/closing the HTTP connection and passing headers. At least theoretically that would be a concern... so that's why I was thinking of websockets. I was imagining that you could subscribe to a set of offsets which would then continually be sent back to the client at a given interval (maybe even user desired interval?). Either all the subscribed offsets could be returned, or even better, only those that have changed since last time.

I understand that FSUIPC in itself is stateless - poll and response - so this would of course require a running websocket server with some logic in it. But due to the overhead of HTTP I believe it would perform substantially better to have that websocket server continually poll FSUIPC internally than doing the polling over the HTTP protocol? Or is there something I'm missing?

Thanks,

Allan

Link to post
Share on other sites

I've got WebSockets working. Here's a quick video of real time updates every 100ms.

https://youtu.be/E6RR94O8nfs

This is the JavaScript for this page:

var fsuipcURL = "ws://127.0.0.1:2048/fsuipc";
var ws;

function btnConnectClick(e) {
    if (!ws) {
        // create a new WebSocket using the URL with the 'fsuipc' protocol.
        ws = new WebSocket(fsuipcURL, "fsuipc");

        ws.onopen = function () {
            alert("Socket Open...");
        };

        ws.onmessage = function (evt) {
            // Find out which request was responded to and process it
            var response = JSON.parse(evt.data);
            switch (response.name) {
                case 'info':
                    showInfo(response);
                    break;
                case 'offsetsTest':
                    showOffsetData(response);
                    break;
            }
        };

        ws.onclose = function () {

            // websocket is closed.
            alert("Connection is closed...");
            ws = null;
        };
    }
}

function btnInfoClick(e) {
    // make a request to the sever for info.
    request = {
        request: 'info',
        name: 'info'
    };

    if (ws) {
        ws.send(JSON.stringify(request));
    }
}

function btnReadOffsetsClick(e) {
    // make a request to the sever to read offset data
    // First setup a data structure containing the offset requests

    // This contains an array of ofset objects. Each object contains:
    // name: used to identify the value when the response comes back (can be anything)
    // address: Hexadecimal address of the offset
    // type: the type of data in the offset. Must be:
    //       'int'   (signed integer)
    //       'uint'  (unsigned integer)
    //       'string'
    //       'float'
    // size: The size of the offset in bytes 
    request = {
        request: 'offsets.read', // Tell the server to read offsets
        name: 'offsetsTest', // An ID so we can match the response
        interval: 100, // Send every 100ms - specfiy 0 for read once (no repeat).
        offsets: [
            { name: 'altitude', address: '0570', type: 'int', size: 8 },
            { name: 'avionicsMaster', address: '2E80', type: 'uint', size: 4 },
            { name: 'heading', address: '0580', type: 'uint', size: 4 },
            { name: 'aircraftName', address: '3D00', type: 'string', size: 256 },
        ]
    };

    if (ws) {
        ws.send(JSON.stringify(request));
    }
}

function showInfo(response) {
    if (response.success) {
        var data = response.data;
        // Create a table to display the data
        displayHTML = '<table>';
        // enumerate each returned data item and add as a row to the table
        for (var propertyName in data) {
            displayHTML += '<tr>';
            displayHTML += '<td>' + propertyName + '</td><td>' + data[propertyName] + '</td>';
            displayHTML += '</tr>';
        }
        displayHTML += "</table>";
    }
    else {
        displayHTML = "Request failed with error code: " + response.errorCode + "&nbsp;" + response.errorMessage;
    }
    document.getElementById('fsuipcInfo').innerHTML = displayHTML;
}

function showOffsetData(response) {
    // clear error display
    document.getElementById('fsuipcReadOffsets').innerHTML = '';
    var displayHTML = "";
    
    if (response.success) {
        var data = response.data;
        // display each offset value on the page
        document.getElementById('aircraftName').innerText = data['aircraftName'];
        document.getElementById('avionicsMaster').innerText = data['avionicsMaster'] > 0 ? 'ON' : 'OFF';
        // convert heading from FS units to degrees
        var headingDegrees = data['heading'] * 360 / (65536 * 65536);
        document.getElementById('headingTrue').innerText = headingDegrees.toFixed(0);
        // convert altitude metres to feet
        var altitudeFeet = data['altitude'] / (65535 * 65535) * 3.28084;
        document.getElementById('altitude').innerText = altitudeFeet.toFixed(0);
    }
    else {
        displayHTML = "Request failed with error code: " + response.errorCode + "&nbsp;" + response.errorMessage;
    }

    // set any error HTML into the div
    document.getElementById('fsuipcReadOffsets').innerHTML = displayHTML;
}

Is that more like what you had in mind?

If so, I'll get it to a stable version with offset read and write so you can test it. 

Let me know if you have any other comments or suggestions.

Paul 

  • Like 2
Link to post
Share on other sites

I have reviewed the code now - it looks terrific! Good to see you have the "name" ID in there so that we can match the response in case we need to use it a-la-HTTP. Will it only send a message with offset values if there is a change in at least one of them, or what do you think about that? Could save a lot of network traffic for values that rarely change... eg. if you wanted to monitor taxi lights for example...

Will you be able to subscribe to multiple offsets.read requests with different intervals or only one? Just curious as I'm not sure if that would be needed... I guess the same reasoning goes for whether or not one can stop receiving messages for something you have previously subscribed to...

Link to post
Share on other sites
Quote

Will it only send a message with offset values if there is a change in at least one of them, or what do you think about that?

That's a good idea. I'll put that in.

Quote

Will you be able to subscribe to multiple offsets.read requests ...

Yes, you can set up multiple read requests each with their own interval. I think this is useful as not all information would need to be read at the same rate. It also makes sense to split the offsets up into  logical groups, e.g. lights, engines etc. especially if the request only sends data if one of the offsets has changed.

I'll be adding an 'offset.stop' so you can stop the request if you don't need it anymore.

Paul

  • Like 1
Link to post
Share on other sites

Excellent stuff.

I assume you are thinking of sending all values when at least one changes... Wondering if it will make sense to even only send the values that have actually changed. Would save some bandwidth but would require client-side logic to check which ones are present.

Link to post
Share on other sites

Yeah I was thinking about that.

Probably the best thing is to make it an option on the request. That way the user can decide if they want to check which values are present or not.

It would also be a good way of knowing which values have changed. Some applications like flight recorders are mainly based on logging values changing. You would need to test for the change anyway so checking for the value to be present in the return message would be no less inconvenient.

For people writing gauge type applications, they just wouldn't enable the option and get all value from the request back all the time (if at least one has changed).

Paul 

  • Like 1
Link to post
Share on other sites

Hi, I'm just joining this thread as it is something I have been developing myself ( http/REST Bridge to FSUIPC using DLL)  but rather than developing something that is already being worked on (and probably better!) I thought see if I can help or contribute in anyway (even if by testing).

The reason behind this is a software I have developed which requires to send/receive to MSFS over http or web sockets (best option).

Is there a working version I could test by any chance?

Thanks

Andy

Edited by Andy Gilbert
Link to post
Share on other sites

Hi Andy,

I have an initial version working well. It just does basic reading and writing of offsets at the moment. More will be added in the future to expose the all helper functions of the .NET Client DLL.

I'm about half way through the documentation. I'm hoping to release it for beta testing early next week. I'll post again in this thread when it's ready.

Your help with testing and any feedback will be very welcome.

Paul

Link to post
Share on other sites
18 minutes ago, Paul Henty said:

Hi Andy,

I have an initial version working well. It just does basic reading and writing of offsets at the moment. More will be added in the future to expose the all helper functions of the .NET Client DLL.

I'm about half way through the documentation. I'm hoping to release it for beta testing early next week. I'll post again in this thread when it's ready.

Your help with testing and any feedback will be very welcome.

Paul

Sounds great, look forward to it. Happy to help.

Andy

Link to post
Share on other sites

Hi Everyone,

I have the first beta version of the WebSocket Server ready for testing. If you'd like to download it and test it out, please visit:

http://fsuipcwebsockets.paulhenty.com/

On the website you can download the server program and read all the documentation. If you have the server running locally while you are browsing the site, there are working examples on some of the pages.

For the server program you'll need the .NET Framework Version 4.6.2 or higher. If you are keeping your Windows up-to-date it should already be installed.

Paul 

 

Edited by Paul Henty
URL Corrected
  • Like 1
Link to post
Share on other sites
23 minutes ago, Paul Henty said:

I have the first beta version of the WebSocket Server ready for testing. If you'd like to download it and test it out, please visit:

http://fsuipcwebsocketserver/paulhenty.com/

Thanks Paul! I'll add this to the FSUIPC6 installer at some point as another optional 'extra'. It might also be worth adding functionality directly in FSUIPC to start/stop the http server (when installed), but that can come later.

Btw, can you check the link address - I get a  'This site can’t be reached' message!

 

Link to post
Share on other sites

Great stuff Paul, will have a play. It would be nice if this did get bundled with FSUIPC and can be controlled from FSCUIPC

I am developing some software that communicates with my own bridge software and want to "offer" the ability for users to use FSUIPC if preferred (and for beneficial reasons) however, that means either adding the option to my end user software or to my bridge app, which will then connect to this which is turn talks to FSCIPC which then talks to MSFS! 😱

Obviously not an issue for you guys, this is something I am to try and resolve, just thinking of ways to cut down the amount of separate downloads required and to be run and managed at once.

Andy

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use. Guidelines Privacy Policy We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.