diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0519249..9c1303b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -15,9 +15,9 @@ NOAA Integration is a Home Assistant custom component that provides NOAA solar a ### Code Validation and Quality - **ALWAYS validate Python syntax before making changes**: - - `python3 -m py_compile custom_components/noaa_integration/__init__.py custom_components/noaa_integration/sensor.py custom_components/noaa_integration/image.py` -- takes <1 second + - `python3 -m py_compile custom_components/noaa_it_all/__init__.py custom_components/noaa_it_all/sensor.py custom_components/noaa_it_all/image.py` -- takes <1 second - **ALWAYS run code linting before committing**: - - `flake8 custom_components/noaa_integration/ --max-line-length=120` -- takes <5 seconds + - `flake8 custom_components/noaa_it_all/ --max-line-length=120` -- takes <5 seconds - Fix all linting issues before proceeding. Common issues: blank line spacing (E302), line length (E501), unused imports (F401) - **NEVER commit code with linting errors** - the HACS validation will fail @@ -32,9 +32,9 @@ For thorough validation of your changes, run all essential checks: ```bash # Essential validation sequence (takes <30 seconds total) python3 --version # Verify Python -python3 -m py_compile custom_components/noaa_integration/*.py # Syntax check -flake8 custom_components/noaa_integration/ --max-line-length=120 # Code quality -python3 -c "import json; print('Valid:', json.load(open('custom_components/noaa_integration/manifest.json'))['domain'])" # JSON validation +python3 -m py_compile custom_components/noaa_it_all/*.py # Syntax check +flake8 custom_components/noaa_it_all/ --max-line-length=120 # Code quality +python3 -c "import json; print('Valid:', json.load(open('custom_components/noaa_it_all/manifest.json'))['domain'])" # JSON validation ``` **CRITICAL**: Fix ALL flake8 issues before committing - zero tolerance for linting errors. @@ -69,11 +69,23 @@ python3 -c "import json; print('Valid:', json.load(open('custom_components/noaa_ ### Key Files and Locations ``` -/custom_components/noaa_integration/ -├── __init__.py # Component initialization and platform discovery +/custom_components/noaa_it_all/ +├── __init__.py # Component setup and platform forwarding ├── manifest.json # Component metadata, dependencies, version -├── sensor.py # Sensor entities: K-index, geomagnetic storm data and interpretations -└── image.py # Image entities: geoelectric field and aurora forecast images +├── config_flow.py # UI config flow (config_flow: true in the manifest) +├── const.py # Constants, API endpoints, defaults +├── coordinator.py # DataUpdateCoordinator: fetches and caches NOAA data +├── parsers.py # Parsing helpers for NOAA API and text-product responses +├── entity_naming.py # Shared entity naming helpers +├── sensor.py # Sensor platform +├── binary_sensor.py # Binary sensor platform +├── image.py # Image platform: geoelectric field and aurora forecast images +├── weather.py # Weather platform +├── strings.json # UI strings for the config flow +├── sensors/ # Per-area sensor definitions (space_weather, surf, alerts, +│ # forecasts, hurricanes, weather_observations, weather_extra) +├── translations/ # en.json +└── brand/ # Brand images served by HA (icon/logo, incl. @2x and dark) ``` ### Configuration Files @@ -124,7 +136,7 @@ python3 -c "import json; print('Valid:', json.load(open('custom_components/noaa_ 4. Users install via HACS in Home Assistant ### Version Management -- Update version in `custom_components/noaa_integration/manifest.json` +- Update version in `custom_components/noaa_it_all/manifest.json` - Version format: semantic versioning (e.g., "1.0.12") - HACS uses manifest version for release tracking diff --git a/README.md b/README.md index 734f084..0492590 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ![Tracked Installs](https://img.shields.io/endpoint?url=https://analytics.home-assistant.io/api/badge_custom_integrations_json/noaa_it_all.json&style=for-the-badge&logo=home-assistant&label=Tracked%20Installs&color=gray)

-
+ NOAA It All

This Home Assistant integration provides comprehensive NOAA data through sensors and images, with the latest addition of location-specific rip current and surf zone forecasts. diff --git a/hacs.json b/hacs.json index 3d74728..4f2c521 100644 --- a/hacs.json +++ b/hacs.json @@ -1,7 +1,7 @@ { "name": "NOAA It All", "content_in_root": false, - "country": "US", + "country": "US", "render_readme": true, "homeassistant": "2026.3.0", "zip_release": false diff --git a/tests/test_manifest.py b/tests/test_manifest.py index 94cf3d0..3315253 100644 --- a/tests/test_manifest.py +++ b/tests/test_manifest.py @@ -2,6 +2,7 @@ import json import os +import re import struct import unittest import zlib @@ -218,12 +219,51 @@ def test_corners_are_transparent(self): ) def test_root_icon_exists(self): - """icon.png at the repository root is required for HACS store display.""" + """icon.png at the repository root is the README header image source. + + It is NOT read by HACS or Home Assistant for any store or UI display. + Those come from custom_components/noaa_it_all/brand/ (inside HA) and from + the home-assistant/brands CDN (the HACS store list). + """ root_icon = os.path.join(_REPO, "icon.png") self.assertTrue(os.path.isfile(root_icon), "icon.png missing from repository root") w, h, _, _, _ = _png_dimensions(root_icon) self.assertEqual((w, h), (256, 256), "root icon.png must be 256x256") +class TestReadmeImages(unittest.TestCase): + """Guard against image URLs that render as a broken image. + + A github.com///blob/... URL serves an HTML *page*, not an image, + so it shows as broken on GitHub and on the HACS repository page (hacs.json sets + render_readme, so HACS renders this same markdown). + """ + + _FENCE = re.compile(r"^\s*(```|~~~).*?^\s*\1", re.DOTALL | re.MULTILINE) + _HTML_IMG = re.compile(r"]*?\ssrc=[\"']([^\"']+)[\"']", re.IGNORECASE) + _MD_IMG = re.compile(r"!\[[^\]]*\]\(\s*([^\s)]+)") + + @classmethod + def setUpClass(cls): + with open(os.path.join(_REPO, "README.md"), encoding="utf-8") as f: + body = f.read() + # Drop fenced code blocks first: the Lovelace card examples contain + # templates that are documentation, not real images. + body = cls._FENCE.sub("", body) + cls.urls = cls._HTML_IMG.findall(body) + cls._MD_IMG.findall(body) + + def test_images_found(self): + """Sanity check that the extraction actually matched something.""" + self.assertTrue(self.urls, "no image URLs found in README.md -- extraction is broken") + + def test_no_github_blob_image_urls(self): + for url in self.urls: + if "github.com" in url and "/blob/" in url: + self.fail( + f"README.md image URL serves an HTML page, not an image: {url}\n" + "Use https://raw.githubusercontent.com//// instead." + ) + + if __name__ == "__main__": unittest.main()