Notifier and Listeners¶
Notifier¶
The Notifier object is used as a message distributor for a bus. The Notifier uses an event loop or creates a thread to read messages from the bus and distributes them to listeners.
- class can.Notifier(bus, listeners, timeout=1.0, loop=None)[source]¶
Manages the distribution of
Message
instances to listeners.Supports multiple buses and listeners.
Note
Remember to call stop() after all messages are received as many listeners carry out flush operations to persist data.
- Parameters:
bus (BusABC | List[BusABC]) – A Bus or a list of buses to listen to.
listeners (Iterable[Listener | Callable[[Message], Awaitable[None] | None]]) – An iterable of
Listener
or callables that receive aMessage
and return nothing.timeout (float) – An optional maximum number of seconds to wait for any
Message
.loop (AbstractEventLoop | None) – An
asyncio
event loop to schedule thelisteners
in.
- add_bus(bus)[source]¶
Add a bus for notification.
- Parameters:
bus (BusABC) – CAN bus instance.
- Return type:
None
- add_listener(listener)[source]¶
Add new Listener to the notification list. If it is already present, it will be called two times each time a message arrives.
- remove_listener(listener)[source]¶
Remove a listener from the notification list. This method throws an exception if the given listener is not part of the stored listeners.
- Parameters:
listener (Listener | Callable[[Message], Awaitable[None] | None]) – Listener to be removed from the list to be notified
- Raises:
ValueError – if listener was never added to this notifier
- Return type:
None
Listener¶
The Listener class is an “abstract” base class for any objects which wish to register to receive notifications of new messages on the bus. A Listener can be used in two ways; the default is to call the Listener with a new message, or by calling the method on_message_received.
Listeners are registered with Notifier object(s) which ensure they are notified whenever a new message is received.
1#!/usr/bin/env python
2
3import time
4
5import can
6
7
8def main():
9 with can.Bus(interface="virtual", receive_own_messages=True) as bus:
10 print_listener = can.Printer()
11 notifier = can.Notifier(bus, [print_listener])
12
13 bus.send(can.Message(arbitration_id=1, is_extended_id=True))
14 bus.send(can.Message(arbitration_id=2, is_extended_id=True))
15 bus.send(can.Message(arbitration_id=1, is_extended_id=False))
16
17 time.sleep(1.0)
18 notifier.stop()
19
20
21if __name__ == "__main__":
22 main()
Subclasses of Listener that do not override on_message_received will cause
NotImplementedError
to be thrown when a message is received on
the CAN bus.
- class can.Listener[source]¶
The basic listener that can be called directly to handle some CAN message:
listener = SomeListener() msg = my_bus.recv() # now either call listener(msg) # or listener.on_message_received(msg) # Important to ensure all outputs are flushed listener.stop()
- on_error(exc)[source]¶
This method is called to handle any exception in the receive thread.
- Parameters:
exc (Exception) – The exception causing the thread to stop
- Return type:
None
There are some listeners that already ship together with python-can and are listed below. Some of them allow messages to be written to files, and the corresponding file readers are also documented here.
Note
Please note that writing and the reading a message might not always yield a completely unchanged message again, since some properties are not (yet) supported by some file formats.
Note
Additional file formats for both reading/writing log files can be added via
a plugin reader/writer. An external package can register a new reader
by using the can.io.message_reader
entry point. Similarly, a writer can
be added using the can.io.message_writer
entry point.
The format of the entry point is reader_name=module:classname
where classname
is a can.io.generic.BaseIOHandler
concrete implementation.
entry_points={
'can.io.message_reader': [
'.asc = my_package.io.asc:ASCReader'
]
},
BufferedReader¶
- class can.BufferedReader[source]¶
A BufferedReader is a subclass of
Listener
which implements a message buffer: that is, when thecan.BufferedReader
instance is notified of a new message it pushes it into a queue of messages waiting to be serviced. The messages can then be fetched withget_message()
.Putting in messages after
stop()
has been called will raise an exception, seeon_message_received()
.- Attr is_stopped:
True
if the reader has been stopped
- get_message(timeout=0.5)[source]¶
Attempts to retrieve the message that has been in the queue for the longest amount of time (FIFO). If no message is available, it blocks for given timeout or until a message is received (whichever is shorter), or else returns None. This method does not block after
can.BufferedReader.stop()
has been called.- Parameters:
timeout (float) – The number of seconds to wait for a new message.
- Returns:
the received
can.Message
or None, if the queue is empty.- Return type:
Message | None
- class can.AsyncBufferedReader(**kwargs)[source]¶
A message buffer for use with
asyncio
.See Asyncio support for how to use with
can.Notifier
.Can also be used as an asynchronous iterator:
async for msg in reader: print(msg)
- Parameters:
kwargs (Any)
- async get_message()[source]¶
Retrieve the latest message when awaited for:
msg = await reader.get_message()
- Returns:
The CAN message.
- Return type: