Skip to content

Home Assistant App (add-on) changes #1305

Open
roflcoopter wants to merge 5 commits intomasterfrom
feature/hass-app-test
Open

Home Assistant App (add-on) changes #1305
roflcoopter wants to merge 5 commits intomasterfrom
feature/hass-app-test

Conversation

@roflcoopter
Copy link
Copy Markdown
Owner

First draft of the needed changes to get Viseron running as a Home Assistant App

MJPEG streaming is not working yet, need to figure that one out still.

Closes #576

Copilot AI review requested due to automatic review settings March 30, 2026 16:39
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 30, 2026

Deploy Preview for viseron canceled.

Name Link
🔨 Latest commit 9d9f3c2
🔍 Latest deploy log https://app.netlify.com/projects/viseron/deploys/69d3c47224d4e50008cda591

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR is a first draft of changes aimed at running Viseron as a Home Assistant add-on/app, with particular focus on Home Assistant Ingress/subpath compatibility across backend redirects/URL generation, frontend API base paths, and the nginx proxy layer.

Changes:

  • Add Ingress-aware subpath handling in the Tornado request handler and use it for file redirects.
  • Update nginx to forward the ingress header, inject a frontend window.baseUrl, and tweak MJPEG proxying (disable buffering/gzip).
  • Add container init logic to symlink media directories into /data for simpler volume mapping; update frontend API client base path detection.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
viseron/components/webserver/tiered_file_handler.py Uses computed subpath when redirecting to /files/... to support ingress/subpaths.
viseron/components/webserver/request_handler.py Adds ingress-header-aware get_subpath() and minor formatting changes.
rootfs/usr/local/nginx/conf/proxy.conf Forwards X-Ingress-Path header to backend.
rootfs/usr/local/nginx/conf/nginx.conf Injects window.baseUrl based on ingress header; disables buffering/gzip for MJPEG endpoints.
rootfs/etc/cont-init.d/10-adduser Attempts to symlink media directories into /data for Home Assistant add-on volume usage.
frontend/src/lib/api/client.ts Uses injected window.baseUrl (if present) for API base path selection.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +16 to +19
# Create symlink only if it doesn't already exist
if [ ! -L "/${folder}" ]; then
ln -s "/data/${folder}" "/${folder}"
fi
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Symlink creation only checks -L and will fail for folders that already exist as real directories. /segments is created during image build (see docker/Dockerfile), so ln -s will error and leave /segments pointing at the container filesystem instead of /data/segments, undermining the “single volume mapping” goal. Handle the “directory exists” case (eg, migrate contents to /data/segments and replace it with a symlink, or skip with a clear log + ensure the app writes to /data).

Suggested change
# Create symlink only if it doesn't already exist
if [ ! -L "/${folder}" ]; then
ln -s "/data/${folder}" "/${folder}"
fi
target="/${folder}"
data_target="/data/${folder}"
# If target is already a symlink, leave it as is
if [ -L "${target}" ]; then
continue
fi
# If target is an existing real directory, migrate contents then replace with a symlink
if [ -d "${target}" ]; then
if [ "$(ls -A "${target}" 2>/dev/null)" ]; then
log_info "Migrating existing contents from ${target} to ${data_target}"
mv "${target}"/* "${data_target}/" 2>/dev/null || :
mv "${target}"/.[!.]* "${data_target}/" 2>/dev/null || :
mv "${target}"/..?* "${data_target}/" 2>/dev/null || :
fi
if ! rmdir "${target}" 2>/dev/null; then
log_warn "Could not remove existing directory ${target}; skipping symlink creation"
continue
fi
elif [ -e "${target}" ]; then
log_warn "Path ${target} exists and is not a directory or symlink; skipping symlink creation"
continue
fi
ln -s "${data_target}" "${target}"

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 31, 2026 08:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +8 to +9
if ((window as any).baseUrl) {
const base = (window as any).baseUrl as string;
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using (window as any).baseUrl bypasses type-safety. Consider adding a declare global { interface Window { baseUrl?: string } } in an appropriate .d.ts (eg vite-env.d.ts) and then using window.baseUrl here, so this stays typed and discoverable.

Suggested change
if ((window as any).baseUrl) {
const base = (window as any).baseUrl as string;
const win = window as Window & { baseUrl?: string };
if (typeof win.baseUrl === "string" && win.baseUrl.length > 0) {
const base = win.baseUrl;

Copilot uses AI. Check for mistakes.
@roflcoopter roflcoopter force-pushed the feature/hass-app-test branch from c47d3bc to 1b09097 Compare April 4, 2026 10:23
Copilot AI review requested due to automatic review settings April 6, 2026 14:34
@roflcoopter roflcoopter changed the base branch from dev to master April 6, 2026 14:35
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +24 to +31
const prevSrcRef = useRef<string>(src);

// Reset state synchronously during render when src changes
if (prevSrcRef.current !== src) {
prevSrcRef.current = src;
if (error !== null) setError(null);
if (!isLoading) setIsLoading(true);
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hook calls setError/setIsLoading during render when src changes (lines 27-31). React state updates during render can trigger warnings (“cannot update a component while rendering”) and can cause unexpected re-render loops. Move this reset logic into an effect keyed on src (or derive state from src) instead of mutating state during render.

Suggested change
const prevSrcRef = useRef<string>(src);
// Reset state synchronously during render when src changes
if (prevSrcRef.current !== src) {
prevSrcRef.current = src;
if (error !== null) setError(null);
if (!isLoading) setIsLoading(true);
}
useEffect(() => {
setError(null);
setIsLoading(true);
}, [src]);

Copilot uses AI. Check for mistakes.
firstFrame = false;
setIsLoading(false);
}
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the stream ends/terminates without yielding any multipart parts, firstFrame stays true and isLoading is never set to false, leaving the UI spinner up indefinitely with no error. After the for await loop completes, ensure you set isLoading false (and preferably set an error) when no frames were received.

Suggested change
}
}
if (!cancelled && firstFrame) {
setError("MJPEG stream ended before any frames were received.");
setIsLoading(false);
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Home assistant addon

2 participants