The project uses ESPHome for building firmware. Test configurations are in the tests/ directory.
esphome build tests/<test-name>.yamlExample:
esphome build tests/esp32-idf.yamlesphome run tests/<test-name>.yamlesphome clean tests/<test-name>.yamlThere are no automated linters configured in the repository. However, follow these guidelines:
- Use 2 spaces for indentation (no tabs)
- Keep line length under 120 characters
- Use quoted strings for special values (e.g.,
"true","123") - Validate YAML syntax with online tools or
yamllintif available locally
- Follow the existing code style (see section 2 below)
- No automatic formatter configured; maintain consistency with surrounding code
This repository does not contain unit tests. Validation is done by:
- Building each test configuration in the CI (see
.github/workflows/main.yml) - Manual verification on hardware
To verify a change builds successfully for all test configurations:
# From the repository root
for f in tests/*.yaml; do
if [[ "$f" != *"secrets"* ]]; then
echo "Building $f"
esphome build "$f" || exit 1
fi
done- Components live in
components/ehmtxv2/ - Header files:
.h - Implementation files:
.cpp - Python configuration:
__init__.py
- Indentation: 2 spaces (no tabs)
- Line length: Aim for <= 120 characters
- Braces:
- Opening brace on same line for functions, classes, namespaces
- Opening brace on new line for structs/enums (follow existing usage)
- Pointer/Reference:
Type*andType&(no spaces around*/&) - Spaces:
- After commas in function calls and parameters
- Around binary operators (
+,-,==, etc.) - No spaces after
(or before)
- Order:
- Standard library (
<vector>,<string>, etc.) - ESPHome core (
esphome.h) - ESPHome components (
esphome/components/...) - Other ESPHome components (if any)
- Local component headers (
EHMTX.h,EHMTX_queue.h, etc.)
- Standard library (
- Each import on its own line
- Use
#ifndefheader guards with_Hsuffix
- Use ESPHome types when available:
uint8_t,uint16_t,uint32_tfor integersboolfor booleansstd::stringfor stringsColorfor RGB colors (defined in esphome.h)esphome::display::BaseFont*for fonts
- Avoid raw pointers when possible; use ESPHome's smart pointers for components
- For arrays: prefer
std::arrayorstd::vectorover raw arrays when size is variable
- Classes:
PascalCase(e.g.,EHMTX,EHMTX_queue) - Functions and methods:
snake_case(e.g.,setup(),draw_text()) - Member variables:
snake_casewith trailing underscore (e.g.,brightness_,screen_pointer_) - Constants:
UPPER_SNAKE_CASE(e.g.,MAXQUEUE,POLINGINTERVAL) - Enums:
PascalCasefor enum name,UPPER_SNAKE_CASEfor values (e.g.,show_mode::MODE_CLOCK) - Namespaces:
lowercase(e.g.,esphome)
- Use ESPHome's logging macros:
ESP_LOGD(tag, format, ...)for debugESP_LOGI(tag, format, ...)for infoESP_LOGW(tag, format, ...)for warningsESP_LOGE(tag, format, ...)for errorsESP_LOGXX_FORCE_TAG(tag, ...)to force tag
- Define
static const char *const TAG = "EHMTXv2";at top of files - For recoverable errors, log and return safe defaults
- For unrecoverable errors in setup, consider
ESP_LOGEand halt execution - Validate inputs in public methods (e.g., check for null pointers, valid ranges)
- Indentation: 4 spaces (standard Python)
- Line length: Aim for <= 88 characters (Black style)
- Imports:
- Standard library first
- Third-party (PIL, requests) second
- ESPHome modules last
- Each import grouped and sorted alphabetically within group
- Use
from esphome import ...for ESPHome imports
- Variables and functions:
snake_case - Constants:
UPPER_SNAKE_CASE - Classes:
PascalCase
- Use
try/exceptfor specific exceptions:try: # operation except SpecificError as e: raise core.EsphomeError(f"Context: {e}")
- Avoid bare
except:clauses - Log warnings with
logging.warning()for recoverable issues - Use
logging.info()for non-error status updates
- Use
cv.for config validation (fromesphome.config_validation) - Use
cg.for code generation (fromesphome.codegen) - Access config values via
config[CONF_KEY] - Use
CORE.relative_config_path(path)for file paths - Register triggers with
automation.build_automation()
- All user-facing options use
CONF_*constants defined in__init__.py - Add new options to both the schema and the
to_codefunction - Use
cv.Optionalwith sensible defaults for new features - Validate ranges with
cv.int_range(min=X, max=Y) - Use
cv.templatablefor options that should support lambdas
setup(): Called once at startup; initialize hardware and statedump_config(): Optional; logs configuration to ESPHome logs- Loop methods:
update(): Called atget_setup_priority()interval (set viaPollingComponent)tick(): High-frequency update (if needed)
- Ensure all dynamically allocated memory is freed (though ESPHome usually handles this)
- Use ESPHome's
display::andlight::APIs for hardware access - Avoid direct register access; use ESPHome wrappers
- For timing, use
millis()ormicros()from Arduino core - Use
yield()in long-running operations to avoid watchdog triggers
- Add configuration option to
__init__.pyschema - Add member variables to
EHMTXclass inEHMTX.h - Initialize in constructor
- Handle in
update()/tick()/draw()methods as appropriate - Add public API method if needed for services/triggers
- Update documentation in README.md if user-facing
- Version defined in
EHMTX.h:static const char *const EHMTX_VERSION = "YYYY.MM.D"; - Update when making breaking changes or significant features
- Follow CalVer (Year.Month.Day) or similar incremental scheme