3 Commits
Author SHA1 Message Date
alex 1dea6958c8 Add icon files 2025-12-24 02:09:13 +10:00
alex 5e456e7dd4 Fix AttributeError in OptionsFlow and add loading icon overlay
- Fix BomLocalOptionsFlow AttributeError by using super().__init__() instead of direct assignment
- Add single_config_entry to manifest to enforce single integration instance
- Add YAML config check to prevent UI config when YAML config exists
- Add icon static path registration for /local/community/bom_local/icon.png
- Add loading overlay with animated icon to card
- Bump version to 0.3.0

Fixes #1
2025-12-24 02:04:58 +10:00
alex 9d4d176013 Fix forecastTime to use API metadata instead of current time
- Use metadata.forecastTime from API response instead of endTime in fetchHistoricalFrames
- Ensures forecast time displays correctly in user's browser timezone
- Fixes issue where forecast time was showing incorrect timezone
2025-12-23 21:03:33 +10:00
13 changed files with 58 additions and 8 deletions
+5
View File
@@ -66,6 +66,11 @@ async def _async_setup_integration(hass: HomeAssistant, service_url: str):
"/local/community/bom_local/bom-local-card.js",
hass.config.path("custom_components/bom_local/www/bom-local-card.js"),
True
),
StaticPathConfig(
"/local/community/bom_local/icon.png",
hass.config.path("custom_components/bom_local/icon.png"),
True
)
])
+5 -1
View File
@@ -17,6 +17,10 @@ class BomLocalConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_user(self, user_input=None):
"""Handle the initial step."""
# Check if YAML configuration already exists by checking if component is loaded
if DOMAIN in self.hass.config.components:
return self.async_abort(reason="already_configured")
errors = {}
if user_input is not None:
# We could validate the URL here by trying a fetch
@@ -39,7 +43,7 @@ class BomLocalOptionsFlow(config_entries.OptionsFlow):
"""Handle options flow."""
def __init__(self, config_entry):
self.config_entry = config_entry
super().__init__(config_entry)
async def async_step_init(self, user_input=None):
"""Manage the options."""
Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

+2 -1
View File
@@ -3,8 +3,9 @@
"name": "BOM Local Radar",
"codeowners": ["@alexhopeoconnor"],
"config_flow": true,
"single_config_entry": true,
"iot_class": "local_polling",
"version": "0.2.0",
"version": "0.3.0",
"dependencies": ["http", "websocket_api"],
"documentation": "https://github.com/alexhopeoconnor/bom-local-card",
"issue_tracker": "https://github.com/alexhopeoconnor/bom-local-card/issues"
@@ -1073,7 +1073,7 @@ BomLocalRadarCardEditor = __decorate([
t$1('bom-local-card-editor')
], BomLocalRadarCardEditor);
const CARD_VERSION = '0.2.0';
const CARD_VERSION = '0.3.0';
const DEFAULT_FRAME_INTERVAL = 2.0; // seconds
const DEFAULT_RESTART_DELAY = 2000; // ms (pause before looping)
const DEFAULT_REFRESH_INTERVAL = 30; // seconds
@@ -1300,7 +1300,7 @@ class RadarApiService {
frames: allFrames,
lastUpdated: endTime,
observationTime: metadata.observationTime || (newestCacheFolder === null || newestCacheFolder === void 0 ? void 0 : newestCacheFolder.observationTime) || endTime,
forecastTime: endTime,
forecastTime: metadata.forecastTime || endTime,
weatherStation: metadata.weatherStation,
distance: metadata.distance,
cacheIsValid: (_a = metadata.cacheIsValid) !== null && _a !== void 0 ? _a : true,
@@ -1419,6 +1419,25 @@ const imageStyles = i$3 `
flex-direction: column;
align-items: center;
gap: 12px;
z-index: 10;
}
.loading-icon {
width: 80px;
height: 80px;
animation: pulse 2s ease-in-out infinite;
opacity: 0.8;
}
@keyframes pulse {
0%, 100% {
opacity: 0.8;
transform: scale(1);
}
50% {
opacity: 1;
transform: scale(1.05);
}
}
.loading-message {
@@ -3267,6 +3286,7 @@ let BomLocalRadarCard = class BomLocalRadarCard extends i {
${this.isLoading
? x `
<div class="loading">
<img class="loading-icon" src="/local/community/bom_local/icon.png" alt="BOM Local Radar" />
<ha-circular-progress indeterminate></ha-circular-progress>
<div class="loading-message">Loading radar data...</div>
</div>
+1 -1
View File
@@ -22,7 +22,7 @@ services:
# Application configuration
- CACHEDIRECTORY=/app/cache
- CACHERETENTIONHOURS=24
- TIMEZONE=Australia/Brisbane
- TIMEZONE=Australia/Sydney
# Debug output enabled by default for test environment
- DEBUG__ENABLED=true
- DEBUG__WAITMS=2000
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "bom-local-card",
"version": "0.2.0",
"version": "0.3.0",
"description": "Home Assistant custom card for displaying Australian Bureau of Meteorology (BOM) rain radar data with animated slideshow and historical data support",
"module": "bom-local-card.js",
"keywords": [
+1
View File
@@ -591,6 +591,7 @@ export class BomLocalRadarCard extends LitElement implements LovelaceCard {
${this.isLoading
? html`
<div class="loading">
<img class="loading-icon" src="/local/community/bom_local/icon.png" alt="BOM Local Radar" />
<ha-circular-progress indeterminate></ha-circular-progress>
<div class="loading-message">Loading radar data...</div>
</div>
+1 -1
View File
@@ -1,4 +1,4 @@
export const CARD_VERSION = '0.2.0';
export const CARD_VERSION = '0.3.0';
export const DEFAULT_FRAME_INTERVAL = 2.0; // seconds
export const DEFAULT_RESTART_DELAY = 2000; // ms (pause before looping)
export const DEFAULT_REFRESH_INTERVAL = 30; // seconds
+1 -1
View File
@@ -154,7 +154,7 @@ export class RadarApiService {
frames: allFrames,
lastUpdated: endTime,
observationTime: metadata.observationTime || newestCacheFolder?.observationTime || endTime,
forecastTime: endTime,
forecastTime: metadata.forecastTime || endTime,
weatherStation: metadata.weatherStation,
distance: metadata.distance,
cacheIsValid: metadata.cacheIsValid ?? true,
+19
View File
@@ -72,6 +72,25 @@ export const imageStyles: CSSResultGroup = css`
flex-direction: column;
align-items: center;
gap: 12px;
z-index: 10;
}
.loading-icon {
width: 80px;
height: 80px;
animation: pulse 2s ease-in-out infinite;
opacity: 0.8;
}
@keyframes pulse {
0%, 100% {
opacity: 0.8;
transform: scale(1);
}
50% {
opacity: 1;
transform: scale(1.05);
}
}
.loading-message {