CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pylogix

Communication driver for reading and writing data from Rockwell Automation ControlLogix, CompactLogix, and Micro8xx PLCs over Ethernet I/P

Pending
Overview
Eval results
Files

time-operations.mddocs/

PLC Time Management

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.

Capabilities

Reading PLC Time

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")

Setting PLC Time

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 time

Time 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')

Time Zone and DST Considerations

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'

Periodic Time Synchronization

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()

Error Handling for Time Operations

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')

MicroPython Considerations

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

docs

advanced-messaging.md

core-operations.md

device-discovery.md

index.md

tag-discovery.md

time-operations.md

tile.json