
Remote health monitoring is rapidly growing in the healthcare field. With tools like the Fitbit and Apple watch, people are able to monitor vital health data from anywhere in the world.
This tutorial uses the KY039 sensor connected to the ESP32 development board to measure the heartbeat pulses and send the heartbeat measurement to the AskSensors platform over MQTT.
The AskSensors IoT cloud gives us easy-to-use tools to store data and manage sensors devices data. It also provides smart dashboards to visualize data using widgets. The AskSensors web application can be used to monitor real-time heartbeat data remotely from a mobile phone or laptop, from anywhere in the world over the internet.
1) Prerequisites :
Setting up the AskSensors IoT platform is very easy. Followings are the prerequisites you need to be able to monitor the heartbeat with AskSensors IoT cloud.
- Before beginning with this tutorial, if you are new to AskSensors, create an AskSensors account.
- You should be familiar with the AskSensors IoT platform: Read the Getting Started with AskSensors.
- After sign up, create a new sensor device with at least one module to connect your Heartbeat sensor.
- Now after this click on ‘Add graph’ and select the graph type you prefer to show the measurements.
- Copy down your sensor API KEY IN, we will use it later when we attempt to write data or send data from the ESP32.
2) Required Materials
These are the parts required to build the circuit.
- ESP32 development board.
- Heart/pulse rate sensor module KY039.
- Jumper wires.
- Computer running Arduino IDE software.
- USB micro cable to connect ESP32 development board to the computer.
3) KY039 Features
The KY039 module is a plug-and-play Sensor that collects heart rate data and pulses from the human body.
- It uses bright infrared (IR) LED and a phototransistor to detect the pulse of the finger (Heartbeat).
- A red LED flashes with each pulse.
- The analog output gives an analog signal that matches the heart rate.
- Power supply: 3.3V to 5V DC Voltage
- Output: Analogue based on a heart rate measurement (maximum voltage equal to supply voltage)
- Pin description:

- Ground : min/ground of input voltage
- Vcc : 3.3V or 5V DC input voltage
- S : Analog output Signal
- Notes:
- This KY039 module is NOT a professional medical device and should not be used to treat medical case that may put life in danger.
- This product is designed to work when the user is not moving and far from home lighting 50Hz/60Hz noises. Otherwise, it will give inaccurate results.
4) Circuit schematic
The connections are so simple. The following figure shows the schematic diagram of the circuit we will be using in this tutorial.

- Connect the “+” pin of the KY039 to the 3V3 of the ESP32 board.
- Connect the “-” pin to the ESP32 ground.
- The signal pin of the pulse sensor must be connected to an analog pin of ESP32. Connect the Analog pin of the KY039 to the A0 pin of the ESP32 (ADC values from 0 to 4095).
- Last, connect your ESP32 to the computer through a USB cable. The ESP32 will be powered from the USB 5V.
5) Install the ESP32 in Arduino IDE
The ESP32 will be programmed using Arduino IDE. There’s an add-on for the Arduino IDE (1.8.7 or higher) that allows you to program the ESP32 using the Arduino IDE and its programming language. Follow the instructions below:
- Open the preferences window from the Arduino IDE : File> Preferences.
- Go to the “Additional Board Manager URLs” field, Enter the following URL:
https://dl.espressif.com/dl/package_esp32_index.json
- If you already have the ESP8266 boards URL, separate the URLs with a comma as shown below:
https://dl.espressif.com/dl/package_esp32_index.json, http://arduino.esp8266.com/stable/package_esp8266com_index.json- Open boards manager (Tools > Board > Boards Manager), search for ESP32 and click the install button for the “ESP32 by Espressif Systems”.
6) Download the libraries
- The PubSubClient library provides a client for doing simple publish/subscribe messaging with a server that supports MQTT.
o Download the PubSubClient library from github.
o Unzip the .zip folder and you should get pubsubclient-master folder.
o Rename your folder from pubsubclient-master to pubsubclient.
o Move the pubsubclient folder to your Arduino IDE installation libraries folder.
o Then, re-open your Arduino IDE.
The library comes with a number of example sketches that are not fully compatible with the ESP32. However, the example provided in this tutorial is working very reliably in the Arduino IDE software.
- The AskSensors MQTT Publish/Subscribe API is described in detail in this guide.
7) Write the code
Download this complete demo from the AskSensors github page. You need to edit the code with your own SSID, password, username and MQTT topic.
const char* ssid = ".................."; // Wifi SSID
<span style="color: #993300;">const char* password = ".................."; // Wifi Password </span>
<span style="color: #993300;">const char* username = "................."; // my AskSensors username </span>
<span style="color: #993300;">const char* pubTopic = "publish/..../....."; // publish/username/apiKeyIn </span>
<span style="color: #993300;">const unsigned int writeInterval = 2000; // write interval (in ms)
</span>8) Upload the code
- Connect your ESP32 board to your computer through the micro-USB cable. Make sure the power LED goes high on the module to ensure power supply.
- Open your arduino IDE and select Tools options for your ESP32 board type and serial port where it’s connected then click upload. The code will be running automatically after Reset.
- Open the serial terminal to supervise the ESP32 software sequence step by step.
- Now, we will return back to the AskSensors web application to monitor the heartbeat measurements sent by the ESP32(Beats Per Minute).

9) Source code
A basic source code is shown below. Please refer to the AskSensors Github page to get the latest version and updates.
/*
<span style="color: #993300;">* Description: Heartbeat Pulse Sensor monitoring with ESP32 and AskSensors IoT</span>
<span style="color: #993300;">* Author: https://asksensors.com, 2020</span>
<span style="color: #993300;">* github: https://github.com/asksensors</span>
<span style="color: #993300;">*/</span>
<span style="color: #993300;">#include <WiFi.h></span>
<span style="color: #993300;">#include <PubSubClient.h></span>
<span style="color: #993300;">//TODO: ESP32 MQTT user config</span>
<span style="color: #993300;">const char* ssid = ".................."; // Wifi SSID</span>
<span style="color: #993300;">const char* password = ".................."; // Wifi Password</span>
<span style="color: #993300;">const char* username = "................."; // my AskSensors username</span>
<span style="color: #993300;">const char* pubTopic = "publish/..../....."; // publish/username/apiKeyIn</span>
<span style="color: #993300;">const unsigned int writeInterval = 2000; // write interval (in ms)</span>
<span style="color: #993300;">//AskSensors MQTT config</span>
<span style="color: #993300;">const char* mqtt_server = "mqtt.asksensors.com";</span>
<span style="color: #993300;">unsigned int mqtt_port = 1883;</span>
<span style="color: #993300;">// KY039 defines</span>
<span style="color: #993300;">#define TAB_LENGTH 4</span>
<span style="color: #993300;">#define RISE_THRESHOLD 5
#define CALIB_OFFSET 0
</span>
<span style="color: #993300;">WiFiClient askClient;</span>
<span style="color: #993300;">PubSubClient client(askClient);</span>
<span style="color: #993300;">void setup() {</span>
<span style="color: #993300;">Serial.begin(115200);</span>
<span style="color: #993300;">Serial.println("*****************************************************");</span>
<span style="color: #993300;">Serial.println("********** Program Start : ESP32 publishes KY039 Heartbeat data to AskSensors over MQTT");</span>
<span style="color: #993300;">Serial.print("********** connecting to WIFI : ");</span>
<span style="color: #993300;">Serial.println(ssid);</span>
<span style="color: #993300;">WiFi.begin(ssid, password);</span>
<span style="color: #993300;">while (WiFi.status() != WL_CONNECTED) {</span>
<span style="color: #993300;">delay(500);</span>
<span style="color: #993300;">Serial.print(".");</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">Serial.println("");</span>
<span style="color: #993300;">Serial.println("->WiFi connected");</span>
<span style="color: #993300;">Serial.println("->IP address: ");</span>
<span style="color: #993300;">Serial.println(WiFi.localIP());</span>
<span style="color: #993300;">client.setServer(mqtt_server, mqtt_port);</span>
<span style="color: #993300;">client.setCallback(callback);</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">void loop() {</span>
<span style="color: #993300;">float analog_Tab[TAB_LENGTH], analog_sum;</span>
<span style="color: #993300;">float last, analog_average, start;</span>
<span style="color: #993300;">float KY039_data, first, second, third, before;</span>
<span style="color: #993300;">bool rising;</span>
<span style="color: #993300;">int rise_count, n_reads;</span>
<span style="color: #993300;">long int last_beat, now, ptr;</span>
<span style="color: #993300;">// WiFi connection </span>
<span style="color: #993300;">if (!client.connected()) </span>
<span style="color: #993300;">reconnect();</span>
<span style="color: #993300;">client.loop();</span>
<span style="color: #993300;">// Init variables</span>
<span style="color: #993300;">for (int i = 0; i < TAB_LENGTH; i++) analog_Tab[i] = 0;</span>
<span style="color: #993300;">analog_sum = 0;</span>
<span style="color: #993300;">ptr = 0;</span>
<span style="color: #993300;">while(1) {</span>
<span style="color: #993300;">// calculate an average of the sensor during a 20 ms period to eliminate the 50 Hz noise caused by electric light</span>
<span style="color: #993300;">n_reads = 0;</span>
<span style="color: #993300;">start = millis();</span>
<span style="color: #993300;">analog_average = 0.;</span>
<span style="color: #993300;">do {</span>
<span style="color: #993300;">analog_average += analogRead(A0);</span>
<span style="color: #993300;">n_reads++;</span>
<span style="color: #993300;">now = millis();</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">while (now < start + 20); </span>
<span style="color: #993300;">analog_average /= n_reads; // we got an average</span>
<span style="color: #993300;">// Add the newest measurement to an array and subtract the oldest measurement from the array</span>
<span style="color: #993300;">// to maintain a sum of last measurements</span>
<span style="color: #993300;">analog_sum -= analog_Tab[ptr];</span>
<span style="color: #993300;">analog_sum += analog_average;</span>
<span style="color: #993300;">analog_Tab[ptr] = analog_average;</span>
<span style="color: #993300;">last = analog_sum / TAB_LENGTH;</span>
<span style="color: #993300;">// now last holds the average of the values in the array</span>
<span style="color: #993300;">// check for a rising curve (= a heart beat)</span>
<span style="color: #993300;">if (last > before) {</span>
<span style="color: #993300;">rise_count++;</span>
<span style="color: #993300;">if (!rising && rise_count > RISE_THRESHOLD) {</span>
<span style="color: #993300;">// we have detected a rising curve, which implies a heartbeat.</span>
<span style="color: #993300;">// Record the time since last beat, keep track of the two previous times (first, second, third) to get a weighed average.</span>
<span style="color: #993300;">// The rising flag prevents us from detecting the same rise more than once.</span>
<span style="color: #993300;">rising = true;</span>
<span style="color: #993300;">first = millis() - last_beat;</span>
<span style="color: #993300;">last_beat = millis();</span>
<span style="color: #993300;">// Calculate the weighed average of heartbeat rate according to the three last beats</span>
<span style="color: #993300;">KY039_data = 60000. / (0.4 * first + 0.3 * second + 0.3 * third)+CALIB_OFFSET;</span>
<span style="color: #993300;">Serial.print(KY039_data);</span>
<span style="color: #993300;">Serial.println(" BPM\n"); // Unit</span>
<span style="color: #993300;">third = second;</span>
<span style="color: #993300;">second = first;</span>
<span style="color: #993300;">Serial.println("********** Publish MQTT data to ASKSENSORS");</span>
<span style="color: #993300;">char mqtt_payload[30] = "";</span>
<span style="color: #993300;">snprintf (mqtt_payload, 30, "m1=%f", KY039_data);</span>
<span style="color: #993300;">Serial.print("Publish message: ");</span>
<span style="color: #993300;">Serial.println(mqtt_payload);</span>
<span style="color: #993300;">client.publish(pubTopic, mqtt_payload);</span>
<span style="color: #993300;">Serial.println("> MQTT data published");</span>
<span style="color: #993300;">Serial.println("********** End ");</span>
<span style="color: #993300;">Serial.println("*****************************************************");</span>
<span style="color: #993300;">delay(writeInterval);// delay</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">else</span>
<span style="color: #993300;">{</span>
<span style="color: #993300;">// Ok, the curve is falling</span>
<span style="color: #993300;">rising = false;</span>
<span style="color: #993300;">rise_count = 0;</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">before = last;</span>
<span style="color: #993300;">ptr++;</span>
<span style="color: #993300;">ptr %= TAB_LENGTH;</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">// MQTT callback</span>
<span style="color: #993300;">void callback(char* topic, byte* payload, unsigned int length) {</span>
<span style="color: #993300;">Serial.print("Message arrived [");</span>
<span style="color: #993300;">Serial.print(topic);</span>
<span style="color: #993300;">Serial.print("] ");</span>
<span style="color: #993300;">for (int i = 0; i < length; i++) {</span>
<span style="color: #993300;">Serial.print((char)payload[i]);</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">Serial.println();</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">void reconnect() {</span>
<span style="color: #993300;">// Loop until we're reconnected</span>
<span style="color: #993300;">while (!client.connected()) {</span>
<span style="color: #993300;">Serial.print("********** Attempting MQTT connection...");</span>
<span style="color: #993300;">// Attempt to connect</span>
<span style="color: #993300;">if (client.connect("ESP32Client", username, "")) { </span>
<span style="color: #993300;">Serial.println("-> MQTT client connected");</span>
<span style="color: #993300;">} else {</span>
<span style="color: #993300;">Serial.print("failed, rc=");</span>
<span style="color: #993300;">Serial.print(client.state());</span>
<span style="color: #993300;">Serial.println("-> try again in 5 seconds");</span>
<span style="color: #993300;">// Wait 5 seconds before retrying</span>
<span style="color: #993300;">delay(5000);</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">}</span>
<span style="color: #993300;">}</span>
What’s Next?
That’s it! We are done with this tutorial. Thanks for your reading!
Ready to start connecting other sensors to the cloud? Have a look at this tutorials list on how to connect Things to the AskSensors IoT platform in few steps.
