Compare commits

..
22 Commits
Author SHA1 Message Date
semantic-release f12371e519 chore(release): v1.0.16
Update Version / Update Version (push) Successful in 5s
2026-07-10 09:09:57 +00:00
sirmrak eae1c9cef2 fix: Test new secrets
Update Version / Update Version (push) Successful in 6s
2026-07-10 12:09:50 +03:00
semantic-release 8dff505bb4 chore(release): v1.0.15
Update Version / Update Version (push) Successful in 5s
2026-07-10 06:49:05 +00:00
sirmrak 342a98327d fix: lux_cooldown_active
Update Version / Update Version (push) Successful in 7s
2026-07-10 09:48:56 +03:00
sirmrak d10e83c750 Добавить LICENSE
Update Version / Update Version (push) Successful in 5s
2026-07-09 22:28:37 +03:00
semantic-release 0deb61f920 chore(release): v1.0.14
Update Version / Update Version (push) Successful in 5s
2026-07-09 19:22:51 +00:00
sirmrak 563095cbcf fix: Удалены переводы атрибутов из custom_components/motion_light/translations
Update Version / Update Version (push) Successful in 6s
2026-07-09 22:22:43 +03:00
sirmrak 952feac482 fixЖ перевод атрибутов удален
Update Version / Update Version (push) Successful in 5s
2026-07-09 22:20:23 +03:00
sirmrak 7c229b37f2 Обновить custom_components/motion_light/translations/ru.json
Update Version / Update Version (push) Successful in 5s
2026-07-09 22:11:42 +03:00
sirmrak 19546a12e6 Обновить custom_components/motion_light/translations/en.json
Update Version / Update Version (push) Successful in 5s
2026-07-09 22:09:15 +03:00
sirmrak 7b9b1030f2 Обновить custom_components/motion_light/translations/en.json
Update Version / Update Version (push) Successful in 5s
2026-07-09 22:08:45 +03:00
sirmrak 13df970b21 Обновить custom_components/motion_light/manifest.json
Update Version / Update Version (push) Successful in 5s
2026-07-09 22:05:41 +03:00
semantic-release 8069a5d635 chore(release): v1.0.13
Update Version / Update Version (push) Successful in 5s
2026-07-09 19:00:28 +00:00
sirmrak 356b61e6e6 fix: Test validation
Update Version / Update Version (push) Successful in 6s
2026-07-09 22:00:19 +03:00
sirmrak 3b93a6a16b Добавление тестов
Update Version / Update Version (push) Successful in 5s
2026-07-09 21:59:37 +03:00
semantic-release aa7eb0a9d9 chore(release): v1.0.12
Update Version / Update Version (push) Successful in 5s
2026-07-09 18:47:22 +00:00
sirmrak 0888c63b80 fix: test
Update Version / Update Version (push) Successful in 5s
2026-07-09 21:47:14 +03:00
sirmrak c6e7b332cf Обновить .gitea/workflows/update_version.yml
Update Version / Update Version (push) Successful in 5s
2026-07-09 21:45:52 +03:00
semantic-release 7b4fdfe629 chore(release): v1.0.11
Update Version / Update Version (push) Successful in 5s
2026-07-09 18:35:55 +00:00
sirmrak 15dd7e3880 fix: Test
Update Version / Update Version (push) Failing after 6s
2026-07-09 21:35:49 +03:00
sirmrak 28811370e9 Обновить .gitea/workflows/update_version.yml
Update Version / Update Version (push) Successful in 5s
2026-07-09 21:35:26 +03:00
sirmrak a1fca2f4d1 Обновить pyproject.toml
Update Version / Update Version (push) Successful in 6s
2026-07-09 21:34:44 +03:00
10 changed files with 381 additions and 213 deletions
+27 -3
View File
@@ -13,7 +13,6 @@ jobs:
update-version:
name: Update Version
runs-on: ubuntu-latest
# Пропускаем workflow если коммит от бота
if: github.actor != 'gitea-actions[bot]' && github.actor != 'Gitea Actions Bot'
permissions:
contents: write
@@ -41,5 +40,30 @@ jobs:
- name: Run semantic-release
env:
GITEA_TOKEN: ${{ secrets.PAT_TOKEN }}
PYTHONHTTPSVERIFY: "0"
run: semantic-release version
run: |
echo "🧹 Сбрасываем конфликтующие переменные Gitea Actions..."
unset GITHUB_SERVER_URL
unset GITHUB_API_URL
unset GITHUB_REPOSITORY
echo "🔐 Записываем оригинальный Root CA от mkcert из секретов..."
echo "${{ secrets.LOCAL_ROOT_CA }}" > /tmp/rootCA.crt
# Проверка на случай, если секрет забыли настроить
if [ ! -s /tmp/rootCA.crt ]; then
echo "❌ Ошибка: Секрет LOCAL_ROOT_CA пуст. Проверьте настройки репозитория!"
exit 1
fi
echo "✅ Root CA успешно прочитан."
# Находим, где конкретно Python (библиотека certifi) хранит свои сертификаты
CERTIFI_PATH=$(python3 -c "import certifi; print(certifi.where())")
echo "Путь к bundle Python: $CERTIFI_PATH"
# Внедряем корневой сертификат mkcert в конец доверенного списка Python
cat /tmp/rootCA.crt >> "$CERTIFI_PATH"
echo "✅ Root CA от mkcert добавлен в доверенные для Python!"
echo "🚀 Запускаем semantic-release..."
semantic-release version
+94 -8
View File
@@ -1,14 +1,87 @@
name: Create Release
name: Test and Release
on:
push:
tags:
- 'v*'
workflow_dispatch: # Позволяет запускать вручную
jobs:
release:
name: Create GitHub Release
# Шаг 1: Валидация структуры HA интеграции
validate:
name: Validate Integration
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Hassfest Validation
uses: home-assistant/actions/hassfest@master
- name: HACS Validation
uses: hacs/action@main
with:
category: "integration"
# Шаг 2: Запуск тестов (если есть)
test:
name: Run Tests
runs-on: ubuntu-latest
needs: validate
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: |
python -m pip install --upgrade pip
pip install pytest pytest-homeassistant-custom-component
if [ -f requirements_test.txt ]; then pip install -r requirements_test.txt; fi
- name: Run tests
run: |
if [ -d "tests" ]; then
pytest tests/ --cov=custom_components/motion_light --cov-report=xml
else
echo "No tests directory found, skipping tests"
fi
# Шаг 3: Проверка стиля кода
lint:
name: Code Quality
runs-on: ubuntu-latest
needs: validate
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install linters
run: |
pip install black ruff mypy
- name: Check code formatting with black
run: |
black --check custom_components/motion_light/ || echo "Code formatting issues found"
- name: Check code with ruff
run: |
ruff check custom_components/motion_light/ || echo "Ruff issues found"
# Шаг 4: Создание релиза (только если все проверки пройдены)
release:
name: Create Release
runs-on: ubuntu-latest
needs: [validate, test, lint]
permissions:
contents: write
@@ -24,9 +97,16 @@ jobs:
TAG=${GITHUB_REF#refs/tags/}
echo "tag=$TAG" >> $GITHUB_OUTPUT
TAG_MSG=$(git tag -l --format='%(contents)' $TAG 2>/dev/null || git log -1 --pretty=%B)
echo "message<<EOF" >> $GITHUB_OUTPUT
echo "$TAG_MSG" >> $GITHUB_OUTPUT
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
COMMITS=$(git log --pretty=format:"- %s" --reverse)
else
COMMITS=$(git log ${PREV_TAG}..HEAD --pretty=format:"- %s" --reverse)
fi
echo "commits<<EOF" >> $GITHUB_OUTPUT
echo "$COMMITS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create GitHub Release
@@ -34,13 +114,19 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ steps.tag.outputs.tag }}"
MSG="${{ steps.tag.outputs.message }}"
COMMITS="${{ steps.tag.outputs.commits }}"
echo "🚀 Создаём релиз $TAG в GitHub..."
cat > /tmp/release_notes.md << EOF
## Изменения в версии $TAG
$COMMITS
EOF
gh release create "$TAG" \
--title "Release $TAG" \
--notes "$MSG" \
--notes-file /tmp/release_notes.md \
--target main
echo "✅ Релиз создан!"
+48
View File
@@ -2,6 +2,54 @@
<!-- version list -->
## v1.0.16 (2026-07-10)
### Bug Fixes
- Test new secrets
([`eae1c9c`](https://192.168.200.208:3000/sirmrak/motion_light/commit/eae1c9cef21aa9285a6e5b2174949b6bf2942154))
## v1.0.15 (2026-07-10)
### Bug Fixes
- Lux_cooldown_active
([`342a983`](https://192.168.200.208:3000/sirmrak/motion_light/commit/342a98327d2297977323e12f84e0dc9bc8b3a49d))
## v1.0.14 (2026-07-09)
### Bug Fixes
- Удалены переводы атрибутов из custom_components/motion_light/translations
([`563095c`](https://192.168.200.208:3000/sirmrak/motion_light/commit/563095cbcf77d22d02a7176faf5aec6837d18b37))
## v1.0.13 (2026-07-09)
### Bug Fixes
- Test validation
([`356b61e`](https://192.168.200.208:3000/sirmrak/motion_light/commit/356b61e6e618a423503d44d2f0d9ef96fee0da0d))
## v1.0.12 (2026-07-09)
### Bug Fixes
- Test
([`0888c63`](https://192.168.200.208:3000/sirmrak/motion_light/commit/0888c63b804be1e5bedd7e72fbfd142dd4f88287))
## v1.0.11 (2026-07-09)
### Bug Fixes
- Test
([`15dd7e3`](https://192.168.200.208:3000/sirmrak/motion_light/commit/15dd7e3880dad782f502eb70db6aa8ca23f803bc))
## v1.0.10 (2026-07-09)
### Bug Fixes
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 sirmrak
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+1 -1
View File
@@ -1,4 +1,4 @@
"""The Motion Light integration. Test"""
"""The Motion Light integration."""
import logging
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
+18 -2
View File
@@ -619,6 +619,20 @@ class MotionLightCoordinator(DataUpdateCoordinator):
"state": self._state,
"attributes": self.attributes,
})
def _cancel_lux_cooldown(self):
"""Cancel lux cooldown when light is turned on."""
if self._lux_cooldown_active:
self.logger.debug("Cancelling lux cooldown")
self._lux_cooldown_active = False
if self._lux_cooldown_timer:
self._lux_cooldown_timer()
self._lux_cooldown_timer = None
self.async_set_updated_data({
"state": self._state,
"attributes": self.attributes,
})
@callback
def _check_lux_periodically(self, _=None):
"""Check lux periodically."""
@@ -655,7 +669,8 @@ class MotionLightCoordinator(DataUpdateCoordinator):
if not self._is_any_sensor_active():
self.logger.debug("No sensors active, not turning on")
return
self._cancel_lux_cooldown()
triggered_by = self._attributes.get("triggered_by")
await self._turn_on_switches()
await self._update_state(STATE_ON, triggered_by=triggered_by)
@@ -670,7 +685,7 @@ class MotionLightCoordinator(DataUpdateCoordinator):
await self._update_state(STATE_IDLE)
self._start_lux_check_timer()
return
self._cancel_lux_cooldown()
triggered_by = self._attributes.get("triggered_by")
await self._turn_on_switches()
await self._update_state(STATE_ON, triggered_by=triggered_by)
@@ -735,6 +750,7 @@ class MotionLightCoordinator(DataUpdateCoordinator):
async def _enter_manual_on(self):
"""Enter manual_on state."""
self._cancel_lux_cooldown()
await self._update_state(STATE_MANUAL_ON)
if self.manual_idle_timeout > 0:
self._reset_manual_idle_timer()
+10 -10
View File
@@ -1,12 +1,12 @@
{
"domain": "motion_light",
"name": "Motion Light",
"version": "1.0.10",
"documentation": "https://github.com/sirmrak/motion_light",
"issue_tracker": "https://github.com/sirmrak/motion_light/issues",
"dependencies": [],
"codeowners": ["@sirmrak"],
"requirements": [],
"iot_class": "local_push",
"config_flow": true
"domain": "motion_light",
"name": "Motion Light",
"codeowners": ["@sirmrak"],
"config_flow": true,
"dependencies": [],
"documentation": "https://github.com/sirmrak/motion_light",
"iot_class": "local_push",
"issue_tracker": "https://github.com/sirmrak/motion_light/issues",
"requirements": [],
"version": "1.0.16"
}
@@ -1,101 +1,85 @@
{
"config": {
"step": {
"user": {
"title": "Motion Light",
"description": "Motion-based lighting control setup",
"data": {
"name": "Name",
"main_sensors": "Main triggers",
"extend_sensors": "Extend sensors (optional)",
"switch_entities": "Controlled switches",
"lux_sensor": "Illuminance sensor (optional)",
"force_stop_sensor": "Force stop sensor (optional)",
"force_stop_state": "Force stop sensor state",
"log_level": "Log level"
"config": {
"step": {
"user": {
"title": "Motion Light",
"description": "Motion-based lighting control setup",
"data": {
"name": "Name",
"main_sensors": "Main triggers",
"extend_sensors": "Extend sensors (optional)",
"switch_entities": "Controlled switches",
"lux_sensor": "Illuminance sensor (optional)",
"force_stop_sensor": "Force stop sensor (optional)",
"force_stop_state": "Force stop sensor state",
"log_level": "Log level"
}
}
}
}
}
},
"options": {
"step": {
"init": {
"title": "Motion Light Options",
"description": "Change integration parameters",
"data": {
"main_sensors": "Main triggers",
"extend_sensors": "Extend sensors (optional)",
"switch_entities": "Controlled switches",
"lux_sensor": "Illuminance sensor (optional)",
"force_stop_sensor": "Force stop sensor (optional)",
"force_stop_state": "Force stop sensor state",
"log_level": "Log level"
}
}
}
},
"entity": {
"switch": {
"motion_light_enabled": {
"name": "Control"
},
"motion_light_priority_manual": {
"name": "Manual priority"
}
},
"sensor": {
"motion_light_status": {
"name": "Status",
"state": {
"idle": "Idle",
"detecting": "Detecting",
"on": "On",
"delaying": "Delaying",
"active": "Extended",
"off": "Off",
"manual_on": "Manual on",
"manual_off_cooldown": "Manual off cooldown",
"force_stopped": "Force stopped",
"error": "Error",
"disabled": "Disabled"
"options": {
"step": {
"init": {
"title": "Motion Light Options",
"description": "Change integration parameters",
"data": {
"main_sensors": "Main triggers",
"extend_sensors": "Extend sensors (optional)",
"switch_entities": "Controlled switches",
"lux_sensor": "Illuminance sensor (optional)",
"force_stop_sensor": "Force stop sensor (optional)",
"force_stop_state": "Force stop sensor state",
"log_level": "Log level"
}
}
}
},
"entity": {
"switch": {
"motion_light_enabled": {
"name": "Control"
},
"motion_light_priority_manual": {
"name": "Manual priority"
}
},
"attributes": {
"switch_entities": "Controlled switches",
"main_sensors": "Main triggers",
"extend_sensors": "Extend sensors",
"lux_sensor": "Illuminance sensor",
"force_stop_sensor": "Force stop sensor",
"force_stop_state": "Force stop state",
"force_stop_active": "Force stop active",
"active_main_sensors": "Active main triggers",
"active_extend_sensors": "Active extend sensors",
"lux_value": "Current illuminance",
"lux_cooldown_active": "Lux cooldown active",
"lux_check_active": "Lux check active",
"triggered_by": "Triggered by",
"last_motion_time": "Last motion time"
"sensor": {
"motion_light_status": {
"name": "Status",
"state": {
"idle": "Idle",
"detecting": "Detecting",
"on": "On",
"delaying": "Delaying",
"active": "Extended",
"off": "Off",
"manual_on": "Manual on",
"manual_off_cooldown": "Manual off cooldown",
"force_stopped": "Force stopped",
"error": "Error",
"disabled": "Disabled"
}
}
},
"number": {
"motion_light_motion_filter": {
"name": "Motion filter"
},
"motion_light_off_delay": {
"name": "Off delay"
},
"motion_light_lux_threshold": {
"name": "Lux threshold"
},
"motion_light_lux_cooldown": {
"name": "Lux cooldown"
},
"motion_light_manual_idle_timeout": {
"name": "'Forgot to turn off' timer"
},
"motion_light_manual_off_cooldown": {
"name": "Manual off cooldown"
}
}
}
},
"number": {
"motion_light_motion_filter": {
"name": "Motion filter"
},
"motion_light_off_delay": {
"name": "Off delay"
},
"motion_light_lux_threshold": {
"name": "Lux threshold"
},
"motion_light_lux_cooldown": {
"name": "Lux cooldown"
},
"motion_light_manual_idle_timeout": {
"name": "'Forgot to turn off' timer"
},
"motion_light_manual_off_cooldown": {
"name": "Manual off cooldown"
}
}
}
}
@@ -1,101 +1,85 @@
{
"config": {
"step": {
"user": {
"title": "Motion Light",
"description": "Настройка управления освещением по движению",
"data": {
"name": "Название",
"main_sensors": "Главные триггеры",
"extend_sensors": "Датчики продления (опционально)",
"switch_entities": "Управляемые выключатели",
"lux_sensor": "Датчик освещённости (опционально)",
"force_stop_sensor": "Датчик принудительной остановки (опционально)",
"force_stop_state": "Состояние датчика принудительной остановки",
"log_level": "Уровень логирования"
"config": {
"step": {
"user": {
"title": "Motion Light",
"description": "Настройка управления освещением по движению",
"data": {
"name": "Название",
"main_sensors": "Главные триггеры",
"extend_sensors": "Датчики продления (опционально)",
"switch_entities": "Управляемые выключатели",
"lux_sensor": "Датчик освещённости (опционально)",
"force_stop_sensor": "Датчик принудительной остановки (опционально)",
"force_stop_state": "Состояние датчика принудительной остановки",
"log_level": "Уровень логирования"
}
}
}
}
}
},
"options": {
"step": {
"init": {
"title": "Настройки Motion Light",
"description": "Изменение параметров интеграции",
"data": {
"main_sensors": "Главные триггеры",
"extend_sensors": "Датчики продления (опционально)",
"switch_entities": "Управляемые выключатели",
"lux_sensor": "Датчик освещённости (опционально)",
"force_stop_sensor": "Датчик принудительной остановки (опционально)",
"force_stop_state": "Состояние датчика принудительной остановки",
"log_level": "Уровень логирования"
}
}
}
},
"entity": {
"switch": {
"motion_light_enabled": {
"name": "Управление"
},
"motion_light_priority_manual": {
"name": "Приоритет ручного"
}
},
"sensor": {
"motion_light_status": {
"name": "Статус",
"state": {
"idle": "Ожидание",
"detecting": "Обнаружение",
"on": "Включено",
"delaying": "Задержка выключения",
"active": "Продлено",
"off": "Выключено",
"manual_on": "Ручное включение",
"manual_off_cooldown": "Пауза после ручного выкл.",
"force_stopped": "Принудительная остановка",
"error": "Ошибка",
"disabled": "Отключено"
"options": {
"step": {
"init": {
"title": "Настройки Motion Light",
"description": "Изменение параметров интеграции",
"data": {
"main_sensors": "Главные триггеры",
"extend_sensors": "Датчики продления (опционально)",
"switch_entities": "Управляемые выключатели",
"lux_sensor": "Датчик освещённости (опционально)",
"force_stop_sensor": "Датчик принудительной остановки (опционально)",
"force_stop_state": "Состояние датчика принудительной остановки",
"log_level": "Уровень логирования"
}
}
}
},
"entity": {
"switch": {
"motion_light_enabled": {
"name": "Управление"
},
"motion_light_priority_manual": {
"name": "Приоритет ручного"
}
},
"attributes": {
"switch_entities": "Управляемые выключатели",
"main_sensors": "Главные триггеры",
"extend_sensors": "Датчики продления",
"lux_sensor": "Датчик освещённости",
"force_stop_sensor": "Датчик принудительной остановки",
"force_stop_state": "Состояние принудительной остановки",
"force_stop_active": "Принудительная остановка активна",
"active_main_sensors": "Активные главные триггеры",
"active_extend_sensors": "Активные датчики продления",
"lux_value": "Текущая освещённость",
"lux_cooldown_active": "Cooldown люкса активен",
"lux_check_active": "Проверка люкса активна",
"triggered_by": "Активировано",
"last_motion_time": "Последнее движение"
"sensor": {
"motion_light_status": {
"name": "Статус",
"state": {
"idle": "Ожидание",
"detecting": "Обнаружение",
"on": "Включено",
"delaying": "Задержка выключения",
"active": "Продлено",
"off": "Выключено",
"manual_on": "Ручное включение",
"manual_off_cooldown": "Пауза после ручного выкл.",
"force_stopped": "Принудительная остановка",
"error": "Ошибка",
"disabled": "Отключено"
}
}
},
"number": {
"motion_light_motion_filter": {
"name": "Фильтр движения"
},
"motion_light_off_delay": {
"name": "Задержка выключения"
},
"motion_light_lux_threshold": {
"name": "Порог освещённости"
},
"motion_light_lux_cooldown": {
"name": "Cooldown люкса"
},
"motion_light_manual_idle_timeout": {
"name": "Таймер 'забыл выключить'"
},
"motion_light_manual_off_cooldown": {
"name": "Cooldown ручного выкл."
}
}
}
},
"number": {
"motion_light_motion_filter": {
"name": "Фильтр движения"
},
"motion_light_off_delay": {
"name": "Задержка выключения"
},
"motion_light_lux_threshold": {
"name": "Порог освещённости"
},
"motion_light_lux_cooldown": {
"name": "Cooldown люкса"
},
"motion_light_manual_idle_timeout": {
"name": "Таймер 'забыл выключить'"
},
"motion_light_manual_off_cooldown": {
"name": "Cooldown ручного выкл."
}
}
}
}
+6 -1
View File
@@ -7,9 +7,14 @@ version_variables = [
commit_message = "chore(release): v{version}"
# ВАЖНО: не создавать релиз через API
# ВАЖНО: не создаём релиз в Gitea (релиз будет в GitHub)
upload_to_vcs_release = false
[tool.semantic_release.remote]
type = "gitea"
domain = "192.168.200.208:3000"
api_domain = "192.168.200.208:3000"
[tool.semantic_release.branches.main]
match = "(main|master)"
prerelease = false