Python library for controlling Konica Minolta CS-150, CS-160, LS-150, and LS-160 chroma meters and luminance meters. All functions still under development.
- Complete device control via USB
- Luminance and color measurements
- All measurement modes (Lvxy, XYZ, Lvudvd, etc.)
- Device configuration (integration time, sync, peak/valley)
- Display and backlight control
- Close-up lens configuration
- Read/delete stored measurements
- Device information and diagnostics
- Python 3.6+
- pythonnet >= 3.0.0
- Windows 10/11 (might work on different OS, not tested yet)
- Konica Minolta LC-MISDK (included in
sdk_binfolder) - Device USB drivers (see candelameter manual and section below)
The device needs to be installed with the correct drivers. If it shows up in the device manager as just USB Serial Device it might not work. These steps did work for me:
- Open the device manager
- Right click the device under (COM & LPT)
- Click update drivers
- Click
Browse my computer for driver software - Select the driver folder and
Have Disk... - Choose the .INF file"
The candelameter should now show up as somethign like Measurement Device (COMx)
pip install pythonnetFor this project to work properly you need to replicate the project structure from a .net application. The easiest way is to build a minimal working .net example (in the Konica Minolta LC-MISDK there is some example code, additional dlls need to be installed via nuget) and then copy the debug folder with all the .dll files. For copyright reasons I can't include any files from the LC-MISDK in this project. In the future I will test in more detail which files are actually neccessary.
This is a tree view of my working solution :
ROOT FOLDER
│ libtest.py
│
└───src
└───konica_lscs
│ __init__.py
│
└───sdk_bin
│ App.config
│ CalculateColor.dll
│ CalculateDominantWavelength.dll
│ CalculateRequiredData.dll
│ CalculateTduvJIS.dll
│ CalculateXYZ.dll
│ CalculateYuvD.dll
│ CalculateYxy.dll
│ Kmop.BusinessCore.dll
│ Kmop.BusinessProxy.dll
│ Kmop.BusinessWorkflow.dll
│ Kmop.ColorCore.dll
│ Kmop.ColorProxy.dll
│ Kmop.CommunicationCore.dll
│ Kmop.CommunicationProxy.dll
│ Kmop.Constants.dll
│ Kmop.ContextServices.dll
│ Kmop.DAL.Utilities.dll
│ Kmop.DataAccessCore.dll
│ Kmop.DataAccessProxy.dll
│ Kmop.DummyDAL.dll
│ Kmop.HostConn.dll
│ Kmop.IBusiness.dll
│ Kmop.IBusinessServicesContract.dll
│ Kmop.IColorService.dll
│ Kmop.ICommunicationServicesContract.dll
│ Kmop.IDAL.dll
│ Kmop.IDataAccessServiceContract.dll
│ Kmop.IDeviceCommand.dll
│ Kmop.IInstrumentServiceContract.dll
│ Kmop.IKmopDAL.dll
│ Kmop.Instrument.ConnectDevice.dll
│ Kmop.Instrument.CS100P.dll
│ Kmop.InstrumentControl.dll
│ Kmop.InstrumentCore.dll
│ Kmop.InstrumentProxy.dll
│ Kmop.IRuleEngine.dll
│ Kmop.KmopDummyDAL.dll
│ Kmop.Rest.DTO.dll
│ Kmop.Rest.Interface.dll
│ Kmop.RuleEngine.CS100P.dll
│ Kmop.RuleEngineProxy.dll
│ Kmop.SignalRClient.dll
│ Kmop.Utilities.dll
│ LC-MISDK.dll
│ log4net.dll
│ MathNet.Numerics.dll
│ Microsoft.AspNet.SignalR.Client.dll
│ Newtonsoft.Json.dll
│ ServiceStack.Common.dll
│ ServiceStack.dll
│ ServiceStack.Interfaces.dll
│ ServiceStack.OrmLite.dll
│ ServiceStack.OrmLite.MySql.dll
│ ServiceStack.ServiceInterface.dll
│ ServiceStack.Text.dll
│ SimpleInjector.Diagnostics.dll
│ SimpleInjector.dll
│ WeightValue.dll
│ WordingList.dll
│
├───calccolor
│ └───x64
│ CalculateColor.dll
│ CalculateDominantWavelength.dll
│ CalculateRequiredData.dll
│ CalculateTduvJIS.dll
│ CalculateXYZ.dll
│ CalculateYuvD.dll
│ CalculateYxy.dll
│ OBS_10_1nm.obs
│ OBS_10_5nm.obs
│ OBS_2_1nm.obs
│ OBS_2_5nm.obs
│ WeightValue.dll
│ WordingList.dll
│ WP_USER01.uwp
│
└───IDMap
CS-150.xml
CS-160.xml
LS-150.xml
LS-160.xml
Included in the project there is a libtest.py file that runs through some basic examples. Below are some very basic use-cases.
from konica_lscs import KonicaDevice
# Basic measurement
with KonicaDevice() as device:
device.connect()
device.measure()
luminance = device.get_luminance()
print(f"Luminance: {luminance} cd/m²")from konica_lscs import KonicaDevice
device = KonicaDevice()
device.connect()
# Take a measurement
device.measure()
# Get luminance
lv = device.get_luminance()
print(f"Luminance: {lv:.2f} cd/m²")
# Get all color values
color = device.get_color()
print(f"Color: {color}")
device.disconnect()with KonicaDevice() as device:
device.connect()
device.measure()
lv = device.get_luminance()
print(f"Luminance: {lv:.2f} cd/m²")
# Automatically disconnects devicewith KonicaDevice() as device:
device.connect()
info = device.get_device_info()
print(f"Device: {info['product_name']}")
print(f"Serial: {info['serial_number']}")
print(f"Firmware: {info['firmware_major']}.{info['firmware_minor']}")
sdk_version = device.get_sdk_version()
print(f"SDK: {sdk_version}")with KonicaDevice() as device:
device.connect()
# Set auto integration time
device.set_measurement_time('auto')
# Or manual integration time (1.5 seconds)
device.set_measurement_time('manual', manual_time=1.5)
# Enable sync mode at 60 Hz
device.set_sync_mode(sync=True, frequency=60.0)
# Set peak measurement
device.set_peak_valley('peak') # 'peak', 'valley', or 'off'with KonicaDevice() as device:
device.connect()
# Backlight control
device.set_backlight(True)
device.set_backlight_level(5) # 1-5 (1=darkest, 5=brightest)
# Color mode
device.set_color_mode('lvxy') # 'lvxy', 'xyz', 'lvudvd', etc.with KonicaDevice() as device:
device.connect()
device.set_measurement_time('auto')
for i in range(10):
device.measure()
lv = device.get_luminance()
print(f"Measurement {i+1}: {lv:.2f} cd/m²")with KonicaDevice() as device:
device.connect()
# Get number of stored measurements
count = device.get_number_of_samples()
print(f"Stored samples: {count}")
# Read stored measurements
for i in range(1, count + 1):
sample = device.read_sample_data(i)
print(f"Sample {i}: {sample}")
# Delete all stored data
device.delete_sample_data(-1) # -1 = delete allwith KonicaDevice() as device:
device.connect()
device.measure()
# Read as XYZ
device.set_color_mode('xyz')
xyz = device.get_color()
print(f"XYZ: {xyz}")
# Read as Lvxy
device.set_color_mode('lvxy')
lvxy = device.get_color()
print(f"Lvxy: {lvxy}")
# Or read XYZ directly
xyz_direct = device.read_latest_data_xyz()
print(f"XYZ direct: {xyz_direct}")There are all the functions from the official manual included in the library. However so far I have only tested the ones below:
connect(com_port=0)- Connect to device (0 = auto-detect)disconnect(com_port=0)- Disconnect from deviceget_device_list()- Get dictionary of connected devices
measure(wait=True, com_port=0)- Take a measurementwait_for_idle(com_port=0)- Wait for measurement to completecancel_measurement(com_port=0)- Cancel ongoing measurement
get_luminance(com_port=0)- Get luminance in cd/m²get_color(com_port=0)- Get all color values as dictread_display_value(com_port=0)- Read device display valuesread_latest_data_xyz(com_port=0)- Read as XYZ tristimulus values
get_number_of_samples(com_port=0)- Get count of stored measurementsread_sample_data(data_number, com_port=0)- Read stored measurementdelete_sample_data(data_number=-1, com_port=0)- Delete stored data (-1 = all)
set_measurement_time(mode, manual_time=1.0, com_port=0)- Set integration timeget_measurement_time(com_port=0)- Get integration time settingsset_sync_mode(sync, frequency=60.0, com_port=0)- Set sync modeget_sync_mode(com_port=0)- Get sync mode settingsset_peak_valley(mode, com_port=0)- Set peak/valley mode ('off', 'peak', 'valley')get_peak_valley(com_port=0)- Get peak/valley mode
set_close_up_lens(lens_type, com_port=0)- Set close-up lens ('standard', 'no153', 'no135', 'no122', 'no110')get_close_up_lens(com_port=0)- Get current lens setting
set_backlight(on, com_port=0)- Turn backlight on/offget_backlight(com_port=0)- Get backlight statusset_backlight_level(level, com_port=0)- Set brightness (1-5)get_backlight_level(com_port=0)- Get brightness levelset_color_mode(mode, com_port=0)- Set color mode ('lvxy', 'xyz', 'lvudvd', 'lvtcpduv', 'lvdwpe', 'lv')get_color_mode(com_port=0)- Get current color mode
get_device_info(com_port=0)- Get device info dictget_sdk_version()- Get SDK version string
The device supports multiple color spaces:
- Lvxy - Luminance (cd/m²), chromaticity x, y
- XYZ - CIE XYZ tristimulus values
- Lvudvd - Luminance, CIE 1976 UCS chromaticity u', v'
- LvTcpDuv - Luminance, correlated color temperature, Duv
- LvDwPe - Luminance, dominant wavelength, excitation purity
- Lv - Luminance only (LS-series devices)
- CS-150 (Chroma Meter)
- CS-160 (Chroma Meter)
- LS-150 (Luminance Meter)
- LS-160 (Luminance Meter)
The LS-series devices only support luminance measurements, not color.
- .Net does not like dlls from the internet
- Run the
unblock_dll.pytool
- Ensure all DLL files are in the
sdk_binfolder - Check that pythonnet is properly installed
- Have you tried turning it off and on again? Is it plugged in?
- Ensure device drivers are installed (see manual section 5.3)
- Try specifying COM port explicitly:
device.connect(com_port=3)
- Ensure measurement completed before reading:
device.measure(wait=True) - Check that color mode is supported by your device model
# Get list of connected devices
with KonicaDevice() as device:
devices = device.get_device_list()
print(f"Found devices: {devices}")
# Connect to specific device
device.connect(com_port=3)with KonicaDevice() as device:
device.connect()
# Fast measurements (auto mode)
device.set_measurement_time('auto')
# Or precise measurements (manual mode)
device.set_measurement_time('manual', manual_time=2.0)This library interfaces with the Konica Minolta LC-MISDK. See the SDK license agreement for terms. The python code is licensed under the MIT License.
Contributions are very welcome. Report any issues via Github. If anybody would like to further help improve this project I'm happy about any help.
read_latest_datafunction not working properly. For now useread_display_value
- Check if all functions work
- Check which files are actually neccessary, at the moment all are included
- Re-work into actually installable library
- Implement proper tests
- 0.1.0 - Initial release
- 0.1.1 - Add dll unblock tool
- 0.2.0 - Add automatic check if LS or CS device