mirror of
https://github.com/esphome/esphome.git
synced 2025-07-30 15:16:37 +00:00
Merge branch 'integration' into memory_api
This commit is contained in:
commit
bacb6a2c11
@ -1 +1 @@
|
|||||||
7920671c938a5ea6a11ac4594204b5ec8f38d579c962bf1f185e8d5e3ad879be
|
32b0db73b3ae01ba18c9cbb1dabbd8156bc14dded500471919bd0a3dc33916e0
|
||||||
|
891
.github/workflows/auto-label-pr.yml
vendored
891
.github/workflows/auto-label-pr.yml
vendored
@ -14,6 +14,7 @@ env:
|
|||||||
SMALL_PR_THRESHOLD: 30
|
SMALL_PR_THRESHOLD: 30
|
||||||
MAX_LABELS: 15
|
MAX_LABELS: 15
|
||||||
TOO_BIG_THRESHOLD: 1000
|
TOO_BIG_THRESHOLD: 1000
|
||||||
|
COMPONENT_LABEL_THRESHOLD: 10
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
label:
|
label:
|
||||||
@ -23,24 +24,6 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.2.2
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
- name: Get changes
|
|
||||||
id: changes
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
# Get PR number
|
|
||||||
pr_number="${{ github.event.pull_request.number }}"
|
|
||||||
|
|
||||||
# Get list of changed files using gh CLI
|
|
||||||
files=$(gh pr diff $pr_number --name-only)
|
|
||||||
echo "files<<EOF" >> $GITHUB_OUTPUT
|
|
||||||
echo "$files" >> $GITHUB_OUTPUT
|
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Get file stats (additions + deletions) using gh CLI
|
|
||||||
stats=$(gh pr view $pr_number --json files --jq '.files | map(.additions + .deletions) | add')
|
|
||||||
echo "total_changes=${stats:-0}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Generate a token
|
- name: Generate a token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v2
|
||||||
@ -55,93 +38,466 @@ jobs:
|
|||||||
script: |
|
script: |
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const SMALL_PR_THRESHOLD = parseInt('${{ env.SMALL_PR_THRESHOLD }}');
|
||||||
|
const MAX_LABELS = parseInt('${{ env.MAX_LABELS }}');
|
||||||
|
const TOO_BIG_THRESHOLD = parseInt('${{ env.TOO_BIG_THRESHOLD }}');
|
||||||
|
const COMPONENT_LABEL_THRESHOLD = parseInt('${{ env.COMPONENT_LABEL_THRESHOLD }}');
|
||||||
|
const BOT_COMMENT_MARKER = '<!-- auto-label-pr-bot -->';
|
||||||
|
const CODEOWNERS_MARKER = '<!-- codeowners-request -->';
|
||||||
|
const TOO_BIG_MARKER = '<!-- too-big-request -->';
|
||||||
|
|
||||||
|
const MANAGED_LABELS = [
|
||||||
|
'new-component',
|
||||||
|
'new-platform',
|
||||||
|
'new-target-platform',
|
||||||
|
'merging-to-release',
|
||||||
|
'merging-to-beta',
|
||||||
|
'core',
|
||||||
|
'small-pr',
|
||||||
|
'dashboard',
|
||||||
|
'github-actions',
|
||||||
|
'by-code-owner',
|
||||||
|
'has-tests',
|
||||||
|
'needs-tests',
|
||||||
|
'needs-docs',
|
||||||
|
'needs-codeowners',
|
||||||
|
'too-big',
|
||||||
|
'labeller-recheck'
|
||||||
|
];
|
||||||
|
|
||||||
|
const DOCS_PR_PATTERNS = [
|
||||||
|
/https:\/\/github\.com\/esphome\/esphome-docs\/pull\/\d+/,
|
||||||
|
/esphome\/esphome-docs#\d+/
|
||||||
|
];
|
||||||
|
|
||||||
|
// Global state
|
||||||
const { owner, repo } = context.repo;
|
const { owner, repo } = context.repo;
|
||||||
const pr_number = context.issue.number;
|
const pr_number = context.issue.number;
|
||||||
|
|
||||||
// Hidden marker to identify bot comments from this workflow
|
// Get current labels and PR data
|
||||||
const BOT_COMMENT_MARKER = '<!-- auto-label-pr-bot -->';
|
|
||||||
|
|
||||||
// Get current labels
|
|
||||||
const { data: currentLabelsData } = await github.rest.issues.listLabelsOnIssue({
|
const { data: currentLabelsData } = await github.rest.issues.listLabelsOnIssue({
|
||||||
owner,
|
owner,
|
||||||
repo,
|
repo,
|
||||||
issue_number: pr_number
|
issue_number: pr_number
|
||||||
});
|
});
|
||||||
const currentLabels = currentLabelsData.map(label => label.name);
|
const currentLabels = currentLabelsData.map(label => label.name);
|
||||||
|
|
||||||
// Define managed labels that this workflow controls
|
|
||||||
const managedLabels = currentLabels.filter(label =>
|
const managedLabels = currentLabels.filter(label =>
|
||||||
label.startsWith('component: ') ||
|
label.startsWith('component: ') || MANAGED_LABELS.includes(label)
|
||||||
[
|
|
||||||
'new-component',
|
|
||||||
'new-platform',
|
|
||||||
'new-target-platform',
|
|
||||||
'merging-to-release',
|
|
||||||
'merging-to-beta',
|
|
||||||
'core',
|
|
||||||
'small-pr',
|
|
||||||
'dashboard',
|
|
||||||
'github-actions',
|
|
||||||
'by-code-owner',
|
|
||||||
'has-tests',
|
|
||||||
'needs-tests',
|
|
||||||
'needs-docs',
|
|
||||||
'too-big',
|
|
||||||
'labeller-recheck'
|
|
||||||
].includes(label)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check for mega-PR early - if present, skip most automatic labeling
|
||||||
|
const isMegaPR = currentLabels.includes('mega-pr');
|
||||||
|
|
||||||
|
// Get all PR files with automatic pagination
|
||||||
|
const prFiles = await github.paginate(
|
||||||
|
github.rest.pulls.listFiles,
|
||||||
|
{
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: pr_number
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate data from PR files
|
||||||
|
const changedFiles = prFiles.map(file => file.filename);
|
||||||
|
const totalChanges = prFiles.reduce((sum, file) => sum + (file.additions || 0) + (file.deletions || 0), 0);
|
||||||
|
|
||||||
console.log('Current labels:', currentLabels.join(', '));
|
console.log('Current labels:', currentLabels.join(', '));
|
||||||
console.log('Managed labels:', managedLabels.join(', '));
|
|
||||||
|
|
||||||
// Get changed files
|
|
||||||
const changedFiles = `${{ steps.changes.outputs.files }}`.split('\n').filter(f => f.length > 0);
|
|
||||||
const totalChanges = parseInt('${{ steps.changes.outputs.total_changes }}') || 0;
|
|
||||||
|
|
||||||
console.log('Changed files:', changedFiles.length);
|
console.log('Changed files:', changedFiles.length);
|
||||||
console.log('Total changes:', totalChanges);
|
console.log('Total changes:', totalChanges);
|
||||||
|
if (isMegaPR) {
|
||||||
const labels = new Set();
|
console.log('Mega-PR detected - applying limited labeling logic');
|
||||||
|
|
||||||
// Fetch TARGET_PLATFORMS and PLATFORM_COMPONENTS from API
|
|
||||||
let targetPlatforms = [];
|
|
||||||
let platformComponents = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch('https://data.esphome.io/components.json');
|
|
||||||
const componentsData = await response.json();
|
|
||||||
|
|
||||||
// Extract target platforms and platform components directly from API
|
|
||||||
targetPlatforms = componentsData.target_platforms || [];
|
|
||||||
platformComponents = componentsData.platform_components || [];
|
|
||||||
|
|
||||||
console.log('Target platforms from API:', targetPlatforms.length, targetPlatforms);
|
|
||||||
console.log('Platform components from API:', platformComponents.length, platformComponents);
|
|
||||||
} catch (error) {
|
|
||||||
console.log('Failed to fetch components data from API:', error.message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get environment variables
|
// Fetch API data
|
||||||
const smallPrThreshold = parseInt('${{ env.SMALL_PR_THRESHOLD }}');
|
async function fetchApiData() {
|
||||||
const maxLabels = parseInt('${{ env.MAX_LABELS }}');
|
try {
|
||||||
const tooBigThreshold = parseInt('${{ env.TOO_BIG_THRESHOLD }}');
|
const response = await fetch('https://data.esphome.io/components.json');
|
||||||
|
const componentsData = await response.json();
|
||||||
|
return {
|
||||||
|
targetPlatforms: componentsData.target_platforms || [],
|
||||||
|
platformComponents: componentsData.platform_components || []
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Failed to fetch components data from API:', error.message);
|
||||||
|
return { targetPlatforms: [], platformComponents: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: Merge branch detection
|
||||||
|
async function detectMergeBranch() {
|
||||||
|
const labels = new Set();
|
||||||
|
const baseRef = context.payload.pull_request.base.ref;
|
||||||
|
|
||||||
// Strategy: Merge to release or beta branch
|
|
||||||
const baseRef = context.payload.pull_request.base.ref;
|
|
||||||
if (baseRef !== 'dev') {
|
|
||||||
if (baseRef === 'release') {
|
if (baseRef === 'release') {
|
||||||
labels.add('merging-to-release');
|
labels.add('merging-to-release');
|
||||||
} else if (baseRef === 'beta') {
|
} else if (baseRef === 'beta') {
|
||||||
labels.add('merging-to-beta');
|
labels.add('merging-to-beta');
|
||||||
}
|
}
|
||||||
|
|
||||||
// When targeting non-dev branches, only use merge warning labels
|
return labels;
|
||||||
const finalLabels = Array.from(labels);
|
}
|
||||||
|
|
||||||
|
// Strategy: Component and platform labeling
|
||||||
|
async function detectComponentPlatforms(apiData) {
|
||||||
|
const labels = new Set();
|
||||||
|
const componentRegex = /^esphome\/components\/([^\/]+)\//;
|
||||||
|
const targetPlatformRegex = new RegExp(`^esphome\/components\/(${apiData.targetPlatforms.join('|')})/`);
|
||||||
|
|
||||||
|
for (const file of changedFiles) {
|
||||||
|
const componentMatch = file.match(componentRegex);
|
||||||
|
if (componentMatch) {
|
||||||
|
labels.add(`component: ${componentMatch[1]}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const platformMatch = file.match(targetPlatformRegex);
|
||||||
|
if (platformMatch) {
|
||||||
|
labels.add(`platform: ${platformMatch[1]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: New component detection
|
||||||
|
async function detectNewComponents() {
|
||||||
|
const labels = new Set();
|
||||||
|
const addedFiles = prFiles.filter(file => file.status === 'added').map(file => file.filename);
|
||||||
|
|
||||||
|
for (const file of addedFiles) {
|
||||||
|
const componentMatch = file.match(/^esphome\/components\/([^\/]+)\/__init__\.py$/);
|
||||||
|
if (componentMatch) {
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(file, 'utf8');
|
||||||
|
if (content.includes('IS_TARGET_PLATFORM = True')) {
|
||||||
|
labels.add('new-target-platform');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Failed to read content of ${file}:`, error.message);
|
||||||
|
}
|
||||||
|
labels.add('new-component');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: New platform detection
|
||||||
|
async function detectNewPlatforms(apiData) {
|
||||||
|
const labels = new Set();
|
||||||
|
const addedFiles = prFiles.filter(file => file.status === 'added').map(file => file.filename);
|
||||||
|
|
||||||
|
for (const file of addedFiles) {
|
||||||
|
const platformFileMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\.py$/);
|
||||||
|
if (platformFileMatch) {
|
||||||
|
const [, component, platform] = platformFileMatch;
|
||||||
|
if (apiData.platformComponents.includes(platform)) {
|
||||||
|
labels.add('new-platform');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const platformDirMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\/__init__\.py$/);
|
||||||
|
if (platformDirMatch) {
|
||||||
|
const [, component, platform] = platformDirMatch;
|
||||||
|
if (apiData.platformComponents.includes(platform)) {
|
||||||
|
labels.add('new-platform');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: Core files detection
|
||||||
|
async function detectCoreChanges() {
|
||||||
|
const labels = new Set();
|
||||||
|
const coreFiles = changedFiles.filter(file =>
|
||||||
|
file.startsWith('esphome/core/') ||
|
||||||
|
(file.startsWith('esphome/') && file.split('/').length === 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (coreFiles.length > 0) {
|
||||||
|
labels.add('core');
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: PR size detection
|
||||||
|
async function detectPRSize() {
|
||||||
|
const labels = new Set();
|
||||||
|
const testChanges = prFiles
|
||||||
|
.filter(file => file.filename.startsWith('tests/'))
|
||||||
|
.reduce((sum, file) => sum + (file.additions || 0) + (file.deletions || 0), 0);
|
||||||
|
|
||||||
|
const nonTestChanges = totalChanges - testChanges;
|
||||||
|
|
||||||
|
if (totalChanges <= SMALL_PR_THRESHOLD) {
|
||||||
|
labels.add('small-pr');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't add too-big if mega-pr label is already present
|
||||||
|
if (nonTestChanges > TOO_BIG_THRESHOLD && !isMegaPR) {
|
||||||
|
labels.add('too-big');
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: Dashboard changes
|
||||||
|
async function detectDashboardChanges() {
|
||||||
|
const labels = new Set();
|
||||||
|
const dashboardFiles = changedFiles.filter(file =>
|
||||||
|
file.startsWith('esphome/dashboard/') ||
|
||||||
|
file.startsWith('esphome/components/dashboard_import/')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dashboardFiles.length > 0) {
|
||||||
|
labels.add('dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: GitHub Actions changes
|
||||||
|
async function detectGitHubActionsChanges() {
|
||||||
|
const labels = new Set();
|
||||||
|
const githubActionsFiles = changedFiles.filter(file =>
|
||||||
|
file.startsWith('.github/workflows/')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (githubActionsFiles.length > 0) {
|
||||||
|
labels.add('github-actions');
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: Code owner detection
|
||||||
|
async function detectCodeOwner() {
|
||||||
|
const labels = new Set();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data: codeownersFile } = await github.rest.repos.getContent({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
path: 'CODEOWNERS',
|
||||||
|
});
|
||||||
|
|
||||||
|
const codeownersContent = Buffer.from(codeownersFile.content, 'base64').toString('utf8');
|
||||||
|
const prAuthor = context.payload.pull_request.user.login;
|
||||||
|
|
||||||
|
const codeownersLines = codeownersContent.split('\n')
|
||||||
|
.map(line => line.trim())
|
||||||
|
.filter(line => line && !line.startsWith('#'));
|
||||||
|
|
||||||
|
const codeownersRegexes = codeownersLines.map(line => {
|
||||||
|
const parts = line.split(/\s+/);
|
||||||
|
const pattern = parts[0];
|
||||||
|
const owners = parts.slice(1);
|
||||||
|
|
||||||
|
let regex;
|
||||||
|
if (pattern.endsWith('*')) {
|
||||||
|
const dir = pattern.slice(0, -1);
|
||||||
|
regex = new RegExp(`^${dir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`);
|
||||||
|
} else if (pattern.includes('*')) {
|
||||||
|
// First escape all regex special chars except *, then replace * with .*
|
||||||
|
const regexPattern = pattern
|
||||||
|
.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
|
||||||
|
.replace(/\*/g, '.*');
|
||||||
|
regex = new RegExp(`^${regexPattern}$`);
|
||||||
|
} else {
|
||||||
|
regex = new RegExp(`^${pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { regex, owners };
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const file of changedFiles) {
|
||||||
|
for (const { regex, owners } of codeownersRegexes) {
|
||||||
|
if (regex.test(file) && owners.some(owner => owner === `@${prAuthor}`)) {
|
||||||
|
labels.add('by-code-owner');
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Failed to read or parse CODEOWNERS file:', error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: Test detection
|
||||||
|
async function detectTests() {
|
||||||
|
const labels = new Set();
|
||||||
|
const testFiles = changedFiles.filter(file => file.startsWith('tests/'));
|
||||||
|
|
||||||
|
if (testFiles.length > 0) {
|
||||||
|
labels.add('has-tests');
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy: Requirements detection
|
||||||
|
async function detectRequirements(allLabels) {
|
||||||
|
const labels = new Set();
|
||||||
|
|
||||||
|
// Check for missing tests
|
||||||
|
if ((allLabels.has('new-component') || allLabels.has('new-platform')) && !allLabels.has('has-tests')) {
|
||||||
|
labels.add('needs-tests');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for missing docs
|
||||||
|
if (allLabels.has('new-component') || allLabels.has('new-platform')) {
|
||||||
|
const prBody = context.payload.pull_request.body || '';
|
||||||
|
const hasDocsLink = DOCS_PR_PATTERNS.some(pattern => pattern.test(prBody));
|
||||||
|
|
||||||
|
if (!hasDocsLink) {
|
||||||
|
labels.add('needs-docs');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for missing CODEOWNERS
|
||||||
|
if (allLabels.has('new-component')) {
|
||||||
|
const codeownersModified = prFiles.some(file =>
|
||||||
|
file.filename === 'CODEOWNERS' &&
|
||||||
|
(file.status === 'modified' || file.status === 'added') &&
|
||||||
|
(file.additions || 0) > 0
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!codeownersModified) {
|
||||||
|
labels.add('needs-codeowners');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate review messages
|
||||||
|
function generateReviewMessages(finalLabels) {
|
||||||
|
const messages = [];
|
||||||
|
const prAuthor = context.payload.pull_request.user.login;
|
||||||
|
|
||||||
|
// Too big message
|
||||||
|
if (finalLabels.includes('too-big')) {
|
||||||
|
const testChanges = prFiles
|
||||||
|
.filter(file => file.filename.startsWith('tests/'))
|
||||||
|
.reduce((sum, file) => sum + (file.additions || 0) + (file.deletions || 0), 0);
|
||||||
|
const nonTestChanges = totalChanges - testChanges;
|
||||||
|
|
||||||
|
const tooManyLabels = finalLabels.length > MAX_LABELS;
|
||||||
|
const tooManyChanges = nonTestChanges > TOO_BIG_THRESHOLD;
|
||||||
|
|
||||||
|
let message = `${TOO_BIG_MARKER}\n### 📦 Pull Request Size\n\n`;
|
||||||
|
|
||||||
|
if (tooManyLabels && tooManyChanges) {
|
||||||
|
message += `This PR is too large with ${nonTestChanges} line changes (excluding tests) and affects ${finalLabels.length} different components/areas.`;
|
||||||
|
} else if (tooManyLabels) {
|
||||||
|
message += `This PR affects ${finalLabels.length} different components/areas.`;
|
||||||
|
} else {
|
||||||
|
message += `This PR is too large with ${nonTestChanges} line changes (excluding tests).`;
|
||||||
|
}
|
||||||
|
|
||||||
|
message += ` Please consider breaking it down into smaller, focused PRs to make review easier and reduce the risk of conflicts.\n\n`;
|
||||||
|
message += `For guidance on breaking down large PRs, see: https://developers.esphome.io/contributing/submitting-your-work/#how-to-approach-large-submissions`;
|
||||||
|
|
||||||
|
messages.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CODEOWNERS message
|
||||||
|
if (finalLabels.includes('needs-codeowners')) {
|
||||||
|
const message = `${CODEOWNERS_MARKER}\n### 👥 Code Ownership\n\n` +
|
||||||
|
`Hey there @${prAuthor},\n` +
|
||||||
|
`Thanks for submitting this pull request! Can you add yourself as a codeowner for this integration? ` +
|
||||||
|
`This way we can notify you if a bug report for this integration is reported.\n\n` +
|
||||||
|
`In \`__init__.py\` of the integration, please add:\n\n` +
|
||||||
|
`\`\`\`python\nCODEOWNERS = ["@${prAuthor}"]\n\`\`\`\n\n` +
|
||||||
|
`And run \`script/build_codeowners.py\``;
|
||||||
|
|
||||||
|
messages.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle reviews
|
||||||
|
async function handleReviews(finalLabels) {
|
||||||
|
const reviewMessages = generateReviewMessages(finalLabels);
|
||||||
|
const hasReviewableLabels = finalLabels.some(label =>
|
||||||
|
['too-big', 'needs-codeowners'].includes(label)
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: reviews } = await github.rest.pulls.listReviews({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: pr_number
|
||||||
|
});
|
||||||
|
|
||||||
|
const botReviews = reviews.filter(review =>
|
||||||
|
review.user.type === 'Bot' &&
|
||||||
|
review.state === 'CHANGES_REQUESTED' &&
|
||||||
|
review.body && review.body.includes(BOT_COMMENT_MARKER)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasReviewableLabels) {
|
||||||
|
const reviewBody = `${BOT_COMMENT_MARKER}\n\n${reviewMessages.join('\n\n---\n\n')}`;
|
||||||
|
|
||||||
|
if (botReviews.length > 0) {
|
||||||
|
// Update existing review
|
||||||
|
await github.rest.pulls.updateReview({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: pr_number,
|
||||||
|
review_id: botReviews[0].id,
|
||||||
|
body: reviewBody
|
||||||
|
});
|
||||||
|
console.log('Updated existing bot review');
|
||||||
|
} else {
|
||||||
|
// Create new review
|
||||||
|
await github.rest.pulls.createReview({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: pr_number,
|
||||||
|
body: reviewBody,
|
||||||
|
event: 'REQUEST_CHANGES'
|
||||||
|
});
|
||||||
|
console.log('Created new bot review');
|
||||||
|
}
|
||||||
|
} else if (botReviews.length > 0) {
|
||||||
|
// Dismiss existing reviews
|
||||||
|
for (const review of botReviews) {
|
||||||
|
try {
|
||||||
|
await github.rest.pulls.dismissReview({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
pull_number: pr_number,
|
||||||
|
review_id: review.id,
|
||||||
|
message: 'Review dismissed: All requirements have been met'
|
||||||
|
});
|
||||||
|
console.log(`Dismissed bot review ${review.id}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Failed to dismiss review ${review.id}:`, error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main execution
|
||||||
|
const apiData = await fetchApiData();
|
||||||
|
const baseRef = context.payload.pull_request.base.ref;
|
||||||
|
|
||||||
|
// Early exit for non-dev branches
|
||||||
|
if (baseRef !== 'dev') {
|
||||||
|
const branchLabels = await detectMergeBranch();
|
||||||
|
const finalLabels = Array.from(branchLabels);
|
||||||
|
|
||||||
console.log('Computed labels (merge branch only):', finalLabels.join(', '));
|
console.log('Computed labels (merge branch only):', finalLabels.join(', '));
|
||||||
|
|
||||||
// Add new labels
|
// Apply labels
|
||||||
if (finalLabels.length > 0) {
|
if (finalLabels.length > 0) {
|
||||||
console.log(`Adding labels: ${finalLabels.join(', ')}`);
|
|
||||||
await github.rest.issues.addLabels({
|
await github.rest.issues.addLabels({
|
||||||
owner,
|
owner,
|
||||||
repo,
|
repo,
|
||||||
@ -150,13 +506,9 @@ jobs:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove old managed labels that are no longer needed
|
// Remove old managed labels
|
||||||
const labelsToRemove = managedLabels.filter(label =>
|
const labelsToRemove = managedLabels.filter(label => !finalLabels.includes(label));
|
||||||
!finalLabels.includes(label)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const label of labelsToRemove) {
|
for (const label of labelsToRemove) {
|
||||||
console.log(`Removing label: ${label}`);
|
|
||||||
try {
|
try {
|
||||||
await github.rest.issues.removeLabel({
|
await github.rest.issues.removeLabel({
|
||||||
owner,
|
owner,
|
||||||
@ -169,324 +521,78 @@ jobs:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return; // Exit early, don't process other strategies
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategy: Component and Platform labeling
|
// Run all strategies
|
||||||
const componentRegex = /^esphome\/components\/([^\/]+)\//;
|
const [
|
||||||
const targetPlatformRegex = new RegExp(`^esphome\/components\/(${targetPlatforms.join('|')})/`);
|
branchLabels,
|
||||||
|
componentLabels,
|
||||||
|
newComponentLabels,
|
||||||
|
newPlatformLabels,
|
||||||
|
coreLabels,
|
||||||
|
sizeLabels,
|
||||||
|
dashboardLabels,
|
||||||
|
actionsLabels,
|
||||||
|
codeOwnerLabels,
|
||||||
|
testLabels
|
||||||
|
] = await Promise.all([
|
||||||
|
detectMergeBranch(),
|
||||||
|
detectComponentPlatforms(apiData),
|
||||||
|
detectNewComponents(),
|
||||||
|
detectNewPlatforms(apiData),
|
||||||
|
detectCoreChanges(),
|
||||||
|
detectPRSize(),
|
||||||
|
detectDashboardChanges(),
|
||||||
|
detectGitHubActionsChanges(),
|
||||||
|
detectCodeOwner(),
|
||||||
|
detectTests()
|
||||||
|
]);
|
||||||
|
|
||||||
for (const file of changedFiles) {
|
// Combine all labels
|
||||||
// Check for component changes
|
const allLabels = new Set([
|
||||||
const componentMatch = file.match(componentRegex);
|
...branchLabels,
|
||||||
if (componentMatch) {
|
...componentLabels,
|
||||||
const component = componentMatch[1];
|
...newComponentLabels,
|
||||||
labels.add(`component: ${component}`);
|
...newPlatformLabels,
|
||||||
}
|
...coreLabels,
|
||||||
|
...sizeLabels,
|
||||||
|
...dashboardLabels,
|
||||||
|
...actionsLabels,
|
||||||
|
...codeOwnerLabels,
|
||||||
|
...testLabels
|
||||||
|
]);
|
||||||
|
|
||||||
// Check for target platform changes
|
// Detect requirements based on all other labels
|
||||||
const platformMatch = file.match(targetPlatformRegex);
|
const requirementLabels = await detectRequirements(allLabels);
|
||||||
if (platformMatch) {
|
for (const label of requirementLabels) {
|
||||||
const targetPlatform = platformMatch[1];
|
allLabels.add(label);
|
||||||
labels.add(`platform: ${targetPlatform}`);
|
}
|
||||||
|
|
||||||
|
let finalLabels = Array.from(allLabels);
|
||||||
|
|
||||||
|
// For mega-PRs, exclude component labels if there are too many
|
||||||
|
if (isMegaPR) {
|
||||||
|
const componentLabels = finalLabels.filter(label => label.startsWith('component: '));
|
||||||
|
if (componentLabels.length > COMPONENT_LABEL_THRESHOLD) {
|
||||||
|
finalLabels = finalLabels.filter(label => !label.startsWith('component: '));
|
||||||
|
console.log(`Mega-PR detected - excluding ${componentLabels.length} component labels (threshold: ${COMPONENT_LABEL_THRESHOLD})`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get PR files for new component/platform detection
|
// Handle too many labels (only for non-mega PRs)
|
||||||
const { data: prFiles } = await github.rest.pulls.listFiles({
|
const tooManyLabels = finalLabels.length > MAX_LABELS;
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
pull_number: pr_number
|
|
||||||
});
|
|
||||||
|
|
||||||
const addedFiles = prFiles.filter(file => file.status === 'added').map(file => file.filename);
|
if (tooManyLabels && !isMegaPR && !finalLabels.includes('too-big')) {
|
||||||
|
finalLabels = ['too-big'];
|
||||||
// Calculate changes excluding root tests directory for too-big calculation
|
|
||||||
const testChanges = prFiles
|
|
||||||
.filter(file => file.filename.startsWith('tests/'))
|
|
||||||
.reduce((sum, file) => sum + (file.additions || 0) + (file.deletions || 0), 0);
|
|
||||||
|
|
||||||
const nonTestChanges = totalChanges - testChanges;
|
|
||||||
console.log(`Test changes: ${testChanges}, Non-test changes: ${nonTestChanges}`);
|
|
||||||
|
|
||||||
// Strategy: New Component detection
|
|
||||||
for (const file of addedFiles) {
|
|
||||||
// Check for new component files: esphome/components/{component}/__init__.py
|
|
||||||
const componentMatch = file.match(/^esphome\/components\/([^\/]+)\/__init__\.py$/);
|
|
||||||
if (componentMatch) {
|
|
||||||
try {
|
|
||||||
// Read the content directly from the filesystem since we have it checked out
|
|
||||||
const content = fs.readFileSync(file, 'utf8');
|
|
||||||
|
|
||||||
// Strategy: New Target Platform detection
|
|
||||||
if (content.includes('IS_TARGET_PLATFORM = True')) {
|
|
||||||
labels.add('new-target-platform');
|
|
||||||
}
|
|
||||||
labels.add('new-component');
|
|
||||||
} catch (error) {
|
|
||||||
console.log(`Failed to read content of ${file}:`, error.message);
|
|
||||||
// Fallback: assume it's a new component if we can't read the content
|
|
||||||
labels.add('new-component');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategy: New Platform detection
|
|
||||||
for (const file of addedFiles) {
|
|
||||||
// Check for new platform files: esphome/components/{component}/{platform}.py
|
|
||||||
const platformFileMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\.py$/);
|
|
||||||
if (platformFileMatch) {
|
|
||||||
const [, component, platform] = platformFileMatch;
|
|
||||||
if (platformComponents.includes(platform)) {
|
|
||||||
labels.add('new-platform');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for new platform files: esphome/components/{component}/{platform}/__init__.py
|
|
||||||
const platformDirMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\/__init__\.py$/);
|
|
||||||
if (platformDirMatch) {
|
|
||||||
const [, component, platform] = platformDirMatch;
|
|
||||||
if (platformComponents.includes(platform)) {
|
|
||||||
labels.add('new-platform');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const coreFiles = changedFiles.filter(file =>
|
|
||||||
file.startsWith('esphome/core/') ||
|
|
||||||
(file.startsWith('esphome/') && file.split('/').length === 2)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (coreFiles.length > 0) {
|
|
||||||
labels.add('core');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strategy: Small PR detection
|
|
||||||
if (totalChanges <= smallPrThreshold) {
|
|
||||||
labels.add('small-pr');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strategy: Dashboard changes
|
|
||||||
const dashboardFiles = changedFiles.filter(file =>
|
|
||||||
file.startsWith('esphome/dashboard/') ||
|
|
||||||
file.startsWith('esphome/components/dashboard_import/')
|
|
||||||
);
|
|
||||||
|
|
||||||
if (dashboardFiles.length > 0) {
|
|
||||||
labels.add('dashboard');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strategy: GitHub Actions changes
|
|
||||||
const githubActionsFiles = changedFiles.filter(file =>
|
|
||||||
file.startsWith('.github/workflows/')
|
|
||||||
);
|
|
||||||
|
|
||||||
if (githubActionsFiles.length > 0) {
|
|
||||||
labels.add('github-actions');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strategy: Code Owner detection
|
|
||||||
try {
|
|
||||||
// Fetch CODEOWNERS file from the repository (in case it was changed in this PR)
|
|
||||||
const { data: codeownersFile } = await github.rest.repos.getContent({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
path: 'CODEOWNERS',
|
|
||||||
});
|
|
||||||
|
|
||||||
const codeownersContent = Buffer.from(codeownersFile.content, 'base64').toString('utf8');
|
|
||||||
const prAuthor = context.payload.pull_request.user.login;
|
|
||||||
|
|
||||||
// Parse CODEOWNERS file
|
|
||||||
const codeownersLines = codeownersContent.split('\n')
|
|
||||||
.map(line => line.trim())
|
|
||||||
.filter(line => line && !line.startsWith('#'));
|
|
||||||
|
|
||||||
let isCodeOwner = false;
|
|
||||||
|
|
||||||
// Precompile CODEOWNERS patterns into regex objects
|
|
||||||
const codeownersRegexes = codeownersLines.map(line => {
|
|
||||||
const parts = line.split(/\s+/);
|
|
||||||
const pattern = parts[0];
|
|
||||||
const owners = parts.slice(1);
|
|
||||||
|
|
||||||
let regex;
|
|
||||||
if (pattern.endsWith('*')) {
|
|
||||||
// Directory pattern like "esphome/components/api/*"
|
|
||||||
const dir = pattern.slice(0, -1);
|
|
||||||
regex = new RegExp(`^${dir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`);
|
|
||||||
} else if (pattern.includes('*')) {
|
|
||||||
// Glob pattern
|
|
||||||
const regexPattern = pattern
|
|
||||||
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
||||||
.replace(/\\*/g, '.*');
|
|
||||||
regex = new RegExp(`^${regexPattern}$`);
|
|
||||||
} else {
|
|
||||||
// Exact match
|
|
||||||
regex = new RegExp(`^${pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return { regex, owners };
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const file of changedFiles) {
|
|
||||||
for (const { regex, owners } of codeownersRegexes) {
|
|
||||||
if (regex.test(file)) {
|
|
||||||
// Check if PR author is in the owners list
|
|
||||||
if (owners.some(owner => owner === `@${prAuthor}`)) {
|
|
||||||
isCodeOwner = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isCodeOwner) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCodeOwner) {
|
|
||||||
labels.add('by-code-owner');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log('Failed to read or parse CODEOWNERS file:', error.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strategy: Test detection
|
|
||||||
const testFiles = changedFiles.filter(file =>
|
|
||||||
file.startsWith('tests/')
|
|
||||||
);
|
|
||||||
|
|
||||||
if (testFiles.length > 0) {
|
|
||||||
labels.add('has-tests');
|
|
||||||
} else {
|
|
||||||
// Only check for needs-tests if this is a new component or new platform
|
|
||||||
if (labels.has('new-component') || labels.has('new-platform')) {
|
|
||||||
labels.add('needs-tests');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strategy: Documentation check for new components/platforms
|
|
||||||
if (labels.has('new-component') || labels.has('new-platform')) {
|
|
||||||
const prBody = context.payload.pull_request.body || '';
|
|
||||||
|
|
||||||
// Look for documentation PR links
|
|
||||||
// Patterns to match:
|
|
||||||
// - https://github.com/esphome/esphome-docs/pull/1234
|
|
||||||
// - esphome/esphome-docs#1234
|
|
||||||
const docsPrPatterns = [
|
|
||||||
/https:\/\/github\.com\/esphome\/esphome-docs\/pull\/\d+/,
|
|
||||||
/esphome\/esphome-docs#\d+/
|
|
||||||
];
|
|
||||||
|
|
||||||
const hasDocsLink = docsPrPatterns.some(pattern => pattern.test(prBody));
|
|
||||||
|
|
||||||
if (!hasDocsLink) {
|
|
||||||
labels.add('needs-docs');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Set to Array
|
|
||||||
let finalLabels = Array.from(labels);
|
|
||||||
|
|
||||||
console.log('Computed labels:', finalLabels.join(', '));
|
console.log('Computed labels:', finalLabels.join(', '));
|
||||||
|
|
||||||
// Check if PR has mega-pr label
|
// Handle reviews
|
||||||
const isMegaPR = currentLabels.includes('mega-pr');
|
await handleReviews(finalLabels);
|
||||||
|
|
||||||
// Check if PR is too big (either too many labels or too many line changes)
|
// Apply labels
|
||||||
const tooManyLabels = finalLabels.length > maxLabels;
|
|
||||||
const tooManyChanges = nonTestChanges > tooBigThreshold;
|
|
||||||
|
|
||||||
if ((tooManyLabels || tooManyChanges) && !isMegaPR) {
|
|
||||||
const originalLength = finalLabels.length;
|
|
||||||
console.log(`PR is too big - Labels: ${originalLength}, Changes: ${totalChanges} (non-test: ${nonTestChanges})`);
|
|
||||||
|
|
||||||
// Get all reviews on this PR to check for existing bot reviews
|
|
||||||
const { data: reviews } = await github.rest.pulls.listReviews({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
pull_number: pr_number
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if there's already an active bot review requesting changes
|
|
||||||
const existingBotReview = reviews.find(review =>
|
|
||||||
review.user.type === 'Bot' &&
|
|
||||||
review.state === 'CHANGES_REQUESTED' &&
|
|
||||||
review.body && review.body.includes(BOT_COMMENT_MARKER)
|
|
||||||
);
|
|
||||||
|
|
||||||
// If too big due to line changes only, keep original labels and add too-big
|
|
||||||
// If too big due to too many labels, replace with just too-big
|
|
||||||
if (tooManyChanges && !tooManyLabels) {
|
|
||||||
finalLabels.push('too-big');
|
|
||||||
} else {
|
|
||||||
finalLabels = ['too-big'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only create a new review if there isn't already an active bot review
|
|
||||||
if (!existingBotReview) {
|
|
||||||
// Create appropriate review message
|
|
||||||
let reviewBody;
|
|
||||||
if (tooManyLabels && tooManyChanges) {
|
|
||||||
reviewBody = `${BOT_COMMENT_MARKER}\nThis PR is too large with ${nonTestChanges} line changes (excluding tests) and affects ${originalLength} different components/areas. Please consider breaking it down into smaller, focused PRs to make review easier and reduce the risk of conflicts.\n\nFor guidance on breaking down large PRs, see: https://developers.esphome.io/contributing/submitting-your-work/#but-howwww-looonnnggg`;
|
|
||||||
} else if (tooManyLabels) {
|
|
||||||
reviewBody = `${BOT_COMMENT_MARKER}\nThis PR affects ${originalLength} different components/areas. Please consider breaking it down into smaller, focused PRs to make review easier and reduce the risk of conflicts.\n\nFor guidance on breaking down large PRs, see: https://developers.esphome.io/contributing/submitting-your-work/#but-howwww-looonnnggg`;
|
|
||||||
} else {
|
|
||||||
reviewBody = `${BOT_COMMENT_MARKER}\nThis PR is too large with ${nonTestChanges} line changes (excluding tests). Please consider breaking it down into smaller, focused PRs to make review easier and reduce the risk of conflicts.\n\nFor guidance on breaking down large PRs, see: https://developers.esphome.io/contributing/submitting-your-work/#but-howwww-looonnnggg`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request changes on the PR
|
|
||||||
await github.rest.pulls.createReview({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
pull_number: pr_number,
|
|
||||||
body: reviewBody,
|
|
||||||
event: 'REQUEST_CHANGES'
|
|
||||||
});
|
|
||||||
console.log('Created new "too big" review requesting changes');
|
|
||||||
} else {
|
|
||||||
console.log('Skipping review creation - existing bot review already requesting changes');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Check if PR was previously too big but is now acceptable
|
|
||||||
const wasPreviouslyTooBig = currentLabels.includes('too-big');
|
|
||||||
|
|
||||||
if (wasPreviouslyTooBig || isMegaPR) {
|
|
||||||
console.log('PR is no longer too big or has mega-pr label - dismissing bot reviews');
|
|
||||||
|
|
||||||
// Get all reviews on this PR to find reviews to dismiss
|
|
||||||
const { data: reviews } = await github.rest.pulls.listReviews({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
pull_number: pr_number
|
|
||||||
});
|
|
||||||
|
|
||||||
// Find bot reviews that requested changes
|
|
||||||
const botReviews = reviews.filter(review =>
|
|
||||||
review.user.type === 'Bot' &&
|
|
||||||
review.state === 'CHANGES_REQUESTED' &&
|
|
||||||
review.body && review.body.includes(BOT_COMMENT_MARKER)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Dismiss bot reviews
|
|
||||||
for (const review of botReviews) {
|
|
||||||
try {
|
|
||||||
await github.rest.pulls.dismissReview({
|
|
||||||
owner,
|
|
||||||
repo,
|
|
||||||
pull_number: pr_number,
|
|
||||||
review_id: review.id,
|
|
||||||
message: isMegaPR ?
|
|
||||||
'Review dismissed: mega-pr label was added' :
|
|
||||||
'Review dismissed: PR size is now acceptable'
|
|
||||||
});
|
|
||||||
console.log(`Dismissed review ${review.id}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(`Failed to dismiss review ${review.id}:`, error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new labels
|
|
||||||
if (finalLabels.length > 0) {
|
if (finalLabels.length > 0) {
|
||||||
console.log(`Adding labels: ${finalLabels.join(', ')}`);
|
console.log(`Adding labels: ${finalLabels.join(', ')}`);
|
||||||
await github.rest.issues.addLabels({
|
await github.rest.issues.addLabels({
|
||||||
@ -497,11 +603,8 @@ jobs:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove old managed labels that are no longer needed
|
// Remove old managed labels
|
||||||
const labelsToRemove = managedLabels.filter(label =>
|
const labelsToRemove = managedLabels.filter(label => !finalLabels.includes(label));
|
||||||
!finalLabels.includes(label)
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const label of labelsToRemove) {
|
for (const label of labelsToRemove) {
|
||||||
console.log(`Removing label: ${label}`);
|
console.log(`Removing label: ${label}`);
|
||||||
try {
|
try {
|
||||||
|
@ -11,7 +11,7 @@ ci:
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
# Ruff version.
|
# Ruff version.
|
||||||
rev: v0.12.4
|
rev: v0.12.5
|
||||||
hooks:
|
hooks:
|
||||||
# Run the linter.
|
# Run the linter.
|
||||||
- id: ruff
|
- id: ruff
|
||||||
|
@ -89,9 +89,9 @@ def choose_prompt(options, purpose: str = None):
|
|||||||
def choose_upload_log_host(
|
def choose_upload_log_host(
|
||||||
default, check_default, show_ota, show_mqtt, show_api, purpose: str = None
|
default, check_default, show_ota, show_mqtt, show_api, purpose: str = None
|
||||||
):
|
):
|
||||||
options = []
|
options = [
|
||||||
for port in get_serial_ports():
|
(f"{port.path} ({port.description})", port.path) for port in get_serial_ports()
|
||||||
options.append((f"{port.path} ({port.description})", port.path))
|
]
|
||||||
if default == "SERIAL":
|
if default == "SERIAL":
|
||||||
return choose_prompt(options, purpose=purpose)
|
return choose_prompt(options, purpose=purpose)
|
||||||
if (show_ota and "ota" in CORE.config) or (show_api and "api" in CORE.config):
|
if (show_ota and "ota" in CORE.config) or (show_api and "api" in CORE.config):
|
||||||
@ -119,9 +119,7 @@ def mqtt_logging_enabled(mqtt_config):
|
|||||||
return False
|
return False
|
||||||
if CONF_TOPIC not in log_topic:
|
if CONF_TOPIC not in log_topic:
|
||||||
return False
|
return False
|
||||||
if log_topic.get(CONF_LEVEL, None) == "NONE":
|
return log_topic.get(CONF_LEVEL, None) != "NONE"
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get_port_type(port):
|
def get_port_type(port):
|
||||||
|
@ -7,7 +7,6 @@ namespace a4988 {
|
|||||||
static const char *const TAG = "a4988.stepper";
|
static const char *const TAG = "a4988.stepper";
|
||||||
|
|
||||||
void A4988::setup() {
|
void A4988::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (this->sleep_pin_ != nullptr) {
|
if (this->sleep_pin_ != nullptr) {
|
||||||
this->sleep_pin_->setup();
|
this->sleep_pin_->setup();
|
||||||
this->sleep_pin_->digital_write(false);
|
this->sleep_pin_->digital_write(false);
|
||||||
|
@ -7,8 +7,6 @@ namespace absolute_humidity {
|
|||||||
static const char *const TAG = "absolute_humidity.sensor";
|
static const char *const TAG = "absolute_humidity.sensor";
|
||||||
|
|
||||||
void AbsoluteHumidityComponent::setup() {
|
void AbsoluteHumidityComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, " Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
|
ESP_LOGD(TAG, " Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
|
||||||
this->temperature_sensor_->add_on_state_callback([this](float state) { this->temperature_callback_(state); });
|
this->temperature_sensor_->add_on_state_callback([this](float state) { this->temperature_callback_(state); });
|
||||||
if (this->temperature_sensor_->has_state()) {
|
if (this->temperature_sensor_->has_state()) {
|
||||||
|
@ -37,7 +37,6 @@ const LogString *adc_unit_to_str(adc_unit_t unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ADCSensor::setup() {
|
void ADCSensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
|
||||||
// Check if another sensor already initialized this ADC unit
|
// Check if another sensor already initialized this ADC unit
|
||||||
if (ADCSensor::shared_adc_handles[this->adc_unit_] == nullptr) {
|
if (ADCSensor::shared_adc_handles[this->adc_unit_] == nullptr) {
|
||||||
adc_oneshot_unit_init_cfg_t init_config = {}; // Zero initialize
|
adc_oneshot_unit_init_cfg_t init_config = {}; // Zero initialize
|
||||||
|
@ -17,7 +17,6 @@ namespace adc {
|
|||||||
static const char *const TAG = "adc.esp8266";
|
static const char *const TAG = "adc.esp8266";
|
||||||
|
|
||||||
void ADCSensor::setup() {
|
void ADCSensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
|
||||||
#ifndef USE_ADC_SENSOR_VCC
|
#ifndef USE_ADC_SENSOR_VCC
|
||||||
this->pin_->setup();
|
this->pin_->setup();
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,7 +9,6 @@ namespace adc {
|
|||||||
static const char *const TAG = "adc.libretiny";
|
static const char *const TAG = "adc.libretiny";
|
||||||
|
|
||||||
void ADCSensor::setup() {
|
void ADCSensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
|
||||||
#ifndef USE_ADC_SENSOR_VCC
|
#ifndef USE_ADC_SENSOR_VCC
|
||||||
this->pin_->setup();
|
this->pin_->setup();
|
||||||
#endif // !USE_ADC_SENSOR_VCC
|
#endif // !USE_ADC_SENSOR_VCC
|
||||||
|
@ -14,7 +14,6 @@ namespace adc {
|
|||||||
static const char *const TAG = "adc.rp2040";
|
static const char *const TAG = "adc.rp2040";
|
||||||
|
|
||||||
void ADCSensor::setup() {
|
void ADCSensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
adc_init();
|
adc_init();
|
||||||
|
@ -8,10 +8,7 @@ static const char *const TAG = "adc128s102";
|
|||||||
|
|
||||||
float ADC128S102::get_setup_priority() const { return setup_priority::HARDWARE; }
|
float ADC128S102::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
void ADC128S102::setup() {
|
void ADC128S102::setup() { this->spi_setup(); }
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->spi_setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ADC128S102::dump_config() {
|
void ADC128S102::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "ADC128S102:");
|
ESP_LOGCONFIG(TAG, "ADC128S102:");
|
||||||
|
@ -10,7 +10,6 @@ static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
|
|||||||
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
|
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
|
||||||
|
|
||||||
void ADS1115Component::setup() {
|
void ADS1115Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint16_t value;
|
uint16_t value;
|
||||||
if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) {
|
if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -9,7 +9,6 @@ static const char *const TAG = "ads1118";
|
|||||||
static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
|
static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
|
||||||
|
|
||||||
void ADS1118::setup() {
|
void ADS1118::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->spi_setup();
|
this->spi_setup();
|
||||||
|
|
||||||
this->config_ = 0;
|
this->config_ = 0;
|
||||||
|
@ -24,8 +24,6 @@ static const uint16_t ZP_CURRENT = 0x0000;
|
|||||||
static const uint16_t ZP_DEFAULT = 0xFFFF;
|
static const uint16_t ZP_DEFAULT = 0xFFFF;
|
||||||
|
|
||||||
void AGS10Component::setup() {
|
void AGS10Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
auto version = this->read_version_();
|
auto version = this->read_version_();
|
||||||
if (version) {
|
if (version) {
|
||||||
ESP_LOGD(TAG, "AGS10 Sensor Version: 0x%02X", *version);
|
ESP_LOGD(TAG, "AGS10 Sensor Version: 0x%02X", *version);
|
||||||
@ -45,8 +43,6 @@ void AGS10Component::setup() {
|
|||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, "AGS10 Sensor Resistance: unknown");
|
ESP_LOGE(TAG, "AGS10 Sensor Resistance: unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Sensor initialized");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AGS10Component::update() {
|
void AGS10Component::update() {
|
||||||
|
@ -38,8 +38,6 @@ static const uint8_t AHT10_STATUS_BUSY = 0x80;
|
|||||||
static const float AHT10_DIVISOR = 1048576.0f; // 2^20, used for temperature and humidity calculations
|
static const float AHT10_DIVISOR = 1048576.0f; // 2^20, used for temperature and humidity calculations
|
||||||
|
|
||||||
void AHT10Component::setup() {
|
void AHT10Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) {
|
if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) {
|
||||||
ESP_LOGE(TAG, "Reset failed");
|
ESP_LOGE(TAG, "Reset failed");
|
||||||
}
|
}
|
||||||
@ -80,8 +78,6 @@ void AHT10Component::setup() {
|
|||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGV(TAG, "Initialization complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AHT10Component::restart_read_() {
|
void AHT10Component::restart_read_() {
|
||||||
|
@ -17,8 +17,6 @@ static const char *const TAG = "aic3204";
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AIC3204::setup() {
|
void AIC3204::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
// Set register page to 0
|
// Set register page to 0
|
||||||
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set page 0 failed");
|
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set page 0 failed");
|
||||||
// Initiate SW reset (PLL is powered off as part of reset)
|
// Initiate SW reset (PLL is powered off as part of reset)
|
||||||
|
@ -90,8 +90,6 @@ bool AM2315C::convert_(uint8_t *data, float &humidity, float &temperature) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AM2315C::setup() {
|
void AM2315C::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
// get status
|
// get status
|
||||||
uint8_t status = 0;
|
uint8_t status = 0;
|
||||||
if (this->read(&status, 1) != i2c::ERROR_OK) {
|
if (this->read(&status, 1) != i2c::ERROR_OK) {
|
||||||
|
@ -34,7 +34,6 @@ void AM2320Component::update() {
|
|||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
}
|
}
|
||||||
void AM2320Component::setup() {
|
void AM2320Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t data[8];
|
uint8_t data[8];
|
||||||
data[0] = 0;
|
data[0] = 0;
|
||||||
data[1] = 4;
|
data[1] = 4;
|
||||||
|
@ -54,8 +54,6 @@ enum { // APDS9306 registers
|
|||||||
}
|
}
|
||||||
|
|
||||||
void APDS9306::setup() {
|
void APDS9306::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
if (!this->read_byte(APDS9306_PART_ID, &id)) { // Part ID register
|
if (!this->read_byte(APDS9306_PART_ID, &id)) { // Part ID register
|
||||||
this->error_code_ = COMMUNICATION_FAILED;
|
this->error_code_ = COMMUNICATION_FAILED;
|
||||||
@ -86,8 +84,6 @@ void APDS9306::setup() {
|
|||||||
|
|
||||||
// Set to active mode
|
// Set to active mode
|
||||||
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
|
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
|
||||||
|
|
||||||
ESP_LOGCONFIG(TAG, "APDS9306 setup complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void APDS9306::dump_config() {
|
void APDS9306::dump_config() {
|
||||||
|
@ -15,7 +15,6 @@ static const char *const TAG = "apds9960";
|
|||||||
#define APDS9960_WRITE_BYTE(reg, value) APDS9960_ERROR_CHECK(this->write_byte(reg, value));
|
#define APDS9960_WRITE_BYTE(reg, value) APDS9960_ERROR_CHECK(this->write_byte(reg, value));
|
||||||
|
|
||||||
void APDS9960::setup() {
|
void APDS9960::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
if (!this->read_byte(0x92, &id)) { // ID register
|
if (!this->read_byte(0x92, &id)) { // ID register
|
||||||
this->error_code_ = COMMUNICATION_FAILED;
|
this->error_code_ = COMMUNICATION_FAILED;
|
||||||
|
@ -14,6 +14,8 @@ with warnings.catch_warnings():
|
|||||||
from aioesphomeapi import APIClient, parse_log_message
|
from aioesphomeapi import APIClient, parse_log_message
|
||||||
from aioesphomeapi.log_runner import async_run
|
from aioesphomeapi.log_runner import async_run
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
|
||||||
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
|
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE
|
||||||
|
|
||||||
@ -66,7 +68,5 @@ async def async_run_logs(config: dict[str, Any], address: str) -> None:
|
|||||||
|
|
||||||
def run_logs(config: dict[str, Any], address: str) -> None:
|
def run_logs(config: dict[str, Any], address: str) -> None:
|
||||||
"""Run the logs command."""
|
"""Run the logs command."""
|
||||||
try:
|
with contextlib.suppress(KeyboardInterrupt):
|
||||||
asyncio.run(async_run_logs(config, address))
|
asyncio.run(async_run_logs(config, address))
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
@ -7,8 +7,6 @@ namespace as3935 {
|
|||||||
static const char *const TAG = "as3935";
|
static const char *const TAG = "as3935";
|
||||||
|
|
||||||
void AS3935Component::setup() {
|
void AS3935Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
this->irq_pin_->setup();
|
this->irq_pin_->setup();
|
||||||
LOG_PIN(" IRQ Pin: ", this->irq_pin_);
|
LOG_PIN(" IRQ Pin: ", this->irq_pin_);
|
||||||
|
|
||||||
|
@ -7,9 +7,7 @@ namespace as3935_spi {
|
|||||||
static const char *const TAG = "as3935_spi";
|
static const char *const TAG = "as3935_spi";
|
||||||
|
|
||||||
void SPIAS3935Component::setup() {
|
void SPIAS3935Component::setup() {
|
||||||
ESP_LOGI(TAG, "SPIAS3935Component setup started!");
|
|
||||||
this->spi_setup();
|
this->spi_setup();
|
||||||
ESP_LOGI(TAG, "SPI setup finished!");
|
|
||||||
AS3935Component::setup();
|
AS3935Component::setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,6 @@ static const uint8_t REGISTER_AGC = 0x1A; // 8 bytes / R
|
|||||||
static const uint8_t REGISTER_MAGNITUDE = 0x1B; // 16 bytes / R
|
static const uint8_t REGISTER_MAGNITUDE = 0x1B; // 16 bytes / R
|
||||||
|
|
||||||
void AS5600Component::setup() {
|
void AS5600Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
if (!this->read_byte(REGISTER_STATUS).has_value()) {
|
if (!this->read_byte(REGISTER_STATUS).has_value()) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
|
@ -8,7 +8,6 @@ namespace as7341 {
|
|||||||
static const char *const TAG = "as7341";
|
static const char *const TAG = "as7341";
|
||||||
|
|
||||||
void AS7341Component::setup() {
|
void AS7341Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
LOG_I2C_DEVICE(this);
|
LOG_I2C_DEVICE(this);
|
||||||
|
|
||||||
// Verify device ID
|
// Verify device ID
|
||||||
|
@ -71,7 +71,7 @@ bool AT581XComponent::i2c_read_reg(uint8_t addr, uint8_t &data) {
|
|||||||
return this->read_register(addr, &data, 1) == esphome::i2c::NO_ERROR;
|
return this->read_register(addr, &data, 1) == esphome::i2c::NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AT581XComponent::setup() { ESP_LOGCONFIG(TAG, "Running setup"); }
|
void AT581XComponent::setup() {}
|
||||||
void AT581XComponent::dump_config() { LOG_I2C_DEVICE(this); }
|
void AT581XComponent::dump_config() { LOG_I2C_DEVICE(this); }
|
||||||
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
|
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
|
||||||
bool AT581XComponent::i2c_write_config() {
|
bool AT581XComponent::i2c_write_config() {
|
||||||
|
@ -41,7 +41,6 @@ void ATM90E26Component::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ATM90E26Component::setup() {
|
void ATM90E26Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->spi_setup();
|
this->spi_setup();
|
||||||
|
|
||||||
uint16_t mmode = 0x422; // default values for everything but L/N line current gains
|
uint16_t mmode = 0x422; // default values for everything but L/N line current gains
|
||||||
|
@ -109,7 +109,6 @@ void ATM90E32Component::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ATM90E32Component::setup() {
|
void ATM90E32Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->spi_setup();
|
this->spi_setup();
|
||||||
|
|
||||||
uint16_t mmode0 = 0x87; // 3P4W 50Hz
|
uint16_t mmode0 = 0x87; // 3P4W 50Hz
|
||||||
|
@ -17,7 +17,6 @@ constexpr static const uint8_t AXS_READ_TOUCHPAD[11] = {0xb5, 0xab, 0xa5, 0x5a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AXS15231Touchscreen::setup() {
|
void AXS15231Touchscreen::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (this->reset_pin_ != nullptr) {
|
if (this->reset_pin_ != nullptr) {
|
||||||
this->reset_pin_->setup();
|
this->reset_pin_->setup();
|
||||||
this->reset_pin_->digital_write(false);
|
this->reset_pin_->digital_write(false);
|
||||||
@ -36,7 +35,6 @@ void AXS15231Touchscreen::setup() {
|
|||||||
if (this->y_raw_max_ == 0) {
|
if (this->y_raw_max_ == 0) {
|
||||||
this->y_raw_max_ = this->display_->get_native_height();
|
this->y_raw_max_ = this->display_->get_native_height();
|
||||||
}
|
}
|
||||||
ESP_LOGCONFIG(TAG, "AXS15231 Touchscreen setup complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AXS15231Touchscreen::update_touches() {
|
void AXS15231Touchscreen::update_touches() {
|
||||||
|
@ -121,8 +121,6 @@ void spi_dma_tx_finish_callback(unsigned int param) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BekenSPILEDStripLightOutput::setup() {
|
void BekenSPILEDStripLightOutput::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
size_t buffer_size = this->get_buffer_size_();
|
size_t buffer_size = this->get_buffer_size_();
|
||||||
size_t dma_buffer_size = (buffer_size * 8) + (2 * 64);
|
size_t dma_buffer_size = (buffer_size * 8) + (2 * 64);
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ MTreg:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void BH1750Sensor::setup() {
|
void BH1750Sensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->name_.c_str());
|
|
||||||
uint8_t turn_on = BH1750_COMMAND_POWER_ON;
|
uint8_t turn_on = BH1750_COMMAND_POWER_ON;
|
||||||
if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
|
if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -266,8 +266,10 @@ async def delayed_off_filter_to_code(config, filter_id):
|
|||||||
async def autorepeat_filter_to_code(config, filter_id):
|
async def autorepeat_filter_to_code(config, filter_id):
|
||||||
timings = []
|
timings = []
|
||||||
if len(config) > 0:
|
if len(config) > 0:
|
||||||
for conf in config:
|
timings.extend(
|
||||||
timings.append((conf[CONF_DELAY], conf[CONF_TIME_OFF], conf[CONF_TIME_ON]))
|
(conf[CONF_DELAY], conf[CONF_TIME_OFF], conf[CONF_TIME_ON])
|
||||||
|
for conf in config
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
timings.append(
|
timings.append(
|
||||||
(
|
(
|
||||||
@ -573,16 +575,15 @@ async def setup_binary_sensor_core_(var, config):
|
|||||||
await automation.build_automation(trigger, [], conf)
|
await automation.build_automation(trigger, [], conf)
|
||||||
|
|
||||||
for conf in config.get(CONF_ON_MULTI_CLICK, []):
|
for conf in config.get(CONF_ON_MULTI_CLICK, []):
|
||||||
timings = []
|
timings = [
|
||||||
for tim in conf[CONF_TIMING]:
|
cg.StructInitializer(
|
||||||
timings.append(
|
MultiClickTriggerEvent,
|
||||||
cg.StructInitializer(
|
("state", tim[CONF_STATE]),
|
||||||
MultiClickTriggerEvent,
|
("min_length", tim[CONF_MIN_LENGTH]),
|
||||||
("state", tim[CONF_STATE]),
|
("max_length", tim.get(CONF_MAX_LENGTH, 4294967294)),
|
||||||
("min_length", tim[CONF_MIN_LENGTH]),
|
|
||||||
("max_length", tim.get(CONF_MAX_LENGTH, 4294967294)),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
for tim in conf[CONF_TIMING]
|
||||||
|
]
|
||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, timings)
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var, timings)
|
||||||
if CONF_INVALID_COOLDOWN in conf:
|
if CONF_INVALID_COOLDOWN in conf:
|
||||||
cg.add(trigger.set_invalid_cooldown(conf[CONF_INVALID_COOLDOWN]))
|
cg.add(trigger.set_invalid_cooldown(conf[CONF_INVALID_COOLDOWN]))
|
||||||
|
@ -88,7 +88,6 @@ const char *oversampling_to_str(BME280Oversampling oversampling) { // NOLINT
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BME280Component::setup() {
|
void BME280Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t chip_id = 0;
|
uint8_t chip_id = 0;
|
||||||
|
|
||||||
// Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
|
// Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
|
||||||
|
@ -71,7 +71,6 @@ static const char *iir_filter_to_str(BME680IIRFilter filter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BME680Component::setup() {
|
void BME680Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t chip_id;
|
uint8_t chip_id;
|
||||||
if (!this->read_byte(BME680_REGISTER_CHIPID, &chip_id) || chip_id != 0x61) {
|
if (!this->read_byte(BME680_REGISTER_CHIPID, &chip_id) || chip_id != 0x61) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -15,8 +15,6 @@ std::vector<BME680BSECComponent *>
|
|||||||
uint8_t BME680BSECComponent::work_buffer_[BSEC_MAX_WORKBUFFER_SIZE] = {0};
|
uint8_t BME680BSECComponent::work_buffer_[BSEC_MAX_WORKBUFFER_SIZE] = {0};
|
||||||
|
|
||||||
void BME680BSECComponent::setup() {
|
void BME680BSECComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->device_id_.c_str());
|
|
||||||
|
|
||||||
uint8_t new_idx = BME680BSECComponent::instances.size();
|
uint8_t new_idx = BME680BSECComponent::instances.size();
|
||||||
BME680BSECComponent::instances.push_back(this);
|
BME680BSECComponent::instances.push_back(this);
|
||||||
|
|
||||||
|
@ -21,8 +21,6 @@ static const char *const TAG = "bme68x_bsec2.sensor";
|
|||||||
static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
|
static const std::string IAQ_ACCURACY_STATES[4] = {"Stabilizing", "Uncertain", "Calibrating", "Calibrated"};
|
||||||
|
|
||||||
void BME68xBSEC2Component::setup() {
|
void BME68xBSEC2Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
this->bsec_status_ = bsec_init_m(&this->bsec_instance_);
|
this->bsec_status_ = bsec_init_m(&this->bsec_instance_);
|
||||||
if (this->bsec_status_ != BSEC_OK) {
|
if (this->bsec_status_ != BSEC_OK) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -119,7 +119,6 @@ const float GRAVITY_EARTH = 9.80665f;
|
|||||||
void BMI160Component::internal_setup_(int stage) {
|
void BMI160Component::internal_setup_(int stage) {
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case 0:
|
case 0:
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t chipid;
|
uint8_t chipid;
|
||||||
if (!this->read_byte(BMI160_REGISTER_CHIPID, &chipid) || (chipid != 0b11010001)) {
|
if (!this->read_byte(BMI160_REGISTER_CHIPID, &chipid) || (chipid != 0b11010001)) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -20,7 +20,6 @@ void BMP085Component::update() {
|
|||||||
this->set_timeout("temperature", 5, [this]() { this->read_temperature_(); });
|
this->set_timeout("temperature", 5, [this]() { this->read_temperature_(); });
|
||||||
}
|
}
|
||||||
void BMP085Component::setup() {
|
void BMP085Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t data[22];
|
uint8_t data[22];
|
||||||
if (!this->read_bytes(BMP085_REGISTER_AC1_H, data, 22)) {
|
if (!this->read_bytes(BMP085_REGISTER_AC1_H, data, 22)) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -57,7 +57,6 @@ static const char *iir_filter_to_str(BMP280IIRFilter filter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BMP280Component::setup() {
|
void BMP280Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t chip_id = 0;
|
uint8_t chip_id = 0;
|
||||||
|
|
||||||
// Read the chip id twice, to work around a bug where the first read is 0.
|
// Read the chip id twice, to work around a bug where the first read is 0.
|
||||||
|
@ -70,7 +70,6 @@ static const LogString *iir_filter_to_str(IIRFilter filter) {
|
|||||||
|
|
||||||
void BMP3XXComponent::setup() {
|
void BMP3XXComponent::setup() {
|
||||||
this->error_code_ = NONE;
|
this->error_code_ = NONE;
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
// Call the Device base class "initialise" function
|
// Call the Device base class "initialise" function
|
||||||
if (!reset()) {
|
if (!reset()) {
|
||||||
ESP_LOGE(TAG, "Failed to reset");
|
ESP_LOGE(TAG, "Failed to reset");
|
||||||
|
@ -128,8 +128,6 @@ void BMP581Component::setup() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
this->error_code_ = NONE;
|
this->error_code_ = NONE;
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
// 1) Soft reboot //
|
// 1) Soft reboot //
|
||||||
////////////////////
|
////////////////////
|
||||||
|
@ -15,7 +15,6 @@ static const uint8_t BP1658CJ_ADDR_START_5CH = 0x30;
|
|||||||
static const uint8_t BP1658CJ_DELAY = 2;
|
static const uint8_t BP1658CJ_DELAY = 2;
|
||||||
|
|
||||||
void BP1658CJ::setup() {
|
void BP1658CJ::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->data_pin_->setup();
|
this->data_pin_->setup();
|
||||||
this->data_pin_->digital_write(false);
|
this->data_pin_->digital_write(false);
|
||||||
this->clock_pin_->setup();
|
this->clock_pin_->setup();
|
||||||
|
@ -20,7 +20,6 @@ static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111;
|
|||||||
static const uint8_t BP5758D_DELAY = 2;
|
static const uint8_t BP5758D_DELAY = 2;
|
||||||
|
|
||||||
void BP5758D::setup() {
|
void BP5758D::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->data_pin_->setup();
|
this->data_pin_->setup();
|
||||||
this->data_pin_->digital_write(false);
|
this->data_pin_->digital_write(false);
|
||||||
delayMicroseconds(BP5758D_DELAY);
|
delayMicroseconds(BP5758D_DELAY);
|
||||||
|
@ -22,9 +22,8 @@ def validate_id(config):
|
|||||||
if CONF_CAN_ID in config:
|
if CONF_CAN_ID in config:
|
||||||
can_id = config[CONF_CAN_ID]
|
can_id = config[CONF_CAN_ID]
|
||||||
id_ext = config[CONF_USE_EXTENDED_ID]
|
id_ext = config[CONF_USE_EXTENDED_ID]
|
||||||
if not id_ext:
|
if not id_ext and can_id > 0x7FF:
|
||||||
if can_id > 0x7FF:
|
raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
|
||||||
raise cv.Invalid("Standard IDs must be 11 Bit (0x000-0x7ff / 0-2047)")
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ namespace canbus {
|
|||||||
static const char *const TAG = "canbus";
|
static const char *const TAG = "canbus";
|
||||||
|
|
||||||
void Canbus::setup() {
|
void Canbus::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (!this->setup_internal()) {
|
if (!this->setup_internal()) {
|
||||||
ESP_LOGE(TAG, "setup error!");
|
ESP_LOGE(TAG, "setup error!");
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -8,8 +8,6 @@ namespace cap1188 {
|
|||||||
static const char *const TAG = "cap1188";
|
static const char *const TAG = "cap1188";
|
||||||
|
|
||||||
void CAP1188Component::setup() {
|
void CAP1188Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
// Reset device using the reset pin
|
// Reset device using the reset pin
|
||||||
if (this->reset_pin_ != nullptr) {
|
if (this->reset_pin_ != nullptr) {
|
||||||
this->reset_pin_->setup();
|
this->reset_pin_->setup();
|
||||||
|
@ -10,8 +10,6 @@ static const char *const TAG = "cd74hc4067";
|
|||||||
float CD74HC4067Component::get_setup_priority() const { return setup_priority::DATA; }
|
float CD74HC4067Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||||
|
|
||||||
void CD74HC4067Component::setup() {
|
void CD74HC4067Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
this->pin_s0_->setup();
|
this->pin_s0_->setup();
|
||||||
this->pin_s1_->setup();
|
this->pin_s1_->setup();
|
||||||
this->pin_s2_->setup();
|
this->pin_s2_->setup();
|
||||||
|
@ -14,7 +14,6 @@ static const uint8_t CH422G_REG_OUT_UPPER = 0x23; // write reg for output bit
|
|||||||
static const char *const TAG = "ch422g";
|
static const char *const TAG = "ch422g";
|
||||||
|
|
||||||
void CH422GComponent::setup() {
|
void CH422GComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
// set outputs before mode
|
// set outputs before mode
|
||||||
this->write_outputs_();
|
this->write_outputs_();
|
||||||
// Set mode and check for errors
|
// Set mode and check for errors
|
||||||
|
@ -4,7 +4,6 @@ namespace esphome {
|
|||||||
namespace chsc6x {
|
namespace chsc6x {
|
||||||
|
|
||||||
void CHSC6XTouchscreen::setup() {
|
void CHSC6XTouchscreen::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (this->interrupt_pin_ != nullptr) {
|
if (this->interrupt_pin_ != nullptr) {
|
||||||
this->interrupt_pin_->setup();
|
this->interrupt_pin_->setup();
|
||||||
this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE);
|
this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE);
|
||||||
@ -15,8 +14,6 @@ void CHSC6XTouchscreen::setup() {
|
|||||||
if (this->y_raw_max_ == this->y_raw_min_) {
|
if (this->y_raw_max_ == this->y_raw_min_) {
|
||||||
this->y_raw_max_ = this->display_->get_native_height();
|
this->y_raw_max_ = this->display_->get_native_height();
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGCONFIG(TAG, "CHSC6X Touchscreen setup complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHSC6XTouchscreen::update_touches() {
|
void CHSC6XTouchscreen::update_touches() {
|
||||||
|
@ -20,7 +20,6 @@ uint8_t cm1106_checksum(const uint8_t *response, size_t len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CM1106Component::setup() {
|
void CM1106Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t response[8] = {0};
|
uint8_t response[8] = {0};
|
||||||
if (!this->cm1106_write_command_(C_M1106_CMD_GET_CO2, sizeof(C_M1106_CMD_GET_CO2), response, sizeof(response))) {
|
if (!this->cm1106_write_command_(C_M1106_CMD_GET_CO2, sizeof(C_M1106_CMD_GET_CO2), response, sizeof(response))) {
|
||||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||||
|
@ -52,8 +52,6 @@ bool CS5460AComponent::softreset_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CS5460AComponent::setup() {
|
void CS5460AComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
float current_full_scale = (pga_gain_ == CS5460A_PGA_GAIN_10X) ? 0.25 : 0.10;
|
float current_full_scale = (pga_gain_ == CS5460A_PGA_GAIN_10X) ? 0.25 : 0.10;
|
||||||
float voltage_full_scale = 0.25;
|
float voltage_full_scale = 0.25;
|
||||||
current_multiplier_ = current_full_scale / (fabsf(current_gain_) * 0x1000000);
|
current_multiplier_ = current_full_scale / (fabsf(current_gain_) * 0x1000000);
|
||||||
|
@ -42,7 +42,6 @@ static const uint8_t CSE7761_CMD_ENABLE_WRITE = 0xE5; // Enable write operation
|
|||||||
enum CSE7761 { RMS_IAC, RMS_IBC, RMS_UC, POWER_PAC, POWER_PBC, POWER_SC, ENERGY_AC, ENERGY_BC };
|
enum CSE7761 { RMS_IAC, RMS_IBC, RMS_UC, POWER_PAC, POWER_PBC, POWER_SC, ENERGY_AC, ENERGY_BC };
|
||||||
|
|
||||||
void CSE7761Component::setup() {
|
void CSE7761Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->write_(CSE7761_SPECIAL_COMMAND, CSE7761_CMD_RESET);
|
this->write_(CSE7761_SPECIAL_COMMAND, CSE7761_CMD_RESET);
|
||||||
uint16_t syscon = this->read_(0x00, 2); // Default 0x0A04
|
uint16_t syscon = this->read_(0x00, 2); // Default 0x0A04
|
||||||
if ((0x0A04 == syscon) && this->chip_init_()) {
|
if ((0x0A04 == syscon) && this->chip_init_()) {
|
||||||
|
@ -6,7 +6,6 @@ namespace cst226 {
|
|||||||
static const char *const TAG = "cst226.touchscreen";
|
static const char *const TAG = "cst226.touchscreen";
|
||||||
|
|
||||||
void CST226Touchscreen::setup() {
|
void CST226Touchscreen::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (this->reset_pin_ != nullptr) {
|
if (this->reset_pin_ != nullptr) {
|
||||||
this->reset_pin_->setup();
|
this->reset_pin_->setup();
|
||||||
this->reset_pin_->digital_write(true);
|
this->reset_pin_->digital_write(true);
|
||||||
@ -95,7 +94,6 @@ void CST226Touchscreen::continue_setup_() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->setup_complete_ = true;
|
this->setup_complete_ = true;
|
||||||
ESP_LOGCONFIG(TAG, "CST226 Touchscreen setup complete");
|
|
||||||
}
|
}
|
||||||
void CST226Touchscreen::update_button_state_(bool state) {
|
void CST226Touchscreen::update_button_state_(bool state) {
|
||||||
if (this->button_touched_ == state)
|
if (this->button_touched_ == state)
|
||||||
|
@ -35,11 +35,9 @@ void CST816Touchscreen::continue_setup_() {
|
|||||||
if (this->y_raw_max_ == this->y_raw_min_) {
|
if (this->y_raw_max_ == this->y_raw_min_) {
|
||||||
this->y_raw_max_ = this->display_->get_native_height();
|
this->y_raw_max_ = this->display_->get_native_height();
|
||||||
}
|
}
|
||||||
ESP_LOGCONFIG(TAG, "CST816 Touchscreen setup complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CST816Touchscreen::setup() {
|
void CST816Touchscreen::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (this->reset_pin_ != nullptr) {
|
if (this->reset_pin_ != nullptr) {
|
||||||
this->reset_pin_->setup();
|
this->reset_pin_->setup();
|
||||||
this->reset_pin_->digital_write(true);
|
this->reset_pin_->digital_write(true);
|
||||||
|
@ -20,8 +20,6 @@ static const uint8_t DAC7678_REG_INTERNAL_REF_0 = 0x80;
|
|||||||
static const uint8_t DAC7678_REG_INTERNAL_REF_1 = 0x90;
|
static const uint8_t DAC7678_REG_INTERNAL_REF_1 = 0x90;
|
||||||
|
|
||||||
void DAC7678Output::setup() {
|
void DAC7678Output::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
ESP_LOGV(TAG, "Resetting device");
|
ESP_LOGV(TAG, "Resetting device");
|
||||||
|
|
||||||
// Reset device
|
// Reset device
|
||||||
|
@ -70,7 +70,6 @@ bool DallasTemperatureSensor::read_scratch_pad_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DallasTemperatureSensor::setup() {
|
void DallasTemperatureSensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (!this->check_address_())
|
if (!this->check_address_())
|
||||||
return;
|
return;
|
||||||
if (!this->read_scratch_pad_())
|
if (!this->read_scratch_pad_())
|
||||||
|
@ -12,7 +12,6 @@ static const uint32_t TEARDOWN_TIMEOUT_DEEP_SLEEP_MS = 5000;
|
|||||||
bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
void DeepSleepComponent::setup() {
|
void DeepSleepComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
global_has_deep_sleep = true;
|
global_has_deep_sleep = true;
|
||||||
|
|
||||||
const optional<uint32_t> run_duration = get_run_duration_();
|
const optional<uint32_t> run_duration = get_run_duration_();
|
||||||
|
@ -74,8 +74,7 @@ def range_segment_list(input):
|
|||||||
if isinstance(input, list):
|
if isinstance(input, list):
|
||||||
for list_item in input:
|
for list_item in input:
|
||||||
if isinstance(list_item, list):
|
if isinstance(list_item, list):
|
||||||
for item in list_item:
|
flat_list.extend(list_item)
|
||||||
flat_list.append(item)
|
|
||||||
else:
|
else:
|
||||||
flat_list.append(list_item)
|
flat_list.append(list_item)
|
||||||
else:
|
else:
|
||||||
|
@ -8,7 +8,6 @@ namespace dht {
|
|||||||
static const char *const TAG = "dht";
|
static const char *const TAG = "dht";
|
||||||
|
|
||||||
void DHT::setup() {
|
void DHT::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->pin_->digital_write(true);
|
this->pin_->digital_write(true);
|
||||||
this->pin_->setup();
|
this->pin_->setup();
|
||||||
this->pin_->digital_write(true);
|
this->pin_->digital_write(true);
|
||||||
|
@ -34,7 +34,6 @@ void DHT12Component::update() {
|
|||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
}
|
}
|
||||||
void DHT12Component::setup() {
|
void DHT12Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t data[5];
|
uint8_t data[5];
|
||||||
if (!this->read_data_(data)) {
|
if (!this->read_data_(data)) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -11,8 +11,6 @@ void DPS310Component::setup() {
|
|||||||
uint8_t coef_data_raw[DPS310_NUM_COEF_REGS];
|
uint8_t coef_data_raw[DPS310_NUM_COEF_REGS];
|
||||||
auto timer = DPS310_INIT_TIMEOUT;
|
auto timer = DPS310_INIT_TIMEOUT;
|
||||||
uint8_t reg = 0;
|
uint8_t reg = 0;
|
||||||
|
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
// first, reset the sensor
|
// first, reset the sensor
|
||||||
if (!this->write_byte(DPS310_REG_RESET, DPS310_CMD_RESET)) {
|
if (!this->write_byte(DPS310_REG_RESET, DPS310_CMD_RESET)) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -10,7 +10,6 @@ namespace ds1307 {
|
|||||||
static const char *const TAG = "ds1307";
|
static const char *const TAG = "ds1307";
|
||||||
|
|
||||||
void DS1307Component::setup() {
|
void DS1307Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (!this->read_rtc_()) {
|
if (!this->read_rtc_()) {
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ namespace ds2484 {
|
|||||||
static const char *const TAG = "ds2484.onewire";
|
static const char *const TAG = "ds2484.onewire";
|
||||||
|
|
||||||
void DS2484OneWireBus::setup() {
|
void DS2484OneWireBus::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->reset_device();
|
this->reset_device();
|
||||||
this->search();
|
this->search();
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ namespace duty_cycle {
|
|||||||
static const char *const TAG = "duty_cycle";
|
static const char *const TAG = "duty_cycle";
|
||||||
|
|
||||||
void DutyCycleSensor::setup() {
|
void DutyCycleSensor::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
|
|
||||||
this->pin_->setup();
|
this->pin_->setup();
|
||||||
this->store_.pin = this->pin_->to_isr();
|
this->store_.pin = this->pin_->to_isr();
|
||||||
this->store_.last_level = this->pin_->digital_read();
|
this->store_.last_level = this->pin_->digital_read();
|
||||||
|
@ -16,7 +16,6 @@ static const uint16_t PRESSURE_ADDRESS = 0x04B0;
|
|||||||
|
|
||||||
void EE895Component::setup() {
|
void EE895Component::setup() {
|
||||||
uint16_t crc16_check = 0;
|
uint16_t crc16_check = 0;
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
write_command_(SERIAL_NUMBER, 8);
|
write_command_(SERIAL_NUMBER, 8);
|
||||||
uint8_t serial_number[20];
|
uint8_t serial_number[20];
|
||||||
this->read(serial_number, 20);
|
this->read(serial_number, 20);
|
||||||
|
@ -16,7 +16,6 @@ static const uint8_t GET_Y_RES[4] = {0x53, 0x63, 0x00, 0x00};
|
|||||||
static const uint8_t GET_POWER_STATE_CMD[4] = {0x53, 0x50, 0x00, 0x01};
|
static const uint8_t GET_POWER_STATE_CMD[4] = {0x53, 0x50, 0x00, 0x01};
|
||||||
|
|
||||||
void EKTF2232Touchscreen::setup() {
|
void EKTF2232Touchscreen::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
this->interrupt_pin_->setup();
|
this->interrupt_pin_->setup();
|
||||||
|
|
||||||
|
@ -57,8 +57,6 @@ static const uint8_t EMC2101_POLARITY_BIT = 1 << 4;
|
|||||||
float Emc2101Component::get_setup_priority() const { return setup_priority::HARDWARE; }
|
float Emc2101Component::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
void Emc2101Component::setup() {
|
void Emc2101Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
// make sure we're talking to the right chip
|
// make sure we're talking to the right chip
|
||||||
uint8_t chip_id = reg(EMC2101_REGISTER_WHOAMI).get();
|
uint8_t chip_id = reg(EMC2101_REGISTER_WHOAMI).get();
|
||||||
if ((chip_id != EMC2101_CHIP_ID) && (chip_id != EMC2101_ALT_CHIP_ID)) {
|
if ((chip_id != EMC2101_CHIP_ID) && (chip_id != EMC2101_ALT_CHIP_ID)) {
|
||||||
|
@ -49,8 +49,6 @@ static const uint8_t ENS160_DATA_STATUS_NEWGPR = 0x01;
|
|||||||
static const uint8_t ENS160_DATA_AQI = 0x07;
|
static const uint8_t ENS160_DATA_AQI = 0x07;
|
||||||
|
|
||||||
void ENS160Component::setup() {
|
void ENS160Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
// check part_id
|
// check part_id
|
||||||
uint16_t part_id;
|
uint16_t part_id;
|
||||||
if (!this->read_bytes(ENS160_REG_PART_ID, reinterpret_cast<uint8_t *>(&part_id), 2)) {
|
if (!this->read_bytes(ENS160_REG_PART_ID, reinterpret_cast<uint8_t *>(&part_id), 2)) {
|
||||||
|
@ -87,7 +87,6 @@ static uint32_t crc7(uint32_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ENS210Component::setup() {
|
void ENS210Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
uint16_t part_id = 0;
|
uint16_t part_id = 0;
|
||||||
// Reset
|
// Reset
|
||||||
|
@ -38,8 +38,6 @@ void ES7210::dump_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ES7210::setup() {
|
void ES7210::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
// Software reset
|
// Software reset
|
||||||
ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0xff));
|
ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0xff));
|
||||||
ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0x32));
|
ES7210_ERROR_FAILED(this->write_byte(ES7210_RESET_REG00, 0x32));
|
||||||
|
@ -34,8 +34,6 @@ void ES7243E::dump_config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ES7243E::setup() {
|
void ES7243E::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG01, 0x3A));
|
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_CLOCK_MGR_REG01, 0x3A));
|
||||||
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_RESET_REG00, 0x80));
|
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_RESET_REG00, 0x80));
|
||||||
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_TEST_MODE_REGF9, 0x00));
|
ES7243E_ERROR_FAILED(this->write_byte(ES7243E_TEST_MODE_REGF9, 0x00));
|
||||||
|
@ -17,8 +17,6 @@ static const char *const TAG = "es8156";
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ES8156::setup() {
|
void ES8156::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG02_SCLK_MODE, 0x04));
|
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG02_SCLK_MODE, 0x04));
|
||||||
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG20_ANALOG_SYS1, 0x2A));
|
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG20_ANALOG_SYS1, 0x2A));
|
||||||
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG21_ANALOG_SYS2, 0x3C));
|
ES8156_ERROR_FAILED(this->write_byte(ES8156_REG21_ANALOG_SYS2, 0x3C));
|
||||||
|
@ -22,8 +22,6 @@ static const char *const TAG = "es8311";
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ES8311::setup() {
|
void ES8311::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x1F));
|
ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x1F));
|
||||||
ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x00));
|
ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x00));
|
||||||
|
@ -23,8 +23,6 @@ static const char *const TAG = "es8388";
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ES8388::setup() {
|
void ES8388::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
// mute DAC
|
// mute DAC
|
||||||
this->set_mute_state_(true);
|
this->set_mute_state_(true);
|
||||||
|
|
||||||
|
@ -973,14 +973,16 @@ def _write_idf_component_yml():
|
|||||||
|
|
||||||
# Called by writer.py
|
# Called by writer.py
|
||||||
def copy_files():
|
def copy_files():
|
||||||
if CORE.using_arduino:
|
if (
|
||||||
if "partitions.csv" not in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES]:
|
CORE.using_arduino
|
||||||
write_file_if_changed(
|
and "partitions.csv" not in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES]
|
||||||
CORE.relative_build_path("partitions.csv"),
|
):
|
||||||
get_arduino_partition_csv(
|
write_file_if_changed(
|
||||||
CORE.platformio_options.get("board_upload.flash_size")
|
CORE.relative_build_path("partitions.csv"),
|
||||||
),
|
get_arduino_partition_csv(
|
||||||
)
|
CORE.platformio_options.get("board_upload.flash_size")
|
||||||
|
),
|
||||||
|
)
|
||||||
if CORE.using_esp_idf:
|
if CORE.using_esp_idf:
|
||||||
_write_sdkconfig()
|
_write_sdkconfig()
|
||||||
_write_idf_component_yml()
|
_write_idf_component_yml()
|
||||||
@ -1000,7 +1002,7 @@ def copy_files():
|
|||||||
__version__,
|
__version__,
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, file in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES].items():
|
for file in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES].values():
|
||||||
if file[KEY_PATH].startswith("http"):
|
if file[KEY_PATH].startswith("http"):
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
@ -25,8 +25,6 @@ static const char *const TAG = "esp32_ble";
|
|||||||
|
|
||||||
void ESP32BLE::setup() {
|
void ESP32BLE::setup() {
|
||||||
global_ble = this;
|
global_ble = this;
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
if (!ble_pre_setup_()) {
|
if (!ble_pre_setup_()) {
|
||||||
ESP_LOGE(TAG, "BLE could not be prepared for configuration");
|
ESP_LOGE(TAG, "BLE could not be prepared for configuration");
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
|
@ -140,20 +140,22 @@ VALUE_TYPES = {
|
|||||||
|
|
||||||
|
|
||||||
def validate_char_on_write(char_config):
|
def validate_char_on_write(char_config):
|
||||||
if CONF_ON_WRITE in char_config:
|
if (
|
||||||
if not char_config[CONF_WRITE] and not char_config[CONF_WRITE_NO_RESPONSE]:
|
CONF_ON_WRITE in char_config
|
||||||
raise cv.Invalid(
|
and not char_config[CONF_WRITE]
|
||||||
f"{CONF_ON_WRITE} requires the {CONF_WRITE} or {CONF_WRITE_NO_RESPONSE} property to be set"
|
and not char_config[CONF_WRITE_NO_RESPONSE]
|
||||||
)
|
):
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"{CONF_ON_WRITE} requires the {CONF_WRITE} or {CONF_WRITE_NO_RESPONSE} property to be set"
|
||||||
|
)
|
||||||
return char_config
|
return char_config
|
||||||
|
|
||||||
|
|
||||||
def validate_descriptor(desc_config):
|
def validate_descriptor(desc_config):
|
||||||
if CONF_ON_WRITE in desc_config:
|
if CONF_ON_WRITE in desc_config and not desc_config[CONF_WRITE]:
|
||||||
if not desc_config[CONF_WRITE]:
|
raise cv.Invalid(
|
||||||
raise cv.Invalid(
|
f"{CONF_ON_WRITE} requires the {CONF_WRITE} property to be set"
|
||||||
f"{CONF_ON_WRITE} requires the {CONF_WRITE} property to be set"
|
)
|
||||||
)
|
|
||||||
if CONF_MAX_LENGTH not in desc_config:
|
if CONF_MAX_LENGTH not in desc_config:
|
||||||
value = desc_config[CONF_VALUE][CONF_DATA]
|
value = desc_config[CONF_VALUE][CONF_DATA]
|
||||||
if cg.is_template(value):
|
if cg.is_template(value):
|
||||||
|
@ -310,9 +310,7 @@ async def to_code(config):
|
|||||||
for conf in config.get(CONF_ON_BLE_ADVERTISE, []):
|
for conf in config.get(CONF_ON_BLE_ADVERTISE, []):
|
||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
if CONF_MAC_ADDRESS in conf:
|
if CONF_MAC_ADDRESS in conf:
|
||||||
addr_list = []
|
addr_list = [it.as_hex for it in conf[CONF_MAC_ADDRESS]]
|
||||||
for it in conf[CONF_MAC_ADDRESS]:
|
|
||||||
addr_list.append(it.as_hex)
|
|
||||||
cg.add(trigger.set_addresses(addr_list))
|
cg.add(trigger.set_addresses(addr_list))
|
||||||
await automation.build_automation(trigger, [(ESPBTDeviceConstRef, "x")], conf)
|
await automation.build_automation(trigger, [(ESPBTDeviceConstRef, "x")], conf)
|
||||||
for conf in config.get(CONF_ON_BLE_SERVICE_DATA_ADVERTISE, []):
|
for conf in config.get(CONF_ON_BLE_SERVICE_DATA_ADVERTISE, []):
|
||||||
|
@ -20,7 +20,6 @@ static constexpr uint8_t DAC0_PIN = 25;
|
|||||||
static const char *const TAG = "esp32_dac";
|
static const char *const TAG = "esp32_dac";
|
||||||
|
|
||||||
void ESP32DAC::setup() {
|
void ESP32DAC::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->pin_->setup();
|
this->pin_->setup();
|
||||||
this->turn_off();
|
this->turn_off();
|
||||||
|
|
||||||
|
@ -59,8 +59,6 @@ static size_t IRAM_ATTR HOT encoder_callback(const void *data, size_t size, size
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ESP32RMTLEDStripLightOutput::setup() {
|
void ESP32RMTLEDStripLightOutput::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
size_t buffer_size = this->get_buffer_size_();
|
size_t buffer_size = this->get_buffer_size_();
|
||||||
|
|
||||||
RAMAllocator<uint8_t> allocator(this->use_psram_ ? 0 : RAMAllocator<uint8_t>::ALLOC_INTERNAL);
|
RAMAllocator<uint8_t> allocator(this->use_psram_ ? 0 : RAMAllocator<uint8_t>::ALLOC_INTERNAL);
|
||||||
|
@ -294,9 +294,8 @@ async def to_code(config):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if get_esp32_variant() == VARIANT_ESP32:
|
if get_esp32_variant() == VARIANT_ESP32 and CONF_IIR_FILTER in config:
|
||||||
if CONF_IIR_FILTER in config:
|
cg.add(touch.set_iir_filter(config[CONF_IIR_FILTER]))
|
||||||
cg.add(touch.set_iir_filter(config[CONF_IIR_FILTER]))
|
|
||||||
|
|
||||||
if get_esp32_variant() == VARIANT_ESP32S2 or get_esp32_variant() == VARIANT_ESP32S3:
|
if get_esp32_variant() == VARIANT_ESP32S2 or get_esp32_variant() == VARIANT_ESP32S3:
|
||||||
if CONF_FILTER_MODE in config:
|
if CONF_FILTER_MODE in config:
|
||||||
|
@ -245,7 +245,7 @@ async def to_code(config):
|
|||||||
if ver <= cv.Version(2, 3, 0):
|
if ver <= cv.Version(2, 3, 0):
|
||||||
# No ld script support
|
# No ld script support
|
||||||
ld_script = None
|
ld_script = None
|
||||||
if ver <= cv.Version(2, 4, 2):
|
elif ver <= cv.Version(2, 4, 2):
|
||||||
# Old ld script path
|
# Old ld script path
|
||||||
ld_script = ld_scripts[0]
|
ld_script = ld_scripts[0]
|
||||||
else:
|
else:
|
||||||
|
@ -14,7 +14,6 @@ namespace esp8266_pwm {
|
|||||||
static const char *const TAG = "esp8266_pwm";
|
static const char *const TAG = "esp8266_pwm";
|
||||||
|
|
||||||
void ESP8266PWM::setup() {
|
void ESP8266PWM::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->pin_->setup();
|
this->pin_->setup();
|
||||||
this->turn_off();
|
this->turn_off();
|
||||||
}
|
}
|
||||||
|
@ -73,8 +73,7 @@ def ota_esphome_final_validate(config):
|
|||||||
else:
|
else:
|
||||||
new_ota_conf.append(ota_conf)
|
new_ota_conf.append(ota_conf)
|
||||||
|
|
||||||
for port_conf in merged_ota_esphome_configs_by_port.values():
|
new_ota_conf.extend(merged_ota_esphome_configs_by_port.values())
|
||||||
new_ota_conf.append(port_conf)
|
|
||||||
|
|
||||||
full_conf[CONF_OTA] = new_ota_conf
|
full_conf[CONF_OTA] = new_ota_conf
|
||||||
fv.full_config.set(full_conf)
|
fv.full_config.set(full_conf)
|
||||||
|
@ -112,7 +112,7 @@ def _is_framework_spi_polling_mode_supported():
|
|||||||
return True
|
return True
|
||||||
if cv.Version(5, 3, 0) > framework_version >= cv.Version(5, 2, 1):
|
if cv.Version(5, 3, 0) > framework_version >= cv.Version(5, 2, 1):
|
||||||
return True
|
return True
|
||||||
if cv.Version(5, 2, 0) > framework_version >= cv.Version(5, 1, 4):
|
if cv.Version(5, 2, 0) > framework_version >= cv.Version(5, 1, 4): # noqa: SIM103
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
if CORE.using_arduino:
|
if CORE.using_arduino:
|
||||||
|
@ -54,7 +54,6 @@ EthernetComponent *global_eth_component; // NOLINT(cppcoreguidelines-avoid-non-
|
|||||||
EthernetComponent::EthernetComponent() { global_eth_component = this; }
|
EthernetComponent::EthernetComponent() { global_eth_component = this; }
|
||||||
|
|
||||||
void EthernetComponent::setup() {
|
void EthernetComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (esp_reset_reason() != ESP_RST_DEEPSLEEP) {
|
if (esp_reset_reason() != ESP_RST_DEEPSLEEP) {
|
||||||
// Delay here to allow power to stabilise before Ethernet is initialized.
|
// Delay here to allow power to stabilise before Ethernet is initialized.
|
||||||
delay(300); // NOLINT
|
delay(300); // NOLINT
|
||||||
|
@ -1,5 +1,97 @@
|
|||||||
|
from esphome.automation import Trigger, build_automation, validate_automation
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
|
from esphome.components.esp8266 import CONF_RESTORE_FROM_FLASH, KEY_ESP8266
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_TRIGGER_ID,
|
||||||
|
PLATFORM_BK72XX,
|
||||||
|
PLATFORM_ESP32,
|
||||||
|
PLATFORM_ESP8266,
|
||||||
|
PLATFORM_LN882X,
|
||||||
|
PLATFORM_RTL87XX,
|
||||||
|
)
|
||||||
|
from esphome.core import CORE
|
||||||
|
from esphome.final_validate import full_config
|
||||||
|
|
||||||
CODEOWNERS = ["@anatoly-savchenkov"]
|
CODEOWNERS = ["@anatoly-savchenkov"]
|
||||||
|
|
||||||
factory_reset_ns = cg.esphome_ns.namespace("factory_reset")
|
factory_reset_ns = cg.esphome_ns.namespace("factory_reset")
|
||||||
|
FactoryResetComponent = factory_reset_ns.class_("FactoryResetComponent", cg.Component)
|
||||||
|
FastBootTrigger = factory_reset_ns.class_("FastBootTrigger", Trigger, cg.Component)
|
||||||
|
|
||||||
|
CONF_MAX_DELAY = "max_delay"
|
||||||
|
CONF_RESETS_REQUIRED = "resets_required"
|
||||||
|
CONF_ON_INCREMENT = "on_increment"
|
||||||
|
|
||||||
|
|
||||||
|
def _validate(config):
|
||||||
|
if CONF_RESETS_REQUIRED in config:
|
||||||
|
return cv.only_on(
|
||||||
|
[
|
||||||
|
PLATFORM_BK72XX,
|
||||||
|
PLATFORM_ESP32,
|
||||||
|
PLATFORM_ESP8266,
|
||||||
|
PLATFORM_LN882X,
|
||||||
|
PLATFORM_RTL87XX,
|
||||||
|
]
|
||||||
|
)(config)
|
||||||
|
|
||||||
|
if CONF_ON_INCREMENT in config:
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"'{CONF_ON_INCREMENT}' requires a value for '{CONF_RESETS_REQUIRED}'"
|
||||||
|
)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(FactoryResetComponent),
|
||||||
|
cv.Optional(CONF_MAX_DELAY, default="10s"): cv.All(
|
||||||
|
cv.positive_time_period_seconds,
|
||||||
|
cv.Range(min=cv.TimePeriod(milliseconds=1000)),
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_RESETS_REQUIRED): cv.positive_not_null_int,
|
||||||
|
cv.Optional(CONF_ON_INCREMENT): validate_automation(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(FastBootTrigger),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
|
_validate,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _final_validate(config):
|
||||||
|
if CORE.is_esp8266 and CONF_RESETS_REQUIRED in config:
|
||||||
|
fconfig = full_config.get()
|
||||||
|
if not fconfig.get_config_for_path([KEY_ESP8266, CONF_RESTORE_FROM_FLASH]):
|
||||||
|
raise cv.Invalid(
|
||||||
|
"'resets_required' needs 'restore_from_flash' to be enabled in the 'esp8266' configuration"
|
||||||
|
)
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
if reset_count := config.get(CONF_RESETS_REQUIRED):
|
||||||
|
var = cg.new_Pvariable(
|
||||||
|
config[CONF_ID],
|
||||||
|
reset_count,
|
||||||
|
config[CONF_MAX_DELAY].total_milliseconds,
|
||||||
|
)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
for conf in config.get(CONF_ON_INCREMENT, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await build_automation(
|
||||||
|
trigger,
|
||||||
|
[
|
||||||
|
(cg.uint8, "x"),
|
||||||
|
(cg.uint8, "target"),
|
||||||
|
],
|
||||||
|
conf,
|
||||||
|
)
|
||||||
|
76
esphome/components/factory_reset/factory_reset.cpp
Normal file
76
esphome/components/factory_reset/factory_reset.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include "factory_reset.h"
|
||||||
|
|
||||||
|
#include "esphome/core/application.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
#if !defined(USE_RP2040) && !defined(USE_HOST)
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace factory_reset {
|
||||||
|
|
||||||
|
static const char *const TAG = "factory_reset";
|
||||||
|
static const uint32_t POWER_CYCLES_KEY = 0xFA5C0DE;
|
||||||
|
|
||||||
|
static bool was_power_cycled() {
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
return esp_reset_reason() == ESP_RST_POWERON;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_ESP8266
|
||||||
|
auto reset_reason = EspClass::getResetReason();
|
||||||
|
return strcasecmp(reset_reason.c_str(), "power On") == 0 || strcasecmp(reset_reason.c_str(), "external system") == 0;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_LIBRETINY
|
||||||
|
auto reason = lt_get_reboot_reason();
|
||||||
|
return reason == REBOOT_REASON_POWER || reason == REBOOT_REASON_HARDWARE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void FactoryResetComponent::dump_config() {
|
||||||
|
uint8_t count = 0;
|
||||||
|
this->flash_.load(&count);
|
||||||
|
ESP_LOGCONFIG(TAG, "Factory Reset by Reset:");
|
||||||
|
ESP_LOGCONFIG(TAG,
|
||||||
|
" Max interval between resets %" PRIu32 " seconds\n"
|
||||||
|
" Current count: %u\n"
|
||||||
|
" Factory reset after %u resets",
|
||||||
|
this->max_interval_ / 1000, count, this->required_count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FactoryResetComponent::save_(uint8_t count) {
|
||||||
|
this->flash_.save(&count);
|
||||||
|
global_preferences->sync();
|
||||||
|
this->defer([count, this] { this->increment_callback_.call(count, this->required_count_); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void FactoryResetComponent::setup() {
|
||||||
|
this->flash_ = global_preferences->make_preference<uint8_t>(POWER_CYCLES_KEY, true);
|
||||||
|
if (was_power_cycled()) {
|
||||||
|
uint8_t count = 0;
|
||||||
|
this->flash_.load(&count);
|
||||||
|
// this is a power on reset or external system reset
|
||||||
|
count++;
|
||||||
|
if (count == this->required_count_) {
|
||||||
|
ESP_LOGW(TAG, "Reset count reached, factory resetting");
|
||||||
|
global_preferences->reset();
|
||||||
|
// delay to allow log to be sent
|
||||||
|
delay(100); // NOLINT
|
||||||
|
App.safe_reboot(); // should not return
|
||||||
|
}
|
||||||
|
this->save_(count);
|
||||||
|
ESP_LOGD(TAG, "Power on reset detected, incremented count to %u", count);
|
||||||
|
this->set_timeout(this->max_interval_, [this]() {
|
||||||
|
ESP_LOGD(TAG, "No reset in the last %" PRIu32 " seconds, resetting count", this->max_interval_ / 1000);
|
||||||
|
this->save_(0); // reset count
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this->save_(0); // reset count if not a power cycle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace factory_reset
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // !defined(USE_RP2040) && !defined(USE_HOST)
|
43
esphome/components/factory_reset/factory_reset.h
Normal file
43
esphome/components/factory_reset/factory_reset.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/core/preferences.h"
|
||||||
|
#if !defined(USE_RP2040) && !defined(USE_HOST)
|
||||||
|
|
||||||
|
#ifdef USE_ESP32
|
||||||
|
#include <esp_system.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace factory_reset {
|
||||||
|
class FactoryResetComponent : public Component {
|
||||||
|
public:
|
||||||
|
FactoryResetComponent(uint8_t required_count, uint32_t max_interval)
|
||||||
|
: required_count_(required_count), max_interval_(max_interval) {}
|
||||||
|
|
||||||
|
void dump_config() override;
|
||||||
|
void setup() override;
|
||||||
|
void add_increment_callback(std::function<void(uint8_t, uint8_t)> &&callback) {
|
||||||
|
this->increment_callback_.add(std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~FactoryResetComponent() = default;
|
||||||
|
void save_(uint8_t count);
|
||||||
|
ESPPreferenceObject flash_{}; // saves the number of fast power cycles
|
||||||
|
uint8_t required_count_; // The number of boot attempts before fast boot is enabled
|
||||||
|
uint32_t max_interval_; // max interval between power cycles
|
||||||
|
CallbackManager<void(uint8_t, uint8_t)> increment_callback_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class FastBootTrigger : public Trigger<uint8_t, uint8_t> {
|
||||||
|
public:
|
||||||
|
explicit FastBootTrigger(FactoryResetComponent *parent) {
|
||||||
|
parent->add_increment_callback([this](uint8_t current, uint8_t target) { this->trigger(current, target); });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace factory_reset
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif // !defined(USE_RP2040) && !defined(USE_HOST)
|
@ -9,7 +9,6 @@ namespace fastled_base {
|
|||||||
static const char *const TAG = "fastled";
|
static const char *const TAG = "fastled";
|
||||||
|
|
||||||
void FastLEDLightOutput::setup() {
|
void FastLEDLightOutput::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->controller_->init();
|
this->controller_->init();
|
||||||
this->controller_->setLeds(this->leds_, this->num_leds_);
|
this->controller_->setLeds(this->leds_, this->num_leds_);
|
||||||
this->effect_data_ = new uint8_t[this->num_leds_]; // NOLINT
|
this->effect_data_ = new uint8_t[this->num_leds_]; // NOLINT
|
||||||
|
@ -55,9 +55,7 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = await fastled_base.new_fastled_light(config)
|
var = await fastled_base.new_fastled_light(config)
|
||||||
|
|
||||||
rgb_order = cg.RawExpression(
|
rgb_order = cg.RawExpression(config.get(CONF_RGB_ORDER, "RGB"))
|
||||||
config[CONF_RGB_ORDER] if CONF_RGB_ORDER in config else "RGB"
|
|
||||||
)
|
|
||||||
data_rate = None
|
data_rate = None
|
||||||
|
|
||||||
if CONF_DATA_RATE in config:
|
if CONF_DATA_RATE in config:
|
||||||
|
@ -57,8 +57,6 @@ void FingerprintGrowComponent::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FingerprintGrowComponent::setup() {
|
void FingerprintGrowComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
this->has_sensing_pin_ = (this->sensing_pin_ != nullptr);
|
this->has_sensing_pin_ = (this->sensing_pin_ != nullptr);
|
||||||
this->has_power_pin_ = (this->sensor_power_pin_ != nullptr);
|
this->has_power_pin_ = (this->sensor_power_pin_ != nullptr);
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@ namespace fs3000 {
|
|||||||
static const char *const TAG = "fs3000";
|
static const char *const TAG = "fs3000";
|
||||||
|
|
||||||
void FS3000Component::setup() {
|
void FS3000Component::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
|
|
||||||
if (model_ == FIVE) {
|
if (model_ == FIVE) {
|
||||||
// datasheet gives 9 points to interpolate from for the 1005 model
|
// datasheet gives 9 points to interpolate from for the 1005 model
|
||||||
static const uint16_t RAW_DATA_POINTS_1005[9] = {409, 915, 1522, 2066, 2523, 2908, 3256, 3572, 3686};
|
static const uint16_t RAW_DATA_POINTS_1005[9] = {409, 915, 1522, 2066, 2523, 2908, 3256, 3572, 3686};
|
||||||
|
@ -9,7 +9,6 @@ namespace ft5x06 {
|
|||||||
static const char *const TAG = "ft5x06.touchscreen";
|
static const char *const TAG = "ft5x06.touchscreen";
|
||||||
|
|
||||||
void FT5x06Touchscreen::setup() {
|
void FT5x06Touchscreen::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (this->interrupt_pin_ != nullptr) {
|
if (this->interrupt_pin_ != nullptr) {
|
||||||
this->interrupt_pin_->setup();
|
this->interrupt_pin_->setup();
|
||||||
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
@ -50,7 +49,6 @@ void FT5x06Touchscreen::continue_setup_() {
|
|||||||
this->y_raw_max_ = this->display_->get_native_height();
|
this->y_raw_max_ = this->display_->get_native_height();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGCONFIG(TAG, "FT5x06 Touchscreen setup complete");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FT5x06Touchscreen::update_touches() {
|
void FT5x06Touchscreen::update_touches() {
|
||||||
|
@ -28,7 +28,6 @@ static const uint8_t FT63X6_ADDR_CHIP_ID = 0xA3;
|
|||||||
static const char *const TAG = "FT63X6";
|
static const char *const TAG = "FT63X6";
|
||||||
|
|
||||||
void FT63X6Touchscreen::setup() {
|
void FT63X6Touchscreen::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
if (this->interrupt_pin_ != nullptr) {
|
if (this->interrupt_pin_ != nullptr) {
|
||||||
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
this->interrupt_pin_->setup();
|
this->interrupt_pin_->setup();
|
||||||
|
@ -34,7 +34,6 @@ void GDK101Component::update() {
|
|||||||
|
|
||||||
void GDK101Component::setup() {
|
void GDK101Component::setup() {
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
// first, reset the sensor
|
// first, reset the sensor
|
||||||
if (!this->reset_sensor_(data)) {
|
if (!this->reset_sensor_(data)) {
|
||||||
this->status_set_error("Reset failed!");
|
this->status_set_error("Reset failed!");
|
||||||
|
@ -17,7 +17,6 @@ static const uint8_t RESTART_CMD2 = 0xA5;
|
|||||||
static const uint8_t READ_DELAY = 40; // minimum milliseconds from datasheet to safely read measurement result
|
static const uint8_t READ_DELAY = 40; // minimum milliseconds from datasheet to safely read measurement result
|
||||||
|
|
||||||
void GLR01I2CComponent::setup() {
|
void GLR01I2CComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up GL-R01 I2C...");
|
|
||||||
// Verify sensor presence
|
// Verify sensor presence
|
||||||
if (!this->read_byte_16(REG_VERSION, &this->version_)) {
|
if (!this->read_byte_16(REG_VERSION, &this->version_)) {
|
||||||
ESP_LOGE(TAG, "Failed to communicate with GL-R01 I2C sensor!");
|
ESP_LOGE(TAG, "Failed to communicate with GL-R01 I2C sensor!");
|
||||||
|
@ -8,7 +8,6 @@ namespace gpio {
|
|||||||
static const char *const TAG = "gpio.one_wire";
|
static const char *const TAG = "gpio.one_wire";
|
||||||
|
|
||||||
void GPIOOneWireBus::setup() {
|
void GPIOOneWireBus::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup");
|
|
||||||
this->t_pin_->setup();
|
this->t_pin_->setup();
|
||||||
this->t_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
this->t_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
// clear bus with 480µs high, otherwise initial reset in search might fail
|
// clear bus with 480µs high, otherwise initial reset in search might fail
|
||||||
|
@ -8,8 +8,6 @@ static const char *const TAG = "switch.gpio";
|
|||||||
|
|
||||||
float GPIOSwitch::get_setup_priority() const { return setup_priority::HARDWARE; }
|
float GPIOSwitch::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
void GPIOSwitch::setup() {
|
void GPIOSwitch::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->name_.c_str());
|
|
||||||
|
|
||||||
bool initial_state = this->get_initial_state_with_restore_mode().value_or(false);
|
bool initial_state = this->get_initial_state_with_restore_mode().value_or(false);
|
||||||
|
|
||||||
// write state before setup
|
// write state before setup
|
||||||
|
@ -84,7 +84,6 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
)
|
)
|
||||||
.extend(cv.polling_component_schema("20s"))
|
.extend(cv.polling_component_schema("20s"))
|
||||||
.extend(uart.UART_DEVICE_SCHEMA),
|
.extend(uart.UART_DEVICE_SCHEMA),
|
||||||
cv.only_with_arduino,
|
|
||||||
)
|
)
|
||||||
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema("gps", require_rx=True)
|
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema("gps", require_rx=True)
|
||||||
|
|
||||||
@ -123,4 +122,9 @@ async def to_code(config):
|
|||||||
cg.add(var.set_hdop_sensor(sens))
|
cg.add(var.set_hdop_sensor(sens))
|
||||||
|
|
||||||
# https://platformio.org/lib/show/1655/TinyGPSPlus
|
# https://platformio.org/lib/show/1655/TinyGPSPlus
|
||||||
cg.add_library("mikalhart/TinyGPSPlus", "1.1.0")
|
# Using fork of TinyGPSPlus patched to build on ESP-IDF
|
||||||
|
cg.add_library(
|
||||||
|
"TinyGPSPlus",
|
||||||
|
None,
|
||||||
|
"https://github.com/esphome/TinyGPSPlus.git#v1.1.0",
|
||||||
|
)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user