0

Data is parsed, but not visualized. IO Dashboard
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Data is parsed, but not visualized. IO Dashboard

by Fantomaz on Wed May 01, 2019 3:59 pm

Hi you Guys,

I managed to understand the Fona along with the Arduino somewhat, the last couple of weeks.
I even got the github examples of a Geofencing project working including MQTT... More or less...

The problem I encountered was that the Fona did get the right coordinates by its GPS, but that I was not able to view it on Adafruits' IO server dashboard.
I monitored the actions of the Arduino on my serial monitor and as far as I understand, the data was successfully parsed to the IO dashboard. For that matter, I got a perfect readout of the Battery power, nicely on a scale. So data is sent and received but only partly visualized.

What might be the reason for that?

Code: Select all | TOGGLE FULL SIZE
// Geo Fencing project with Adafruit IO
// Author: Marco Schwartz
//
// Inspired by the code from Tony DiCola
//
// Released under a MIT license:
// https://opensource.org/licenses/MIT

// Libraries
#include <Adafruit_SleepyDog.h>
#include <SoftwareSerial.h>
#include "Adafruit_FONA.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_FONA.h"

// Alarm pins
const int ledPin = 6;

// Size of the geo fence (in meters)
const float maxDistance = 100;

// Latitude & longitude for distance measurement
float initialLatitude;
float initialLongitude;
float latitude, longitude, speed_kph, heading, altitude;

// FONA pins configuration
#define FONA_RX              2   // FONA serial RX pin (pin 2 for shield).
#define FONA_TX              3   // FONA serial TX pin (pin 3 for shield).
#define FONA_RST             4   // FONA reset pin (pin 4 for shield)

// FONA GPRS configuration
#define FONA_APN             "internet"  // APN used by cell data service (leave blank if unused)
#define FONA_USERNAME        ""  // Username used by cell data service (leave blank if unused).
#define FONA_PASSWORD        ""  // Password used by cell data service (leave blank if unused).

// Adafruit IO configuration
#define AIO_SERVER           "io.adafruit.com"  // Adafruit IO server name.
#define AIO_SERVERPORT       1883  // Adafruit IO port.
#define AIO_USERNAME         "your-adafruit-io-name"  // Adafruit IO username (see http://accounts.adafruit.com/).
#define AIO_KEY              "your-adafruit-io-key"  // Adafruit IO key (see settings page at: https://io.adafruit.com/settings).

// Feeds
#define LOCATION_FEED_NAME       "location"  // Name of the AIO feed to log regular location updates.
#define MAX_TX_FAILURES      3  // Maximum number of publish failures in a row before resetting the whole sketch.

// FONA instance & configuration
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);     // FONA software serial connection.
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);                 // FONA library connection.
const char MQTT_SERVER[] = AIO_SERVER;
const char MQTT_USERNAME[]  = AIO_USERNAME;
const char MQTT_PASSWORD[]  = AIO_KEY;

// Setup the FONA MQTT class by passing in the FONA class and MQTT server and login details.
Adafruit_MQTT_FONA mqtt(&fona, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD);

uint8_t txFailures = 0;                                       // Count of how many publish failures have occured in a row.

// Feeds configuration
const char LOCATION_FEED[] = AIO_USERNAME "/feeds/" LOCATION_FEED_NAME "/csv";
Adafruit_MQTT_Publish location_feed = Adafruit_MQTT_Publish(&mqtt, LOCATION_FEED);

const char BATTERY_FEED[] = AIO_USERNAME "/feeds/battery";
Adafruit_MQTT_Publish battery_feed = Adafruit_MQTT_Publish(&mqtt, BATTERY_FEED);

const char ALERTS_FEED[] = AIO_USERNAME "/feeds/alerts";
Adafruit_MQTT_Publish alerts_feed = Adafruit_MQTT_Publish(&mqtt, ALERTS_FEED);

void setup() {
 
  // Initialize serial output.
  Serial.begin(115200);
  Serial.println(F("Geofencing with Adafruit IO & FONA808"));

  // Set alarm components
  pinMode(ledPin, OUTPUT);

  // Initialize the FONA module
  Serial.println(F("Initializing FONA....(may take 10 seconds)"));
  fonaSS.begin(4800);
  if (!fona.begin(fonaSS)) {
    halt(F("Couldn't find FONA"));
  }
  fonaSS.println("AT+CMEE=2");
  Serial.println(F("FONA is OK"));

  // Use the watchdog to simplify retry logic and make things more robust.
  // Enable this after FONA is intialized because FONA init takes about 8-9 seconds.
  Watchdog.enable(8000);
  Watchdog.reset();

  // Wait for FONA to connect to cell network (up to 8 seconds, then watchdog reset).
  Serial.println(F("Checking for network..."));
  while (fona.getNetworkStatus() != 1) {
   delay(500);
  }

  // Enable GPS.
  fona.enableGPS(true);

  // Start the GPRS data connection.
  Watchdog.reset();
  fona.setGPRSNetworkSettings(F(FONA_APN));
  //fona.setGPRSNetworkSettings(F(FONA_APN), F(FONA_USERNAME), F(FONA_PASSWORD));
  delay(2000);
  Watchdog.reset();
  Serial.println(F("Disabling GPRS"));
  fona.enableGPRS(false);
  delay(2000);
  Watchdog.reset();
  Serial.println(F("Enabling GPRS"));
  if (!fona.enableGPRS(true)) {
    halt(F("Failed to turn GPRS on, resetting..."));
  }
  Serial.println(F("Connected to Cellular!"));

  // Wait a little bit to stabilize the connection.
  Watchdog.reset();
  delay(3000);

  // Now make the MQTT connection.
  int8_t ret = mqtt.connect();
  if (ret != 0) {
    Serial.println(mqtt.connectErrorString(ret));
    halt(F("MQTT connection failed, resetting..."));
  }
  Serial.println(F("MQTT Connected!"));

  // Initial GPS read
  bool gpsFix = fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude);
  initialLatitude = latitude;
  initialLongitude = longitude;

  // Set alert to 0
  logAlert(0, alerts_feed);

}

void loop() {
 
  // Watchdog reset at start of loop--make sure everything below takes less than 8 seconds in normal operation!
  Watchdog.reset();

  // Reset everything if disconnected or too many transmit failures occured in a row.
  if (!fona.TCPconnected() || (txFailures >= MAX_TX_FAILURES)) {
    halt(F("Connection lost, resetting..."));
  }

  // Grab a GPS reading.
  float latitude, longitude, speed_kph, heading, altitude;
  bool gpsFix = fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude);

  Serial.print("Latitude: ");
  printFloat(latitude, 5);
  Serial.println("");

  Serial.print("Longitude: ");
  printFloat(longitude, 5);
  Serial.println("");

  // Calculate distance between new & old coordinates
  float distance = distanceCoordinates(latitude, longitude, initialLatitude, initialLongitude);
 
  Serial.print("Distance: ");
  printFloat(distance, 5);
  Serial.println("");

  // Set alarm on?
  if (distance > maxDistance) {
    logAlert(1, alerts_feed);
  }
 
  // Grab battery reading
  uint16_t vbat;
  fona.getBattPercent(&vbat);

  // Log the current location to the path feed, then reset the counter.
  logLocation(latitude, longitude, altitude, location_feed);
  logBatteryPercent(vbat, battery_feed);
 
  // Wait 5 seconds
  delay(5000);

}

// Log alerts
void logAlert(uint32_t alert, Adafruit_MQTT_Publish& publishFeed) {

  // Publish
  Serial.print(F("Publishing alert: "));
  Serial.println(alert);
  if (!publishFeed.publish(alert)) {
    Serial.println(F("Publish failed!"));
    txFailures++;
  }
  else {
    Serial.println(F("Publish succeeded!"));
    txFailures = 0;
  }
 
}

// Log battery
void logBatteryPercent(uint32_t indicator, Adafruit_MQTT_Publish& publishFeed) {

  // Publish
  Serial.print(F("Publishing battery percentage: "));
  Serial.println(indicator);
  if (!publishFeed.publish(indicator)) {
    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(float latitude, float longitude, float altitude, 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++] = ',';

  // 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;
  }
}


// Halt function called when an error occurs.  Will print an error and stop execution while
// doing a fast blink of the LED.  If the watchdog is enabled it will reset after 8 seconds.
void halt(const __FlashStringHelper *error) {
  Serial.println(error);
  while (1) {
    digitalWrite(ledPin, LOW);
    delay(100);
    digitalWrite(ledPin, HIGH);
    delay(100);
  }
}

// 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.print("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!");
}

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;
  }
}

// Calculate distance between two points
float distanceCoordinates(float flat1, float flon1, float flat2, float flon2) {

  // Variables
  float dist_calc=0;
  float dist_calc2=0;
  float diflat=0;
  float diflon=0;

  // Calculations
  diflat  = radians(flat2-flat1);
  flat1 = radians(flat1);
  flat2 = radians(flat2);
  diflon = radians((flon2)-(flon1));

  dist_calc = (sin(diflat/2.0)*sin(diflat/2.0));
  dist_calc2 = cos(flat1);
  dist_calc2*=cos(flat2);
  dist_calc2*=sin(diflon/2.0);
  dist_calc2*=sin(diflon/2.0);
  dist_calc +=dist_calc2;

  dist_calc=(2*atan2(sqrt(dist_calc),sqrt(1.0-dist_calc)));
 
  dist_calc*=6371000.0; //Converting to meters

  return dist_calc;
}

Fantomaz
 
Posts: 16
Joined: Sun May 21, 2017 5:14 pm

Re: Data is parsed, but not visualized. IO Dashboard

by adafruit_support_mike on Thu May 02, 2019 4:48 am

I've moved this to the Adafruit.IO forum, but will keep an eye on it in case there are any questions or issues specifically related to the FONA.

Do you happen to have a copy of the GPS information the microcontroller has sent to your Adafruit.IO account so far?

adafruit_support_mike
 
Posts: 57131
Joined: Thu Feb 11, 2010 2:51 pm

Re: Data is parsed, but not visualized. IO Dashboard

by Fantomaz on Thu May 02, 2019 7:30 am

No, but that can be arranged.
I'll continue this treath in the IO section.
Tx so far.

Fantomaz
 
Posts: 16
Joined: Sun May 21, 2017 5:14 pm

Re: Data is parsed, but not visualized. IO Dashboard

by brubell on Thu May 09, 2019 10:02 am

Are the feeds being updated with GPS location? The data point should include locational data as metadata (see: https://io.adafruit.com/api/docs/?cpp#create-data).

You may want to switch to the Adafruit IO Arduino library from Adafruit MQTT; it allows passing locational metadata along with the value, check out the example in the sidebar for the URL linked.

brubell
 
Posts: 380
Joined: Fri Jul 17, 2015 10:33 pm

Re: Data is parsed, but not visualized. IO Dashboard

by Fantomaz on Thu May 09, 2019 5:16 pm

First, Sorry Mike for the lack of returned info. I'm somewhat occupied with my job.

Brubell, If I understand it correctly, you pointed out to me how to parse the coordinate data?
I use a (proven?) workable sketch and if I get it right (based on the serial monitor data I examened), the location data is parsed twice. Raw as a string of numbers/digits and more recognizable as Longitude/Latitude.

The link you ad. in your reply, directs me to an example? Or to the conditions of how de format of the data should look like?

Fantomaz
 
Posts: 16
Joined: Sun May 21, 2017 5:14 pm

Re: Data is parsed, but not visualized. IO Dashboard

by brubell on Fri May 10, 2019 9:55 am

The Map dashboard element only parses the metadata associated with a value on a feed. You mentioned your dashboard, are you trying to use another type of block other than the map block?

Could you post a screenshot of the dashboard with the party visualized location data?

brubell
 
Posts: 380
Joined: Fri Jul 17, 2015 10:33 pm

Re: Data is parsed, but not visualized. IO Dashboard

by Fantomaz on Sun May 19, 2019 12:01 pm

Hello Brubell,

I have a dashboard, containing 3 feeds.
One which visualizes the remaining power in de battery, which works correctly.
Besides that one, I have 2 feeds, containing the same data. One to visualize the coordinates in text. And one where those coordinates are visualized on a map.

Both cases, containing coordinates, are not parsed. At least not in a way for me to monitor them on my dashboard.

screenshot dashboard.jpg
screenshot dashboard.jpg (62.87 KiB) Viewed 34 times

Block inspector MAP.jpg
Block inspector MAP.jpg (56.73 KiB) Viewed 34 times

Block inspector TEXT coordinates.jpg
Block inspector TEXT coordinates.jpg (60.79 KiB) Viewed 34 times

Fantomaz
 
Posts: 16
Joined: Sun May 21, 2017 5:14 pm

Re: Data is parsed, but not visualized. IO Dashboard

by brubell on Mon May 20, 2019 9:55 am

Can you post a screenshot of the location feeds? I'm curious why the data in the feed isn't getting parsed by the text block...

brubell
 
Posts: 380
Joined: Fri Jul 17, 2015 10:33 pm

Please be positive and constructive with your questions and comments.