Source code for devctrl.devices.led_controller.impl.thorlabs_ledd1b
import serial
import serial.tools.list_ports
from ..base import LedController
import logging
log = logging.getLogger(__name__)
ARDUINO_SOFTWARE_VERSION_STRING = "Arduino Nano CPD 1"
"""Software version string that the Arduino's firmware must return upon query"""
[docs]
class LEDD1B(LedController):
"""Control Thorlabs LEDD1B LED driver using an Arduino Nano
The Arduino must have the correct software loaded on it.
See the arduino-thorlabs-ledd1b project directory for details.
:param port: Serial port name (default: "COM4")
"""
_CLASS_TYPE = "implementation"
[docs]
def __init__(self, port="COM4"):
super().__init__()
self.port = port
self.arduino = serial.Serial(port=port, baudrate=9600, timeout=0.1)
# flush input
while self.arduino.read(1):
pass
self.level = None
[docs]
def __del__(self):
self.off()
self.arduino.close()
[docs]
def check_has_correct_software(self, no_error=False):
"""Verify the Arduino has the correct software loaded
Runs the identify command and raises an exception if the Arduino
does not reply with the expected output string.
:param no_error: If True, don't raise exception on error
:raises ConnectionError: If Arduino doesn't have expected software
"""
self._write('i')
lines = self.read()
if len(lines) < 1 or not lines[-1].startswith(bytes(ARDUINO_SOFTWARE_VERSION_STRING, "utf-8")):
log.error(f"Arduino did not return the expected output - does it have the correct software loaded?\nExpected: '{ARDUINO_SOFTWARE_VERSION_STRING}'\nReceived:{lines}")
if not no_error:
raise ConnectionError("Arduino did not return the expected output - does it have the correct software loaded?")
[docs]
def is_connected(self) -> bool:
"""Check if the Arduino is connected and responding
Sends an identify command to verify communication.
:return: True if Arduino responds, False otherwise
"""
try:
self._write('i')
lines = self.read()
return True
except Exception as e:
log.error(f"Failed to query 'i': {e}")
return False
[docs]
def _write(self, val):
"""Send a command to the Arduino
:param val: Command string to send
"""
self.arduino.write(bytes(val, 'utf-8'))
self.arduino.flush()
[docs]
def read(self):
"""Read response lines from the Arduino
:return: List of response lines
"""
data = self.arduino.readlines()
return data
[docs]
def on(self):
self._write("1")
[docs]
def off(self):
self._write("0")
[docs]
def set_brightness_percent(self, level:int):
"""Set the LED brightness percentage
This controller only supports 0% or 100% brightness.
:param level: Brightness level (0 or 100)
:raises ValueError: If level is not 0 or 100
"""
if level == 0: self.off()
elif level == 100: self.on()
else:
raise ValueError(f"LEDD1B Led controller can only set 0% or 100%")
self.level = level
[docs]
def get_brightness_percent(self):
"""Get the current brightness percentage
:return: Current brightness level (0 or 100)
:raises RuntimeError: If brightness was never set
"""
if self.level is None:
raise RuntimeError(f"{self}: Can not return brightness because it was not set for this instance.")
return self.level
[docs]
def __repr__(self) -> str:
"""
:return: Formatted string with device model and port
"""
return f"Thorlabs LEDD1B ({self.port})"
[docs]
def get_capabilities(self) -> int:
"""Get controller capabilities
Returns a bitmask indicating supported features.
:return: Capabilities bitmask (BRIGHTNESS_ON_OFF)
"""
return LedController.BRIGHTNESS_ON_OFF
[docs]
@classmethod
def _enumerate_devices(cls) -> list[str]:
"""Enumerate available LEDD1B devices
Scans serial ports for Arduino devices matching the expected criteria.
:return: List of available serial port names
"""
devs = []
coms = serial.tools.list_ports.comports()
# Require a device with no product field and empty serial number
# Change these conditions to support different devices
for com in coms:
if com.product is not None: continue
if com.serial_number: continue
if com.manufacturer not in ["wch.cn"]: continue
devs.append(com.device)
return devs
[docs]
@classmethod
def connect_device(cls, device_name: str) -> "LEDD1B":
"""Connect to a LEDD1B LED controller
Creates a new LEDD1B instance connected to the specified serial port.
:param device_name: Serial port name
:return: Configured LEDD1B instance
"""
return LEDD1B(port=device_name)
if __name__ == '__main__':
led = LEDD1B()