0
# Monitoring
1
2
Event-driven monitoring system for detecting card insertion/removal and reader connection/disconnection using the observer pattern. This enables applications to respond automatically to smart card and reader events.
3
4
## Capabilities
5
6
### Card Monitoring
7
8
CardMonitoring provides automatic detection of card insertion and removal events across all available readers.
9
10
```python { .api }
11
class CardObserver:
12
def update(self, observable, handlers):
13
"""
14
Called when card insertion or removal events occur.
15
16
Args:
17
observable (CardMonitor): The card monitor that detected the event
18
handlers (tuple): (added_cards, removed_cards) where:
19
- added_cards (list[Card]): Cards that were inserted
20
- removed_cards (list[Card]): Cards that were removed
21
"""
22
23
class CardMonitor:
24
"""
25
Singleton monitor for card insertion and removal events.
26
Automatically monitors all available readers.
27
"""
28
29
def addObserver(self, observer):
30
"""
31
Add an observer to receive card events.
32
33
Args:
34
observer (CardObserver): Observer to add
35
"""
36
37
def deleteObserver(self, observer):
38
"""
39
Remove an observer from receiving card events.
40
41
Args:
42
observer (CardObserver): Observer to remove
43
"""
44
```
45
46
### Reader Monitoring
47
48
ReaderMonitoring provides detection of reader connection and disconnection events, useful for applications that need to track available readers dynamically.
49
50
```python { .api }
51
class ReaderObserver:
52
def update(self, observable, handlers):
53
"""
54
Called when reader connection or disconnection events occur.
55
56
Args:
57
observable (ReaderMonitor): The reader monitor that detected the event
58
handlers (tuple): (added_readers, removed_readers) where:
59
- added_readers (list[Reader]): Readers that were connected
60
- removed_readers (list[Reader]): Readers that were disconnected
61
"""
62
63
class ReaderMonitor:
64
def __init__(self, startOnDemand=True, readerProc=None, period=1):
65
"""
66
Initialize reader monitoring.
67
68
Args:
69
startOnDemand (bool): If True, monitoring starts when first observer is added
70
readerProc (callable, optional): Function to get reader list. Defaults to readers()
71
period (int): Polling period in seconds for reader detection
72
"""
73
74
def addObserver(self, observer):
75
"""
76
Add an observer to receive reader events.
77
78
Args:
79
observer (ReaderObserver): Observer to add
80
"""
81
82
def deleteObserver(self, observer):
83
"""
84
Remove an observer from receiving reader events.
85
86
Args:
87
observer (ReaderObserver): Observer to remove
88
"""
89
```
90
91
### Observer Pattern Support
92
93
Base classes for implementing the observer pattern used throughout the monitoring system.
94
95
```python { .api }
96
class Observer:
97
def update(self, observable, handlers):
98
"""
99
Called when the observed object changes.
100
101
Args:
102
observable: The object being observed
103
handlers: Event-specific data
104
"""
105
106
class Observable:
107
def addObserver(self, observer):
108
"""Add an observer to this observable."""
109
110
def deleteObserver(self, observer):
111
"""Remove an observer from this observable."""
112
113
def deleteObservers(self):
114
"""Remove all observers."""
115
116
def notifyObservers(self, handlers=None):
117
"""
118
Notify all observers of a change.
119
120
Args:
121
handlers: Event data to pass to observers
122
"""
123
124
def setChanged(self):
125
"""Mark this observable as changed."""
126
127
def clearChanged(self):
128
"""Clear the changed flag."""
129
130
def hasChanged(self):
131
"""
132
Check if this observable has changed.
133
134
Returns:
135
bool: True if changed flag is set
136
"""
137
138
def countObservers(self):
139
"""
140
Get the number of observers.
141
142
Returns:
143
int: Observer count
144
"""
145
```
146
147
## Usage Examples
148
149
### Basic Card Monitoring
150
151
```python
152
from smartcard.CardMonitoring import CardMonitor, CardObserver
153
from smartcard.util import toHexString
154
155
class SimpleCardObserver(CardObserver):
156
def update(self, observable, actions):
157
(addedcards, removedcards) = actions
158
159
for card in addedcards:
160
print(f"Card inserted in {card.reader}")
161
print(f"ATR: {toHexString(card.atr)}")
162
163
for card in removedcards:
164
print(f"Card removed from {card.reader}")
165
print(f"ATR: {toHexString(card.atr)}")
166
167
# Create and start monitoring
168
monitor = CardMonitor()
169
observer = SimpleCardObserver()
170
monitor.addObserver(observer)
171
172
print("Monitoring for card events... (Press Ctrl+C to stop)")
173
try:
174
# Keep the program running to receive events
175
import time
176
while True:
177
time.sleep(1)
178
except KeyboardInterrupt:
179
print("Stopping card monitoring")
180
monitor.deleteObserver(observer)
181
```
182
183
### Card Monitoring with Automatic Connection
184
185
```python
186
import threading
187
from smartcard.CardMonitoring import CardMonitor, CardObserver
188
from smartcard.util import toHexString
189
190
class AutoConnectObserver(CardObserver):
191
def update(self, observable, actions):
192
(addedcards, removedcards) = actions
193
194
for card in addedcards:
195
# Automatically connect to inserted cards
196
threading.Thread(target=self.handle_card, args=(card,)).start()
197
198
def handle_card(self, card):
199
try:
200
connection = card.createConnection()
201
connection.connect()
202
203
print(f"Connected to card in {card.reader}")
204
205
# Send a simple command
206
GET_DATA = [0x00, 0xCA, 0x9F, 0x7F, 0x00]
207
response, sw1, sw2 = connection.transmit(GET_DATA)
208
209
print(f"GET DATA response: {toHexString(response)}")
210
print(f"Status: {sw1:02X} {sw2:02X}")
211
212
except Exception as e:
213
print(f"Error handling card: {e}")
214
finally:
215
if 'connection' in locals():
216
connection.disconnect()
217
218
# Set up monitoring
219
monitor = CardMonitor()
220
observer = AutoConnectObserver()
221
monitor.addObserver(observer)
222
223
print("Auto-connecting to inserted cards...")
224
```
225
226
### Reader Monitoring
227
228
```python
229
from smartcard.ReaderMonitoring import ReaderMonitor, ReaderObserver
230
231
class SimpleReaderObserver(ReaderObserver):
232
def update(self, observable, actions):
233
(addedreaders, removedreaders) = actions
234
235
for reader in addedreaders:
236
print(f"Reader connected: {reader}")
237
238
for reader in removedreaders:
239
print(f"Reader disconnected: {reader}")
240
241
# Create and start reader monitoring
242
monitor = ReaderMonitor()
243
observer = SimpleReaderObserver()
244
monitor.addObserver(observer)
245
246
print("Monitoring for reader events...")
247
try:
248
import time
249
while True:
250
time.sleep(1)
251
except KeyboardInterrupt:
252
print("Stopping reader monitoring")
253
monitor.deleteObserver(observer)
254
```
255
256
### Combined Card and Reader Monitoring
257
258
```python
259
from smartcard.CardMonitoring import CardMonitor, CardObserver
260
from smartcard.ReaderMonitoring import ReaderMonitor, ReaderObserver
261
from smartcard.util import toHexString
262
263
class SmartCardSystemObserver(CardObserver, ReaderObserver):
264
def __init__(self):
265
self.active_cards = {}
266
267
def update(self, observable, actions):
268
# Handle both card and reader events
269
if isinstance(observable, CardMonitor):
270
self.handle_card_event(actions)
271
elif isinstance(observable, ReaderMonitor):
272
self.handle_reader_event(actions)
273
274
def handle_card_event(self, actions):
275
(addedcards, removedcards) = actions
276
277
for card in addedcards:
278
reader_name = str(card.reader)
279
self.active_cards[reader_name] = card
280
print(f"β Card inserted in {reader_name}")
281
print(f" ATR: {toHexString(card.atr)}")
282
283
for card in removedcards:
284
reader_name = str(card.reader)
285
if reader_name in self.active_cards:
286
del self.active_cards[reader_name]
287
print(f"β Card removed from {reader_name}")
288
289
def handle_reader_event(self, actions):
290
(addedreaders, removedreaders) = actions
291
292
for reader in addedreaders:
293
print(f"π Reader connected: {reader}")
294
295
for reader in removedreaders:
296
reader_name = str(reader)
297
if reader_name in self.active_cards:
298
del self.active_cards[reader_name]
299
print(f"π Reader disconnected: {reader}")
300
301
# Set up comprehensive monitoring
302
observer = SmartCardSystemObserver()
303
304
card_monitor = CardMonitor()
305
card_monitor.addObserver(observer)
306
307
reader_monitor = ReaderMonitor()
308
reader_monitor.addObserver(observer)
309
310
print("Monitoring smart card system events...")
311
print("Insert/remove cards and connect/disconnect readers to see events")
312
313
try:
314
import time
315
while True:
316
time.sleep(1)
317
318
# Show current status every 10 seconds
319
if int(time.time()) % 10 == 0:
320
print(f"\nCurrent active cards: {len(observer.active_cards)}")
321
for reader, card in observer.active_cards.items():
322
print(f" {reader}: {toHexString(card.atr, toHexString.PACK)}")
323
print()
324
325
except KeyboardInterrupt:
326
print("\nCleaning up monitors...")
327
card_monitor.deleteObserver(observer)
328
reader_monitor.deleteObserver(observer)
329
```
330
331
### Context Manager for Monitoring
332
333
```python
334
from smartcard.CardMonitoring import CardMonitor, CardObserver
335
import contextlib
336
337
class ContextCardObserver(CardObserver):
338
def __init__(self):
339
self.events = []
340
341
def update(self, observable, actions):
342
(addedcards, removedcards) = actions
343
for card in addedcards:
344
self.events.append(('inserted', card))
345
for card in removedcards:
346
self.events.append(('removed', card))
347
348
@contextlib.contextmanager
349
def card_monitoring():
350
"""Context manager for card monitoring."""
351
monitor = CardMonitor()
352
observer = ContextCardObserver()
353
monitor.addObserver(observer)
354
355
try:
356
yield observer
357
finally:
358
monitor.deleteObserver(observer)
359
360
# Usage with context manager
361
with card_monitoring() as observer:
362
print("Monitoring cards for 10 seconds...")
363
import time
364
time.sleep(10)
365
366
print(f"Detected {len(observer.events)} events:")
367
for event_type, card in observer.events:
368
print(f" {event_type}: {card.reader}")
369
```
370
371
## Related Types
372
373
```python { .api }
374
# Card and Reader objects used in monitoring events
375
class Card:
376
def __init__(self, reader, atr):
377
"""
378
Card object containing reader and ATR information.
379
380
Args:
381
reader (Reader): Reader containing the card
382
atr (list[int]): Answer To Reset bytes
383
"""
384
385
@property
386
def reader(self):
387
"""Reader: The reader containing this card."""
388
389
@property
390
def atr(self):
391
"""list[int]: Answer To Reset bytes."""
392
393
class Reader:
394
def __init__(self, readername):
395
"""
396
Reader object.
397
398
Args:
399
readername (str): Name of the reader
400
"""
401
402
def __str__(self):
403
"""str: Reader name as string."""
404
405
# Monitoring event data types
406
EventHandlers = tuple[list[Card], list[Card]] # (added, removed)
407
ReaderEventHandlers = tuple[list[Reader], list[Reader]] # (added, removed)
408
```