Config UI: fix preserving modbus fields (#25029)
This commit is contained in:
parent
6591514456
commit
2a0429aa76
5 changed files with 119 additions and 19 deletions
|
|
@ -110,12 +110,21 @@ func templateForConfig(class templates.Class, conf map[string]any) (templates.Te
|
|||
func filterValidTemplateParams(tmpl *templates.Template, conf map[string]any) map[string]any {
|
||||
res := make(map[string]any)
|
||||
|
||||
// check if template has modbus capability
|
||||
hasModbus := len(tmpl.ModbusChoices()) > 0
|
||||
|
||||
for k, v := range conf {
|
||||
if k == "template" {
|
||||
res[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
// preserve modbus fields if template supports modbus
|
||||
if hasModbus && slices.Contains(templates.ModbusParams, k) {
|
||||
res[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
if i, _ := tmpl.ParamByName(k); i >= 0 {
|
||||
res[k] = v
|
||||
}
|
||||
|
|
|
|||
57
tests/config-modbus-fields.spec.ts
Normal file
57
tests/config-modbus-fields.spec.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { test, expect, type Page, type Locator } from "@playwright/test";
|
||||
import { start, stop, baseUrl } from "./evcc";
|
||||
import { expectModalVisible, enableExperimental } from "./utils";
|
||||
|
||||
const CONFIG_MODBUS_FIELDS = "config-modbus-fields.sql";
|
||||
|
||||
test.use({ baseURL: baseUrl() });
|
||||
|
||||
test.beforeAll(async () => {
|
||||
await start(undefined, CONFIG_MODBUS_FIELDS);
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await stop();
|
||||
});
|
||||
|
||||
async function openMeterModal(page: Page, title: string): Promise<Locator> {
|
||||
await page.goto("/#/config");
|
||||
await enableExperimental(page, true);
|
||||
await page
|
||||
.getByTestId("pv")
|
||||
.filter({ hasText: title })
|
||||
.getByRole("button", { name: "edit" })
|
||||
.click();
|
||||
const modal = page.getByTestId("meter-modal");
|
||||
await expectModalVisible(modal);
|
||||
return modal;
|
||||
}
|
||||
|
||||
test.describe("modbus fields", async () => {
|
||||
test("tcpip", async ({ page }) => {
|
||||
const modal = await openMeterModal(page, "TCP Test");
|
||||
await expect(page.getByLabel("Network")).toBeChecked();
|
||||
await expect(page.getByLabel("TCP")).toBeChecked();
|
||||
await expect(modal.getByLabel("IP address or hostname")).toHaveValue("192.168.1.10");
|
||||
await expect(modal.getByLabel("Port", { exact: true })).toHaveValue("5020");
|
||||
await expect(modal.getByLabel("Modbus ID")).toHaveValue("10");
|
||||
});
|
||||
|
||||
test("rs485tcpip", async ({ page }) => {
|
||||
const modal = await openMeterModal(page, "RTU/IP Test");
|
||||
await expect(page.getByLabel("Network")).toBeChecked();
|
||||
await expect(page.getByLabel("RTU")).toBeChecked();
|
||||
await expect(modal.getByLabel("IP address or hostname")).toHaveValue("192.168.1.20");
|
||||
await expect(modal.getByLabel("Port", { exact: true })).toHaveValue("8899");
|
||||
await expect(modal.getByLabel("Modbus ID")).toHaveValue("20");
|
||||
});
|
||||
|
||||
test("rs485serial", async ({ page }) => {
|
||||
const modal = await openMeterModal(page, "Serial Test");
|
||||
await expect(page.getByLabel("Serial / USB")).toBeChecked();
|
||||
await expect(modal.getByLabel("Device name")).toHaveValue("/dev/ttyUSB5");
|
||||
await expect(modal.getByLabel("Baud rate")).toHaveValue("19200");
|
||||
await expect(modal.getByLabel("ComSet")).toHaveValue("8E1");
|
||||
await expect(modal.getByLabel("Modbus ID")).toHaveValue("30");
|
||||
});
|
||||
});
|
||||
24
tests/config-modbus-fields.sql
Normal file
24
tests/config-modbus-fields.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
BEGIN;
|
||||
|
||||
CREATE TABLE `configs` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT
|
||||
, `class` integer
|
||||
, `type` text
|
||||
, `title` text
|
||||
, `icon` text
|
||||
, `product` text
|
||||
, `value` text
|
||||
);
|
||||
CREATE TABLE `settings` (
|
||||
`key` text
|
||||
, `value` text
|
||||
, PRIMARY KEY(`key`)
|
||||
);
|
||||
|
||||
INSERT INTO configs(id, class, type, title, icon, product, value) VALUES(1, 2, 'template', 'TCP Test', '', 'SunSpec Inverter', '{"host":"192.168.1.10","id":10,"modbus":"tcpip","port":5020,"template":"sunspec-inverter","usage":"pv"}');
|
||||
INSERT INTO configs(id, class, type, title, icon, product, value) VALUES(2, 2, 'template', 'RTU/IP Test', '', 'SunSpec Inverter', '{"host":"192.168.1.20","id":20,"modbus":"rs485tcpip","port":8899,"template":"sunspec-inverter","usage":"pv"}');
|
||||
INSERT INTO configs(id, class, type, title, icon, product, value) VALUES(3, 2, 'template', 'Serial Test', '', 'SunSpec Inverter', '{"baudrate":19200,"comset":"8E1","device":"/dev/ttyUSB5","id":30,"modbus":"rs485serial","template":"sunspec-inverter","usage":"pv"}');
|
||||
|
||||
INSERT INTO settings("key", value) VALUES('pvMeters', 'db:1,db:2,db:3');
|
||||
|
||||
COMMIT;
|
||||
|
|
@ -74,19 +74,19 @@ func (t *Template) ModbusValues(renderMode int, values map[string]any) {
|
|||
var defaultValue string
|
||||
|
||||
switch p.Name {
|
||||
case ModbusParamNameId:
|
||||
case ModbusParamId:
|
||||
if modbusParam.ID != 0 {
|
||||
defaultValue = strconv.Itoa(modbusParam.ID)
|
||||
}
|
||||
case ModbusParamNamePort:
|
||||
case ModbusParamPort:
|
||||
if modbusParam.Port != 0 {
|
||||
defaultValue = strconv.Itoa(modbusParam.Port)
|
||||
}
|
||||
case ModbusParamNameBaudrate:
|
||||
case ModbusParamBaudrate:
|
||||
if modbusParam.Baudrate != 0 {
|
||||
defaultValue = strconv.Itoa(modbusParam.Baudrate)
|
||||
}
|
||||
case ModbusParamNameComset:
|
||||
case ModbusParamComset:
|
||||
if modbusParam.Comset != "" {
|
||||
defaultValue = modbusParam.Comset
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,14 +25,14 @@ const (
|
|||
ModbusKeyTCPIP = "tcpip"
|
||||
ModbusKeyUDP = "udp"
|
||||
|
||||
ModbusParamNameId = "id"
|
||||
ModbusParamNameDevice = "device"
|
||||
ModbusParamNameBaudrate = "baudrate"
|
||||
ModbusParamNameComset = "comset"
|
||||
ModbusParamNameURI = "uri"
|
||||
ModbusParamNameHost = "host"
|
||||
ModbusParamNamePort = "port"
|
||||
ModbusParamNameRTU = "rtu"
|
||||
ModbusParamId = "id"
|
||||
ModbusParamDevice = "device"
|
||||
ModbusParamBaudrate = "baudrate"
|
||||
ModbusParamComset = "comset"
|
||||
ModbusParamURI = "uri"
|
||||
ModbusParamHost = "host"
|
||||
ModbusParamPort = "port"
|
||||
ModbusParamRTU = "rtu"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -41,7 +41,19 @@ const (
|
|||
RenderModeInstance
|
||||
)
|
||||
|
||||
var ValidModbusChoices = []string{ModbusChoiceRS485, ModbusChoiceTCPIP, ModbusChoiceUDP}
|
||||
var (
|
||||
ValidModbusChoices = []string{ModbusChoiceRS485, ModbusChoiceTCPIP, ModbusChoiceUDP}
|
||||
|
||||
// ModbusParams contains all field names used by modbus templates
|
||||
ModbusParams = []string{
|
||||
ModbusParamId, ModbusParamDevice, ModbusParamBaudrate, ModbusParamComset,
|
||||
ModbusParamURI, ModbusParamHost, ModbusParamPort, ModbusParamRTU,
|
||||
}
|
||||
|
||||
ModbusConnectionTypes = []string{
|
||||
ModbusKeyTCPIP, ModbusKeyUDP, ModbusKeyRS485Serial, ModbusKeyRS485TCPIP,
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
CapabilityISO151182 = "iso151182" // ISO 15118-2 support
|
||||
|
|
@ -63,12 +75,10 @@ const (
|
|||
|
||||
var ValidRequirements = []string{RequirementEEBUS, RequirementMQTT, RequirementSponsorship, RequirementSkipTest}
|
||||
|
||||
var predefinedTemplateProperties = []string{
|
||||
"type", "template", "name",
|
||||
ModbusParamNameId, ModbusParamNameDevice, ModbusParamNameBaudrate, ModbusParamNameComset,
|
||||
ModbusParamNameURI, ModbusParamNameHost, ModbusParamNamePort, ModbusParamNameRTU,
|
||||
ModbusKeyTCPIP, ModbusKeyUDP, ModbusKeyRS485Serial, ModbusKeyRS485TCPIP,
|
||||
}
|
||||
var predefinedTemplateProperties = append(
|
||||
[]string{"type", "template", "name"},
|
||||
append(ModbusParams, ModbusConnectionTypes...)...,
|
||||
)
|
||||
|
||||
// TextLanguage contains language-specific texts
|
||||
type TextLanguage struct {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue