paint-brush
How to Stream Real-Time Heart Rate with WebSocketsby@kyriakos
904 reads
904 reads

How to Stream Real-Time Heart Rate with WebSockets

by Kyriakos EleftheriouDecember 22nd, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

WebSockets are a technology for bidirectional, real-time communication between a web browser and a server. They allow for full-duplex communication, meaning that the server and the client can both send and receive data simultaneously. The WebSocket protocol uses the HTTP protocol to initiate the connection, but once the connection is established, the WebSocket Protocol takes over. This allows for efficient and fast communication between server and client. We developed an API that makes it easy to stream heart rate data from wearables and sensors.
featured image - How to Stream Real-Time Heart Rate with WebSockets
Kyriakos Eleftheriou HackerNoon profile picture

We developed an API that makes it easy to stream heart rate data from wearables and sensors and realized that there’s very little guidance on how to use WebSockets, so here’s a brief guide:


First of all, WebSockets is a technology for bidirectional, real-time communication between a web browser and a server. They allow for full-duplex communication, meaning that the server and the client can both send and receive data simultaneously.


WebSockets are created using the WebSocket protocol, which is a standard protocol for establishing a persistent, bi-directional connection between a web client and a server.


The WebSocket protocol uses the HTTP protocol to initiate the connection, but once the connection is established, the WebSocket protocol takes over and allows for full-duplex communication.


Here are the steps for how WebSockets work:


  1. The web client sends an HTTP request to the server to upgrade the connection to a WebSocket connection. This request includes a special Upgrade header that indicates that the client wants to use the WebSocket protocol.
  2. The server receives the HTTP request and checks the Upgrade header. If the Upgrade header is present and indicates that the client wants to use the WebSocket protocol, the server sends an HTTP response that includes an Upgrade header to confirm the switch to the WebSocket protocol.
  3. Once the connection has been upgraded to a WebSocket connection, the server and the client can send and receive data. This allows for real-time, bi-directional communication between the server and the client.
  4. The server and the client can send and receive data asynchronously without the need for the client to poll the server for new data continuously. This allows for efficient and fast communication between the server and the client.
  5. To end the WebSocket connection, either the server or the client can send a unique close frame to initiate the closing of the connection. Once the connection has been closed, the server and the client can no longer send or receive data through the WebSocket connection.


Maintaining the connection and establishing a handshake:


const WebSocket = require("ws")

const WS_CONNECTION = "wss://ws.tryterra.co/connect";

function initWS(token) {
    const socket = new WebSocket(WS_CONNECTION)

    var expectingHeartBeatAck = false

    socket.addEventListener('open', function (event) {
        console.log("Connection Established");
    })

    function heartBeat(){   
        if(!expectingHeartBeatAck){
            var heartBeatPayload = JSON.stringify({
                "op": 0
            })
            socket.send(heartBeatPayload)
            console.log("↑  " + heartBeatPayload)
            expectingHeartBeatAck = true
        }
        else socket.close()
    }
    
    socket.addEventListener('message', function (event) {
        console.log("↓  " + event.data);
        var message = JSON.parse(event.data)
        if (message["op"] == 2){
            heartBeat()
            setInterval(heartBeat, message["d"]["heartbeat_interval"])
            var payload = JSON.stringify(
                {
                    "op": 3,
                    "d": {
                        "token": token,
                        "type": 1  //0  for user, 1 for developer
                    }
                }
            )
            socket.send(payload)
        }
        if (message["op"] == 1){
            expectingHeartBeatAck = false
        }
    })


    socket.addEventListener('close', function (event) {
        console.log('close');
        console.log(event.reason);
    })


    socket.addEventListener('error', function (event) {
        console.log('error');
        console.log(event);
    })
}



Running the function:


initWs(token)


Here’s what happens:


Connection Established
↓  {"op":2,"d":{"heartbeat_interval":40000}}
↑  {"op":0}
↑  {"op":3,"d":{"token":"dGVzdGluZ0VsbGlvdHQ.MU1fASa1nR9EpQWQx67xIN7veTFKFwudaB4HbN4kw9A","type":1}}
↓  {"op":1}
↓  {"op":4}
↑  {"op":0}
↓  {"op":1}
↓  {"op":5,"d":{"ts":"2022-06-01T14:47:08.055Z","val":86.0},"uid":"100b370c-d2be-42a2-b757-01fc85c41031","seq":12254,"t":"HEART_RATE"}
↓  {"op":5,"d":{"ts":"2022-06-01T14:47:08.701Z","val":87.0},"uid":"100b370c-d2be-42a2-b757-01fc85c41031","seq":12255,"t":"HEART_RATE"}
↓  {"op":5,"d":{"ts":"2022-06-01T14:47:09.698Z","val":86.0},"uid":"100b370c-d2be-42a2-b757-01fc85c41031","seq":12256,"t":"HEART_RATE"}
↓  {"op":5,"d":{"ts":"2022-06-01T14:47:11.041Z","val":86.0},"uid":"100b370c-d2be-42a2-b757-01fc85c41031","seq":12257,"t":"HEART_RATE"}
↓  {"op":5,"d":{"ts":"2022-06-01T14:47:12.049Z","val":86.0},"uid":"100b370c-d2be-42a2-b757-01fc85c41031","seq":12258,"t":"HEART_RATE"}



Each WebSocket server has its protocol and may not adhere to the same one. However, the idea is always the same: you initiate the connection, complete the handshake, and do something “on message, on open, and on close.”