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
188 changes: 188 additions & 0 deletions .github/workflows/test_maidesite_desk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
name: Test Maidesite Desk Component

permissions:
contents: read
packages: read

on:
push:
branches:
- main
- 'desk**'
paths:
- 'components/maidesite_desk/**'
- 'tests/maidesite_desk/**'
- '.github/workflows/test_maidesite_desk.yml'
pull_request:
branches:
- main
paths:
- 'components/maidesite_desk/**'
- 'tests/maidesite_desk/**'
- '.github/workflows/test_maidesite_desk.yml'
workflow_dispatch:

jobs:
test-build:
name: Test ESPHome Build
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
board: [esp32s2, esp32c3, full]
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Build ESPHome firmware for ${{ matrix.board }}
uses: esphome/build-action@v7
with:
yaml-file: tests/maidesite_desk/test_maidesite_desk_${{ matrix.board == 'full' && 'full' || matrix.board }}.yaml
version: latest

lint-code:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
name: Lint C++ Code
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install clang-format
run: |
sudo apt-get update
sudo apt-get install -y clang-format

- name: Run clang-format check
run: |
find components/maidesite_desk -name '*.cpp' -o -name '*.h' | \
xargs clang-format -style=file --dry-run --Werror

lint-python:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
name: Lint Python Code
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install linting tools
run: |
pip install --upgrade pip
pip install flake8 pylint black

- name: Run black check
run: |
black --check components/maidesite_desk/

- name: Run flake8
run: |
flake8 components/maidesite_desk/ --count --select=E9,F63,F7,F82 --show-source --statistics
flake8 components/maidesite_desk/ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

test-python:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
name: Python Unit Tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install dependencies
run: |
pip install --upgrade pip
pip install pytest pytest-cov esphome

- name: Run Python unit tests
run: |
pytest tests/maidesite_desk/ -v --cov=components/maidesite_desk --cov-report=xml --cov-report=term

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
flags: unittests
name: codecov-maidesite-desk
fail_ci_if_error: false

test-minimal-config:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
name: Test Minimal Configuration
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install ESPHome
run: |
pip install --upgrade pip
pip install esphome

- name: Validate minimal config
run: |
esphome config tests/maidesite_desk/test_maidesite_desk_mini.yaml

test-full-config:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
name: Test Full Configuration
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install ESPHome
run: |
pip install --upgrade pip
pip install esphome

- name: Validate full config
run: |
esphome config tests/maidesite_desk/test_maidesite_desk_full.yaml

summary:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
name: Test Summary
runs-on: ubuntu-latest
timeout-minutes: 5
needs: [test-build, lint-code, lint-python, test-python, test-minimal-config, test-full-config]
if: always()
steps:
- name: Check test results
run: |
echo "Test Build: ${{ needs.test-build.result }}"
echo "Lint C++: ${{ needs.lint-code.result }}"
echo "Lint Python: ${{ needs.lint-python.result }}"
echo "Python Unit Tests: ${{ needs.test-python.result }}"
echo "Minimal Config: ${{ needs.test-minimal-config.result }}"
echo "Full Config: ${{ needs.test-full-config.result }}"

if [ "${{ needs.test-build.result }}" != "success" ] || \
[ "${{ needs.lint-code.result }}" != "success" ] || \
[ "${{ needs.lint-python.result }}" != "success" ] || \
[ "${{ needs.test-python.result }}" != "success" ] || \
[ "${{ needs.test-minimal-config.result }}" != "success" ] || \
[ "${{ needs.test-full-config.result }}" != "success" ]; then
echo "One or more tests failed"
exit 1
fi
echo "All tests passed successfully!"
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
1 change: 0 additions & 1 deletion components/maidesite_desk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import uart
from esphome.const import CONF_ID

Expand Down
32 changes: 32 additions & 0 deletions components/maidesite_desk/maidesite_desk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,17 +98,25 @@ void MaidesiteDeskComponent::decode_response(std::vector<uint8_t> message) {
if (new_height == this->current_height_)
return;
this->current_height_ = new_height;
#ifdef USE_SENSOR
if (this->height_abs_sensor_ != nullptr)
this->height_abs_sensor_->publish_state(this->current_height_);
#endif
#ifdef USE_NUMBER
if (this->height_abs_number_ != nullptr)
this->height_abs_number_->publish_state(this->current_height_);
#endif

#ifdef USE_SENSOR
if (this->height_pct_sensor_ != nullptr && limit_max_ != 0)
this->height_pct_sensor_->publish_state((this->current_height_ - this->limit_min_) /
(this->limit_max_ - this->limit_min_) * 100);
#endif
#ifdef USE_NUMBER
if (this->height_pct_number_ != nullptr && limit_max_ != 0)
this->height_pct_number_->publish_state(
roundf((this->current_height_ - this->limit_min_) / (this->limit_max_ - this->limit_min_) * 1000) / 10);
#endif
break;

case 0x20:
Expand All @@ -117,17 +125,25 @@ void MaidesiteDeskComponent::decode_response(std::vector<uint8_t> message) {

if ((message[4] & 1) == 0) { // low nibble 0 -> no max limit, use physical_max_
this->limit_max_ = this->physical_max_;
#ifdef USE_SENSOR
if (this->height_max_sensor_ != nullptr)
this->height_max_sensor_->publish_state(this->limit_max_);
#endif
#ifdef USE_NUMBER
if (height_abs_number_ != nullptr)
this->height_abs_number_->traits.set_max_value(this->limit_max_);
#endif
}
if ((message[4] >> 4) == 0) { // high nibble 0 -> no min limit, use physical_min_
this->limit_min_ = this->physical_min_;
#ifdef USE_SENSOR
if (this->height_min_sensor_ != nullptr)
this->height_min_sensor_->publish_state(limit_min_);
#endif
#ifdef USE_NUMBER
if (height_abs_number_ != nullptr)
this->height_abs_number_->traits.set_min_value(limit_min_);
#endif
}
break;

Expand All @@ -145,53 +161,69 @@ void MaidesiteDeskComponent::decode_response(std::vector<uint8_t> message) {
delay(10);

this->limit_max_ = this->byte2float(message[4], message[5]);
#ifdef USE_SENSOR
if (this->height_max_sensor_ != nullptr)
this->height_max_sensor_->publish_state(limit_max_);
#endif
#ifdef USE_NUMBER
if (height_abs_number_ != nullptr)
this->height_abs_number_->traits.set_max_value(limit_max_);
#endif
break;

case 0x22:
ESP_LOGI(TAG, "Set min. height to 0x%02X%02X", message[4], message[5]);
delay(10);

this->limit_min_ = this->byte2float(message[4], message[5]);
#ifdef USE_SENSOR
if (this->height_min_sensor_ != nullptr)
this->height_min_sensor_->publish_state(limit_min_);
#endif
#ifdef USE_NUMBER
if (height_abs_number_ != nullptr)
this->height_abs_number_->traits.set_min_value(limit_min_);
#endif
break;

case 0x25:
ESP_LOGI(TAG, "Set position m1 to 0x%02X%02X", message[4], message[5]);
delay(10);

#ifdef USE_SENSOR
if (this->position_m1_sensor_ != nullptr)
this->position_m1_sensor_->publish_state(this->byte2float(message[4], message[5]));
#endif
break;

case 0x26:
ESP_LOGI(TAG, "Set position m2 to 0x%02X%02X", message[4], message[5]);
delay(10);

#ifdef USE_SENSOR
if (this->position_m2_sensor_ != nullptr)
this->position_m2_sensor_->publish_state(this->byte2float(message[4], message[5]));
#endif
break;

case 0x27:
ESP_LOGI(TAG, "Set position m3 to 0x%02X%02X", message[4], message[5]);
delay(10);

#ifdef USE_SENSOR
if (this->position_m3_sensor_ != nullptr)
this->position_m3_sensor_->publish_state(this->byte2float(message[4], message[5]));
#endif
break;

case 0x28:
ESP_LOGI(TAG, "Set position m4 to 0x%02X%02X", message[4], message[5]);
delay(10);

#ifdef USE_SENSOR
if (this->position_m4_sensor_ != nullptr)
this->position_m4_sensor_->publish_state(this->byte2float(message[4], message[5]));
#endif
break;

// case 0x0E:
Expand Down
74 changes: 74 additions & 0 deletions tests/maidesite_desk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Testing Documentation for Maidesite Desk Component

This directory contains comprehensive tests for the `maidesite_desk` ESPHome component.

## Test Structure

### Unit Tests (`test_maidesite_desk_unit.py`)

- Tests Python configuration validation
- Tests component metadata (CODEOWNERS, DEPENDENCIES, etc.)
- Tests configuration schema structure
- Tests all platform imports (sensor, number, button)
- Tests code generation logic

### Integration Tests (`test_maidesite_desk_integration.py`)

- Tests minimal feature configuration on ESP32 board
- Tests full feature configuration on ESP32 board
- Tests configuration on ESP32-S2 board
- Tests configuration on ESP32-C3 board

### Test Configuration Files

- `test_maidesite_desk_esp32s2.yaml` - ESP32-S2 Wemos S2 Mini
- `test_maidesite_desk_esp32c3.yaml` - ESP32-C3 mini (RISC-V)
- `test_maidesite_desk_mini.yaml` - Minimal ESP32 configuration for basic testing
- `test_maidesite_desk_full.yaml` - Comprehensive ESP32 configuration with all features

## Running Tests Locally

### Prerequisites

```bash
pip install -r ../requirements.txt
```

### Run All Tests

```bash
pytest tests/maidesite_desk/ -v
```

### Run Only Unit Tests

```bash
pytest tests/maidesite_desk/test_maidesite_desk_unit.py -v
```

### Run Only Integration Tests

```bash
pytest tests/maidesite_desk/test_maidesite_desk_integration.py -v
```

### Run with Coverage

```bash
pytest tests/maidesite_desk/ --cov=components.maidesite_desk --cov-report=html
```

## Test Coverage

The test suite covers:

- Component configuration validation
- All sensor entities (height_abs, height_pct, height_min, height_max, position_m1-m4)
- All number entities (height_abs, height_pct)
- All button entities (stop, step_up, step_down, goto_max, goto_min, goto_m1-m4, save_m1-m4)
- Multiple ESP32 board variants (ESP32, ESP32-S2, ESP32-C3)
- Minimal and full configuration scenarios

## CI/CD Integration

These tests are designed to run in GitHub Actions CI/CD pipelines. See `.github/workflows/test_maidesite_desk.yml` for the workflow configuration.
Loading
Loading