Skip to content

Conversation

@andig
Copy link
Member

@andig andig commented Nov 7, 2025

Depends on #25285, #25342

TODO

@andig andig added the infrastructure Basic functionality label Nov 7, 2025
@andig andig changed the title HomeAssistant: add oauth provider HomeAssistant: add auto-discovery Nov 13, 2025
@andig andig requested a review from naltatis November 13, 2025 18:42
@andig andig marked this pull request as ready for review November 13, 2025 18:42
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `util/homeassistant/handler.go:36` </location>
<code_context>
+	jsonWrite(w, slices.Sorted(maps.Keys(instances)))
+}
+
+func (h *handler) Home(w http.ResponseWriter, req *http.Request) {
+	home := req.PathValue("home")
+
</code_context>

<issue_to_address>
**suggestion:** Returning HTTP 400 for unknown home may not be the most appropriate status code.

Consider returning HTTP 404 instead of 400 when instanceByName(home) is nil, as this better indicates the resource was not found.

Suggested implementation:

```golang
func (h *handler) Home(w http.ResponseWriter, req *http.Request) {
	home := req.PathValue("home")

	mu.Lock()
	defer mu.Unlock()

	instance := instanceByName(home)
	if instance == nil {
		http.Error(w, "home not found", http.StatusNotFound)
		return
	}

	// ... rest of the handler logic ...

```

If the handler previously returned HTTP 400 for this case, you should remove or replace that code with the new block above. Also, ensure that `instanceByName` is accessible in this scope and that the rest of the handler logic is executed only if the instance is found.
</issue_to_address>

### Comment 2
<location> `util/homeassistant/handler.go:64-68` </location>
<code_context>
+}
+
+// jsonWrite writes a JSON response
+func jsonWrite(w http.ResponseWriter, data any) {
+	if err := json.NewEncoder(w).Encode(data); err != nil {
+		log.ERROR.Printf("homeassistant: failed to encode JSON: %v", err)
</code_context>

<issue_to_address>
**suggestion:** Consider setting Content-Type header for JSON responses.

Setting the header in jsonWrite will help clients reliably parse the response as JSON.

```suggestion
func jsonWrite(w http.ResponseWriter, data any) {
	w.Header().Set("Content-Type", "application/json")
	if err := json.NewEncoder(w).Encode(data); err != nil {
		log.ERROR.Printf("homeassistant: failed to encode JSON: %v", err)
	}
}
```
</issue_to_address>

### Comment 3
<location> `server/service/registry.go:36` </location>
<code_context>
+	return mux
+}
+
+type handler struct {
+	base string
+}
</code_context>

<issue_to_address>
**issue (complexity):** Consider replacing the custom handler and manual path logic with ServeMux prefix matching and http.StripPrefix for simpler routing.

Using a custom `ServeHTTP` + global registry + manual path‐trimming adds a lot of boilerplate. You can get identical behavior by wiring each registered handler into a sub‐mux with `ServeMux`’s built-in prefix matching and `http.StripPrefix`. For example, drop the `handler` type entirely and replace your `Handler` with:

```go
func Handler(base string) http.Handler {
    mux := http.NewServeMux()

    mu.Lock()
    defer mu.Unlock()
    for name, h := range registry {
        // e.g. "/homes/foo/"
        prefix := fmt.Sprintf("%s/%s/", base, name)

        // strip "/homes/foo" then hand off to h
        mux.Handle(prefix, http.StripPrefix(prefix, h))
    }

    return mux
}
```

Then you can remove:

- the custom `handler` struct
- its `ServeHTTP` + manual `TrimPrefix` call
- the dynamic path‐param logic

All you need is the global `registry` + `Register` and a single loop at startup, no hand‐rolled routing or braces parsing.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@andig
Copy link
Member Author

andig commented Nov 14, 2025

@naltatis network part is finished

@naltatis naltatis self-assigned this Nov 15, 2025
@andig
Copy link
Member Author

andig commented Nov 16, 2025

Doesn't build:

make ui
npm run build

> build
> vite build

vite v7.1.11 building for production...
✓ 27 modules transformed.
✗ Build failed in 628ms
error during build:
[vite]: Rollup failed to resolve import "axios-cache-interceptor" from "/Users/a25058/htdocs/evcc/assets/js/api.ts".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
    at viteLog (file:///Users/a25058/htdocs/evcc/node_modules/vite/dist/node/chunks/config.js:33879:57)
    at onRollupLog (file:///Users/a25058/htdocs/evcc/node_modules/vite/dist/node/chunks/config.js:33909:7)
    at onLog (file:///Users/a25058/htdocs/evcc/node_modules/vite/dist/node/chunks/config.js:33711:4)
    at file:///Users/a25058/htdocs/evcc/node_modules/rollup/dist/es/shared/node-entry.js:20937:32
    at Object.logger [as onLog] (file:///Users/a25058/htdocs/evcc/node_modules/rollup/dist/es/shared/node-entry.js:22823:9)
    at ModuleLoader.handleInvalidResolvedId (file:///Users/a25058/htdocs/evcc/node_modules/rollup/dist/es/shared/node-entry.js:21567:26)
    at file:///Users/a25058/htdocs/evcc/node_modules/rollup/dist/es/shared/node-entry.js:21525:26
make: *** [ui] Error 1

@andig andig added the experimental Experimental feature label Nov 16, 2025
@naltatis
Copy link
Member

@andig neue npm dependency. mach mal make install-ui oder npm ci.

@andig
Copy link
Member Author

andig commented Nov 18, 2025

@naltatis added the /select logic discussed on Slack. Do you see why the tests are failing?

@naltatis
Copy link
Member

Do you see why the tests are failing?

not at first glance. Seems to primarily affect config UI related tests.

@naltatis
Copy link
Member

naltatis commented Nov 18, 2025

@andig seems to be axios-cache-interceptor introduces unexpected behavior. I added it to handle parallel requests to the same endpoint. Let's optimize this specific topic alter and more focused.

This also explains the strange behavior you showed me, where the ui does not show newly created devices.

@naltatis
Copy link
Member

naltatis commented Nov 18, 2025

Finetuned autocomplete/datalist behavior across browsers.

🔽 show dropdown icon if options are available
❎ show clear button if a value is selected
🌈 cross-browser testing (firefox sadly requires double click or keypress before presenting options)
📱 actual option styling varies across browsers and operating systems. mobile optimization builtin. selection and search behavior should be the same everywhere.

example in desktop Safari

Bildschirmaufnahme.2025-11-18.um.17.49.21.webm

example iOS Safari

mobile.webm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

experimental Experimental feature infrastructure Basic functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants