From 14b422da856c9b41489b5d9db35911a66ad9ef1e Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Fri, 22 May 2026 21:43:03 +0200 Subject: [PATCH] Templates: render template-specific modbus defaults in instance mode (#29852) --- util/templates/template_modbus.go | 10 ++-- util/templates/template_modbus_test.go | 73 ++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 util/templates/template_modbus_test.go diff --git a/util/templates/template_modbus.go b/util/templates/template_modbus.go index 5d4c81aa8..72b523486 100644 --- a/util/templates/template_modbus.go +++ b/util/templates/template_modbus.go @@ -93,13 +93,13 @@ func (t *Template) ModbusValues(renderMode int, values map[string]any) { } if defaultValue != "" { - // for modbus params the default value is carried - // using the parameter default, not the value - // TODO figure out why that's necessary + // apply the template-specific default to both the render values + // (so RenderModeInstance YAML reflects it) and the param definition + // (so the Config UI surfaces it as default). The earlier guard above + // ensures user-supplied values are not overwritten. + values[p.Name] = defaultValue if renderMode == RenderModeInstance { t.SetParamDefault(p.Name, defaultValue) - } else { - values[p.Name] = defaultValue } } } diff --git a/util/templates/template_modbus_test.go b/util/templates/template_modbus_test.go new file mode 100644 index 000000000..3c446f4a2 --- /dev/null +++ b/util/templates/template_modbus_test.go @@ -0,0 +1,73 @@ +package templates + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var renderModeNames = map[int]string{ + RenderModeInstance: "instance", + RenderModeDocs: "docs", + RenderModeUnitTest: "unittest", +} + +// TestModbusTemplateDefaultID verifies that a template-specific modbus id +// (e.g. Wallbe/Phoenix controllers using id 255) is rendered into the resulting +// instance config when the user did not supply an explicit id. See #29804. +func TestModbusTemplateDefaultID(t *testing.T) { + for _, mode := range []int{RenderModeInstance, RenderModeDocs, RenderModeUnitTest} { + t.Run(renderModeNames[mode], func(t *testing.T) { + tmpl, err := ByName(Charger, "phoenix-ev-eth") + require.NoError(t, err) + + _, values, err := tmpl.RenderResult(mode, map[string]any{ + "host": "192.168.0.8", + "port": 502, + }) + require.NoError(t, err) + assert.Equal(t, "255", values["id"], "template-specific modbus id must be applied") + }) + } +} + +// TestModbusTemplateUserIDOverridesTemplate ensures a user-supplied id wins +// over the template default in all render modes. +func TestModbusTemplateUserIDOverridesTemplate(t *testing.T) { + for _, mode := range []int{RenderModeInstance, RenderModeDocs, RenderModeUnitTest} { + t.Run(renderModeNames[mode], func(t *testing.T) { + tmpl, err := ByName(Charger, "phoenix-ev-eth") + require.NoError(t, err) + + _, values, err := tmpl.RenderResult(mode, map[string]any{ + "host": "192.168.0.8", + "port": 502, + "id": 42, + }) + require.NoError(t, err) + assert.Equal(t, "42", values["id"], "user-supplied modbus id must not be overwritten") + }) + } +} + +// TestWallbeTemplateCoveredByPhoenix verifies the BC migration: a config that +// still references the removed `wallbe` templates is transparently routed to +// the phoenix-ev-eth template via the `covers:` directive, while still +// producing the Wallbe controller's modbus slave id 255. +func TestWallbeTemplateCoveredByPhoenix(t *testing.T) { + for _, name := range []string{"wallbe", "wallbe-meter", "wallbe-pre2019", "wallbe-pre2019-meter"} { + t.Run(name, func(t *testing.T) { + tmpl, err := ByName(Charger, name) + require.NoError(t, err) + assert.Equal(t, "phoenix-ev-eth", tmpl.Template) + + _, values, err := tmpl.RenderResult(RenderModeInstance, map[string]any{ + "host": "192.168.0.8", + "port": 502, + }) + require.NoError(t, err) + assert.Equal(t, "255", values["id"]) + }) + } +}