PROJECT 13 · CAPSTONE

Capstone: Build Your Own IoT Device

Combine the week into one device that senses, acts, and connects to the cloud, then demo it.

⬇ Download the starter sketch The starter already connects to Wi-Fi and Ubidots. Follow the TODO 1/2/3 markers to make it yours.

🎯 Objective

By the end of this project, you will:

1 · The brief

In a team, build a device that does all three:

  1. Senses with at least one sensor (DHT11, PIR, LDR, potentiometer)
  2. Acts with at least one output (LED, RGB LED, buzzer, relay, OLED)
  3. Connects to the cloud: a Ubidots dashboard (Project 11) and/or a Telegram bot (Project 12)
Keep the scope small and make it work end to end. A simple thing that fully works beats an ambitious thing that does not.

2 · Idea menu

IdeaSenseActCloud
Smart room monitorDHT11 + LDROLED readoutUbidots charts
Motion security nodePIRBuzzerTelegram alert
Greenhouse minderDHT11 + LDRLED warningUbidots gauge + event
Cloud appliancebuttonrelayUbidots switch + Telegram
Comfort meterDHT11RGB LED green/yellow/redUbidots dashboard

3 · Getting started

4 · Code Walkthrough: Understanding the Starter Template

The starter is Project 11 with the project-specific parts hollowed out. It compiles and runs as it stands, publishing a constant 0.0, so you can confirm the cloud half works before you touch a sensor. Three TODO markers say where your code goes.

TODO 1: read your sensor

#include "UbidotsEsp32Mqtt.h"
// TODO 1: add your sensor library includes here, e.g.:
// #include <Adafruit_Sensor.h>
// #include <DHT.h>

float readMySensor() {
  // TODO 1: replace this with a real reading from your sensor.
  //   return analogRead(SENSOR_PIN);      // potentiometer / LDR
  //   return dht.readTemperature();       // DHT11
  return 0.0;
}

Everything about your measurement is behind one function. That is deliberate: the rest of the sketch never needs to know whether the number came from an ADC pin, a DHT11, or a calculation across three sensors. Change readMySensor() and the whole device follows.

There are three places to touch for a new sensor, and forgetting the third is the usual bug: the include, the object (for example DHT dht(DHTPIN, DHTTYPE);), and the begin() call in setup().

If your sensor can fail, guard it as Project 9 did: if (isnan(t)) { ... } and skip the publish rather than sending a bad number.

TODO 2: publish what you care about

// TODO 2: add every variable you want to see in the dashboard.
ubidots.add(VAR_SENSOR, value);
ubidots.publish(DEVICE_LABEL);

One add() per variable, then a single publish(). Add a second reading by adding a second const char *VAR_... at the top and a second add() here. Rename VAR_SENSOR to what you are actually measuring (soil, lux, temperature): that name is what appears in Ubidots, so a good one makes the dashboard explain itself.

TODO 3: decide what a command means

void callback(char *topic, byte *payload, unsigned int length) {
  ...
  float v = atof(value);

  // TODO 3: decide what a command means for your project.
  digitalWrite(OUTPUT_PIN, (v >= 0.5) ? HIGH : LOW);
  Serial.printf("[CLOUD] command -> %.1f\n", v);
}

The payload arrives as a number, so a command does not have to be on/off. v could be a brightness for ledcWrite() (Project 3), a target temperature to compare against, or an index selecting which message to show on the OLED (Project 10). Keep the callback short: set a variable or write a pin, and let loop() do anything slow.

What the template already handles for you

CodeWhat it does
connectToWifi() + setup() + reconnect()Gets you onto the network and the broker.
subscribeLastValue(DEVICE_LABEL, VAR_COMMAND)Listens for cloud commands and picks up the current value at boot.
if (!ubidots.connected()) in loop()Reconnects and re-subscribes after a Wi-Fi drop.
millis() - lastPublish > PUBLISH_EVERY_MSPublishes on a timer without blocking.
ubidots.loop()Services MQTT so your callback() actually fires.
Serial.printf("[PUB] ...")Your fastest debugging tool. Keep printing while you build.
Not using Ubidots? If your project is Telegram-based, start from Project 12's sketch instead and apply the same three questions: what do I read, what do I report, what do I do when told.

5 · What to show at the demo (about 3 minutes)

  1. What problem does your device solve, and for whom?
  2. Show it working: trigger the sensor, watch the actuator and the dashboard or chat respond.
  3. One thing that was harder than expected, and how you handled it.
  4. One thing you would add with another day.

6 · Grading (10 points)

CriteriaPoints
Sensor reads real, sensible values2
Actuator responds correctly2
Data reaches the cloud3
Full loop works live at the demo2
Clear explanation of the idea1

Bonus (up to 2): a cloud alert/event, a clean OLED display, or a genuinely creative idea.

7 · Finish on time

8 · Wrapping Up: What You've Learned

Look back at the week. Every project was one idea, and the capstone is where they stop being separate:

The engineering habits matter as much as the APIs: check that hardware started, guard against bad readings, keep credentials out of your code's public life, print enough on Serial to see what is happening, and keep a version that works before adding the next thing.

That is a real IoT skill set. The next device you build is the same shape, with different parts.

← Project 12 · Telegram Bot All Projects →