Build

IoT Publish-Subscribe Without an SDK

5 min read Cameron Akhavan on Apr 23, 2018

In this tutorial, we’ll show you how to use PubNub’s REST API for controlling and monitoring IoT devices. Let’s first explain what PubNub’s REST API is and why you as an IoT developer would consider using it.

Why Use the PubNub REST API?

While there are many details to learn with RESTful programming, the key idea for PubNub’s REST API is that, if you follow a very basic URL structure, you can use PubNub to publish and subscribe to data that is passed over the internet.

The advantages here are that if PubNub doesn’t have an SDK that supports your IoT device, you can use PubNub’s REST API as a workaround. You can make what are called GET requests with HTTP using nothing but a coding language like Python, C, or C++. I’ll show you what that looks like in a second.

Also, SDK files use up a lot of memory and it’s wasteful sometimes to use them when your IoT device has limited memory. With REST, you’re just communicating over the internet with your coding language’s pre-existing library, which means you can minimize the cost of your devices hardware storage components.

Of course, we have over 70 SDKs, and a number of them for IoT devices, so if that’s more your style, check them out here.

With that,let’s go through a simple demo showing how you’d use the REST API on an Arduino.

Code Walkthrough

I chose to use Python because it’s easy and really good for IoT programming. For this project, you’re going to need to implement 3 different pieces of code: One part for publishing, one for subscribing, and one for communicating with the Arduino.

Publishing

import requests
import json 
command = 0 
if __name__ == '__main__':
  while True:
    #user input
    command = input("what is you command 
") type(command) #publish request publish = requests.get('http://pubsub.pubnub.com/publish/pub-c-379c2e9b-8ffd-43b8-b2d6-ee3c2f0fbf31/sub-c-7fe8c6c0-3eba-11e8-afae-2a65d00afee8/0/ch1/0/%22' + str(command) + '%22') ## Setting up a Subscriber #subscriber format sub = 'http://pubsub.pubnub.com/subscribe/sub-c-7fe8c6c0-3eba-11e8-afae-2a65d00afee8/ch1/callback/0' #subscribe request (initial) subscribe = requests.get(sub) #subscribe request read = requests.get('http://pubsub.pubnub.com/subscribe/sub-c-7fe8c6c0-3eba-11e8-afae-2a65d00afee8/ch1/0/' + str(subscribe.content[1])) #jsonify into object jData = json.loads(read.content) #print(jData)

Note: The bottom half with Subscribe is optional

You’ll first need to import these libraries. The Python requests library is especially important, for it allows you to communicate your code with the HTTP protocol using .get() requests.

import requests
import json

Next, take in the user commands for publishing and store them in a variable. Don’t forget to initialize command to a zero or null value globally!

if __name__ == '__main__':
  while True:
    #user input
    command = input("what is you command 
") type(command)

Now it’s time to use the magical GET request for publishing. Format for the PubNub publish GET request can be found here.

At the end of the GET request string, add your user command like this:

+ str(command) +

NOTE: Since URLs have a lot of rules with which characters you’re allowed to use, you’re going to have to use %22 for any apostrophe ( “ ‘ “ ) character and %20 for spaces. It’s just URL encoding so Python doesn’t get confused.

Subscribing

Now let’s set up our subscriber to receive our messages wirelessly. We’re going to tackle this code out of order to make it more comprehensible.

import requests
import json 
import time
import serial
#subscriber format
sub = 'http://pubsub.pubnub.com/subscribe/sub-c-7fe8c6c0-3eba-11e8-afae-2a65d00afee8/ch1/callback/0'
command = 0 
#PySerial Set up
Arduino_Serial = serial.Serial('/dev/cu.usbmodem1411',9600) 
#Command Communication
def func(command):
  if command == 'ON':
     Arduino_Serial.write('1'.encode())
     print("LED ON")
  elif command == 'OFF':
     Arduino_Serial.write('0'.encode())
     print("LED OFF")
 
if __name__ == '__main__':
  while True:
    #Subscribe request (initial)
    subscribe = requests.get(sub)
    #Subscribe request into variable
    read = requests.get('http://pubsub.pubnub.com/subscribe/sub-c-7fe8c6c0-3eba-11e8-afae-2a65d00afee8/ch1/0/' + str(subscribe.content[1]))
    #Jsonify data into an object
    jData = json.loads(read.content)
    #print(jData)
    size = len(jData[0])
    command = jData[0][size-1]
    func(command)
    time.sleep(3)

First, import these libraries:

import requests
import json 
import time
import serial

Serial is a useful library for Python programming, which allows you to use Python code to communicate with Arduino Code.

Before we look at the infinite while loop in main, let’s store the subscriber GET request formatting in a variable for code cleanliness.

#subscriber format
sub = 'http://pubsub.pubnub.com/subscribe/sub-c-7fe8c6c0-3eba-11e8-afae-2a65d00afee8/ch1/callback/0'

Now use that variable to make an initial subscriber GET request. We make an initial request to get a time token.

if __name__ == '__main__':
  while True:
    #Subscribe request (initial)
    subscribe = requests.get(sub)

The time token response is going to be hidden in the second element of the array the server gives us in the response. We’re going to need to extract the time token like this when adding it to our official subscriber GET request.

#Subscribe request into variable
read = requests.get('http://pubsub.pubnub.com/subscribe/sub-c-7fe8c6c0-3eba-11e8-afae-2a65d00afee8/ch1/0/' + str(subscribe.content[1]))

This is optional, but the reason why we imported that JSON library was so we can use the very handy json.loads()function. This “jsonifiys” (or formats) our data into a neat little object.

#Jsonify data into an object
jData = json.loads(read.content)

Now, in order to grab the useful data we want (the user command), we need to dig through the double array that jData is going to spit out for us. The first array will be a list of messages that have been sent so far on that channel, and the second array will be the time token.

In order to properly extract it, we grab the last element of the first array.

#print(jData)
size = len(jData[0])
command = jData[0][size-1]

Now we call a function to handle the data at the end of the while loop

func(command)
time.sleep(3)

Here is that function that uses PySerial to communicate with Arduino code that turns an LED on if it receives the message ON and off if it receives the message OFF.

#Command Communication
def func(command):
  if command == 'ON':
     Arduino_Serial.write('1'.encode())
     print("LED ON")
  elif command == 'OFF':
     Arduino_Serial.write('0'.encode())
     print("LED OFF")

Notice: In this function, anytime we want to tell our Arduino code to turn the LED on, we send it a ‘1’, but since the Arduino is receiving the data serially through a USB into our laptop, we need to .encode() it.

Before we go to the Arduino code, here is the initialization for the PySerial capability.

#PySerial Set up
Arduino_Serial = serial.Serial('/dev/cu.usbmodem1411',9600)

“9600” is our baudrate and ‘/dev/cu.usbmodem1411’ is the port name to which our Arduino is connected to.

Arduino

const int led = 13;
char value = 2;
void setup()
{
    Serial.begin(9600);
    pinMode(led, OUTPUT);
    digitalWrite(led, LOW);
    Serial.println("Connection established...");
}
void loop()
{
    while (Serial.available())
    {
        value = Serial.read();
    }
    if (value == '1') {
        digitalWrite(led, HIGH);
    }
    else if (value == '0')
    {
        digitalWrite(led, LOW);
    }
}

This is the configuration for an LED hooked up to PIN 13 and GROUND.

Top: You can find the name of the port your Arduino is connected to by going into the top menu: Tools->Port

After you’re done writing the Arduino code, hit the green checkmark to compile and the green right arrow to upload it to your connected Arduino.

Arduino code

Now you’re all set to start using PubNub’s REST API on any Arduino device! Just run the publisher program and subscriber program on two different terminals, and you’re off!

0