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
10 changes: 0 additions & 10 deletions .deepsource.toml

This file was deleted.

110 changes: 110 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
name: CI

on:
# Feature branches are covered by the pull_request trigger. Running on their
# pushes as well would duplicate every job on any branch with an open PR, and
# publish a check for the skipped compile job under its unsubstituted matrix
# name. The trade-off is no CI on a branch until its PR is opened.
push:
branches: [master]
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
pre-commit:
name: pre-commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: pre-commit/action@v3.0.1
env:
# Local-only guardrail; being on master is expected in CI.
SKIP: no-commit-to-branch

esphome-config:
name: esphome config
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
# Deliberately unpinned: the point of this job is to catch configs that
# break against the current ESPHome release. Pin here if you need to hold
# the repo at a specific version.
- name: Install ESPHome
run: pip install esphome
- name: Report ESPHome version
run: esphome version
# devices/secrets.yaml is gitignored, so CI generates a placeholder one.
- name: Generate placeholder secrets
run: python scripts/generate_ci_secrets.py
- name: Validate device configs
run: |
status=0
for config in devices/*.yaml; do
if [ "$(basename "$config")" = "secrets.yaml" ]; then
continue
fi
echo "::group::$config"
if ! esphome config "$config" > /dev/null; then
echo "::error file=$config::esphome config failed"
status=1
fi
echo "::endgroup::"
done
exit $status

# Compiling proves the custom C++ components in components/ still build. The
# matrix is the smallest set of devices that covers every custom component,
# across both platforms -- the components are compiled per-platform, so an
# esp32 build says nothing about the esp8266 ones.
esphome-compile:
name: compile ${{ matrix.device }}
runs-on: ubuntu-latest
# Compiles are slow, so skip them on feature-branch pushes; the pull request
# and the post-merge master push both still get a full build.
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/master'
env:
# Cache the ESP-IDF install rather than re-downloading it every run.
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
strategy:
fail-fast: false
matrix:
include:
- device: pool # esp32s3 / esp-idf: pool_controller, pzem6l24
platform: esp32
- device: water-heater # esp32 / esp-idf: high_temp_water_heater
platform: esp32
- device: hvac # esp32 / esp-idf: econet_zone_control
platform: esp32
- device: pool-lights # esp8266: treo_led_pool_light
platform: esp8266
- device: master-bed # esp8266: bed_sensor
platform: esp8266
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Cache PlatformIO and ESP-IDF
uses: actions/cache@v4
with:
path: |
~/.platformio
~/.esphome-idf
key: build-${{ matrix.platform }}-${{ hashFiles('devices/packages/device_base*.yaml') }}
restore-keys: build-${{ matrix.platform }}-
- name: Install ESPHome
run: pip install esphome
- name: Generate placeholder secrets
run: python scripts/generate_ci_secrets.py
- name: Compile ${{ matrix.device }}
run: esphome compile devices/${{ matrix.device }}.yaml
15 changes: 0 additions & 15 deletions .github/workflows/lint.yml

This file was deleted.

16 changes: 13 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ default_install_hook_types:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.15.15
rev: v0.16.0
hooks:
# Run the linter.
- id: ruff
Expand All @@ -27,7 +27,7 @@ repos:
additional_dependencies:
- flake8-docstrings==1.7.0
- pydocstyle==5.1.1
files: ^components/.+\.py$
files: ^(components|scripts)/.+\.py$
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
Expand All @@ -42,7 +42,7 @@ repos:
rev: v3.21.2
hooks:
- id: pyupgrade
args: [--py311-plus]
args: [--py312-plus]
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.37.1
hooks:
Expand All @@ -53,6 +53,16 @@ repos:
hooks:
- id: clang-format
types_or: [c, c++]
- repo: https://github.com/pylint-dev/pylint
rev: v4.0.6
hooks:
- id: pylint
files: ^(components|scripts)/.+\.py$
# esphome must be importable or every `from esphome...` import in the
# custom components resolves to import-error. Deliberately unpinned so
# components are linted against the current release.
additional_dependencies:
- esphome
- repo: local
hooks:
- id: tag-esphome-version
Expand Down
5 changes: 1 addition & 4 deletions components/bed_sensor/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import esphome.codegen as cg
from esphome.components import binary_sensor, output, sensor, text_sensor
import esphome.config_validation as cv
from esphome.components import binary_sensor
from esphome.components import output
from esphome.components import sensor
from esphome.components import text_sensor
from esphome.const import (
CONF_ID,
CONF_OUTPUT,
Expand Down
14 changes: 7 additions & 7 deletions components/pool_controller/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor, time
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_NAME, CONF_TIME_ID

from .const import (
CONF_PRIMARY_PUMP,
CONF_AUXILIARY_PUMPS,
CONF_SEQUENCE_DELAY,
CONF_DISABLE_PUMPS_SENSOR,
CONF_STATE_SAVE_INTERVAL,
CONF_MAX_RESUME_AGE,
CONF_PRIMARY_PUMP,
CONF_SEQUENCE_DELAY,
CONF_STATE_SAVE_INTERVAL,
)
from .schema.types import PoolController
from .schema.heater import CONF_POOL_HEATER, POOL_HEATER_SCHEMA, heater_to_code
from .schema.pump import (
PRIMARY_PUMP_SCHEMA,
AUX_PUMP_SCHEMA,
PRIMARY_PUMP_SCHEMA,
pump_to_code,
schedule_select_to_code,
)
from .schema.heater import CONF_POOL_HEATER, POOL_HEATER_SCHEMA, heater_to_code
from .schema.types import PoolController

AUTO_LOAD = [
"binary_sensor",
Expand Down
3 changes: 2 additions & 1 deletion components/pool_controller/schema/heater.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output, sensor, water_heater
import esphome.config_validation as cv
from esphome.const import CONF_OUTPUT

from .types import PoolHeater

# Constants are defined inline here because they are only used for the pool heater.
Expand Down
69 changes: 38 additions & 31 deletions components/pool_controller/schema/pump.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,69 @@
import uuid

from esphome import automation
import esphome.codegen as cg
from esphome.components import (
binary_sensor,
button,
output,
select as esphome_select,
sensor,
switch as esphome_switch,
text_sensor,
)
import esphome.config_validation as cv
from esphome import automation
from esphome.components import binary_sensor, button, output, sensor, text_sensor
from esphome.components import switch as esphome_switch
from esphome.components import select as esphome_select
from esphome.const import (
CONF_ID,
CONF_NAME,
CONF_OUTPUT,
DEVICE_CLASS_PROBLEM,
CONF_TRIGGER_ID,
DEVICE_CLASS_PROBLEM,
ENTITY_CATEGORY_DIAGNOSTIC,
)

from ..const import (
CONF_SCHEDULES,
CONF_RUNTIMES,
CONF_START_TIME,
CONF_END_TIME,
CONF_MINUTES_PER_HOUR,
CONF_SCHEDULE_SELECT,
CONF_CURRENT_SENSOR,
CONF_ANOMALY_DETECTION_SWITCH,
CONF_ANOMALY_BASELINE_RESET_BUTTON,
CONF_ANOMALY_STATUS_BINARY_SENSOR,
CONF_ANOMALY_DETECTION_SWITCH,
CONF_ANOMALY_REASON_TEXT_SENSOR,
CONF_ANOMALY_STATUS_BINARY_SENSOR,
CONF_ANOMALY_THRESHOLD_PCT,
CONF_LEARNING_SAMPLES,
CONF_ON_ANOMALY,
CONF_CURRENT_ON_THRESHOLD,
CONF_NO_CURRENT_BINARY_SENSOR,
CONF_CURRENT_TIMEOUT,
CONF_CURRENT_SENSOR,
CONF_CURRENT_STALE_BINARY_SENSOR,
CONF_CURRENT_TIMEOUT,
CONF_END_TIME,
CONF_FLOW_LOSS_BINARY_SENSOR,
CONF_FLOW_SENSOR,
CONF_FLOW_TIMEOUT,
CONF_FLOW_LOSS_BINARY_SENSOR,
CONF_LEARNING_SAMPLES,
CONF_MINUTES_PER_HOUR,
CONF_NO_CURRENT_BINARY_SENSOR,
CONF_ON_ANOMALY,
CONF_RUNTIMES,
CONF_SCHEDULE_SELECT,
CONF_SCHEDULES,
CONF_START_TIME,
CONF_UNEXPECTED_FLOW_BINARY_SENSOR,
)
from .schedule import (
SCHEDULE_SCHEMA,
_days_to_mask,
_time_to_minutes,
_validate_unique_schedule_names,
)
from .types import (
ScheduleSelect,
PrimaryPumpSwitch,
AuxiliaryPumpSwitch,
PumpAnomalySwitch,
PumpAnomalyStatusBinarySensor,
PrimaryPumpSwitch,
PumpAnomalyReasonTextSensor,
PumpAnomalyResetButton,
PumpNoCurrentBinarySensor,
PumpAnomalyStatusBinarySensor,
PumpAnomalySwitch,
PumpAnomalyTrigger,
PumpCurrentStaleBinarySensor,
PumpFlowLossBinarySensor,
PumpNoCurrentBinarySensor,
PumpUnexpectedFlowBinarySensor,
PumpAnomalyTrigger,
)
from .schedule import (
SCHEDULE_SCHEMA,
_validate_unique_schedule_names,
_time_to_minutes,
_days_to_mask,
ScheduleSelect,
)

DEFAULT_ANOMALY_DETECTION_SWITCH_PREFIX = (
Expand Down
33 changes: 16 additions & 17 deletions components/pool_controller/schema/schedule.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import esphome.config_validation as cv
from esphome.components.time import validate_cron_days_of_week
import esphome.config_validation as cv
from esphome.const import (
CONF_DAYS_OF_WEEK,
CONF_HOUR,
CONF_MINUTE,
CONF_NAME,
CONF_SECOND,
)
from ..const import (
CONF_END_TIME,
CONF_MINUTES_PER_HOUR,
CONF_RUNTIMES,
CONF_START_TIME,
)

from ..const import CONF_END_TIME, CONF_MINUTES_PER_HOUR, CONF_RUNTIMES, CONF_START_TIME


def _time_to_minutes(time_val):
Expand Down Expand Up @@ -84,21 +80,24 @@ def _validate_runtime(runtime):
def _validate_no_runtime_overlaps(schedule):
"""Validate that no two runtimes in the same schedule overlap on the same days."""
runtimes = schedule[CONF_RUNTIMES]
for i in range(len(runtimes)):
for i, a in enumerate(runtimes):
for j in range(i + 1, len(runtimes)):
a, b = runtimes[i], runtimes[j]
b = runtimes[j]
a_start = _time_to_minutes(a[CONF_START_TIME])
a_end = _time_to_minutes(a[CONF_END_TIME])
b_start = _time_to_minutes(b[CONF_START_TIME])
b_end = _time_to_minutes(b[CONF_END_TIME])
if a_start < b_end and b_start < a_end:
if _runtime_days(a) & _runtime_days(b):
raise cv.Invalid(
f"Runtime {i} ({_time_to_str(a[CONF_START_TIME])}-"
f"{_time_to_str(a[CONF_END_TIME])}) overlaps with "
f"runtime {j} ({_time_to_str(b[CONF_START_TIME])}-"
f"{_time_to_str(b[CONF_END_TIME])}) on shared days"
)
if (
a_start < b_end
and b_start < a_end
and _runtime_days(a) & _runtime_days(b)
):
raise cv.Invalid(
f"Runtime {i} ({_time_to_str(a[CONF_START_TIME])}-"
f"{_time_to_str(a[CONF_END_TIME])}) overlaps with "
f"runtime {j} ({_time_to_str(b[CONF_START_TIME])}-"
f"{_time_to_str(b[CONF_END_TIME])}) on shared days"
)
return schedule


Expand Down
Loading
Loading