PubNub recently revamped its C-Core SDK’s you can find the details here on our GitHub page. It provides updated support for newer chips including Espressif, notably ESP32S3 chipsets!
PubNub has long been a champion of the IoT space. We have a number of customers who use us to deliver sensor data to & from factories, farms and fields. Creating digital twins of buildings, spaces and events for a while now.
With access to IoT chips readily available and incredibly cheap. You can build some amazing IoT projects powered by PubNub.
One recent project that I did using an ESP32 chip & PubNub was to manage the turning on & off of a ground source heat water pump.
Here’s some brief details on the project
The pump needs to function automatically, turning on at 11pm and off at 8am daily.
An ‘On’ Switch needs to be included so that a human can manually turn on the pump.
A temperature sensor needs to be included, when the temperature drops below 1C then turn on the pump.
Using PubNub, I want to be able to log when the last on/off event occurred
Using PubNub, I want to be able to turn on & off the pump
Here’s a small circuit diagram
(I'm aware this is an Arduino UNO Chip, for some reason the schematic software I use couldn't make an ESP chip look this good!)
Breaking down the circuit
Black - Ground
Red - 5 Volt
Orange - Temperature input sensor
Green - Switch / Button input
Yellow - Relay activate output
Red/Green/Blue - Tricolor LED.
Brown & Purple - AC Lines that power the pump.
Playing with high voltage electricity is very dangerous and you should take all necessary precautions, consult a qualified electrician as required.
Here's the physical hardware:
With the hardware now complete we can turn to the software component. With ESP32 chips you can use Arduino IDE or equivalent to write and upload the code to the chip.
The Libraries used in this script are:
WiFi.h
WiFiUdp.h
NTPClient.h
TimeLib.h
OneWire.h
DallasTemperature.h
PubNub.h
WiFi Libraries are used to connect to a Wifi network and manage that connection. NTP and TimeLib are used to get and maintain the current time from an NTP Server. OneWire and DallasTemperature are used to get the temperature from the thermal probe. PubNub is used to publish data to PubNub and separately subscribe to a channel ready to receive data and/or commands.
Here's the initial code:
#include <WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <TimeLib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 6
// WiFi credentials
const char* ssid = "WiFiSSID Goes HERE";
const char* password = "Your WiFi Password goes here.";
// Setup Temp Probe
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// NTP settings
const long utcOffsetInSeconds = -5 * 3600; // Eastern Standard Time (EST) offset: UTC -5 hours
const int daylightOffsetInSeconds = 3600; // Daylight Saving Time (DST) offset: UTC +1 hour
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds + daylightOffsetInSeconds);
// Pin definitions
const int onSwitchPin = 47; // Manual override switch
const int relayPin = 15; // Relay control pin
// System
const int onTime = 23; // Relay on at 23:00
const int offTime = 8; // Relay off at 08:00
// Temperature thresholds
const int lowTempActivate = 1; // Activate relay below 1C
const int lowTempDeactivate = 2; // Deactivate relay above 2C
// Variables
int currentRelayStatus = LOW; // Current relay status
If you're copying this, make sure you update the code to represent your pin numbers, pump on/off times, wifi credentials and UTC time.
Once we have declared all of our variables we can compile our setup loop.
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
// Initialize WiFi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" Connected!");
// Initialize NTP client
timeClient.begin();
// Initialize temperature sensor
sensors.begin();
// Set up pins
pinMode(onSwitchPin, INPUT_PULLUP);
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, LOW); // Ensure relay is off initially
}
Looking at what goes on in the setup loop;
A serial connection is created
The chip connects to the wifi
Once a connection is established, we connect to an NTP Server and obtain the local time
The setup for the temperature sensor takes place
The setup for the input and output pins takes place
This is the main loop code:
void loop() {
// Update NTP time
timeClient.update();
// Get current hour
int currentHour = (timeClient.getEpochTime() % 86400L) / 3600;
Serial.print("Current hour: ");
Serial.println(currentHour);
// Read temperature
sensors.requestTemperatures();
float currentTemp = sensors.getTempCByIndex(0);
Serial.print("Current temperature: ");
Serial.println(currentTemp);
// Read manual switch state
bool manualSwitch = digitalRead(onSwitchPin) == LOW;
// Determine relay state
if (manualSwitch) {
// Manual override: Turn relay on
currentRelayStatus = HIGH;
} else if (currentHour >= onTime || currentHour < offTime) {
// Time-based control
if (currentTemp < lowTempActivate) {
currentRelayStatus = HIGH;
} else if (currentTemp > lowTempDeactivate) {
currentRelayStatus = LOW;
}
} else {
// Outside time range
currentRelayStatus = LOW;
}
// Update relay state
digitalWrite(relayPin, currentRelayStatus);
// Debugging
Serial.print("Relay state: ");
Serial.println(currentRelayStatus == HIGH ? "ON" : "OFF");
// Wait 1 second before next loop
delay(1000);
}
At the top of the function we get the current time, read the temperature value and check to see if the manual switch is on.
Once we have all the required inputs we can determine what state the relay should be in.
Adding PubNub to the mix
As I mentioned in the beginning, I want to use PubNub to both log the on/off events and also trigger a remote activation of the pump.
You can find the the new SDK here: https://github.com/pubnub/c-core
With the library installed we can setup our connection to PubNub.
With sending data to PubNub you need a few things:
Pub and Sub keys, these can be found in your PubNub Console at: https://admin.pubnub.com
Channel to send messages to, you can find a doc on channel design here: https://www.pubnub.com/docs/general/channels/overview
JSON Message Object, as part of our docs you can read all about how to send structured data over PubNub; https://www.pubnub.com/docs/general/messages/type
// PubNub credentials
const char* pub_key = "YourPubKey"; // Replace with your PubNub publish key
const char* sub_key = "YourSubKey"; // Replace with your PubNub subscribe key
const char* channel = "PumpBot"; // Replace with your PubNub channel.
void setup() {
…
// Initialize PubNub
PubNub.begin(pub_key, sub_key);
}
void loop() {
…
// Check for incoming messages
PubSubClient *subClient = PubNub.subscribe(channel);
if (subClient) {
char c;
String msg = "";
while (subClient->connected() && (c = subClient->read()) >= 0) {
msg += c;
}
subClient->stop();
// Parse the received message
if (msg.length() > 0) {
Serial.println("Received message: " + msg);
if (msg.indexOf("\"type\": \"action\", \"command\": \"on\"") > -1) {
Serial.println("Turning pump ON.");
digitalWrite(pumpPin, HIGH); // Turn pump on
} else if (msg.indexOf("\"type\": \"action\", \"command\": \"off\"") > -1) {
Serial.println("Turning pump OFF.");
digitalWrite(pumpPin, LOW); // Turn pump off
}
}
}
}
These changes allow the script to connect to PubNub and receive a json message {"type": "action", "command": "on"} which will activate the pump.
Finally lets add in the logging so that when the pump is turned on or off, it publishes a message to PubNub letting us log and track when the pump is turned on:
void publishPumpState(const char* state) {
String message = "{\"type\": \"action\", \"pump\": \"" + String(state) + "\"}";
PubNonSubClient *client = PubNub.publish(channel, message.c_str());
if (!client) {
Serial.println("Failed to publish pump state.");
} else {
char c;
while (client->connected() && (c = client->read()) >= 0) {
Serial.print(c);
}
Serial.println("\nPump state published successfully.");
}
client->stop();
}
void loop() {
…
if (buttonState == LOW && lastButtonState == HIGH) {
Serial.println("Button pressed! Sending event to PubNub...");
// Publish message to PubNub
publishPumpState("on"); // Publish pump state
if (!client) {
Serial.println("Failed to publish message.");
} else {
char c;
while (client->connected() && (c = client->read()) >= 0) {
Serial.print(c);
}
Serial.println("\nMessage published successfully.");
}
client->stop();
}
}
If you need to track what state the pump is, you can jump into your admin console at: https://admin.pubnub.com and navigate to the debug page:
Closing Out
PubNub is a great use case for the control and utility monitoring of IoT Devices. With realtime messaging at the core of sending information to/from a device you can quickly build a stable and fast network that lets you monitor and interact with systems, devices, pumps and digital twins.
If you would like to know more about how PubNub can help you with your IoT projects please reach out, our teams would love to help.
Sign up for a free account today, or discuss your needs with one of our solution experts.