Tuesday, February 23, 2016

Arduino - MQTT - Raspberry Pi

a. What I have done in the class:

I have integrated my Raspberry Pi and Arduino through MQTT, to listen and respond on photocell(sensors that allow you to detect light) readings. I used pubsubclient to test request-response on wifi. Arduino - Pubsubclient provides examples of basic tests, so that we can test pre requirements.

Arduino - Hardware
  1. Arduino WiFi Module
  2. Photocell
  3. Resistors (10k, 330 ohm)
  4. LED
  5. Jumping wires
Arduino - Software / MQTT
There are four main tasks the Arduino software needs to take care of for this example:
  • Gather light sensor readings periodically
  • Publish sensor readings via MQTT
  • Listen for commands via MQTT
  • Control the LED based on a setpoint
  • An MQTT client is created in the setup function.
Experimnet overview:

The MQTT client connects (if it is not already connected).
Based on the “sensing mode” the application decides how to drive the LED.  It could be OFF, ON or SENSE.  In the SENSE case a light reading is taken and the LED is driven according to a hardcoded setpoint.

#include <SPI.h>
#include <PubSubClient.h>
#include <ESP8266WiFi.h>

#define MQTT_SERVER "q.m2m.io"

byte MAC_ADDRESS[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x31, 0xB8 };
PubSubClient client;

// Pin 9 is the LED output pin
int ledPin = 9;
// Analog 0 is the input pin
int lightPinIn = 0;

// defines and variable for sensor/control mode
#define MODE_OFF    0  // not sensing light, LED off
#define MODE_ON     1  // not sensing light, LED on
#define MODE_SENSE  2  // sensing light, LED controlled by software
int senseMode = 0;

unsigned long time;

char message_buff[100];

void setup()
{
  // initialize the digital pin as an output.
  pinMode(ledPin, OUTPUT);

  // init serial link for debugging
  Serial.begin(9600);

  if (Ethernet.begin(MAC_ADDRESS) == 0)
  {
      Serial.println("Failed to configure Ethernet using DHCP");
      return;
  }

  client = PubSubClient(MQTT_SERVER, 1883, callback);
}

void loop()
{
  if (!client.connected())
  {
      // clientID, username, MD5 encoded password
      client.connect("arduino-mqtt", "", "");
      client.publish("io.m2m/arduino/lightsensor", "I'm alive!");
      client.subscribe("io.m2m/arduino/lightsensor");
  }

  switch (senseMode) {
    case MODE_OFF:
      // light should be off
      digitalWrite(ledPin, LOW);
      break;
    case MODE_ON:
      // light should be on
      digitalWrite(ledPin, HIGH);
      break;
    case MODE_SENSE:
      // light is adaptive to light sensor
   
      // read from light sensor (photocell)
      int lightRead = analogRead(lightPinIn);

      // if there is light in the room, turn off LED
      // else, if it is "dark", turn it on
      // scale of light in this circit is roughly 0 - 900
      // 500 is a "magic number" for "dark"
      if (lightRead > 500) {
        digitalWrite(ledPin, LOW);
      } else {
        digitalWrite(ledPin, HIGH);
      }
   
      // publish light reading every 5 seconds
      if (millis() > (time + 5000)) {
        time = millis();
        String pubString = "{\"report\":{\"light\": \"" + String(lightRead) + "\"}}";
        pubString.toCharArray(message_buff, pubString.length()+1);
        //Serial.println(pubString);
        client.publish("io.m2m/arduino/lightsensor", message_buff);
      }
   
   
  }

  // MQTT client loop processing
  client.loop();
}

// handles message arrived on subscribed topic(s)
void callback(char* topic, byte* payload, unsigned int length) {

  int i = 0;

  for(i=0; i<length; i++) {
    message_buff[i] = payload[i];
  }
  message_buff[i] = '\0';

  String msgString = String(message_buff);

  if (msgString.equals("{\"command\":{\"lightmode\": \"OFF\"}}")) {
    senseMode = MODE_OFF;
  } else if (msgString.equals("{\"command\":{\"lightmode\": \"ON\"}}")) {
    senseMode = MODE_ON;
  } else if (msgString.equals("{\"command\":{\"lightmode\": \"SENSE\"}}")) {
    senseMode = MODE_SENSE;
  }
}

I was able to connect and receive the responses, but I didn't observe the light to be turn on and off.
I think I still need to improve the program to work on my experiment.



Program to connect to the MQTT Server:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <String.h>


const char* ssid = "Pi_AP";
const char* password = "Raspberry";
const char* mqtt_server = "192.168.0.34";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
int timer = 200;
int ar[] = {15, 12, 4, 16};


void setup_wifi() {

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}



void off() {

  for(int i = 0; i < 4 ; i++){
  digitalWrite(ar[i], LOW);
  }

}

void red() {
  off();
  for(int i = 0; i < 2 ; i++){
    digitalWrite(ar[i], HIGH);
  }
}

void yellow() {
  off();
  for(int i = 2; i < 4 ; i++){
    digitalWrite(ar[i], HIGH);
  }
}


void allOn() {

  for(int i = 0; i < 4 ; i++){
  digitalWrite(ar[i], HIGH);
  }

}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  Serial.println();

  String s = "";

  for(int i = 0; i< length; i++) {
    char a = ((char)payload[i]);
    s = s + a;
  }


  if( s == "disco") {
    disco();
  }
  else if( s == "on"){
    allOn();
  }
  else if( s == "off") {
    off();
  }
  else if(s == "red") {
    red();
  }
  else if(s == "yellow") {
    yellow();
  }

}

void reconnect() {
   while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
      if (client.connect("ESP8266Client")) {
      Serial.println("connected");
          client.publish("outTopic", "hello world");
        client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
           delay(5000);
    }
  }
}

void setup() {
  for(int i = 0; i < 4; i++){
    pinMode(ar[i],OUTPUT);  
  }
  Serial.begin(115200);

  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  if (now - lastMsg > 1000) {
    lastMsg = now;
    ++value;
    snprintf (msg, 75, "hello world #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish("outTopic", msg);
     }
}

b. To whom I helped and What I did for them:

  • I  helped HemaLatha to connect to her server and getting connection responses from the server. Also I helped her to modify the code to work on our experiment to get the result. In the class, she almost done with her experiment. We saw the light blinked only once, but need to implement further.
  • I also helped Bhargav, Pavan, Sandeep and Jorge, to do basic test on pubsubclient.

c. Who helped me and What they did for me:

  • Bhargav, Pavan, Sandeep and Jorge helped to me find the resources on the web, wiring diagrams and modification in the given code.

References:

  • http://www.rs-online.com/designspark/electronics/blog/building-distributed-node-red-applications-with-mqtt
  • http://jpmens.net/2013/09/01/installing-mosquitto-on-a-raspberry-pi/
  • http://pubsubclient.knolleary.net/
  • https://learn.adafruit.com/photocells/overview
  • http://m2mio.tumblr.com/post/30048662088/a-simple-example-arduino-mqtt-m2mio

No comments:

Post a Comment