Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 0 additions & 55 deletions .github/workflows/build.yml

This file was deleted.

41 changes: 41 additions & 0 deletions .github/workflows/pip.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Pip

on:
workflow_dispatch:
pull_request:
push:
branches: [main, dev]
jobs:
build:
name: Build on ${{ matrix.platform }} with Python ${{ matrix.python-version }}
runs-on: ${{ matrix.platform }}
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install system dependencies
run: |
sudo apt update
sudo apt install -y libusb-1.0-0-dev libftdi1-dev pkg-config

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true

- name: Build and install the package
run: |
pip install --verbose .

- name: Test import
run: |
mkdir /tmp/testenv
cd /tmp/testenv
python -c "import pyectool; print('pyectool import successful')"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
build/*
*/__pycache__/*
dist/*
35 changes: 0 additions & 35 deletions .gitlab-ci.yml

This file was deleted.

6 changes: 3 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "extern/FrameworkWindowsUtils"]
path = extern/FrameworkWindowsUtils
url = https://github.com/DHowett/FrameworkWindowsUtils
[submodule "src/extern/FrameworkWindowsUtils"]
path = src/extern/FrameworkWindowsUtils
url = https://github.com/DHowett/FrameworkWindowsUtils
59 changes: 59 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# To use:
#
# pre-commit run -a
#
# Or:
#
# pre-commit install # (runs every time you commit in git)
#
# To update this file:
#
# pre-commit autoupdate
#
# See https://github.com/pre-commit/pre-commit

ci:
autoupdate_commit_msg: "chore: update pre-commit hooks"
autofix_commit_msg: "style: pre-commit fixes"

repos:
# Standard hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-merge-conflict
- id: check-symlinks
- id: check-yaml
exclude: ^conda\.recipe/meta\.yaml$
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
- id: requirements-txt-fixer
- id: trailing-whitespace

# Check linting and style issues
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.11.13"
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
- id: ruff-format
exclude: ^(docs)

# Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
hooks:
- id: remove-tabs
exclude: ^(docs)

# CMake formatting
- repo: https://github.com/cheshirekow/cmake-format-precommit
rev: v0.6.13
hooks:
- id: cmake-format
additional_dependencies: [pyyaml]
types: [file]
files: (\.cmake|CMakeLists.txt)(.in)?$
41 changes: 29 additions & 12 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,26 +1,43 @@
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.15...3.27)

if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
endif()
project(
${SKBUILD_PROJECT_NAME}
VERSION ${SKBUILD_PROJECT_VERSION}
LANGUAGES CXX)

# Required for building Python extension modules via pybind11
find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)

project(ECTool
VERSION 1.0.0
DESCRIPTION "ChromeOS EC Tool"
LANGUAGES CXX)
# Find pybind11 (installed via pip/conda or system-wide)
find_package(pybind11 CONFIG REQUIRED)

if(NOT WIN32)
find_package(PkgConfig REQUIRED)
pkg_check_modules(libusb REQUIRED libusb-1.0)
pkg_check_modules(libftdi1 REQUIRED libftdi1)
find_package(PkgConfig REQUIRED)
pkg_check_modules(libusb REQUIRED libusb-1.0)
pkg_check_modules(libftdi1 REQUIRED libftdi1)
else()

endif()

set(CMAKE_CXX_STANDARD 17)

add_subdirectory(src/core)
add_subdirectory(src/bindings)
add_subdirectory(src/extern)

if(WIN32)
add_subdirectory(src/getopt)
add_subdirectory(src/getopt)
endif()

install(
TARGETS ectool libectool libectool_py
RUNTIME DESTINATION pyectool/bin # ectool CLI binary
LIBRARY DESTINATION pyectool # libectool_py.so (shared Python module)
ARCHIVE DESTINATION pyectool/lib # libectool.a (static lib)
)

install(
DIRECTORY src/include/
DESTINATION pyectool/include
FILES_MATCHING
PATTERN "libectool.h")
93 changes: 70 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,80 @@
# libectool
# Pyectool

libectool is a shared library extracted from ectool, providing programmatic access to Embedded Controller (EC) functionalities on ChromeOS and compatible devices.
**Pyectool** is a Python package with C++ bindings for interacting with the Embedded Controller (EC) on ChromeOS and Framework devices. It is extracted from and based on [`ectool`](https://gitlab.howett.net/DHowett/ectool) utility, and exposes EC control functions directly to Python programs via a native extension.

## Features
- Exposes EC control functions via a shared library (`libectool.so`).
- Supports fan control, battery management, temperature monitoring, and more.
- Designed for integration into other applications.
## Features

- Python bindings for EC functionality using `pybind11`.
- Supports fan duty control, temperature reading, AC power status, and more.
- Designed for integration with hardware management or fan control tools.
- Shared core logic with `libectool` for C/C++ integration.

---

## Build & Install (Python Package)

We use [`scikit-build-core`](https://scikit-build-core.readthedocs.io/en/latest/) to build the C++ extension via CMake.

### Prerequisites

Install the required system dependencies:

## Build Instructions
```sh
cd libectool
mkdir build && cd build
cmake ..
cmake --build .
```
## Post Build Instructions
After building, you need to move `libectool.so` to a library directory where it can be found by your system:
sudo apt update
sudo apt install -y libusb-1.0-0-dev libftdi1-dev pkg-config
````
### Clone the repository

### Option 1 — User-specific (Recommended for non-root users)
## Install system-wide
```sh
mkdir -p ~/.local/lib
cp src/core/libectool.so ~/.local/lib/libectool.so
export LD_LIBRARY_PATH="$HOME/.local/lib:$LD_LIBRARY_PATH"
sudo pip install .
```
To make it persistent across sessions, add the export to your shell configuration:
```sh
echo 'export LD_LIBRARY_PATH="$HOME/.local/lib:$LD_LIBRARY_PATH"' >> ~/.bashrc
Or:

```bash
sudo env "PIP_BREAK_SYSTEM_PACKAGES=1" pip install .
```
### Option 2 — Global installation
(Required on modern distros like Ubuntu 24.04 due to PEP 668.)

### Test from outside the repo dir
After installing, **do not run Python from the `libectool/` directory**, since it contains a `pyectool/` folder that may shadow the installed package.

Instead, test from another location, e.g.:

```sh
sudo cp src/core/libectool.so /usr/local/lib/libectool.so
cd ..
sudo python -c "import pyectool; print(pyectool.is_on_ac())"
```

## VENV INSTALLATION

If you **don’t** want to touch system Python:

### Create venv

```bash
python3 -m venv ~/.venv/pyectool
source ~/.venv/pyectool/bin/activate
```

### Install your package

Inside the venv:
```bash
pip install .
```
### Test from outside the repo dir
```bash
cd ..
sudo env "PATH=$PATH" python -c "import pyectool; print(pyectool.is_on_ac())"
```

### Available Functions

| Function | Description |
| ------------------------------------------ | -------------------------------------------------------------------------------- |
| `auto_fan_control()` | Enables automatic fan control by the EC. |
| `get_max_non_battery_temperature() -> float` | Returns the highest temperature (in °C) from all sensors except the battery. |
| `get_max_temperature() -> float` | Returns the highest temperature (in °C) from all EC sensors including battery. |
| `is_on_ac() -> bool` | Checks whether the device is running on AC power. |
| `set_fan_duty(percent: int)` | Sets the fan duty cycle manually (0–100%). |
27 changes: 27 additions & 0 deletions pyectool/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from __future__ import annotations

from .libectool_py import (
__doc__,
__version__,
ascii_mode,
auto_fan_control,
get_max_non_battery_temperature,
get_max_temperature,
init,
is_on_ac,
release,
set_fan_duty,
)

__all__ = [
"__doc__",
"__version__",
"ascii_mode",
"auto_fan_control",
"get_max_non_battery_temperature",
"get_max_temperature",
"init",
"is_on_ac",
"release",
"set_fan_duty",
]
Loading