Python library for controlling Sirena carbot features over USB via LUCI_local protocol
Project description
sirena-carbot
A Python library for controlling Sirena carbot features over USB using the LUCI_local protocol.
Table of Contents
- Overview
- Requirements
- Installation
- Quick Start
- Connecting to the Device
- RX Monitor
- Available Controls
- How Commands Work
- Testing the Library
- Adding New Controls
- Publishing Updates to PyPI
- Project Structure
- Changelog
- Troubleshooting
Overview
sirena-carbot is a pip-installable Python library that lets you control car features (windows, mirrors, child lock, etc.) by sending LUCI_local commands to a carbot USB device over a serial connection.
Each control function follows a simple on/off pattern:
front_right_window_up(1) # ON → sends command over USB
front_right_window_up(0) # OFF → placeholder, does nothing
Requirements
- Python 3.8 or higher
- A Sirena carbot USB device connected to your machine
pyserial(installed automatically as a dependency)
Installation
pip install sirena-carbot
Installing from source (for development)
git clone https://github.com/your-org/sirena-carbot.git
cd sirena-carbot
pip install -e .
Quick Start
from sirena_carbot import *
enable_rx_monitor() # opens a separate terminal showing RX data
connect() # auto-detects USB port
front_right_window_up(1)
mirror_fold(1)
child_lock_on(1)
disconnect()
Wildcard import
from sirena_carbot import *
Imports all public names:
connect, disconnect, list_ports, enable_rx_monitor,
all window / mirror / child-lock functions.
Connecting to the Device
Auto-detect port (recommended)
connect()
Specify port manually
connect("COM3") # Windows
connect("/dev/ttyUSB0") # Linux
connect("/dev/tty.usbserial-0001") # macOS
List available ports
ports = list_ports()
for p in ports:
print(p['port'], '-', p['description'])
Connection parameters
| Parameter | Value |
|---|---|
| Baud rate | 57600 |
| Data bits | 8 |
| Parity | None |
| Stop bits | 1 |
RX Monitor
Call enable_rx_monitor() before connect() to automatically open a separate terminal window that displays all incoming serial data from the device in real time.
from sirena_carbot import *
enable_rx_monitor() # ← opens a new cmd window showing live RX data
connect()
front_right_window_up(1)
The monitor window looks like:
=== Sirena Carbot — RX Monitor ===
[12:34:01] RX: OK
[12:34:01] RX: LUCI_ACK 245
[12:34:02] RX: window_up done
How it works internally:
- Opens a local socket server on a free port
- Launches
sirena_carbot/_rx_monitor.pyin a newcmdwindow connected to that socket - Attaches a log callback to
SerialManagerthat forwards every RX line to the monitor window
Available Controls
All control functions accept state=1 (send command) or state=0 (no-op placeholder).
Return value: True if the command was sent successfully, False otherwise.
success = front_right_window_up(1)
if not success:
print("Command failed – is the device connected?")
Window Controls
| # | Function | Command sent (state=1) |
|---|---|---|
| 1 | front_right_window_up(1) |
LUCI_local 245 front_right_window_up |
| 2 | front_right_window_down(1) |
LUCI_local 245 front_right_window_down |
| 3 | front_left_window_up(1) |
LUCI_local 245 front_left_window_up |
| 4 | front_left_window_down(1) |
LUCI_local 245 front_left_window_down |
| 5 | rear_right_window_up(1) |
LUCI_local 245 rear_right_window_up |
| 6 | rear_right_window_down(1) |
LUCI_local 245 rear_right_window_down |
| 7 | rear_left_window_up(1) |
LUCI_local 245 rear_left_window_up |
| 8 | rear_left_window_down(1) |
LUCI_local 245 rear_left_window_down |
Mirror Controls
| # | Function | Command sent (state=1) |
|---|---|---|
| 9 | mirror_fold(1) |
LUCI_local 245 mirror_fold |
| 10 | mirror_unfold(1) |
LUCI_local 245 mirror_unfold |
Child Lock Controls
| # | Function | Command sent (state=1) |
|---|---|---|
| 11 | child_lock_on(1) |
LUCI_local 245 child_lock_on |
| 12 | child_lock_off(1) |
LUCI_local 245 child_lock_off |
How Commands Work
When you call a control function with state=1, the library sends a plain-text command over USB:
LUCI_local 245 <command_name>\n
When called with state=0, nothing is sent — it is a placeholder for future OFF implementation.
| Parameter | Value |
|---|---|
| Protocol | LUCI_local |
| Target | 245 |
| Encoding | UTF-8 |
| Line ending | \n |
Testing the Library
A test script is included at the root of the repository: test_library.py
import time
from sirena_carbot import *
enable_rx_monitor()
connect()
front_right_window_up(1); time.sleep(5)
front_right_window_down(1); time.sleep(5)
front_left_window_up(1); time.sleep(5)
front_left_window_down(1); time.sleep(5)
rear_right_window_up(1); time.sleep(5)
rear_right_window_down(1); time.sleep(5)
rear_left_window_up(1); time.sleep(5)
rear_left_window_down(1); time.sleep(5)
mirror_fold(1); time.sleep(5)
mirror_unfold(1); time.sleep(5)
child_lock_on(1); time.sleep(5)
child_lock_off(1); time.sleep(5)
disconnect()
Run it:
python test_library.py
- Sends all 12 commands with a 5-second gap between each for safety
- RX responses appear live in the separate monitor window
- Main terminal stays silent
Adding New Controls
Add one line in sirena_carbot/controls.py:
horn = _make_control("horn")
headlights_on = _make_control("headlights_on")
door_lock = _make_control("door_lock")
door_unlock = _make_control("door_unlock")
Then export in sirena_carbot/__init__.py:
from .controls import (
# existing...
horn,
headlights_on,
door_lock,
door_unlock,
)
__all__ = [
# existing...
"horn",
"headlights_on",
"door_lock",
"door_unlock",
]
Publishing Updates to PyPI
First time setup
- Create an account at https://pypi.org
- Go to Account Settings → API tokens → Add API token
- Copy the token (starts with
pypi-) - Save in
~/.pypirc:
[distutils]
index-servers = pypi
[pypi]
username = __token__
password = pypi-YOUR_TOKEN_HERE
Release workflow
# 1. Bump version in pyproject.toml AND sirena_carbot/__init__.py
# 2. Clean old build artifacts
Remove-Item -Recurse -Force dist, build, *.egg-info
# 3. Build
python -m build
# 4. Upload
python -m twine upload dist/*
Version numbering
| Change type | Example |
|---|---|
| Bug fix | 1.0.0 → 1.0.1 |
| New functions added | 1.0.0 → 1.1.0 |
| Breaking / major changes | 1.0.0 → 2.0.0 |
PyPI does not allow re-uploading the same version. Always bump before uploading.
Project Structure
carbot_software/
├── pyproject.toml # Package metadata and build config
├── README.md # This file
├── test_library.py # Test script (sends all commands)
├── serial_communication.py # Low-level USB serial driver
└── sirena_carbot/
├── __init__.py # Public API
├── connection.py # Connection manager + enable_rx_monitor()
├── controls.py # Control functions (_make_control factory)
└── _rx_monitor.py # RX monitor window (launched automatically)
Key classes (internal)
| Class | File | Responsibility |
|---|---|---|
SerialManager |
serial_communication.py |
Opens port, reads/writes bytes, manages threads |
ServoController |
serial_communication.py |
Builds SetServoPartial commands |
Changelog
v1.0.0
- Added
enable_rx_monitor()— opens a live RX data window in a separate terminal - Added mirror controls:
mirror_fold,mirror_unfold - Added child lock controls:
child_lock_on,child_lock_off from sirena_carbot import *supported via__all__- Test script simplified to 15 lines with 5-second safety delay between commands
v0.1.1
- Fixed
pyproject.tomlbuild backend (setuptools.build_meta)
v0.1.0
- Initial release: window controls,
connect,disconnect,list_ports
Troubleshooting
RuntimeError: No serial ports found
- Make sure the carbot USB device is plugged in
- Specify port manually:
connect("COM3") - Linux/macOS:
sudo usermod -aG dialout $USERthen log out and back in
Error: Not connected to serial port
Always call connect() before any control function:
from sirena_carbot import *
connect()
front_right_window_up(1)
Command returns False
- Check the USB cable
- Ensure
connect()returnedTrue - Reconnect:
disconnect() connect()
RX Monitor window does not open
- Ensure you called
enable_rx_monitor()beforeconnect() - Windows only: requires
cmd.exe— not supported in Linux/macOS as-is
Wrong COM port selected automatically
for p in list_ports():
print(p)
connect("COM5")
state=0 does nothing — is that a bug?
No. state=0 is intentionally a placeholder until the firmware implements OFF behaviour.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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 sirena_carbot-1.0.1.tar.gz.
File metadata
- Download URL: sirena_carbot-1.0.1.tar.gz
- Upload date:
- Size: 12.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c821c1c1b0014b599bba10e8591151976abd9a53f586009b56fdb9fe8bfead89
|
|
| MD5 |
2731eed74a78cc50bb0b3b802aee2908
|
|
| BLAKE2b-256 |
076e5189ce28783434186d9b03854ff5765e9d33f6b887c22da530b5d67b2cfc
|
File details
Details for the file sirena_carbot-1.0.1-py3-none-any.whl.
File metadata
- Download URL: sirena_carbot-1.0.1-py3-none-any.whl
- Upload date:
- Size: 9.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cb54f0b333710719360998acd5ea680fc58afa6a8d491c67bf51cb3a8f66733
|
|
| MD5 |
3f9cfce614470fcafbdf11c4be443e8e
|
|
| BLAKE2b-256 |
7c81d8589e46612bc0e6f29a291041753b4e76fc05dba9735c8b273443adbcd9
|