0

Subscription doesn't work
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Subscription doesn't work

by jeffrey on Sun Dec 23, 2018 6:54 pm

I have an Uno connected to the Fona 808 shield. I used the mqtt_fona example to try this out. I send my location and battery voltage successfully to AdafruitIO. I have a feed called onoffbutton with a switch on the dashboard. I have the following function called in my loop, so it happens often enough that I shouldn't miss something. However, I am missing something. The onoffbutton is never received by my Uno.

Here's the code:

Code: Select all | TOGGLE FULL SIZE
/***************************************************
  Adafruit MQTT Library FONA Example

  Designed specifically to work with the Adafruit FONA
  ----> http://www.adafruit.com/products/1946
  ----> http://www.adafruit.com/products/1963
  ----> http://www.adafruit.com/products/2468
  ----> http://www.adafruit.com/products/2542

  These cellular modules use TTL Serial to communicate, 2 pins are
  required to interface.

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/
#include <Adafruit_SleepyDog.h>
#include <SoftwareSerial.h>
#include "Adafruit_FONA.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_FONA.h"

/*************************** FONA ***********************************/

// Default pins for Feather 32u4 FONA
#define FONA_RX  2
#define FONA_TX  3
#define FONA_RST 4
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);

Adafruit_FONA fona = Adafruit_FONA(FONA_RST);

const int ledPin = 13; // triggered by feed from Adafruit

// Optionally configure a GPRS APN, username, and password.
// You might need to do this to access your network's GPRS/data
// network.  Contact your provider for the exact APN, username,
// and password values.  Username and password are optional and
// can be removed, but APN is required.
#define FONA_APN       "warehouse"
#define FONA_USERNAME  ""
#define FONA_PASSWORD  ""

/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883
#define AIO_USERNAME    "jeffrey"
#define AIO_KEY         "e92e585f65ea598ccce43d14ce93c789dcd0b54a"

/************ Global State (you don't need to change this!) ******************/

// You don't need to change anything below this line!
#define halt(s) { Serial.println(F( s )); while(1);  }

// FONAconnect is a helper function that sets up the FONA and connects to
// the GPRS network. See the fonahelper.cpp tab above for the source!
boolean FONAconnect(const __FlashStringHelper *apn, const __FlashStringHelper *username, const __FlashStringHelper *password);

/****************************** Feeds ***************************************/

// Setup the FONA MQTT class by passing in the FONA class and MQTT server and login details.
Adafruit_MQTT_FONA mqtt(&fona, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
Adafruit_MQTT_Publish mylocation = Adafruit_MQTT_Publish(&mqtt,AIO_USERNAME "/feeds/mylocation/csv");
Adafruit_MQTT_Publish myVDC = Adafruit_MQTT_Publish(&mqtt,AIO_USERNAME "/feeds/myVDC");
Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/onoffbutton");
//Adafruit_MQTT_Subscribe errors = Adafruit_MQTT_Subscribe(&mqtt,AIO_USERNAME "/errors");
//Adafruit_MQTT_Subscribe throttle = Adafruit_MQTT_Subscribe(&mqtt,AIO_USERNAME "/throttle");


//#define LOCATION_FEED_NAME "mylocation"
     
/*************************** Sketch Code ************************************/

// How many transmission failures in a row we're willing to be ok with before reset
uint8_t txfailures = 0;
#define MAXTXFAILURES 3
uint8_t txFailures = 0;

float latitude, longitude, speed_kph, heading, altitude;

int count = 0; // Holds the current count for sketch.
// Define how long we delay sending data to Adafruit.io.
#define IO_LOOP_DELAY 30000
unsigned long lastUpdate = 0; // Just in case IO_LOOP_DELAY doesn't work out.

void setup() {
  pinMode(ledPin, OUTPUT);
 
  while (!Serial);

  // Watchdog is optional!
  //Watchdog.enable(10000); // 10 seconds to connect to the cell tower.
 
  Serial.begin(115200);
  Serial.println(F("Adafruit FONA MQTT demo"));

  // Initialise the FONA module
  while (! FONAconnect(F(FONA_APN), F(FONA_USERNAME), F(FONA_PASSWORD))) {
    Serial.println("Retrying FONA");
  }

  Serial.println(F("Connected to Cellular!"));

  Watchdog.reset();
  delay(5000);  // wait a few seconds to stabilize connection
  Watchdog.reset();

  //fona setup
  fona.enableGPS(true);

  MQTT_connect();
  mqtt.subscribe(&onoffbutton);
//  mqtt.subscribe(&throttle);
//  mqtt.subscribe(&errors);
}

uint32_t x=0;

void loop() {
  // Ensure the connection to the MQTT server is alive (this will make the first
  // connection and automatically reconnect when disconnected).  See the MQTT_connect
  // function definition further below.
//  if(!mqtt.ping()) {
//    mqtt.disconnect();
//  }
  MQTT_connect();

  ReadSubscription();
 
  if (millis() > (lastUpdate + IO_LOOP_DELAY)) {
    logBatteryPercent(myVDC);
    // Log the current location to the path feed if lat and long aren't zero.
    logLocation(mylocation);
    lastUpdate = millis();
  }
}

// Check subscriptions.
void ReadSubscription(){
  Serial.println("Checking subscriptions...");
  Adafruit_MQTT_Subscribe *subscription;
  Serial.println((char *)subscription);
  while ((subscription = mqtt.readSubscription(4000))){
    Serial.println((char *)subscription); // See what's coming from Adafruit.
    if (subscription == &onoffbutton){
      Serial.print(F("Got onoffbutton: "));
      Serial.println((char *)onoffbutton.lastread);
      if (strcmp((char *)onoffbutton.lastread, "ON") == 0) {
        digitalWrite(ledPin, LOW);
      }
      if (strcmp((char *)onoffbutton.lastread, "OFF") == 0) {
        digitalWrite(ledPin, HIGH);
      }
     
    }
//    else if(subscription == &errors) {
//      Serial.print(F("ERROR: "));
//      Serial.println((char *)errors.lastread);
//    }
//    else if(subscription == &throttle) {
//      Serial.println((char *)throttle.lastread);
//    }
  }
  Serial.println("Done checking subscriptions.");
}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }

  Serial.println("Connecting to MQTT... ");

  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
//    Serial.println(mqtt.connectErrorString(ret));
    Serial.println("Retrying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);  // wait 5 seconds
  }
  Serial.println("MQTT Connected!");
}

// Log battery
void logBatteryPercent(Adafruit_MQTT_Publish& publishFeed) {

 // Grab battery reading
  uint16_t vbat;
  fona.getBattPercent(&vbat);
  uint32_t FonaBat;
  FonaBat = vbat;
  // Publish
  Serial.print(F("Publishing battery percentage: "));
  Serial.println(FonaBat);
  if (!publishFeed.publish(FonaBat)) {
    Serial.println(F("Publish failed!"));
    txFailures++;
  }
  else {
    Serial.println(F("Publish succeeded!"));
    txFailures = 0;
  }
}

// Serialize the lat, long, altitude to a CSV string that can be published to the specified feed.
void logLocation(Adafruit_MQTT_Publish& publishFeed) {
  // Initialize a string buffer to hold the data that will be published.
  char sendBuffer[120];
  memset(sendBuffer, 0, sizeof(sendBuffer));
  int index = 0;

  // Start with '0,' to set the feed value.  The value isn't really used so 0 is used as a placeholder.
  sendBuffer[index++] = '0';
  sendBuffer[index++] = ',';

  bool gpsFix=fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude);
  if(latitude!=0) {
    if(longitude!=0) {
      Serial.print("Latitude: ");
      printFloat(latitude, 5);
      Serial.println("");
   
      Serial.print("Longitude: ");
      printFloat(longitude, 5);
      Serial.println("");
      // Now set latitude, longitude, altitude separated by commas.
      dtostrf(latitude, 2, 6, &sendBuffer[index]);
      index += strlen(&sendBuffer[index]);
      sendBuffer[index++] = ',';
      dtostrf(longitude, 3, 6, &sendBuffer[index]);
      index += strlen(&sendBuffer[index]);
      sendBuffer[index++] = ',';
      dtostrf(altitude, 2, 6, &sendBuffer[index]);
   
      // Finally publish the string to the feed.
      Serial.print(F("Publishing location: "));
      Serial.println(sendBuffer);
      if (!publishFeed.publish(sendBuffer)) {
        Serial.println(F("Publish failed!"));
        txFailures++;
      }
      else {
        Serial.println(F("Publish succeeded!"));
        txFailures = 0;
      }
    }
  }
 
}

void printFloat(float value, int places) {
  // this is used to cast digits
  int digit;
  float tens = 0.1;
  int tenscount = 0;
  int i;
  float tempfloat = value;

  // make sure we round properly. this could use pow from <math.h>, but doesn't seem worth the import
  // if this rounding step isn't here, the value  54.321 prints as 54.3209

  // calculate rounding term d:   0.5/pow(10,places) 
  float d = 0.5;
  if (value < 0)
    d *= -1.0;
  // divide by ten for each decimal place
  for (i = 0; i < places; i++)
    d/= 10.0;   
  // this small addition, combined with truncation will round our values properly
  tempfloat +=  d;

  // first get value tens to be the large power of ten less than value
  // tenscount isn't necessary but it would be useful if you wanted to know after this how many chars the number will take

  if (value < 0)
    tempfloat *= -1.0;
  while ((tens * 10.0) <= tempfloat) {
    tens *= 10.0;
    tenscount += 1;
  }


  // write out the negative if needed
  if (value < 0)
    Serial.print('-');

  if (tenscount == 0)
    Serial.print(0, DEC);

  for (i=0; i< tenscount; i++) {
    digit = (int) (tempfloat/tens);
    Serial.print(digit, DEC);
    tempfloat = tempfloat - ((float)digit * tens);
    tens /= 10.0;
  }

  // if no places after decimal, stop now and return
  if (places <= 0)
    return;

  // otherwise, write the point and continue on
  Serial.print('.'); 

  // now write out each decimal place by shifting digits one by one into the ones place and writing the truncated value
  for (i = 0; i < places; i++) {
    tempfloat *= 10.0;
    digit = (int) tempfloat;
    Serial.print(digit,DEC); 
    // once written, subtract off that digit
    tempfloat = tempfloat - (float) digit;
  }
}


I have serial.prints in the code to see what is coming in on the subscription and nothing is coming back from AdafruitIO.

I also tried subscribing to error and throttle, but either they aren't working or I don't have errors or the need to throttle. I am only publishing data once every 30 seconds, but I am checking the subscription a lot.

Anybody have any ideas how to get the subscription to work and what I must be missing?

jeffrey
 
Posts: 31
Joined: Sat May 12, 2012 8:04 pm

Please be positive and constructive with your questions and comments.