Silicon ChipTeach-In 2024 – Learn electronics with the ESP32 - September 2024 SILICON CHIP
  1. Contents
  2. Publisher's Letter: Hello from the other side of the planet
  3. Feature: Techno Talk - I don’t want to be a Norbert... by Max the Magnificent
  4. Feature: The Fox Report by Barry Fox
  5. Feature: Net Work by Alan Winstanley
  6. Subscriptions
  7. Project: Build Your Own Calibrated Microphones by Phil Prosser
  8. Feature: Using Electronic Modules – 1.3-inch monochrome OLED by Jim Rowe
  9. Project: Modern PIC Programming Adaptor by Nicholas Vinen
  10. Feature: Circuit Surgery by Ian Bell
  11. Back Issues
  12. Feature: Audio Out by Jake Rothman
  13. Feature: Max’s Cool Beans by Max the Magnificent
  14. Project: Salad Bowl Speakers by Phil Prosser
  15. Feature: Teach-In 2024 – Learn electronics with the ESP32 by Mike Tooley
  16. Back Issues
  17. PartShop
  18. Market Centre
  19. Advertising Index
  20. Back Issues

This is only a preview of the September 2024 issue of Practical Electronics.

You can view 0 of the 80 pages in the full issue.

Articles in this series:
  • (November 2020)
  • Techno Talk (December 2020)
  • Techno Talk (January 2021)
  • Techno Talk (February 2021)
  • Techno Talk (March 2021)
  • Techno Talk (April 2021)
  • Techno Talk (May 2021)
  • Techno Talk (June 2021)
  • Techno Talk (July 2021)
  • Techno Talk (August 2021)
  • Techno Talk (September 2021)
  • Techno Talk (October 2021)
  • Techno Talk (November 2021)
  • Techno Talk (December 2021)
  • Communing with nature (January 2022)
  • Should we be worried? (February 2022)
  • How resilient is your lifeline? (March 2022)
  • Go eco, get ethical! (April 2022)
  • From nano to bio (May 2022)
  • Positivity follows the gloom (June 2022)
  • Mixed menu (July 2022)
  • Time for a total rethink? (August 2022)
  • What’s in a name? (September 2022)
  • Forget leaves on the line! (October 2022)
  • Giant Boost for Batteries (December 2022)
  • Raudive Voices Revisited (January 2023)
  • A thousand words (February 2023)
  • It’s handover time (March 2023)
  • AI, Robots, Horticulture and Agriculture (April 2023)
  • Prophecy can be perplexing (May 2023)
  • Technology comes in different shapes and sizes (June 2023)
  • AI and robots – what could possibly go wrong? (July 2023)
  • How long until we’re all out of work? (August 2023)
  • We both have truths, are mine the same as yours? (September 2023)
  • Holy Spheres, Batman! (October 2023)
  • Where’s my pneumatic car? (November 2023)
  • Good grief! (December 2023)
  • Cheeky chiplets (January 2024)
  • Cheeky chiplets (February 2024)
  • The Wibbly-Wobbly World of Quantum (March 2024)
  • Techno Talk - Wait! What? Really? (April 2024)
  • Techno Talk - One step closer to a dystopian abyss? (May 2024)
  • Techno Talk - Program that! (June 2024)
  • Techno Talk (July 2024)
  • Techno Talk - That makes so much sense! (August 2024)
  • Techno Talk - I don’t want to be a Norbert... (September 2024)
  • Techno Talk - Sticking the landing (October 2024)
  • Techno Talk (November 2024)
  • Techno Talk (December 2024)
  • Techno Talk (January 2025)
  • Techno Talk (February 2025)
  • Techno Talk (March 2025)
  • Techno Talk (April 2025)
  • Techno Talk (May 2025)
  • Techno Talk (June 2025)
Articles in this series:
  • The Fox Report (July 2024)
  • The Fox Report (September 2024)
  • The Fox Report (October 2024)
  • The Fox Report (November 2024)
  • The Fox Report (December 2024)
  • The Fox Report (January 2025)
  • The Fox Report (February 2025)
  • The Fox Report (March 2025)
  • The Fox Report (April 2025)
  • The Fox Report (May 2025)
Articles in this series:
  • Win a Microchip Explorer 8 Development Kit (April 2024)
  • Net Work (May 2024)
  • Net Work (June 2024)
  • Net Work (July 2024)
  • Net Work (August 2024)
  • Net Work (September 2024)
  • Net Work (October 2024)
  • Net Work (November 2024)
  • Net Work (December 2024)
  • Net Work (January 2025)
  • Net Work (February 2025)
  • Net Work (March 2025)
  • Net Work (April 2025)
Articles in this series:
  • Circuit Surgery (April 2024)
  • STEWART OF READING (April 2024)
  • Circuit Surgery (May 2024)
  • Circuit Surgery (June 2024)
  • Circuit Surgery (July 2024)
  • Circuit Surgery (August 2024)
  • Circuit Surgery (September 2024)
  • Circuit Surgery (October 2024)
  • Circuit Surgery (November 2024)
  • Circuit Surgery (December 2024)
  • Circuit Surgery (January 2025)
  • Circuit Surgery (February 2025)
  • Circuit Surgery (March 2025)
  • Circuit Surgery (April 2025)
  • Circuit Surgery (May 2025)
  • Circuit Surgery (June 2025)
Articles in this series:
  • Audio Out (January 2024)
  • Audio Out (February 2024)
  • AUDIO OUT (April 2024)
  • Audio Out (May 2024)
  • Audio Out (June 2024)
  • Audio Out (July 2024)
  • Audio Out (August 2024)
  • Audio Out (September 2024)
  • Audio Out (October 2024)
  • Audio Out (March 2025)
  • Audio Out (April 2025)
  • Audio Out (May 2025)
  • Audio Out (June 2025)
Articles in this series:
  • Max’s Cool Beans (April 2024)
  • Max’s Cool Beans (May 2024)
  • Max’s Cool Beans (June 2024)
  • Max’s Cool Beans (July 2024)
  • Max’s Cool Beans (August 2024)
  • Max’s Cool Beans (September 2024)
  • Max’s Cool Beans (October 2024)
  • Max’s Cool Beans (November 2024)
  • Max’s Cool Beans (December 2024)
Articles in this series:
  • Teach-In 2024 (April 2024)
  • Teach-In 2024 (May 2024)
  • Teach-In 2024 – Learn electronics with the ESP32 (June 2024)
  • Teach-In 2024 – Learn electronics with the ESP32 (July 2024)
  • Teach-In 2024 – Learn electronics with the ESP32 (August 2024)
  • Teach-In 2024 – Learn electronics with the ESP32 (September 2024)
  • Teach-In 2024 – Learn electronics with the ESP32 (October 2024)
  • Teach-In 2024 – Learn electronics with the ESP32 (November 2024)
Teach-In 2024 Learn electronics with the ESP32 by Mike Tooley Part 7 – Telling the Time I n the last part of our Teach-In series, we ex- plored some of the ESP32’s inbuilt features that make wireless communication a reality. That started with a simple wireless Access Point to send environmental data that can be displayed on a phone, tablet, laptop or desktop PC. This instalment continues that theme by showing how an ESP32 can connect to the Internet and use a network time protocol (NTP) server to obtain the current time with very high accuracy. Our Practical Project features the construction of a highly accurate digital clock with a low-cost 16 × 2 LCD panel display, while our Coding Workshop will take your coding skills to a new level by introducing arrays and structures. The learning objectives for the seventh part of our series are: n Know how to connect to an NTP time server n Know how to format and display NTP data n Know how to use C++ arrays and structures The Network Time Protocol (NTP) The Network Time Protocol is a set of rules for synchronising computers and microcontrollers using data derived from a standard network time reference. This allows you to obtain the time and date with very high precision and without any additional hardware. NTP servers (see Table 7.1) must operate independently of their locale, providing worldwide access to UTC (Universal Coordinated Time). Like GMT (Greenwich Mean Time), UTC is the same all over the world and needs to be adjusted for the local time zone and daylight saving, where appropriate. To use NTP with an ESP32 (or similar microcontroller), we usually configure the ESP32 as a client that connects to an NTP server via the UDP (User Datagram Protocol) on port 123. Once connected, the client sends a request packet to the Table 7.1 – Internet time servers Region Host name Asia asia.pool.ntp.org Europe europe.pool.ntp.org North America north-america.pool.ntp.org Oceania oceania.pool.ntp.org South America south-america.pool.ntp.org Worldwide pool.ntp.org 70 About Teach-In Our latest Teach-In series is about using the popular ESP32 module as a basis for learning electronics and coding. We will be making no assumptions about your coding ability or your previous experience of electronics. If you know one but not the other, you have come to the right place. On the other hand, if you happen to be a complete newbie there’s no need to worry because the series will take a progressive hands-on approach. There will be plenty of time to build up your knowledge and plenty of opportunity to test things out along the way. We’ve not included too much basic theory because this can be easily found elsewhere, including several of our previous Teach-In series, see: https://bit.ly/pe-ti https://bit.ly/pe-ti-bundle Earch month, there’ll be projects and challenges to help you check and develop your understanding of the topics covered. server, which responds with a timestamp packet containing data that’s parsed to extract the required information. Using the public Internet, NTP usually maintains time to within just a few milliseconds, but when used in the more controlled environment of a LAN (Local Area Network), the accuracy can be improved to within 1ms. Unlike protocols like TCP, UDP does not rely on handshaking and does not keep track of what’s sent. It thus avoids the repeat transmissions and overheads associated with error checking, and is the preferred method for time-critical applications like NTP. Time zones To compensate for different time zones, it is necessary to adjust the UTC offset. This is calculated by multiplying the GMT zone by 3600 (the number of seconds for each hour difference in GMT). This is quite easy to do, as illustrated by the time zone and daylight saving offsets for various cities in Table 7.2. For example, the GMT offset for Paris is gmtOffset_sec = 3600 while that for Singapore is gmtOffset_sec = 28800. In our code, each of these time zone offsets would be defined as longs using lines like these two examples: const long gmtOffset_sec = 3600; // Paris const long gmtOffset_sec = 28800; // Singapore Practical Electronics | September | 2024 Gotcha! Because UTC and GMT share the same current time, they are often confused. The essential difference between the two is that UTC is a time standard while GMT is a time zone that just happens to have zero offset from UTC. Daylight saving time (DST) First proposed by Benjamin Franklin in Paris in 1784, daylight saving is the practice of putting clocks backwards in winter and forwards in summer to make best use of the available daylight. Today, many countries observe this practice, so it must be accommodated when obtaining local times from UTC. To obtain the time adjusted for daylight saving, we use a further one-hour offset which is applied during the applicable months. Since we are only dealing with an offset of 3600 seconds, we can use an integer value with a line of the form: const int daylightOffset_sec = 3600; // DST offset Having determined the required time zone and DST offsets, we are ready to configure the application using the values that we have defined. This can be achieved using the timeconfigTime() function, as follows: timeconfigTime(gmtOffset_sec, daylightOffset_sec, ntpServer); Check it out! The time has come to check out your ESP32’s ability to obtain and display NTP data, so let’s connect to the default (worldwide) NTP time server, retrieve the current time and display it using the Serial Monitor. That might sound complicated, but it’s actually quite easy! We need to include two required libraries, <WiFi.h> and “time.h”, using: #include <WiFi.h> #include "time.h" The first of these two libraries manages the ESP32’s Wi-Fi interface while the second facilitates the exchange of data between the ESP32 (as a client) and the NTP time server. Next, we will need to define various network parameters including the SSID (see last month), Wi-Fi password, NTP time server and the required offsets for GMT (time zone) and DST. You may have a different offset, but for London (UK), this is achieved using code like: // Network parameters const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASSWORD"; const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 0; const int daylightOffset_sec = 3600; The getLocalTime() function will send a request packet to the NTP server, parse the time stamp packet received, and store the date and time information extracted from it in a time structure called timeinfo. There will be more information about the use of C++ structures is in the Coding Workshop below, under the heading Coding Workshop on page 72. The complete code listing appears in Listing 7.1, while Fig.7.1 is a screen grab showing how the data appears in the ESP32’s Serial Monitor. Practical Electronics | September | 2024 Table 7.2 – Time zones and DST offsets for various cities City & country Time zone Offset DST? Adelaide, Australia GMT+9½ 9.5 × 3600 = 34200 Yes Athens, Greece GMT+2 2 × 3600 = 7200 Yes Brisbane, Australia GMT+10 10 × 3600 = 36000 No Helsinki, Finland GMT+2 2 × 3600 = 7200 Yes London, England GMT+0 0 × 3600 = 3600 Yes New York, USA GMT−5 −5 × 3600 = −18000 Yes Paris, France GMT+1 1 × 3600 = 3600 Yes Singapore GMT+8 8 × 3600 = 28800 No Listing 7.1 – Fetch and display NTP time data using the ESP32’s Serial Monitor // Include the required library files #include <WiFi.h> #include "time.h" // Network parameters const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASSWORD"; const char* ntpServer = "pool.ntp.org"; const long gmtOff_sec = 0; // Change if necessary const int daylightOff_sec = 3600; // Change if nec. void setup() { Serial.begin(115200); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } // Initialise and get the time configTime(gmtOff_sec, daylightOff_sec, ntpServer); printLocalTime(); // Disconnect WiFi WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } void loop() { delay(1000); printLocalTime(); } void printLocalTime() { struct tm timeinfo; // Warn if time is not found if (!getLocalTime(&timeinfo)) { Serial.println("Time not found!"); Serial.println("Is the router OK?"); return; } // Display the current time Serial.println("* CURRENT NTP TIME *"); Serial.println(&timeinfo, "%H:%M:%S"); Serial.println(&timeinfo, "%A %d"); Serial.println(""); } Gotcha! The default NTP time server at pool.ntp.org automatically selects a time server that is nearby, but you can specify a different time server selected from the list in Table 7.1. You may also need to change one or both offsets as required for your location. 71 Table 7.3 – Parsed values returned by getLocalTime() Fig.7.1: The output of the ESP32 Serial Monitor running the NTP sketch in Listing 7.1. Working with time data A wide variety of options can be used to extract the data that you need from the timeinfo structure. This makes it delightfully easy to manipulate and format the data that you need. Table 7.3 lists the available specifiers. For example, %A is used to obtain just the day of the week while %F will provide you with the data in long (YYYY-MMDD) format. The code fragment in Listing 7.2 shows just a few of the formatting option for date/time strings. The result of running the code is shown in Fig.7.2. Specifier Value returned Example %A Day of the week Monday %a Day of the week (abbreviated) Mon %B Month of the year January %b Month of the year (abbreviated) Jan %D Short format date (MM/DD/YY) 05/15/24 %d Day of the month 12 %F Long format date (YYYY-MM-DD) 2024-02-10 %H Hour of the day (24-hour format) 21 %I Hour of the day (12-hour format) 9 %j Day of the year 211 %Y Year 2024 %y Last two digits of the year 24 %m Month as a number 05 %M Minute of the hour 59 %p AM or PM PM %r 12-hour clock time 09:15:21 am %R 24-hour time HH: MM 21:19 %S Second of the minute 21 %T Formatted time (HH: MM: SS) 09:15:21 Arrays provide a way of storing multiple values within a single variable, avoiding the need for separate variable declarations. Structures take this one stage further by allowing you to group variables regardless of their type. Let’s see how they work. String arrays We briefly mentioned string arrays in Part 6 of this Teach-In series, when we showed how strings are stored as an array of alphanumeric characters. Arrays can be extremely useful, particularly when storing and manipulating the same data types. Coding Workshop To declare an array, you simply need to define the variable This month’s Coding Workshop provides you with an introductype, specify the name for the array and the number of elements tion to the arrays and structures available in C++. that need to be stored. It is possible to have multi-dimensional arrays, but we’ll stick to a single dimension here. Note that the name of the array should be immediately folListing 7.2 – Some possible date/time string formats lowed by square brackets containing the number of items in the array. Here are two examples: // Display current time in different formats Serial.print("Formatted time: \t"); string colourChannel[5]; Serial.println(&timeinfo, "%T"); Serial.print("Time (24 hour format): \t"); Serial.println(&timeinfo, "%R"); This declares a colourChannel[] array that will hold six string Serial.print("Time (12 hour format): \t"); Serial.println(&timeinfo, "%r"); Serial.print("Minutes and seconds: \t"); Serial.println(&timeinfo, "%M:%S" ); Serial.print("Month, day and year): \t"); Serial.println(&timeinfo, "%B %d %Y"); Serial.print("Date (long format): \t"); Serial.println(&timeinfo, "%F"); Serial.print("Date (short format): \t"); Serial.println(&timeinfo, "%D"); Serial.print("AM or PM: \t\t"); Serial.println(&timeinfo, "%p"); Serial.print("Day of the year: \t"); Serial.println(&timeinfo, "%j"); Serial.println(""); Fig.7.2: The result of running the code in Listing 7.2. 72 Practical Electronics | September | 2024 Gotcha! Listing 7.3 – Example of using data structures with the ESP32 Array indexes start with 0 so that [0] is the first element, [1] is the second element, and so on. It’s important to remember this if you’re coding with arrays! /* Using structures with the ESP32 */ variables. To place values into the array, we can arrange them in the form of a comma-separated list enclosed by a pair of curly braces: string colourChannel[5] = {"Red", "Green", "Blue", "Black", "White"}; // Declare our structure struct sensors { String name; String type; int address; bool status; int calibration; long data; } Sensor1, Sensor2, Sensor3; void setup() { Serial.begin(115200); Each string in the list is enclosed in its own opening and closing quotation marks. Without these, they won’t be interpreted as strings! // Define the first sensor Sensor1.name = "Lobby"; // Lobby sensor Sensor1.type = "72X121"; Sensor1.address = 64; Sensor1.status = false; Sensor1.calibration = 255; Sensor1.data = 0; Numeric arrays Numerical values are handled similarly. For example, the following code fragment creates an array of four longs (32-bit or 64-bit integers) designed for use in the RF synthesiser of an FT8 HF transceiver: // Define the second sensor Sensor2.name = "Hall"; // Hall sensor Sensor2.type = "72X121"; Sensor2.address = 64; Sensor2.status = false; Sensor2.calibration = 127; Sensor2.data = 0; long txFT8[4] = { 3573000, 7074000, 10136000, 14074000 }; Accessing array elements Individual elements stored within an array are accessed using an index number with a value from 0 to one less than the size of the array. This can be a little confusing, so we’ve provided some examples in Tables 7.4 and 7.5 which respectively show how the variables in our two previous array examples are indexed. Structures Structures, like those that we met earlier using NTP, provide a neat and efficient way of grouping related variables. However, unlike arrays, structures can contain a mixture of many different data types. In contrast, all the elements in a single array must be of the same type. Each of the variables becomes a member of the structure. To create a structure, use the struct keyword and then declare each of its members, as shown in Listing 7.3. In Listing 7.3, the sensors structure has seven members of which two are strings (name and type), two are integers (address and calibration), one is a long (data), and one is a Boolean (status). Each of the sensors (Sensor1, Sensor2 and Sensor3) shares the same structure. The variables that apply to the individual sensors are defined and initialised in the code, starting with Sensor1 and ending with Sensor3. To show how the structure might be used, the loop included in the listing has some sample data for display using the ESP32’s Serial Monitor. Table 7.4 – Indexing the colourChannel[] array // Sensor name // Sensor type // Bus address // Status flag // Calibration factor // Sensor data // Three sensors // Define the third sensor Sensor3.name = "Office"; // Office sensor Sensor3.type = "92Y200"; Sensor3.address = 64; Sensor3.status = false; Sensor3.calibration = 192; Sensor3.data = 0; } void loop() { // Code to fetch and process sensor data goes here Sensor1.status = true; // Sensor OK Sensor2.status = false; // Faulty sensor detected Sensor3.status = true; // Sensor OK // But for test purposes add some data here Sensor1.data = 12928; Sensor2.data = 0; // No data returned Sensor3.data = 22491; // Check each sensor and if online display its data Serial.println("Current sensor data: "); if (Sensor1.status == true) { Serial.println(Sensor1.name + "\t" + Sensor1.data); } else { Serial.println(Sensor1.name + "\tFault!"); } if (Sensor2.status == true) { Serial.println(Sensor2.name + "\t" + Sensor2.data); } else { Serial.println(Sensor2.name + "\tFault!"); } if (Sensor3.status == true) { Serial.println(Sensor3.name + "\t" + Sensor3.data); } else { Serial.println(Sensor3.name + "\tFault!"); } Serial.println(); delay(5000); // Wait five seconds } Array index Code reference String stored Table 7.5 – Indexing the txFT8[] array 0 colourChannel[0] Red Array index Code reference Numeric value stored 1 colourChannel[1] Green 0 txFT8[0] 3573000 2 colourChannel[2] Blue 1 txFT8[1] 7074000 3 colourChannel[3] Black 2 txFT8[2] 10136000 4 colourChannel[4] White 3 txFT8[3] 14074000 Practical Electronics | September | 2024 73 A Practical Project Our Practical Project uses NTP to convert the ESP32 into a network-synchronised clock with the current time displayed on a low-cost 16 × 2 LCD panel. The circuit to interface the ESP32 to the 16 × 2 LCD panel is shown in Fig.7.3. The LCD panel is fitted with an I2C interface (see Part 5) that only requires four connections: GND, VCC, SDA (I2C data) and SCL (I2C clock). To centre the time on the LCD display, so that it looks nice, we need to be able to address individual character cells, as shown in Fig.7.4. For example, after first initialising the LCD screen, to place the letter ‘A’ in row 0, column 9 of the display we would use the following code: Fig.7.3: Connecting the alphanumeric LCD screen to the ESP32 only requires four wires. Two are for the bidirectional I2C serial bus (SDA & SCL), while the other two deliver power and provide a common ground for serial communications. Teach-In Challenge lcd.setCursor(9, 0); // Cursor to row 0, column 9 The functionality of this month’s Practical Project can easily be extended by adding one or more relays to control external lcd.print("A"); // Display the character equipment. It can switch this equipment on or off based on the Whereas, to display the letter B in row 1, column 5, we use: current time and/or date. Our Teach-In Challenge involves adding a single relay that lcd.setCursor(5, 1); // Cursor to row 1, column 5 can be used to control some external night security lighting that’s to operate during the period 20:00 to 07:00. The relay lcd.print("B"); // Display the character (RL1) is similar to those that we met earlier in Part 5 of TeachOn each occasion, we’ve used lcd.setCursor to locate the In and only requires simple interface circuitry along the lines of that shown in Figs.7.6 and Fig.7.7. character cell before printing the character. You will need to define the I/O pin for RL1 using a line of The preferred layout for the date and time display is shown the form: in Fig.7.5. The starting point for the hours, minutes and seconds string is set to row 0, column 4, while the day and date appear below, // Define the I/O pin const int LightingRelay = 23; starting at row 1, column 4. The prototype layout for the network-synchronised clock is Thereafter, we will be able to control the lighting within a shown in the photo below, while the code for the ESP32 NTP conditional statement using the function call: clock is shown in Listing 7.4. 74 Practical Electronics | September | 2024 Fig.7.5: How we have chosen to display the time and date in the available space on the LCD. Fig.7.4: Characters on the 16×2 LCD are identified by row and column numbers. digitalWrite(LightingRelay, HIGH) ... to turn the lighting ‘on’, and ... digitalWrite(LightingRelay, LOW) ... to turn the lighting ‘off’. We will leave the conditional statements to you. Next month Next month, we will be showing you how to add a low-cost GPS module to your ESP32. This will allow you to use your ESP32 with an inexpensive LCD panel to obtain and display accurate time, location, altitude and speed data. One important advantage of GPS time over NTP is that it wil work just about anywhere and does not need Internet access. Coding Workshop will provide you with some pointers to help you develop code to be used with GPS/GNSS (Global Navigation Satellite System) modules and our Practical Project PE will feature a simple GPS/GNSS location fixer. Listing 7.4 – Code for the ESP32 NTP clock /* Simple ESP32 clock using a 16 x 2 LCD display and time data obtained from an NTP server. */ // Include the required library files #include <WiFi.h> #include "time.h" #include <LiquidCrystal_I2C.h> // Define the LCD parameters int lcdColumns = 16; int lcdRows = 2; // Setup the LCD LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows); // Network parameters const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASSWORD"; const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 0; const int daylightOffset_sec = 3600; void setup() { // Initialise the LCD lcd.init(); // Turn the backlight on lcd.backlight(); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } // Initialise and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); printLocalTime(); Fig.7.6: This circuit is the same as Fig.7.3 except now we have introduced a relay module controlled by the ESP32. // Disconnect WiFi WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } void loop() { delay(1000); printLocalTime(); } void printLocalTime() { struct tm timeinfo; // Warn if time is not found if (!getLocalTime(&timeinfo)) { lcd.setCursor(0, 0); // First row lcd.print("Time not found!"); lcd.setCursor(0, 1); // Second row lcd.print("Check router?"); return; } // Send the time info to the LCD lcd.setCursor(4, 0); // First row lcd.print(&timeinfo, "%H:%M:%S"); lcd.setCursor(4, 1); // Second row lcd.print(&timeinfo, "%A %d"); } Fig.7.7: the relay module requires just three extra wires. Practical Electronics | September | 2024 75