0

I've an Arduino board with some sensors and one actuator. It is connected to a Raspberry Pi via a USB cable.

The idea is, normally the Arduino will be printing the data on Serial. This is retrieved by the Raspberry Pi with the help of this Python script. If any event is met in the cloud side, or if I click a button on the cloud, that should trigger the actuator on the Arduino side.

I've the following MQTT client code.

#!/usr/bin/env python
import logging
import time
import json
import serial
import paho.mqtt.client as mqtt
MQTT_BROKER = "things.ubidots.com"
MQTT_PORT = 1883  # Default MQTT Port is 1883
MQTT_KEEPALIVE_INTERVAL = 45  # In seconds
MQTT_USER_NAME = "Broker_User_Name"
MQTT_USER_PASSWORD = "Broker_User_Password"
PUB_TOPIC1 = "/v1.6/devices/mqtt/temperature"
SUB_TOPIC1 = "/v1.6/devices/mqtt/temperature"
PUB_TOPIC2 = "/v1.6/devices/mqtt/humidity"
SUB_TOPIC2 = "/v1.6/devices/mqtt/humidity"
PUB_TOPIC3 = "/v1.6/devices/mqtt/luminance"
SUB_TOPIC3 = "/v1.6/devices/mqtt/luminance"
PUB_TOPIC4 = "/v1.6/devices/mqtt/ADC"
SUB_TOPIC4 = "/v1.6/devices/mqtt/ADC"
PUB_TOPIC5 = "/v1.6/devices/mqtt/Battery_Status"
SUB_TOPIC5 = "/v1.6/devices/mqtt/Battery_Status"
Quqlity_of_Service = 0

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)                                                                               
handler = logging.FileHandler('MQTT_log_file.log')  # create a file handler
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') # create a logging format
handler.setFormatter(formatter)
logger.addHandler(handler)# add the handlers to the logger
logger.info("")
logger.info("######## Program started ########")

MQTT_MSG1 = 0
MQTT_MSG2 = 0
MQTT_MSG3 = 0
MQTT_MSG4 = 0
MQTT_MSG5 = 0
msg_body = ""
rc = 0  # For error checking

time.sleep(0.3)
pub_sub_option = int(raw_input("Do you want to be:\n 1.Publisher\n 2.Subscriber\n 3.Both\n :"))
logger.info("\nPublisher and Subscriber Option: {}".format(pub_sub_option))
if pub_sub_option == 1:
    print("")
    print("You have selected only Publisher")
    print("")
elif pub_sub_option == 2:
    print("")
    print("You have selected only Subscriber")
    print("")
elif pub_sub_option == 3:
    print("")
    print("You have selected both Publisher and Subscriber")
    print("")
else:
    print("")
    print("Please select the correct option.")
    print("")

if pub_sub_option == 1:
    publisher_check = 1
    subscriber_check = 0
elif pub_sub_option == 2:
    publisher_check = 0
    subscriber_check = 1
elif pub_sub_option == 3:
    publisher_check = 1
    subscriber_check = 1

serial_data = serial.Serial(port='/dev/ttyACM0', baudrate=115200) # Read the Sensor Data
logger.debug("Serial Data: {}".format(serial_data))

#  ----# Json Data Converter Function #----
def json_data_publish(PUB_TOPIC, sensor_variable, Quqlity_of_Service):
    message = {'value': sensor_variable}
    logger.debug("Json Data Publisher Value: {}".format(message))
    mqttc.publish(PUB_TOPIC, json.dumps(message), Quqlity_of_Service)

def connack_string(connack_code):
    """Return the string associated with a CONNACK result"""
    if connack_code == 0:
        return "Connection Accepted."
    elif connack_code == 1:
        return "Connection Refused: unacceptable protocol version."
    elif connack_code == 2:
        return "Connection Refused: identifier rejected."
    elif connack_code == 3:
        return "Connection Refused: broker unavailable."
    elif connack_code == 4:
        return "Connection Refused: bad user name or password."
    elif connack_code == 5:
        return "Connection Refused: not authorised."
    else:
        return "Connection Refused: unknown reason."

# Define on_connect event Handler
def on_connect(client, userdata, flags, rc):
    logger.debug(connack_string(int(rc)))
    print(connack_string(int(rc)))

# Define on_message event Handler for Topic 1
def on_message(client, userdata, msg):
    logger.debug("Control is in On_Message")
    received_topic = str(msg.topic)
    received_message = str(msg.payload.decode())

    if received_topic != "" and received_message != "":
        if received_topic == SUB_TOPIC1:
            received_temp_data = int(received_message)
            print("The Received Temperature Data is: {}\n".format(received_temp_data))
            logger.debug("The Received Temperature Data is: {}".format(received_temp_data))

        elif received_topic == SUB_TOPIC2:
            received_humid_data = int(received_message)
            print("The Received Humidity Data is: {}\n".format(received_humid_data))
            logger.debug("The Received Humidity Data is: {}".format(received_humid_data))

# Define on_publish event Handler
def on_publish(client, userdata, mid):
    pass

# Initiate MQTT Client
mqttc = mqtt.Client()
logger.debug("MQTT Client is Initialized")

# Connect with MQTT Broker
mqttc.username_pw_set(MQTT_USER_NAME, MQTT_USER_PASSWORD)
mqttc.connect(MQTT_BROKER, MQTT_PORT, MQTT_KEEPALIVE_INTERVAL)
logger.debug("Connected to MQTT Broker")

# Register Event Handlers
mqttc.on_connect = on_connect
logger.debug("Control is in On_Connect Event Handler")
mqttc.on_message = on_message
logger.debug("Control is in On_Message Event Handler")

# subscribe for topic
if subscriber_check == 1:
    mqttc.subscribe(SUB_TOPIC1, Quqlity_of_Service)
    mqttc.subscribe(SUB_TOPIC2, Quqlity_of_Service)
    mqttc.subscribe(SUB_TOPIC3, Quqlity_of_Service)
    mqttc.subscribe(SUB_TOPIC4, Quqlity_of_Service)
    mqttc.subscribe(SUB_TOPIC5, Quqlity_of_Service)

while rc == 0:
    try:
        rc = mqttc.loop()
        if publisher_check == 1:
#    ----  # Data from Real Sensors #----
            data = serial_data.readline(20)
            pieces = data.split(":")
            if pieces[0] == "Temperature":
                MQTT_MSG1 = pieces[1]
            if pieces[0] == "Humidity":
                MQTT_MSG2 = pieces[1]
            if pieces[0] == "Luminance":
                MQTT_MSG3 = pieces[1]
            if pieces[0] == "ADC":
                MQTT_MSG4 = pieces[1]
            if pieces[0] == "Battery_Status":
                MQTT_MSG5 = pieces[1]
            logger.debug("Json Enabled")
            json_data_publish(PUB_TOPIC1, MQTT_MSG1, Quqlity_of_Service)
            print("Temperature {} Published\n".format(MQTT_MSG1))
            logger.debug("Temperature {} Published with QOS = {}".format(MQTT_MSG1, Quqlity_of_Service))
            time.sleep(1)
            json_data_publish(PUB_TOPIC2, MQTT_MSG2, Quqlity_of_Service)
            print("Humidity {} Published\n".format(MQTT_MSG2))
            logger.debug("Humidity {} Published with QOS = {}".format(MQTT_MSG2, Quqlity_of_Service))
            time.sleep(1)
            json_data_publish(PUB_TOPIC3, MQTT_MSG3, Quqlity_of_Service)
            print("Luminance {} Published\n".format(MQTT_MSG3))
            logger.debug("Luminance {} Published with QOS = {}".format(MQTT_MSG3, Quqlity_of_Service))
            time.sleep(1)
            json_data_publish(PUB_TOPIC4, MQTT_MSG4, Quqlity_of_Service)
            print("ADC {} Published\n".format(MQTT_MSG4))
            logger.debug("ADC {} Published with QOS = {}".format(MQTT_MSG4, Quqlity_of_Service))
            time.sleep(1)
            json_data_publish(PUB_TOPIC5, MQTT_MSG5, Quqlity_of_Service)
            print("Battery_Status {} Published\n".format(MQTT_MSG5))
            logger.debug("Battery_Status {} Published with QOS = {}".format(MQTT_MSG5, Quqlity_of_Service))
            time.sleep(1)
    except KeyboardInterrupt:
        print("\nThe Process is Terminated")
        break

This code can be used as

  1. MQTT Publisher
  2. MQTT Subscriber
  3. MQTT Publisher and Subscriber

But normally in my setup it is alway operated in mode 3 (both publisher and subscriber), as I want to trigger the actuator.

The code uploads the data without any problem. But the problem comes when receiving it. There will be a delay while receiving data. But if I run the same code as subscriber (mode 2) from my laptop it works perfectly. As soon data is uploaded it gets received in my laptop.

And please let me know if I can write the same code in a much more efficient way.

Arunkrishna
  • 51
  • 2
  • 7

1 Answers1

0

I'm going to guess that the delay is in the sleep method in the while loop. Why don't you separate the code into 'sub' and 'pub' code and run them separately on the Raspberry Pi. I'm not a Python expert but I think everything is running under a single thread, hence, when you sleep, it is pausing the only thread.

Roger
  • 7,062
  • 13
  • 20
  • Yeah. I'm using free service from cloud service provider. So I can only send a data for every one second, So I've use delay in between. I check with multithreading as you have suggested. Thankyou – Arunkrishna Aug 29 '17 at 04:45