DEV Community

Cover image for Opstracle Detection with KiwisIoT
S. Nishanth
S. Nishanth

Posted on

Opstracle Detection with KiwisIoT

title: Measuring Distance with an ESP8266 and an Ultrasonic Sensor, Streamed to KiwisIoT
published: false
description: Build a Wi-Fi distance monitor with an ESP8266 NodeMCU, an HC-SR04 ultrasonic sensor, and a live KiwisIoT dashboard.
tags: esp8266, iot, arduino, embedded

cover_image: REPLACE_WITH_COVER_IMAGE_URL

Ever wanted a live distance reading on a dashboard you can check from any browser? In this project, an ESP8266 NodeMCU reads an HC-SR04 ultrasonic sensor every two seconds, calculates the distance in centimeters, and sends the value over Wi-Fi to a KiwisIoT panel, where it updates in near real time.

The full project, including the sketch, README, and images, is on GitHub: https://github.com/Kiwistron/KiwisIoT-Projects/tree/main/esp8266/003-ultrasonic-kiwisiot

What You Need

  • ESP8266 NodeMCU (CP2102 or CH340 board)
  • HC-SR04 ultrasonic sensor
  • A micro USB cable
  • Four jumper wires
  • Arduino IDE 1.8.19 or later
  • A KiwisIoT account

Wiring

HC-SR04 Pin NodeMCU Pin Notes
VCC VIN (5V) The HC-SR04 needs 5V
GND GND Common ground
TRIG D1 (GPIO5) Trigger output
ECHO D2 (GPIO4) Echo input

Circuit diagram

Watch out for the ECHO pin. The HC-SR04 outputs 5V on ECHO, but the ESP8266's GPIO pins only tolerate 3.3V. A simple voltage divider (for example, 1 kΩ in series with ECHO and 2 kΩ from ECHO to GND) protects the board. A logic level shifter works too.

code


#include <ESP8266WiFi.h>
#include <KiwisIoT.h>

const char* ssid = "YOUR_WIFI_NAME";
const char* pass = "YOUR_WIFI_PASSWORD";

const char* topic = "YOUR_DASHBOARD_TOPIC_ID";

#define TRIG_PIN D1
#define ECHO_PIN D2

KiwisIoT kiwisiot(ssid, pass, topic);

void sendDistance() {

  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);

  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000);

  if (duration == 0) {

    Serial.println();
    Serial.println("Ultrasonic: No echo received");

    return;
  }

  float distance = duration * 0.0343 / 2;

  Serial.println();
  Serial.println("---------- ULTRASONIC MONITORING ----------");

  Serial.print("Distance: ");
  Serial.print(distance, 2);
  Serial.println(" cm");

  String distanceData = String(distance, 2);

  kiwisiot.send("0", distanceData);

  Serial.print("Sent to KiwisIoT Channel 0: ");
  Serial.print(distanceData);
  Serial.println(" cm");
}

void setup() {

  Serial.begin(115200);
  Serial.println("   ULTRASONIC DISTANCE MONITOR   ");

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

  digitalWrite(TRIG_PIN, LOW);

  Serial.println("Ultrasonic sensor initialized");

  Serial.println("Connecting to KiwisIoT...");

  kiwisiot.begin();

  Serial.println("KiwisIoT initialized");
  Serial.println("Starting distance monitoring...");
}

void loop() {

  kiwisiot.run();

  static unsigned long lastSend = 0;

  if (millis() - lastSend >= 2000) {

    lastSend = millis();

    sendDistance();
  }

  delay(100);
}
Enter fullscreen mode Exit fullscreen mode

How the Measurement Works

The ultrasonic sensor measures distance by timing an echo. The firmware sends a 10 µs pulse on TRIG, then uses pulseIn() to measure how long ECHO stays HIGH. Sound travels about 0.0343 cm per microsecond, and the signal travels to the object and back, so the distance is:

distance (cm) = duration × 0.0343 / 2
Enter fullscreen mode Exit fullscreen mode

Here is the core function from the sketch:

void sendDistance() {

  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);

  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000);

  if (duration == 0) {
    Serial.println("Ultrasonic: No echo received");
    return;
  }

  float distance = duration * 0.0343 / 2;

  String distanceData = String(distance, 2);
  kiwisiot.send("0", distanceData);
}
Enter fullscreen mode Exit fullscreen mode

The 30000 argument sets a 30 ms timeout, so if nothing reflects the signal, pulseIn() returns 0 instead of blocking the loop. The sketch checks for that and skips the send.

Sending Data to KiwisIoT

The loop() function calls kiwisiot.run() on every pass to keep the connection alive, and sends a reading every 2 seconds using a millis() timer. This avoids delay() blocking the connection work.

void loop() {
  kiwisiot.run();

  static unsigned long lastSend = 0;
  if (millis() - lastSend >= 2000) {
    lastSend = millis();
    sendDistance();
  }

  delay(100);
}
Enter fullscreen mode Exit fullscreen mode

Setting Up the Dashboard

  1. Log in to KiwisIoT and create a new panel.
  2. Add a Label widget to show the reading.
  3. Copy the panel's Topic ID and paste it into the sketch.

The label updates with each reading, and the panel shows Online while the board is connected.

Serial Monitor Output

Open the Serial Monitor at 115200 baud to check the readings locally:

---------- ULTRASONIC MONITORING ----------
Distance: 5.35 cm
[TX] {"0":"5.35"}
Sent to KiwisIoT Channel 0: 5.35 cm

Ultrasonic: No echo received
Enter fullscreen mode Exit fullscreen mode

code output

Troubleshooting

  • "Access is denied" on upload: Close the Serial Monitor before uploading.
  • "No echo received" every time: Check the TRIG and ECHO wiring and the 5V supply. Point the sensor at a flat, hard surface.
  • Unstable readings: Secure the jumper wires and keep the sensor away from walls.
  • Dashboard not updating: Confirm the Topic ID and that the board is connected to a 2.4 GHz network.

Where to Go Next

  • Trigger an alert when the distance drops below a threshold
  • Log readings over time for KiwisIoT's chart widgets
  • Add more sensors on separate channels

The complete code and setup instructions are in the GitHub repository. Feedback and improvements are welcome.

Top comments (0)