'Web Bluetooth: Can't pair BLE device with Mobile Device with Live Server VS Code extension

I'm a beginner in the Web Development world. I want to pair a BLE device (NRF52840 DK) with my mobile device through a web page. I tested an example for Web Bluetooth and it works fine on my PC as you can see on the following image:

Pairing my PC (Chrome) with a BLE device successfully

enter image description here

I did it through the popular extension Live Server on VS Code. When I tried to access to that page on my mobile (Android) using my IP and port, and pressed the button nothing happened.

Pairing my mobile (Chrome) with a BLE device unsuccessfully

enter image description here

Is there something that I'm not taking into consideration?

Here is the HTML & JS code:

<!DOCTYPE html>
<html>
    <head>
        <title>BLE WebApp</title>
    </head>
    <body>
        <form>
            <button>Connect with BLE device</button>
        </form>

        <script>
            var deviceName = 'Nordic_HRM'

            function isWebBluetoothEnabled() {
                if (!navigator.bluetooth) {
                    console.log('Web Bluetooth API is not available in this browser!')
                    return false
                }
                return true
            }

            function getDeviceInfo() {
                let chosenHeartRateService = null;
            
                console.log('Requesting Bluetooth Device...')
                navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
                .then(device => device.gatt.connect())
                .then(server => {
                    console.log("Getting HR Service…")
                    return server.getPrimaryService('heart_rate');
                })
                .then(service => {
                    chosenHeartRateService = service;
                    return Promise.all([
                        service.getCharacteristic('heart_rate_measurement')
                        .then(handleHeartRateMeasurementCharacteristic),
                    ]);
                })
            }

            function handleHeartRateMeasurementCharacteristic(characteristic) {
            return characteristic.startNotifications()
            .then(char => {
                characteristic.addEventListener('characteristicvaluechanged',
                                                onHeartRateChanged);
            });
            }

            function onHeartRateChanged(event) {
                const characteristic = event.target;
                console.log(parseHeartRate(characteristic.value));
            }

            function parseHeartRate(data) {
                const flags = data.getUint8(0);
                const rate16Bits = flags & 0x1;
                const result = {};
                let index = 1;
                if (rate16Bits) {
                    result.heartRate = data.getUint16(index, /*littleEndian=*/true);
                    index += 2;
                } else {
                    result.heartRate = data.getUint8(index);
                    index += 1;
                }
                const contactDetected = flags & 0x2;
                const contactSensorPresent = flags & 0x4;
                if (contactSensorPresent) {
                    result.contactDetected = !!contactDetected;
                }
                const energyPresent = flags & 0x8;
                if (energyPresent) {
                    result.energyExpended = data.getUint16(index, /*littleEndian=*/true);
                    index += 2;
                }
                const rrIntervalPresent = flags & 0x10;
                if (rrIntervalPresent) {
                    const rrIntervals = [];
                    for (; index + 1 < data.byteLength; index += 2) {
                    rrIntervals.push(data.getUint16(index, /*littleEndian=*/true));
                    }
                    result.rrIntervals = rrIntervals;
                }
                return result;
            }

            document.querySelector('form').addEventListener('submit', function(event) {
                event.stopPropagation()
                event.preventDefault()
            
                if (isWebBluetoothEnabled()) {
                    getDeviceInfo()
                }
            })
        </script>
    </body>
</html>


Solution 1:[1]

use mkcert to create a certificate usage:

mkcert 127.0.0.1 localhost 0.0.0.0 192.168.0.X

use the files generated to add it to settings.json file in .vscode directory (create if doesn't exist)

{
    "liveServer.settings.https": {
        "enable": true,
        "cert": "/full/path/to/file/192.168.0.108+3.pem",
        "key": "/full/path/to/file/192.168.0.108+3-key.pem",
        "passphrase": ""
    }
}

this will create a warning once due to the nature of self signed certificates, but it'll make sure almost all features of https work. The issue I faced using this method is that it is considered not secure enough to install a PWA on a local device by chrome.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Giri Priyadarshan