Communication driver for reading and writing data from Rockwell Automation ControlLogix, CompactLogix, and Micro8xx PLCs over Ethernet I/P
—
Functions for reading and setting the PLC's internal clock, enabling time synchronization between PLCs and host systems. These operations are essential for applications requiring accurate timestamps, scheduled operations, and time-based process control.
Retrieve the current time from the PLC's internal clock with options for different time formats.
def GetPLCTime(raw=False):
"""
Get the PLC's current time.
Args:
raw (bool): If True, return raw microseconds since Unix epoch.
If False, return formatted datetime object (default).
Returns:
Response: Object containing the PLC time in Value field
- Value: datetime object (raw=False) or int microseconds (raw=True)
- Status: "Success" or error description
"""Usage Examples:
from pylogix import PLC
with PLC() as comm:
comm.IPAddress = '192.168.1.100'
# Get PLC time as datetime object
response = comm.GetPLCTime()
if response.Status == 'Success':
plc_time = response.Value
print(f"PLC Time: {plc_time}")
print(f"Formatted: {plc_time.strftime('%Y-%m-%d %H:%M:%S')}")
# Get raw time as microseconds since Unix epoch
response = comm.GetPLCTime(raw=True)
if response.Status == 'Success':
microseconds = response.Value
print(f"Raw PLC Time: {microseconds} microseconds")
# Convert to seconds for comparison
seconds = microseconds / 1_000_000
print(f"Seconds since epoch: {seconds}")Time Format Details:
The PLC time is stored internally as microseconds since the Unix epoch (January 1, 1970, 00:00:00 UTC). When raw=False (default), PyLogix converts this to a Python datetime object for easier handling.
# Working with datetime objects
response = comm.GetPLCTime()
if response.Status == 'Success':
plc_time = response.Value
# Extract time components
year = plc_time.year
month = plc_time.month
day = plc_time.day
hour = plc_time.hour
minute = plc_time.minute
second = plc_time.second
microsecond = plc_time.microsecond
# Compare with system time
import datetime
system_time = datetime.datetime.now()
time_diff = abs((plc_time - system_time).total_seconds())
print(f"Time difference: {time_diff:.2f} seconds")Set the PLC's internal clock to synchronize with the host system or a specific time.
def SetPLCTime(dst=None):
"""
Set the PLC's clock to the current system time.
Args:
dst (bool, optional): Daylight Saving Time flag
- True: DST is active
- False: Standard time
- None: Use system DST setting (default)
Returns:
Response: Object indicating success or failure
- Value: Timestamp that was set (in microseconds)
- Status: "Success" or error description
"""Usage Examples:
with PLC() as comm:
comm.IPAddress = '192.168.1.100'
# Set PLC time to current system time with automatic DST detection
response = comm.SetPLCTime()
if response.Status == 'Success':
set_time = response.Value
print(f"PLC time synchronized successfully")
print(f"Set time: {set_time} microseconds")
else:
print(f"Failed to set PLC time: {response.Status}")
# Explicitly set DST flag
response = comm.SetPLCTime(dst=True) # Force DST active
response = comm.SetPLCTime(dst=False) # Force standard timeTime Synchronization Workflow:
def synchronize_plc_time(plc_ip):
"""Complete time synchronization workflow with validation."""
with PLC() as comm:
comm.IPAddress = plc_ip
# Get current PLC time
before_response = comm.GetPLCTime()
if before_response.Status != 'Success':
print(f"Cannot read PLC time: {before_response.Status}")
return False
plc_time_before = before_response.Value
print(f"PLC time before sync: {plc_time_before}")
# Set PLC time to system time
set_response = comm.SetPLCTime()
if set_response.Status != 'Success':
print(f"Failed to set PLC time: {set_response.Status}")
return False
print("Time synchronization command sent successfully")
# Verify the new time
import time
time.sleep(1) # Wait for PLC to process the time change
after_response = comm.GetPLCTime()
if after_response.Status == 'Success':
plc_time_after = after_response.Value
print(f"PLC time after sync: {plc_time_after}")
# Calculate synchronization accuracy
import datetime
system_time = datetime.datetime.now()
sync_error = abs((plc_time_after - system_time).total_seconds())
print(f"Synchronization accuracy: ±{sync_error:.3f} seconds")
return sync_error < 2.0 # Consider sync successful if within 2 seconds
return False
# Usage
success = synchronize_plc_time('192.168.1.100')Understanding how PyLogix handles time zones and daylight saving time is important for accurate time operations.
DST Handling:
import time
# Check current system DST status
dst_active = time.localtime().tm_isdst == 1
print(f"System DST active: {dst_active}")
# Set PLC time with explicit DST control
with PLC() as comm:
comm.IPAddress = '192.168.1.100'
if dst_active:
response = comm.SetPLCTime(dst=True)
print("PLC time set with DST active")
else:
response = comm.SetPLCTime(dst=False)
print("PLC time set with standard time")Time Zone Considerations:
PyLogix works with the local system time. For applications spanning multiple time zones, consider converting to UTC:
import datetime
def set_plc_time_utc(plc_ip):
"""Set PLC time to UTC regardless of system timezone."""
with PLC() as comm:
comm.IPAddress = plc_ip
# Get current UTC time
utc_now = datetime.datetime.utcnow()
print(f"Setting PLC to UTC time: {utc_now}")
# Note: SetPLCTime() uses system time, so this approach
# requires manual timestamp manipulation for UTC
response = comm.SetPLCTime(dst=False) # UTC doesn't use DST
return response.Status == 'Success'For applications requiring continuous time accuracy, implement periodic synchronization:
import threading
import time as time_module
class PLCTimeSynchronizer:
"""Automatic PLC time synchronization service."""
def __init__(self, plc_ip, sync_interval=3600): # Default: sync every hour
self.plc_ip = plc_ip
self.sync_interval = sync_interval
self.running = False
self.thread = None
def start(self):
"""Start the synchronization service."""
self.running = True
self.thread = threading.Thread(target=self._sync_loop)
self.thread.daemon = True
self.thread.start()
print(f"PLC time sync started for {self.plc_ip} (interval: {self.sync_interval}s)")
def stop(self):
"""Stop the synchronization service."""
self.running = False
if self.thread:
self.thread.join()
print("PLC time synchronization stopped")
def _sync_loop(self):
"""Main synchronization loop."""
while self.running:
try:
with PLC() as comm:
comm.IPAddress = self.plc_ip
response = comm.SetPLCTime()
if response.Status == 'Success':
print(f"PLC {self.plc_ip} time synchronized")
else:
print(f"Sync failed for {self.plc_ip}: {response.Status}")
except Exception as e:
print(f"Sync error for {self.plc_ip}: {e}")
# Wait for next sync interval
for _ in range(self.sync_interval):
if not self.running:
break
time_module.sleep(1)
# Usage example
synchronizer = PLCTimeSynchronizer('192.168.1.100', sync_interval=1800) # 30 minutes
synchronizer.start()
# Later...
# synchronizer.stop()Time operations can fail for various reasons. Implement robust error handling:
def robust_time_sync(plc_ip, max_retries=3, retry_delay=5):
"""Robust time synchronization with retry logic."""
for attempt in range(max_retries):
try:
with PLC() as comm:
comm.IPAddress = plc_ip
comm.SocketTimeout = 10.0 # Longer timeout for time operations
# Try to set time
response = comm.SetPLCTime()
if response.Status == 'Success':
print(f"Time sync successful on attempt {attempt + 1}")
return True
else:
print(f"Attempt {attempt + 1} failed: {response.Status}")
except Exception as e:
print(f"Exception on attempt {attempt + 1}: {e}")
if attempt < max_retries - 1:
print(f"Retrying in {retry_delay} seconds...")
time_module.sleep(retry_delay)
print(f"Failed to sync time after {max_retries} attempts")
return False
# Usage
success = robust_time_sync('192.168.1.100')When using PyLogix on MicroPython, time operations have some limitations:
# On MicroPython, always use raw=True for GetPLCTime
response = comm.GetPLCTime(raw=True)
if response.Status == 'Success':
# MicroPython doesn't have datetime module
# Work with raw microseconds
microseconds = response.Value
seconds = microseconds // 1_000_000
print(f"PLC time in seconds: {seconds}")Install with Tessl CLI
npx tessl i tessl/pypi-pylogix