Trying to print hex value of fingerprint sensor to the cloud

Hi,

I am using the adafruit example of the fingerprint sensor to print the hex value to the cloud.
As of now I am able to print that data on the serial monitor, but when I try to use the same logic or add that data to an array and then print that data to the cloud, it seems to be failing. Can someone please help me with this.

Here is the snippet of the code:

  for (int i = 0; i < 512; ++i) {
      //Serial.print("0x");
      String a;
     a=  String(printHex(fingerTemplate[i], 2));
      //char finger1[i];
      StaticJsonDocument<200> doc;
      doc["finerprnt"] = a;
      //Serial.print(", ");
       char jsonBuffer[512];
        serializeJson(doc, jsonBuffer); // print to client
        post_data(jsonBuffer);
  }

Here is the complete code:

#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>
#include <MKRNB.h>
//#include "VescUart.h"
#include <Adafruit_Fingerprint.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#define OLED_RESET 4
// Debug options
#define PRINT_AT        true   // Show or hide AT command output from the modem
#include <Adafruit_Fingerprint.h>
#include <FlashStorage.h>

//D v28
FlashStorage(sum_one, int);
FlashStorage(addr_one, int);

#if (defined(__AVR__) || defined(ESP8266)) && !defined(__AVR_ATmega2560__)
// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino  (WHITE wire)
// Set up the serial port to use softwareserial..
SoftwareSerial mySerial(2, 3);

#else
// On Leonardo/M0/etc, others with hardware serial, use hardware serial!
// #0 is green wire, #1 is white
#define mySerial Serial1

#endif


Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);

int id = 1;
int var1 = 0;
int cursor = 80;
int getFingerprintIDez();

// PIN Number
const char PINNUMBER[]     = "";
char apn[] = "soracom.io";
char user[] = "sora";
char pass[] = "sora";

// Server details
const char server[] = "unified.soracom.io";
const int  port = 80;


NBClient client;
GPRS gprs;
NB nbAccess(PRINT_AT);
HttpClient http(client, server, port);

// connection state
bool connected = false;

// Publish interval
long previousMillis = 0;
long interval = 10000; // milliseconds // D v2orginial value: long interval = 20000; chnages the time interval in which it will report

//v4-from v33 of the arduino code
Adafruit_SSD1306 display(OLED_RESET);

#if defined(ARDUINO_FEATHER_ESP32) // Feather Huzzah32
#define TFT_CS         14
#define TFT_RST        15
#define TFT_DC         32

#elif defined(ESP8266)
#define TFT_CS         4
#define TFT_RST        16
#define TFT_DC         5

#else
// For the breakout board, you can use any 2 or 3 pins.
// These pins will also work for the 1.8" TFT shield.
#define TFT_CS        1 // D v25 changes to use pin 1 for CS in MKR1500
#define TFT_RST        -1 // Or set to -1 and connect to Arduino RESET pin // D v25 changes to use built in reset pinout in MKR1500
#define TFT_DC         2 // D v25 changes to use pin 2 for CS in MKR1500
#endif

//D v15 for audrino to connect to fingerprint sensor
//D v2
#if (defined(__AVR__) || defined(ESP8266)) && !defined(__AVR_ATmega2560__)
// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino  (WHITE wire)
// Set up the serial port to use softwareserial..
SoftwareSerial mySerial(2, 4);

#else
// On Leonardo/M0/etc, others with hardware serial, use hardware serial!
// #0 is green wire, #1 is white
#define mySerial Serial1

#endif

const int DIN_PIN = 7;
int LedPin=6;

// OPTION 1 (recommended) is to use the HARDWARE SPI pins, which are unique
// to each board and not reassignable. For Arduino Uno: MOSI = pin 11 and
// SCLK = pin 13. This is the fastest mode of operation and is required if
// using the breakout board's microSD card.

// For 1.44" and 1.8" TFT with ST7735 use:
//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); // D v21 uncomment this and comment the line below to use 1.44inch display.Need to change the display font in case I use 1.44"

// For 1.14", 1.3", 1.54", and 2.0" TFT with ST7789:
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST); // D v22 uncommment to use this display

/** Initiate VescUart class */
//VescUart UART;

int rpm;
float voltage;
float current;
float power;
float amphour;
float tach;
float distance;
float velocity;
float watthour;
float batpercentage;
//Variable that will change the value
int lastAdcValue = 0; 
int currentAdcValue = 0; 

void setup() {
  pinMode(SARA_RESETN, OUTPUT);
  digitalWrite(SARA_RESETN, LOW);
  pinMode(SARA_PWR_ON, OUTPUT);

  //Initialize serial and wait for port to open:
  Serial.begin(115200);



  start_and_connect_modem();
    Serial1.begin(115200); // Serial1.begin(19200);
  
  while (!Serial1) {;}

  /** Define which ports to use as UART */
//  UART.setSerialPort(&Serial1);
  pinMode( DIN_PIN, INPUT_PULLUP );
  // tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab

  // OR use this initializer (uncomment) if using a 1.3" or 1.54" 240x240 TFT:
  tft.init(240, 240);           // Init ST7789 240x240  // D v22 uncommment to use this display

  // tft print function!
  tftPrintTest();

  Serial.begin(9600);
  while (!Serial);  // For Yun/Leo/Micro/Zero/...
  delay(100);
  Serial.println("\n\nAdafruit Fingerprint sensor enrollment");

  // set the data rate for the sensor serial port
  finger.begin(57600);

  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1) { delay(1); }
  }

  Serial.println(F("Reading sensor parameters"));
  finger.getParameters();
  Serial.print(F("Status: 0x")); Serial.println(finger.status_reg, HEX);
  Serial.print(F("Sys ID: 0x")); Serial.println(finger.system_id, HEX);
  Serial.print(F("Capacity: ")); Serial.println(finger.capacity);
  Serial.print(F("Security level: ")); Serial.println(finger.security_level);
  Serial.print(F("Device address: ")); Serial.println(finger.device_addr, HEX);
  Serial.print(F("Packet len: ")); Serial.println(finger.packet_len);
  Serial.print(F("Baud rate: ")); Serial.println(finger.baud_rate);


  Serial.println("Ready to enroll a fingerprint!");
  //Serial.println("Please type in the ID # (from 1 to 127) you want to save this finger as...");
  id = sum();
  if (id == 0) {// ID #0 not allowed, try again!
     return;
  }
  Serial.print("Enrolling ID #");
  Serial.println(id);

  while (!  getFingerprintEnroll() );
   //for (int finger = id; finger = id; finger++) {
  int finger=id;
  {downloadFingerprintTemplate(finger);}
}

uint8_t getFingerprintEnroll() {

  int p = -1;
  Serial.print("Waiting for valid finger to enroll as #"); Serial.println(id);
  while (p != FINGERPRINT_OK) {
    p = finger.getImage();
    switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image taken");
      break;
    case FINGERPRINT_NOFINGER:
      Serial.println(".");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      break;
    case FINGERPRINT_IMAGEFAIL:
      Serial.println("Imaging error");
      break;
    default:
      Serial.println("Unknown error");
      break;
    }
  }

  // OK success!

  p = finger.image2Tz(1);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      Serial.println("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      Serial.println("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      Serial.println("Could not find fingerprint features");
      return p;
    default:
      Serial.println("Unknown error");
      return p;
  }

  Serial.println("Remove finger");
  delay(2000);
  p = 0;
  while (p != FINGERPRINT_NOFINGER) {
    p = finger.getImage();
  }
  Serial.print("ID "); Serial.println(id);
  p = -1;
  Serial.println("Place same finger again");
  while (p != FINGERPRINT_OK) {
    p = finger.getImage();
    switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image taken");
      break;
    case FINGERPRINT_NOFINGER:
      Serial.print(".");
      break;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      break;
    case FINGERPRINT_IMAGEFAIL:
      Serial.println("Imaging error");
      break;
    default:
      Serial.println("Unknown error");
      break;
    }
  }

  // OK success!

  p = finger.image2Tz(2);
  switch (p) {
    case FINGERPRINT_OK:
      Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      Serial.println("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      Serial.println("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      Serial.println("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      Serial.println("Could not find fingerprint features");
      return p;
    default:
      Serial.println("Unknown error");
      return p;
  }

  // OK converted!
  Serial.print("Creating model for #");  Serial.println(id);

  p = finger.createModel();
  if (p == FINGERPRINT_OK) {
    Serial.println("Prints matched!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
    return p;
  } else if (p == FINGERPRINT_ENROLLMISMATCH) {
    Serial.println("Fingerprints did not match");
    return p;
  } else {
    Serial.println("Unknown error");
    return p;
  }

  Serial.print("ID "); Serial.println(id);
  p = finger.storeModel(id);
  if (p == FINGERPRINT_OK) {
    Serial.println("Stored!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    Serial.println("Communication error");
    return p;
  } else if (p == FINGERPRINT_BADLOCATION) {
    Serial.println("Could not store in that location");
    return p;
  } else if (p == FINGERPRINT_FLASHERR) {
    Serial.println("Error writing to flash");
    return p;
  } else {
    Serial.println("Unknown error");
    return p;
  }

  return true;
}

uint8_t readnumber(void) {
  uint8_t num = 0;

  while (num == 0) {
    while (! Serial.available());
    num = Serial.parseInt();
  }
  return num;
}
uint8_t downloadFingerprintTemplate(uint16_t id)
{

  // OK success!

  Serial.print("Attempting to get #"); Serial.println(id);
int  p = finger.getModel();
  switch (p) {
    case FINGERPRINT_OK:
      Serial.print("Template "); Serial.print(id); Serial.println(" transferring:");
      break;
   default:
      Serial.print("Unknown error "); Serial.println(p);
      return p;
  }

  // one data packet is 267 bytes. in one data packet, 11 bytes are 'usesless' :D
  uint8_t bytesReceived[534]; // 2 data packets
  memset(bytesReceived, 0xff, 534);

  uint32_t starttime = millis();
  int i = 0;
  while (i < 534 && (millis() - starttime) < 20000) {
      if (mySerial.available()) {
          bytesReceived[i++] = mySerial.read();
      }
  }
  Serial.print(i); Serial.println(" bytes read.");
  Serial.println("Decoding packet...");

  uint8_t fingerTemplate[512]; // the real template
  memset(fingerTemplate, 0xff, 512);

  // filtering only the data packets
  int uindx = 9, index = 0;
  while (index < 534) {
      while (index < uindx) ++index;
      uindx += 256;
      while (index < uindx) {
          fingerTemplate[index++] = bytesReceived[index];
      }
      uindx += 2;
      while (index < uindx) ++index;
      uindx = index + 9;
  }
  for (int i = 0; i < 512; ++i) {
      //Serial.print("0x");
      String a;
     a=  String(printHex(fingerTemplate[i], 2));
      //char finger1[i];
      StaticJsonDocument<200> doc;
      doc["finerprnt"] = a;
      //Serial.print(", ");
       char jsonBuffer[512];
        serializeJson(doc, jsonBuffer); // print to client
        post_data(jsonBuffer);
  }
  Serial.println("\ndone.");
//break;
}

void printHex(int num, int precision) {
    char tmp[16];
    char format[128];

    sprintf(format, "%%.%dX", precision);

    sprintf(tmp, format, num);
    Serial.print(tmp);

  
}

void loop() {
  unsigned long currentMillis = millis();

  delay(50);

  // Make sure the device is still connected to CatM network
  if (nbAccess.isAccessAlive()) {
    // Enforce Interval
    if (currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;

      //D v33
      if (nbAccess.isAccessAlive()) {
        // Construct the JSON data to send
        StaticJsonDocument<200> doc;
        // doc["time"] = millis();
        int currentAdcValue = analogRead(A0);
        
        while(currentAdcValue != lastAdcValue)
  {
     lastAdcValue=currentAdcValue;
    //Serial.print("last adc value: ");
    // doc["Time"] = "July 21, 2021 11:38:00";

    delay(500);
    break;
    }
  delay(500);
      
        char jsonBuffer[512];
        serializeJson(doc, jsonBuffer); // print to client
        post_data(jsonBuffer);
      }
    }
  } else {
    Serial.println("Modem disconnected, reconnecting");
    connected = false;
    connect_modem();
  }
}



void post_data(String postData) {
  //Serial.println("making POST request");
  String contentType = "application/json";

  http.post("/", contentType, postData);

  // read the status code and body of the response
  int statusCode = http.responseStatusCode();
  String response = http.responseBody();
}

void start_and_connect_modem() {
  pinMode(SARA_RESETN, OUTPUT);
  digitalWrite(SARA_RESETN, LOW);
  pinMode(SARA_PWR_ON, OUTPUT);

  // Send Poweron pulse
  digitalWrite(SARA_PWR_ON, HIGH);
  delay(150);
  digitalWrite(SARA_PWR_ON, LOW);
  delay(500);
  // Turn on the modem
  if (Serial) Serial.print(">>> Turning on modem...");
  if (MODEM.begin()) {
    if (Serial) Serial.println(" done!");
  } else {
    if (Serial) Serial.println(" error, could not turn on modem! Try power-cycling.");
    return;
  }

  while (!MODEM.noop());
  MODEM.sendf("ATI9");
  MODEM.waitForResponse(2000);

  // Run AT commands to reset the modem to global default settings
  Serial.print(">>> Resetting modem to default settings...");
  MODEM.sendf("AT+CFUN=0");
  MODEM.waitForResponse(6000);
  MODEM.sendf("AT+UMNOPROF=2");
  MODEM.waitForResponse(2000);
  MODEM.sendf("AT+CFUN=15");
  MODEM.waitForResponse(6000);
  MODEM.sendf("AT+CFUN=0");
  MODEM.waitForResponse(2000);
  MODEM.sendf("AT+UMNOPROF=0");
  MODEM.waitForResponse(2000);
  MODEM.sendf("AT+CFUN=15");
  MODEM.waitForResponse(2000);
  MODEM.sendf("AT+URAT=7");
  MODEM.waitForResponse(2000);
  //D v33
  /*MODEM.sendf("AT+UBANDMASK?");
    MODEM.waitForResponse(6000);*/
  Serial.println(" done!");

  delay(2000);
  // attempt to connect to GSM and GPRS:
  Serial.print("Attempting to connect to GSM and GPRS");
  //Serial.println();
  connect_modem();

}

void connect_modem() {
  // After starting the modem with GSM.begin()
  // attach the shield to the GPRS network with the APN, login and password
  while (!connected) {
    if ((nbAccess.begin(PINNUMBER, apn, user, pass) == NB_READY) &&
        (gprs.attachGPRS() == GPRS_READY)) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
        pinMode(SARA_RESETN, OUTPUT);
  digitalWrite(SARA_RESETN, LOW);
  pinMode(SARA_PWR_ON, OUTPUT);

  start_and_connect_modem();
    }
  }

  Serial.println("You're connected to the network");
}


void tftPrintTest() {
  tft.setTextWrap(true);
  tft.fillScreen(ST77XX_BLACK);
  tft.setCursor(0, 0);
  tft.setTextColor(ST77XX_GREEN);
  tft.setTextSize(2);
}

int sum()
{
  var1 = sum_one.read(); // D v19 read the value from addr 205 and see if it has any ID already stored in it
  var1 = var1 + 1;
  sum_one.write(var1); //D v19 store the ID value in the corresponding addr
  return var1;
}

your variables (a, doc) are local to to the for instruction statement so are "lost" at each iteration. Declare them before the for loop.

shouldn't the serializeJson() and post() be done after the loop is completed rather than at each step?

1 Like

I made the above changes:

  }
  String a;
  StaticJsonDocument<200> doc;
      
  for (int i = 0; i < 512; ++i) {
      //Serial.print("0x");
           a=  String(printHex(fingerTemplate[i],2));
      //char finger1[i];
      doc["finerprnt"] = a;
      //Serial.print(", ");
       /*char jsonBuffer[512];
        serializeJson(doc, jsonBuffer); // print to client
        post_data(jsonBuffer);*/
  }
  
  char jsonBuffer[512];
        serializeJson(doc, jsonBuffer); // print to client
        post_data(jsonBuffer);

After I made the above changes I am getting the following error:

Arduino: 1.8.15 (Windows Store 1.8.49.0) (Windows 10), Board: "Arduino MKR NB 1500"

G:\My Drive\Drive\Drive\Firmware\arduino NB iot\nbiot_5c_07222021\nbiot_5c_07222021.ino: In function 'uint8_t downloadFingerprintTemplate(uint16_t)':

nbiot_5c_07222021:402:52: error: invalid use of void expression

            a=  String(printHex(fingerTemplate[i],2));

                                                    ^

exit status 1

invalid use of void expression

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Is there something that I am missing?

printHex(fingerTemplate[i],2) was printing the value of fingerTemplate at index i on 2 digits, you don't want that...

can we step back 1 sec and explain what you want to see in the jsonBuffer? say your fingerTemplate arrays holds {0x10, 0x20, 0x30, 0x00, 0x50, 0x60}. What should the jsonBuffer look like?

Basically I would want to output with the JSON buffer would be the hex data that the fingerprint sensor outputs.
In the above example I would need the json buffer output be
{"type":"a", "data":[0x10, 0x20, 0x30, 0x00, 0x50, 0x60]}

so why don't you build it directly? something like this for example
(typed here, untested)

const size_t bufferSize = 512; // MAKE SURE IT'S LARGE ENOUGH
char jsonBuffer[bufferSize];

const byte fingerTemplate[] = {0x10, 0x20, 0x30, 0x00, 0x50, 0x60};
const size_t templateSize = sizeof fingerTemplate / sizeof fingerTemplate[0];


void setup() {
  Serial.begin(115200);
  Serial.println();
  
  strlcpy(jsonBuffer, "{\"type\":\"a\", \"data\": [", bufferSize);
  for (size_t i = 0; i < templateSize; i++) {
    char hexByteBuffer[7]; // enough for "0x__, " or "0x__]}"and trailing null
    if (i < templateSize - 1)
      sprintf(hexByteBuffer, "0x%02X, ", fingerTemplate[i]); // the hex value with comma and space
    else
      sprintf(hexByteBuffer, "0x%02X]}", fingerTemplate[i]); //  this is then end the hex value with ]} to close the JSON
    strlcat(jsonBuffer, hexByteBuffer, bufferSize);
  }
  Serial.print(F("JSON BUFFER IS: "));
  Serial.println(jsonBuffer);
}

void loop() {}

if all goes well you should see

JSON BUFFER IS: {"type":"a", "data": [0x10, 0x20, 0x30, 0x00, 0x50, 0x60]}

Note that if you have 512 bytes in the fingerTemplate, each using 6 bytes ("0x__, ") your jsonBuffer will need to be MUCH larger than 512... I let you do the maths

you should check strlcat() returned value to know if you overflowed the buffer (in case you miscalculate the required size)