I recently started building a GPS tracker. My code is based off of some of the example code here.
I have stripped back the code and am just testing the sending of a Telegram message on a spare NodeMCU I had on hand. So far I have;
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <UniversalTelegramBot.h>
#include <WiFiClientSecure.h>
//------- WiFi Settings -------
#define WIFI_SSID "my_ssid"
#define WIFI_PASSWORD "my_pass"
// ------- Telegram Config --------
#define BOT_TOKEN "_token_"
#define CHAT_ID "_id_"
X509List cert(TELEGRAM_CERTIFICATE_ROOT);
WiFiClientSecure secured_client;
UniversalTelegramBot bot(BOT_TOKEN, secured_client);
// ------- Pin Definitions --------
#define IgnitionPin D5
#define EnginePin D6
#define DoorsPin D7
// ------- Variables for Interrupts --------
volatile bool engineOnFlag = false;
volatile bool engineOffFlag = false;
volatile bool ignitionOnFlag = false;
volatile bool ignitionOffFlag = false;
volatile bool lockedFlag = false;
volatile bool unlockedFlag = false;
// ------- Status Functions --------
void IRAM_ATTR ignition() {
if (digitalRead(IgnitionPin) == HIGH) {
ignitionOnFlag = true;
}
else if (digitalRead(IgnitionPin) == LOW) {
ignitionOffFlag = true;
}
return;
}
void IRAM_ATTR engine() {
if (digitalRead(EnginePin) == HIGH) {
engineOnFlag = true;
}
else if (digitalRead(EnginePin) == LOW) {
engineOffFlag = true;
}
return;
}
void IRAM_ATTR locks() {
if (digitalRead(DoorsPin) == HIGH) {
lockedFlag = true;
}
else if (digitalRead(DoorsPin) == LOW) {
unlockedFlag = true;
}
return;
}
// ------- Message Functions --------
void sendIgnitionOnMessage() {
ignitionOnFlag = false;
String message = "Ignition on";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
}
return;
}
void sendIgnitionOffMessage() {
ignitionOffFlag = false;
String message = "Ignition off";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
}
return;
}
void sendEngineOnMessage() {
engineOnFlag = false;
String message = "Engine on";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
}
return;
}
void sendEngineOffMessage() {
engineOffFlag = false;
String message = "Engine off";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
}
return;
}
void sendLockedMessage() {
lockedFlag = false;
String message = "Locked";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
}
return;
}
void sendUnlockedMessage() {
unlockedFlag = false;
String message = "Unlocked";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
}
return;
}
void setup() {
// ------- Init Serial Port --------
Serial.begin(115200);
Serial.println();
// ------- Pin Setup --------
pinMode(IgnitionPin, INPUT_PULLUP);
pinMode(EnginePin, INPUT_PULLUP);
pinMode(DoorsPin, INPUT_PULLUP);
// ------- Interrupt Setup --------
// NOTE: It is important to use interrupts when making network calls in the sketch
// if you just checked the status of the button in the loop you might miss the button press.
//attachInterrupt(Doors, Doors(open), RISING); //this would be great but it isn't how interrupts work!
//attachInterrupt(digitalPinToInterrupt(GPIO), ISR, mode); //mode can be rising, falling, change
attachInterrupt(IgnitionPin, ignition, CHANGE);
attachInterrupt(EnginePin, engine, CHANGE);
attachInterrupt(DoorsPin, locks, CHANGE);
// ------- Connect to WiFi network --------
Serial.print("Connecting to WiFi SSID ");
Serial.print(WIFI_SSID" ");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
secured_client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}
Serial.print("\nWiFi connected. IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Retrieving time: ");
configTime(0, 0, "pool.ntp.org"); // get UTC time via NTP
time_t now = time(nullptr);
while (now < 24 * 3600)
{
Serial.print(".");
delay(100);
now = time(nullptr);
}
Serial.println(now);
bot.sendMessage(CHAT_ID, "Tracker started up.", "");
}
void loop() {
if (ignitionOnFlag) {
sendIgnitionOnMessage();
}
if (ignitionOffFlag) {
sendIgnitionOffMessage();
}
if (engineOnFlag) {
sendEngineOnMessage();
}
if (engineOffFlag) {
sendEngineOffMessage();
}
if (lockedFlag) {
sendLockedMessage();
}
if (unlockedFlag) {
sendUnlockedMessage();
}
}
At this point it sends messages but it seems to have a real issue with sending multiple messages (both on and off, in no particular order) when triggering each input, and sometimes triggering one input causes messages regarding other inputs to be sent. I am putting this issue down to noise on the breadboard so really my issue is how to debounce the inputs in software (usually I would prefer top use hardware debouncing but as it this is for a vehicle inputs can be noisy so would rather clean them up in code to make sure we're good).
I did debounce the flags in the loop instead but this didn't seem to make much difference. I also moved the setting flags to false code to the start of the relevant functions as I wondered if the waiting for the success return from the Telegram message was causing an issue but seemingly not.
I would think that I want my code for debouncing would want to be in the main loop as I don't want to be waiting in functions.
For reference the code I had to debounce the flags was;
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <ESP8266WiFi.h>
#include <UniversalTelegramBot.h>
#include <WiFiClientSecure.h>
//------- WiFi Settings -------
#define WIFI_SSID "my_ssid"
#define WIFI_PASSWORD "my_pass"
// ------- Telegram Config --------
#define BOT_TOKEN "_token_"
#define CHAT_ID "_id_"
X509List cert(TELEGRAM_CERTIFICATE_ROOT);
WiFiClientSecure secured_client;
UniversalTelegramBot bot(BOT_TOKEN, secured_client);
// ------- Pin Definitions --------
#define IgnitionPin D5
#define EnginePin D6
#define DoorsPin D7
// ------- Variables for Interrupts --------
volatile bool engineOnFlag = false;
volatile bool engineOffFlag = false;
volatile bool ignitionOnFlag = false;
volatile bool ignitionOffFlag = false;
volatile bool lockedFlag = false;
volatile bool unlockedFlag = false;
// ------- Status Functions --------
void IRAM_ATTR ignition() {
ignitionInputTriggerTime = millis();
if (digitalRead(IgnitionPin) == HIGH) {
ignitionOnFlag = true;
}
else if (digitalRead(IgnitionPin) == LOW) {
ignitionOffFlag = true;
}
return;
}
void IRAM_ATTR engine() {
engineInputTriggerTime = millis();
if (digitalRead(EnginePin) == HIGH) {
engineOnFlag = true;
}
else if (digitalRead(EnginePin) == LOW) {
engineOffFlag = true;
}
return;
}
void IRAM_ATTR locks() {
lockInputTriggerTime = millis();
if (digitalRead(DoorsPin) == HIGH) {
lockedFlag = true;
}
else if (digitalRead(DoorsPin) == LOW) {
unlockedFlag = true;
}
return;
}
// ------- Message Functions --------
void sendIgnitionOnMessage() {
String message = "Ignition on";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
ignitionOnFlag = false;
}
return;
}
void sendIgnitionOffMessage() {
String message = "Ignition off";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
ignitionOffFlag = false;
}
return;
}
void sendEngineOnMessage() {
String message = "Engine on";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
engineOnFlag = false;
}
return;
}
void sendEngineOffMessage() {
String message = "Engine off";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
engineOffFlag = false;
}
return;
}
void sendLockedMessage() {
String message = "Locked";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
lockedFlag = false;
}
return;
}
void sendUnlockedMessage() {
String message = "Unlocked";
if(bot.sendMessage(CHAT_ID, message, "Markdown")) {
Serial.println(message + " successfully sent");
unlockedFlag = false;
}
return;
}
void setup() {
// ------- Init Serial Port --------
Serial.begin(115200);
Serial.println();
// ------- Pin Setup --------
pinMode(IgnitionPin, INPUT_PULLUP);
pinMode(EnginePin, INPUT_PULLUP);
pinMode(DoorsPin, INPUT_PULLUP);
// ------- Interrupt Setup --------
// NOTE: It is important to use interrupts when making network calls in the sketch
// if you just checked the status of the button in the loop you might miss the button press.
//attachInterrupt(Doors, Doors(open), RISING); //this would be great but it isn't how interrupts work!
//attachInterrupt(digitalPinToInterrupt(GPIO), ISR, mode); //mode can be rising, falling, change
attachInterrupt(IgnitionPin, ignition, CHANGE);
attachInterrupt(EnginePin, engine, CHANGE);
attachInterrupt(DoorsPin, locks, CHANGE);
// ------- Connect to WiFi network --------
Serial.print("Connecting to WiFi SSID ");
Serial.print(WIFI_SSID" ");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
secured_client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}
Serial.print("\nWiFi connected. IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Retrieving time: ");
configTime(0, 0, "pool.ntp.org"); // get UTC time via NTP
time_t now = time(nullptr);
while (now < 24 * 3600)
{
Serial.print(".");
delay(100);
now = time(nullptr);
}
Serial.println(now);
bot.sendMessage(CHAT_ID, "Tracker started up.", "");
}
void loop() {
if ((ignitionOnFlag) && (millis() - ignitionInputTriggerTime >= debounceTime)) {
sendIgnitionOnMessage();
}
if ((ignitionOffFlag) && (millis() - ignitionInputTriggerTime >= debounceTime)) {
sendIgnitionOffMessage();
}
if ((engineOnFlag) && (millis() - engineInputTriggerTime >= debounceTime)) {
sendEngineOnMessage();
}
if ((engineOffFlag) && (millis() - engineInputTriggerTime >= debounceTime)) {
sendEngineOffMessage();
}
if ((lockedFlag) && (millis() - lockInputTriggerTime >= debounceTime)) {
sendLockedMessage();
}
if ((unlockedFlag) && (millis() - lockInputTriggerTime >= debounceTime)) {
sendUnlockedMessage();
}
}```