Skip to content

larsgk/web-thermometer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

title published description tags cover_image published_at
Creating a Web Thermometer
true
Learn how to build a web thermometer with Web Bluetooth and Web Components
WebComponents, WebBluetooth, Fugu
2023-08-11 00:15 +0000

Spiderman has joined some LEGO spacemen in a quest to web enable a BLE GATT temperature sensor and display the readings on their 1x1cm brick display...

While they're working on that, I'll share what's under the hood :)

Temperature Sensor in Thingy:52

The Thingy:52 by Nordic Semiconductor has a lot of built-in sensors (temperature, humidity, pressure, air quality, color, accelerometer, gyroscope, and more).

First, switch it on:

Switching on Thingy52

In our case, we are interested in reading values from the temperature sensor, so let's take a look in the documentation for the device:

Thingy52 GATT Temperature

Note: The xxxx in the base UUID should be replaced with numbers from the same column for service and characteristic(s).

From this, we can see two 128bit UUIDs we need:

  • ef680200-9b35-4933-9b10-52ffa9740042 - the "Weather station service"
  • ef680201-9b35-4933-9b10-52ffa9740042 - the "Temperature characteristic"

It's also a good idea to fetch the battery level, which follows the officially assigned 16bit UUID for battery service:

GATT BatteryService

Connecting to the Thingy:52 from a web application is quite easy, just remember to list the services that might be required for your app in the list of optionalServices:

const THINGY_CONFIGURATION_SERVICE_UUID = 'ef680100-9b35-4933-9b10-52ffa9740042';
const WEATHER_STATION_SERVICE_UUID      = 'ef680200-9b35-4933-9b10-52ffa9740042';
...
const device = await navigator.bluetooth.requestDevice({
    filters: [{ services: [THINGY_CONFIGURATION_SERVICE_UUID] }],
    optionalServices: [
        'battery_service',
        WEATHER_STATION_SERVICE_UUID
    ]
});

Temperature data

The temperature data is made available under the Weather Station Service and in order to read the data, you'll need to subscribe to the temperature updates on the Temperature Characteristic:

const TEMPERATURE_CHARACTERISTIC_UUID   = 'ef680201-9b35-4933-9b10-52ffa9740042';
...
async #startThermometerNotifications(server) {
    const service = await server.getPrimaryService(WEATHER_STATION_SERVICE_UUID);
    const characteristic = await service.getCharacteristic(TEMPERATURE_CHARACTERISTIC_UUID);
    characteristic.addEventListener('characteristicvaluechanged', this.#onThermometerChange.bind(this));
    return characteristic.startNotifications();
}

Whenever there is an update, read out the values:

_onThermometerChange(event) {
    const target = event.target;

    const integer = target.value.getInt8(0);
    const decimal = target.value.getUint8(1);

    const celsius = Number.parseFloat(`${integer}.${decimal}`);

    const temperature = {
        celsius,
        fahrenheit: celsius * 9 / 5 + 32,
        kelvin: celsius + 273.15
    }

    this.dispatchEvent(new CustomEvent('thermometer', {
        detail: temperature
    }));
}

Thermometer Web Component

We'll need some visualization for the thermometer, and I found a very nice thermometer made in pure css by Mircea Georgescu, which will be a good base for a simple thermometer web component.

CSS Thermometer

Disclaimer: I am definitely not a CSS expert, so sorry Mircea for the hacks I made :)

For the purpose of this demo, I have hacked the linear-gradient used for the positioning of the level and the position of the temperature reading:

_handleTemperature({detail}) {
    this.#celsius.innerHTML = `${detail.celsius.toFixed(1)}°C`;
    this.#celsius.style.transform = `translateY(${-detail.celsius/2}px)`;

    const perc = 50 - (detail.celsius * 0.32);
    this.#thermometer.style.background = `linear-gradient(#fff 0%, #fff ${perc}%, #d00 ${perc}%, #d00 100%)`
}

The full source of the component is here.

Building the application

Handling the connection to the Thingy:52 will be done with a scaled down variant what I did in another post: Generic Sensors and Thingy:52. It injects a small widget in the page that handles connectivity and shows battery levels.

Besides that (the thingy52-widget), the application only consists of the new thermometer UI component:

<body>
    <thingy52-widget></thingy52-widget>
    <div class="flex-container">
        <div class="content">
            <div class="col">
                <h2>Web Thermometer</h2>
                <thermometer-ui></thermometer-ui>
            </div>
        </div>
    </div>
</body>

All working together

Reading from a distance

Web Temperature APP

Repo: https://github.com/larsgk/web-thermometer Demo: https://larsgk.github.io/web-thermometer

Feedback, requests, issue reports and PRs are very welcome!

Enjoy ;)

Releases

No releases published

Packages

No packages published