Skip to content

Commit

Permalink
Feat(Time Sync): Make time sync optional
Browse files Browse the repository at this point in the history
Makes time synchronisation optional by providing a class instantiation property.
Use the `time_sync` boolean property to configure time synchronisation.
  • Loading branch information
CodeGoat-dev committed Jan 26, 2025
1 parent 130b1f0 commit aad6545
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 33 deletions.
6 changes: 5 additions & 1 deletion changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ This document outlines the changes made between versions of the **Goat - Pico Ne

### New Features

#### Instantiation

When instantiating the `NetworkManager` class, you can now specify a `time_sync` Boolean property to enable/disable time synchronisation.

#### Date And Time Synchronisation

When connected to a wireless network, the system date and time is now synchronised from a well known NTP time provider. The **World Time API** is used for date and time retrieval.
When connected to a wireless network, the system date and time can now be synchronised from a well known NTP time provider. The **World Time API** is used for date and time retrieval.

### Bug Fixes

Expand Down
7 changes: 6 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Pico Network Manager comes packed with the following features:
Configure a web interface for your firmware to be used when connected to a network.

- **Time Synchronisation**
Automatic time synchronisation from World Time API when connected to wi-fi.
Enable automatic time synchronisation from World Time API when connected to wi-fi.

---

Expand Down Expand Up @@ -122,6 +122,7 @@ The library is easy to integrate into your existing project.
ap_password="MyPassword",
ap_dns_server=True,
hostname="MyPicoW",
time_sync=True,
sta_web_server=web_server
)
```
Expand All @@ -137,6 +138,7 @@ The library is easy to integrate into your existing project.
ap_password="MyPassword",
ap_dns_server=True,
hostname="MyPicoW",
time_sync=True,
sta_web_server=web_server
)

Expand All @@ -155,6 +157,9 @@ The library is easy to integrate into your existing project.

# DHCP settings
network_manager.hostname = "PicoW"

# Time synchronisation
network_manager.time_sync = time_sync
```
- Your optional web server must implement `run()` and `stop_server()` methods which the Network Manager will use.

Expand Down
69 changes: 38 additions & 31 deletions src/NetworkManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class NetworkManager:
Responsible for maintaining network state and managing connection lifetime.
"""
# Class constructor
def __init__(self, ap_ssid="Goat - Captive Portal", ap_password="password", ap_dns_server=True, hostname="PicoW", sta_web_server=None):
def __init__(self, ap_ssid="Goat - Captive Portal", ap_password="password", ap_dns_server=True, hostname="PicoW", time_sync=True, sta_web_server=None):
"""Constructs the class and exposes properties."""
# Network configuration
self.config_directory = "/config"
Expand Down Expand Up @@ -60,6 +60,9 @@ def __init__(self, ap_ssid="Goat - Captive Portal", ap_password="password", ap_d
# Captive portal DNS server
self.dns_server = NetworkManagerDNS(portal_ip=self.ap_ip_address)

# Time synchronisation
self.time_sync = time_sync

# STA web server configuration
self.sta_web_server = sta_web_server

Expand Down Expand Up @@ -91,8 +94,10 @@ async def load_config(self):
if self.sta_if.isconnected():
self.ip_address = self.sta_if.ifconfig()[0]
print(f"Connected to {ssid}. IP: {self.ip_address}")
# Set system date/time
try:
await self.get_ntp_time()
if self.time_sync:
await self.get_ntp_time()
except Exception as e:
print(f"Unable to set the system date and time: {e}")
if self.sta_web_server:
Expand Down Expand Up @@ -170,6 +175,33 @@ async def stop_ap(self):
except Exception as e:
print(f"Error stopping Access point: {e}")

async def start_captive_portal_server(self):
"""Starts the captive portal HTTP server asynchronously."""
if not self.ip_address:
print("AP IP address not assigned. Cannot start server.")
return

try:
self.server = await asyncio.start_server(self.handle_request, self.ip_address, self.captive_portal_http_port)
print(f"Serving on {self.ip_address}:{self.captive_portal_http_port}")

while True:
await asyncio.sleep(1) # Keep the server running
except Exception as e:
print(f"Error starting the captive portal server: {e}")

async def stop_captive_portal_server(self):
"""Stops the captive portal HTTP server."""
try:
if self.server:
self.server.close()
await self.server.wait_closed()
print("Server stopped.")
else:
print("Server already stopped.")
except Exception as e:
print(f"Error stopping server: {e}")

async def handle_request(self, reader, writer):
"""Handles incoming HTTP requests for the captive portal."""
try:
Expand Down Expand Up @@ -316,7 +348,8 @@ async def connect_to_wifi(self, request):

# Set system date/time
try:
await self.get_ntp_time()
if self.time_sync:
await self.get_ntp_time()
except Exception as e:
print(f"Unable to set the system date and time: {e}")

Expand Down Expand Up @@ -364,7 +397,8 @@ async def reconnect_to_wifi(self, request):

# Set system date/time
try:
await self.get_ntp_time()
if self.time_sync:
await self.get_ntp_time()
except Exception as e:
print(f"Unable to set the system date and time: {e}")

Expand Down Expand Up @@ -406,33 +440,6 @@ def serve_index(self):
<p><a href='/scan'>Start Scan</a></p>"""
return self.html_template("Goat - Captive Portal", body)

async def start_captive_portal_server(self):
"""Starts the captive portal HTTP server asynchronously."""
if not self.ip_address:
print("AP IP address not assigned. Cannot start server.")
return

try:
self.server = await asyncio.start_server(self.handle_request, self.ip_address, self.captive_portal_http_port)
print(f"Serving on {self.ip_address}:{self.captive_portal_http_port}")

while True:
await asyncio.sleep(1) # Keep the server running
except Exception as e:
print(f"Error starting the captive portal server: {e}")

async def stop_captive_portal_server(self):
"""Stops the captive portal HTTP server."""
try:
if self.server:
self.server.close()
await self.server.wait_closed()
print("Server stopped.")
else:
print("Server already stopped.")
except Exception as e:
print(f"Error stopping server: {e}")

async def get_ntp_time(self):
"""Fetches the current date and time from an NTP server or time API and sets the system time."""
url = "http://worldtimeapi.org/api/ip"
Expand Down

0 comments on commit aad6545

Please sign in to comment.