DEV Community

Hedy
Hedy

Posted on

How would i display sensor results to Raspberry Pi webpage?

The simplest is to run a tiny web server on the Raspberry Pi that reads your sensor and serves an HTML page that updates itself (polling or WebSockets). Below are three approaches—pick A for quick wins, B for real-time updates, C if you like visual dashboards with almost no coding.

A) Python + Flask (poll every few seconds)
1) Wire the sensor

Examples:

  • DHT22 → 1 GPIO + 3.3 V + GND
  • I²C sensors (e.g., BMP280, SHT31) → SDA (GPIO2), SCL (GPIO3), 3.3 V, GND
  • 1-Wire (DS18B20) → enable 1-Wire in raspi-config (Interface Options)

2) Install basics

sudo apt update
sudo apt install -y python3-venv python3-pip
python3 -m venv ~/env
source ~/env/bin/activate
pip install flask
# Optional sensor libs (choose yours)
pip install adafruit-circuitpython-dht adafruit-circuitpython-bmp280 RPi.GPIO board
Enter fullscreen mode Exit fullscreen mode

3) Minimal Flask app (save as app.py)

from flask import Flask, jsonify, render_template_string
import time, random
# TODO: replace with your real sensor read (e.g., Adafruit libs)
def read_sensor():
    # return a dict; replace with real readings
    return {"temp_c": round(20 + random.random()*5, 2),
            "humidity": round(40 + random.random()*10, 1),
            "ts": int(time.time())}

PAGE = """
<!doctype html>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Raspberry Pi Sensor</title>
<style>
  body{font-family:system-ui,Arial;margin:2rem;color:#0b1320}
  .card{max-width:520px;padding:1rem;border:1px solid #e5e7eb;border-radius:12px}
  h1{margin:.2rem 0 1rem}
  .grid{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
  .k{font-size:3rem;font-weight:700}
  .muted{color:#64748b}
  #spark{width:100%;height:60px}
</style>
<div class="card">
  <h1>📟 Sensor Dashboard</h1>
  <div class="grid">
    <div><div class="muted">Temperature</div><div id="t" class="k">-- °C</div></div>
    <div><div class="muted">Humidity</div><div id="h" class="k">-- %</div></div>
  </div>
  <div class="muted" style="margin-top:.8rem">Updated: <span id="time">--</span></div>
  <svg id="spark" viewBox="0 0 100 20" preserveAspectRatio="none"></svg>
</div>
<script>
const tEl = document.getElementById('t');
const hEl = document.getElementById('h');
const timeEl = document.getElementById('time');
const spark = document.getElementById('spark');
let history = [];

function drawSpark() {
  if (history.length < 2) return;
  const max = Math.max(...history), min = Math.min(...history) || 0;
  const xs = history.map((v,i)=>[i*(100/(history.length-1)), 20-( (v-min)/(max-min||1)*20 )]);
  const d = "M"+xs.map(([x,y])=>`${x},${y}`).join(" L ");
  spark.innerHTML = `<path d="${d}" fill="none" stroke="black" stroke-width="0.8"/>`;
}

async function tick(){
  try{
    const r = await fetch('/api');
    const j = await r.json();
    tEl.textContent = j.temp_c.toFixed(2) + " °C";
    hEl.textContent = j.humidity.toFixed(1) + " %";
    timeEl.textContent = new Date(j.ts*1000).toLocaleString();
    history.push(j.temp_c);
    if (history.length > 40) history.shift();
    drawSpark();
  }catch(e){ console.error(e); }
}
setInterval(tick, 2000);
tick();
</script>
"""

app = Flask(__name__)

@app.route("/")
def index():
    return render_template_string(PAGE)

@app.route("/api")
def api():
    return jsonify(read_sensor())

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

Enter fullscreen mode Exit fullscreen mode

Hook up your real sensor

Replace read_sensor() with code for your device. Examples:

DHT22 (GPIO4)

import adafruit_dht, board
dht = adafruit_dht.DHT22(board.D4, use_pulseio=False)
def read_sensor():
    t = dht.temperature
    h = dht.humidity
    return {"temp_c": round(t,2), "humidity": round(h,1), "ts": int(time.time())}
Enter fullscreen mode Exit fullscreen mode

BMP280 (I²C)

import board, busio, adafruit_bmp280
i2c = busio.I2C(board.SCL, board.SDA)
bmp = adafruit_bmp280.Adafruit_BMP280_I2C(i2c)
def read_sensor():
    return {"temp_c": round(bmp.temperature,2), "humidity": None, "ts": int(time.time())}
Enter fullscreen mode Exit fullscreen mode

4) Run it

source ~/env/bin/activate
python app.py
Enter fullscreen mode Exit fullscreen mode

Browse from your PC: http://:8000/ (or http://raspberrypi.local:8000/)

5) Start on boot (systemd)

Create /etc/systemd/system/sensor-web.service:

[Unit]
Description=Pi Sensor Web
After=network-online.target

[Service]
User=pi
WorkingDirectory=/home/pi/sensor-web
ExecStart=/home/pi/env/bin/python /home/pi/sensor-web/app.py
Restart=always

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Then:

sudo systemctl daemon-reload
sudo systemctl enable --now sensor-web
Enter fullscreen mode Exit fullscreen mode

B) Real-time updates (WebSockets)

If you want sub-second updates without polling, use Flask-SocketIO:

pip install flask-socketio eventlet
Enter fullscreen mode Exit fullscreen mode

In Python, emit readings on a timer; in the page, subscribe via Socket.IO and update the DOM. This reduces overhead for frequent updates.

C) Zero-code dashboards (Node-RED)

  1. sudo apt install -y nodered (or use the official script from nodered.org)
  2. Start Node-RED: node-red-start → open http://:1880
  3. Add rpi-gpio / I²C input nodes, process in a function node, and wire to dashboard nodes.
  4. Open the dashboard at /ui (buttons, gauges, charts with clicks).

This is great for multi-sensor projects and prototyping.

Tips & pitfalls

  • Serve JSON + a simple HTML/JS—keeps logic clean and lets you redesign the page later.
  • Use 4-bit SDMMC + buffering (if logging) to avoid blocking the web loop during writes.
  • Security: keep it on your LAN; if you must expose it, put nginx in front and use basic auth/TLS.
  • Performance: don’t read slow sensors more often than they can update; cache the last reading and serve it to the page.

Top comments (0)