diff --git a/cmd/configure/devicetest.go b/cmd/configure/devicetest.go index 0662385a4..5ffeebbe6 100644 --- a/cmd/configure/devicetest.go +++ b/cmd/configure/devicetest.go @@ -84,7 +84,7 @@ func (d *DeviceTest) testCharger(v interface{}) (DeviceTestResult, error) { return DeviceTestResultInvalid, err } } else { - return DeviceTestResultInvalid, errors.New("Selected device is not a wallbox!") + return DeviceTestResultInvalid, errors.New("selected device is not a wallbox!") } if v, ok := v.(api.Meter); ok { @@ -116,11 +116,11 @@ func (d *DeviceTest) testMeter(deviceCategory DeviceCategory, v interface{}) (De return DeviceTestResultInvalid, err } } else { - return DeviceTestResultInvalid, errors.New("Selected device is not a battery meter!") + return DeviceTestResultInvalid, errors.New("selected device is not a battery meter!") } } } else { - return DeviceTestResultInvalid, errors.New("Selected device is not a meter!") + return DeviceTestResultInvalid, errors.New("selected device is not a meter!") } return DeviceTestResultValid, nil @@ -135,7 +135,7 @@ func (d *DeviceTest) testVehicle(v interface{}) (DeviceTestResult, error) { } } } else { - return DeviceTestResultInvalid, errors.New("Selected device is not a vehicle!") + return DeviceTestResultInvalid, errors.New("selected device is not a vehicle!") } return DeviceTestResultValid, nil diff --git a/cmd/configure/flow.go b/cmd/configure/flow.go index 0737d4f83..300846676 100644 --- a/cmd/configure/flow.go +++ b/cmd/configure/flow.go @@ -96,51 +96,89 @@ func (c *CmdConfigure) configureDeviceGuidedSetup() { func (c *CmdConfigure) configureLinkedTypes(templateItem templates.Template) { linkedTemplates := templateItem.GuidedSetup.Linked + deviceOfTemplateAdded := make(map[string]bool) + if linkedTemplates == nil { return } for _, linkedTemplate := range linkedTemplates { + if linkedTemplate.ExcludeTemplate != "" { + // don't process this linked template if a referenced exclude template was added + if deviceOfTemplateAdded[linkedTemplate.ExcludeTemplate] { + continue + } + } + + linkedTemplateItem, err := templates.ByTemplate(linkedTemplate.Template, string(DeviceClassMeter)) + if err != nil { + fmt.Println("Error: " + err.Error()) + return + } + if len(linkedTemplateItem.Params) == 0 || linkedTemplate.Usage == "" { + break + } + + category := DeviceCategory(linkedTemplate.Usage) + + localizeMap := localizeMap{ + "Linked": linkedTemplateItem.Description, + "Article": DeviceCategories[category].article, + "Additional": DeviceCategories[category].additional, + "Category": DeviceCategories[category].title, + } + + fmt.Println() + if !c.askYesNo(c.localizedString("AddLinkedDeviceInCategory", localizeMap)) { + continue + } + for ok := true; ok; { - deviceItem := device{} - - linkedTemplateItem, err := templates.ByTemplate(linkedTemplate.Template, string(DeviceClassMeter)) - if err != nil { - fmt.Println("Error: " + err.Error()) - return - } - if len(linkedTemplateItem.Params) == 0 || linkedTemplate.Usage == "" { - return + if added := c.configureLinkedTemplate(linkedTemplateItem, category); added { + deviceOfTemplateAdded[linkedTemplate.Template] = true } - category := DeviceCategory(linkedTemplate.Usage) - - fmt.Println() - if !c.askYesNo(c.localizedString("AddLinkedDeviceInCategory", localizeMap{"Linked": linkedTemplateItem.Description, "Article": DeviceCategories[category].article, "Category": DeviceCategories[category].title})) { + if !linkedTemplate.Multiple { break } - values := c.processConfig(linkedTemplateItem.Params, category) - deviceItem, err = c.processDeviceValues(values, linkedTemplateItem, deviceItem, category) - if err != nil { - if !errors.Is(err, c.errDeviceNotValid) { - fmt.Println() - fmt.Println(err) - } - fmt.Println() - if c.askConfigFailureNextStep() { - continue - } - - } else { - c.configuration.AddDevice(deviceItem, category) - - fmt.Println() - fmt.Println(linkedTemplateItem.Description + " " + c.localizedString("Device_Added", nil)) + fmt.Println() + if !c.askYesNo(c.localizedString("AddAnotherLinkedDeviceInCategory", localizeMap)) { + break } - break } } + fmt.Println("DONE") +} + +// configureLinkedTemplate lets the user configure a device that is marked as being linked to a guided device +// returns true if a device was added +func (c *CmdConfigure) configureLinkedTemplate(template templates.Template, category DeviceCategory) bool { + for ok := true; ok; { + deviceItem := device{} + + values := c.processConfig(template.Params, category) + deviceItem, err := c.processDeviceValues(values, template, deviceItem, category) + if err != nil { + if !errors.Is(err, c.errDeviceNotValid) { + fmt.Println() + fmt.Println(err) + } + fmt.Println() + if c.askConfigFailureNextStep() { + continue + } + + } else { + c.configuration.AddDevice(deviceItem, category) + + fmt.Println() + fmt.Println(template.Description + " " + c.localizedString("Device_Added", nil)) + return true + } + break + } + return false } // configureDeviceCategory lets the user select and configure a device from a specific category diff --git a/cmd/configure/localization/de.toml b/cmd/configure/localization/de.toml index 306c258a6..4dceba78b 100644 --- a/cmd/configure/localization/de.toml +++ b/cmd/configure/localization/de.toml @@ -15,7 +15,8 @@ ItemNotPresent = "Mein Gerät ist nicht in der Liste" AddDeviceInCategory = "Möchtest du {{ .Article }} {{ .Category }} hinzufügen?" AddAnotherDeviceInCategory = "Möchtest du noch {{ .Additional }} {{ .Category }} hinzufügen?" -AddLinkedDeviceInCategory = "Möchtest du '{{ .Linked }}' als {{ .Article }} {{ .Category }} hinzufügen?" +AddLinkedDeviceInCategory = "Möchtest du ein '{{ .Linked }}' Gerät als {{ .Article }} {{ .Category }} hinzufügen?" +AddAnotherLinkedDeviceInCategory = "Möchtest du noch ein '{{ .Linked }}' Gerät als {{ .Article }} {{ .Category }} hinzufügen?" Error = "Fehler: {{ .Error }}" Error_ItemNotPresent = "Gerät nicht vorhanden" diff --git a/cmd/configure/localization/en.toml b/cmd/configure/localization/en.toml index 65bcdc2b6..3807a5a87 100644 --- a/cmd/configure/localization/en.toml +++ b/cmd/configure/localization/en.toml @@ -15,7 +15,8 @@ ItemNotPresent = "My device is not in this list" AddDeviceInCategory = "Do you want to add {{ .Article }} {{ .Category }}?" AddAnotherDeviceInCategory = "Do you want to add {{ .Additional }} {{ .Category }}?" -AddLinkedDeviceInCategory = "Do you want to add '{{ .Linked }}' as {{ .Article }} {{ .Category }}?" +AddLinkedDeviceInCategory = "Do you want to add a '{{ .Linked }}' device as {{ .Article }} {{ .Category }}?" +AddAnotherLinkedDeviceInCategory = "Do you want to add another '{{ .Linked }}' device as {{ .Article }} {{ .Category }}?" Error = "Error: {{ .Error }}" Error_ItemNotPresent = "Device not present" diff --git a/templates/README.md b/templates/README.md index 161135ab8..162b75d86 100644 --- a/templates/README.md +++ b/templates/README.md @@ -50,6 +50,16 @@ Allows to define a list of meter devices that are typically installed with this - `pv`: for pv inverter/meter - `battery`: for battery inverter/meter +#### `multiple` + +`multiple:true` to define that multiple devices of this template can be added + +#### `excludetemplate` + +`excludetemplate` defines a linked device `template` value. If defined and a device of the linked template is added, then this linked template won't be considered in the flow + +Example Use Case: With SMA Home Manager, there can be a SMA Energy Meter used for getting the PV generation or multiple SMA PV inverters. But never both together. So if the used added an SMA Energy Meter, then the flow shoudn't ask for SMA PV inverters. + ## `requirements` `requirements` provides an option to define various requirements / dependencies that need to be setup diff --git a/templates/definition/charger/nrgkick-bluetooth.yaml b/templates/definition/charger/nrgkick-bluetooth.yaml index 9f5db6836..17e2b1f95 100644 --- a/templates/definition/charger/nrgkick-bluetooth.yaml +++ b/templates/definition/charger/nrgkick-bluetooth.yaml @@ -5,6 +5,7 @@ params: required: true - name: pin required: true + mask: true render: | type: nrgkick-bluetooth mac: {{ .mac }} diff --git a/templates/definition/charger/tinkerforge-warp-pro.yaml b/templates/definition/charger/tinkerforge-warp-pro.yaml index 4844343d5..bf1973d09 100644 --- a/templates/definition/charger/tinkerforge-warp-pro.yaml +++ b/templates/definition/charger/tinkerforge-warp-pro.yaml @@ -9,8 +9,14 @@ params: - name: host required: true example: 192.0.2.2 + help: + de: Die IP Adresse oder der Hostname des MQTT Brokers + en: The IP address or hostname of the MQTT broker - name: port default: 1883 + help: + de: Der Port des MQTT Brokers + en: The port of the MQTT broker - name: topic default: warp - name: timeout diff --git a/templates/definition/charger/tinkerforge-warp.yaml b/templates/definition/charger/tinkerforge-warp.yaml index af111caf2..d8476ca2f 100644 --- a/templates/definition/charger/tinkerforge-warp.yaml +++ b/templates/definition/charger/tinkerforge-warp.yaml @@ -9,8 +9,14 @@ params: - name: host required: true example: 192.0.2.2 + help: + de: Die IP Adresse oder der Hostname des MQTT Brokers + en: The IP address or hostname of the MQTT broker - name: port default: 1883 + help: + de: Der Port des MQTT Brokers + en: The port of the MQTT broker - name: topic default: warp - name: timeout diff --git a/templates/definition/meter/powerfox-poweropti.yaml b/templates/definition/meter/powerfox-poweropti.yaml index 5f03aba7b..13c07991c 100644 --- a/templates/definition/meter/powerfox-poweropti.yaml +++ b/templates/definition/meter/powerfox-poweropti.yaml @@ -7,6 +7,7 @@ params: required: true - name: password required: true + mask: true render: | type: custom power: diff --git a/templates/definition/meter/sma-homemanager.yaml b/templates/definition/meter/sma-homemanager.yaml index a3559627e..e185e365d 100644 --- a/templates/definition/meter/sma-homemanager.yaml +++ b/templates/definition/meter/sma-homemanager.yaml @@ -9,8 +9,11 @@ guidedsetup: usage: pv - template: sma-inverter usage: pv + multiple: true + excludetemplate: sma-energy-meter - template: sma-inverter usage: battery + multiple: true params: - name: usage choice: ["grid"] diff --git a/templates/definition/vehicle/fiat.yaml b/templates/definition/vehicle/fiat.yaml index cc2f986a4..57ff40195 100644 --- a/templates/definition/vehicle/fiat.yaml +++ b/templates/definition/vehicle/fiat.yaml @@ -3,6 +3,7 @@ description: Fiat paramsbase: vehicle params: - name: pin + mask: true - name: vin example: ZFAE... - name: capacity diff --git a/templates/docs/charger/tinkerforge-warp-pro.yaml b/templates/docs/charger/tinkerforge-warp-pro.yaml index 26a1881da..41e1e8d90 100644 --- a/templates/docs/charger/tinkerforge-warp-pro.yaml +++ b/templates/docs/charger/tinkerforge-warp-pro.yaml @@ -1,7 +1,7 @@ type: template template: tinkerforge-warp-pro description: TinkerForge WARP Charger Pro -host: 192.0.2.2 -port: 1883 +host: 192.0.2.2 # Die IP Adresse oder der Hostname des MQTT Brokers +port: 1883 # Der Port des MQTT Brokers topic: warp timeout: 30s \ No newline at end of file diff --git a/templates/docs/charger/tinkerforge-warp.yaml b/templates/docs/charger/tinkerforge-warp.yaml index 1e120a1a5..db4b2b403 100644 --- a/templates/docs/charger/tinkerforge-warp.yaml +++ b/templates/docs/charger/tinkerforge-warp.yaml @@ -1,7 +1,7 @@ type: template template: tinkerforge-warp description: TinkerForge WARP Charger -host: 192.0.2.2 -port: 1883 +host: 192.0.2.2 # Die IP Adresse oder der Hostname des MQTT Brokers +port: 1883 # Der Port des MQTT Brokers topic: warp timeout: 30s \ No newline at end of file diff --git a/util/templates/template.go b/util/templates/template.go index b1b7673c4..8848ab0b7 100644 --- a/util/templates/template.go +++ b/util/templates/template.go @@ -100,8 +100,10 @@ type GuidedSetup struct { // Linked Template type LinkedTemplate struct { - Template string - Usage string // usage: "grid", "pv", "battery" + Template string + Usage string // usage: "grid", "pv", "battery" + Multiple bool // if true, multiple instances of this template can be added + ExcludeTemplate string // only consider this if no device of the named linked template was added } // Param is a proxy template parameter