2525 0x4 : "Latch Relay"
2626}
2727
28+ _BOOTLOADER_ADDRESS = const (0x64 )
29+
2830class _I2CHelper :
2931 """
3032 A helper class for interacting with I2C devices on supported boards.
@@ -131,7 +133,7 @@ class Modulino:
131133 This class variable needs to be overridden in derived classes.
132134 """
133135
134- def __init__ (self , i2c_bus : I2C = None , address : int = None , name : str = None ) :
136+ def __init__ (self , i2c_bus : I2C = None , address : int = None , name : str = None , check_connection : bool = True ) -> None :
135137 """
136138 Initializes the Modulino object with the given i2c bus and address.
137139 If the address is not provided, the device will try to auto discover it.
@@ -143,6 +145,7 @@ def __init__(self, i2c_bus: I2C = None, address: int = None, name: str = None):
143145 i2c_bus (I2C): The I2C bus to use. If not provided, the default I2C bus will be used.
144146 address (int): The address of the device. If not provided, the device will try to auto discover it.
145147 name (str): The name of the device.
148+ check_connection (bool): Whether to check if the device is connected to the bus.
146149 """
147150
148151 if i2c_bus is None :
@@ -166,7 +169,7 @@ def __init__(self, i2c_bus: I2C = None, address: int = None, name: str = None):
166169
167170 if self .address is None :
168171 raise RuntimeError (f"Couldn't find the { self .name } device on the bus. Try resetting the board." )
169- elif not self .connected :
172+ elif check_connection and not self .connected :
170173 raise RuntimeError (f"Couldn't find a { self .name } device with address { hex (self .address )} on the bus. Try resetting the board." )
171174
172175 def discover (self , default_addresses : list [int ]) -> int | None :
@@ -181,11 +184,9 @@ def discover(self, default_addresses: list[int]) -> int | None:
181184 if len (default_addresses ) == 0 :
182185 return None
183186
184- devices_on_bus = self .i2c_bus .scan ()
185- for addr in default_addresses :
186- if addr in devices_on_bus :
187- return addr
188-
187+ devices_on_bus = Modulino .scan (self .i2c_bus , default_addresses )
188+ if len (devices_on_bus ) > 0 :
189+ return devices_on_bus [0 ]
189190 return None
190191
191192 def __bool__ (self ) -> bool :
@@ -205,7 +206,12 @@ def connected(self) -> bool:
205206 """
206207 if not bool (self ):
207208 return False
208- return self .address in self .i2c_bus .scan ()
209+
210+ try :
211+ self .i2c_bus .writeto (self .address , b'' )
212+ return True
213+ except OSError :
214+ return False
209215
210216 @property
211217 def pin_strap_address (self ) -> int | None :
@@ -267,7 +273,7 @@ def enter_bootloader(self):
267273 sleep (0.25 ) # Wait for the device to reset
268274 return True
269275 except OSError as e :
270- # ENODEV (e.errno == 19) can be thrown if either the device reset while writing out the buffer
276+ # ENODEV (e.errno == 19) can be thrown if the device resets while writing out the buffer
271277 return False
272278
273279 def read (self , amount_of_bytes : int ) -> bytes | None :
@@ -312,6 +318,20 @@ def has_default_address(self) -> bool:
312318 """
313319 return self .address in self .default_addresses
314320
321+ @staticmethod
322+ def scan (bus : I2C , target_addresses = None ) -> list [int ]:
323+ addresses = bytearray () # Use 8bit data type
324+ # General call address (0x00) is skipped in default range
325+ candidates = target_addresses if target_addresses is not None else range (1 ,128 )
326+
327+ for address in candidates :
328+ try :
329+ bus .writeto (address , b'' )
330+ addresses .append (address )
331+ except OSError :
332+ pass
333+ return list (addresses )
334+
315335 @staticmethod
316336 def available_devices (bus : I2C = None ) -> list [Modulino ]:
317337 """
@@ -325,10 +345,13 @@ def available_devices(bus: I2C = None) -> list[Modulino]:
325345 """
326346 if bus is None :
327347 bus = _I2CHelper .get_interface ()
328- device_addresses = bus .scan ()
348+ device_addresses = Modulino .scan (bus )
329349 devices = []
330350 for address in device_addresses :
331- device = Modulino (i2c_bus = bus , address = address )
351+ if address == _BOOTLOADER_ADDRESS :
352+ # Skip bootloader address
353+ continue
354+ device = Modulino (i2c_bus = bus , address = address , check_connection = False )
332355 devices .append (device )
333356 return devices
334357
0 commit comments