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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
# Clang-Tidy configuration for OpenEVSE ESP32 Firmware
# This configuration enforces naming conventions and common C++ best practices
# See NAMING_CONVENTIONS.md for detailed documentation

Checks: >
readability-identifier-naming,
readability-inconsistent-declaration-parameter-name,
readability-misleading-indentation,
modernize-use-nullptr,
modernize-use-override,
performance-for-range-copy,
performance-implicit-conversion-in-loop,
performance-inefficient-string-concatenation

# Naming convention enforcement
CheckOptions:
# Classes and Structs: PascalCase
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.StructCase
value: CamelCase

# Enums: PascalCase
- key: readability-identifier-naming.EnumCase
value: CamelCase

# Enum constants for plain enums: UPPER_SNAKE_CASE
# Note: This applies to plain enums. Scoped enums should use PascalCase
# but clang-tidy can't distinguish between the two automatically
- key: readability-identifier-naming.EnumConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.EnumConstantPrefix
value: ''

# Functions and Methods: camelCase
- key: readability-identifier-naming.FunctionCase
value: camelBack
- key: readability-identifier-naming.MethodCase
value: camelBack

# Member Variables: _snake_case (underscore prefix)
- key: readability-identifier-naming.PrivateMemberCase
value: lower_case
- key: readability-identifier-naming.PrivateMemberPrefix
value: '_'
- key: readability-identifier-naming.ProtectedMemberCase
value: lower_case
- key: readability-identifier-naming.ProtectedMemberPrefix
value: '_'

# Public member variables: snake_case (no underscore)
# This is for structs and public data members
- key: readability-identifier-naming.PublicMemberCase
value: lower_case

# Local Variables: camelCase (preferred)
# Note: snake_case is also acceptable for legacy compatibility
# We set this to camelCase for new code
- key: readability-identifier-naming.VariableCase
value: camelBack

# Parameters: camelCase (preferred)
- key: readability-identifier-naming.ParameterCase
value: camelBack

# Global Variables: snake_case
- key: readability-identifier-naming.GlobalVariableCase
value: lower_case

# Constants: UPPER_SNAKE_CASE
- key: readability-identifier-naming.ConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.GlobalConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.StaticConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.ConstexprVariableCase
value: UPPER_CASE

# Macros: UPPER_SNAKE_CASE
- key: readability-identifier-naming.MacroDefinitionCase
value: UPPER_CASE
- key: readability-identifier-naming.MacroDefinitionIgnoredRegexp
value: '^(_.*|DEBUG_PORT)$'

# Namespaces: lowercase or snake_case
- key: readability-identifier-naming.NamespaceCase
value: lower_case

# Template Parameters: PascalCase
- key: readability-identifier-naming.TemplateParameterCase
value: CamelCase

# Type Aliases and Typedefs: PascalCase
- key: readability-identifier-naming.TypeAliasCase
value: CamelCase
- key: readability-identifier-naming.TypedefCase
value: CamelCase

# Exclude external libraries and generated code
HeaderFilterRegex: '^.*/(src|lib)/.*\.(h|hpp)$'

# Set to warnings (not errors) for legacy code compatibility
# New code should still aim to pass all checks
WarningsAsErrors: ''
...

18 changes: 13 additions & 5 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,19 @@ pio run -e openevse_wifi_v1 # Expected to fail with HTTPClientError in restrict
## Coding Conventions and Patterns

### Naming Conventions:
- **Config variables**: `snake_case` (e.g., `mqtt_server`, `divert_type`, `led_brightness`)
- **Private members**: `_snake_case` with leading underscore (e.g., `_openevse`, `_state`, `_pilot`)
- **Constants/defines**: `UPPER_SNAKE_CASE` (e.g., `CONFIG_OFFSET`, `EVSE_MONITOR_POLL_TIME`)
- **Classes**: `PascalCase` (e.g., `EvseMonitor`, `LcdTask`, `MongooseHttpServer`)
- **Enum values**: `UPPER_SNAKE_CASE` (e.g., `OPENEVSE_STATE_STARTING`)

**Complete naming conventions are documented in [NAMING_CONVENTIONS.md](../NAMING_CONVENTIONS.md)**

Quick reference:
- **Classes/Structs**: `PascalCase` (e.g., `EvseMonitor`, `LcdTask`, `MongooseHttpServer`)
- **Functions/Methods**: `camelCase` (e.g., `getState()`, `setChargeCurrent()`)
- **Member variables**: `_snake_case` with leading underscore (e.g., `_openevse`, `_state`, `_pilot`)
- **Local variables**: `camelCase` preferred (e.g., `chargeCurrent`), `snake_case` acceptable
- **Global variables**: `snake_case` (e.g., `mqtt_server`, `divert_type`, `led_brightness`)
- **Constants/Macros**: `UPPER_SNAKE_CASE` (e.g., `CONFIG_OFFSET`, `EVSE_MONITOR_POLL_TIME`)
- **Enum types**: `PascalCase` (e.g., `LedState`, `ScreenType`)
- **Enum values (plain)**: `UPPER_SNAKE_CASE` with prefix (e.g., `SCREEN_BOOT`, `WIFI_DISCONNECT_REASON_AUTH_FAIL`)
- **Enum values (scoped)**: `PascalCase` (e.g., `LimitType::Energy`, `DivertMode::Normal`)

### RAPI Command Integration:
- **Pattern**: Use callback-based async RAPI commands with lambda functions
Expand Down
120 changes: 120 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
name: Lint C++ Code

on:
pull_request:
paths:
- 'src/**/*.cpp'
- 'src/**/*.h'
- '.clang-tidy'
- '.github/workflows/lint.yaml'

jobs:
clang-tidy:
name: Run clang-tidy
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: false # Don't need GUI submodules for C++ linting

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

- name: Cache PlatformIO
uses: actions/cache@v5
with:
path: ~/.platformio
key: ${{ runner.os }}-platformio-lint-${{ hashFiles('platformio.ini') }}
restore-keys: |
${{ runner.os }}-platformio-lint-

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.x'

- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio

# We need to get the include paths from PlatformIO without doing a full build
# This creates the .pio directory structure with include paths
- name: Initialize PlatformIO environment
run: |
pio pkg install -e openevse_wifi_v1 || true
continue-on-error: true

- name: Get changed C++ files
id: changed-files
uses: tj-actions/changed-files@v46
with:
files: |
src/**/*.cpp
src/**/*.h

- name: Run clang-tidy on changed files
if: steps.changed-files.outputs.any_changed == 'true'
run: |
echo "Running clang-tidy on changed files:"
echo "${{ steps.changed-files.outputs.all_changed_files }}"

# Build compile_commands.json for better analysis
pio run -e openevse_wifi_v1 -t compiledb 2>/dev/null || true

# Get include paths
INCLUDES="-Isrc -Ilib"
if [ -d ".pio/libdeps/openevse_wifi_v1" ]; then
for dir in .pio/libdeps/openevse_wifi_v1/*/; do
INCLUDES="$INCLUDES -I$dir"
if [ -d "$dir/src" ]; then
INCLUDES="$INCLUDES -I$dir/src"
fi
done
fi

# ESP32 Arduino core includes
if [ -d "$HOME/.platformio/packages/framework-arduinoespressif32" ]; then
INCLUDES="$INCLUDES -I$HOME/.platformio/packages/framework-arduinoespressif32/cores/esp32"
INCLUDES="$INCLUDES -I$HOME/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include"
fi

# Run clang-tidy on each changed file
EXIT_CODE=0
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
echo "Checking $file..."
if clang-tidy "$file" -- $INCLUDES -DARDUINO=10819 -DESP32 -std=gnu++11 2>&1 | tee clang-tidy-output.txt; then
echo "✓ $file passed"
else
echo "✗ $file has issues"
EXIT_CODE=1
fi
done

# Print summary
if [ $EXIT_CODE -eq 0 ]; then
echo "✓ All files passed clang-tidy checks"
else
echo "✗ Some files have naming convention violations"
echo "Please review the output above and fix the issues"
echo "See NAMING_CONVENTIONS.md for details on naming conventions"
fi

exit $EXIT_CODE

- name: Comment on PR (if issues found)
if: failure()
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '⚠️ **Naming Convention Issues Detected**\n\nThe clang-tidy check found naming convention violations in your code. Please review the [NAMING_CONVENTIONS.md](https://github.com/OpenEVSE/openevse_esp32_firmware/blob/master/NAMING_CONVENTIONS.md) document and fix the issues.\n\nRun `clang-tidy` locally to see detailed issues:\n```bash\nclang-tidy src/your_file.cpp -- -Isrc -Ilib\n```'
})
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ ubuntu-xenial-16.04-cloudimg-console.log

# VSCode stuff
.vscode
# But allow shared project settings
!.vscode/settings.json
!.vscode/extensions.json
.vscode/browse.vc.db*
.vscode/c_cpp_properties.json
.vscode/*.db
Expand Down
35 changes: 35 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
// OpenEVSE ESP32 Firmware - Recommended VS Code Extensions
"recommendations": [
// C/C++ Development
"ms-vscode.cpptools",
"ms-vscode.cpptools-extension-pack",

// PlatformIO Integration
"platformio.platformio-ide",

// Code Quality
"llvm-vs-code-extensions.vscode-clangd",
"notskm.clang-tidy",

// Git Integration
"eamodio.gitlens",

// EditorConfig Support
"editorconfig.editorconfig",

// JavaScript/TypeScript (for GUI development)
"dbaeumer.vscode-eslint",
"svelte.svelte-vscode",

// Markdown Documentation
"yzhang.markdown-all-in-one",

// YAML (for workflows)
"redhat.vscode-yaml",

// General Utilities
"streetsidesoftware.code-spell-checker",
"wayou.vscode-todo-highlight"
]
}
95 changes: 95 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{
// OpenEVSE ESP32 Firmware - VS Code Settings
// These settings align with the project's naming conventions documented in NAMING_CONVENTIONS.md

// Editor Settings
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.detectIndentation": false,
"editor.rulers": [100],
"editor.formatOnSave": false,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.encoding": "utf8",

// C/C++ Extension Settings
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 2, ColumnLimit: 100 }",
"C_Cpp.clang_format_sortIncludes": false,
"C_Cpp.codeAnalysis.clangTidy.enabled": true,
"C_Cpp.codeAnalysis.clangTidy.path": "clang-tidy",
"C_Cpp.codeAnalysis.clangTidy.config": "",
"C_Cpp.codeAnalysis.clangTidy.useBuildPath": false,

// File Associations
"files.associations": {
"*.h": "cpp",
"*.cpp": "cpp",
"*.ino": "cpp"
},

// Exclude build artifacts from search
"files.exclude": {
"**/.pio": true,
"**/.vscode/.browse.c_cpp.db*": true,
"**/.vscode/c_cpp_properties.json": true,
"**/.vscode/launch.json": true
},

"search.exclude": {
"**/.pio": true,
"**/node_modules": true,
"**/gui-v2/dist": true
},

// PlatformIO Integration
"platformio-ide.autoRebuildAutocompleteIndex": true,
"platformio-ide.useBuiltinPIOCore": true,
"platformio-ide.activateOnlyOnPlatformIOProject": false,

// Git Settings
"git.ignoreLimitWarning": true,

// Language Specific Settings
"[cpp]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "ms-vscode.cpptools"
},
"[c]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "ms-vscode.cpptools"
},
"[javascript]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[typescript]": {
"editor.tabSize": 2,
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[json]": {
"editor.tabSize": 2
},
"[markdown]": {
"editor.tabSize": 2,
"files.trimTrailingWhitespace": false
},

// Naming Convention Hints (displayed in IntelliSense)
"C_Cpp.errorSquiggles": "enabled",
"C_Cpp.intelliSenseEngine": "default",
"C_Cpp.enhancedColorization": "enabled",

// Recommended Extensions Banner
"extensions.ignoreRecommendations": false,

// Terminal Settings
"terminal.integrated.env.linux": {
"PATH": "${env:HOME}/.platformio/penv/bin:${env:PATH}"
},
"terminal.integrated.env.osx": {
"PATH": "${env:HOME}/.platformio/penv/bin:${env:PATH}"
},
"terminal.integrated.env.windows": {
"PATH": "${env:USERPROFILE}\\.platformio\\penv\\Scripts;${env:PATH}"
}
}
Loading
Loading