0
# PLC Time Management
1
2
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.
3
4
## Capabilities
5
6
### Reading PLC Time
7
8
Retrieve the current time from the PLC's internal clock with options for different time formats.
9
10
```python { .api }
11
def GetPLCTime(raw=False):
12
"""
13
Get the PLC's current time.
14
15
Args:
16
raw (bool): If True, return raw microseconds since Unix epoch.
17
If False, return formatted datetime object (default).
18
19
Returns:
20
Response: Object containing the PLC time in Value field
21
- Value: datetime object (raw=False) or int microseconds (raw=True)
22
- Status: "Success" or error description
23
"""
24
```
25
26
**Usage Examples:**
27
28
```python
29
from pylogix import PLC
30
31
with PLC() as comm:
32
comm.IPAddress = '192.168.1.100'
33
34
# Get PLC time as datetime object
35
response = comm.GetPLCTime()
36
if response.Status == 'Success':
37
plc_time = response.Value
38
print(f"PLC Time: {plc_time}")
39
print(f"Formatted: {plc_time.strftime('%Y-%m-%d %H:%M:%S')}")
40
41
# Get raw time as microseconds since Unix epoch
42
response = comm.GetPLCTime(raw=True)
43
if response.Status == 'Success':
44
microseconds = response.Value
45
print(f"Raw PLC Time: {microseconds} microseconds")
46
47
# Convert to seconds for comparison
48
seconds = microseconds / 1_000_000
49
print(f"Seconds since epoch: {seconds}")
50
```
51
52
**Time Format Details:**
53
54
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.
55
56
```python
57
# Working with datetime objects
58
response = comm.GetPLCTime()
59
if response.Status == 'Success':
60
plc_time = response.Value
61
62
# Extract time components
63
year = plc_time.year
64
month = plc_time.month
65
day = plc_time.day
66
hour = plc_time.hour
67
minute = plc_time.minute
68
second = plc_time.second
69
microsecond = plc_time.microsecond
70
71
# Compare with system time
72
import datetime
73
system_time = datetime.datetime.now()
74
time_diff = abs((plc_time - system_time).total_seconds())
75
print(f"Time difference: {time_diff:.2f} seconds")
76
```
77
78
### Setting PLC Time
79
80
Set the PLC's internal clock to synchronize with the host system or a specific time.
81
82
```python { .api }
83
def SetPLCTime(dst=None):
84
"""
85
Set the PLC's clock to the current system time.
86
87
Args:
88
dst (bool, optional): Daylight Saving Time flag
89
- True: DST is active
90
- False: Standard time
91
- None: Use system DST setting (default)
92
93
Returns:
94
Response: Object indicating success or failure
95
- Value: Timestamp that was set (in microseconds)
96
- Status: "Success" or error description
97
"""
98
```
99
100
**Usage Examples:**
101
102
```python
103
with PLC() as comm:
104
comm.IPAddress = '192.168.1.100'
105
106
# Set PLC time to current system time with automatic DST detection
107
response = comm.SetPLCTime()
108
if response.Status == 'Success':
109
set_time = response.Value
110
print(f"PLC time synchronized successfully")
111
print(f"Set time: {set_time} microseconds")
112
else:
113
print(f"Failed to set PLC time: {response.Status}")
114
115
# Explicitly set DST flag
116
response = comm.SetPLCTime(dst=True) # Force DST active
117
response = comm.SetPLCTime(dst=False) # Force standard time
118
```
119
120
**Time Synchronization Workflow:**
121
122
```python
123
def synchronize_plc_time(plc_ip):
124
"""Complete time synchronization workflow with validation."""
125
with PLC() as comm:
126
comm.IPAddress = plc_ip
127
128
# Get current PLC time
129
before_response = comm.GetPLCTime()
130
if before_response.Status != 'Success':
131
print(f"Cannot read PLC time: {before_response.Status}")
132
return False
133
134
plc_time_before = before_response.Value
135
print(f"PLC time before sync: {plc_time_before}")
136
137
# Set PLC time to system time
138
set_response = comm.SetPLCTime()
139
if set_response.Status != 'Success':
140
print(f"Failed to set PLC time: {set_response.Status}")
141
return False
142
143
print("Time synchronization command sent successfully")
144
145
# Verify the new time
146
import time
147
time.sleep(1) # Wait for PLC to process the time change
148
149
after_response = comm.GetPLCTime()
150
if after_response.Status == 'Success':
151
plc_time_after = after_response.Value
152
print(f"PLC time after sync: {plc_time_after}")
153
154
# Calculate synchronization accuracy
155
import datetime
156
system_time = datetime.datetime.now()
157
sync_error = abs((plc_time_after - system_time).total_seconds())
158
print(f"Synchronization accuracy: ±{sync_error:.3f} seconds")
159
160
return sync_error < 2.0 # Consider sync successful if within 2 seconds
161
162
return False
163
164
# Usage
165
success = synchronize_plc_time('192.168.1.100')
166
```
167
168
### Time Zone and DST Considerations
169
170
Understanding how PyLogix handles time zones and daylight saving time is important for accurate time operations.
171
172
**DST Handling:**
173
174
```python
175
import time
176
177
# Check current system DST status
178
dst_active = time.localtime().tm_isdst == 1
179
print(f"System DST active: {dst_active}")
180
181
# Set PLC time with explicit DST control
182
with PLC() as comm:
183
comm.IPAddress = '192.168.1.100'
184
185
if dst_active:
186
response = comm.SetPLCTime(dst=True)
187
print("PLC time set with DST active")
188
else:
189
response = comm.SetPLCTime(dst=False)
190
print("PLC time set with standard time")
191
```
192
193
**Time Zone Considerations:**
194
195
PyLogix works with the local system time. For applications spanning multiple time zones, consider converting to UTC:
196
197
```python
198
import datetime
199
200
def set_plc_time_utc(plc_ip):
201
"""Set PLC time to UTC regardless of system timezone."""
202
with PLC() as comm:
203
comm.IPAddress = plc_ip
204
205
# Get current UTC time
206
utc_now = datetime.datetime.utcnow()
207
print(f"Setting PLC to UTC time: {utc_now}")
208
209
# Note: SetPLCTime() uses system time, so this approach
210
# requires manual timestamp manipulation for UTC
211
response = comm.SetPLCTime(dst=False) # UTC doesn't use DST
212
213
return response.Status == 'Success'
214
```
215
216
### Periodic Time Synchronization
217
218
For applications requiring continuous time accuracy, implement periodic synchronization:
219
220
```python
221
import threading
222
import time as time_module
223
224
class PLCTimeSynchronizer:
225
"""Automatic PLC time synchronization service."""
226
227
def __init__(self, plc_ip, sync_interval=3600): # Default: sync every hour
228
self.plc_ip = plc_ip
229
self.sync_interval = sync_interval
230
self.running = False
231
self.thread = None
232
233
def start(self):
234
"""Start the synchronization service."""
235
self.running = True
236
self.thread = threading.Thread(target=self._sync_loop)
237
self.thread.daemon = True
238
self.thread.start()
239
print(f"PLC time sync started for {self.plc_ip} (interval: {self.sync_interval}s)")
240
241
def stop(self):
242
"""Stop the synchronization service."""
243
self.running = False
244
if self.thread:
245
self.thread.join()
246
print("PLC time synchronization stopped")
247
248
def _sync_loop(self):
249
"""Main synchronization loop."""
250
while self.running:
251
try:
252
with PLC() as comm:
253
comm.IPAddress = self.plc_ip
254
response = comm.SetPLCTime()
255
256
if response.Status == 'Success':
257
print(f"PLC {self.plc_ip} time synchronized")
258
else:
259
print(f"Sync failed for {self.plc_ip}: {response.Status}")
260
261
except Exception as e:
262
print(f"Sync error for {self.plc_ip}: {e}")
263
264
# Wait for next sync interval
265
for _ in range(self.sync_interval):
266
if not self.running:
267
break
268
time_module.sleep(1)
269
270
# Usage example
271
synchronizer = PLCTimeSynchronizer('192.168.1.100', sync_interval=1800) # 30 minutes
272
synchronizer.start()
273
274
# Later...
275
# synchronizer.stop()
276
```
277
278
### Error Handling for Time Operations
279
280
Time operations can fail for various reasons. Implement robust error handling:
281
282
```python
283
def robust_time_sync(plc_ip, max_retries=3, retry_delay=5):
284
"""Robust time synchronization with retry logic."""
285
286
for attempt in range(max_retries):
287
try:
288
with PLC() as comm:
289
comm.IPAddress = plc_ip
290
comm.SocketTimeout = 10.0 # Longer timeout for time operations
291
292
# Try to set time
293
response = comm.SetPLCTime()
294
295
if response.Status == 'Success':
296
print(f"Time sync successful on attempt {attempt + 1}")
297
return True
298
else:
299
print(f"Attempt {attempt + 1} failed: {response.Status}")
300
301
except Exception as e:
302
print(f"Exception on attempt {attempt + 1}: {e}")
303
304
if attempt < max_retries - 1:
305
print(f"Retrying in {retry_delay} seconds...")
306
time_module.sleep(retry_delay)
307
308
print(f"Failed to sync time after {max_retries} attempts")
309
return False
310
311
# Usage
312
success = robust_time_sync('192.168.1.100')
313
```
314
315
### MicroPython Considerations
316
317
When using PyLogix on MicroPython, time operations have some limitations:
318
319
```python
320
# On MicroPython, always use raw=True for GetPLCTime
321
response = comm.GetPLCTime(raw=True)
322
if response.Status == 'Success':
323
# MicroPython doesn't have datetime module
324
# Work with raw microseconds
325
microseconds = response.Value
326
seconds = microseconds // 1_000_000
327
print(f"PLC time in seconds: {seconds}")
328
```