@@ -108,6 +108,14 @@ function App() {
108108 * consecutive failures before the user is told about it.
109109 */
110110 const [ controlError , setControlError ] = useState < string | null > ( null )
111+ const [ updateRequested , setUpdateRequested ] = useState ( false )
112+
113+ useEffect ( ( ) => {
114+ if ( ! updateRequested ) return
115+
116+ const timeout = window . setTimeout ( ( ) => setUpdateRequested ( false ) , 15_000 )
117+ return ( ) => window . clearTimeout ( timeout )
118+ } , [ updateRequested ] )
111119
112120 /*
113121 * Consecutive failure count for each endpoint.
@@ -238,6 +246,7 @@ function App() {
238246 previousCalculatingRef . current = data . calculating
239247
240248 setStatusData ( data )
249+ if ( data . updating ) setUpdateRequested ( false )
241250
242251 /*
243252 * Predbat has just completed a calculation.
@@ -317,6 +326,36 @@ function App() {
317326 } )
318327 }
319328
329+ async function installLatestUpdate ( ) {
330+ setUpdateRequested ( true )
331+
332+ try {
333+ const response = await fetch ( './api/service' , {
334+ method : 'POST' ,
335+ headers : { 'Content-Type' : 'application/json' } ,
336+ body : JSON . stringify ( {
337+ service : 'update/install' ,
338+ data : { entity_id : 'update.predbat_version' }
339+ } )
340+ } )
341+
342+ if ( ! response . ok ) throw new Error ( `HTTP ${ response . status } ` )
343+
344+ const result = await response . json ( ) as { result ?: unknown } | null
345+ if ( result ?. result === 'error' ) throw new Error ( 'Home Assistant rejected the update request' )
346+
347+ setControlError ( null )
348+ fetchStatus ( ) . catch ( ( ) => {
349+ // Polling will retry if Predbat restarts before returning status.
350+ } )
351+ } catch ( error ) {
352+ console . error ( 'Unable to start the Predbat update:' , error )
353+ const detail = error instanceof Error ? error . message : 'Unknown error'
354+ setControlError ( `Predbat could not start the update. ${ detail } ` )
355+ setUpdateRequested ( false )
356+ }
357+ }
358+
320359 /*
321360 * Manual retry used by the error notice.
322361 */
@@ -569,6 +608,9 @@ function App() {
569608 status = { statusData . status }
570609 mode = { statusData . mode }
571610 version = { statusData . version }
611+ latestVersion = { statusData . latest_version }
612+ updateAvailable = { statusData . update_available }
613+ updating = { updating || updateRequested }
572614 lastUpdated = { statusData . last_updated }
573615 configOk = { statusData . config_ok }
574616
@@ -583,6 +625,8 @@ function App() {
583625 onReadOnlyChange = { ( value ) => updateControl ( 'set_read_only' , value ) }
584626
585627 onDebugChange = { ( value ) => updateControl ( 'debug_enable' , value ) }
628+
629+ onUpdate = { installLatestUpdate }
586630 />
587631
588632 < PlanSummary plan = { planData . plan } />
0 commit comments