A GNSS Tracker based on ESP32-C3 + A7672S 4G Module
You should find majority of the details needed for using the hardware here
⚡ Introduction
VALTRACK-V4-VTS-ESP32-C3 as the name itself depicts, is a fully configurable low power Vehicle Tracking System device. It was designed to be versatile and flexible enough to fit into any vehicle tracking scenario, be it for tracking 🚲 Bikes, 🚗 Cars or 🚚 Trucks.
- Features
- Specifications
- Getting Started
- Programming Details
- Schematics
- Firmware
- Purchase link
Features
Here you will get a brief idea on what the device is capable of and the important features
Power section :
The device has two power inputs,
VALTRACK-V4-VTS Power section |
1) Main Power input - VCHG :
This is the main power input of the device and is usually connected to the vehicles battery. Right now the device supports from 12VDC to 42VDC input range. When you power the device from VCHG it also charges the battery connected to VBAT input. The main power chip used here is the TPS54240 switching regulator.
2) Backup battery power input - VBAT
This is the back up battery input and a 3.7V to 4.2V LiPo battery has to be connected to it. Use at least 400mAH battery. The main power chip used here is the MP2617 switching battery charger with power path management.
To understand the power section of the device, look at the block diagram.
Specifications
Model No. | VALTRACK-V4-VTS [ESP32-C3] |
Operating Voltage |
|
Backup Battery Input : 3.7V to 4.2V DC [Connect a single cell 3.7V-4.2V Li-Po or Li-Ion Battery] ⚠Doesn't have Reverse Polarity Protection | |
Dimensions | With Enclosure - Length: 52mm * Width: 65mm * Height: 30 mm |
PCB Dimensions - Length: 34mm * Width: 43mm * Thickness: 1.6 mm | |
Battery Support |
|
Cellular module | A7672S - 4G-LTE-CAT1 / 2G - For India & Asia |
A7672E - 4G-LTE-CAT1 /2G - For Europe | |
Australia | |
Navigation hardware | Inbuilt GNSS of A7672x |
A7672x has inbuilt GNSS hardware which needs passive or external active antenna [Bias is already provided to the GNSS U.FL connector] | |
Aux Inputs | None |
Aux Outputs | None |
Operating Modes | HTTP, SMS, MQTT/TCP |
Configuration Methods | USB / Bluetooth (Yet to be implemented) |
Processor | Espressif ESP32-C3FH4 RISC-V chipset |
Motion Sensor | LIS3DH 12-bit, 3-axis Accelerometer |
Memory | 4MB inbuilt flash of ESP32-C3FH4 |
Antenna |
📶 Cellular : U.FL Connector
|
A7672x GNSS : U.FL Connector
|
|
Connectivity | Bluetooth, GPRS, SMS, Call |
SIM connector | Nano SIM card connector available |
Flashing options | Micro USB |
Enclosure | Device ships in a standard IP67 rated enclosure if ordered. |
Purchase info
Board purchase information
Product variants
- Without Enclosure
- With Enclosure
GNSS Antenna Selection
- Internal Patch antenna
- External antenna
We offer the device with above options, You can order the device only if you want to use it in some other instrument along with other hardware or you can order the device with a IP67 enclosure.
We also offer the device with internal GNSS patch antenna or external antenna. If you choose external antenna, we provide a SMA connector on the enclosure(if ordered) and add a bias resistor to power the external active antenna. Then you can connect a external antenna to the board via the U.FL connector. External GNSS antenna option is helpful when you want to install devices in places where there is no direct satellite view. In such cases you can use the external GNSS active antenna shown in below image.
VALTRACK-V4-VTS-ESP32-C3 enclosures with and without external antenna option |
From Left, (External GNSS antenna device, External GNSS antenna device, Internal GNSS Patch antenna device) |
Getting Started
Opening the enclosure
You need to remove the four screws present in the bottom of the enclosure to open it. Use a star head screw driver.
Inserting the SIM card
Get a Nano-SIM card and insert it into the boards push-pull type SIM card slot.
Power should not be connected to the device during SIM card insertion
Powering the device
VALTRACK-V4-VTS-ESP32-C3 can run from any of the two power sources,
Main Power Input [VCHG connector] |
|
Has Reverse Polarity Protection | |
Backup Battery Input [VBAT connector] |
Doesn't have Reverse Polarity Protection |
Device can start functioning with any of above power sources.
LED Indicators
- Once the device is powered ON, The LED will show up and start with all RED .
- Once the SIM is registered to the network, the NETWORK LED turns GREEN .
- Once the GNSS module gets a location sync, the LOCATION LED turns GREEN .
- After 30 seconds of inactivity, all LED will turn OFF to save power and turn ON again on movement detected by Accelerometer.
- POWER LED remains RED all the time
Configuration
Configuration is not yet implented in firmware, but can be done using USB and Bluetooth or WiFi
Programming
Here you will find the details needed for develop your own firmware for the device
If you are interested in writing firmware for the VALTRACK-V4-VTS device, you will need to know where is each pin of MCU is connected to.
Since the schematics of the device is not yet openly available, We are providing the MCU pin connection details, which should be able to help you in determining how is the whole architecture laid out. Watching our device intro video would also help to get an overall idea on the hardware present on board.
MCU Pinout Details
Pin Number | Pin Name | Net Name | Connected to |
---|---|---|---|
2, 3, 11, 17, 18, 31, 32 | VDD3P3, VDD3P3_RTC, VDD3P3_CPU, VDD_SPI, VDDA | 3V3DC | 3.3VDC output of LDO |
19, 20, 21, 22, 23, 24 | SPIHD, SPIWP, SPICS0, SPICLK, SPID, SPIQ | CLK_IN | 32.768 KHz crystal |
1 | LNA_IN | RF_ANTENNA | Bluetooth / WiFi Chip antenna via matching network |
4 | GPIO0 | LPUART1_TX | Cellular module RXD input pin through level translator. |
5 | GPIO1 | LPUART1_RX | Cellular module TXD output pin through level translator. |
6 | GPIO2 | ANALOG_IN | VCHG input through voltage divider resistor network.
|
7 | CHIP_PU | CHIP_PU | CHIP_PU line |
9 | GPIO4 | TPS_ENABLE | Enable input of switching regulator TPS54240
Do no activate this pin without connecting a 3,7V battery to avoid Race around condition |
10 | GPIO5 | IIC_DATA | I2C data of LIS3DH Accelerometer |
12 | GPIO6 | IIC_CLK | I2C clock of LIS3DH Accelerometer |
13 | GPIO7 | SIM_PWRKEY_3V3 | Cellular module PWRKEY pin through N channel MOSFET.
|
14 | GPIO8 | LED_SIGNAL | WS2812B battery LED input |
15 | GPIO9 | GPIO9 | Tactile switch input
|
16 | GPIO10 | GSM_ENABLE | Enable input of power gating MOSFET for Cellular module
|
14 | GPIO8 | LED_SIGNAL | WS2812B battery LED input |
25 | GPIO18 | USB_DN | USB DP line |
27 | GPIO20 | U0RXD | Drawn to test points |
28 | GPIO21 | U0TXD | Drawn to test points |
29 | XTAL_N | OSC_OUT | 40 MHz crystal |
30 | XTAL_P | OSC_IN | 40 MHz crystal |
26 | GPIO19 | USB_DP | USB DN line |
33 | GND | GND | POWER PAD GND |
J62 - VCHG Connector [SMT pads] - Pinout Details
Pin Number | Pin Name | Connected to |
---|---|---|
1 | VCHG | VCHG input of system through FUSE and diode
|
2 | GND | System Ground |
J41 - VBAT Connector [SMT pads] - Pinout Details
Pin Number | Pin Name | Connected to |
---|---|---|
1 | VBAT | VBAT input of system or Backup battery input
|
2 | GND | System Ground |
Schematics
Firmware
https://github.com/ValetronSystems/VALTRACK-V4-ESP32-C3.git
Link to ESP-IDF based firmware
GitHub - ValetronSystems/VALTRACK-V4-ESP32-C3: Source code for VALTRACK-V4-VTS-ESP32-C3 & VALTRACK-V4-MFW-ESP32C3 designs
Arduino example sketch with hardware initializations to get started
// #include "main.h"
// UART1 TX-----0
// UART1 RX-----1
// ANALOG IN----2
// INT1---------3
// TPS-ENABLE---4
// IIC-DATA-----5
// IIC-CLOCK----6
// PWRKEY-------7
// LED-SIGNAL---8
// SWITCH-SW2---9
// GSM-ENABLE---10
// USB DN-------18
// USB_DP-------19
// UART0 RX-----20
// UART0 TX-----21
#define TINY_GSM_MODEM_SIM7600
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
// Set serial for AT commands (to the module)
// Use Hardware Serial on Mega, Leonardo, Micro
#define SerialAT Serial1
// Increase RX buffer to capture the entire response
// Chips without internal buffering (A6/A7, ESP8266, M590)
// need enough space in the buffer for the entire response
// else data will be lost (and the http library will fail).
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 1024
#endif
// See all AT commands, if wanted
// #define DUMP_AT_COMMANDS
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
// #define LOGGING // <- Logging is for the HTTP library
// Range to attempt to autobaud
// NOTE: DO NOT AUTOBAUD in production code. Once you've established
// communication, set a fixed baud rate using modem.setBaud(#).
#define GSM_AUTOBAUD_MIN 9600
#define GSM_AUTOBAUD_MAX 115200
// Add a reception delay, if needed.
// This may be needed for a fast processor at a slow baud rate.
// #define TINY_GSM_YIELD() { delay(2); }
// Define how you're planning to connect to the internet
// These defines are only for this example; they are not needed in other code.
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false
// set GSM PIN, if any
#define GSM_PIN ""
// Your GPRS credentials, if any
const char apn[] = "www";
const char gprsUser[] = "";
const char gprsPass[] = "";
// Your WiFi connection credentials, if applicable
const char wifiSSID[] = "SSID";
const char wifiPass[] = "password";
// Server details
const char server[] = "xyz.in";
const char resource[] = "";
const int port = 80;
#include <TinyGsmClient.h>
#include <ArduinoHttpClient.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
// Just in case someone defined the wrong thing..
#if TINY_GSM_USE_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS
#undef TINY_GSM_USE_GPRS
#undef TINY_GSM_USE_WIFI
#define TINY_GSM_USE_GPRS false
#define TINY_GSM_USE_WIFI true
#endif
#if TINY_GSM_USE_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI
#undef TINY_GSM_USE_GPRS
#undef TINY_GSM_USE_WIFI
#define TINY_GSM_USE_GPRS true
#define TINY_GSM_USE_WIFI false
#endif
#ifdef DUMP_AT_COMMANDS
#include <StreamDebugger.h>
StreamDebugger debugger(SerialAT, SerialMon);
TinyGsm modem(debugger);
#else
TinyGsm modem(SerialAT);
#endif
TinyGsmClient client(modem);
HttpClient http(client, server, port);
/////////////////////////////////////////////////////////////////////////////////////////////
// PWRKEY 7
// GSM ENABLE 10
// LED SIGNAL 8
// TPS ENABLE 4 //OR CHG IN
// INT1 3
// ANALOG IN 2
// IIC DATA 5
// IIC CLOCK 6
#define GPIO_IIC_DATA 5
#define GPIO_IIC_CLOCK 6
#define GPIO_PWRKEY 7
#define GPIO_GSM_ENABLE 10
#define GPIO_TPS_ENABLE 4
#define GPIO_INT1 3
#define GPIO_SOS 9
#define GPIO_CHG_IN 4
#define GPIO_LED_SIGNAL 8
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(3, GPIO_LED_SIGNAL, NEO_GRB + NEO_KHZ800);
#define BATTERY_LED 0
#define NETWORK_LED 1
#define LOCATION_LED 2
#define RED 0
#define GREEN 1
#define BLUE 2
#define BRIGHTNESS 64
void UpdateLED(int LED, int Color, int Brightness )
{
switch(Color)
{
case RED :
pixels.setPixelColor(LED, pixels.Color(Brightness, 0, 0));
break;
case GREEN :
pixels.setPixelColor(LED, pixels.Color(0, Brightness, 0));
break;
case BLUE :
pixels.setPixelColor(LED, pixels.Color(0, 0, Brightness));
break;
default:
pixels.setPixelColor(LED, pixels.Color(0, 0, 0));
break;
}
pixels.show(); // This sends the updated pixel color to the hardware.
}
void EnableGSM(void)
{
digitalWrite(GPIO_GSM_ENABLE, 1);// 10 GSM_ENABLE &LED_ENABLE
}
void DisableGSM(void)
{
digitalWrite(GPIO_GSM_ENABLE, 0);// 10 GSM_DISABLE & LED_DISABLE
}
void InitGPIO(void)
{
pinMode(GPIO_PWRKEY, OUTPUT);
pinMode(GPIO_GSM_ENABLE, OUTPUT);
}
void InitLED(void)
{
// pixels.begin(); // This initializes the NeoPixel library.
UpdateLED(BATTERY_LED,RED, BRIGHTNESS);
UpdateLED(NETWORK_LED,GREEN, BRIGHTNESS);
UpdateLED(LOCATION_LED,BLUE, BRIGHTNESS);
}
void InitGSM(void)
{
// !!!!!!!!!!!
digitalWrite(GPIO_PWRKEY, 0);
digitalWrite(GPIO_PWRKEY, 1);
delay(1000);
digitalWrite(GPIO_PWRKEY, 0);
// Set your reset, enable, power pins here
// !!!!!!!!!!!
}
void InitUART0(void)
{
Serial.begin(115200);
}
void InitUART1(void)
{
Serial1.begin(115200,SERIAL_8N1,1,0);
}
#define REG_CTRL_REG1 0x20
#define REG_CTRL_REG2 0x21
#define REG_CTRL_REG3 0x22
#define REG_CTRL_REG4 0x23
#define REG_CTRL_REG5 0x24
#define REG_CTRL_REG6 0x25
#define REG_INT1_CFG 0x30
#define REG_INT1_SRC 0x31
#define REG_INT1_THS 0x32
#define REG_INT1_DURATION 0x33
#define ACCLEROMETER_I2C_ADDRESS 0x19 //LIS3D
uint8_t I2C_RdReg(uint8_t RegisterAddress)
{
Wire.beginTransmission(ACCLEROMETER_I2C_ADDRESS);
Wire.write(RegisterAddress);
Wire.endTransmission();
Wire.requestFrom(ACCLEROMETER_I2C_ADDRESS, 1);
delay(2);
return (uint8_t)Wire.read();
}
void I2C_WrReg(uint8_t RegisterAddress, uint8_t Data)
{
Wire.beginTransmission(ACCLEROMETER_I2C_ADDRESS);
Wire.write(RegisterAddress);
Wire.write(Data);
Wire.endTransmission();
}
void InitAccelerometer(void)
{
uint8_t VALREAD=0;
Wire.begin(GPIO_IIC_DATA,GPIO_IIC_CLOCK);
VALREAD = I2C_RdReg(0x26);
VALREAD = I2C_RdReg(0x0F);//VALREAD = I2C_RdReg(0x0D);
Serial.print("Motion Sensor = ");
if(VALREAD == 0x33)
{
Serial.println("LIS3DH Found");
}
else
{
Serial.println("LIS3DH Not Found");
}
I2C_WrReg(REG_CTRL_REG1, 0x57);
I2C_WrReg(REG_CTRL_REG4, 0x08);
delay(200);
// VALREAD = I2C_RdReg(REG_CTRL_REG1);
I2C_WrReg(REG_CTRL_REG2, 0x05);
I2C_WrReg(REG_CTRL_REG3, 0x40);// I2C_WrReg(MMA8652_CTRL_REG3, 0x39);
I2C_WrReg(REG_CTRL_REG5, 0x08);
// VALREAD = I2C_RdReg(REG_CTRL_REG5);
I2C_WrReg(REG_CTRL_REG6, 0x02);
//I2C_WrReg(REG_CTRL_REG6, 0xFF);
I2C_WrReg(REG_INT1_THS,0x18);
I2C_WrReg(REG_INT1_DURATION,0x00);
I2C_WrReg(REG_INT1_CFG,0x2A);
for(uint8_t i=0x07;i<=0x3F;i++)
{
VALREAD = I2C_RdReg(i);
}
}
void setup() {
delay(5000);
InitGPIO();
InitUART0();
InitUART1();
EnableGSM();
InitLED();
InitAccelerometer();
InitGSM();
Serial.println("Wait...");
Serial.println("Wait...1");
// Set GSM module baud rate
//TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
//SerialAT.begin(115200,SERIAL_8N1,1,0);
delay(6000);
Serial.println("Hello\r\n");
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println("Initializing modem...");
modem.restart();
// modem.init();
String modemInfo = modem.getModemInfo();
SerialMon.print("Modem Info: ");
SerialMon.println(modemInfo);
#if TINY_GSM_USE_GPRS
// Unlock your SIM card with a PIN if needed
if (GSM_PIN && modem.getSimStatus() != 3) { modem.simUnlock(GSM_PIN); }
#endif
modemInfo = modem.getSignalQuality();
SerialMon.print("Signal Quality: ");
SerialMon.println(modemInfo);
//xTaskCreate(ADCTask, "ADCTask", 2048, NULL, 10, NULL);
// xTaskCreate(StartTimerTask, "StartTimerTask", 4096, NULL, 10, NULL);
// xTaskCreate(StartMainTask, "StartMainTask", 8192, NULL, 10, NULL); //TIMER_TASK_STACK_SIZE
//thisModem().sendAT(GF("+IPR="), baud);
modem.sendAT(GF("+IPR?"));
modem.waitResponse(10000,"+IPR");
}
void loop() {
#if TINY_GSM_USE_WIFI
// Wifi connection parameters must be set before waiting for the network
SerialMon.print(F("Setting SSID/password..."));
if (!modem.networkConnect(wifiSSID, wifiPass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
#endif
#if TINY_GSM_USE_GPRS && defined TINY_GSM_MODEM_XBEE
// The XBee must run the gprsConnect function BEFORE waiting for network!
modem.gprsConnect(apn, gprsUser, gprsPass);
#endif
SerialMon.print("Waiting for network...");
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
if (modem.isNetworkConnected()) { SerialMon.println("Network connected"); }
#if TINY_GSM_USE_GPRS
// GPRS connection parameters are usually set after network registration
SerialMon.print(F("Connecting to "));
SerialMon.print(apn);
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
if (modem.isGprsConnected()) { SerialMon.println("GPRS connected"); }
#endif
SerialMon.print(F("Performing HTTP GET request... "));
int err = http.get(resource);
if (err != 0) {
SerialMon.println(F("failed to connect"));
delay(10000);
return;
}
int status = http.responseStatusCode();
SerialMon.print(F("Response status code: "));
SerialMon.println(status);
if (!status) {
delay(10000);
return;
}
SerialMon.println(F("Response Headers:"));
while (http.headerAvailable()) {
String headerName = http.readHeaderName();
String headerValue = http.readHeaderValue();
SerialMon.println(" " + headerName + " : " + headerValue);
}
int length = http.contentLength();
if (length >= 0) {
SerialMon.print(F("Content length is: "));
SerialMon.println(length);
}
if (http.isResponseChunked()) {
SerialMon.println(F("The response is chunked"));
}
String body = http.responseBody();
SerialMon.println(F("Response:"));
SerialMon.println(body);
SerialMon.print(F("Body length is: "));
SerialMon.println(body.length());
// Shutdown
http.stop();
SerialMon.println(F("Server disconnected"));
#if TINY_GSM_USE_WIFI
modem.networkDisconnect();
SerialMon.println(F("WiFi disconnected"));
#endif
#if TINY_GSM_USE_GPRS
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
#endif
// Do nothing forevermore
while (true) { delay(1000); }
}
Google Sheets - Script
App script info to append VALTRACK-V4 HTTP post data to Google sheets
In firmware a define in has to be enabled, which makes the HTTP function wait for 302 Moved Temporarily response. Google App script gives 302 response instead of 200 so enable this #define. When you want to use custom response string, you can comment this line.
#define SHEETS_ENABLED
Sample packet to test
{"resource":[{"devid":"123095050300182","time":"2023-03-29 12:30:44","etype":"REBOOT","lat":"15.200000","lon":"75.32000","vbat":"0.000000","speed":"0.000000"}]}
Script to be pasted in Google sheets extension
function doPost(req) {
var logid=0;
var devid=0;
var lat=0;
var lon=0;
var time=0;
var server_time=0;
var etype=0;
var speed=0;
var vbat=0;
var vmbat=0;
var pInt=0;
var nlat=0;
var nlon=0;
var ncsq=0;
var ltype=0;
var coach_num=0;
var fuel=0;
var origin=0;
var engine=0;
var output;
var data = JSON.parse(req.postData.contents);
var sheet = SpreadsheetApp.getActiveSheet();
let datenow = new Date();
var packet = data.resource;
for(var i=0;i<packet.length;i++)
{
try{
sheet.appendRow([
packet[i].logid,
packet[i].devid,
packet[i].lat,
packet[i].lon,
packet[i].time,
datenow,
packet[i].etype,
packet[i].speed,
packet[i].vbat,
packet[i].vmbat,
packet[i].pInt,
'http://maps.google.com/maps?z=18amp;&q='+packet[i].lat+','+packet[i].lon,
packet[i].nlat,
packet[i].nlon,
packet[i].ncsq,
packet[i].ltype,
packet[i].coach_num,
packet[i].fuel,
packet[i].origin,
packet[i].engine,
'VALTRACK-V4-VTS-ESP32-C3'
]);
}
catch(error)
{
output = error;
}
}
return ContentService.createTextOutput(JSON.stringify({data:output})).setMimeType(ContentService.MimeType.JSON);
}