Fast PI Vision symbol using Web Sockets (Channels) - PI Web API

Blog Post created by wpribula on Jun 6, 2017

I got an request to map possibility of creating the custom symbol for PI Vision which will be updated more frequently than each 5 seconds.

First I created value symbol with Web Sockets (Channels). Channels are feature in PI Web API which allows you to sign up for points updates and receive updates.

I took value symbol from GitHub and changed it little bit.


I erased function on onDataUpdate as this will not be used. You still need to keep this function empty as symbol requires it.

this.onDataUpdate = dataUpdate;

function dataUpdate(data) { }


Then I created Web Socket and assigned it function which is run when new message (data) are received.

var socket = new WebSocket("wss://localhost:4434/piwebapi/streams/P0u_Oxy1F8QE6Bw15TlA0e9AVEgAAAVy1TUlYzXENEVDE1OC5GQVNU/channel");
socket.onmessage = SocketMessage;

WebID is hardcoded here. However I will show how to receive it using PI Web API.


Here is function for processing Web Socket message:

         function SocketMessage(event) {
            var msg = JSON.parse(event.data);
            var time = new Date(msg.Items[0].Items[0].Timestamp);
            var value = msg.Items[0].Items[0].Value
            var name = msg.Items[0].Name
            scope.value = value; 
            scope.time = time; 
            scope.label = name;

Web Socket can send more than one value, however I would like to have the newest one, so I used index 0.

This is enough to have working fast Value Symbol, updated as fast as it is possible to receive data from Web Sockets.


Now how to find WebID. I created function for that. I need to search in both in Attributes and in PI Points so it is why there are two parts. I am using PI Web API HTTP request to search by path.

function createURLs(data){
            if (data){
                path = data.Data[0].Path;
                if (path){
                    urlP = piWebAPI + '/points?path=' + path;
                    urlA = piWebAPI + '/attributes?path=' + path;                               
                var httpRequestPIPoint = new XMLHttpRequest();
                httpRequestPIPoint.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                        var attribute = JSON.parse(this.responseText);
                        if (attribute.WebId){
                            WebID = attribute.WebId
                httpRequestPIPoint.open("GET",urlP, true);
                httpRequestPIPoint.withCredentials = true;  
                var httpRequestAttribute = new XMLHttpRequest();
                httpRequestAttribute.withCredentials  = true;
                httpRequestAttribute.onreadystatechange = function() {
                    if (this.readyState == 4 && this.status == 200) {
                        var pipoint = JSON.parse(this.responseText);
                        if (pipoint.WebId){
                            WebID = pipoint.WebId
                httpRequestAttribute.open("GET",urlA, true);
                httpRequestAttribute.withCredentials = true;  
                if (WebID){
                    url = piWebAPI + '/streams/' + WebID + '/plot?starttime=' + '*-' + timeRange + 's' + '&endtime=' + '*';
                    wssurl = 'wss' + piWebAPI.substring(5,piWebAPI.length) + '/streamsets/channel?includeInitialValues=true&webId=' + WebID;


So this is all. I finished my project modifying trend symbol from GitHub using both HTTP request for plot values and Channels to receive fast values at the end of the trend. However this is topic for the another post.