Skip to content

Instantly share code, notes, and snippets.

@RajivCodeLab
Created April 17, 2024 08:20
Show Gist options
  • Save RajivCodeLab/3485549df9427d4fd1c387896a5158ae to your computer and use it in GitHub Desktop.
Save RajivCodeLab/3485549df9427d4fd1c387896a5158ae to your computer and use it in GitHub Desktop.
WebSocket on Raspberry Pi Pico W using (MicroDot)
<!DOCTYPE html>
<html>
<head>
<title>Live Temperature Dashboard</title>
<meta charset="UTF-8">
<!-- Include Chart.js library -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
@import url(https://fonts.googleapis.com/css?family=Open+Sans:700,300);
.frame {
position: absolute;
top: 50%;
left: 7%;
width: 400px;
height: 400px;
margin-top: -200px;
margin-left: -200px;
border-radius: 2px;
overflow: hidden;
background: #222;
color: #333;
font-family: 'Open Sans', Helvetica, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: #222;
}
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
}
.temparature-meter__container {
position: relative;
height: 200px;
width: 200px;
border-radius: 200px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .07);
border: solid 10px #fff;
overflow: hidden;
&:after {
position: absolute;
content: "";
height: 120px;
width: 120px;
background-color: #fff;
z-index: 0;
transform: rotate(45deg);
bottom: -40px;
left: 40px;
z-index: 1;
}
}
.temparature-meter__inner {
display: flex;
text-align: center;
height: 100%;
width: 100%;
border-radius: 100%;
box-shadow: inset 0 0 10px rgba(0, 0, 0, .4);
background: linear-gradient(to right, #148d04 0%,#f52c3d 100%);
overflow: hidden;
.temparature-meter__inner-ring {
cursor: pointer;
position: relative;
margin: auto;
display: flex;
flex-direction: column;
justify-content: center;
height: 130px;
width: 130px;
background-color: #fff;
border-radius: 100%;
box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.2);
z-index: 9;
&:after {
content: "";
position: absolute;
width: 1px;
height: 50%;
background-image: linear-gradient(#148d04 15px, transparent 0);
top: 0;
left: 50%;
transform-origin: bottom;
transform: rotatez(-35deg);
transition: all 0.8s ease-in-out;
}
&:hover:after {
transform: rotatez(-20deg);
}
.temparature-count {
display: block;
position: absolute;
width: 100%;
text-align: center;
transition: all 0.8s ease-in-out;
&.c2 {
opacity: 0;
transform: translatex(50px) scale(0.5);
}
}
&:hover {
.c1 {
opacity: 0;
transform: translatex(-50px) scale(0.5);
}
.c2 {
opacity: 1;
transform: translatex(0) scale(1);
}
}
}
.temparature-inside {
position: relative;
font-size: 50px;
display: inline-block;
letter-spacing: -5px;
font-weight: 500;
color: #148d04;
height: 58px;
.temperature-sup {
font-size: 20px;
position: absolute;
position: relative;
right: -45px;
top: -30px;
}
}
.temparature-outside {
font-size: 13px;
}
.temparature-meter__inner-label {
font-size: 13px;
}
}
body {
background-color: #222;
color: #fff;
font-family: Arial, sans-serif;
}
h1 {
text-align: center;
color: #148d04;
}
.chart-container {
margin-left: 300px;
margin-top:20px;
text-align:center;
height: 70vh; /* Set the height to half of the viewport height */
}
header {
background-color: #333;
color: #fff;
padding: 10px;
text-align: center;
/* Remove default margin */
display: flex; /* Use flexbox to align items */
align-items: center; /* Vertically center items */
}
#temperature {
text-align: center;
font-size: 24px;
margin-bottom: 20px;
margin-top:30px;
}
canvas {
text-align:center;
width:100%;
}
.logo {
width: 50px; /* Adjust the width of the logo */
height: auto; /* Maintain aspect ratio */
margin-right: 10px; /* Add some space between logo and title */
margin-left: 35px;
}
</style>
</head>
<body>
<header>
<img src="data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3MS42OSA5Mi4xMDkiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojNDZhZjRifS5jbHMtMntmaWxsOiNjZDIzNTV9PC9zdHlsZT48L2RlZnM+PHBhdGggZD0iTTcxLjUzIDUyLjk4Yy0uNDEtNC4yNjYtMi4zMjgtOC4wNi01LjA1MS0xMC4wNmExMi40NzMgMTIuNDczIDAgMCAwLTIuMzQ0LTQuNTYgMTMuOTg2IDEzLjk4NiAwIDAgMC00Ljk3Ny05LjQgNS4yNTUgNS4yNTUgMCAwIDAgMS4xNTItMS40MDVjMy4zMDYtMS40NzYgNS42MzYtNC41NzYgNS45MDctNi44ODFhOS4wNDUgOS4wNDUgMCAwIDAgMi44NTctNS45MjUgNS42NjUgNS42NjUgMCAwIDAtLjUwNi0yLjY2NyA1LjA2OCA1LjA2OCAwIDAgMCAxLjMyMS01LjIzYy0uOTg3LTIuODYtNC40NDQtNC43MTUtOS4wODgtNC45MTJBNy4zMiA3LjMyIDAgMCAwIDU1Ljc0LjIwOGExMS42OTkgMTEuNjk5IDAgMCAwLTIuNzMyLjMzNkE2LjIxOSA2LjIxOSAwIDAgMCA1MC4zMjIgMCAxMC41MSAxMC41MSAwIDAgMCA0NS4yIDEuMzk3YTQuNzA5IDQuNzA5IDAgMCAwLS42MTgtLjA0Yy0yLjMwNiAwLTQuNjEgMS41ODgtNS43NzkgMi41MzVhMTcuNTIgMTcuNTIgMCAwIDAtMy4wMzcgMy4xNjQgMTcuNTI0IDE3LjUyNCAwIDAgMC0zLjAzNy0zLjE2NGMtMS4xNjktLjk0Ny0zLjQ3My0yLjUzNS01Ljc3OS0yLjUzNmE0LjcxMiA0LjcxMiAwIDAgMC0uNjE4LjA0QTEwLjUxMiAxMC41MTIgMCAwIDAgMjEuMjA4IDBhNi4yMiA2LjIyIDAgMCAwLTIuNjg2LjU0NEExMS42OTggMTEuNjk4IDAgMCAwIDE1Ljc5LjIwOGE3LjMyIDcuMzIgMCAwIDAtNS4wNiAxLjczMmMtNC42NDUuMTk3LTguMTAzIDIuMDUzLTkuMDkgNC45MTJhNS4wNjggNS4wNjggMCAwIDAgMS4zMjEgNS4yMyA1LjY2NyA1LjY2NyAwIDAgMC0uNTA1IDIuNjY3IDkuMDQ0IDkuMDQ0IDAgMCAwIDIuODU3IDUuOTI1Yy4yNyAyLjMwNSAyLjYwMSA1LjQwNSA1LjkwNiA2Ljg4MmE1LjI1MyA1LjI1MyAwIDAgMCAxLjE1MiAxLjQwMyAxMy45ODcgMTMuOTg3IDAgMCAwLTQuOTc2IDkuNDAyIDEyLjQ3MSAxMi40NzEgMCAwIDAtMi4zNDQgNC41NTlDMi4zMjggNDQuOTIuNDEgNDguNzE0IDAgNTIuOThjLS40MDggNC4yNC43NTUgOC4xOTggMy4xMjMgMTAuNzA1YTE1LjE1OCAxNS4xNTggMCAwIDAgMi41NzQgNS45MTFBMTUuMzgzIDE1LjM4MyAwIDAgMCA5LjU4IDc4LjU3YTE1Ljg5NyAxNS44OTcgMCAwIDAgOC41NjQgNS4wODkgMjAuNzMzIDIwLjczMyAwIDAgMCA2Ljg0OCA0LjI0IDE1Ljg4OCAxNS44ODggMCAwIDAgMjEuNTQ2IDAgMjAuNzM4IDIwLjczOCAwIDAgMCA2Ljg0OC00LjI0IDE1Ljg5NyAxNS44OTcgMCAwIDAgOC41NjMtNS4wODkgMTUuMzgzIDE1LjM4MyAwIDAgMCAzLjg4NC04Ljk3MiAxNS4xNTQgMTUuMTU0IDAgMCAwIDIuNTc0LTUuOTEyYzIuMzY3LTIuNTA3IDMuNTMtNi40NjUgMy4xMjMtMTAuNzA1WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLjA4IC4wMDIpIi8+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNDQuNDQ2IDYuMThhLjM2Ni4zNjYgMCAwIDEgLjQ2NS4zOWMtLjExNiAxLjA5NS41NDcuOTU3LjcwMy43NjJhNS43MzggNS43MzggMCAwIDEgNS4xODktMi40ODkuMzY2LjM2NiAwIDAgMSAuMjUuNTljLS42NS45NjUuMDUgMS4xNDguMzEuOTc1IDIuNjU0LTEuNjYgNS4xODctMS42NjMgNi4xNi0uOTY2YS4zNjYuMzY2IDAgMCAxIC4wMjEuNTY5Yy0uOTgzLjgzNy0uNDMyIDEuMjU0LS4wODUgMS4xMjcgMi42OTUtLjk1MiA2LjQxNi0uMTEgNy43MTUuOTg3YS4zNjkuMzY5IDAgMCAxIC4wMDkuNTU5IDcuMzEyIDcuMzEyIDAgMCAwLTIuODE1IDQuOTFjLS4wNzMuNjQ2Ljk5OC41MSAxLjQ1LjM5M2EuMzY2LjM2NiAwIDAgMSAuNDU2LjM0MmMuMDQxIDEuNTUyLTEuNDI3IDMuMjU4LTMuNjEgNC43MTctLjI5My4xOTUtLjI1MS42NjQuNDE2LjY4MWEuMzYyLjM2MiAwIDAgMSAuMzExLjU0NWMtLjc3OSAxLjQ0NS0xLjgzOCAyLjgwNi01LjQ0NSAzLjc0YS4zNy4zNyAwIDAgMC0uMDUuNjk4LjM1NC4zNTQgMCAwIDEgLjExNS42MjVjLTMuNTkyIDMuMDg1LTEyLjY5NSAxLjg2OS0xMy44NS0zLjMyNGEuMzY1LjM2NSAwIDAgMSAuMDY1LS4yOTcgMzQuNjAzIDM0LjYwMyAwIDAgMSAxNS4wOTYtMTEuNDg2LjI4Ny4yODcgMCAwIDAtLjE0Mi0uNTUzIDI0LjY4NSAyNC42ODUgMCAwIDAtMTYuMzk0IDkuODg0LjM3LjM3IDAgMCAxLS40Ny4xMDZjLTUuODM1LTMuMDEyLTEuMDQzLTExLjkwOCA0LjEzLTEzLjQ4NVpNMTAuMTM5IDIwLjI3MmEuMzYyLjM2MiAwIDAgMSAuMzEtLjU0NWMuNjY4LS4wMTcuNzEtLjQ4Ni40MTctLjY4MS0yLjE4NC0xLjQ2LTMuNjUxLTMuMTY1LTMuNjEtNC43MTdhLjM2Ni4zNjYgMCAwIDEgLjQ1Ni0uMzQyYy40NTIuMTE3IDEuNTIzLjI1MyAxLjQ1LS4zOTNhNy4zMTIgNy4zMTIgMCAwIDAtMi44MTUtNC45MS4zNjkuMzY5IDAgMCAxIC4wMS0uNTU5YzEuMjk3LTEuMDk3IDUuMDE5LTEuOTM5IDcuNzE0LS45ODcuMzQ3LjEyNy44OTctLjI5LS4wODUtMS4xMjdhLjM2Ni4zNjYgMCAwIDEgLjAyMi0uNTY5Yy45NzItLjY5NyAzLjUwNC0uNjk0IDYuMTYuOTY2LjI1OS4xNzMuOTU5LS4wMS4zMDktLjk3NGEuMzY2LjM2NiAwIDAgMSAuMjUtLjU5MSA1LjczOCA1LjczOCAwIDAgMSA1LjE4OSAyLjQ4OWMuMTU2LjE5NS44MTkuMzMzLjcwMy0uNzYzYS4zNjYuMzY2IDAgMCAxIC40NjUtLjM4OWM1LjE3MyAxLjU3NyA5Ljk2NCAxMC40NzMgNC4xMyAxMy40ODVhLjM3LjM3IDAgMCAxLS40Ny0uMTA2QTI0LjY4NSAyNC42ODUgMCAwIDAgMTQuMzUgOS42NzVhLjI4Ny4yODcgMCAwIDAtLjE0Mi41NTMgMzQuNjAzIDM0LjYwMyAwIDAgMSAxNS4wOTUgMTEuNDg2LjM2NC4zNjQgMCAwIDEgLjA2Ni4yOTdjLTEuMTU2IDUuMTkzLTEwLjI1OSA2LjQwOS0xMy44NSAzLjMyNGEuMzU0LjM1NCAwIDAgMSAuMTE1LS42MjUuMzcuMzcgMCAwIDAtLjA1LS42OThjLTMuNjA3LS45MzQtNC42NjYtMi4yOTUtNS40NDUtMy43NFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC4wOCAuMDAyKSIvPjxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTU4Ljc1NCAzNi4xNDZjMS40OTYgMy45OC4zMyA1Ljg5NC0zLjIxOSAzLjg2OGEyNS40NCAyNS40NCAwIDAgMS03LjQ1NC02LjI0OWMtMi42NzQtMy4xNzYtLjkzNi00LjU5MSAzLjI3NS0zLjgyOGExMS4zNjggMTEuMzY4IDAgMCAxIDcuMzk4IDYuMjA5Wk00Mi44MzQgMzEuNjY4YzUuMDc2IDQuMjE5LS43NCA3LjIwNS03LjA3IDcuMjA1cy0xMi4xNDQtMi45ODYtNy4wNjgtNy4yMDVhMTEuMjg2IDExLjI4NiAwIDAgMSAxNC4xMzggMFpNMTIuNzc2IDM2LjE0NmExMS4zNjggMTEuMzY4IDAgMCAxIDcuMzk4LTYuMjFjNC4yMTEtLjc2MiA1Ljk0OS42NTMgMy4yNzUgMy44M2EyNS40NCAyNS40NCAwIDAgMS03LjQ1NCA2LjI0OGMtMy41NSAyLjAyNi00LjcxNi4xMTItMy4yMi0zLjg2OFpNNS40MzMgNTguMjY0YTExLjM2NCAxMS4zNjQgMCAwIDEgLjg0NC05LjY3YzEuODc1LTMuMTkxIDMuNzYzLTMuMDY0IDQuNTEyLS4zNmExNi45NTQgMTYuOTU0IDAgMCAxLS45NzcgMTEuMTc0Yy0xLjM4OSAyLjc2LTMuMTI2IDEuODI3LTQuMzc5LTEuMTQ0Wk0xOC45NTcgNzguOTMyYTExLjI5NyAxMS4yOTcgMCAwIDEtOC40OTgtMTAuMDgyYy43MDQtMTYuMzgyIDI0LjMxNCAxMi44NzQgOC40OTggMTAuMDgyWk0xOS40MzcgNTguNTI4Yy0zLjk1OS0yLjI4NS01LjAwNy03Ljg4My0yLjM0LTEyLjUwMnM4LjAzOS02LjUxMSAxMS45OTgtNC4yMjUgNS4wMDcgNy44ODQgMi4zNCAxMi41MDMtOC4wMzkgNi41MS0xMS45OTggNC4yMjRaTTQyLjM3MiA4NS4xODRhMTEuMzA3IDExLjMwNyAwIDAgMS0xMy4yMTQgMGMtMy45MjMtMi43MDkuMDI0LTUuODI2IDYuNjA3LTUuODI2czEwLjUzIDMuMTE3IDYuNjA3IDUuODI2WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLjA4IC4wMDIpIi8+PGVsbGlwc2UgY2xhc3M9ImNscy0yIiBjeD0iMzUuODQ1IiBjeT0iNjcuMzc4IiByeD0iOS4xOSIgcnk9IjcuODc3Ii8+PHBhdGggY2xhc3M9ImNscy0yIiBkPSJNNDAuMDk1IDU0LjMwNGMtMi42NjctNC42Mi0xLjYyLTEwLjIxNyAyLjM0LTEyLjUwM3M5LjMzLS4zOTQgMTEuOTk4IDQuMjI1IDEuNjE5IDEwLjIxNy0yLjM0IDEyLjUwMmMtMy45NiAyLjI4Ni05LjMzMS4zOTUtMTEuOTk4LTQuMjI0Wk01Mi41NzMgNzguOTMyYy0xNS44MTYgMi43OTIgNy43OTQtMjYuNDY0IDguNDk4LTEwLjA4MmExMS4yOTcgMTEuMjk3IDAgMCAxLTguNDk4IDEwLjA4MlpNNjYuMDk2IDU4LjI2NGMtMS4yNTIgMi45NzEtMi45OSAzLjkwNC00LjM3OCAxLjE0NGExNi45NTQgMTYuOTU0IDAgMCAxLS45NzctMTEuMTc1Yy43NDktMi43MDMgMi42MzYtMi44MyA0LjUxMi4zNmExMS4zNjQgMTEuMzY0IDAgMCAxIC44NDMgOS42NzFaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSguMDggLjAwMikiLz48L3N2Zz4=" class="logo">
<h1>Live Temperature Dashboard</h1>
</header>
<div class="frame">
<div class="center">
<div class="temparature-meter__container">
<div class="temparature-meter__inner">
<div class="temparature-meter__inner-ring">
<div class="temparature-inside">
<span id="temp-meter" class="temparature-count c1"></span>
<span class="temperature-sup">°</span>
</div>
<div class="temparature-meter__inner-label">Bedroom</div>
</div>
</div>
</div>
</div>
</div>
<div id="temperature">Temperature: --</div>
<div class="chart-container">
<canvas id="temperatureGraph"></canvas>
</div>
<script>
const socket = new WebSocket('ws://' + location.host + '/temperature');
let chart; // Reference to the chart object
socket.addEventListener('message', ev => {
console.log(ev);
const temperature = parseFloat(ev.data);
updateGraph('temperatureGraph', 'Temperature (°C)', temperature);
updateTemperatureDisplay(temperature);
});
function updateTemperatureDisplay(temperature) {
document.getElementById('temperature').textContent = `Temperature: ${temperature.toFixed(2)} °C`;
document.getElementById('temp-meter').textContent = temperature.toFixed(2);
}
function updateGraph(chartId, label, value) {
const ctx = document.getElementById(chartId).getContext('2d');
if (!chart) {
chart = new Chart(ctx, {
type: 'line',
data: {
labels: Array.from({ length: 15 }, (_, i) => i + 1),
datasets: [{
label: label,
data: Array(25).fill(value), // Fills array with 10 same values for initial chart setup
fill: true,
borderColor: '#148d04',
tension: 0.4
}]
},
options: {
scales: {
x: {
title: {
display: true,
text: 'Time',
color: '#ccc'
},
grid: {
color: '#444'
},
ticks: {
color: '#ccc'
}
},
y: {
title: {
display: true,
text: label,
color: '#ccc'
},
grid: {
color: '#444'
},
ticks: {
color: '#ccc'
}
}
},
plugins: {
legend: {
labels: {
color: '#ccc'
}
}
}
}
});
} else {
// Update the existing chart data
chart.data.labels.push(new Date().toLocaleTimeString());
chart.data.datasets[0].data.push(value);
if (chart.data.labels.length > 10) {
chart.data.labels.shift(); // Remove the oldest label
chart.data.datasets[0].data.shift(); // Remove the oldest data point
}
chart.update();
}
}
</script>
</body>
</html>
import machine
import time
import network
from microdot import Microdot, send_file
from microdot.websocket import with_websocket
def connect_to_wifi():
sta_if = network.WLAN(network.STA_IF)
if not sta_if.isconnected():
print("Connecting to the network...")
sta_if.active(True)
sta_if.connect("Airtel_RAJEEV", "00351553")
while not sta_if.isconnected():
pass
print("Connected to IP: ", sta_if.ifconfig()[0])
connect_to_wifi()
app = Microdot()
@app.route('/')
async def index(request):
return send_file("index.html")
@app.route('/temperature')
@with_websocket
async def index(request, ws):
while True:
adc = machine.ADC(4) # Use ADC pin GP4
conversion_factor = 3.3 / (65535) # ADC conversion factor
sensor_value = adc.read_u16() * conversion_factor
temperature = 27 - (sensor_value - 0.706) / 0.001721 # Convert sensor value to temperature (formula may vary)
await ws.send(str(temperature))
time.sleep(1)
app.run(debug= True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment