0
# Listeners and Events
1
2
Real-time notification system for NetworkTable changes including entry modifications, connection status, and table updates. Essential for responsive robotics applications that need to react immediately to data changes.
3
4
## Capabilities
5
6
### Entry Listeners
7
8
Listen for changes to NetworkTable entries at various scopes.
9
10
```python { .api }
11
def addEntryListener(listener: Callable, immediateNotify: bool = True, localNotify: bool = True):
12
"""
13
Add a global entry listener for all NetworkTable changes.
14
15
Parameters:
16
- listener: Callable. Function called on entry changes with signature:
17
listener(key, value, isNew) or listener(entry, key, value, isNew)
18
- immediateNotify: bool. Call listener immediately with current values
19
- localNotify: bool. Whether to notify on local changes
20
21
Returns:
22
int: Listener ID for removal
23
"""
24
25
def removeEntryListener(listener):
26
"""
27
Remove an entry listener.
28
29
Parameters:
30
- listener: Callable or int. Listener function or ID to remove
31
"""
32
```
33
34
### Connection Listeners
35
36
Listen for NetworkTables connection status changes.
37
38
```python { .api }
39
def addConnectionListener(listener: Callable, immediateNotify: bool = False):
40
"""
41
Add a connection status listener.
42
43
Parameters:
44
- listener: Callable. Function called on connection changes with signature:
45
listener(connected, info) where:
46
- connected: bool, current connection status
47
- info: dict, connection information
48
- immediateNotify: bool. Call listener immediately with current status
49
50
Returns:
51
int: Listener ID for removal
52
"""
53
54
def removeConnectionListener(listener):
55
"""
56
Remove a connection listener.
57
58
Parameters:
59
- listener: Callable or int. Listener function or ID to remove
60
"""
61
```
62
63
### Table-Level Entry Listeners
64
65
Add listeners to specific tables for scoped notifications.
66
67
```python { .api }
68
class NetworkTable:
69
def addEntryListener(listener: Callable, immediateNotify: bool = False,
70
key: str = None, localNotify: bool = False):
71
"""
72
Add an entry listener for this table.
73
74
Parameters:
75
- listener: Callable. Function called on entry changes
76
- immediateNotify: bool. Call listener immediately with current values
77
- key: str, optional. Specific key to watch (None for all keys in table)
78
- localNotify: bool. Whether to notify on local changes
79
"""
80
81
def addEntryListenerEx(listener: Callable, flags: int, key: str = None,
82
paramIsNew: bool = True):
83
"""
84
Add an entry listener with extended options.
85
86
Parameters:
87
- listener: Callable. Function called on entry changes
88
- flags: int. Bitmask of notification flags
89
- key: str, optional. Specific key to watch
90
- paramIsNew: bool. Whether to pass isNew parameter to listener
91
"""
92
93
def removeEntryListener(listener):
94
"""
95
Remove an entry listener from this table.
96
97
Parameters:
98
- listener: Callable. Previously added listener function
99
"""
100
101
def addSubTableListener(listener: Callable, localNotify: bool = False):
102
"""
103
Add a listener for subtable creation/deletion.
104
105
Parameters:
106
- listener: Callable. Function called when subtables change
107
- localNotify: bool. Whether to notify on local changes
108
"""
109
```
110
111
### Entry-Level Listeners
112
113
Add listeners to specific entries for maximum efficiency.
114
115
```python { .api }
116
class NetworkTableEntry:
117
def addListener(listener: Callable, flags: int, paramIsNew: bool = True) -> int:
118
"""
119
Add a listener for changes to this specific entry.
120
121
Parameters:
122
- listener: Callable. Function called when entry changes with signature:
123
listener(entry, value, isNew) if paramIsNew=True
124
listener(entry, value) if paramIsNew=False
125
- flags: int. Bitmask of notification flags
126
- paramIsNew: bool. Whether to pass isNew parameter to listener
127
128
Returns:
129
int: Listener ID for removal
130
"""
131
132
def removeListener(listener_id: int):
133
"""
134
Remove a listener by ID.
135
136
Parameters:
137
- listener_id: int. ID returned from addListener
138
"""
139
```
140
141
## Notification Flags
142
143
Control when listeners are called with notification flag constants.
144
145
```python { .api }
146
# Notification timing flags
147
NT_NOTIFY_IMMEDIATE = 0x01 # Notify immediately with current values
148
NT_NOTIFY_LOCAL = 0x02 # Notify on local changes
149
150
# Notification event flags
151
NT_NOTIFY_NEW = 0x04 # Notify when entries are created
152
NT_NOTIFY_DELETE = 0x08 # Notify when entries are deleted
153
NT_NOTIFY_UPDATE = 0x10 # Notify when entry values change
154
NT_NOTIFY_FLAGS = 0x20 # Notify when entry flags change
155
156
# Common combinations
157
NOTIFY_ALL = NT_NOTIFY_NEW | NT_NOTIFY_DELETE | NT_NOTIFY_UPDATE | NT_NOTIFY_FLAGS
158
NOTIFY_CHANGES = NT_NOTIFY_UPDATE | NT_NOTIFY_FLAGS
159
```
160
161
## Usage Examples
162
163
### Global Entry Listener
164
165
```python
166
from networktables import NetworkTables
167
168
def on_entry_change(key, value, isNew):
169
"""Called whenever any NetworkTable entry changes."""
170
status = "NEW" if isNew else "UPDATED"
171
print(f"Entry {status}: {key} = {value}")
172
173
# Add global listener
174
NetworkTables.addEntryListener(on_entry_change, immediateNotify=True)
175
176
# The listener will be called for all entry changes across all tables
177
```
178
179
### Connection Status Monitoring
180
181
```python
182
from networktables import NetworkTables
183
184
def on_connection_change(connected, info):
185
"""Called when connection status changes."""
186
if connected:
187
print(f"Connected to {info.get('remote_ip', 'unknown')}")
188
else:
189
print("Disconnected from NetworkTables")
190
191
# Monitor connection status
192
NetworkTables.addConnectionListener(on_connection_change, immediateNotify=True)
193
194
# Start client connection
195
NetworkTables.initialize(server='roborio-1234-frc.local')
196
```
197
198
### Table-Specific Listeners
199
200
```python
201
from networktables import NetworkTables
202
203
def on_smartdashboard_change(key, value, isNew):
204
"""Called when SmartDashboard entries change."""
205
print(f"SmartDashboard update: {key} = {value}")
206
207
def on_vision_target_change(key, value, isNew):
208
"""Called only when vision target data changes."""
209
print(f"Vision target updated: {value}")
210
211
# Listen to entire SmartDashboard table
212
sd = NetworkTables.getTable('SmartDashboard')
213
sd.addEntryListener(on_smartdashboard_change)
214
215
# Listen to specific key in Vision table
216
vision = NetworkTables.getTable('Vision')
217
vision.addEntryListener(on_vision_target_change, key='targetDistance')
218
```
219
220
### Entry-Specific Listeners
221
222
```python
223
from networktables import NetworkTables
224
225
def on_speed_change(entry, value, isNew):
226
"""Called when drive speed changes."""
227
print(f"Drive speed: {value} m/s")
228
229
# Validate speed limits
230
if value > 5.0:
231
print("WARNING: Speed exceeds safe limit!")
232
233
# Listen to specific entry for maximum efficiency
234
speed_entry = NetworkTables.getEntry('/SmartDashboard/driveSpeed')
235
listener_id = speed_entry.addListener(
236
on_speed_change,
237
NetworkTables.NotifyFlags.UPDATE | NetworkTables.NotifyFlags.NEW
238
)
239
240
# Remove listener when done
241
speed_entry.removeListener(listener_id)
242
```
243
244
### Advanced Listener Configuration
245
246
```python
247
from networktables import NetworkTables
248
249
def robot_state_listener(key, value, isNew):
250
"""Monitor critical robot state changes."""
251
print(f"Robot state change: {key} = {value}")
252
253
def config_listener(key, value, isNew):
254
"""Monitor configuration changes that should persist."""
255
print(f"Config updated: {key} = {value}")
256
# Could trigger config save here
257
258
# Listen only to new entries and updates, not flag changes
259
flags = NetworkTables.NotifyFlags.NEW | NetworkTables.NotifyFlags.UPDATE
260
261
robot_table = NetworkTables.getTable('Robot')
262
robot_table.addEntryListenerEx(robot_state_listener, flags)
263
264
# Listen to configuration with immediate notification
265
config_table = NetworkTables.getTable('Config')
266
config_table.addEntryListenerEx(
267
config_listener,
268
flags | NetworkTables.NotifyFlags.IMMEDIATE
269
)
270
```
271
272
### Subtable Monitoring
273
274
```python
275
from networktables import NetworkTables
276
277
def on_camera_added(table, key, subtable, isNew):
278
"""Called when new camera subtables are created."""
279
if isNew:
280
print(f"New camera detected: {key}")
281
# Could set up camera-specific listeners here
282
283
vision_table = NetworkTables.getTable('Vision')
284
vision_table.addSubTableListener(on_camera_added)
285
```
286
287
### Listener Cleanup Patterns
288
289
```python
290
from networktables import NetworkTables
291
292
class RobotDataMonitor:
293
def __init__(self):
294
self.listeners = []
295
296
def start_monitoring(self):
297
"""Start all listeners and track them for cleanup."""
298
# Connection monitoring
299
conn_listener = NetworkTables.addConnectionListener(self.on_connection)
300
self.listeners.append(('connection', conn_listener))
301
302
# Entry monitoring
303
entry_listener = NetworkTables.addEntryListener(self.on_entry_change)
304
self.listeners.append(('entry', entry_listener))
305
306
# Specific entry monitoring
307
speed_entry = NetworkTables.getEntry('/SmartDashboard/speed')
308
speed_listener = speed_entry.addListener(
309
self.on_speed_change,
310
NetworkTables.NotifyFlags.UPDATE
311
)
312
self.listeners.append(('speed_entry', speed_entry, speed_listener))
313
314
def stop_monitoring(self):
315
"""Clean up all listeners."""
316
for listener_info in self.listeners:
317
if listener_info[0] == 'connection':
318
NetworkTables.removeConnectionListener(listener_info[1])
319
elif listener_info[0] == 'entry':
320
NetworkTables.removeEntryListener(listener_info[1])
321
elif listener_info[0] == 'speed_entry':
322
entry, listener_id = listener_info[1], listener_info[2]
323
entry.removeListener(listener_id)
324
325
self.listeners.clear()
326
327
def on_connection(self, connected, info):
328
print(f"Connection: {connected}")
329
330
def on_entry_change(self, key, value, isNew):
331
print(f"Entry: {key} = {value}")
332
333
def on_speed_change(self, entry, value, isNew):
334
print(f"Speed: {value}")
335
336
# Usage
337
monitor = RobotDataMonitor()
338
monitor.start_monitoring()
339
340
# Later cleanup
341
monitor.stop_monitoring()
342
```
343
344
## Error Handling
345
346
```python
347
from networktables import NetworkTables
348
349
def safe_listener(key, value, isNew):
350
"""Listener with error handling to prevent crashes."""
351
try:
352
# Process the change
353
process_value_change(key, value)
354
except Exception as e:
355
print(f"Error processing {key}: {e}")
356
# Continue execution despite errors
357
358
def process_value_change(key, value):
359
"""Your actual processing logic here."""
360
pass
361
362
# Add listener with error handling
363
NetworkTables.addEntryListener(safe_listener)
364
```
365
366
## Listener Performance Tips
367
368
1. **Use specific listeners**: Entry-level listeners are more efficient than global listeners
369
2. **Filter notifications**: Use notification flags to only receive relevant events
370
3. **Avoid heavy processing**: Keep listener functions lightweight to avoid blocking
371
4. **Handle errors**: Always include error handling to prevent listener crashes
372
5. **Clean up listeners**: Remove listeners when no longer needed to prevent memory leaks