Islamic Prayer Times - ESP32 TTGO T-Display

by AKN in Circuits > Arduino

884 Views, 8 Favorites, 0 Comments

Islamic Prayer Times - ESP32 TTGO T-Display

Grounds-cropped.jpg
Grounds.jpg
Prayer Time Display - TTGO T-Display - 25 Dec 2024
Portal.jpg
IMG-20241224-WA0003.jpg
Deep-Sleep.jpg
Prayer Screen-02.jpg

This is an Arduino IDE project that uses a readily-available development board that includes a small TFT screen - LilyGo TTGO T-Display - to retrieve and display Islamic prayer time data according to the geolocation of the user.

ESP32 Dev. Board

The LilyGo TTGO T-Display is an ESP32 device and is available from all the usual outlets. The standard 'shell' available through the same stores makes a glaringly obvious omission - space for a battery! A 402030 or 402035 lithium battery is ideal and can be stuck to the back of this case/shell with double-sided tape or strips as listed in the Supplies section below..

There are a number of freely-available .stl files for this board that incorporate space for a lithium battery. A search will reveal many to suit your needs. Here is one example. If you fancy 3D-printing your own or maybe even modifying the stock case/shell, it's available in the TTGO T-Display GitHub repository.

There is almost no soldering required except for wiring the supplied JST connector to a battery. You can be up and running in a very short time once the Arduino IDE and necessary libraries are installed. Please refer to the ReadMe.md file in this project's GitHub repository.

APIs & Keys

Prayer data is retrieved from https://muwaqqit.com in JSON format via the site's JSON endpoint. This API requires the user's latitude and longitude coordinates along with other basic information to provide a full month's prayer data.

Geolocation information is retrieved from Google using the Google Maps API. This requires a personal API key. There are many resources to guide you through how to obtain the API key. This API is accurate enough for the purpose of the project.

Since July 2018, Google has updated the terms for their Maps APIs. You must link a billing method to the Google Cloud Console to access it. For more details, visit: Google Maps Platform Pricing. Please be mindful of the number of requests you make. While there is a free monthly allowance, it is subject to change at any time. I am not liable for any billing costs incurred through the use of the Google API.

A GPS module could have been implemented, but this adds unnecessary bulk to the device. The WiFiLocation library fully manages the retrieval of lat/long and accuracy data. Other 'free' services and libraries are available, like the GeoIP library. However, accuracy is hit-and-miss when connected to the internet via a mobile 'phone. Hard-wired internet connections return reasonably accurate geolocation data. I might implement a GPS module if I can find one small (read 'tiny') enough to fit inside the current case.

Google's Timezone API is used to determine the Timezone string to pass to Muwaqqit. DST and UTC offsets are passed to the NTP/Time library to correct DST and UTC offsets.

Be sure to enable these APIs in your Google Cloud Maps Platform API Dashboard.

Be aware that in sparsely populated areas where WiFi access points are limited, geolocation accuracy may be compromised, leading to inaccurate prayer times.

APIs can stop working at any time. If you suspect a broken API, insert the endpoint into a browser window to check the result.

Muwaqqit

There are a number of prayer-time APIs available. This is one of the most configurable, accurate and reliable sources for prayer data. The developer has thoroughly researched this science, gaining the approval of scholars of the subject. Please consider supporting Muwaqqit.

Arduino Sketch

I'm not the most accomplished or elegant coder. You may find that some parts/functions resemble example code from the installed libraries. I'm a great believer of not reinventing the wheel! I'm sure you'll find ways to streamline the code.

ArduinoJSON

This library is used to extract the required data to display on the TFT screen and serial port. The WiFiLocation library also uses ArduinoJSON. Please also consider supporting Benoit.

This project was started over four years ago, and stalled due to my lack of understanding how to extract JSON elements or how to use ArduinoJSON. Having purchased Benoit's book, and access to more examples, I was able to complete what I'd planned on achieving in a few days!

WiFiManager

This library is incorporated to eliminate the need to hard-code one's WiFi credentials.

This library also allows Over The Air updates. This has been successfully tested!

Supplies

Screenshot 2024-12-09 195101.png
Screenshot 2024-12-09 195345.png
IMG-20241224-WA0005.jpg
IMG-20241224-WA0008.jpg
TTGO-CH9102.jpg

Hardware

LilyGo TTGO T-Display Module (16M)

T-Display Shell

402030 Lithium Battery

402035 Lithium Battery

Double-sided adhesive strips


Software

Muwaqqit API Documentation

Arduino IDE

Google Maps API

GitHub Project Sketch


Serial Driver

If you haven't already done so, you'll need to install the correct serial driver. Without this driver, the Arduino IDE won't "see" the device. All the T-Display boards I have seen use the WCH CH9102F chip.

Adafruit has a decent tutorial on how to install the driver.

Windows CHxxx driver

Mac CHxxx driver

Arduino IDE

Screenshot 2024-12-09 193721.png

ESP32 Board Install - V2.0.17

If not already, install the Arduino IDE. You'll need to install ESP32 Board files. Instructions are available at a number of sites. Random Nerd Tutorials is a reliable source.

There have been some issues with the V3 release of Espressif's ESP32 Board library, which caused some compilation problems. Downgrading to V2.0.17 resolved the problems experienced. It may also be prudent to downgrade the Arduino ESP32 Board to V2.0.13

Libraries

Search for the following Libraries and install the versions shown:

ArduinoJSON - V7.3.0

ArduinoJSON provides an elegant and powerful solution to extracting JSON data.

QuickDebug - V0.7.0 ***

Get the QuickDebug library (.zip format) and install manually from the Sketch/Include Library/Add .ZIP Library... menu.

TFT_eSPI - V2.5.43

TFT_eSPI library's setup file will need to be modified. Locate where TFT_eSPI is installed. Ensure the User_Setup_Select.h file is correctly configured for the TTGO T-Display ST7789 driver:

Comment out the line as below:
//#include <User_Setup.h> // Default setup is root library folder

Uncomment line as below:
#include <User_Setups/Setup25_TTGO_T_Display.h> // Setup file for ESP32 and TTGO T-Display ST7789V SPI bus TFT


WiFiLocation - V1.3.0

WiFiLocation leverages Google's Maps API to retrieve longitude and latitude coordinates without the need use a GPS receiver. The returned coordinates are extremely accurate! So long as you're in a densely WiFi-populated area.

You'll need to install the QuickDebug library for V1.3.0 to install. Otherwise, V1.2.9 has been tested to work without QuickDebug. V1.3.0 seems to return more accurate and reliable coordinates. See above for installation.

WiFiManager - V2.0.17

This library is incorporated to eliminate the need to hard-code one's WiFi credentials. If no WiFi credentials are stored or the stored SSID is not present, an Access Point is enabled for you to launch the WiFi Configuration Portal.

Battery18650Stats - V1.0.0 ***

This library provides an easy method of obtaining battery charge level and voltage.

Tjpg_decoder - V1.1.0 ***

Library to decode and display non-progressive Jpeg images. This is used to display a Google map image of the current location.

*** Newly added functionality since this instructable was published

Arduino Sketch

Screenshot 2024-12-09 200908.png
Screenshot 2024-12-09 201056.png

Download the latest version of the Sketch from GitHub and save it to your Sketch directory and open for editing.

Board Type & COM Port

Set the Board type to ESP32 Dev Module.

Plug in your TTGO board into an unused USB port. Select the correct COM Port linked to the Board.

Google API Key

Insert your Google Maps API Key in the line indicated:

const char* googleApiKey = "Paste Your Google API Key Here";

This Key will be used to access Google's Timezone, Geolocation, Geocode and Maps Static APIs. Be sure to enable these APIs in your Google Cloud Maps Platform API Dashboard.

Upload Sketch

You're now ready to compile and upload the code to the TTGO device. There shouldn't be any compilation errors and your device is ready for use. If you encounter any errors, review the reported errors, correct any issues and re-upload.

My skills

As touched on earlier, my coding skills are rudimentary at best, so please go easy on me. :-) I'll try to tidy-up the flow and placement of functions into a logical order at some point.

Sketch Function Descriptions

tftOutput() // Callback function for TJpg_Decoder

formatspiffs() // Function to format SPIFFS is a file system is not present. ***

syncTime() // Function to synchronize time with NTP server. You can replace the 'stock' pool.ntp.org NTP server with any other you may prefer.

const char* ntp_server = "pool.ntp.org";

fetchJSON() // Fetch JSON data from Muwaqqit.

timeToSeconds(const char* timeStr) // Function to convert time string HH:MM:SS to total seconds since midnight. Reason is to help determine which is the current prayer.

getTZ() // Function to determine Timezone, DST and UTC Offset via Google Maps Timezone API.

getAddress() // Function to determine location Address from Lat/Long and send to TFT.

fetchAndSaveMap(float latMap, float lonMap) // Function to retrieve location map image from Google's staticmap API ***

decodeAndDisplayMap() // Function to read SPIFF contents os saved image, decode jpg and display on TFT ***

drawflag() // Draw Palestinian Flag as a show of solidarity to all those being harmed and oppressed.

batteryV() // Determine the charge state of the battery.

This function now uses the more reliable Battery18650Stats library. ***

printLocalTime() // Function to print current local time and date.

checkButton() // Function to test if button pressed and held for 3 seconds to reset WiFi credentials during prayer times view.

print_wakeup_reason() // Send to serial device, the wake-up reason. For debug purposes.

checkButtons() // Function to determine map zoom level and map type during map view. ***

updateDisplay() // Update map image on TFT when zoom levels or maptype changed in checkButtons() function. ***

setup() // Configuration and setup of screen, button, WiFi, Splash screen, and first retrieval & display of prayer data.

loop() // Update time and battery status on TFT. Repeat until Deep-Sleep entered after 60 seconds.

*** Newly added functionality since this instructable was published

Programme Flow

Here is a detailed description of the main points of the sketch.

  1. Definition of all libraries used, initialisation of:
  2. WiFiManager
  3. WiFiLocation
  4. TFT_eSPI
  5. NTP Service
  6. GPIO Pin definitions
  7. definition of global variables
  8. Setup() function
  9. Configure TFT display
  10. Initialise GPIO pins used
  11. Initialize Serial Port
  12. Send to serial port the reason wake-up forced after Deep-Sleep
  13. Draw flag
  14. Display Config Portal details
  15. Initialise WiFi config portal
  16. If previously configured WiFi not available or WiFi not configured within 60 seconds, enter deep-sleep
  17. Determine Latitude & Longitude
  18. Get time & date from NTP server
  19. Pass date to Google Timezone API ***
  20. Determine Timezone, DST & UTC offset ***
  21. Get time & date from NTP server and apply correct offsets ***
  22. Send local time and date to serial port
  23. Get location address from Google Maps API ***
  24. Get and display map of current location from Google Maps API ***
  25. Pass fully-formed URL endpoint to Muwaqqit API
  26. Receive prayer time data
  27. Get location address via Google Geocode API ***
  28. If wake-up button is pressed and held during start-up, skip to display address and then prayer times. ***
  29. Display approximate postal address of current location for 5 seconds
  30. Display a Google map of the current location.
  31. Zoom in and out with buttons.
  32. Swap between roadmap and satellite view if both buttons pressed simultaneously.
  33. Update current time & date
  34. Display prayer times
  35. Highlight current prayer time
  36. Loop() function
  37. Send local time to serial port
  38. Update local time and date on TFT screen
  39. Update battery status on TFT screen - % or "Charging" ***
  40. Check if button on GPIO 35 pressed and held for 3 seconds
  41. If button pressed and held, initiate WiFi portal. Shutdown after 3 minutes if WiFi not re-configured
  42. If 60 seconds have elapsed after running Loop function, enter deep-sleep
  43. Otherwise, repeat Loop().

*** Newly added functionality since this instructable was published

Functionality

WiFi-AP.jpg
Portal-02.jpg
Portal-01.jpg
Screenshot 2024-12-09 201541.png
Update-01.jpg
Update-02.jpg
Update-03.jpg

WiFi Configuration Portal

If no connection or no SSID defined, the WiFi Configuration Portal is enabled.

On a mobile device, connect to SSID "Muwaqqit-AP" - You may have to browse to 192.168.4.1

Select "Configure WiFi"

Choose WiFi network, enter password and select "Save"

Configuration portal will close and the device will connect to the chosen WiFi network and continue.

Reset WiFi SSID Credentials

If at any time you want to change the WiFi credentials, press and hold the top button for 3 seconds while prayer times are displayed to launch the configuration portal, where you can delete or set a new WiFi network SSID.

OTA Update

WifiManager has the additional functionality to apply Over The Air (OTA) updates. You'll see the "Update" button when you connect to the configuration portal. Point to the .bin file you want to install and let it do the rest. It's best to do this through a browser window, not the captive portal that's automatically presented during configuration.

To save the compiled .bin file, go to "Sketch/Export Compiled Binary." The compiled .bin file is stored in the sketch's home directory under 'build.' There will be a number of files in this directory. You want to point to the file that reads "Islamic Prayer Times Display-TTGO.ino.bin" if you've not changed the GitHub filename.

Deep Sleep

To conserve battery life, the ESP32 device is forced into Deep-Sleep mode in two places:

  1. if the WiFi Configuration Portal has not been modified for 60 seconds,
  2. after prayer times have been displayed for 60 seconds.

The device will remain in Deep-Sleep until the lower button is pressed, whereby the device will restart. See below - Wake-Up.

The TFT is also placed into Low Power mode, and now even less power is being drawn during Deep Sleep. A 250mAh LiPo battery seems to last around 7-10 days with "normal" use. ***

tft.writecommand(ST7789_DISPOFF); // Switch off the display
tft.writecommand(ST7789_SLPIN); // Sleep the display driver
delay(120); //Allow time to stabilise action before moving-on to enable deep-sleep of ESP32


Wake-Up

As mentioned above, at certain points the device enters Deep-Sleep. You can force a Restart/Wake-up by pressing the lower button.

Pressing and holding the wake-up button during the start-up phase will skip display of postal address and Google map and move directly to displaying prayer times. ***

Serial Debug

With the Serial Monitor enabled, you'll see a flow of information being printed for you to verify that the device is functioning as expected, i.e geolocation data, prayer times API URL string, formatted prayer table etc.

*** Newly added functionality since this instructable was published

Customising

A number of timers,delays and switches are used and are merely a starting point. The default timings are set for optimal viewing time and conservation of battery life. Here are the areas you might want to modify to your preference:

Time until Deep Sleep

This is the length of time the prayer times will remain on-screen before entering Deep-Sleep. Default value is 30000 milliseconds, denoting 30 seconds. Modify the variable 'interval' to your preference:

const unsigned long interval = 30000; // Interval before entering Deep_Sleep - 60 seconds


Change WiFi SSID Credentials

If at any time you want to change the WiFi credentials, press and hold the top button for 3 seconds while prayer times are displayed to launch the WiFi configuration portal, ready for the WiFi to be configured. You can change the length of time to hold the button by modifying this line:

delay(3000); // reset delay hold


WiFi Configuration Portal Timeout

Closes the WiFi Portal after 180 seconds on no action. Modify this line to your desired timeout:

wifiManager.setConfigPortalTimeout(180); // auto close config portal after 3 minutes


Muwaqqit API Endpoint URL

Should you have a need to retrieve prayer times with different settings e.g for Fajr or Isha angles, please consult Muwaqqit's API documentation to further customise your desired settings.

// API endpoint
const char* api_url = "";
const char* api_url1 = "https://www.muwaqqit.com/api.json?d=";
const char* api_url2 = ";lt=";
const char* api_url3 = "&ln=";
const char* api_url4 = ";fa=-18;era=-12&ea=-13&tztype=auto&tz=";


Here is an example of a fully-formed Muwaqqit endpoint:

https://www.muwaqqit.com/api.json?d=2024-12-23;lt=51.4447975&ln=-1.8653843;fa=-18;era=-12&ea=-13&tztype=auto&tz=Europe/London


Google Geocode Location API

If you find that the returned address and format isn't suitable for your requirements, head over to Google's detailed documentation on Reverse Geocoding.. You can choose what you want returned by customising the API endpoint and using ArduinoJson to filter the response.

https://maps.googleapis.com/maps/api/geocode/json?


JsonObject filter_results_0_address_components_0 = filter["results"][0]["address_components"].add<JsonObject>();
filter_results_0_address_components_0["short_name"] = true;


JsonArray results = doc["results"];
JsonArray results_0_address_components = results[0]["address_components"];

const char* housenumber = results_0_address_components[0]["short_name"]; // number
const char* streetname = results_0_address_components[1]["short_name"]; // route (Road)
const char* townname = results_0_address_components[2]["short_name"]; // postal_town - e.g. London
const char* postalcode = results_0_address_components[6]["short_name"]; // postal_code
const char* countyname = results_0_address_components[3]["short_name"]; // "political" (County) - e.g. Wiltshire
const char* countryname1 = results_0_address_components[4]["short_name"]; // "political" (Country) - e.g. England
const char* countryname2 = results_0_address_components[5]["short_name"]; // "country" - e.g. GB


Handedness Customisation ***

The device's current button orientation is optimized for right-handed users. If you wish to modify the sketch to flip the device 180°, a few changes are required. First, you need to swap the button definitions. Then, you need to appropriately initialise the screen rotation. The changes you need to apply are shown below:

Global settings:
#define TRIGGER_PIN GPIO_NUM_0
#define WAKEUP_PIN 35

Setup()
tft.setRotation(3);

*** Newly added since this instructable was published

Future Enhancements

Satellite-01.jpg
Roadmap-02.jpg
Satellite-02.jpg
Roadmap-01.jpg

Map and qibla direction ***

This function now displays on the TFT, a map of the current location along with a line indicating the direction of prayer. This is retrieved from Google's staticmap API. The implemented endpoint URL is shown below:

https://maps.googleapis.com/maps/api/staticmap?center=<location latitude>,<location longitude>&zoom=16&size=240x135&format=jpg-baseline&markers=size:tiny%7Ccolor:0xff0000ff%7C<location latitude>,<location longitude>&path=geodesic:true|color:0xff0000ff|weight:4|<location latitude>,<location longitude>|21.4224779,39.8262775&key=<Your Google Maps API Key>

The received map image is stored in SPIFFS and then displayed on the TFT.

Zoom in/out and swapping between Roadmap and Satellite view has been implemented in the current sketch.

  1. Top button (not reset) - Zoom-in
  2. Lower button - Zoom-out
  3. Both buttons - Toggle between Roadmap and Satellite view.

Zoom levels and detail will vary from place to place as described in the staticmap "zoom-levels" documentation.

Multi-SSIDs

Unfortunately, the current version of WiFiManager does not support storage of multiple access points. This functionality is listed in the library's roadmap from a few years ago - so here's hoping...

Time-Zone ***

Automatically determining the user's time-zone and DST settings may be necessary to return the correct displayed time and passing correct time-zone to the Muwaqqit API. This is a Work-in-Progress and will be incorporated at a future date. In the meantime, feel free to modify the lines shown here for your location:

const long gmt_offset_sec = 0; // Adjust if necessary for your timezone
const int daylight_offset_sec = 3600; // Adjust for daylight savings

21 Dec - You'll be pleased to learn that this has now been implemented and the change has been committed to the GitHub repository. Its functionality just needs to be confirmed by testing in other worldwide regions...

*** Newly added functionality since this instructable was published

Over to You

Feel free to comment with any useful thoughts and how you may have modified this project to suit your needs.

Have fun making it and supporting the services that have made this project possible!

Updated 5 Feb 2025