TODO 1/2/3 markers to make it yours.
diagram.json above and paste its wiring in to load the circuit.
🎯 Objective
By the end of this project, you will:
- Combine a sensor, an actuator, and a network service into one device that does something a person would actually want.
- Scope a build to the time available, which is the skill that decides whether a demo works.
- Start from a template and extend it, the way most embedded work really begins.
- Debug a system with several moving parts by testing one at a time.
- Explain your design to a room: the problem, the solution, and what you would do next.
1The brief
In a team, build a device that does all three:
- Senses with at least one sensor (DHT11, PIR, LDR, potentiometer, an obstacle‑avoidance module)
- Acts with at least one output (LED, RGB LED, active or passive buzzer, relay, OLED)
- Connects to the cloud: a Ubidots dashboard (Project 11) and/or a Telegram bot (Project 12)
2Idea menu
| Idea | Sense | Act | Cloud |
|---|---|---|---|
| Smart room monitor | DHT11 + LDR | OLED readout | Ubidots charts |
| Motion security node | PIR | Buzzer | Telegram alert |
| Greenhouse minder | DHT11 + LDR | LED warning | Ubidots gauge + event |
| Cloud appliance | button | relay | Ubidots switch + Telegram |
| Comfort meter | DHT11 | RGB LED green/yellow/red | Ubidots dashboard |
| Obstacle alarm | obstacle‑avoidance module | passive buzzer warning tone | Telegram message when something gets close |
| Light-and-sound alert | LDR (darkness trigger) | passive buzzer melody | Ubidots event when it goes dark |
3Getting started
- Open the starter sketch. It already connects to Wi-Fi and Ubidots, publishes one value, and reacts to one command. Follow the
TODO 1/2/3markers. - Steal freely from earlier projects: wiring and code for each part are in the Project Hub and the Components Glossary.
- Give your device a unique
DEVICE_LABELso your data does not mix with another team's.
4Code 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 (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
| Code | What 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_MS | Publishes 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. |
Pre-demo integration checklist
Work through this once each part works alone, before you trust the whole loop:
- Sensor prints a sensible value on Serial (not
nan, not stuck at one number) - Actuator responds to a hardcoded test value before it responds to the sensor
- Wi‑Fi connects, and reconnects if you toggle the router or walk out of range
- The cloud side (Ubidots dashboard or Telegram chat) shows the first real reading
- A cloud command reaches the board and the actuator reacts within a few seconds
- The whole loop, sense → cloud → actuator, still works after pressing EN/RESET
DEVICE_LABEL(orCHAT_ID) is unique to your team, not left at the default- Credentials (
WIFI_PASS,UBIDOTS_TOKEN,BOT_TOKEN) are filled in, not still placeholders
If a step fails, go back to the single project it came from (Project 9 for a sensor, Project 11 or 12 for the cloud link) and confirm it still works in isolation before debugging the combination.
5What to show at the demo (about 3 minutes)
- What problem does your device solve, and for whom?
- Show it working: trigger the sensor, watch the actuator and the dashboard or chat respond.
- One thing that was harder than expected, and how you handled it.
- One thing you would add with another day.
6Grading (10 points)
| Criteria | Points |
|---|---|
| Sensor reads real, sensible values | 2 |
| Actuator responds correctly | 2 |
| Data reaches the cloud | 3 |
| Full loop works live at the demo | 2 |
| Clear explanation of the idea | 1 |
Bonus (up to 2): a cloud alert/event, a clean OLED display, or a genuinely creative idea.
7Finish on time
- Wire and test one part at a time, confirm good Serial values before adding the cloud.
- Use
millis(), notdelay(), so Wi-Fi and MQTT stay responsive. - Keep a known-working version before adding the next feature.
🎯 Knowledge Check
1. What is the main purpose of the starter template?
2. What should you do first when combining sensor + actuator + cloud?
3. What does the pre-demo integration checklist help you verify?
4. What is the recommended demo structure?
9Wrapping Up: What You've Learned
Look back at the week. Every project was one idea, and the capstone is where they stop being separate:
- Read the world, decide, act on the world (Project 1). Everything since has been a richer version of that loop.
- Digital or analog, raw counts or physical units (Projects 2, 3, 9). Knowing which kind of sensor you have tells you how much interpreting is your job.
millis(), neverdelay()(Project 4). Not a style rule: it is what lets a device do two things at once, and every networked project since has depended on it.- The board can serve a page (Projects 5 to 9): great on the local network, invisible from outside it.
- State has to be kept honest (Project 8). When two interfaces control one output, they both have to be told the truth.
- Local output has its place (Project 10). Not everything needs a phone.
- Publish/subscribe reaches anywhere (Project 11), and an existing app can be your UI (Project 12).
Now try
- OTA updates: Add over-the-air update capability so you can upload new sketches without connecting the USB cable.
- Web dashboard: Add a simple web page (like Project 9) that shows the same sensor data as the Telegram bot, giving you two ways to view the data.
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.