---
title: How to Build a Personal Weather Station with Node.js and ESP32
siteUrl: https://logzly.com/craftcodeacademy
author: craftcodeacademy (CraftCode Academy)
date: 2026-06-18T12:14:01.628094
tags: [weather, nodejs, esp32]
url: https://logzly.com/craftcodeacademy/how-to-build-a-personal-weather-station-with-node-js-and-esp32
---


Ever looked out the window, wondered why the temperature jumps just before you step outside, and thought “I could measure that myself”?  A tiny weather station lets you capture real‑time data right from your balcony, and you get to play with code while you’re at it.  In this guide I’ll walk you through the whole process – from wiring the sensors to serving the data on a Node.js dashboard – using only tools most makers already have at home.

## What You’ll Need

### Hardware

- **[ESP32 development board](/craftcodeacademy/build-a-voicecontrolled-led-wall-panel-with-nodered-and-arduino)** – the little Wi‑Fi brain that talks to your sensors.
- **DHT22 (or DHT11) temperature & humidity sensor** – cheap, reliable, and perfect for hobby projects.
- **BMP280 barometric pressure sensor** – gives you pressure and altitude.
- **Breadboard and jumper wires** – for a quick, solder‑free prototype.
- **USB‑C cable** – to power and flash the ESP32.

### Software

- **Node.js (v14 or later)** – runs the server that collects and displays data.
- **Arduino IDE or VS Code with PlatformIO** – to compile and upload code to the ESP32.
- **npm packages**: `express`, `socket.io`, `johnny-five` (optional for extra hardware control).

All of these are free, and you can find the hardware on any electronics store or online marketplace.

## Step 1 – Set Up the ESP32 Development Environment

1. Install the Arduino IDE if you haven’t already.  Open **File → Preferences** and add the ESP32 board URL: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json`.
2. Go to **Tools → Board → ESP32 Arduino** and select “ESP32 Dev Module”.
3. Plug the board into your computer, choose the correct COM port, and hit the **Upload** button on a simple “blink” sketch to confirm everything works.

That first blink is like the first sip of coffee – it tells you the system is alive.

## Step 2 – Wire the Sensors

| Sensor | ESP32 Pin | Connection |
|--------|-----------|------------|
| DHT22  | 4 (GPIO4) | VCC → 3.3 V, GND → GND, DATA → GPIO4 (add a 10 kΩ pull‑up to 3.3 V) |
| BMP280 | 21 (SDA) / 22 (SCL) | VCC → 3.3 V, GND → GND, SDA → GPIO21, SCL → GPIO22 |

Use a breadboard so you can rearrange things later.  Double‑check that the power pins go to 3.3 V, not 5 V – the ESP32 can be picky.

## Step 3 – Write the ESP32 Firmware

Create a new sketch called `weather_station.ino`.  Below is a minimal version that reads the sensors and sends JSON over Wi‑Fi to a Node.js server.

```cpp
#include <WiFi.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_BMP280.h>

#define DHTPIN 4
#define DHTTYPE DHT22

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
const char* host = "YOUR_PC_IP";   // e.g. 192.168.1.50
const uint16_t port = 3000;        // same as Node server

DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP280 bmp; // I2C

void setup() {
  Serial.begin(115200);
  dht.begin();
  bmp.begin();

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");
}

void loop() {
  float temp = dht.readTemperature();
  float hum  = dht.readHumidity();
  float pres = bmp.readPressure() / 100.0; // hPa

  if (isnan(temp) || isnan(hum) || isnan(pres)) {
    Serial.println("Failed to read sensors");
    delay(2000);
    return;
  }

  // Build JSON payload
  StaticJsonDocument<200> doc;
  doc["temperature"] = temp;
  doc["humidity"]    = hum;
  doc["pressure"]    = pres;
  char buffer[200];
  serializeJson(doc, buffer);

  // Send to server
  WiFiClient client;
  if (!client.connect(host, port)) {
    Serial.println("Connection failed");
    delay(2000);
    return;
  }
  client.println("POST /data HTTP/1.1");
  client.println("Content-Type: application/json");
  client.print("Content-Length: ");
  client.println(strlen(buffer));
  client.println();
  client.println(buffer);
  client.stop();

  Serial.println("Data sent");
  delay(60000); // send once a minute
}
```

Replace `YOUR_SSID`, `YOUR_PASSWORD`, and `YOUR_PC_IP` with your own values.  The code uses the ArduinoJson library to keep the payload tiny – a good habit when you’re on a low‑power device.

## Step 4 – Spin Up the Node.js Server

Create a folder called `weather-server` and run `npm init -y`.  Then install the needed packages:

```bash
npm install express socket.io body-parser
```

The [Node.js server](/craftcodeacademy/how-to-create-an-interactive-webcontrolled-led-matrix-using-node-js-and-raspberry-pi) will handle incoming sensor data and broadcast it via websockets.

Now create `server.js`:

```js
const express = require('express');
const bodyParser = require('body-parser');
const http = require('http');
const socketIo = require('socket.io');

const app = express();
app.use(bodyParser.json());

const server = http.createServer(app);
const io = socketIo(server);

let latestData = {};

app.post('/data', (req, res) => {
  latestData = req.body;
  io.emit('update', latestData);
  res.sendStatus(200);
});

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', socket => {
  socket.emit('update', latestData);
});

const PORT = 3000;
server.listen(PORT, () => console.log(`Server listening on ${PORT}`));
```

Create a simple `index.html` in the same folder:

```html
<!DOCTYPE html>
<html>
<head>
  <title>My Weather Station</title>
  <style>
    body { font-family: Arial, sans-serif; margin: 2rem; }
    .card { border: 1px solid #ccc; padding: 1rem; margin-bottom: 1rem; }
  </style>
</head>
<body>
  <h1>Live Weather Data</h1>
  <div id="temp" class="card"></div>
  <div id="hum" class="card"></div>
  <div id="pres" class="card"></div>

  <script src="/socket.io/socket.io.js"></script>
  <script>
    const socket = io();
    function render(data) {
      document.getElementById('temp').innerText = `Temperature: ${data.temperature.toFixed(1)} °C`;
      document.getElementById('hum').innerText = `Humidity: ${data.humidity.toFixed(1)} %`;
      document.getElementById('pres').innerText = `Pressure: ${data.pressure.toFixed(1)} hPa`;
    }
    socket.on('update', render);
  </script>
</body>
</html>
```

Run the server with `node server.js`.  Open a browser at `http://localhost:3000` and you should see live numbers appear as the ESP32 pushes data every minute.

## Step 5 – Make It Your Own

Now that the basics work, you can add a few personal touches:

- **Data logging** – write each JSON payload to a file or a tiny SQLite DB for later analysis.
- **Graphing** – use a library like Chart.js on the front‑end for [interactive visualizations with p5.js](/craftcodeacademy/build-an-interactive-portfolio-with-p5-js-on-a-raspberry-pi) to plot temperature over the day.
- **Alerts** – have the ESP32 send an email or a push notification when humidity spikes.
- **Power** – move the board to a solar‑charged LiPo pack for a truly off‑grid station.

I started with the bare‑bones version, then added a simple line chart.  Watching the sunrise temperature climb on a graph felt oddly satisfying – like seeing your code breathe.

## Troubleshooting Tips

| Symptom | Likely Cause | Fix |
|---------|--------------|-----|
| No Wi‑Fi connection | Wrong SSID/password or ESP32 in deep sleep | Double‑check credentials; add a short delay before Wi‑Fi.begin |
| JSON payload empty | Sensor wiring error or missing pull‑up resistor | Verify connections; add 10 kΩ resistor on DHT data line |
| Browser shows “404” | Server not serving `index.html` from correct path | Ensure `index.html` sits next to `server.js` and you run `node server.js` from that folder |

A quick serial print of the sensor values before sending can save you a lot of head‑scratching.

## Wrap‑Up Thoughts

Building a personal weather station is a perfect blend of hardware tinkering and web development.  You get to see raw sensor data, push it through a network, and turn it into a live dashboard – all with tools that are free and widely supported.  The best part?  Once you have the pipeline working, you can reuse it for any other IoT project – soil moisture, light levels, you name it.

So grab an ESP32, solder a couple of pins, and let the weather come to you.  The sky’s not the limit; it’s just the first data point.