I will guide you to build an application that can read Thingy:52 data via web BLE.
Story
In this blog, we'll explore how to create a web-based temperature monitor using the Thingy:52 sensor and the Web Bluetooth API. This project will guide you through setting up the hardware, connecting it to your web application via Bluetooth, and displaying the real-time temperature data on a web chart. Let's get started!
Components Required
Thingy:52Computer or mobile device with Bluetooth supportA web server to host your web application (optional)
Get PCBs for Your Projects Manufactured
You must check out PCBWAY for ordering PCBs online for cheap!
You get 10 good-quality PCBs manufactured and shipped to your doorstep for cheap. You will also get a discount on shipping on your first order. Upload your Gerber files onto PCBWAY to get them manufactured with good quality and quick turnaround time. PCBWay now could provide a complete product solution, from design to enclosure production. Check out their online Gerber viewer function. With reward points, you can get free stuff from their gift shop. Also, check out this useful blog on PCBWay Plugin for KiCad from here. Using this plugin, you can directly order PCBs in just one click after completing your design in KiCad.
Setting Up Thingy:52
Thingy:52 is a compact, versatile sensor platform designed for IoT applications.
It features various sensors, including temperature, humidity, air quality, and more. Before diving into the code, ensure your Thingy:52 is powered on and ready for Bluetooth connections.
Creating the Web Application
1. Setting Up the HTML Structure
Create an HTML file to serve as the structure of your web application. This file will include the necessary elements for connecting to Thingy:52 and displaying the temperature data.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Thingy:52 Temperature Monitor</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<h1>Thingy:52 Temperature Monitor</h1>
<button id="connectButton">Connect</button>
<canvas id="temperatureChart" width="400" height="200"></canvas>
<p id="temperatureData">Temperature: --°C</p>
<script src="main.js"></script>
</body>
</html>
2. Adding the JavaScript Logic
Next, create a JavaScript file (main.js) to handle the Bluetooth connection, read the temperature data, and update the chart.
Initialize Chart.js
First, let's initialize a line chart using Chart.js to display the temperature data.
const ctx = document.getElementById('temperatureChart').getContext('2d');
const temperatureChart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Temperature (°C)',
data: [],
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1
}]
},
options: {
scales: {
x: {
type: 'time',
time: {
unit: 'second'
}
},
y: {
beginAtZero: true
}
}
}
});
Connect to Thingy:52 via Web Bluetooth
Add the following code to handle the Bluetooth connection and read the temperature data from Thingy:52.
const connectButton = document.getElementById('connectButton');
const temperatureData = document.getElementById('temperatureData');
let thingyDevice;
let temperatureCharacteristic;
connectButton.addEventListener('click', async () => {
try {
thingyDevice = await navigator.bluetooth.requestDevice({
filters: [{ services: ['ef680200-9b35-4933-9b10-52ffa9740042'] }]
});
const server = await thingyDevice.gatt.connect();
const service = await server.getPrimaryService('ef680200-9b35-4933-9b10-52ffa9740042');
temperatureCharacteristic = await service.getCharacteristic('ef680201-9b35-4933-9b10-52ffa9740042');
temperatureCharacteristic.addEventListener('characteristicvaluechanged', handleTemperatureData);
await temperatureCharacteristic.startNotifications();
console.log('Connected to Thingy:52');
} catch (error) {
console.error('Error connecting to Thingy:52', error);
}
});
function handleTemperatureData(event) {
const value = event.target.value.getUint8(0);
const temperature = value / 10;
temperatureData.textContent = `Temperature: ${temperature}°C`;
const currentTime = new Date();
temperatureChart.data.labels.push(currentTime);
temperatureChart.data.datasets[0].data.push(temperature);
temperatureChart.update();
}
This code handles the following tasks:
Connects to the Thingy:52 device via Bluetooth.Subscribes to the temperature characteristic to receive updates.Reads and processes the temperature data.Updates the Chart.js chart with the new temperature data.
Running the Web Application
To run the web application, you can simply open the index.html file in a web browser that supports the Web Bluetooth API (e.g., Chrome, Edge).
If you're hosting the application on a web server, ensure the server supports HTTPS, as Web Bluetooth requires a secure context.
Complete Code:
Here is the complete HTML file.
Thingy:52 Temperature Monitor
:root {
--bg-primary: #1a1a1a;
--bg-secondary: #2d2d2d;
--text-primary: #ffffff;
--accent-color: #00ff9d;
--accent-hover: #00cc7d;
--error-color: #ff4444;
--gradient-start: #2d2d2d;
--gradient-end: #1a1a1a;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
transition: all 0.3s ease;
}
body {
font-family: 'Segoe UI', sans-serif;
background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
color: var(--text-primary);
padding: 2rem;
min-height: 100vh;
}
.container {
max-width: 900px;
margin: 2rem auto;
background: rgba(45, 45, 45, 0.8);
padding: 3rem;
border-radius: 1.5rem;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
backdrop-filter: blur(20px);
}
h1 {
text-align: center;
margin-bottom: 3rem;
font-size: 3rem;
letter-spacing: 2px;
background: linear-gradient(45deg, var(--accent-color), #00ffff, var(--accent-color));
background-size: 200% auto;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: gradient 3s ease infinite;
}
.chart-container {
height: 450px;
margin: 3rem 0;
padding: 1.5rem;
background: rgba(0, 0, 0, 0.3);
border-radius: 1.5rem;
border: 2px solid rgba(255, 255, 255, 0.1);
transition: all 0.4s ease;
}
.chart-container:hover {
transform: translateY(-5px);
}
button {
padding: 0.8rem 1.5rem;
background: linear-gradient(45deg, var(--accent-color), #00ffff);
color: var(--bg-primary);
border: none;
border-radius: 0.5rem;
cursor: pointer;
font-size: 1rem;
font-weight: bold;
display: block;
margin: 0 auto;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 255, 157, 0.2);
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 255, 157, 0.3);
}
button:active {
transform: translateY(0);
}
.status {
font-size: 1.2rem;
padding: 1.2rem;
margin: 2rem 0;
border-radius: 0.5rem;
text-align: center;
background: rgba(0, 0, 0, 0.3);
border: none;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
.error {
background: rgba(255, 68, 68, 0.2);
border-color: var(--error-color);
animation: shake 0.5s ease-in-out;
}
@keyframes gradient {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
Thingy:52 Temperature Monitor
Connect to Thingy:52
Ready to connect
const THINGY_SERVICE_UUID = 'ef680200-9b35-4933-9b10-52ffa9740042';
const TEMP_CHARACTERISTIC_UUID = 'ef680201-9b35-4933-9b10-52ffa9740042';
let device = null;
let tempChart = null;
const MAX_DATA_POINTS = 10;
const UPDATE_INTERVAL = 2000; // 5 seconds
let lastUpdateTime = 0;
function initChart() {
const ctx = document.getElementById('tempChart').getContext('2d');
const style = getComputedStyle(document.documentElement);
const accentColor = style.getPropertyValue('--accent-color').trim();
const textColor = style.getPropertyValue('--text-primary').trim();
tempChart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Temperature °C',
data: [],
borderColor: accentColor,
backgroundColor: 'rgba(0, 255, 157, 0.1)',
tension: 0.4,
borderWidth: 3,
pointRadius: 6,
pointBackgroundColor: accentColor,
pointHoverRadius: 8,
pointHoverBorderWidth: 3,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
animations: {
tension: {
duration: 1000,
easing: 'ease-in-out'
}
},
plugins: {
legend: {
labels: {
color: textColor,
font: {
size: 16,
weight: 'bold'
},
padding: 20
}
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0.8)',
titleFont: {
size: 16
},
bodyFont: {
size: 14
},
padding: 12
}
},
scales: {
y: {
beginAtZero: false,
ticks: {
color: textColor,
font: {
size: 14
},
padding: 10
},
grid: {
color: 'rgba(255, 255, 255, 0.1)'
}
},
x: {
ticks: {
color: textColor,
font: {
size: 14
},
padding: 10
},
grid: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
}
}
});
}
function updateChart(temperature) {
const timeString = new Date().toLocaleTimeString();
tempChart.data.labels.push(timeString);
tempChart.data.datasets[0].data.push(temperature);
if (tempChart.data.labels.length > MAX_DATA_POINTS) {
tempChart.data.labels.shift();
tempChart.data.datasets[0].data.shift();
}
tempChart.update('none');
}
function parseTemperature(value) {
const dataView = new DataView(value.buffer);
const integer = dataView.getInt8(0);
const decimal = dataView.getUint8(1);
return integer + decimal/100.0;
}
function updateTemperatureDisplay(temperature) {
const statusEl = document.getElementById('statusText');
const tempStr = temperature.toFixed(1);
statusEl.innerHTML = `
${tempStr}°C
Last updated: ${new Date().toLocaleTimeString()}
`;
}
async function connectToThingy() {
try {
device = await navigator.bluetooth.requestDevice({
filters: [{ namePrefix: 'Thingy' }],
optionalServices: [THINGY_SERVICE_UUID]
});
const server = await device.gatt.connect();
const service = await server.getPrimaryService(THINGY_SERVICE_UUID);
const characteristic = await service.getCharacteristic(TEMP_CHARACTERISTIC_UUID);
await characteristic.startNotifications();
characteristic.addEventListener('characteristicvaluechanged', (event) => {
const now = Date.now();
if (now - lastUpdateTime >= UPDATE_INTERVAL) {
const temperature = parseTemperature(event.target.value);
updateChart(temperature);
updateTemperatureDisplay(temperature);
lastUpdateTime = now;
}
});
document.getElementById('connectButton').textContent = 'Disconnect';
document.getElementById('statusText').textContent = 'Connected';
} catch (error) {
console.error('Error:', error);
document.getElementById('statusText').textContent = error.message;
document.getElementById('statusText').classList.add('error');
}
}
window.addEventListener('load', () => {
initChart();
document.getElementById('connectButton').addEventListener('click', async () => {
if (device?.gatt?.connected) {
await device.gatt.disconnect();
document.getElementById('connectButton').textContent = 'Connect to Thingy:52';
document.getElementById('statusText').textContent = 'Disconnected';
} else {
await connectToThingy();
}
});
});
Conclusion
This blog demonstrated how to create a web-based temperature monitor using the Thingy:52 sensor and the Web Bluetooth API. This project showcases the power of Web Bluetooth for building real-time, interactive IoT applications. You can further enhance this project by adding features such as data logging, and alerts, or integrating other sensors from the Thingy:52 platform. Happy coding
