Lite version of zCube Developer Kit for SLI-F1 device (non-commercial use only)
Project description
zCube (z3 Engine) Developer Kit For Python
Copyright (c)2025 by Zappadoc - All Rights Reserved.
Change history:
-- 2025.04.03: created - Zappadoc
zCube (z3 engine) developer kit for Python interacts with Leo bodnar SLI (Shift-Lights Interface) USB devices (SLI-F1, SLI-PRO, SLI-M and SLI-FTEC) using Python script. The kit includes a Full (EULA) and Lite (free non-commercial) module versions for each device.
Note: Some features are not available in the Lite version.
Main Features:
- Device initialization and capability detection
- Input polling (Full version only)
- LED control (RPM, Warning)
- External LED control (Full version only)
- Display panel (3, 4, or 6 digits) control (limited charset in lite version)
- Gear indicator (limited charset in lite version)
- Brightness control (Full version)
- rumble motor on Bodnar Conversion kit - SLI-FTEC device (Full version)
To use:
- Plug in your device
- Choose either the Lite or Full version of the module to install
- Run the script directly to test available features
This source code, module, lib and all information, data, and algorithms associated with it are subject to change without notice.
zCube (z3) Extensions:
SLI-PRO: z3slipro and z3slipro_lite
SLI-F1: z3slif1 and z3slif1_lite
SLI-M: z3slim and z3slim_lite
SLI-FTEC (Fanatec Conversion Kit): z3sliftec and z3sliftec_lite
Main Features:
- Device initialization and capability detection
- Input polling (full version only)
- LED control (RPM, Warning/FLAG)
- External LED control (full version only)
- Display panel (3, 4, or 6 digits) control (limited charset in lite version)
- Gear indicator (limited charset in lite version)
- Brightness control (full version)
- Rumble motors on Bodnar Conversion kit - SLI-FTEC device (full version)
To use:
- Plug in your device
- Choose either the Lite or Full version of the module
- Run the script directly to test available features
Note: Some features are not available in the Lite version.
Read Doc / API for more info:
https://www.eksimracing.org/zcube-developer-kit/
License:
https://www.eksimracing.org/terms-conditions
DISCLAIMER:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
All product names are trademarks or registered trademarks of their respective holders.
Usage Example
"""
# #####################################################################
sample script to test ZCube API
for zCUBE Engine Python extension module
Copyright (c)2022-2025 by Zappadoc - All Rights Reserved.
https://www.eksimracing.org
This source code, module, lib and all information, data, and algorithms
associated with it are subject to change without notice.
Change history:
-- 2025.04.03: created - Zappadoc
This example shows how to interact with Leo bodnar USB device using the Python.
Both the Full and Lite versions are supported.
Main Features:
- Device initialization and capability detection
- Input polling (Full version only)
- LED control (RPM, Warning)
- External LED control (Full version only)
- Display panel (3, 4, or 6 digits) control (limited charset in lite version)
- Gear indicator (limited charset in lite version)
- Brightness control (Full version)
- Wheel motor simulation on Bodnar Conversion kit - SLI-FTEC device (Full version)
To use:
- Plug in your device
- Choose either the Lite or Full version of the module
- Run the script directly to test available features
Note: Some features are not available in the Lite version.
Read the zCube Doc / API for more info:
https://www.eksimracing.org/zcube-developer-kit/
License:
https://www.eksimracing.org/terms-conditions
DISCLAIMER:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
All product names are trademarks or registered trademarks of their respective holders.
# #####################################################################
"""
import threading
import z3slif1_lite as sli # Free Lite Version
#import z3slif1 as sli # Full Version
import time
# instance of z3 engine
dev_unit1 = sli.z3engine()
# Global variable to track thread status
thread_down = True
# full version vs lite
is_full_version = False
# Global dictionary to store device capabilities
device_info = {}
def initialize_device(dev):
# Initialize the device
if dev.init():
print("Start Testing...")
return True
print("Device Error!\n- device not connected (connect your device)\n- or license not found (register your device)\n- or the default device is not found (change the script with the correct zCube extension!")
return False
def get_device_info(dev):
# Retrieve device information and capabilities
dev_path = dev.get_device_info("device path")
dev_sn = dev.get_device_info("serial number")
dev_name = dev.get_device_info("name")
dev_version = dev.get_device_info("version")
dev_vendid = dev.get_device_info("vendor id")
dev_prodid = dev.get_device_info("product id")
btns = dev.get_device_info("digital")
sw = dev.get_device_info("analog")
max_rpm_leds = dev.get_device_info("max rpm led")
max_warn_leds = dev.get_device_info("max warning led")
max_ext_leds = dev.get_device_info("max external led")
max_brightness = dev.get_device_info("brightness")
is_gear_present = dev.get_device_info("gear")
max_digits = dev.get_device_info("digits") if dev.get_device_info("panel count") >= 1 else 0
max_rumble_motor = dev.get_device_info("rumble motor")
dev_info = {
"name": dev_name,
"version": dev_version,
"vendor_id": dev_vendid,
"product_id": dev_prodid,
"serial_num": dev_sn,
"path": dev_path,
"buttons": btns,
"switches": sw,
"max_rpm_leds": max_rpm_leds,
"max_warn_leds": max_warn_leds,
"max_ext_leds": max_ext_leds,
"max_brightness": max_brightness,
"is_gear_present": is_gear_present,
"max_digits": max_digits,
"max_rumble_motor": max_rumble_motor
}
return dev_info
# ---------------------------------------------------------
def input_watcher(dev, stop_event, dev_name):
# Monitor input events from the device
if "_lite" in dev_name:
print("Not Implemented in Lite Version - Use the Full Version")
return
print("Thread Start: Poll Inputs...\n")
while not stop_event.is_set():
try:
dv, type_, pos, val, is_new = dev.get_input_data()
if is_new:
print(f"Device: {dv}, Type: {type_}, Pos: {pos}, Value: {val}, isNew: {bool(is_new)}")
except Exception as e:
print(f"Error reading input data: {e}")
time.sleep(0.1)
print("Thread Down...\n")
def start_input_thread(dev, dev_name, btns):
# Start the input monitoring thread if conditions are met
global thread_down
if btns > 0 and "_lite" not in dev_name:
dev.start_input_listener()
stop_event = threading.Event()
t = threading.Thread(target=input_watcher, args=(dev, stop_event, dev_name), daemon=True)
t.start()
thread_down = False
return stop_event, t
return None, None
# ---------------------------------------------------------
def toggle_rpm_leds(dev, dev_info, state):
# Toggle RPM LEDs
if dev_info["max_rpm_leds"] > 0:
for i in range(1, dev_info["max_rpm_leds"] + 1):
dev.set_rpm_led(i, state)
dev.show_me()
def toggle_warn_leds(dev, dev_info, state):
# Toggle warning LEDs
if dev_info["max_warn_leds"] > 0:
for i in range(1, dev_info["max_warn_leds"] + 1):
dev.set_warning_led(i, state)
dev.show_me()
def toggle_ext_leds(dev, dev_info, state):
# Toggle external LEDs
if not is_full_version:
return
if dev_info["max_ext_leds"] > 0:
for i in range(1, dev_info["max_ext_leds"] + 1):
dev.set_external_led(i, state)
dev.show_me()
def toggle_all_leds(dev, dev_info, state):
# Toggle all LEDs
toggle_rpm_leds(dev, dev_info, state)
toggle_warn_leds(dev, dev_info, state)
toggle_ext_leds(dev, dev_info, state)
def clear_display(dev, dev_info):
# Clear the display and turn off LEDs
if dev_info["is_gear_present"] > 0:
dev.set_gear(" ", False)
if dev_info["max_digits"] == 3:
dev.set_central_panel(" ")
elif dev_info["max_digits"] == 4:
dev.set_left_panel(" ")
dev.set_right_panel(" ")
elif dev_info["max_digits"] == 6:
dev.set_left_panel(" ")
dev.set_right_panel(" ")
toggle_all_leds(dev, dev_info, 0)
dev.show_me()
def time_to_7seg_string(mn, sc, ms, side=1):
# Convert time to 7-segment display string
if mn == 0 and sc == 0 and ms == 0:
return "-:--.---" if side == 1 else "-.--.---"
elif mn < 10:
return f"{mn}:{sc:02d}.{ms:03d}" if side == 1 else f"{mn}.{sc:02d}.{ms:03d}"
elif mn >= 60:
hr = mn // 60
mn = mn % 60
return f" {hr:02d}.{mn:02d} "
else:
return f" {mn:02d}.{sc:02d}.{ms:01d}"
def simulate_lap_time(dev, dev_info):
# Simulate lap time display
print("Simulate the lap time (1:12.542)")
max_time = 72.542
start_time = time.time()
if not is_full_version:
print("**Limited** charset in Lite Version - Use the Full Version")
if dev_info["max_digits"] == 6:
dev.set_left_panel(" LAP ")
dev.set_right_panel("-:--.---")
if dev_info["max_digits"] == 4:
dev.set_left_panel("LAP ")
dev.set_right_panel("-:--.-")
if dev_info["max_digits"] == 3:
dev.set_central_panel("---")
dev.set_gear(" ")
dev.show_me()
while True:
current_time = (time.time() - start_time) + 59
if current_time >= max_time:
break
minutes = int(current_time // 60)
seconds = int(current_time % 60)
milliseconds = int((current_time * 1000) % 1000)
lap_time_str = time_to_7seg_string(minutes, seconds, milliseconds)
if dev_info["max_digits"] == 6:
dev.set_left_panel(" LAP ")
dev.set_right_panel(lap_time_str)
if dev_info["max_digits"] == 4:
dev.set_left_panel("LAP ")
dev.set_right_panel(lap_time_str)
if dev_info["max_digits"] == 3:
dev.set_central_panel(lap_time_str)
dev.show_me()
elapsed_ticks = time.time() - start_time
time.sleep(max(0.0, (elapsed_ticks - current_time)))
def check_charset(dev, dev_info):
# Check and display character set on the device
if is_full_version:
print("Test charset (full version) on panel display and gear")
words = ["ABS", "GrOUP", "PIt", "bAtt", "FUEL", "CHArG", "StOP", "LAP", "SPEEd", "tEMP", "OIL", "Err", "LO", "HI", "CLr", "On", "OFF", "GO", "rdy", "End"]
words_3chars = ["ABS", "LAP", "PIT", "OIL", "TMP", "BAT", "SPD", "FUE", "ON ", "OFF", "END", "GO ", "ERR", "HI ", "LO ", "CLr", "RDY", "AIR", "ENG", "TRN"]
if dev_info["max_digits"] == 6:
for word in words:
centered = word.center(dev_info["max_digits"])
dev.set_left_panel(centered)
dev.set_right_panel(centered)
dev.show_me()
time.sleep(0.2)
if dev_info["max_digits"] == 4:
for word in words_3chars:
centered = word.center(dev_info["max_digits"])
dev.set_left_panel(centered)
dev.set_right_panel(centered)
dev.show_me()
time.sleep(0.2)
if dev_info["max_digits"] == 3:
for word in words_3chars:
centered = word.center(dev_info["max_digits"])
dev.set_central_panel(centered)
dev.show_me()
time.sleep(0.2)
else:
print("Skip charset test on panel display in lite version")
if dev_info["is_gear_present"] > 0:
max_num = 154 if is_full_version else 10
for i in range(max_num):
ch = chr(i)
try:
if dev_info["max_digits"] > 3:
dev.set_left_panel(" Char ")
dev.set_right_panel(f" {i:03d} ")
dev.set_gear(i)
dev.show_me()
time.sleep(0.1)
except Exception as e:
print(f"Error: {e}")
def initialize_brightness(dev, dev_info):
# Initialize brightness
if not is_full_version:
print("Skip brightness initialization on lite version")
return
if dev_info["max_brightness"] >= 100:
if "ftec" in dev_info["name"]:
brightness_level = 100
else:
brightness_level = 200
dev.set_brightness(brightness_level)
def initialize_gear(dev, dev_info):
# Initialize gear
if dev_info["is_gear_present"] > 0:
dev.set_gear("-")
dev.show_me()
def test_rpm_leds(dev, dev_info):
# Test RPM LEDs
for i in range(1, dev_info["max_rpm_leds"] + 1):
dev.set_rpm_led(i, 1)
if dev_info["is_gear_present"] > 0:
if i <= 9:
dev.set_gear(i, True)
else:
dev.set_gear(i - 10, True)
dev.show_me()
time.sleep(0.2)
for i in range(dev_info["max_rpm_leds"], 0, -1):
dev.set_rpm_led(i, 0)
if dev_info["is_gear_present"] > 0:
if i <= 9:
dev.set_gear(i, True)
else:
dev.set_gear(i - 10, True)
dev.show_me()
time.sleep(0.2)
def test_brightness(dev, dev_info):
# Test brightness
if dev_info["max_brightness"] > 0 and is_full_version:
dev.set_brightness(dev_info["max_brightness"])
if dev_info["is_gear_present"] > 0:
dev.set_gear("_", True)
dev.show_me()
print("Decrease Brightness...")
for i in range(dev_info["max_brightness"], 0, -1):
if dev_info["max_digits"] == 3:
dev.set_central_panel(f"{i:03d}")
elif dev_info["max_digits"] == 4:
dev.set_left_panel(f"{i:03d} ")
dev.set_right_panel("DOWN")
elif dev_info["max_digits"] == 6:
dev.set_left_panel(f" {i:03d} ")
dev.set_right_panel("888888")
dev.set_brightness(i)
dev.show_me()
time.sleep(0.01)
time.sleep(1)
if dev_info["is_gear_present"] > 0:
if "z3sli" in dev_info["name"]:
dev.set_gear(chr(126), True)
else:
dev.set_gear("-", True)
dev.show_me()
print("Increase Brightness...")
for i in range(1, dev_info["max_brightness"] + 1):
if dev_info["max_digits"] == 3:
dev.set_central_panel(f"{i:03d}")
elif dev_info["max_digits"] == 4:
dev.set_left_panel(f"{i:03d} ")
dev.set_right_panel(" UP ")
elif dev_info["max_digits"] == 6:
dev.set_left_panel(f" {i:03d} ")
dev.set_right_panel("--UP--")
dev.set_brightness(i)
dev.show_me()
time.sleep(0.01)
if "ftec" in dev_info["name"]:
dev.set_brightness(100)
else:
dev.set_brightness(200)
clear_display(dev, dev_info)
def test_warning_leds(dev, dev_info):
# Test warning/FLAG LEDs
if dev_info["max_warn_leds"] > 0:
print("Warning/FLAG LED...")
mwl = dev_info["max_warn_leds"] // 2
for i in range(1, mwl + 1):
dev.set_warning_led(i, 1)
dev.set_warning_led((dev_info["max_warn_leds"] + 1) - i, 1)
dev.show_me()
time.sleep(0.4)
for i in range(1, mwl + 1):
dev.set_warning_led((mwl + 1) - i, 0)
dev.set_warning_led(mwl + i, 0)
dev.show_me()
time.sleep(0.4)
def test_external_leds(dev, dev_info):
# Test external/optinal LEDs
if dev_info["max_ext_leds"] > 0 and is_full_version:
print("External LED...")
for i in range(1, dev_info["max_ext_leds"] + 1):
dev.set_external_led(i, 1)
dev.show_me()
time.sleep(0.4)
for i in range(dev_info["max_ext_leds"], 0, -1):
dev.set_external_led(i, 0)
dev.show_me()
time.sleep(0.4)
else:
if "sliftec" not in dev_info["name"]: print("Skip External LED test in lite version")
def test_rumble_motors(dev, dev_info):
# Test rumble/rim motors
if dev_info["max_rumble_motor"] == 2 and is_full_version:
print("Alternate Rim Motors")
for i in range(0, 10):
if i % 2 == 0:
dev.load_rumble_motor(1, 255)
dev.load_rumble_motor(2, 0)
else:
dev.load_rumble_motor(2, 255)
dev.load_rumble_motor(1, 0)
dev.show_me()
time.sleep(0.5)
dev.load_rumble_motor(1, 0)
dev.load_rumble_motor(2, 0)
dev.show_me()
else:
if "sliftec" in dev_info["name"]: print("Skip Rumble motors test in lite version")
def initialize_panels(dev, dev_info):
# Initialize panel displays
if dev_info["max_digits"] == 3:
dev.set_central_panel("888")
elif dev_info["max_digits"] == 4:
dev.set_left_panel("8888")
dev.set_right_panel("-Z3-")
elif dev_info["max_digits"] == 6:
dev.set_left_panel("888888")
dev.set_right_panel(" ZCubE")
dev.show_me()
def run_all_functions(dev, dev_info):
stop_event, t = start_input_thread(dev, dev_info["name"], dev_info["buttons"])
initialize_brightness(dev, dev_info)
initialize_gear(dev, dev_info)
test_rpm_leds(dev, dev_info)
toggle_rpm_leds(dev, dev_info, 1)
time.sleep(0.1)
initialize_panels(dev, dev_info)
time.sleep(0.25)
test_brightness(dev, dev_info)
test_warning_leds(dev, dev_info)
test_external_leds(dev, dev_info)
toggle_all_leds(dev, dev_info, 0)
test_rumble_motors(dev, dev_info)
simulate_lap_time(dev, dev_info)
check_charset(dev, dev_info)
clear_display(dev, dev_info)
if not thread_down and is_full_version:
stop_event.set()
t.join()
if is_full_version:
dev.stop_input_listener()
dev.terminate()
def main():
# Main function to run the device test
isDev1 = initialize_device(dev_unit1)
if isDev1:
global device_info, device2_info, is_full_version
device_info = get_device_info(dev_unit1)
if "_lite" not in device_info["name"]:
is_full_version = True
# Create thread for the device
thread1 = threading.Thread(target=run_all_functions, args=(dev_unit1, device_info,))
# Start the thread
thread1.start()
# Wait for thread to finish
thread1.join()
print("Test Done!")
if __name__ == "__main__":
main()
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file z3slif1_lite-0.2.0-py3-none-win_amd64.whl.
File metadata
- Download URL: z3slif1_lite-0.2.0-py3-none-win_amd64.whl
- Upload date:
- Size: 150.6 kB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.9.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e180c897cf409dd4d8f7d4f4110a0e752b0eb61adccc663ad3bf7a45987f4ae3
|
|
| MD5 |
fac7a6edfa4bd3953849f59ef1ed5610
|
|
| BLAKE2b-256 |
7f95138df9e23a582cf79b83ecd5c285941b67cdbe77f057073b88c1ddd1823f
|