Skip to content

Commit be124f7

Browse files
Merge pull request #41 from TheRealFalseReality/copilot/add-copilot-instructions-file
Add .github/copilot-instructions.md for agent onboarding
2 parents e708cc3 + 5503e04 commit be124f7

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed

.github/copilot-instructions.md

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# Copilot Instructions for Aquarium AI Home Assistant Integration
2+
3+
## Project Overview
4+
5+
This is a **Home Assistant custom integration** called **Aquarium AI** (domain: `aquarium_ai`). It uses Home Assistant's built-in `ai_task` service to perform AI-powered analysis of aquarium sensor data and optional camera feeds, providing natural-language health assessments, water change recommendations, and persistent notifications.
6+
7+
The integration is distributed via **HACS** (Home Assistant Community Store) and has no Python package dependencies beyond Home Assistant itself.
8+
9+
---
10+
11+
## Repository Structure
12+
13+
```
14+
custom_components/aquarium_ai/ # Main integration code
15+
├── __init__.py # Integration setup, core AI analysis logic, helper functions
16+
├── config_flow.py # Multi-step UI configuration flow (ConfigFlow + OptionsFlow)
17+
├── const.py # All constants, defaults, and default AI prompts
18+
├── manifest.json # Integration metadata (domain, version, dependencies)
19+
├── sensor.py # Sensor entities (AI analysis text sensors, per-parameter + overall)
20+
├── binary_sensor.py # Binary sensors (water change needed, parameter problem)
21+
├── button.py # Button entity (Run Analysis)
22+
├── select.py # Select entities (Update Frequency, Notification Format)
23+
├── switch.py # Switch entities (auto-notifications, per-parameter analysis toggles)
24+
├── services.yaml # Service definitions (run_analysis, run_analysis_for_aquarium)
25+
├── strings.json # Default English UI strings
26+
└── translations/
27+
├── en.json # English translations
28+
├── de.json # German translations
29+
└── template.json # Template for new translations
30+
31+
.github/
32+
├── workflows/
33+
│ ├── hassfest.yaml # Validates integration against Home Assistant standards
34+
│ └── validate.yml # HACS validation + hassfest
35+
└── ISSUE_TEMPLATE/
36+
├── bug_report.md
37+
└── feature_request.md
38+
39+
hacs.json # HACS metadata
40+
README.md # User-facing documentation
41+
CONTRIBUTING.md # Contribution guidelines
42+
TRANSLATION_GUIDE.md # Instructions for adding translations
43+
```
44+
45+
---
46+
47+
## Key Architecture Concepts
48+
49+
### Integration Setup Flow
50+
1. `async_setup_entry` in `__init__.py` is the main entry point
51+
2. It forwards setup to all platforms: `sensor`, `binary_sensor`, `switch`, `select`, `button`
52+
3. Schedules periodic AI analysis using `async_track_time_interval`
53+
4. Optionally runs analysis on startup (60-second delay via `async_call_later`)
54+
5. Registers `run_analysis` and `run_analysis_for_aquarium` services
55+
56+
### AI Analysis Pipeline (`__init__.py: send_ai_aquarium_analysis`)
57+
1. Collects sensor data from configured HA sensor entities using `get_sensor_info()`
58+
2. Checks per-parameter analysis toggle switches (stored in `entry.data`)
59+
3. Builds a structured prompt using configurable AI prompt templates from `const.py`
60+
4. Calls `ai_task.generate_data` service with a structured response schema
61+
5. Stores the AI response in `hass.data[DOMAIN][entry_id]["sensor_analysis"]`
62+
6. Sends a `persistent_notification` (if auto-notifications enabled)
63+
7. Triggers state updates on sensor entities via `async_write_ha_state()`
64+
65+
### Shared Data Pattern
66+
Entities read AI analysis results from `hass.data[DOMAIN][entry_id]["sensor_analysis"]` — a dict populated after each AI call. Sensor entities poll this dict on `async_update()`.
67+
68+
### Config Entry Data Storage
69+
All configuration (sensors, toggles, AI prompts, tank info) is stored directly in `config_entry.data`. The options flow updates `entry.data` directly via `hass.config_entries.async_update_entry()` — it does **not** use `entry.options`.
70+
71+
---
72+
73+
## Entity Naming Conventions
74+
75+
All entities are named with the tank name as a prefix:
76+
- `{tank_name} Temperature Analysis` (sensor)
77+
- `{tank_name} Water Change Needed` (binary sensor)
78+
- `{tank_name} Run Analysis` (button)
79+
- `{tank_name} Update Frequency` (select)
80+
- `{tank_name} Analyze Temperature` (switch)
81+
82+
Unique IDs follow the pattern: `{entry_id}_{descriptor}` (e.g., `{entry_id}_temperature_analysis`).
83+
84+
All entities share the same device under:
85+
```python
86+
{"identifiers": {(DOMAIN, config_entry.entry_id)}, "name": f"Aquarium AI - {tank_name}"}
87+
```
88+
89+
---
90+
91+
## AI Response Structure
92+
93+
The AI call uses `ai_task.generate_data` with a `structure` dict. Response keys follow these patterns:
94+
- `{param_name_snake_case}_analysis` — brief (≤200 chars), used for sensor state
95+
- `{param_name_snake_case}_notification_analysis` — detailed, used in notifications
96+
- `overall_analysis` / `overall_notification_analysis` — overall health
97+
- `water_change_recommended``"Yes/No + brief reason"` (drives binary sensor state)
98+
- `water_change_recommendation` — detailed recommendation for notifications
99+
- `camera_visual_analysis` / `camera_visual_notification_analysis` — visual analysis (only if camera configured and toggle enabled)
100+
101+
Sensor states are capped at 255 characters (truncated with `...`).
102+
103+
---
104+
105+
## Adding New Parameters or Sensors
106+
107+
When adding a new sensor type (e.g., Ammonia), you must update **all** of the following:
108+
1. `const.py` — Add `CONF_*_SENSOR`, `CONF_ANALYZE_*`, `DEFAULT_ANALYZE_*`
109+
2. `__init__.py` — Add to `sensor_mappings` list in `async_setup_entry`
110+
3. `sensor.py` — Add to `sensor_mappings` in `async_setup_entry`
111+
4. `binary_sensor.py` — Add to `sensor_mappings`
112+
5. `switch.py` — Add to `parameter_switches` list
113+
6. `config_flow.py` — Add `EntitySelector` to sensors step schema in both `AquariumAIConfigFlow` and `AquariumAIOptionsFlow._get_sensors_schema()`
114+
7. `strings.json` — Add label and description for the new sensor field
115+
8. `translations/en.json` — Mirror the strings.json changes
116+
9. `translations/template.json` — Add the translation key
117+
118+
---
119+
120+
## Validation and CI
121+
122+
There are **no unit tests** in this repository. All testing is done manually in a real Home Assistant environment.
123+
124+
CI runs two checks via GitHub Actions:
125+
- **`hassfest`** (`hassfest.yaml`): Validates integration metadata, manifest, translations, and strings against HA standards
126+
- **`HACS validation`** (`validate.yml`): Validates HACS-specific requirements
127+
128+
To validate locally, you can run hassfest in a Home Assistant dev environment:
129+
```bash
130+
python -m script.hassfest
131+
```
132+
133+
There is no `requirements.txt`, `pyproject.toml`, or linting configuration — the project relies on HA's built-in validation.
134+
135+
---
136+
137+
## Translation System
138+
139+
- `strings.json` is the source of truth for UI text keys
140+
- `translations/en.json` must mirror `strings.json` exactly
141+
- `translations/template.json` is a template for translators
142+
- New translation files go in `translations/{lang_code}.json`
143+
- Hassfest validates that translations match the structure defined in `strings.json`
144+
145+
When modifying UI-visible text (config flow steps, labels, descriptions, error messages):
146+
1. Update `strings.json`
147+
2. Update `translations/en.json` with the same change
148+
3. Update `translations/template.json`
149+
4. Update any other existing translation files if the key structure changes
150+
151+
---
152+
153+
## Debug Logging
154+
155+
To enable debug logging in Home Assistant, add to `configuration.yaml`:
156+
```yaml
157+
logger:
158+
default: info
159+
logs:
160+
custom_components.aquarium_ai: debug
161+
```
162+
163+
All modules use `_LOGGER = logging.getLogger(__name__)`.
164+
165+
---
166+
167+
## Common Errors and Workarounds
168+
169+
- **`sensor_not_found` error in config flow**: The sensor entity provided does not exist in HA states. Validate that the entity is available before saving.
170+
- **`ai_task_required` error**: The `ai_task` entity ID was not provided. It is mandatory for the integration to function.
171+
- **`at_least_one_sensor` error**: At least one sensor entity must be configured.
172+
- **Sensor state truncation**: AI responses longer than 255 characters are automatically truncated to 252 chars + `...` before storing in sensor state.
173+
- **Options flow saves to `entry.data` directly**: Unlike typical HA patterns that use `entry.options`, this integration saves all settings directly into `entry.data` via `async_update_entry`. Do not introduce `entry.options` usage without updating all consumers.
174+
- **No `PLATFORMS` list**: Platform names are hardcoded as a list `["sensor", "binary_sensor", "switch", "select", "button"]` in `async_setup_entry` and `async_unload_entry`.
175+
- **Hassfest validation failures**: Commonly caused by mismatched keys between `strings.json` and `translations/en.json`, or invalid `manifest.json` fields. Always sync these files after changes.
176+
177+
---
178+
179+
## Version and Release
180+
181+
The integration version is defined in `manifest.json` (`"version": "1.2.1"`). Update this when releasing new versions. HACS uses GitHub releases — create a release tag matching the version string.
182+
183+
---
184+
185+
## Home Assistant Coding Conventions
186+
187+
- All setup functions are `async` and prefixed with `async_`
188+
- `async_setup_entry` / `async_unload_entry` are the standard HA entry points
189+
- Use `entry.data.get(KEY, DEFAULT)` pattern for safe config access
190+
- `hass.config_entries.async_update_entry()` is used for runtime config changes
191+
- Entity state must be written via `self.async_write_ha_state()` after mutations
192+
- `_LOGGER` is module-level, not class-level
193+
- Use `vol.Schema` with `voluptuous` for config validation
194+
- Selectors come from `homeassistant.helpers.selector`

0 commit comments

Comments
 (0)