{"owner":"Koenkk","repo":"zigbee2mqtt","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md",".github/copilot-instructions.md"],"skills":{"AGENTS.md":"# AGENTS.md\n\n## Project Overview\n\nZigbee2MQTT is a Zigbee to MQTT bridge that allows you to use your Zigbee devices without the vendor's bridge or gateway. It bridges events and allows you to control Zigbee devices via MQTT, integrating them with any smart home infrastructure.\n\n### Architecture\n\n- **Language**: TypeScript 5.9.3 compiled to JavaScript (ES modules with NodeNext resolution)\n- **Runtime**: Node.js (versions 20, 22, or 24)\n- **Package Manager**: pnpm 10.12.1 (strictly enforced via `packageManager` field)\n- **Core Dependencies**:\n  - `zigbee-herdsman` (6.2.0 - exact version, handles Zigbee adapter communication)\n  - `zigbee-herdsman-converters` (25.42.0 - exact version, device definitions)\n  - `mqtt` (5.14.1 - MQTT client)\n  - `winston` (3.18.3 - logging)\n\n### Project Structure\n\n```\nlib/                    # TypeScript source code\n├── controller.ts       # Main controller orchestrating components\n├── mqtt.ts            # MQTT client management\n├── zigbee.ts          # Zigbee network management\n├── state.ts           # State management\n├── eventBus.ts        # Event-driven communication\n├── extension/         # Extension system (plugins)\n│   └── extension.ts   # Abstract base class\n├── model/             # Domain models (Device, Group)\n├── util/              # Utility functions\n└── types/             # TypeScript type definitions\ntest/                  # Vitest test files with mocks\ndata/                  # Runtime configuration and database\ndist/                  # Compiled JavaScript output\n```\n\n## Setup Commands\n\n### Prerequisites\n\n- Node.js version 20, 22, or 24\n- pnpm 10.12.1 (will be auto-installed via corepack if not present)\n\n### Installation\n\n```bash\n# Install dependencies (uses pnpm lockfile)\npnpm install --frozen-lockfile\n\n# For development without lockfile restrictions\npnpm install\n```\n\n### Initial Build\n\n```bash\n# Full build (TypeScript compilation + hash generation)\npnpm run build\n\n# Build type definitions only\npnpm run build:types\n```\n\n## Development Workflow\n\n### Starting Development\n\n```bash\n# Watch mode - recompile on file changes\npnpm run build:watch\n\n# In another terminal, start Zigbee2MQTT\npnpm start\n```\n\n### Code Quality Checks\n\n```bash\n# Run Biome linter and formatter (check only)\npnpm run check\n\n# Auto-fix linting and formatting issues\npnpm run check:w\n\n# The check runs with --error-on-warnings flag\n# Configuration: biome.json (4-space indent, 150 line width, no bracket spacing)\n```\n\n### Clean Build\n\n```bash\n# Remove build artifacts\npnpm run clean\n\n# Removes: coverage/, dist/, tsconfig.tsbuildinfo\n```\n\n## Testing Instructions\n\n### Running Tests\n\n```bash\n# Run all tests once\npnpm test\n\n# Run tests with coverage report\npnpm run test:coverage\n\n# Watch mode - re-run tests on changes\npnpm run test:watch\n\n# Run benchmarks\npnpm run bench\n```\n\n### Test Requirements\n\n- **Coverage**: 100% code coverage is enforced (configured in `test/vitest.config.mts`)\n- **Framework**: Vitest 3.1.1 with @vitest/coverage-v8\n- **Test Files**: Located in `test/` directory with `.test.ts` extension\n- **Mocks**: Centralized in `test/mocks/` directory\n- **Coverage Report**: Generated in `coverage/` directory (HTML report at `coverage/index.html`)\n\n### Running Specific Tests\n\n```bash\n# Run tests matching a pattern\npnpm vitest run -t \"test name pattern\" --config ./test/vitest.config.mts\n\n# Run specific test file\npnpm vitest run test/controller.test.ts --config ./test/vitest.config.mts\n\n# Focus on one test area in watch mode\npnpm vitest watch -t \"Extension\" --config ./test/vitest.config.mts\n```\n\n## Code Style Guidelines\n\n### TypeScript Conventions\n\n- **Module System**: ES modules with NodeNext resolution\n- **Target**: ESNext\n- **Strict Mode**: Enabled (`noImplicitAny`, `noImplicitThis`)\n- **Decorators**: Experimental decorators enabled (used for `@bind` from `bind-decorator`)\n\n### Import Order\n\n1. Node.js built-in modules (with `node:` prefix)\n2. Third-party libraries\n3. Type-only imports from external packages (using `type` keyword)\n4. Internal absolute imports\n5. Type-only imports from internal modules\n\nExample:\n```typescript\nimport fs from \"node:fs\";\nimport bind from \"bind-decorator\";\nimport type {IClientOptions} from \"mqtt\";\nimport {connectAsync} from \"mqtt\";\nimport type {Zigbee2MQTTAPI} from \"./types/api\";\nimport logger from \"./util/logger\";\n```\n\n### Naming Conventions\n\n- **Classes**: PascalCase (e.g., `Extension`, `Device`)\n- **Functions/Methods**: camelCase (e.g., `publishEntityState`)\n- **Constants**: SCREAMING_SNAKE_CASE (e.g., `CURRENT_VERSION`)\n- **Interfaces/Types**: PascalCase (e.g., `MqttPublishOptions`)\n- **Files**: camelCase for TypeScript (e.g., `eventBus.ts`)\n\n### Code Patterns\n\n- **Async/Await**: Always use async/await, explicitly type return as `Promise<Type>`\n- **Error Handling**: Use `throw new Error(\"message\")`, log with winston logger\n- **Event Handlers**: Use `@bind` decorator to preserve `this` context\n- **Logging**: Use `logger.info()`, `logger.warning()`, `logger.error()`, `logger.debug()`\n\n### Formatting Rules (Biome)\n\n- 4-space indentation\n- 150 character line width\n- No bracket spacing in objects\n- Run `pnpm run check:w` to auto-format\n\n## Build and Deployment\n\n### Build Process\n\n```bash\n# Production build\npnpm run build\n\n# Outputs:\n# - Compiled JavaScript in dist/\n# - Type definitions in dist/types/\n# - Includes hash generation for version tracking\n```\n\n### Pre-publish\n\n```bash\n# Automatically runs before publishing\npnpm run prepack\n\n# Performs: clean + build\n```\n\n### Environment Setup\n\n- Configuration stored in `data/configuration.yaml`\n- Database in `data/database.db`\n- Logs in `data/log/`\n- External extensions in `data/external_extensions/`\n- External converters in `data/external_converters/`\n\n## Architecture Patterns\n\n### Extension System\n\nAll features are implemented as extensions that inherit from the abstract `Extension` base class:\n\n```typescript\nabstract class Extension {\n    protected zigbee: Zigbee;\n    protected mqtt: Mqtt;\n    protected state: State;\n    protected publishEntityState: PublishEntityState;\n    protected eventBus: EventBus;\n\n    async start(): Promise<void> {}  // Initialize extension\n    async stop(): Promise<void> {}   // Cleanup extension\n}\n```\n\n**Key Points**:\n- Constructor should only assign properties (no side effects)\n- Initialization happens in `start()` method\n- Use EventBus for inter-component communication\n- Extensions are loaded and managed by the Controller\n\n### Event-Driven Communication\n\nComponents communicate via the strongly-typed EventBus:\n\n```typescript\n// Emit events\nthis.eventBus.emit('deviceMessage', {device, message});\n\n// Listen to events\nthis.eventBus.on('deviceMessage', this.onDeviceMessage, this);\n```\n\n### Dependency Injection\n\nThe Controller instantiates and injects dependencies into all extensions. Follow this pattern when creating new extensions.\n\n## Pull Request Guidelines\n\n### Target Branch\n\n- **Always create PRs against the `dev` branch**\n- The `master` branch is for production releases only\n\n### Before Submitting\n\n```bash\n# Run all checks\npnpm run check\npnpm test\n\n# Ensure 100% code coverage\npnpm run test:coverage\n\n# Build successfully\npnpm run build\n```\n\n### PR Requirements\n\n- All CI checks must pass (linting, tests, build)\n- 100% test coverage maintained\n- Code follows Biome formatting rules\n- Commit messages should be descriptive\n- Reference related issues when applicable\n\n### CI Pipeline\n\nThe GitHub Actions CI workflow (`.github/workflows/ci.yml`) runs:\n1. Biome code quality checks (`pnpm run check`)\n2. TypeScript compilation (`pnpm run build`)\n3. Full test suite with coverage (`pnpm run test:coverage`)\n4. Benchmarks (on dev branch and PRs)\n5. Docker image builds (on dev branch and tags)\n\n## Working with Device Support\n\n### Adding New Devices\n\n**Important**: Device support is NOT added to this repository. All device definitions live in `zigbee-herdsman-converters`.\n\n- Follow the guide at: https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html\n- No changes to zigbee2mqtt codebase are needed for new devices\n- Device definitions are automatically picked up from `zigbee-herdsman-converters`\n\n## Debugging and Troubleshooting\n\n### Development Setup\n\nFor the easiest development experience, set up a bare-metal installation following:\nhttps://www.zigbee2mqtt.io/guide/installation/01_linux.html\n\n### Logging\n\n- Winston logger is initialized in `lib/util/logger.ts`\n- Log levels: `error`, `warning`, `info`, `debug`\n- Logs are written to console and/or file based on configuration\n- Use structured logging with context (device names, IEEE addresses)\n\n### Common Issues\n\n1. **Import errors after file moves**: Run `pnpm run check` to verify TypeScript and ESLint\n2. **Test failures**: Check if mocks in `test/mocks/` need updates\n3. **Build errors**: Ensure Node.js version is 20, 22, or 24\n4. **Coverage issues**: View HTML report at `coverage/index.html` to identify uncovered code\n\n### Performance Considerations\n\n- Use `fs.rmSync(path, {recursive: true, force: true})` for synchronous file operations\n- Leverage async/await to avoid blocking\n- Cache computed values in getters when appropriate\n- EventBus provides loose coupling between components\n\n## Critical Version Requirements\n\n### Exact Versions\n\nThese dependencies use **exact versions** (no semver ranges) - do not upgrade without thorough testing:\n\n- `zigbee-herdsman@6.2.0` - Critical for Zigbee protocol compatibility\n- `zigbee-herdsman-converters@25.42.0` - Device definitions must match herdsman version\n\n### Node.js Compatibility\n\nOnly these Node.js versions are supported:\n- Node.js 20.x\n- Node.js 22.x\n- Node.js 24.x\n\nUsing other versions may cause runtime errors or incompatibilities.\n\n## Additional Notes\n\n### Package Manager\n\nThis project **requires pnpm 10.12.1**. The `packageManager` field in package.json enforces this via Corepack.\n\nDo not use npm or yarn - they will not respect the pnpm-specific configuration.\n\n### TypeScript Compilation\n\n- Source files in `lib/` are compiled to `dist/`\n- Type definitions exported from `dist/types/api.d.ts`\n- Source maps are inlined for debugging\n- Uses composite project references for faster incremental builds\n\n### External Extensions\n\nTo load external extensions:\n1. Place JavaScript files in `data/external_extensions/`\n2. They will be automatically loaded on startup\n3. No configuration changes needed\n\n### Code Quality Tools\n\n- **Linting/Formatting**: Biome 2.2.5 (replaces ESLint + Prettier)\n- **Type Checking**: TypeScript 5.9.3\n- **Testing**: Vitest 3.1.1\n- **Coverage**: @vitest/coverage-v8\n\n### Documentation\n\n- Main documentation: https://www.zigbee2mqtt.io/\n- Contributing guide: `CONTRIBUTING.md`\n- Coding standards: `.github/copilot-instructions.md`\n- Issue tracker: https://github.com/Koenkk/zigbee2mqtt/issues\n",".github/copilot-instructions.md":"# GitHub Copilot Instructions\n\n## Priority Guidelines\n\nWhen generating code for this repository:\n\n1. **Version Compatibility**: Always detect and respect the exact versions of languages, frameworks, and libraries used in this project\n2. **Context Files**: Prioritize patterns and standards defined in the .github/copilot directory\n3. **Codebase Patterns**: When context files don't provide specific guidance, scan the codebase for established patterns\n4. **Architectural Consistency**: Maintain our layered architectural style with clear separation between controller, extensions, models, and utilities\n5. **Code Quality**: Prioritize maintainability, performance, security, and testability in all generated code\n\n## Technology Stack\n\n### Core Technologies\n- **Language**: TypeScript 5.9.3 with target `esnext` and module `NodeNext`\n- **Runtime**: Node.js ^20 || ^22 || ^24\n- **Package Manager**: pnpm 10.12.1\n- **Testing**: Vitest 3.1.1 with @vitest/coverage-v8\n- **Linting/Formatting**: Biome 2.2.5 (configured with 4-space indents, 150 line width, no bracket spacing)\n\n### Key Dependencies\n- **zigbee-herdsman**: 6.2.0 (exact version - critical for Zigbee protocol compatibility)\n- **zigbee-herdsman-converters**: 25.42.0 (exact version - device definitions)\n- **MQTT**: mqtt 5.14.1\n- **Logging**: winston 3.18.3\n- **YAML**: js-yaml 4.1.0\n- **Decorators**: bind-decorator 1.0.11\n- **WebSocket**: ws 8.18.1\n\n### TypeScript Configuration\n- **Strict Mode**: Enabled with `noImplicitAny` and `noImplicitThis`\n- **Module System**: NodeNext with ESM interop\n- **Decorators**: Experimental decorators enabled\n- **Composite**: True (for project references)\n- **Source Maps**: Inline source maps enabled\n- **Output**: Compiled to `dist/` directory\n\n## Project Architecture\n\n### Directory Structure\n```\nlib/                    # Source TypeScript files\n├── controller.ts       # Main controller orchestrating all components\n├── mqtt.ts            # MQTT client management\n├── zigbee.ts          # Zigbee network management\n├── state.ts           # State management\n├── eventBus.ts        # Event-driven communication\n├── extension/         # Extension system (plugins)\n│   ├── extension.ts   # Abstract base class\n│   ├── availability.ts\n│   ├── bind.ts\n│   ├── bridge.ts\n│   ├── configure.ts\n│   └── ...\n├── model/             # Domain models\n│   ├── device.ts\n│   └── group.ts\n├── util/              # Utility functions\n│   ├── logger.ts\n│   ├── settings.ts\n│   ├── utils.ts\n│   └── ...\n└── types/             # TypeScript type definitions\n    └── api.ts\ntest/                  # Vitest test files\ndata/                  # Runtime configuration and data\n```\n\n### Architectural Patterns\n\n#### Extension Pattern\nAll extensions inherit from the abstract `Extension` base class:\n```typescript\nabstract class Extension {\n    protected zigbee: Zigbee;\n    protected mqtt: Mqtt;\n    protected state: State;\n    protected publishEntityState: PublishEntityState;\n    protected eventBus: EventBus;\n\n    async start(): Promise<void> {}\n    async stop(): Promise<void> {}\n}\n```\n\n#### Event-Driven Architecture\nUse the `EventBus` for component communication. Events are strongly typed:\n```typescript\ninterface EventBusMap {\n    deviceMessage: [data: eventdata.DeviceMessage];\n    mqttMessage: [data: eventdata.MQTTMessage];\n    publishEntityState: [data: eventdata.PublishEntityState];\n    // ... other events\n}\n```\n\n#### Dependency Injection\nThe `Controller` class instantiates and injects dependencies into extensions. Follow this pattern when creating new extensions.\n\n## Code Style and Conventions\n\n### Naming Conventions\n- **Classes**: PascalCase (e.g., `Extension`, `Device`, `EventBus`)\n- **Interfaces/Types**: PascalCase (e.g., `MqttPublishOptions`, `DeviceOptions`)\n- **Functions/Methods**: camelCase (e.g., `publishEntityState`, `enableDisableExtension`)\n- **Constants**: SCREAMING_SNAKE_CASE for top-level constants (e.g., `CURRENT_VERSION`, `LOG_LEVELS`)\n- **Private members**: Prefix with underscore for private class fields only when needed to distinguish from public properties (e.g., `_definitionModelID`)\n- **Files**: camelCase for TypeScript files (e.g., `eventBus.ts`, `externalJS.ts`)\n\n### Import Organization\nFollow this import order (separated by blank lines):\n1. Node.js built-in modules (use `node:` prefix: `import fs from \"node:fs\"`)\n2. Third-party libraries (e.g., `bind-decorator`, `mqtt`)\n3. Type-only imports from external packages (using `type` keyword)\n4. Internal absolute imports from project root\n5. Type-only imports from internal modules\n\nExample:\n```typescript\nimport fs from \"node:fs\";\nimport bind from \"bind-decorator\";\nimport type {IClientOptions} from \"mqtt\";\nimport {connectAsync} from \"mqtt\";\nimport type {Zigbee2MQTTAPI} from \"./types/api\";\nimport logger from \"./util/logger\";\nimport * as settings from \"./util/settings\";\n```\n\n### Type Annotations\n- Use `type` imports for TypeScript types: `import type * as zhc from \"zigbee-herdsman-converters\"`\n- Explicitly type function parameters and return types\n- Use `KeyValue` type for generic object payloads: `type KeyValue = Record<string, any>`\n- Prefer interfaces for object shapes, type aliases for unions/intersections\n- Use namespace exports for related types: `export type * as ZSpec from \"zigbee-herdsman/dist/zspec\"`\n\n### Async/Await Patterns\n- Always use `async/await` for asynchronous operations\n- Return types should be explicitly `Promise<Type>`\n- Methods that don't return values should be `Promise<void>`\n- Use `Awaited<ReturnType<typeof fn>>` for inferring async function return types\n\n### Decorators\nUse `@bind` decorator from `bind-decorator` for methods that need `this` binding:\n```typescript\n@bind async onMQTTMessage(data: eventdata.MQTTMessage): Promise<void> {\n    // Implementation\n}\n```\n\n### Error Handling\n- Use `throw new Error(\"message\")` for explicit errors\n- Include descriptive error messages\n- Log errors using the logger: `logger.error(\"message\")`\n- For Zigbee-herdsman errors, log the stack trace: `logger.error((error as Error).stack!)`\n- Catch and handle errors at appropriate boundaries (controller level)\n\n### Logging\nUse the centralized logger (winston-based):\n```typescript\nimport logger from \"./util/logger\";\n\nlogger.info(\"message\");\nlogger.warning(\"message\");\nlogger.error(\"message\");\nlogger.debug(\"message\");\n```\n\n- Use namespaced loggers for specific modules (created internally by logger)\n- Log levels: `error`, `warning`, `info`, `debug` (from most to least critical)\n- Include relevant context in log messages (device names, IEEE addresses, etc.)\n\n## Code Quality Standards\n\n### Maintainability\n- Write self-documenting code with clear, descriptive names\n- Keep methods focused on single responsibilities\n- Abstract classes should define clear contracts with protected members for subclasses\n- Use constructor dependency injection for required dependencies\n- Limit function complexity - methods should be concise and focused\n- Use TypeScript's strict mode features (`noImplicitAny`, `noImplicitThis`)\n\n### Performance\n- Use `fs.rmSync(path, {recursive: true, force: true})` for synchronous file deletion when appropriate\n- Leverage async/await for I/O operations to avoid blocking\n- Use JSON stable stringify util for consistent object serialization\n- Cache computed values when appropriate (see device model patterns)\n- Use getter methods for computed properties that should be cached\n\n### Security\n- Validate input using Ajv JSON schema validation (see `settings.ts` pattern)\n- Sanitize file paths using `path.join` from Node.js\n- Use YAML safe loading: `yaml.safeLoad()`\n- Handle sensitive data (credentials, tokens) through settings with proper defaults\n- Never log sensitive information (passwords, tokens)\n\n### Testability\n- Write tests using Vitest with describe/it/expect patterns\n- Mock external dependencies using Vitest's `vi.mock()`\n- Use `beforeEach`, `afterEach`, `beforeAll`, `afterAll` for test setup/teardown\n- Place test files in `test/` directory with `.test.ts` extension\n- Mock constructors and modules in the pattern shown in `test/controller.test.ts`\n- Use `flushPromises()` utility for async test synchronization\n- Target 100% code coverage (configured in vitest.config.mts)\n\n## Testing Standards\n\n### Unit Testing Structure\n```typescript\nimport {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from \"vitest\";\n\ndescribe(\"ComponentName\", () => {\n    beforeEach(() => {\n        // Setup\n    });\n\n    it(\"Should do something specific\", async () => {\n        // Arrange\n        const input = {};\n\n        // Act\n        const result = await someFunction(input);\n\n        // Assert\n        expect(result).toBe(expected);\n    });\n});\n```\n\n### Mocking Patterns\n- Create mock modules in `test/mocks/` directory\n- Use `vi.fn()` for function mocks\n- Use `vi.mock()` for module mocks\n- Clear mocks in `afterEach` or between tests\n- Mock external libraries like `mqtt`, `zigbee-herdsman` consistently\n\n### Test Coverage\n- All code in `lib/**` should be covered\n- Use coverage reports: `pnpm test:coverage`\n- Thresholds set to 100% (can be adjusted per project needs)\n- Tests should cover both success and failure paths\n\n## Documentation Standards\n\n### JSDoc Comments\nUse JSDoc-style comments for classes and public methods:\n```typescript\n/**\n * Besides initializing variables, the constructor should do nothing!\n *\n * @param {Zigbee} zigbee Zigbee controller\n * @param {Mqtt} mqtt MQTT controller\n * @param {State} state State controller\n * @param {Function} publishEntityState Method to publish device state to MQTT.\n * @param {EventBus} eventBus The event bus\n */\nconstructor(zigbee: Zigbee, mqtt: Mqtt, state: State, ...) {\n```\n\n### Comment Style\n- Use single-line comments (`//`) for implementation notes\n- Use JSDoc (`/** */`) for public APIs and class/method documentation\n- Include context for non-obvious logic\n- Document parameters with their types and purposes\n- Use `@param` tags with TypeScript types in braces\n- Use biome-ignore comments when necessary: `// biome-ignore lint/rule: reason`\n\n### Code Documentation\n- Document complex algorithms or business logic\n- Explain \"why\" not just \"what\" when logic is non-trivial\n- Include links to relevant issues or documentation when applicable\n- Document deprecations and breaking changes\n\n## TypeScript-Specific Guidelines\n\n### Module System\n- Use ES modules with `import`/`export` syntax\n- Default exports for main classes: `export default class Device {}`\n- Named exports for utilities and types: `export const LOG_LEVELS = ...`\n- Namespace exports for related types: `export type * as ZSpec from ...`\n- Use `.js` extension in imports for local modules when using dynamic imports: `await import(\"./extension/frontend.js\")`\n\n### Type Safety\n- Enable all strict type checking options\n- Use type guards and assertions when necessary: `asserts expose is zhc.Numeric`\n- Prefer `unknown` over `any` when type is truly unknown\n- Use `// biome-ignore lint/suspicious/noExplicitAny: API` when `any` is necessary\n- Define proper interfaces for external module types (e.g., `unix-dgram.d.ts`)\n\n### Generic Types\n- Use generics for reusable, type-safe abstractions\n- Example: `abstract class ExternalJSExtension<M> extends Extension`\n- Constrain generics when appropriate\n- Document generic type parameters\n\n### Utility Types\n- Use built-in utility types: `Partial`, `Required`, `Pick`, `Omit`, `Record`\n- Use `Awaited<ReturnType<typeof fn>>` for async function return types\n- Define custom utility types when patterns emerge\n- Use `type` for aliases, `interface` for object shapes\n\n## Version Control and Releases\n\n### Versioning Strategy\n- Follow Semantic Versioning (MAJOR.MINOR.PATCH)\n- Current version managed in `package.json`\n- Use `-dev` suffix for development versions (e.g., `2.6.2-dev`)\n- Configuration version tracked separately: `CURRENT_VERSION = 4`\n\n### Changelog\n- Maintain CHANGELOG.md with all changes\n- Group changes by type: Bug Fixes, Features, Breaking Changes\n- Include issue/PR references: `([#28583](url))`\n- Include commit references: `([09f33b3](url))`\n- Use conventional commits format\n\n### Git Workflow\n- Development on `dev` branch\n- Production releases from `master` branch\n- Use meaningful commit messages\n- Reference issues in commits\n\n## Project-Specific Patterns\n\n### Settings Management\n- All configuration loaded through `util/settings.ts`\n- Validate settings using Ajv with JSON schema\n- Schema defined in `settings.schema.json`\n- Support runtime setting changes with restart detection\n- Use `settings.get()` to access current configuration\n- Use `settings.getDevice(ieeeAddr)` for device-specific config\n\n### Device and Group Models\n- Devices and groups are domain models wrapping `zigbee-herdsman` entities\n- Access underlying entity via `.zh` property\n- Expose computed properties as getters\n- Include definition from `zigbee-herdsman-converters`\n- Handle coordinator devices specially (type checking)\n\n### MQTT Integration\n- MQTT client wrapped in `Mqtt` class\n- Publish options: `retain`, `qos` properties\n- Topics follow pattern: `{base_topic}/{device}/{attribute}`\n- Event-based message handling via EventBus\n- Clean disconnect handling with retry logic\n\n### Extension System\n- Extensions are loosely coupled plugins\n- Lifecycle: constructor → start() → stop()\n- Constructor should only assign properties (no side effects)\n- Use EventBus for inter-extension communication\n- Extensions can be enabled/disabled at runtime\n- External extensions loaded from `data/external_extensions/`\n\n### State Management\n- State persisted to `state.json`\n- Cached in memory for performance\n- Device states include all exposed attributes\n- State changes trigger events via EventBus\n\n## Best Practices Specific to This Project\n\n1. **Never use language features beyond TypeScript 5.9.3 or ES2024**\n2. **Always respect exact versions of zigbee-herdsman and zigbee-herdsman-converters** - these are critical for device compatibility\n3. **Use the EventBus for all component communication** - avoid direct coupling\n4. **Follow the Extension pattern for new features** - don't add logic directly to Controller\n5. **Log appropriately** - info for user-relevant events, debug for developer info, error for failures\n6. **Test with real Zigbee scenarios** - many edge cases exist with different device types\n7. **Handle coordinator specially** - coordinator is a device but with unique behavior\n8. **Validate all external input** - MQTT messages, configuration files, device data\n9. **Use the bind decorator** for event handlers to preserve `this` context\n10. **Match the exact code formatting** - Biome enforces 4 spaces, 150 line width, no bracket spacing\n\n## Common Patterns to Follow\n\n### Creating a New Extension\n1. Extend `Extension` abstract class\n2. Accept all dependencies in constructor\n3. Implement `start()` method for initialization\n4. Subscribe to EventBus events in `start()`\n5. Implement `stop()` method for cleanup\n6. Export as default: `export default class MyExtension extends Extension`\n\n### Accessing Device Information\n```typescript\nconst device: Device; // Our wrapper\ndevice.ieeeAddr;      // IEEE address\ndevice.name;          // Friendly name\ndevice.zh;            // Underlying zigbee-herdsman device\ndevice.definition;    // zigbee-herdsman-converters definition\ndevice.options;       // User configuration\n```\n\n### Publishing MQTT Messages\n```typescript\nawait this.mqtt.publish(topic, message, {retain: true, qos: 0});\n```\n\n### Emitting Events\n```typescript\nthis.eventBus.emit('deviceMessage', {device, message});\n```\n\n### Listening to Events\n```typescript\nthis.eventBus.on('deviceMessage', this.onDeviceMessage, this);\n```\n\n## Integration Points\n\n### Zigbee-Herdsman Integration\n- Start controller: `await this.zigbee.start()`\n- Access coordinator: `this.zigbee.coordinator()`\n- Device operations through `zigbee-herdsman` API\n- Event handling through EventBus wrappers\n\n### MQTT Integration\n- Connect: `await this.mqtt.connect()`\n- Subscribe: `await this.mqtt.subscribe(topic)`\n- Publish: `await this.mqtt.publish(topic, message, options)`\n- Handle messages via EventBus `mqttMessage` event\n\n### Frontend Integration\n- Optional extension loaded dynamically\n- Serves static files with compression\n- WebSocket support for real-time updates\n- Configurable port and base URL\n\n### Home Assistant Integration\n- Optional extension for discovery\n- Publishes discovery messages to MQTT\n- Supports entities, sensors, and devices\n- Configurable discovery topic\n\n## Critical Compatibility Notes\n\n1. **Node.js**: Only versions 20, 22, and 24 are supported\n2. **TypeScript**: Features must be compatible with 5.9.3\n3. **Zigbee Libraries**: Exact versions are critical - do not suggest upgrades without testing\n4. **MQTT Protocol**: Uses MQTT 3.1.1 and 5.0 features\n5. **ES Modules**: Project uses ESM with NodeNext resolution\n6. **Experimental Decorators**: Required for `@bind` decorator support\n\n## When in Doubt\n\n1. **Search for similar patterns** in the existing codebase\n2. **Check existing extensions** for implementation examples\n3. **Follow the controller and extension architecture** - don't bypass it\n4. **Consult the test files** for usage examples\n5. **Match the exact style** - run `pnpm check` to verify\n6. **Prioritize consistency** over external best practices\n7. **Test thoroughly** - this project controls real hardware\n\n## Resources\n\n- Repository: https://github.com/Koenkk/zigbee2mqtt\n- Documentation: https://koenkk.github.io/zigbee2mqtt\n- License: GPL-3.0\n- Issue Tracker: https://github.com/Koenkk/zigbee2mqtt/issues\n"},"files":{"AGENTS.md":"# AGENTS.md\n\n## Project Overview\n\nZigbee2MQTT is a Zigbee to MQTT bridge that allows you to use your Zigbee devices without the vendor's bridge or gateway. It bridges events and allows you to control Zigbee devices via MQTT, integrating them with any smart home infrastructure.\n\n### Architecture\n\n- **Language**: TypeScript 5.9.3 compiled to JavaScript (ES modules with NodeNext resolution)\n- **Runtime**: Node.js (versions 20, 22, or 24)\n- **Package Manager**: pnpm 10.12.1 (strictly enforced via `packageManager` field)\n- **Core Dependencies**:\n  - `zigbee-herdsman` (6.2.0 - exact version, handles Zigbee adapter communication)\n  - `zigbee-herdsman-converters` (25.42.0 - exact version, device definitions)\n  - `mqtt` (5.14.1 - MQTT client)\n  - `winston` (3.18.3 - logging)\n\n### Project Structure\n\n```\nlib/                    # TypeScript source code\n├── controller.ts       # Main controller orchestrating components\n├── mqtt.ts            # MQTT client management\n├── zigbee.ts          # Zigbee network management\n├── state.ts           # State management\n├── eventBus.ts        # Event-driven communication\n├── extension/         # Extension system (plugins)\n│   └── extension.ts   # Abstract base class\n├── model/             # Domain models (Device, Group)\n├── util/              # Utility functions\n└── types/             # TypeScript type definitions\ntest/                  # Vitest test files with mocks\ndata/                  # Runtime configuration and database\ndist/                  # Compiled JavaScript output\n```\n\n## Setup Commands\n\n### Prerequisites\n\n- Node.js version 20, 22, or 24\n- pnpm 10.12.1 (will be auto-installed via corepack if not present)\n\n### Installation\n\n```bash\n# Install dependencies (uses pnpm lockfile)\npnpm install --frozen-lockfile\n\n# For development without lockfile restrictions\npnpm install\n```\n\n### Initial Build\n\n```bash\n# Full build (TypeScript compilation + hash generation)\npnpm run build\n\n# Build type definitions only\npnpm run build:types\n```\n\n## Development Workflow\n\n### Starting Development\n\n```bash\n# Watch mode - recompile on file changes\npnpm run build:watch\n\n# In another terminal, start Zigbee2MQTT\npnpm start\n```\n\n### Code Quality Checks\n\n```bash\n# Run Biome linter and formatter (check only)\npnpm run check\n\n# Auto-fix linting and formatting issues\npnpm run check:w\n\n# The check runs with --error-on-warnings flag\n# Configuration: biome.json (4-space indent, 150 line width, no bracket spacing)\n```\n\n### Clean Build\n\n```bash\n# Remove build artifacts\npnpm run clean\n\n# Removes: coverage/, dist/, tsconfig.tsbuildinfo\n```\n\n## Testing Instructions\n\n### Running Tests\n\n```bash\n# Run all tests once\npnpm test\n\n# Run tests with coverage report\npnpm run test:coverage\n\n# Watch mode - re-run tests on changes\npnpm run test:watch\n\n# Run benchmarks\npnpm run bench\n```\n\n### Test Requirements\n\n- **Coverage**: 100% code coverage is enforced (configured in `test/vitest.config.mts`)\n- **Framework**: Vitest 3.1.1 with @vitest/coverage-v8\n- **Test Files**: Located in `test/` directory with `.test.ts` extension\n- **Mocks**: Centralized in `test/mocks/` directory\n- **Coverage Report**: Generated in `coverage/` directory (HTML report at `coverage/index.html`)\n\n### Running Specific Tests\n\n```bash\n# Run tests matching a pattern\npnpm vitest run -t \"test name pattern\" --config ./test/vitest.config.mts\n\n# Run specific test file\npnpm vitest run test/controller.test.ts --config ./test/vitest.config.mts\n\n# Focus on one test area in watch mode\npnpm vitest watch -t \"Extension\" --config ./test/vitest.config.mts\n```\n\n## Code Style Guidelines\n\n### TypeScript Conventions\n\n- **Module System**: ES modules with NodeNext resolution\n- **Target**: ESNext\n- **Strict Mode**: Enabled (`noImplicitAny`, `noImplicitThis`)\n- **Decorators**: Experimental decorators enabled (used for `@bind` from `bind-decorator`)\n\n### Import Order\n\n1. Node.js built-in modules (with `node:` prefix)\n2. Third-party libraries\n3. Type-only imports from external packages (using `type` keyword)\n4. Internal absolute imports\n5. Type-only imports from internal modules\n\nExample:\n```typescript\nimport fs from \"node:fs\";\nimport bind from \"bind-decorator\";\nimport type {IClientOptions} from \"mqtt\";\nimport {connectAsync} from \"mqtt\";\nimport type {Zigbee2MQTTAPI} from \"./types/api\";\nimport logger from \"./util/logger\";\n```\n\n### Naming Conventions\n\n- **Classes**: PascalCase (e.g., `Extension`, `Device`)\n- **Functions/Methods**: camelCase (e.g., `publishEntityState`)\n- **Constants**: SCREAMING_SNAKE_CASE (e.g., `CURRENT_VERSION`)\n- **Interfaces/Types**: PascalCase (e.g., `MqttPublishOptions`)\n- **Files**: camelCase for TypeScript (e.g., `eventBus.ts`)\n\n### Code Patterns\n\n- **Async/Await**: Always use async/await, explicitly type return as `Promise<Type>`\n- **Error Handling**: Use `throw new Error(\"message\")`, log with winston logger\n- **Event Handlers**: Use `@bind` decorator to preserve `this` context\n- **Logging**: Use `logger.info()`, `logger.warning()`, `logger.error()`, `logger.debug()`\n\n### Formatting Rules (Biome)\n\n- 4-space indentation\n- 150 character line width\n- No bracket spacing in objects\n- Run `pnpm run check:w` to auto-format\n\n## Build and Deployment\n\n### Build Process\n\n```bash\n# Production build\npnpm run build\n\n# Outputs:\n# - Compiled JavaScript in dist/\n# - Type definitions in dist/types/\n# - Includes hash generation for version tracking\n```\n\n### Pre-publish\n\n```bash\n# Automatically runs before publishing\npnpm run prepack\n\n# Performs: clean + build\n```\n\n### Environment Setup\n\n- Configuration stored in `data/configuration.yaml`\n- Database in `data/database.db`\n- Logs in `data/log/`\n- External extensions in `data/external_extensions/`\n- External converters in `data/external_converters/`\n\n## Architecture Patterns\n\n### Extension System\n\nAll features are implemented as extensions that inherit from the abstract `Extension` base class:\n\n```typescript\nabstract class Extension {\n    protected zigbee: Zigbee;\n    protected mqtt: Mqtt;\n    protected state: State;\n    protected publishEntityState: PublishEntityState;\n    protected eventBus: EventBus;\n\n    async start(): Promise<void> {}  // Initialize extension\n    async stop(): Promise<void> {}   // Cleanup extension\n}\n```\n\n**Key Points**:\n- Constructor should only assign properties (no side effects)\n- Initialization happens in `start()` method\n- Use EventBus for inter-component communication\n- Extensions are loaded and managed by the Controller\n\n### Event-Driven Communication\n\nComponents communicate via the strongly-typed EventBus:\n\n```typescript\n// Emit events\nthis.eventBus.emit('deviceMessage', {device, message});\n\n// Listen to events\nthis.eventBus.on('deviceMessage', this.onDeviceMessage, this);\n```\n\n### Dependency Injection\n\nThe Controller instantiates and injects dependencies into all extensions. Follow this pattern when creating new extensions.\n\n## Pull Request Guidelines\n\n### Target Branch\n\n- **Always create PRs against the `dev` branch**\n- The `master` branch is for production releases only\n\n### Before Submitting\n\n```bash\n# Run all checks\npnpm run check\npnpm test\n\n# Ensure 100% code coverage\npnpm run test:coverage\n\n# Build successfully\npnpm run build\n```\n\n### PR Requirements\n\n- All CI checks must pass (linting, tests, build)\n- 100% test coverage maintained\n- Code follows Biome formatting rules\n- Commit messages should be descriptive\n- Reference related issues when applicable\n\n### CI Pipeline\n\nThe GitHub Actions CI workflow (`.github/workflows/ci.yml`) runs:\n1. Biome code quality checks (`pnpm run check`)\n2. TypeScript compilation (`pnpm run build`)\n3. Full test suite with coverage (`pnpm run test:coverage`)\n4. Benchmarks (on dev branch and PRs)\n5. Docker image builds (on dev branch and tags)\n\n## Working with Device Support\n\n### Adding New Devices\n\n**Important**: Device support is NOT added to this repository. All device definitions live in `zigbee-herdsman-converters`.\n\n- Follow the guide at: https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html\n- No changes to zigbee2mqtt codebase are needed for new devices\n- Device definitions are automatically picked up from `zigbee-herdsman-converters`\n\n## Debugging and Troubleshooting\n\n### Development Setup\n\nFor the easiest development experience, set up a bare-metal installation following:\nhttps://www.zigbee2mqtt.io/guide/installation/01_linux.html\n\n### Logging\n\n- Winston logger is initialized in `lib/util/logger.ts`\n- Log levels: `error`, `warning`, `info`, `debug`\n- Logs are written to console and/or file based on configuration\n- Use structured logging with context (device names, IEEE addresses)\n\n### Common Issues\n\n1. **Import errors after file moves**: Run `pnpm run check` to verify TypeScript and ESLint\n2. **Test failures**: Check if mocks in `test/mocks/` need updates\n3. **Build errors**: Ensure Node.js version is 20, 22, or 24\n4. **Coverage issues**: View HTML report at `coverage/index.html` to identify uncovered code\n\n### Performance Considerations\n\n- Use `fs.rmSync(path, {recursive: true, force: true})` for synchronous file operations\n- Leverage async/await to avoid blocking\n- Cache computed values in getters when appropriate\n- EventBus provides loose coupling between components\n\n## Critical Version Requirements\n\n### Exact Versions\n\nThese dependencies use **exact versions** (no semver ranges) - do not upgrade without thorough testing:\n\n- `zigbee-herdsman@6.2.0` - Critical for Zigbee protocol compatibility\n- `zigbee-herdsman-converters@25.42.0` - Device definitions must match herdsman version\n\n### Node.js Compatibility\n\nOnly these Node.js versions are supported:\n- Node.js 20.x\n- Node.js 22.x\n- Node.js 24.x\n\nUsing other versions may cause runtime errors or incompatibilities.\n\n## Additional Notes\n\n### Package Manager\n\nThis project **requires pnpm 10.12.1**. The `packageManager` field in package.json enforces this via Corepack.\n\nDo not use npm or yarn - they will not respect the pnpm-specific configuration.\n\n### TypeScript Compilation\n\n- Source files in `lib/` are compiled to `dist/`\n- Type definitions exported from `dist/types/api.d.ts`\n- Source maps are inlined for debugging\n- Uses composite project references for faster incremental builds\n\n### External Extensions\n\nTo load external extensions:\n1. Place JavaScript files in `data/external_extensions/`\n2. They will be automatically loaded on startup\n3. No configuration changes needed\n\n### Code Quality Tools\n\n- **Linting/Formatting**: Biome 2.2.5 (replaces ESLint + Prettier)\n- **Type Checking**: TypeScript 5.9.3\n- **Testing**: Vitest 3.1.1\n- **Coverage**: @vitest/coverage-v8\n\n### Documentation\n\n- Main documentation: https://www.zigbee2mqtt.io/\n- Contributing guide: `CONTRIBUTING.md`\n- Coding standards: `.github/copilot-instructions.md`\n- Issue tracker: https://github.com/Koenkk/zigbee2mqtt/issues\n",".github/copilot-instructions.md":"# GitHub Copilot Instructions\n\n## Priority Guidelines\n\nWhen generating code for this repository:\n\n1. **Version Compatibility**: Always detect and respect the exact versions of languages, frameworks, and libraries used in this project\n2. **Context Files**: Prioritize patterns and standards defined in the .github/copilot directory\n3. **Codebase Patterns**: When context files don't provide specific guidance, scan the codebase for established patterns\n4. **Architectural Consistency**: Maintain our layered architectural style with clear separation between controller, extensions, models, and utilities\n5. **Code Quality**: Prioritize maintainability, performance, security, and testability in all generated code\n\n## Technology Stack\n\n### Core Technologies\n- **Language**: TypeScript 5.9.3 with target `esnext` and module `NodeNext`\n- **Runtime**: Node.js ^20 || ^22 || ^24\n- **Package Manager**: pnpm 10.12.1\n- **Testing**: Vitest 3.1.1 with @vitest/coverage-v8\n- **Linting/Formatting**: Biome 2.2.5 (configured with 4-space indents, 150 line width, no bracket spacing)\n\n### Key Dependencies\n- **zigbee-herdsman**: 6.2.0 (exact version - critical for Zigbee protocol compatibility)\n- **zigbee-herdsman-converters**: 25.42.0 (exact version - device definitions)\n- **MQTT**: mqtt 5.14.1\n- **Logging**: winston 3.18.3\n- **YAML**: js-yaml 4.1.0\n- **Decorators**: bind-decorator 1.0.11\n- **WebSocket**: ws 8.18.1\n\n### TypeScript Configuration\n- **Strict Mode**: Enabled with `noImplicitAny` and `noImplicitThis`\n- **Module System**: NodeNext with ESM interop\n- **Decorators**: Experimental decorators enabled\n- **Composite**: True (for project references)\n- **Source Maps**: Inline source maps enabled\n- **Output**: Compiled to `dist/` directory\n\n## Project Architecture\n\n### Directory Structure\n```\nlib/                    # Source TypeScript files\n├── controller.ts       # Main controller orchestrating all components\n├── mqtt.ts            # MQTT client management\n├── zigbee.ts          # Zigbee network management\n├── state.ts           # State management\n├── eventBus.ts        # Event-driven communication\n├── extension/         # Extension system (plugins)\n│   ├── extension.ts   # Abstract base class\n│   ├── availability.ts\n│   ├── bind.ts\n│   ├── bridge.ts\n│   ├── configure.ts\n│   └── ...\n├── model/             # Domain models\n│   ├── device.ts\n│   └── group.ts\n├── util/              # Utility functions\n│   ├── logger.ts\n│   ├── settings.ts\n│   ├── utils.ts\n│   └── ...\n└── types/             # TypeScript type definitions\n    └── api.ts\ntest/                  # Vitest test files\ndata/                  # Runtime configuration and data\n```\n\n### Architectural Patterns\n\n#### Extension Pattern\nAll extensions inherit from the abstract `Extension` base class:\n```typescript\nabstract class Extension {\n    protected zigbee: Zigbee;\n    protected mqtt: Mqtt;\n    protected state: State;\n    protected publishEntityState: PublishEntityState;\n    protected eventBus: EventBus;\n\n    async start(): Promise<void> {}\n    async stop(): Promise<void> {}\n}\n```\n\n#### Event-Driven Architecture\nUse the `EventBus` for component communication. Events are strongly typed:\n```typescript\ninterface EventBusMap {\n    deviceMessage: [data: eventdata.DeviceMessage];\n    mqttMessage: [data: eventdata.MQTTMessage];\n    publishEntityState: [data: eventdata.PublishEntityState];\n    // ... other events\n}\n```\n\n#### Dependency Injection\nThe `Controller` class instantiates and injects dependencies into extensions. Follow this pattern when creating new extensions.\n\n## Code Style and Conventions\n\n### Naming Conventions\n- **Classes**: PascalCase (e.g., `Extension`, `Device`, `EventBus`)\n- **Interfaces/Types**: PascalCase (e.g., `MqttPublishOptions`, `DeviceOptions`)\n- **Functions/Methods**: camelCase (e.g., `publishEntityState`, `enableDisableExtension`)\n- **Constants**: SCREAMING_SNAKE_CASE for top-level constants (e.g., `CURRENT_VERSION`, `LOG_LEVELS`)\n- **Private members**: Prefix with underscore for private class fields only when needed to distinguish from public properties (e.g., `_definitionModelID`)\n- **Files**: camelCase for TypeScript files (e.g., `eventBus.ts`, `externalJS.ts`)\n\n### Import Organization\nFollow this import order (separated by blank lines):\n1. Node.js built-in modules (use `node:` prefix: `import fs from \"node:fs\"`)\n2. Third-party libraries (e.g., `bind-decorator`, `mqtt`)\n3. Type-only imports from external packages (using `type` keyword)\n4. Internal absolute imports from project root\n5. Type-only imports from internal modules\n\nExample:\n```typescript\nimport fs from \"node:fs\";\nimport bind from \"bind-decorator\";\nimport type {IClientOptions} from \"mqtt\";\nimport {connectAsync} from \"mqtt\";\nimport type {Zigbee2MQTTAPI} from \"./types/api\";\nimport logger from \"./util/logger\";\nimport * as settings from \"./util/settings\";\n```\n\n### Type Annotations\n- Use `type` imports for TypeScript types: `import type * as zhc from \"zigbee-herdsman-converters\"`\n- Explicitly type function parameters and return types\n- Use `KeyValue` type for generic object payloads: `type KeyValue = Record<string, any>`\n- Prefer interfaces for object shapes, type aliases for unions/intersections\n- Use namespace exports for related types: `export type * as ZSpec from \"zigbee-herdsman/dist/zspec\"`\n\n### Async/Await Patterns\n- Always use `async/await` for asynchronous operations\n- Return types should be explicitly `Promise<Type>`\n- Methods that don't return values should be `Promise<void>`\n- Use `Awaited<ReturnType<typeof fn>>` for inferring async function return types\n\n### Decorators\nUse `@bind` decorator from `bind-decorator` for methods that need `this` binding:\n```typescript\n@bind async onMQTTMessage(data: eventdata.MQTTMessage): Promise<void> {\n    // Implementation\n}\n```\n\n### Error Handling\n- Use `throw new Error(\"message\")` for explicit errors\n- Include descriptive error messages\n- Log errors using the logger: `logger.error(\"message\")`\n- For Zigbee-herdsman errors, log the stack trace: `logger.error((error as Error).stack!)`\n- Catch and handle errors at appropriate boundaries (controller level)\n\n### Logging\nUse the centralized logger (winston-based):\n```typescript\nimport logger from \"./util/logger\";\n\nlogger.info(\"message\");\nlogger.warning(\"message\");\nlogger.error(\"message\");\nlogger.debug(\"message\");\n```\n\n- Use namespaced loggers for specific modules (created internally by logger)\n- Log levels: `error`, `warning`, `info`, `debug` (from most to least critical)\n- Include relevant context in log messages (device names, IEEE addresses, etc.)\n\n## Code Quality Standards\n\n### Maintainability\n- Write self-documenting code with clear, descriptive names\n- Keep methods focused on single responsibilities\n- Abstract classes should define clear contracts with protected members for subclasses\n- Use constructor dependency injection for required dependencies\n- Limit function complexity - methods should be concise and focused\n- Use TypeScript's strict mode features (`noImplicitAny`, `noImplicitThis`)\n\n### Performance\n- Use `fs.rmSync(path, {recursive: true, force: true})` for synchronous file deletion when appropriate\n- Leverage async/await for I/O operations to avoid blocking\n- Use JSON stable stringify util for consistent object serialization\n- Cache computed values when appropriate (see device model patterns)\n- Use getter methods for computed properties that should be cached\n\n### Security\n- Validate input using Ajv JSON schema validation (see `settings.ts` pattern)\n- Sanitize file paths using `path.join` from Node.js\n- Use YAML safe loading: `yaml.safeLoad()`\n- Handle sensitive data (credentials, tokens) through settings with proper defaults\n- Never log sensitive information (passwords, tokens)\n\n### Testability\n- Write tests using Vitest with describe/it/expect patterns\n- Mock external dependencies using Vitest's `vi.mock()`\n- Use `beforeEach`, `afterEach`, `beforeAll`, `afterAll` for test setup/teardown\n- Place test files in `test/` directory with `.test.ts` extension\n- Mock constructors and modules in the pattern shown in `test/controller.test.ts`\n- Use `flushPromises()` utility for async test synchronization\n- Target 100% code coverage (configured in vitest.config.mts)\n\n## Testing Standards\n\n### Unit Testing Structure\n```typescript\nimport {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from \"vitest\";\n\ndescribe(\"ComponentName\", () => {\n    beforeEach(() => {\n        // Setup\n    });\n\n    it(\"Should do something specific\", async () => {\n        // Arrange\n        const input = {};\n\n        // Act\n        const result = await someFunction(input);\n\n        // Assert\n        expect(result).toBe(expected);\n    });\n});\n```\n\n### Mocking Patterns\n- Create mock modules in `test/mocks/` directory\n- Use `vi.fn()` for function mocks\n- Use `vi.mock()` for module mocks\n- Clear mocks in `afterEach` or between tests\n- Mock external libraries like `mqtt`, `zigbee-herdsman` consistently\n\n### Test Coverage\n- All code in `lib/**` should be covered\n- Use coverage reports: `pnpm test:coverage`\n- Thresholds set to 100% (can be adjusted per project needs)\n- Tests should cover both success and failure paths\n\n## Documentation Standards\n\n### JSDoc Comments\nUse JSDoc-style comments for classes and public methods:\n```typescript\n/**\n * Besides initializing variables, the constructor should do nothing!\n *\n * @param {Zigbee} zigbee Zigbee controller\n * @param {Mqtt} mqtt MQTT controller\n * @param {State} state State controller\n * @param {Function} publishEntityState Method to publish device state to MQTT.\n * @param {EventBus} eventBus The event bus\n */\nconstructor(zigbee: Zigbee, mqtt: Mqtt, state: State, ...) {\n```\n\n### Comment Style\n- Use single-line comments (`//`) for implementation notes\n- Use JSDoc (`/** */`) for public APIs and class/method documentation\n- Include context for non-obvious logic\n- Document parameters with their types and purposes\n- Use `@param` tags with TypeScript types in braces\n- Use biome-ignore comments when necessary: `// biome-ignore lint/rule: reason`\n\n### Code Documentation\n- Document complex algorithms or business logic\n- Explain \"why\" not just \"what\" when logic is non-trivial\n- Include links to relevant issues or documentation when applicable\n- Document deprecations and breaking changes\n\n## TypeScript-Specific Guidelines\n\n### Module System\n- Use ES modules with `import`/`export` syntax\n- Default exports for main classes: `export default class Device {}`\n- Named exports for utilities and types: `export const LOG_LEVELS = ...`\n- Namespace exports for related types: `export type * as ZSpec from ...`\n- Use `.js` extension in imports for local modules when using dynamic imports: `await import(\"./extension/frontend.js\")`\n\n### Type Safety\n- Enable all strict type checking options\n- Use type guards and assertions when necessary: `asserts expose is zhc.Numeric`\n- Prefer `unknown` over `any` when type is truly unknown\n- Use `// biome-ignore lint/suspicious/noExplicitAny: API` when `any` is necessary\n- Define proper interfaces for external module types (e.g., `unix-dgram.d.ts`)\n\n### Generic Types\n- Use generics for reusable, type-safe abstractions\n- Example: `abstract class ExternalJSExtension<M> extends Extension`\n- Constrain generics when appropriate\n- Document generic type parameters\n\n### Utility Types\n- Use built-in utility types: `Partial`, `Required`, `Pick`, `Omit`, `Record`\n- Use `Awaited<ReturnType<typeof fn>>` for async function return types\n- Define custom utility types when patterns emerge\n- Use `type` for aliases, `interface` for object shapes\n\n## Version Control and Releases\n\n### Versioning Strategy\n- Follow Semantic Versioning (MAJOR.MINOR.PATCH)\n- Current version managed in `package.json`\n- Use `-dev` suffix for development versions (e.g., `2.6.2-dev`)\n- Configuration version tracked separately: `CURRENT_VERSION = 4`\n\n### Changelog\n- Maintain CHANGELOG.md with all changes\n- Group changes by type: Bug Fixes, Features, Breaking Changes\n- Include issue/PR references: `([#28583](url))`\n- Include commit references: `([09f33b3](url))`\n- Use conventional commits format\n\n### Git Workflow\n- Development on `dev` branch\n- Production releases from `master` branch\n- Use meaningful commit messages\n- Reference issues in commits\n\n## Project-Specific Patterns\n\n### Settings Management\n- All configuration loaded through `util/settings.ts`\n- Validate settings using Ajv with JSON schema\n- Schema defined in `settings.schema.json`\n- Support runtime setting changes with restart detection\n- Use `settings.get()` to access current configuration\n- Use `settings.getDevice(ieeeAddr)` for device-specific config\n\n### Device and Group Models\n- Devices and groups are domain models wrapping `zigbee-herdsman` entities\n- Access underlying entity via `.zh` property\n- Expose computed properties as getters\n- Include definition from `zigbee-herdsman-converters`\n- Handle coordinator devices specially (type checking)\n\n### MQTT Integration\n- MQTT client wrapped in `Mqtt` class\n- Publish options: `retain`, `qos` properties\n- Topics follow pattern: `{base_topic}/{device}/{attribute}`\n- Event-based message handling via EventBus\n- Clean disconnect handling with retry logic\n\n### Extension System\n- Extensions are loosely coupled plugins\n- Lifecycle: constructor → start() → stop()\n- Constructor should only assign properties (no side effects)\n- Use EventBus for inter-extension communication\n- Extensions can be enabled/disabled at runtime\n- External extensions loaded from `data/external_extensions/`\n\n### State Management\n- State persisted to `state.json`\n- Cached in memory for performance\n- Device states include all exposed attributes\n- State changes trigger events via EventBus\n\n## Best Practices Specific to This Project\n\n1. **Never use language features beyond TypeScript 5.9.3 or ES2024**\n2. **Always respect exact versions of zigbee-herdsman and zigbee-herdsman-converters** - these are critical for device compatibility\n3. **Use the EventBus for all component communication** - avoid direct coupling\n4. **Follow the Extension pattern for new features** - don't add logic directly to Controller\n5. **Log appropriately** - info for user-relevant events, debug for developer info, error for failures\n6. **Test with real Zigbee scenarios** - many edge cases exist with different device types\n7. **Handle coordinator specially** - coordinator is a device but with unique behavior\n8. **Validate all external input** - MQTT messages, configuration files, device data\n9. **Use the bind decorator** for event handlers to preserve `this` context\n10. **Match the exact code formatting** - Biome enforces 4 spaces, 150 line width, no bracket spacing\n\n## Common Patterns to Follow\n\n### Creating a New Extension\n1. Extend `Extension` abstract class\n2. Accept all dependencies in constructor\n3. Implement `start()` method for initialization\n4. Subscribe to EventBus events in `start()`\n5. Implement `stop()` method for cleanup\n6. Export as default: `export default class MyExtension extends Extension`\n\n### Accessing Device Information\n```typescript\nconst device: Device; // Our wrapper\ndevice.ieeeAddr;      // IEEE address\ndevice.name;          // Friendly name\ndevice.zh;            // Underlying zigbee-herdsman device\ndevice.definition;    // zigbee-herdsman-converters definition\ndevice.options;       // User configuration\n```\n\n### Publishing MQTT Messages\n```typescript\nawait this.mqtt.publish(topic, message, {retain: true, qos: 0});\n```\n\n### Emitting Events\n```typescript\nthis.eventBus.emit('deviceMessage', {device, message});\n```\n\n### Listening to Events\n```typescript\nthis.eventBus.on('deviceMessage', this.onDeviceMessage, this);\n```\n\n## Integration Points\n\n### Zigbee-Herdsman Integration\n- Start controller: `await this.zigbee.start()`\n- Access coordinator: `this.zigbee.coordinator()`\n- Device operations through `zigbee-herdsman` API\n- Event handling through EventBus wrappers\n\n### MQTT Integration\n- Connect: `await this.mqtt.connect()`\n- Subscribe: `await this.mqtt.subscribe(topic)`\n- Publish: `await this.mqtt.publish(topic, message, options)`\n- Handle messages via EventBus `mqttMessage` event\n\n### Frontend Integration\n- Optional extension loaded dynamically\n- Serves static files with compression\n- WebSocket support for real-time updates\n- Configurable port and base URL\n\n### Home Assistant Integration\n- Optional extension for discovery\n- Publishes discovery messages to MQTT\n- Supports entities, sensors, and devices\n- Configurable discovery topic\n\n## Critical Compatibility Notes\n\n1. **Node.js**: Only versions 20, 22, and 24 are supported\n2. **TypeScript**: Features must be compatible with 5.9.3\n3. **Zigbee Libraries**: Exact versions are critical - do not suggest upgrades without testing\n4. **MQTT Protocol**: Uses MQTT 3.1.1 and 5.0 features\n5. **ES Modules**: Project uses ESM with NodeNext resolution\n6. **Experimental Decorators**: Required for `@bind` decorator support\n\n## When in Doubt\n\n1. **Search for similar patterns** in the existing codebase\n2. **Check existing extensions** for implementation examples\n3. **Follow the controller and extension architecture** - don't bypass it\n4. **Consult the test files** for usage examples\n5. **Match the exact style** - run `pnpm check` to verify\n6. **Prioritize consistency** over external best practices\n7. **Test thoroughly** - this project controls real hardware\n\n## Resources\n\n- Repository: https://github.com/Koenkk/zigbee2mqtt\n- Documentation: https://koenkk.github.io/zigbee2mqtt\n- License: GPL-3.0\n- Issue Tracker: https://github.com/Koenkk/zigbee2mqtt/issues\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# AGENTS.md\n\n## Project Overview\n\nZigbee2MQTT is a Zigbee to MQTT bridge that allows you to use your Zigbee devices without the vendor's bridge or gateway. It bridges events and allows you to control Zigbee devices via MQTT, integrating them with any smart home infrastructure.\n\n### Architecture\n\n- **Language**: TypeScript 5.9.3 compiled to JavaScript (ES modules with NodeNext resolution)\n- **Runtime**: Node.js (versions 20, 22, or 24)\n- **Package Manager**: pnpm 10.12.1 (strictly enforced via `packageManager` field)\n- **Core Dependencies**:\n  - `zigbee-herdsman` (6.2.0 - exact version, handles Zigbee adapter communication)\n  - `zigbee-herdsman-converters` (25.42.0 - exact version, device definitions)\n  - `mqtt` (5.14.1 - MQTT client)\n  - `winston` (3.18.3 - logging)\n\n### Project Structure\n\n```\nlib/                    # TypeScript source code\n├── controller.ts       # Main controller orchestrating components\n├── mqtt.ts            # MQTT client management\n├── zigbee.ts          # Zigbee network management\n├── state.ts           # State management\n├── eventBus.ts        # Event-driven communication\n├── extension/         # Extension system (plugins)\n│   └── extension.ts   # Abstract base class\n├── model/             # Domain models (Device, Group)\n├── util/              # Utility functions\n└── types/             # TypeScript type definitions\ntest/                  # Vitest test files with mocks\ndata/                  # Runtime configuration and database\ndist/                  # Compiled JavaScript output\n```\n\n## Setup Commands\n\n### Prerequisites\n\n- Node.js version 20, 22, or 24\n- pnpm 10.12.1 (will be auto-installed via corepack if not present)\n\n### Installation\n\n```bash\n# Install dependencies (uses pnpm lockfile)\npnpm install --frozen-lockfile\n\n# For development without lockfile restrictions\npnpm install\n```\n\n### Initial Build\n\n```bash\n# Full build (TypeScript compilation + hash generation)\npnpm run build\n\n# Build type definitions only\npnpm run build:types\n```\n\n## Development Workflow\n\n### Starting Development\n\n```bash\n# Watch mode - recompile on file changes\npnpm run build:watch\n\n# In another terminal, start Zigbee2MQTT\npnpm start\n```\n\n### Code Quality Checks\n\n```bash\n# Run Biome linter and formatter (check only)\npnpm run check\n\n# Auto-fix linting and formatting issues\npnpm run check:w\n\n# The check runs with --error-on-warnings flag\n# Configuration: biome.json (4-space indent, 150 line width, no bracket spacing)\n```\n\n### Clean Build\n\n```bash\n# Remove build artifacts\npnpm run clean\n\n# Removes: coverage/, dist/, tsconfig.tsbuildinfo\n```\n\n## Testing Instructions\n\n### Running Tests\n\n```bash\n# Run all tests once\npnpm test\n\n# Run tests with coverage report\npnpm run test:coverage\n\n# Watch mode - re-run tests on changes\npnpm run test:watch\n\n# Run benchmarks\npnpm run bench\n```\n\n### Test Requirements\n\n- **Coverage**: 100% code coverage is enforced (configured in `test/vitest.config.mts`)\n- **Framework**: Vitest 3.1.1 with @vitest/coverage-v8\n- **Test Files**: Located in `test/` directory with `.test.ts` extension\n- **Mocks**: Centralized in `test/mocks/` directory\n- **Coverage Report**: Generated in `coverage/` directory (HTML report at `coverage/index.html`)\n\n### Running Specific Tests\n\n```bash\n# Run tests matching a pattern\npnpm vitest run -t \"test name pattern\" --config ./test/vitest.config.mts\n\n# Run specific test file\npnpm vitest run test/controller.test.ts --config ./test/vitest.config.mts\n\n# Focus on one test area in watch mode\npnpm vitest watch -t \"Extension\" --config ./test/vitest.config.mts\n```\n\n## Code Style Guidelines\n\n### TypeScript Conventions\n\n- **Module System**: ES modules with NodeNext resolution\n- **Target**: ESNext\n- **Strict Mode**: Enabled (`noImplicitAny`, `noImplicitThis`)\n- **Decorators**: Experimental decorators enabled (used for `@bind` from `bind-decorator`)\n\n### Import Order\n\n1. Node.js built-in modules (with `node:` prefix)\n2. Third-party libraries\n3. Type-only imports from external packages (using `type` keyword)\n4. Internal absolute imports\n5. Type-only imports from internal modules\n\nExample:\n```typescript\nimport fs from \"node:fs\";\nimport bind from \"bind-decorator\";\nimport type {IClientOptions} from \"mqtt\";\nimport {connectAsync} from \"mqtt\";\nimport type {Zigbee2MQTTAPI} from \"./types/api\";\nimport logger from \"./util/logger\";\n```\n\n### Naming Conventions\n\n- **Classes**: PascalCase (e.g., `Extension`, `Device`)\n- **Functions/Methods**: camelCase (e.g., `publishEntityState`)\n- **Constants**: SCREAMING_SNAKE_CASE (e.g., `CURRENT_VERSION`)\n- **Interfaces/Types**: PascalCase (e.g., `MqttPublishOptions`)\n- **Files**: camelCase for TypeScript (e.g., `eventBus.ts`)\n\n### Code Patterns\n\n- **Async/Await**: Always use async/await, explicitly type return as `Promise<Type>`\n- **Error Handling**: Use `throw new Error(\"message\")`, log with winston logger\n- **Event Handlers**: Use `@bind` decorator to preserve `this` context\n- **Logging**: Use `logger.info()`, `logger.warning()`, `logger.error()`, `logger.debug()`\n\n### Formatting Rules (Biome)\n\n- 4-space indentation\n- 150 character line width\n- No bracket spacing in objects\n- Run `pnpm run check:w` to auto-format\n\n## Build and Deployment\n\n### Build Process\n\n```bash\n# Production build\npnpm run build\n\n# Outputs:\n# - Compiled JavaScript in dist/\n# - Type definitions in dist/types/\n# - Includes hash generation for version tracking\n```\n\n### Pre-publish\n\n```bash\n# Automatically runs before publishing\npnpm run prepack\n\n# Performs: clean + build\n```\n\n### Environment Setup\n\n- Configuration stored in `data/configuration.yaml`\n- Database in `data/database.db`\n- Logs in `data/log/`\n- External extensions in `data/external_extensions/`\n- External converters in `data/external_converters/`\n\n## Architecture Patterns\n\n### Extension System\n\nAll features are implemented as extensions that inherit from the abstract `Extension` base class:\n\n```typescript\nabstract class Extension {\n    protected zigbee: Zigbee;\n    protected mqtt: Mqtt;\n    protected state: State;\n    protected publishEntityState: PublishEntityState;\n    protected eventBus: EventBus;\n\n    async start(): Promise<void> {}  // Initialize extension\n    async stop(): Promise<void> {}   // Cleanup extension\n}\n```\n\n**Key Points**:\n- Constructor should only assign properties (no side effects)\n- Initialization happens in `start()` method\n- Use EventBus for inter-component communication\n- Extensions are loaded and managed by the Controller\n\n### Event-Driven Communication\n\nComponents communicate via the strongly-typed EventBus:\n\n```typescript\n// Emit events\nthis.eventBus.emit('deviceMessage', {device, message});\n\n// Listen to events\nthis.eventBus.on('deviceMessage', this.onDeviceMessage, this);\n```\n\n### Dependency Injection\n\nThe Controller instantiates and injects dependencies into all extensions. Follow this pattern when creating new extensions.\n\n## Pull Request Guidelines\n\n### Target Branch\n\n- **Always create PRs against the `dev` branch**\n- The `master` branch is for production releases only\n\n### Before Submitting\n\n```bash\n# Run all checks\npnpm run check\npnpm test\n\n# Ensure 100% code coverage\npnpm run test:coverage\n\n# Build successfully\npnpm run build\n```\n\n### PR Requirements\n\n- All CI checks must pass (linting, tests, build)\n- 100% test coverage maintained\n- Code follows Biome formatting rules\n- Commit messages should be descriptive\n- Reference related issues when applicable\n\n### CI Pipeline\n\nThe GitHub Actions CI workflow (`.github/workflows/ci.yml`) runs:\n1. Biome code quality checks (`pnpm run check`)\n2. TypeScript compilation (`pnpm run build`)\n3. Full test suite with coverage (`pnpm run test:coverage`)\n4. Benchmarks (on dev branch and PRs)\n5. Docker image builds (on dev branch and tags)\n\n## Working with Device Support\n\n### Adding New Devices\n\n**Important**: Device support is NOT added to this repository. All device definitions live in `zigbee-herdsman-converters`.\n\n- Follow the guide at: https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html\n- No changes to zigbee2mqtt codebase are needed for new devices\n- Device definitions are automatically picked up from `zigbee-herdsman-converters`\n\n## Debugging and Troubleshooting\n\n### Development Setup\n\nFor the easiest development experience, set up a bare-metal installation following:\nhttps://www.zigbee2mqtt.io/guide/installation/01_linux.html\n\n### Logging\n\n- Winston logger is initialized in `lib/util/logger.ts`\n- Log levels: `error`, `warning`, `info`, `debug`\n- Logs are written to console and/or file based on configuration\n- Use structured logging with context (device names, IEEE addresses)\n\n### Common Issues\n\n1. **Import errors after file moves**: Run `pnpm run check` to verify TypeScript and ESLint\n2. **Test failures**: Check if mocks in `test/mocks/` need updates\n3. **Build errors**: Ensure Node.js version is 20, 22, or 24\n4. **Coverage issues**: View HTML report at `coverage/index.html` to identify uncovered code\n\n### Performance Considerations\n\n- Use `fs.rmSync(path, {recursive: true, force: true})` for synchronous file operations\n- Leverage async/await to avoid blocking\n- Cache computed values in getters when appropriate\n- EventBus provides loose coupling between components\n\n## Critical Version Requirements\n\n### Exact Versions\n\nThese dependencies use **exact versions** (no semver ranges) - do not upgrade without thorough testing:\n\n- `zigbee-herdsman@6.2.0` - Critical for Zigbee protocol compatibility\n- `zigbee-herdsman-converters@25.42.0` - Device definitions must match herdsman version\n\n### Node.js Compatibility\n\nOnly these Node.js versions are supported:\n- Node.js 20.x\n- Node.js 22.x\n- Node.js 24.x\n\nUsing other versions may cause runtime errors or incompatibilities.\n\n## Additional Notes\n\n### Package Manager\n\nThis project **requires pnpm 10.12.1**. The `packageManager` field in package.json enforces this via Corepack.\n\nDo not use npm or yarn - they will not respect the pnpm-specific configuration.\n\n### TypeScript Compilation\n\n- Source files in `lib/` are compiled to `dist/`\n- Type definitions exported from `dist/types/api.d.ts`\n- Source maps are inlined for debugging\n- Uses composite project references for faster incremental builds\n\n### External Extensions\n\nTo load external extensions:\n1. Place JavaScript files in `data/external_extensions/`\n2. They will be automatically loaded on startup\n3. No configuration changes needed\n\n### Code Quality Tools\n\n- **Linting/Formatting**: Biome 2.2.5 (replaces ESLint + Prettier)\n- **Type Checking**: TypeScript 5.9.3\n- **Testing**: Vitest 3.1.1\n- **Coverage**: @vitest/coverage-v8\n\n### Documentation\n\n- Main documentation: https://www.zigbee2mqtt.io/\n- Contributing guide: `CONTRIBUTING.md`\n- Coding standards: `.github/copilot-instructions.md`\n- Issue tracker: https://github.com/Koenkk/zigbee2mqtt/issues\n","category":"root","tokens":2704},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","title":"copilot-instructions.md","content":"# GitHub Copilot Instructions\n\n## Priority Guidelines\n\nWhen generating code for this repository:\n\n1. **Version Compatibility**: Always detect and respect the exact versions of languages, frameworks, and libraries used in this project\n2. **Context Files**: Prioritize patterns and standards defined in the .github/copilot directory\n3. **Codebase Patterns**: When context files don't provide specific guidance, scan the codebase for established patterns\n4. **Architectural Consistency**: Maintain our layered architectural style with clear separation between controller, extensions, models, and utilities\n5. **Code Quality**: Prioritize maintainability, performance, security, and testability in all generated code\n\n## Technology Stack\n\n### Core Technologies\n- **Language**: TypeScript 5.9.3 with target `esnext` and module `NodeNext`\n- **Runtime**: Node.js ^20 || ^22 || ^24\n- **Package Manager**: pnpm 10.12.1\n- **Testing**: Vitest 3.1.1 with @vitest/coverage-v8\n- **Linting/Formatting**: Biome 2.2.5 (configured with 4-space indents, 150 line width, no bracket spacing)\n\n### Key Dependencies\n- **zigbee-herdsman**: 6.2.0 (exact version - critical for Zigbee protocol compatibility)\n- **zigbee-herdsman-converters**: 25.42.0 (exact version - device definitions)\n- **MQTT**: mqtt 5.14.1\n- **Logging**: winston 3.18.3\n- **YAML**: js-yaml 4.1.0\n- **Decorators**: bind-decorator 1.0.11\n- **WebSocket**: ws 8.18.1\n\n### TypeScript Configuration\n- **Strict Mode**: Enabled with `noImplicitAny` and `noImplicitThis`\n- **Module System**: NodeNext with ESM interop\n- **Decorators**: Experimental decorators enabled\n- **Composite**: True (for project references)\n- **Source Maps**: Inline source maps enabled\n- **Output**: Compiled to `dist/` directory\n\n## Project Architecture\n\n### Directory Structure\n```\nlib/                    # Source TypeScript files\n├── controller.ts       # Main controller orchestrating all components\n├── mqtt.ts            # MQTT client management\n├── zigbee.ts          # Zigbee network management\n├── state.ts           # State management\n├── eventBus.ts        # Event-driven communication\n├── extension/         # Extension system (plugins)\n│   ├── extension.ts   # Abstract base class\n│   ├── availability.ts\n│   ├── bind.ts\n│   ├── bridge.ts\n│   ├── configure.ts\n│   └── ...\n├── model/             # Domain models\n│   ├── device.ts\n│   └── group.ts\n├── util/              # Utility functions\n│   ├── logger.ts\n│   ├── settings.ts\n│   ├── utils.ts\n│   └── ...\n└── types/             # TypeScript type definitions\n    └── api.ts\ntest/                  # Vitest test files\ndata/                  # Runtime configuration and data\n```\n\n### Architectural Patterns\n\n#### Extension Pattern\nAll extensions inherit from the abstract `Extension` base class:\n```typescript\nabstract class Extension {\n    protected zigbee: Zigbee;\n    protected mqtt: Mqtt;\n    protected state: State;\n    protected publishEntityState: PublishEntityState;\n    protected eventBus: EventBus;\n\n    async start(): Promise<void> {}\n    async stop(): Promise<void> {}\n}\n```\n\n#### Event-Driven Architecture\nUse the `EventBus` for component communication. Events are strongly typed:\n```typescript\ninterface EventBusMap {\n    deviceMessage: [data: eventdata.DeviceMessage];\n    mqttMessage: [data: eventdata.MQTTMessage];\n    publishEntityState: [data: eventdata.PublishEntityState];\n    // ... other events\n}\n```\n\n#### Dependency Injection\nThe `Controller` class instantiates and injects dependencies into extensions. Follow this pattern when creating new extensions.\n\n## Code Style and Conventions\n\n### Naming Conventions\n- **Classes**: PascalCase (e.g., `Extension`, `Device`, `EventBus`)\n- **Interfaces/Types**: PascalCase (e.g., `MqttPublishOptions`, `DeviceOptions`)\n- **Functions/Methods**: camelCase (e.g., `publishEntityState`, `enableDisableExtension`)\n- **Constants**: SCREAMING_SNAKE_CASE for top-level constants (e.g., `CURRENT_VERSION`, `LOG_LEVELS`)\n- **Private members**: Prefix with underscore for private class fields only when needed to distinguish from public properties (e.g., `_definitionModelID`)\n- **Files**: camelCase for TypeScript files (e.g., `eventBus.ts`, `externalJS.ts`)\n\n### Import Organization\nFollow this import order (separated by blank lines):\n1. Node.js built-in modules (use `node:` prefix: `import fs from \"node:fs\"`)\n2. Third-party libraries (e.g., `bind-decorator`, `mqtt`)\n3. Type-only imports from external packages (using `type` keyword)\n4. Internal absolute imports from project root\n5. Type-only imports from internal modules\n\nExample:\n```typescript\nimport fs from \"node:fs\";\nimport bind from \"bind-decorator\";\nimport type {IClientOptions} from \"mqtt\";\nimport {connectAsync} from \"mqtt\";\nimport type {Zigbee2MQTTAPI} from \"./types/api\";\nimport logger from \"./util/logger\";\nimport * as settings from \"./util/settings\";\n```\n\n### Type Annotations\n- Use `type` imports for TypeScript types: `import type * as zhc from \"zigbee-herdsman-converters\"`\n- Explicitly type function parameters and return types\n- Use `KeyValue` type for generic object payloads: `type KeyValue = Record<string, any>`\n- Prefer interfaces for object shapes, type aliases for unions/intersections\n- Use namespace exports for related types: `export type * as ZSpec from \"zigbee-herdsman/dist/zspec\"`\n\n### Async/Await Patterns\n- Always use `async/await` for asynchronous operations\n- Return types should be explicitly `Promise<Type>`\n- Methods that don't return values should be `Promise<void>`\n- Use `Awaited<ReturnType<typeof fn>>` for inferring async function return types\n\n### Decorators\nUse `@bind` decorator from `bind-decorator` for methods that need `this` binding:\n```typescript\n@bind async onMQTTMessage(data: eventdata.MQTTMessage): Promise<void> {\n    // Implementation\n}\n```\n\n### Error Handling\n- Use `throw new Error(\"message\")` for explicit errors\n- Include descriptive error messages\n- Log errors using the logger: `logger.error(\"message\")`\n- For Zigbee-herdsman errors, log the stack trace: `logger.error((error as Error).stack!)`\n- Catch and handle errors at appropriate boundaries (controller level)\n\n### Logging\nUse the centralized logger (winston-based):\n```typescript\nimport logger from \"./util/logger\";\n\nlogger.info(\"message\");\nlogger.warning(\"message\");\nlogger.error(\"message\");\nlogger.debug(\"message\");\n```\n\n- Use namespaced loggers for specific modules (created internally by logger)\n- Log levels: `error`, `warning`, `info`, `debug` (from most to least critical)\n- Include relevant context in log messages (device names, IEEE addresses, etc.)\n\n## Code Quality Standards\n\n### Maintainability\n- Write self-documenting code with clear, descriptive names\n- Keep methods focused on single responsibilities\n- Abstract classes should define clear contracts with protected members for subclasses\n- Use constructor dependency injection for required dependencies\n- Limit function complexity - methods should be concise and focused\n- Use TypeScript's strict mode features (`noImplicitAny`, `noImplicitThis`)\n\n### Performance\n- Use `fs.rmSync(path, {recursive: true, force: true})` for synchronous file deletion when appropriate\n- Leverage async/await for I/O operations to avoid blocking\n- Use JSON stable stringify util for consistent object serialization\n- Cache computed values when appropriate (see device model patterns)\n- Use getter methods for computed properties that should be cached\n\n### Security\n- Validate input using Ajv JSON schema validation (see `settings.ts` pattern)\n- Sanitize file paths using `path.join` from Node.js\n- Use YAML safe loading: `yaml.safeLoad()`\n- Handle sensitive data (credentials, tokens) through settings with proper defaults\n- Never log sensitive information (passwords, tokens)\n\n### Testability\n- Write tests using Vitest with describe/it/expect patterns\n- Mock external dependencies using Vitest's `vi.mock()`\n- Use `beforeEach`, `afterEach`, `beforeAll`, `afterAll` for test setup/teardown\n- Place test files in `test/` directory with `.test.ts` extension\n- Mock constructors and modules in the pattern shown in `test/controller.test.ts`\n- Use `flushPromises()` utility for async test synchronization\n- Target 100% code coverage (configured in vitest.config.mts)\n\n## Testing Standards\n\n### Unit Testing Structure\n```typescript\nimport {afterAll, beforeAll, beforeEach, describe, expect, it, vi} from \"vitest\";\n\ndescribe(\"ComponentName\", () => {\n    beforeEach(() => {\n        // Setup\n    });\n\n    it(\"Should do something specific\", async () => {\n        // Arrange\n        const input = {};\n\n        // Act\n        const result = await someFunction(input);\n\n        // Assert\n        expect(result).toBe(expected);\n    });\n});\n```\n\n### Mocking Patterns\n- Create mock modules in `test/mocks/` directory\n- Use `vi.fn()` for function mocks\n- Use `vi.mock()` for module mocks\n- Clear mocks in `afterEach` or between tests\n- Mock external libraries like `mqtt`, `zigbee-herdsman` consistently\n\n### Test Coverage\n- All code in `lib/**` should be covered\n- Use coverage reports: `pnpm test:coverage`\n- Thresholds set to 100% (can be adjusted per project needs)\n- Tests should cover both success and failure paths\n\n## Documentation Standards\n\n### JSDoc Comments\nUse JSDoc-style comments for classes and public methods:\n```typescript\n/**\n * Besides initializing variables, the constructor should do nothing!\n *\n * @param {Zigbee} zigbee Zigbee controller\n * @param {Mqtt} mqtt MQTT controller\n * @param {State} state State controller\n * @param {Function} publishEntityState Method to publish device state to MQTT.\n * @param {EventBus} eventBus The event bus\n */\nconstructor(zigbee: Zigbee, mqtt: Mqtt, state: State, ...) {\n```\n\n### Comment Style\n- Use single-line comments (`//`) for implementation notes\n- Use JSDoc (`/** */`) for public APIs and class/method documentation\n- Include context for non-obvious logic\n- Document parameters with their types and purposes\n- Use `@param` tags with TypeScript types in braces\n- Use biome-ignore comments when necessary: `// biome-ignore lint/rule: reason`\n\n### Code Documentation\n- Document complex algorithms or business logic\n- Explain \"why\" not just \"what\" when logic is non-trivial\n- Include links to relevant issues or documentation when applicable\n- Document deprecations and breaking changes\n\n## TypeScript-Specific Guidelines\n\n### Module System\n- Use ES modules with `import`/`export` syntax\n- Default exports for main classes: `export default class Device {}`\n- Named exports for utilities and types: `export const LOG_LEVELS = ...`\n- Namespace exports for related types: `export type * as ZSpec from ...`\n- Use `.js` extension in imports for local modules when using dynamic imports: `await import(\"./extension/frontend.js\")`\n\n### Type Safety\n- Enable all strict type checking options\n- Use type guards and assertions when necessary: `asserts expose is zhc.Numeric`\n- Prefer `unknown` over `any` when type is truly unknown\n- Use `// biome-ignore lint/suspicious/noExplicitAny: API` when `any` is necessary\n- Define proper interfaces for external module types (e.g., `unix-dgram.d.ts`)\n\n### Generic Types\n- Use generics for reusable, type-safe abstractions\n- Example: `abstract class ExternalJSExtension<M> extends Extension`\n- Constrain generics when appropriate\n- Document generic type parameters\n\n### Utility Types\n- Use built-in utility types: `Partial`, `Required`, `Pick`, `Omit`, `Record`\n- Use `Awaited<ReturnType<typeof fn>>` for async function return types\n- Define custom utility types when patterns emerge\n- Use `type` for aliases, `interface` for object shapes\n\n## Version Control and Releases\n\n### Versioning Strategy\n- Follow Semantic Versioning (MAJOR.MINOR.PATCH)\n- Current version managed in `package.json`\n- Use `-dev` suffix for development versions (e.g., `2.6.2-dev`)\n- Configuration version tracked separately: `CURRENT_VERSION = 4`\n\n### Changelog\n- Maintain CHANGELOG.md with all changes\n- Group changes by type: Bug Fixes, Features, Breaking Changes\n- Include issue/PR references: `([#28583](url))`\n- Include commit references: `([09f33b3](url))`\n- Use conventional commits format\n\n### Git Workflow\n- Development on `dev` branch\n- Production releases from `master` branch\n- Use meaningful commit messages\n- Reference issues in commits\n\n## Project-Specific Patterns\n\n### Settings Management\n- All configuration loaded through `util/settings.ts`\n- Validate settings using Ajv with JSON schema\n- Schema defined in `settings.schema.json`\n- Support runtime setting changes with restart detection\n- Use `settings.get()` to access current configuration\n- Use `settings.getDevice(ieeeAddr)` for device-specific config\n\n### Device and Group Models\n- Devices and groups are domain models wrapping `zigbee-herdsman` entities\n- Access underlying entity via `.zh` property\n- Expose computed properties as getters\n- Include definition from `zigbee-herdsman-converters`\n- Handle coordinator devices specially (type checking)\n\n### MQTT Integration\n- MQTT client wrapped in `Mqtt` class\n- Publish options: `retain`, `qos` properties\n- Topics follow pattern: `{base_topic}/{device}/{attribute}`\n- Event-based message handling via EventBus\n- Clean disconnect handling with retry logic\n\n### Extension System\n- Extensions are loosely coupled plugins\n- Lifecycle: constructor → start() → stop()\n- Constructor should only assign properties (no side effects)\n- Use EventBus for inter-extension communication\n- Extensions can be enabled/disabled at runtime\n- External extensions loaded from `data/external_extensions/`\n\n### State Management\n- State persisted to `state.json`\n- Cached in memory for performance\n- Device states include all exposed attributes\n- State changes trigger events via EventBus\n\n## Best Practices Specific to This Project\n\n1. **Never use language features beyond TypeScript 5.9.3 or ES2024**\n2. **Always respect exact versions of zigbee-herdsman and zigbee-herdsman-converters** - these are critical for device compatibility\n3. **Use the EventBus for all component communication** - avoid direct coupling\n4. **Follow the Extension pattern for new features** - don't add logic directly to Controller\n5. **Log appropriately** - info for user-relevant events, debug for developer info, error for failures\n6. **Test with real Zigbee scenarios** - many edge cases exist with different device types\n7. **Handle coordinator specially** - coordinator is a device but with unique behavior\n8. **Validate all external input** - MQTT messages, configuration files, device data\n9. **Use the bind decorator** for event handlers to preserve `this` context\n10. **Match the exact code formatting** - Biome enforces 4 spaces, 150 line width, no bracket spacing\n\n## Common Patterns to Follow\n\n### Creating a New Extension\n1. Extend `Extension` abstract class\n2. Accept all dependencies in constructor\n3. Implement `start()` method for initialization\n4. Subscribe to EventBus events in `start()`\n5. Implement `stop()` method for cleanup\n6. Export as default: `export default class MyExtension extends Extension`\n\n### Accessing Device Information\n```typescript\nconst device: Device; // Our wrapper\ndevice.ieeeAddr;      // IEEE address\ndevice.name;          // Friendly name\ndevice.zh;            // Underlying zigbee-herdsman device\ndevice.definition;    // zigbee-herdsman-converters definition\ndevice.options;       // User configuration\n```\n\n### Publishing MQTT Messages\n```typescript\nawait this.mqtt.publish(topic, message, {retain: true, qos: 0});\n```\n\n### Emitting Events\n```typescript\nthis.eventBus.emit('deviceMessage', {device, message});\n```\n\n### Listening to Events\n```typescript\nthis.eventBus.on('deviceMessage', this.onDeviceMessage, this);\n```\n\n## Integration Points\n\n### Zigbee-Herdsman Integration\n- Start controller: `await this.zigbee.start()`\n- Access coordinator: `this.zigbee.coordinator()`\n- Device operations through `zigbee-herdsman` API\n- Event handling through EventBus wrappers\n\n### MQTT Integration\n- Connect: `await this.mqtt.connect()`\n- Subscribe: `await this.mqtt.subscribe(topic)`\n- Publish: `await this.mqtt.publish(topic, message, options)`\n- Handle messages via EventBus `mqttMessage` event\n\n### Frontend Integration\n- Optional extension loaded dynamically\n- Serves static files with compression\n- WebSocket support for real-time updates\n- Configurable port and base URL\n\n### Home Assistant Integration\n- Optional extension for discovery\n- Publishes discovery messages to MQTT\n- Supports entities, sensors, and devices\n- Configurable discovery topic\n\n## Critical Compatibility Notes\n\n1. **Node.js**: Only versions 20, 22, and 24 are supported\n2. **TypeScript**: Features must be compatible with 5.9.3\n3. **Zigbee Libraries**: Exact versions are critical - do not suggest upgrades without testing\n4. **MQTT Protocol**: Uses MQTT 3.1.1 and 5.0 features\n5. **ES Modules**: Project uses ESM with NodeNext resolution\n6. **Experimental Decorators**: Required for `@bind` decorator support\n\n## When in Doubt\n\n1. **Search for similar patterns** in the existing codebase\n2. **Check existing extensions** for implementation examples\n3. **Follow the controller and extension architecture** - don't bypass it\n4. **Consult the test files** for usage examples\n5. **Match the exact style** - run `pnpm check` to verify\n6. **Prioritize consistency** over external best practices\n7. **Test thoroughly** - this project controls real hardware\n\n## Resources\n\n- Repository: https://github.com/Koenkk/zigbee2mqtt\n- Documentation: https://koenkk.github.io/zigbee2mqtt\n- License: GPL-3.0\n- Issue Tracker: https://github.com/Koenkk/zigbee2mqtt/issues\n","category":".github","tokens":4391}]}