You Want Electronic Components for your project. 

For more information, contact us at: 

Utilise APIs for Real-Time Monitoring and Remote Control


Dashboards let humans see data. APIs let software talk to software — they enable mobile apps, automated scripts, and other IoT devices to read sensor data and send commands programmatically. This lesson covers REST API usage in both directions: reading data from the cloud and sending commands back to devices.

ANALOGY
A REST API is like a restaurant menu. Each item (endpoint) has a name, a price (authentication requirement), and a description of what you get. You order (send HTTP request), the kitchen prepares it (server processes), and the waiter brings your dish (JSON response). You don’t need to know how the kitchen works.

ThingsBoard REST API — Authentication

ThingsBoard REST API uses JWT (JSON Web Tokens) for authentication. You obtain a token by logging in with your username and password, then include it in all subsequent requests.

Getting a ThingsBoard JWT Token (curl)
# Get JWT token using your ThingsBoard credentials
curl -X POST https://thingsboard.cloud/api/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"username": "your@email.com", "password": "yourPassword"}'

# Response: { "token": "eyJhbGciOi...", "refreshToken": "eyJ..." }

# All subsequent requests include the token in Authorization header:
# Authorization: Bearer eyJhbGciOi...

Reading Telemetry via REST API

ThingsBoard REST API — Read Telemetry (curl)
# Get latest telemetry values for a device
curl -X GET \
  'https://thingsboard.cloud/api/plugins/telemetry/DEVICE/{deviceId}/values/timeseries' \
  -H 'Authorization: Bearer YOUR_JWT_TOKEN'

# Response:
# {
#   "temperature": [{ "ts": 1700000000000, "value": "24.5" }],
#   "humidity":    [{ "ts": 1700000000000, "value": "68.2" }],
#   "light":       [{ "ts": 1700000000000, "value": "2340" }]
# }

# Get historical telemetry for last 1 hour:
curl -X GET \
  'https://thingsboard.cloud/api/plugins/telemetry/DEVICE/{deviceId}/values/timeseries
  ?keys=temperature,humidity&startTs=1699996400000&endTs=1700000000000&limit=100' \
  -H 'Authorization: Bearer YOUR_JWT_TOKEN'

Sending Commands via RPC (Remote Procedure Call)

ThingsBoard supports server-side RPC: the cloud sends a command to a device, and the device can optionally respond. This is how dashboards control actuators remotely.

ThingsBoard REST API — Send RPC Command to Device
# One-way RPC (fire and forget — no response expected)
curl -X POST \
  'https://thingsboard.cloud/api/plugins/rpc/oneway/{deviceId}' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_JWT_TOKEN' \
  -d '{"method": "setLedState", "params": {"state": true}}'

# Two-way RPC (device returns a response)
curl -X POST \
  'https://thingsboard.cloud/api/plugins/rpc/twoway/{deviceId}' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_JWT_TOKEN' \
  -d '{"method": "getTemperature", "params": {}, "timeout": 5000}'

# Response (two-way): { "temperature": 24.5 }

ESP32 — Handling RPC Commands from ThingsBoard

C/C++ — ESP32 Subscribes to ThingsBoard RPC Topic and Acts on Commands
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

const char* RPC_SUBSCRIBE = "v1/devices/me/rpc/request/+";
const char* RPC_RESPONSE  = "v1/devices/me/rpc/response/";

#define LED_PIN   2
#define RELAY_PIN 16

void onRPCRequest(char* topic, byte* payload, unsigned int length) {
  // Extract request ID from topic: v1/devices/me/rpc/request/{id}
  String topicStr  = String(topic);
  String requestId = topicStr.substring(topicStr.lastIndexOf('/') + 1);

  StaticJsonDocument<200> req;
  deserializeJson(req, payload, length);
  String method = req["method"].as<String>();
  Serial.print("RPC: method="); Serial.print(method);

  if (method == "setLedState") {
    bool state = req["params"]["state"];
    digitalWrite(LED_PIN, state ? HIGH : LOW);
    Serial.print(" state="); Serial.println(state);
    // Send response back (for two-way RPC)
    String responseTopic = String(RPC_RESPONSE) + requestId;
    String response = "{\"result\": \"ok\", \"led\": " + String(state ? "true" : "false") + "}";
    mqtt.publish(responseTopic.c_str(), response.c_str());

  } else if (method == "setRelayState") {
    bool state = req["params"]["state"];
    digitalWrite(RELAY_PIN, state ? HIGH : LOW);
    Serial.println(" relay=" + String(state ? "ON" : "OFF"));

  } else if (method == "getTemperature") {
    float temp = dht.readTemperature();
    String responseTopic = String(RPC_RESPONSE) + requestId;
    String response = "{\"temperature\": " + String(temp, 1) + "}";
    mqtt.publish(responseTopic.c_str(), response.c_str());
  }
}

// In setup(), after MQTT connect:
// mqtt.setCallback(onRPCRequest);
// mqtt.subscribe(RPC_SUBSCRIBE);

KEY
ThingsBoard RPC enables true bidirectional cloud-device control. From a dashboard you can add a Switch widget or Button widget that calls an RPC method. This is how dashboards control relays, servos, and displays on remote ESP32 devices in real time.

ThingsBoard Dashboard Control Widgets

Widget type How it works IoT use case
Switch widget Toggle switch that calls setLedState (true/false) via RPC. Operator clicks to toggle; LED/relay responds instantly. Relay control, LED on/off, motor start/stop
Button widget Single-action button that sends an RPC command on click. E.g. ‘Open Valve’ sends {method: openValve, params: {}}. Valve control, door unlock, alarm acknowledge
Slider widget Slider that sends RPC with a numeric value. E.g. set fan speed 0–100%: {method: setFanSpeed, params: {speed: 75}}. Fan speed, LED brightness, servo angle
Round knob Rotary knob for value setting. Sends RPC with numeric value on release. Temperature setpoint, volume control

ThingSpeak REST API — Python Example

Python — ThingSpeak REST API Read and Write
import requests

CHANNEL_ID = 'YOUR_CHANNEL_ID'
READ_KEY   = 'YOUR_READ_API_KEY'
WRITE_KEY  = 'YOUR_WRITE_API_KEY'

# --- READ last 10 temperature readings ---
url    = f'https://api.thingspeak.com/channels/{CHANNEL_ID}/fields/1.json'
params = {'api_key': READ_KEY, 'results': 10}
data   = requests.get(url, params=params).json()

print('Last 10 temperature readings:')
for entry in data['feeds']:
    print(f"  {entry['created_at']}: {entry['field1']} C")

# --- WRITE a sensor reading ---
r = requests.post('https://api.thingspeak.com/update', params={
    'api_key': WRITE_KEY,
    'field1':  24.5,   # temperature
    'field2':  68.2    # humidity
})
print(f'Write response: {r.text}')  # Returns entry number or 0 on error

Building a Remote Monitoring Application

The following Python script demonstrates automated monitoring with email alerts using the ThingsBoard REST API:

Python — Automated ThingsBoard Monitor with Email Alert (server-side script)
import requests, time, smtplib
from email.mime.text import MIMEText

TB_HOST    = 'https://thingsboard.cloud'
TB_EMAIL   = 'your@email.com'
TB_PASSWORD= 'yourPassword'
DEVICE_ID  = 'YOUR_DEVICE_ID'
ALERT_EMAIL= 'operator@nedu.rw'
TEMP_LIMIT = 35.0  # Alert if temperature exceeds this

def get_token():
    r = requests.post(f'{TB_HOST}/api/auth/login',
                      json={'username': TB_EMAIL, 'password': TB_PASSWORD})
    return r.json()['token']

def get_latest_telemetry(token):
    headers = {'Authorization': f'Bearer {token}'}
    r = requests.get(
        f'{TB_HOST}/api/plugins/telemetry/DEVICE/{DEVICE_ID}/values/timeseries',
        headers=headers)
    data = r.json()
    temp = float(data.get('temperature', [{}])[0].get('value', 0))
    hum  = float(data.get('humidity',    [{}])[0].get('value', 0))
    return temp, hum

def send_alert(temp):
    msg = MIMEText(f'ALERT: Temperature {temp:.1f}C exceeds limit {TEMP_LIMIT}C!')
    msg['Subject'] = 'IoT Temperature Alert — Action Required'
    msg['From']    = 'iot-monitor@nedu.rw'
    msg['To']      = ALERT_EMAIL
    with smtplib.SMTP('smtp.gmail.com', 587) as server:
        server.starttls()
        server.login('iot-monitor@nedu.rw', 'smtpPassword')
        server.send_message(msg)
    print(f'Alert email sent: {temp:.1f}C')

token      = get_token()
alert_sent = False
while True:
    try:
        temp, hum = get_latest_telemetry(token)
        print(f'T: {temp:.1f}C  H: {hum:.1f}%')
        if temp > TEMP_LIMIT and not alert_sent:
            send_alert(temp)
            alert_sent = True
        elif temp <= TEMP_LIMIT - 2:  # hysteresis: clear alert at 33°C
            alert_sent = False
    except Exception as e:
        print(f'Error: {e}')
        token = get_token()  # Refresh token on error
    time.sleep(60)  # Check every 60 seconds

TRY
Run this script on your laptop while your ESP32 is publishing to ThingsBoard. Cover the DHT22 with your hand to raise the temperature above 35°C. The script should detect the threshold breach and print the alert.

Security Best Practices for Cloud-Connected IoT

Practice Implementation detail
Use HTTPS/MQTT-TLS always All API calls must use HTTPS (port 443). All MQTT connections must use TLS (port 8883). Never use plain HTTP or MQTT port 1883 for production deployments.
Rotate access tokens Change device access tokens periodically (quarterly for production). If a token is compromised, an attacker can publish false data to your cloud.
Minimal permission principle Each device should only have permission to publish to its own telemetry topics. It should not be able to read other devices’ data or access admin APIs.
Store credentials in NVS ESP32 NVS (Non-Volatile Storage) encrypts secrets at rest. Use Preferences library: prefs.putString("token", token). Never hardcode tokens in source code.
Monitor for anomalies Set up ThingsBoard alarms for impossible values: temperature < -50°C, RSSI < -100 dBm, impossible humidity. These can indicate sensor failure or data injection attacks.
Keep firmware updated Use OTA updates (from Unit 3) to push security patches. A device that hasn’t been updated in 2 years is a liability.

Storing Credentials Securely on ESP32 (NVS)

C/C++ — Using ESP32 NVS for Secure Credential Storage
#include <Preferences.h>
Preferences prefs;

// WRITE credentials to NVS (run once during provisioning)
void storeCredentials() {
  prefs.begin("iot-creds", false);  // false = read/write mode
  prefs.putString("wifi_ssid", "YourNetwork");
  prefs.putString("wifi_pass", "YourPassword");
  prefs.putString("tb_token",  "YourThingsBoardToken");
  prefs.end();
  Serial.println("Credentials stored in NVS.");
}

// READ credentials from NVS at startup
void loadCredentials(String &ssid, String &pass, String &token) {
  prefs.begin("iot-creds", true);  // true = read-only mode
  ssid  = prefs.getString("wifi_ssid", "");
  pass  = prefs.getString("wifi_pass", "");
  token = prefs.getString("tb_token",  "");
  prefs.end();
}

void setup() {
  Serial.begin(115200);
  String ssid, pass, token;
  loadCredentials(ssid, pass, token);
  if (ssid.length() == 0) {
    Serial.println("No credentials found. Run provisioning.");
    return;
  }
  WiFi.begin(ssid.c_str(), pass.c_str());
  // ... rest of setup
}

Check Your Understanding — Lesson 6.3

?
1. Explain the difference between a ThingsBoard ‘one-way RPC’ and a ‘two-way RPC’. Give a specific IoT example where each type is appropriate.
?
2. A student hardcodes the ThingsBoard access token in their ESP32 code and pushes it to a public GitHub repository. What are the security risks and what are the two immediate actions they should take?
?
3. Write the ThingsBoard MQTT topics that an ESP32 must SUBSCRIBE to in order to receive RPC commands, and the topic structure it must PUBLISH to in order to send a response.

I'm an Embedded & AIoT Systems Engineer and the Founder & CEO of Nyereka Tech, a Rwanda-based startup enabling access to STEM tools, training, and innovation. I'm passionate about empowering young innovators through practical technology education and local manufacturing solutions.