Reading multiple data from different fields (8 fields) using the ESP32 for IOT control. (ZYBO-Z7)

Calvin Ng on 19 Nov 2021 (Edited on 19 Nov 2021)
Latest activity Edit by Calvin Ng on 19 Nov 2021

Hi, I am currently working on IOT control using ZYBO-Z7 FPGA with the Pmod ESP32, my goal is to read multiple data across 8 fields simultaneously, my current method is reading data from individual fields manually using the code given from this user from a digilent forum (https://forum.digilentinc.com/topic/21634-retrieve-data-from-thingspeak-through-using-pmod-esp32/), this method makes the control slow as I have to individually wait for 8 fields of data one by one. My current solution I am testing out is to read json data using the C++ code below, however the json file is a placed in constant and can only read from that specific array and does not update real time data from thingspeak, how do I get my ZYBO-Z7 to process multiple data from a single feed with 8 fields all from one json URL? Much needed help please and thanks.

/*
 * This workspace attempts to parse (deserialize) a serialize json data
 * from thingspeak (see project_4_1). The code below was extracted (with some editing) from
 * arduinojson.org/v5/assistant after I input the serialize json data
 * from project_4_1: {"channel":{"id":1410948,"name":"testing","latitude":"0.0","longitude":"0.0","field1":"temp","field2":"ph","created_at":"2021-06-08T07:08:42Z","updated_at":"2021-06-09T04:58:00Z","last_entry_id":3},"feeds":[{"created_at":"2021-06-08T08:05:31Z","entry_id":1,"field1":"63"},{"created_at":"2021-06-08T08:07:35Z","entry_id":2,"field1":"76"},{"created_at":"2021-06-08T08:14:50Z","entry_id":3,"field1":"56"}]}
 * The extracted code from arduinojson assistant was tested in
 * https://wandbox.org/permlink/T07A43gUP3EuZjaF
*/
#include <iostream> //if complained of "unresolved inclusion", just build project
#include <ArduinoJson-v5.13.5.h>
#include "xparameters.h"
#include "xil_printf.h"
#include "sleep.h"
#include "stdio.h"
#include "xtime_l.h"
#include "stdlib.h"  //added
#include "string.h"
#include "xgpiops.h"
extern"C"{
#include "PmodESP32.h"
}
#ifdef __MICROBLAZE__
#define HOST_UART_DEVICE_ID XPAR_AXI_UARTLITE_0_BASEADDR
#define HostUart XUartLite
#define HostUart_Config XUartLite_Config
#define HostUart_CfgInitialize XUartLite_CfgInitialize
#define HostUart_LookupConfig XUartLite_LookupConfig
#define HostUart_Recv XUartLite_Recv
#define HostUartConfig_GetBaseAddr(CfgPtr) (CfgPtr->RegBaseAddr)
#include "xuartlite.h"
#include "xil_cache.h"
#else
#define HOST_UART_DEVICE_ID XPAR_PS7_UART_1_DEVICE_ID
#define HostUart XUartPs
#define HostUart_Config XUartPs_Config
#define HostUart_CfgInitialize XUartPs_CfgInitialize
#define HostUart_LookupConfig XUartPs_LookupConfig
#define HostUart_Recv XUartPs_Recv
#define HostUartConfig_GetBaseAddr(CfgPtr) (CfgPtr->BaseAddress)
#include "xuartps.h"
#endif
#define PMODESP32_UART_BASEADDR XPAR_PMODESP32_0_AXI_LITE_UART_BASEADDR
#define PMODESP32_GPIO_BASEADDR XPAR_PMODESP32_0_AXI_LITE_GPIO_BASEADDR
#define BLOCK_SIZE 40
void EnableCaches();
void DisableCaches();
void DemoInitialize();
void DemoRun();
void DemoCleanup();
void receiveData(XTime time);
void setWifiMode(void);
void connectWifi(void);
void establishConnection(void);
void cipsend(void);
PmodESP32 ESP32;
HostUart myHostUart;
XTime TimeStart;
XTime TimeEnd;
int countdown =60;
char *ptr;
XGpioPs_Config *ConfigPtr;
static XGpioPs Gpio;
u8 light;
u8 light1; //ALS
u16 eCO2;
u16 TVOC;
u8 buf[5]; //AQS
u8 recv_buffer;
u32 num_received;
const float ReferenceVoltage = 3.3;
int sec = 0;
int min = 0;
int hour = 0;
int x = 0;
int j = 0;
int status;
int fakecount1 = 0;
int fakecount2 = 0;
int floatmotor = 0;
int floatpumpspoil = 0;
int motorreal = 0;
int DosingDone = 0;
int led1status = 0;
int led234status = 0;
int pumpstatus = 0;
int motorstatus = 0;
int pumpbroken = 0;
int checkingEC = 0;
float ECvalue = 0;
float PHvalue = 0;
void DemoInitialize () {
	HostUart_Config *CfgPtr;
	EnableCaches();
	ESP32_Initialize(&ESP32, PMODESP32_UART_BASEADDR, PMODESP32_GPIO_BASEADDR);
	CfgPtr = HostUart_LookupConfig(HOST_UART_DEVICE_ID);
	HostUart_CfgInitialize(&myHostUart, CfgPtr, HostUartConfig_GetBaseAddr(CfgPtr));
	   ConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
	   XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
	   XGpioPs_SetDirectionPin(&Gpio, 13, 1);
	   XGpioPs_SetOutputEnablePin(&Gpio, 13,1); //pin1 JF1 layer 1 LED #
	   XGpioPs_SetDirectionPin(&Gpio, 10, 1);
	   XGpioPs_SetOutputEnablePin(&Gpio, 10,1); //pin2 JF2 layer 2, 3, 4 LED #
}
void DemoRun() {
	setWifiMode();
	connectWifi();
	establishConnection();
	cipsend();
}
void DemoCleanup() {
	DisableCaches();
}
int main() {
	DemoInitialize();
	DemoRun();
	      free(ptr);
	      const size_t capacity = JSON_OBJECT_SIZE(10) + 140;
	      DynamicJsonBuffer jsonBuffer(capacity);
	      //const char* json = "{\"created_at\":\"2021-11-19T05:33:15Z\",\"entry_id\":134,\"field1\":\"0\",\"field2\":\"1\",\"field3\":\"1\",\"field4\":\"1\",\"field5\":\"2\",\"field6\":\"2\",\"field7\":\"2\",\"field8\":\"10\"}";
	      JsonObject& root = jsonBuffer.parseObject(json);
	      const char* created_at = root["created_at"]; // "2021-11-19T05:33:15Z"
	      int entry_id = root["entry_id"]; // 134
	      const char* field1 = root["field1"]; // "0"
	      const char* field2 = root["field2"]; // "1"
	      const char* field3 = root["field3"]; // "1"
	      const char* field4 = root["field4"]; // "1"
	      const char* field5 = root["field5"]; // "2"
	      const char* field6 = root["field6"]; // "2"
	      const char* field7 = root["field7"]; // "2"
	      const char* field8 = root["field8"]; // "10"
	      if(root["field1"] == "1")
	      {
	    	  xil_printf("1");
	      }
	      else if(root["field1"] == "0")
	      {
	    	  xil_printf("0");
	      }
	      else
	      {
	    	  xil_printf("error reading");
	      }
	      if(root["field2"] == "1")
	      {
	    	  xil_printf("1");
	      }
	      else if(root["field2"] == "0")
	      {
	    	  xil_printf("0");
	      }
	      else
	      {
	    	  xil_printf("error reading");
	      }
	      if(root["field3"] == "1")
	      {
	    	  xil_printf("1");
	      }
	      else if(root["field3"] == "0")
	      {
	    	  xil_printf("0");
	      }
	      else
	      {
	    	  xil_printf("error reading");
	      }
	      if(root["field4"] == "1")
	      {
	    	  xil_printf("1");
	      }
	      else if(root["field4"] == "0")
	      {
	    	  xil_printf("0");
	      }
	      else
	      {
	    	  xil_printf("error reading");
	      }
	      if(root["field5"] == "1")
	      {
	    	  xil_printf("1");
	      }
	      else if(root["field5"] == "0")
	      {
	    	  xil_printf("0");
	      }
	      else
	      {
	    	  xil_printf("error reading");
	      }
	DemoCleanup();
	return 0;
}
void setWifiMode(void){
    u8 tx[]="AT+CWMODE=3\r\n";
    u32 num = strlen((char *) tx);
    xil_printf((char *) tx);
    ESP32_SendBuffer(&ESP32, tx, num);
    usleep(100000);
    receiveData(1);
}
void connectWifi(void){
    u8 tx[] = "AT+CWJAP=\"eee-iot\",\"gr3enChess30\"\r\n";
    u32 num = strlen((char *) tx);
    xil_printf((char *) tx);
    ESP32_SendBuffer(&ESP32, tx, num);
    usleep(100000);
    receiveData(9);
}
void receiveData(XTime time){
    XTime tEnd, tCur;
    u8 recv_buffer=0;
    u32 num_received=0;
      XTime_GetTime(&tCur);
      tEnd  = tCur + (time * COUNTS_PER_SECOND);
      do
      {
          num_received = ESP32_Recv(&ESP32, &recv_buffer,1);
                  if(num_received >0){
                      num_received = ESP32_Recv(&ESP32, &recv_buffer,1);
                      xil_printf("%c", recv_buffer);
                  }
          if(tCur == tCur + COUNTS_PER_SECOND){
              countdown = countdown -1;
          }
          else
              XTime_GetTime(&tCur);
      } while (tCur < tEnd);
}
void receiveData2(XTime time){
    XTime tEnd, tCur;
    u8 recv_buffer=0;
    u32 num_received=0;
      int i=0;
      int max_index = BLOCK_SIZE-1;
      ptr = (char*) malloc(sizeof(int)*BLOCK_SIZE);  //compare with project_4_3 or _4_1 where (int*) is not required because it is a C file in those projects
      if(ptr==NULL)
      {
          perror("some error");
          //return 1;
      }
      XTime_GetTime(&tCur);
      tEnd  = tCur + (time * COUNTS_PER_SECOND);
      do
      {
          num_received = ESP32_Recv(&ESP32, &recv_buffer,1);
                  if(num_received >0){
                      num_received = ESP32_Recv(&ESP32, &recv_buffer,1);
                          if(i > max_index)
                          {
                              ptr=(char*) realloc(ptr, (max_index+1 + BLOCK_SIZE)*sizeof(int));  //compare with project_4_3 or _4_1 where (int*) in realloc is not required because it is a C file in those projects
                              if(ptr == NULL)
                              {
                                  perror("insufficient memory!");
                                  break;
                              }
                              //printf("\nReallocated!");
                              max_index += BLOCK_SIZE;
                          }
                          ptr[i]=recv_buffer;
                          i++;
                      //}
                  }
          if(tCur == tCur + COUNTS_PER_SECOND){
             countdown = countdown -1;
          }
          else
              XTime_GetTime(&tCur);
      } while (tCur < tEnd);
}
void establishConnection(void){
    u8 tx[] = "AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80\r\n";
    u32 num = strlen((char *) tx);
    ESP32_SendBuffer(&ESP32, tx, num);
    receiveData(1);
}
void cipsend(void){
    u8 command[150];
    u8 finalcmd[50];
      sprintf((char*)command, "GET https://api.thingspeak.com/channels/1572052/feeds/last.json/?api_key=xxxxxxxxxxxxxxxx\r\n");
      u32 length = strlen((char*)command);
      sprintf((char*)finalcmd, "AT+CIPSEND=%d\r\n", (int)length);
      u32 cmdlength =strlen((char*)finalcmd);
      xil_printf("Length %d\r\n", length);
      xil_printf((char *)finalcmd);
      ESP32_SendBuffer(&ESP32, finalcmd, cmdlength);
      usleep(100000);
      xil_printf((char *)command);
      ESP32_SendBuffer(&ESP32, command, length);
      receiveData2(1);
}
void EnableCaches() {
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_ICACHE
   Xil_ICacheEnable();
#endif
#ifdef XPAR_MICROBLAZE_USE_DCACHE
   Xil_DCacheEnable();
#endif
#endif
}
void DisableCaches() {
#ifdef __MICROBLAZE__
#ifdef XPAR_MICROBLAZE_USE_ICACHE
   Xil_ICacheDisable();
#endif
#ifdef XPAR_MICROBLAZE_USE_DCACHE
   Xil_DCacheDisable();
#endif
#endif
}
Christopher Stapels
Christopher Stapels on 19 Nov 2021 (Edited on 19 Nov 2021)

There is a lot going on in this code. Can you could simplify the question, perhaps just show the areas you are using for reading fields and explain the issues are more specifically?

You asked "how do I get my ZYBO-Z7 to process multiple data from a single feed with 8 fields all from one json URL?" Is the problem that you don't know the right URL to call at ThingSpeak or that you don't know how to parse the response and get the individual field values?

Also, can you please add a response to the thingSpeak team post about reading data a few down form this one? We need more feedback from users there.

Calvin Ng
Calvin Ng on 19 Nov 2021 (Edited on 19 Nov 2021)

Hi, sorry for the confusion.

Previously I am able to receive data from a single field using the code below.

   void receiveDataLED1(XTime time){
          XTime tEnd, tCur;
          u8 recv_buffer=0;
          u32 num_received=0;
          int i=0;
          int max_index = BLOCK_SIZE-1;
          /*
              * Malloc Function:
              * Allocates a block of size bytes of memory, returning a pointer to the beginning of the block.*/
          int *ptr= (int *) malloc(sizeof(int)*BLOCK_SIZE);
          if(ptr==NULL)
          {
              perror("some error");//Print error message
              //return 1;
          }
          XTime_GetTime(&tCur);
          tEnd  = tCur + (time * COUNTS_PER_SECOND);
          do
          {
              num_received = ESP32_Recv(&ESP32, &recv_buffer,1);
                      if(num_received >0){
                          num_received = ESP32_Recv(&ESP32, &recv_buffer,1);
                              if(i > max_index)
                              {
                                  ptr=(int *)realloc(ptr, (max_index+1 + BLOCK_SIZE)*sizeof(int));
                                  if(ptr == NULL)
                                  {
                                      perror("insufficient memory!");
                                      break;
                                  }
                                  max_index += BLOCK_SIZE;
                              }
                              ptr[i]=recv_buffer;
                              i++;
                      }
              if(tCur == tCur + COUNTS_PER_SECOND){
                 countdown = countdown -1;
              }
              else
                  XTime_GetTime(&tCur);
          } while (tCur < tEnd);
          xil_printf("Data %d: %c\n\r",i ,ptr[45]);
          if (ptr[45]=='1'){
          	xil_printf("LED1 ON\n\r");
          	XGpioPs_WritePin(&Gpio, 13, 0);
          }else if (ptr[45]=='0')
          {
          	xil_printf("LED1 OFF\n\r");
          	XGpioPs_WritePin(&Gpio, 13, 1);
          } else {
          	xil_printf("ERROR\n\r");
          }
          free(ptr); // Clear the memory to prevent "ptr==null"
      }
   void cipsendLED1(void){
      	u8 command[150];
      	u8 finalcmd[50];
      	sprintf((char*)command, "GET https://api.thingspeak.com/channels/1572052/fields/2/last?key=R8END225F31MA3L8\r\n");
       u32 length = strlen((char*)command);
       sprintf((char*)finalcmd, "AT+CIPSEND=%d\r\n", (int)length);
      	u32 cmdlength =strlen((char*)finalcmd);
      	ESP32_SendBuffer(&ESP32, finalcmd, cmdlength);
      	usleep(100000);
      	ESP32_SendBuffer(&ESP32, command, length);
      	receiveDataLED1(1);
      }

Basically to simplify the question, I am trying to receive data from 8 fields at once, so the current method I am using is parsing the data from this URL link (GET https://api.thingspeak.com/channels/1572052/feeds/last.json/?api_key=xxxxxxxxxxxxxxxx) with this online tool (arduinojson.org/v5/assistant) and using the code generated (attached below) from the online tool with the GET link, I am able to read the parsed data and print out the data correctly. However, this method is not flexible as the code generated basically creates a array with the set parameters from that GET link. This would also mean that this code cannot run live data as I have to manually use the assistant every time the data from Thingspeak updates.

const size_t capacity = JSON_OBJECT_SIZE(10) + 140; DynamicJsonBuffer jsonBuffer(capacity);

const char* json = "{\"created_at\":\"2021-11-19T05:33:15Z\",\"entry_id\":134,\"field1\":\"0\",\"field2\":\"1\",\"field3\":\"1\",\"field4\":\"1\",\"field5\":\"2\",\"field6\":\"2\",\"field7\":\"2\",\"field8\":\"10\"}";

JsonObject& root = jsonBuffer.parseObject(json);

const char* created_at = root["created_at"]; // "2021-11-19T05:33:15Z" int entry_id = root["entry_id"]; // 134 const char* field1 = root["field1"]; // "0" const char* field2 = root["field2"]; // "1" const char* field3 = root["field3"]; // "1" const char* field4 = root["field4"]; // "1" const char* field5 = root["field5"]; // "2" const char* field6 = root["field6"]; // "2" const char* field7 = root["field7"]; // "2" const char* field8 = root["field8"]; // "10"

if(root["field1"] == "1") { xil_printf("1"); } else if(root["field1"] == "0") { xil_printf("0"); } else { xil_printf("error reading"); }

Hopefully this is clear enough, I can explain more if I am not clear in certain areas. Thanks.