ESP32 Pico Kit GPIO control and DHT22 sensor monitor using NDU Arduino SDK

Introduction

NDU is an open-source server-side platform that allows you to monitor and control IoT devices. It is free for both personal and commercial usage and you can deploy it anywhere. If this is your first experience with the platform we recommend to review what-is-ndu page and getting-started guide.

ESP32 is a series of low-cost, low-power system-on-a-chip microcontrollers with integrated self-contained Wi-Fi and dual-mode Bluetooth. ESP32 is a successor of ESP8266 chip.

This sample application will allow you to control GPIO of your ESP32 device using NDU web UI and display humidity/temperature data from DHT22 sensor. We will observe GPIO control using LEDs connected to the pins. The purpose of this application is to demonstrate NDU RPC capabilities and NDU Telemetry.

The application that is running on ESP32 is written using NDU Arduino SDK which is quite simple and easy to understand.

Current GPIO state and GPIO control widget is visualized using built-in customizable dashboard.

Once you complete this sample/tutorial, you will see your sensor data on the following dashboard.

image

List of hardware

image

image

Wiring

DHT22 connection

Pin Connect to
DHT22 VCC Pico 5V
DHT22 DATA Pico 33

LEDs connection

Pin Connect to
LED1 Anode Pico 32 trough resistor (68Ω - 100Ω)
LED2 Anode Pico 26 trough resistor (68Ω - 100Ω)
LED3 Anode Pico 25 trough resistor (68Ω - 100Ω)
LED4 Anode Pico 19 trough resistor (68Ω - 100Ω)
LED5 Anode Pico 22 trough resistor (68Ω - 100Ω)
LED6 Anode Pico 21 trough resistor (68Ω - 100Ω)
All LEDs cathodes Pico Ground

Connection diagram

The following picture summarizes the connections for this project:

image

Device provisioning

This step contains instructions that are necessary to connect your device to NDU.

Open NDU Web UI (http://localhost:8080) in browser and login as tenant administrator. If you loaded the demo data during TB installation, the next credentials can be used:

Go to “Devices” section. Click “+” button and create a device with the name “ESP32 Pico Device”. Set “Device type” to “default”.

image

Once device created, open its details and click “Manage credentials”.

Copy auto-generated access token from the “Access token” field. Please save this device token. It will be referred to later as $ACCESS_TOKEN.

image

Provision your dashboard

Download the dashboard file using this link. Use import/export instructions to import the dashboard to your NDU instance.

Creating ESP32 firmware

Easiest way to program ESP32 Pico Kit is to use Arduino IDE. Following sections are describing that approach.

ESP32 and Arduino IDE setup

First you will need Arduino IDE and all related software installed.

Download and install Arduino IDE.

The Pico board support must be added to Arduino IDE before any program can be built and flashed into ESP32. To do so, install ESP32 package as described below:

  1. Open Arduino IDE.

  2. Open File -> Preferences menu, and add a board manager URLs

    1
    
    https://dl.espressif.com/dl/package_esp32_index.json,http://arduino.esp8266.com/stable/package_esp8266com_index.json
    

    into Additional Boards Manager URL field, as shown below:

    image

  3. Select Tools -> Board… -> Board manager menu.

  4. Enter ESP32 in the search field. Click Install

    image

Install Arduino NDU SDK

To simplify application development, install the NDU Arduino SDK and its dependencies from standard Arduino library repository:

  1. Proceed to Sketch -> Include Library… submenu. Select Manage Libraries.

  2. Find and install NDU Arduino SDK, PubSubClient by Nick O’Leary and ArduinoHttpClient libraries.

    image image image

  3. Install ArduinoJSON library v6.9.1 or higher. Avoid installing beta releases of the ArduinoJson library.

    image

From now on, you can use NDU SDK right from Arduino IDE.

Install ESP32 DHT22 driver

DHT22 sensor, connected to the ESP32 requires a special driver. To install it, proceed as follows:

  1. Click on “Sketch” menu. Open “Include Library…” submenu. Select “Manage Libraries”.

  2. Type “ESP DHT22” in the search field.

  3. Click install on “DHT22 Sensor Library for ESPx”, as shown below:

    image

Connect ESP32 Pico to PC

ESP32 Pico Kit does not require a sophisticated connection. Just plug micro-USB cable into PC and Pico, this should be enough.

Prepare and upload sketch

Download and open esp32-dht-gpio.ino sketch.

Note You need to edit following constants and variables in the sketch:

resources/esp32-dht-gpio.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#include <DHTesp.h>         // DHT for ESP32 library
#include <WiFi.h>           // WiFi control for ESP32
#include <NDU.h>    // NDU SDK

// Helper macro to calculate array size
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

// WiFi access point
#define WIFI_AP_NAME        "WIFI_AP"
// WiFi password
#define WIFI_PASSWORD       "WIFI_PASSWORD"

// See https://thingsboard.io/docs/getting-started-guides/helloworld/ 
// to understand how to obtain an access token
#define TOKEN               "TOKEN"
// NDU server instance.
#define THINGSBOARD_SERVER  "smartapp.netcad.com"

// Baud rate for debug serial
#define SERIAL_DEBUG_BAUD    115200

// Initialize NDU client
WiFiClient espClient;
// Initialize NDU instance
NDU tb(espClient);
// the Wifi radio's status
int status = WL_IDLE_STATUS;

// Array with LEDs that should be lit up one by one
uint8_t leds_cycling[] = { 25, 26, 32 };
// Array with LEDs that should be controlled from NDU, one by one
uint8_t leds_control[] = { 19, 22, 21 };

// DHT object
DHTesp dht;
// ESP32 pin used to query DHT22
#define DHT_PIN 33

// Main application loop delay
int quant = 20;

// Initial period of LED cycling.
int led_delay = 1000;
// Period of sending a temperature/humidity data.
int send_delay = 2000;

// Time passed after LED was turned ON, milliseconds.
int led_passed = 0;
// Time passed after temperature/humidity data was sent, milliseconds.
int send_passed = 0;

// Set to true if application is subscribed for the RPC messages.
bool subscribed = false;
// LED number that is currenlty ON.
int current_led = 0;

// Processes function for RPC call "setValue"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response processDelayChange(const RPC_Data &data)
{
  Serial.println("Received the set delay RPC method");

  // Process data

  led_delay = data;

  Serial.print("Set new delay: ");
  Serial.println(led_delay);

  return RPC_Response(NULL, led_delay);
}

// Processes function for RPC call "getValue"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response processGetDelay(const RPC_Data &data)
{
  Serial.println("Received the get value method");

  return RPC_Response(NULL, led_delay);
}

// Processes function for RPC call "setGpioStatus"
// RPC_Data is a JSON variant, that can be queried using operator[]
// See https://arduinojson.org/v5/api/jsonvariant/subscript/ for more details
RPC_Response processSetGpioState(const RPC_Data &data)
{
  Serial.println("Received the set GPIO RPC method");

  int pin = data["pin"];
  bool enabled = data["enabled"];

  if (pin < COUNT_OF(leds_control)) {
    Serial.print("Setting LED ");
    Serial.print(pin);
    Serial.print(" to state ");
    Serial.println(enabled);

    digitalWrite(leds_control[pin], enabled);
  }

  return RPC_Response(data["pin"], (bool)data["enabled"]);
}

// RPC handlers
RPC_Callback callbacks[] = {
  { "setValue",         processDelayChange },
  { "getValue",         processGetDelay },
  { "setGpioStatus",    processSetGpioState },
};

// Setup an application
void setup() {
  // Initialize serial for debugging
  Serial.begin(SERIAL_DEBUG_BAUD);
  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  InitWiFi();

  // Pinconfig

  for (size_t i = 0; i < COUNT_OF(leds_cycling); ++i) {
    pinMode(leds_cycling[i], OUTPUT);
  }

  for (size_t i = 0; i < COUNT_OF(leds_control); ++i) {
    pinMode(leds_control[i], OUTPUT);
  }

  // Initialize temperature sensor
  dht.setup(DHT_PIN, DHTesp::DHT22);
}

// Main application loop
void loop() {
  delay(quant);

  led_passed += quant;
  send_passed += quant;

  // Check if next LED should be lit up
  if (led_passed > led_delay) {
    // Turn off current LED
    digitalWrite(leds_cycling[current_led], LOW);
    led_passed = 0;
    current_led = current_led >= 2 ? 0 : (current_led + 1);
    // Turn on next LED in a row
    digitalWrite(leds_cycling[current_led], HIGH);
  }

  // Reconnect to WiFi, if needed
  if (WiFi.status() != WL_CONNECTED) {
    reconnect();
    return;
  }

  // Reconnect to NDU, if needed
  if (!tb.connected()) {
    subscribed = false;

    // Connect to the NDU
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Failed to connect");
      return;
    }
  }

  // Subscribe for RPC, if needed
  if (!subscribed) {
    Serial.println("Subscribing for RPC...");

    // Perform a subscription. All consequent data processing will happen in
    // callbacks as denoted by callbacks[] array.
    if (!tb.RPC_Subscribe(callbacks, COUNT_OF(callbacks))) {
      Serial.println("Failed to subscribe for RPC");
      return;
    }

    Serial.println("Subscribe done");
    subscribed = true;
  }

  // Check if it is a time to send DHT22 temperature and humidity
  if (send_passed > send_delay) {
    Serial.println("Sending data...");

    // Uploads new telemetry to NDU using MQTT. 
    // See https://thingsboard.io/docs/reference/mqtt-api/#telemetry-upload-api 
    // for more details

    TempAndHumidity lastValues = dht.getTempAndHumidity();    
    if (isnan(lastValues.humidity) || isnan(lastValues.temperature)) {
      Serial.println("Failed to read from DHT sensor!");
    } else {
      tb.sendTelemetryFloat("temperature", lastValues.temperature);
      tb.sendTelemetryFloat("humidity", lastValues.humidity);
    }

    send_passed = 0;
  }

  // Process messages
  tb.loop();
}

void InitWiFi()
{
  Serial.println("Connecting to AP ...");
  // attempt to connect to WiFi network

  WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected to AP");
}

void reconnect() {
  // Loop until we're reconnected
  status = WiFi.status();
  if ( status != WL_CONNECTED) {
    WiFi.begin(WIFI_AP_NAME, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
    }
    Serial.println("Connected to AP");
  }
}

Troubleshooting

In order to to perform troubleshooting, you must check ESP32 Pico logs. For that, simply open Serial Monitor in the Arduino IDE.

Data visualization and GPIO control

Finally, open NDU Web UI. You can access this dashboard by logging in as a tenant administrator.

In case of local installation (if the demo data was added during TB installation):

In case of live-demo server:

See live-demo page for more details how to get your account.

Go to “Devices” section and locate “ESP32 Pico Device”, open device details and switch to “Latest telemetry” tab. If all is configured correctly you should be able to see latest values of “temperature” and “humidity” in the table.

image

After, open “Dashboards” section then locate and open “ESP32 Pico Dashboard”. As a result, you will see a time-series chart displaying temperature and humidity level (similar to dashboard image in the introduction).

You should also observe a GPIO control for your device. It consists of two widgets: one is for controlling LED blink speed (in milliseconds) and second for turning individual LEDs on and off.

You can switch status of GPIOs using control panel. As a result, you will see LEDs status change on the device. To control LED blink speed, simply turn a knob and observe a speed change.

See also

Browse other samples or explore guides related to main NDU features:

Next steps