diff --git a/charger/template.go b/charger/template.go index 61438432f..67b57c5dd 100644 --- a/charger/template.go +++ b/charger/template.go @@ -26,7 +26,7 @@ func NewChargerFromTemplateConfig(other map[string]interface{}) (api.Charger, er return nil, err } - b, _, err := tmpl.RenderResult(false, other) + b, _, err := tmpl.RenderResult(templates.TemplateRenderModeInstance, other) if err != nil { return nil, err } diff --git a/charger/template_test.go b/charger/template_test.go index 3deda1155..4cb60e106 100644 --- a/charger/template_test.go +++ b/charger/template_test.go @@ -35,7 +35,7 @@ func TestChargerTemplates(t *testing.T) { tmpl := tmpl // set default values for all params - values := tmpl.Defaults(true) + values := tmpl.Defaults(templates.TemplateRenderModeUnitTest) // set the template value which is needed for rendering values["template"] = tmpl.Template @@ -43,6 +43,7 @@ func TestChargerTemplates(t *testing.T) { // set modbus default test values if values[templates.ParamModbus] != nil { modbusChoices := tmpl.ModbusChoices() + // we only test one modbus setup if funk.ContainsString(modbusChoices, templates.ModbusChoiceTCPIP) { values[templates.ModbusTCPIP] = true } else { @@ -53,15 +54,17 @@ func TestChargerTemplates(t *testing.T) { t.Run(tmpl.Template, func(t *testing.T) { t.Parallel() - b, values, err := tmpl.RenderResult(true, values) + b, values, err := tmpl.RenderResult(templates.TemplateRenderModeUnitTest, values) if err != nil { - t.Logf("%s: %s", tmpl.Template, b) + t.Logf("Template: %s", tmpl.Template) + t.Logf("%s", string(b)) t.Error(err) } _, err = NewFromConfig("template", values) if err != nil && !test.Acceptable(err, acceptable) { - t.Logf("%s", tmpl.Template) + t.Logf("Template: %s", tmpl.Template) + t.Logf("%s", string(b)) t.Error(err) } }) diff --git a/cmd/configure/configure.go b/cmd/configure/configure.go index d8f35c622..a3bdcf92f 100644 --- a/cmd/configure/configure.go +++ b/cmd/configure/configure.go @@ -40,6 +40,7 @@ type config struct { } Hems string EEBUS string + MQTT string SponsorToken string } diff --git a/cmd/configure/devicetest.go b/cmd/configure/devicetest.go index 514ae933c..fb0a5f44f 100644 --- a/cmd/configure/devicetest.go +++ b/cmd/configure/devicetest.go @@ -49,7 +49,7 @@ func (d *DeviceTest) Test() (DeviceTestResult, error) { // configure creates a configured device from a template so we can test it func (d *DeviceTest) configure() (interface{}, error) { - b, _, err := d.Template.RenderResult(false, d.ConfigValues) + b, _, err := d.Template.RenderResult(templates.TemplateRenderModeInstance, d.ConfigValues) if err != nil { return nil, err } diff --git a/cmd/configure/flow.go b/cmd/configure/flow.go index 300846676..6da9b4bd1 100644 --- a/cmd/configure/flow.go +++ b/cmd/configure/flow.go @@ -53,7 +53,7 @@ func (c *CmdConfigure) configureDeviceGuidedSetup() { // we only ask for the configuration for the first usage deviceCategory = supportedDeviceCategories[0] - values = c.processConfig(templateItem.Params, deviceCategory) + values = c.processConfig(templateItem, deviceCategory) deviceItem, err = c.processDeviceValues(values, templateItem, deviceItem, deviceCategory) if err != nil { @@ -86,7 +86,7 @@ func (c *CmdConfigure) configureDeviceGuidedSetup() { } fmt.Println() - fmt.Println(templateItem.Description + " " + c.localizedString("Device_Added", nil)) + fmt.Println(templateItem.Description.String(c.lang) + " " + c.localizedString("Device_Added", nil)) c.configureLinkedTypes(templateItem) } @@ -122,7 +122,7 @@ func (c *CmdConfigure) configureLinkedTypes(templateItem templates.Template) { category := DeviceCategory(linkedTemplate.Usage) localizeMap := localizeMap{ - "Linked": linkedTemplateItem.Description, + "Linked": linkedTemplateItem.Description.String(c.lang), "Article": DeviceCategories[category].article, "Additional": DeviceCategories[category].additional, "Category": DeviceCategories[category].title, @@ -148,7 +148,6 @@ func (c *CmdConfigure) configureLinkedTypes(templateItem templates.Template) { } } } - fmt.Println("DONE") } // configureLinkedTemplate lets the user configure a device that is marked as being linked to a guided device @@ -157,7 +156,7 @@ func (c *CmdConfigure) configureLinkedTemplate(template templates.Template, cate for ok := true; ok; { deviceItem := device{} - values := c.processConfig(template.Params, category) + values := c.processConfig(template, category) deviceItem, err := c.processDeviceValues(values, template, deviceItem, category) if err != nil { if !errors.Is(err, c.errDeviceNotValid) { @@ -173,7 +172,7 @@ func (c *CmdConfigure) configureLinkedTemplate(template templates.Template, cate c.configuration.AddDevice(deviceItem, category) fmt.Println() - fmt.Println(template.Description + " " + c.localizedString("Device_Added", nil)) + fmt.Println(template.Description.String(c.lang) + " " + c.localizedString("Device_Added", nil)) return true } break @@ -182,7 +181,7 @@ func (c *CmdConfigure) configureLinkedTemplate(template templates.Template, cate } // configureDeviceCategory lets the user select and configure a device from a specific category -func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (device, error) { +func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (device, templates.Capabilities, error) { fmt.Println() fmt.Printf("- %s %s\n", c.localizedString("Device_Configure", nil), DeviceCategories[deviceCategory].title) @@ -191,6 +190,7 @@ func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (d } var deviceDescription string + var capabilities templates.Capabilities // repeat until the device is added or the user chooses to continue without adding a device for ok := true; ok; { @@ -198,11 +198,12 @@ func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (d templateItem, err := c.processDeviceSelection(deviceCategory) if err != nil { - return device, c.errItemNotPresent + return device, capabilities, c.errItemNotPresent } - deviceDescription = templateItem.Description - values := c.processConfig(templateItem.Params, deviceCategory) + deviceDescription = templateItem.Description.String(c.lang) + capabilities = templateItem.Capabilities + values := c.processConfig(templateItem, deviceCategory) device, err = c.processDeviceValues(values, templateItem, device, deviceCategory) if err != nil { @@ -213,7 +214,7 @@ func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (d // ask if the user wants to add the fmt.Println() if !c.askConfigFailureNextStep() { - return device, err + return device, capabilities, err } continue } @@ -231,5 +232,5 @@ func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (d fmt.Println() fmt.Println(deviceDescription + deviceTitle + " " + c.localizedString("Device_Added", nil)) - return device, nil + return device, capabilities, nil } diff --git a/cmd/configure/helper.go b/cmd/configure/helper.go index 390e3b355..fb5efe656 100644 --- a/cmd/configure/helper.go +++ b/cmd/configure/helper.go @@ -5,6 +5,8 @@ import ( "sort" "strings" + "github.com/evcc-io/evcc/provider/mqtt" + "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/sponsor" "github.com/evcc-io/evcc/util/templates" "github.com/thoas/go-funk" @@ -15,7 +17,7 @@ import ( func (c *CmdConfigure) processDeviceSelection(deviceCategory DeviceCategory) (templates.Template, error) { templateItem := c.selectItem(deviceCategory) - if templateItem.Description == c.localizedString("ItemNotPresent", nil) { + if templateItem.Description.String(c.lang) == c.localizedString("ItemNotPresent", nil) { return templateItem, c.errItemNotPresent } @@ -31,7 +33,7 @@ func (c *CmdConfigure) processDeviceValues(values map[string]interface{}, templa c.addedDeviceIndex++ device.Name = fmt.Sprintf("%s%d", DeviceCategories[deviceCategory].defaultName, c.addedDeviceIndex) - device.Title = templateItem.Description + device.Title = templateItem.Description.String(c.lang) for item, value := range values { if strings.ToLower(item) != "title" { continue @@ -45,9 +47,9 @@ func (c *CmdConfigure) processDeviceValues(values map[string]interface{}, templa fmt.Println() if categoryWithUsage { - fmt.Println(c.localizedString("TestingDevice_TitleUsage", localizeMap{"Device": templateItem.Description, "Usage": deviceCategory.String()})) + fmt.Println(c.localizedString("TestingDevice_TitleUsage", localizeMap{"Device": templateItem.Description.String(c.lang), "Usage": deviceCategory.String()})) } else { - fmt.Println(c.localizedString("TestingDevice_Title", localizeMap{"Device": templateItem.Description})) + fmt.Println(c.localizedString("TestingDevice_Title", localizeMap{"Device": templateItem.Description.String(c.lang)})) } deviceTest := DeviceTest{ @@ -61,9 +63,9 @@ func (c *CmdConfigure) processDeviceValues(values map[string]interface{}, templa fmt.Println(" ", c.localizedString("Error", localizeMap{"Error": err})) fmt.Println() - question := c.localizedString("TestingDevice_AddFailed", localizeMap{"Device": templateItem.Description}) + question := c.localizedString("TestingDevice_AddFailed", localizeMap{"Device": templateItem.Description.String(c.lang)}) if categoryWithUsage { - question = c.localizedString("TestingDevice_AddFailedUsage", localizeMap{"Device": templateItem.Description, "Usage": deviceCategory.String()}) + question = c.localizedString("TestingDevice_AddFailedUsage", localizeMap{"Device": templateItem.Description.String(c.lang), "Usage": deviceCategory.String()}) } if !c.askYesNo(question) { c.addedDeviceIndex-- @@ -77,7 +79,7 @@ func (c *CmdConfigure) processDeviceValues(values map[string]interface{}, templa templateItem.Params = append(templateItem.Params, templates.Param{Name: "name", Value: device.Name}) if !c.expandedMode { - b, err := templateItem.RenderProxyWithValues(values, false) + b, err := templateItem.RenderProxyWithValues(values, c.lang, false) if err != nil { c.addedDeviceIndex-- return device, err @@ -91,7 +93,7 @@ func (c *CmdConfigure) processDeviceValues(values map[string]interface{}, templa templateItem.Render = fmt.Sprintf("name: {{ .name }}\n%s", templateItem.Render) } } - b, _, err := templateItem.RenderResult(false, values) + b, _, err := templateItem.RenderResult(templates.TemplateRenderModeInstance, values) if err != nil { c.addedDeviceIndex-- return device, err @@ -115,21 +117,9 @@ func (c *CmdConfigure) processDeviceRequirements(templateItem templates.Template // check if sponsorship is required if templateItem.Requirements.Sponsorship && c.configuration.config.SponsorToken == "" { - fmt.Println("-- Sponsorship -----------------------------") - fmt.Println() - fmt.Println(c.localizedString("Requirements_Sponsorship_Title", nil)) - fmt.Println() - if !c.askYesNo(c.localizedString("Requirements_Sponsorship_Token", nil)) { - return c.errItemNotPresent + if err := c.askSponsortoken(true); err != nil { + return err } - sponsortoken := c.askValue(question{ - label: c.localizedString("Requirements_Sponsorship_Token_Input", nil), - mask: true, - required: true}) - c.configuration.config.SponsorToken = sponsortoken - sponsor.Subject = sponsortoken - fmt.Println() - fmt.Println("--------------------------------------------") } // check if we need to setup a HEMS @@ -140,6 +130,23 @@ func (c *CmdConfigure) processDeviceRequirements(templateItem templates.Template } } + // check if we need to setup an MQTT broker + if templateItem.Requirements.Mqtt { + if c.configuration.config.MQTT == "" { + mqttConfig, err := c.configureMQTT() + if err != nil { + return err + } + + mqttYaml, err := yaml.Marshal(mqttConfig) + if err != nil { + return err + } + + c.configuration.config.MQTT = string(mqttYaml) + } + } + // check if we need to setup an EEBUS HEMS if templateItem.Requirements.Eebus { if c.configuration.config.EEBUS == "" { @@ -173,12 +180,90 @@ func (c *CmdConfigure) processDeviceRequirements(templateItem templates.Template return nil } +func (c *CmdConfigure) askSponsortoken(required bool) error { + fmt.Println("-- Sponsorship -----------------------------") + if required { + fmt.Println() + fmt.Println(c.localizedString("Requirements_Sponsorship_Title", nil)) + } + fmt.Println() + if !c.askYesNo(c.localizedString("Requirements_Sponsorship_Token", nil)) { + return c.errItemNotPresent + } + + sponsortoken := c.askValue(question{ + label: c.localizedString("Requirements_Sponsorship_Token_Input", nil), + mask: true, + required: true}) + c.configuration.config.SponsorToken = sponsortoken + sponsor.Subject = sponsortoken + fmt.Println() + fmt.Println("--------------------------------------------") + + return nil +} + +func (c *CmdConfigure) configureMQTT() (map[string]interface{}, error) { + fmt.Println() + fmt.Println("-- MQTT Broker ----------------------------") + + var err error + + for ok := true; ok; { + fmt.Println() + host := c.askValue(question{ + label: c.localizedString("UserFriendly_Host_Name", nil), + mask: false, + required: true}) + + port := c.askValue(question{ + label: c.localizedString("UserFriendly_Port_Name", nil), + mask: false, + required: true}) + + user := c.askValue(question{ + label: c.localizedString("UserFriendly_User_Name", nil), + mask: false, + required: false}) + + password := c.askValue(question{ + label: c.localizedString("UserFriendly_Password_Name", nil), + mask: true, + required: false}) + + fmt.Println() + fmt.Println("-------------------------------------------") + + broker := fmt.Sprintf("%s:%s", host, port) + + mqttConfig := map[string]interface{}{ + "broker": broker, + "user": user, + "password": password, + } + + log := util.NewLogger("mqtt") + + if mqtt.Instance, err = mqtt.RegisteredClient(log, broker, user, password, "", 1); err == nil { + return mqttConfig, nil + } + + fmt.Println() + question := c.localizedString("TestingMQTTFailed", nil) + if !c.askYesNo(question) { + return nil, fmt.Errorf("failed configuring mqtt: %w", err) + } + } + + return nil, fmt.Errorf("failed configuring mqtt: %w", err) +} + // fetchElements returns template items of a given class func (c *CmdConfigure) fetchElements(deviceCategory DeviceCategory) []templates.Template { var items []templates.Template for _, tmpl := range templates.ByClass(DeviceCategories[deviceCategory].class.String()) { - if len(tmpl.Params) == 0 || len(tmpl.Description) == 0 { + if len(tmpl.Params) == 0 || len(tmpl.Description.String(c.lang)) == 0 { continue } @@ -202,7 +287,7 @@ func (c *CmdConfigure) fetchElements(deviceCategory DeviceCategory) []templates. if !items[i].Generic && items[j].Generic { return true } - return strings.ToLower(items[i].Description) < strings.ToLower(items[j].Description) + return strings.ToLower(items[i].Description.String(c.lang)) < strings.ToLower(items[j].Description.String(c.lang)) }) return items @@ -233,7 +318,7 @@ func (c *CmdConfigure) paramChoiceValues(params []templates.Param, name string) // processConfig processes an EVCC configuration item // Returns: // a map with param name and values -func (c *CmdConfigure) processConfig(paramItems []templates.Param, deviceCategory DeviceCategory) map[string]interface{} { +func (c *CmdConfigure) processConfig(templateItem templates.Template, deviceCategory DeviceCategory) map[string]interface{} { usageFilter := DeviceCategories[deviceCategory].categoryFilter additionalConfig := make(map[string]interface{}) @@ -242,7 +327,33 @@ func (c *CmdConfigure) processConfig(paramItems []templates.Param, deviceCategor fmt.Println(c.localizedString("Config_Title", nil)) fmt.Println() - for _, param := range paramItems { + for _, param := range templateItem.Params { + if param.Dependencies != nil { + valid := true + for _, dep := range param.Dependencies { + _, valueParam := templateItem.ParamByName(dep.Name) + if valueParam == nil { + break + } + + value := valueParam.Value + switch dep.Check { + case templates.DependencyCheckEmpty: + valid = value == "" + case templates.DependencyCheckNotEmpty: + valid = value != "" + case templates.DependencyCheckEqual: + valid = value == dep.Value + } + if !valid { + break + } + } + if !valid { + continue + } + } + switch param.Name { case templates.ParamModbus: c.processModbusConfig(param, deviceCategory, additionalConfig) @@ -271,7 +382,7 @@ func (c *CmdConfigure) processConfig(paramItems []templates.Param, deviceCategor func (c *CmdConfigure) processListInputConfig(param templates.Param) []string { var values []string - // ask for values until the decides stops + // ask for values until the user decides to stop for ok := true; ok; { newValue := c.processInputConfig(param) values = append(values, newValue) @@ -291,8 +402,15 @@ func (c *CmdConfigure) processListInputConfig(param templates.Param) []string { // handle user input for a simple one value input func (c *CmdConfigure) processInputConfig(param templates.Param) string { userFriendly := c.userFriendlyTexts(param) + + label := userFriendly.Name + langLabel := param.Description.String(c.lang) + if langLabel != "" { + label = langLabel + } + return c.askValue(question{ - label: userFriendly.Name, + label: label, defaultValue: userFriendly.Default, exampleValue: userFriendly.Example, help: userFriendly.Help.String(c.lang), diff --git a/cmd/configure/localization/de.toml b/cmd/configure/localization/de.toml index b57c20174..bc7e5dad5 100644 --- a/cmd/configure/localization/de.toml +++ b/cmd/configure/localization/de.toml @@ -1,5 +1,9 @@ Intro = "Die nächsten Schritte führen durch die Einrichtung einer Konfigurationsdatei für evcc.\nBeachte dass dieser Prozess nicht alle möglichen Szenarien berücksichtigen kann.\nDurch Drücken von CTRL-C kann der Prozess abgebrochen werden.\n\nACHTUNG: Diese Funktionalität hat experimentellen Status!\n D.h. es kann möglich sein, dass die hiermit erstellte Konfigurationsdatei\n in einem Update nicht mehr funktionieren könnte und neu erzeugt werden müsste.\n Wir freuen uns auf euer Feedback auf https://github.com/evcc-io/evcc/discussions/\n\nAuf geht`s:" +Flow_Mode = "In welchem Modus soll die Konfiguration durchgeführt werden?" +Flow_Mode_Standard = "Standard Modus (So einfach und schnell wie möglich)" +Flow_Mode_Advanced = "Fortgeschrittener Modus (Detailliertere Fragen, erfordert jedoch technisches Know-How)" + Flow_Type = "Was möchtest du machen?" Flow_Type_NewConfiguration = "Eine neue evcc Konfigurationsdatei erstellen" Flow_Type_SingleDevice = "Ein einzelnes Gerät konfigurieren (muss manuell in eine Konfigurationsdatei eingetragen werden!)" @@ -90,6 +94,8 @@ TestingDevice_RepeatStep = "Möchtest du erneut ein Gerät aus der Liste auswäh TestingDevice_AddFailed = "Der Test von {{ .Device }} ist fehlgeschlagen. Soll es trotzdem in die Konfiguration aufgenommen werden?" TestingDevice_AddFailedUsage = "Der Test der {{ .Usage }} Konfiguration von {{ .Device }} ist fehlgeschlagen. Soll es trotzdem in die Konfiguration aufgenommen werden?" +TestingMQTTFailed = "Der Test der MQTT Konfiguration ist fehlgeschlagen. Möchten Sie die Konfiguration wiederholen?" + Requirements_Title = "Das Gerät muss die folgenden Voraussetzungen erfüllen:" Requirements_More = "Weitere Informationen:" @@ -131,7 +137,8 @@ Loadpoint_ResetOnDisconnect = "Soll beim Abstecken des Ladekables von einem Fahr Loadpoint_WallboxWOMeter = "Die Wallbox hat keinen Ladestromzähler. Hast du einen externen Zähler dafür installiert, der verwendet werden kann?" Loadpoint_WallboxMaxPower = "Was ist die maximale Leistung, welche die Wallbox zur Verfügung stellen kann?" -Loadpoint_WallboxMaxAmperage = "Was ist die maximale Stromstärke, welche die Wallbox auf einer Phase zur Verfügung stellen kann?" +Loadpoint_WallboxMinAmperage = "Was ist die MINIMALE Stromstärke, welche die Wallbox auf einer Phase zur Verfügung stellen kann?" +Loadpoint_WallboxMaxAmperage = "Was ist die MAXIMALE Stromstärke, welche die Wallbox auf einer Phase zur Verfügung stellen kann?" Loadpoint_WallboxPhases = "Mit wievielen Phasen ist die Wallbox angeschlossen?" Loadpoint_WallboxPower36kW = "3,6 kW" Loadpoint_WallboxPower11kW = "11 kW" diff --git a/cmd/configure/localization/en.toml b/cmd/configure/localization/en.toml index 11c66e42d..9c63dc9e7 100644 --- a/cmd/configure/localization/en.toml +++ b/cmd/configure/localization/en.toml @@ -1,5 +1,9 @@ Intro = "The next steps will guide you through the creation of a configuration file for evcc.\nPlease note that this process cannot cover all possible scenarios.\nYou can cancel the process by pressing CTRL-C anytime.\n\nNOTE: This functionality is in an experimental state!\n This means that the created configuration file may not work\n in a future update of evcc and would need to be recreated.\n We are looking forward to your feedback at https://github.com/evcc-io/evcc/discussions/\n\nLet's go:" +Flow_Mode = "In which mode should this process guide you through the configuration?" +Flow_Mode_Standard = "Standard mode (As simple and quick as possible)" +Flow_Mode_Advanced = "Advanced mode (Ask more details, requires technical know-how)" + Flow_Type = "What do you want to do?" Flow_Type_NewConfiguration = "Create a new evcc configuration file" Flow_Type_SingleDevice = "Configure a single device (has to be added manually to a configuration file!)" @@ -90,6 +94,8 @@ TestingDevice_RepeatStep = "Do you want to repeat choosing a device and configur TestingDevice_AddFailed = "Testing {{ .Device }} failed. Do you want to add it anyway?" TestingDevice_AddFailedUsage = "Testing of the {{ .Usage }} configuration of {{ .Device }} failed. Do you want to add it anyway?" +TestingMQTTFailed = "Testing the MQTT configuration failed. Do you want to repeat its configuration?" + Requirements_Title = "The device needs to provide the following requirements:" Requirements_More = "Additional information:" @@ -131,7 +137,8 @@ Loadpoint_ResetOnDisconnect = "Shall disconnecting the charging cable from the v Loadpoint_WallboxWOMeter = "The wallbox does not provide power data. Do you have an external meter that can be used?" Loadpoint_WallboxMaxPower = "What is the maximum power your wallbox can provide?" -Loadpoint_WallboxMaxAmperage = "What is the maximum amperage your wallbox can provide on a single phase?" +Loadpoint_WallboxMinAmperage = "What is the MINIMUM amperage your wallbox can provide on a single phase?" +Loadpoint_WallboxMaxAmperage = "What is the MAXIMUM amperage your wallbox can provide on a single phase?" Loadpoint_WallboxPhases = "How many phases are connected to the wallbox?" Loadpoint_WallboxPower36kW = "3.6 kW" Loadpoint_WallboxPower11kW = "11 kW" diff --git a/cmd/configure/main.go b/cmd/configure/main.go index 096421f1d..2910fe858 100644 --- a/cmd/configure/main.go +++ b/cmd/configure/main.go @@ -65,19 +65,31 @@ func (c *CmdConfigure) Run(log *util.Logger, flagLang string, advancedMode, expa c.setDefaultTexts() + fmt.Println() + fmt.Println(c.localizedString("Intro", nil)) + + if !c.advancedMode { + // ask the user for his knowledge, so advanced mode can also be turned on this way + fmt.Println() + flowIndex, _ := c.askChoice(c.localizedString("Flow_Mode", nil), []string{ + c.localizedString("Flow_Mode_Standard", nil), + c.localizedString("Flow_Mode_Advanced", nil), + }) + if flowIndex == 1 { + c.advancedMode = true + } + } + if !c.advancedMode { c.flowNewConfigFile() return } fmt.Println() - fmt.Println(c.localizedString("Intro", nil)) - flowChoices := []string{ + flowIndex, _ := c.askChoice(c.localizedString("Flow_Type", nil), []string{ c.localizedString("Flow_Type_NewConfiguration", nil), c.localizedString("Flow_Type_SingleDevice", nil), - } - fmt.Println() - flowIndex, _ := c.askChoice(c.localizedString("Flow_Type", nil), flowChoices) + }) switch flowIndex { case 0: c.flowNewConfigFile() @@ -143,6 +155,10 @@ func (c *CmdConfigure) flowNewConfigFile() { c.configureLoadpoints() c.configureSite() + if c.advancedMode && c.configuration.config.SponsorToken == "" { + _ = c.askSponsortoken(true) + } + yaml, err := c.configuration.RenderConfiguration() if err != nil { c.log.FATAL.Fatal(err) @@ -207,7 +223,7 @@ func (c *CmdConfigure) configureDevices(deviceCategory DeviceCategory, askAdding } for ok := true; ok; { - device, err := c.configureDeviceCategory(deviceCategory) + device, _, err := c.configureDeviceCategory(deviceCategory) if err != nil { break } @@ -243,7 +259,7 @@ func (c *CmdConfigure) configureLoadpoints() { MinCurrent: 6, } - charger, err := c.configureDeviceCategory(DeviceCategoryCharger) + charger, capabilities, err := c.configureDeviceCategory(DeviceCategoryCharger) if err != nil { break } @@ -253,7 +269,7 @@ func (c *CmdConfigure) configureLoadpoints() { if !chargerHasMeter { if c.askYesNo(c.localizedString("Loadpoint_WallboxWOMeter", nil)) { - chargeMeter, err := c.configureDeviceCategory(DeviceCategoryChargeMeter) + chargeMeter, _, err := c.configureDeviceCategory(DeviceCategoryChargeMeter) if err == nil { loadpoint.ChargeMeter = chargeMeter.Name chargerHasMeter = true @@ -272,39 +288,26 @@ func (c *CmdConfigure) configureLoadpoints() { } } - powerChoices := []string{ - c.localizedString("Loadpoint_WallboxPower36kW", nil), - c.localizedString("Loadpoint_WallboxPower11kW", nil), - c.localizedString("Loadpoint_WallboxPower22kW", nil), - c.localizedString("Loadpoint_WallboxPowerOther", nil), + var minValue int = 6 + if capabilities.ISO151182 { + minValue = 2 } - fmt.Println() - powerIndex, _ := c.askChoice(c.localizedString("Loadpoint_WallboxMaxPower", nil), powerChoices) - loadpoint.MinCurrent = 6 - switch powerIndex { - case 0: - loadpoint.MaxCurrent = 16 - if !chargerHasMeter { - loadpoint.Phases = 1 - } - case 1: - loadpoint.MaxCurrent = 16 - if !chargerHasMeter { - loadpoint.Phases = 3 - } - case 2: - loadpoint.MaxCurrent = 32 - if !chargerHasMeter { - loadpoint.Phases = 3 - } - case 3: - amperage := c.askValue(question{ + + if c.advancedMode { + minAmperage := c.askValue(question{ + label: c.localizedString("Loadpoint_WallboxMinAmperage", nil), + valueType: templates.ParamValueTypeNumber, + minNumberValue: int64(minValue), + maxNumberValue: 32, + required: true}) + loadpoint.MinCurrent, _ = strconv.Atoi(minAmperage) + maxAmperage := c.askValue(question{ label: c.localizedString("Loadpoint_WallboxMaxAmperage", nil), valueType: templates.ParamValueTypeNumber, minNumberValue: 6, maxNumberValue: 32, required: true}) - loadpoint.MaxCurrent, _ = strconv.Atoi(amperage) + loadpoint.MaxCurrent, _ = strconv.Atoi(maxAmperage) if !chargerHasMeter { phaseChoices := []string{"1", "2", "3"} @@ -312,6 +315,48 @@ func (c *CmdConfigure) configureLoadpoints() { phaseIndex, _ := c.askChoice(c.localizedString("Loadpoint_WallboxPhases", nil), phaseChoices) loadpoint.Phases = phaseIndex + 1 } + } else { + powerChoices := []string{ + c.localizedString("Loadpoint_WallboxPower36kW", nil), + c.localizedString("Loadpoint_WallboxPower11kW", nil), + c.localizedString("Loadpoint_WallboxPower22kW", nil), + c.localizedString("Loadpoint_WallboxPowerOther", nil), + } + fmt.Println() + powerIndex, _ := c.askChoice(c.localizedString("Loadpoint_WallboxMaxPower", nil), powerChoices) + loadpoint.MinCurrent = minValue + switch powerIndex { + case 0: + loadpoint.MaxCurrent = 16 + if !chargerHasMeter { + loadpoint.Phases = 1 + } + case 1: + loadpoint.MaxCurrent = 16 + if !chargerHasMeter { + loadpoint.Phases = 3 + } + case 2: + loadpoint.MaxCurrent = 32 + if !chargerHasMeter { + loadpoint.Phases = 3 + } + case 3: + amperage := c.askValue(question{ + label: c.localizedString("Loadpoint_WallboxMaxAmperage", nil), + valueType: templates.ParamValueTypeNumber, + minNumberValue: int64(minValue), + maxNumberValue: 32, + required: true}) + loadpoint.MaxCurrent, _ = strconv.Atoi(amperage) + + if !chargerHasMeter { + phaseChoices := []string{"1", "2", "3"} + fmt.Println() + phaseIndex, _ := c.askChoice(c.localizedString("Loadpoint_WallboxPhases", nil), phaseChoices) + loadpoint.Phases = phaseIndex + 1 + } + } } fmt.Println() diff --git a/cmd/configure/survey.go b/cmd/configure/survey.go index a4ced4ccb..96aa8fe47 100644 --- a/cmd/configure/survey.go +++ b/cmd/configure/survey.go @@ -64,15 +64,15 @@ func (c *CmdConfigure) askSelection(message string, items []string) (error, stri // selectItem selects item from list func (c *CmdConfigure) selectItem(deviceCategory DeviceCategory) templates.Template { var emptyItem templates.Template - emptyItem.Description = c.localizedString("ItemNotPresent", nil) + emptyItem.Description.SetString(c.localizedString("ItemNotPresent", nil), c.lang) elements := c.fetchElements(deviceCategory) elements = append(elements, emptyItem) var items []string for _, item := range elements { - if item.Description != "" { - items = append(items, item.Description) + if item.Description.String(c.lang) != "" { + items = append(items, item.Description.String(c.lang)) } } diff --git a/meter/template.go b/meter/template.go index f1816b5db..03bed7eb3 100644 --- a/meter/template.go +++ b/meter/template.go @@ -26,7 +26,7 @@ func NewMeterFromTemplateConfig(other map[string]interface{}) (api.Meter, error) return nil, err } - b, _, err := tmpl.RenderResult(false, other) + b, _, err := tmpl.RenderResult(templates.TemplateRenderModeInstance, other) if err != nil { return nil, err } diff --git a/meter/template_test.go b/meter/template_test.go index e6169bafd..9d67de7fe 100644 --- a/meter/template_test.go +++ b/meter/template_test.go @@ -33,7 +33,7 @@ func TestMeterTemplates(t *testing.T) { tmpl := tmpl // set default values for all params - values := tmpl.Defaults(true) + values := tmpl.Defaults(templates.TemplateRenderModeUnitTest) // set the template value which is needed for rendering values["template"] = tmpl.Template @@ -41,10 +41,11 @@ func TestMeterTemplates(t *testing.T) { // set modbus default test values if values[templates.ParamModbus] != nil { modbusChoices := tmpl.ModbusChoices() + // we only test one modbus setup if funk.ContainsString(modbusChoices, templates.ModbusChoiceTCPIP) { - values[templates.ModbusKeyTCPIP] = true + values[templates.ModbusTCPIP] = true } else { - values[templates.ModbusKeyRS485TCPIP] = true + values[templates.ModbusRS485TCPIP] = true } } @@ -70,14 +71,16 @@ func runTest(t *testing.T, tmpl templates.Template, values map[string]interface{ t.Run(tmpl.Template, func(t *testing.T) { t.Parallel() - b, values, err := tmpl.RenderResult(true, values) + b, values, err := tmpl.RenderResult(templates.TemplateRenderModeUnitTest, values) if err != nil { - t.Logf("%s: %s", tmpl.Template, b) + t.Logf("Template: %s", tmpl.Template) + t.Logf("%s", string(b)) t.Error(err) } if _, err := NewFromConfig("template", values); err != nil && !test.Acceptable(err, acceptable) { - t.Logf("%s", tmpl.Template) + t.Logf("Template: %s", tmpl.Template) + t.Logf("%s", string(b)) t.Error(err) } }) diff --git a/templates/README.md b/templates/README.md index 4f3f73401..a47472787 100644 --- a/templates/README.md +++ b/templates/README.md @@ -18,7 +18,7 @@ The following describes each possible element in a yaml file ## `description` -`description` expects a human readable description of the device, best language neutral and containing the name of the product +`description` expects a human readable description of the device, best containing the name of the product. Values are language specific names via `de`, `en`, `generic` (if string is language independent) ## `generic` @@ -60,6 +60,14 @@ Allows to define a list of meter devices that are typically installed with this 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. +## `capabilities` + +`capabilities` provides an option to define special capabilities of the devie + +**Possible Values**: + +- `iso151182: true`: If the charger supports communicating via ISO15118-2 + ## `requirements` `requirements` provides an option to define various requirements / dependencies that need to be setup @@ -95,6 +103,39 @@ Example Use Case: With SMA Home Manager, there can be a SMA Energy Meter used fo - `usage`: specifies a list of meter classes, the device can be used for. Possible values are `grid`, `pv`, `battery`, and `charger` - `modbus`: specifies that this device is accessed via modbus. It requires the `choice` property to have a list of possible interface values the device provides. These values can be `rs485` and `tcpip`. The command will use either to ask the appropriate questions and settings. The `render` section needs to include the string `{{include "modbus" .}}` in all places where the configuration needs modbus settings. +#### Modbus Options + +- `id`: Device specific default for modbus ID +- `port`: Device specific default for modbus TCPIP port +- `baudrate`: Device specific default for modbus RS485 baudrate +- `comset`: Device specific default for modbus RS485 comset + +### `description` + +`description` allows to define user friendly and language specific names via `de`, `en`, `generic` + +### `dependencies` + +`dependencies` allows to define a list of checks, when this param should be presented to the user, if it should be only in special cases + +#### `name` + +`name` referenced the `param` `name` value + +#### `check` + +`check` defines which kind of check should be performed + +**Possible values**: + +- `empty`: if the `value` of the referenced `param` `name` should be empty +- `notempty`: if the `value` of the referenced `param` `name` should be **NOT** empty +- `equal`: if the `value` of the referenced `param` `name` should match the value of the `value` property + +#### `value` + +`value` property is used in the `equal` `check` + ### `required` `required: true` defines if the user has to provide a value. Default is `false` diff --git a/templates/definition/charger/abl.yaml b/templates/definition/charger/abl.yaml index f0c38274a..eb3656faa 100644 --- a/templates/definition/charger/abl.yaml +++ b/templates/definition/charger/abl.yaml @@ -1,5 +1,6 @@ template: abl -description: ABL eMH / SENEC.Wallbox pro +description: + generic: ABL eMH / SENEC.Wallbox pro requirements: sponsorship: true params: diff --git a/templates/definition/charger/cfos.yaml b/templates/definition/charger/cfos.yaml index 4f0ed7e64..9486f9a6a 100644 --- a/templates/definition/charger/cfos.yaml +++ b/templates/definition/charger/cfos.yaml @@ -1,5 +1,6 @@ -template: cfos_charger -description: cFos PowerBrain +template: cfos +description: + generic: cFos PowerBrain requirements: sponsorship: true params: diff --git a/templates/definition/charger/daheimladen.yaml b/templates/definition/charger/daheimladen.yaml index f2d5f8d03..a62c10a75 100644 --- a/templates/definition/charger/daheimladen.yaml +++ b/templates/definition/charger/daheimladen.yaml @@ -1,7 +1,6 @@ template: daheimladen -description: Daheimladen (Cloud API) -requirements: - sponsorship: true +description: + generic: Daheimladen (Cloud API) params: - name: token help: diff --git a/templates/definition/charger/easee.yaml b/templates/definition/charger/easee.yaml index 767c01098..cdb322ea5 100644 --- a/templates/definition/charger/easee.yaml +++ b/templates/definition/charger/easee.yaml @@ -1,5 +1,6 @@ template: easee -description: Easee Home (Cloud API) +description: + generic: Easee Home (Cloud API) requirements: sponsorship: true params: diff --git a/templates/definition/charger/eebus.yaml b/templates/definition/charger/eebus.yaml index 50d68ac1e..cb41543ce 100644 --- a/templates/definition/charger/eebus.yaml +++ b/templates/definition/charger/eebus.yaml @@ -1,6 +1,10 @@ template: eebus -description: EEBUS kompatible Wallbox +description: + de: EEBUS kompatible Wallbox + en: EEBUS compatible Wallbox generic: true +capabilities: + iso151182: true requirements: eebus: true params: diff --git a/templates/definition/charger/evsedin.yaml b/templates/definition/charger/evsedin.yaml index 88824ecab..5b0eb753b 100644 --- a/templates/definition/charger/evsedin.yaml +++ b/templates/definition/charger/evsedin.yaml @@ -1,5 +1,6 @@ template: evse_din -description: EVSE DIN +description: + generic: EVSE DIN params: - name: modbus choice: ["rs485"] diff --git a/templates/definition/charger/evsewifi.yaml b/templates/definition/charger/evsewifi.yaml index c39367cd8..e26cb0fb0 100644 --- a/templates/definition/charger/evsewifi.yaml +++ b/templates/definition/charger/evsewifi.yaml @@ -1,5 +1,6 @@ template: evsewifi -description: EVSE-Wifi +description: + generic: EVSE-Wifi params: - name: host required: true diff --git a/templates/definition/charger/fritzdect.yaml b/templates/definition/charger/fritzdect.yaml index 2f2a0f548..817a439d4 100644 --- a/templates/definition/charger/fritzdect.yaml +++ b/templates/definition/charger/fritzdect.yaml @@ -1,5 +1,6 @@ template: fritzdect -description: FritzDECT +description: + generic: FritzDECT params: - name: uri default: https://fritz.box diff --git a/templates/definition/charger/goe.yaml b/templates/definition/charger/goe.yaml index 634cad2a4..aac2ae9bb 100644 --- a/templates/definition/charger/goe.yaml +++ b/templates/definition/charger/goe.yaml @@ -1,5 +1,6 @@ template: go-e -description: go-eCharger Home/Pro/V3 +description: + generic: go-eCharger Home/Pro/V3 requirements: description: en: Home und PRO require firmware 040.0 or later, V3 requires firmware 052.1 or later. diff --git a/templates/definition/charger/heidelberg.yaml b/templates/definition/charger/heidelberg.yaml index b212b719b..75bfa5355 100644 --- a/templates/definition/charger/heidelberg.yaml +++ b/templates/definition/charger/heidelberg.yaml @@ -1,5 +1,6 @@ template: heidelberg -description: Heidelberg Energy Control (Modbus RTU) +description: + generic: Heidelberg Energy Control (Modbus RTU) requirements: sponsorship: true params: diff --git a/templates/definition/charger/icharge-cion.yaml b/templates/definition/charger/icharge-cion.yaml index 4c520aadf..2abfbdbea 100644 --- a/templates/definition/charger/icharge-cion.yaml +++ b/templates/definition/charger/icharge-cion.yaml @@ -1,5 +1,6 @@ template: ichargecion -description: i-CHARGE CION (Modbus RTU-over-TCP) +description: + generic: i-CHARGE CION (Modbus RTU-over-TCP) params: - name: modbus choice: ["tcpip"] diff --git a/templates/definition/charger/innogy-ebox.yaml b/templates/definition/charger/innogy-ebox.yaml index 7034adb99..a7d52acae 100644 --- a/templates/definition/charger/innogy-ebox.yaml +++ b/templates/definition/charger/innogy-ebox.yaml @@ -1,5 +1,6 @@ template: innogy-ebox -description: Innogy eBox +description: + generic: Innogy eBox requirements: sponsorship: true params: diff --git a/templates/definition/charger/keba.yaml b/templates/definition/charger/keba.yaml index fa11c13ae..c9437a541 100644 --- a/templates/definition/charger/keba.yaml +++ b/templates/definition/charger/keba.yaml @@ -1,5 +1,6 @@ template: keba -description: KEBA Connect +description: + generic: KEBA Connect requirements: description: en: This requires the UDP function to be enabled with DIP 1.3 = ON, see the installation manual. diff --git a/templates/definition/charger/nrgkick-bluetooth.yaml b/templates/definition/charger/nrgkick-bluetooth.yaml index 17e2b1f95..b8e413d4d 100644 --- a/templates/definition/charger/nrgkick-bluetooth.yaml +++ b/templates/definition/charger/nrgkick-bluetooth.yaml @@ -1,5 +1,6 @@ template: nrgkick-bluetooth -description: NRGKick Bluetooth +description: + generic: NRGKick Bluetooth params: - name: mac required: true diff --git a/templates/definition/charger/nrgkick-connect.yaml b/templates/definition/charger/nrgkick-connect.yaml index 563fe9b55..19d358a47 100644 --- a/templates/definition/charger/nrgkick-connect.yaml +++ b/templates/definition/charger/nrgkick-connect.yaml @@ -1,5 +1,6 @@ template: nrgkick-connect -description: NRGKick Connect +description: + generic: NRGKick Connect params: - name: host required: true diff --git a/templates/definition/charger/openwb.yaml b/templates/definition/charger/openwb.yaml index 932681a3b..be2f62970 100644 --- a/templates/definition/charger/openwb.yaml +++ b/templates/definition/charger/openwb.yaml @@ -1,5 +1,6 @@ template: openwb -description: openWB (MQTT) +description: + generic: openWB (MQTT) requirements: description: en: The wallbox has to be configured running as a loadpoint. diff --git a/templates/definition/charger/phoenix-em-eth.yaml b/templates/definition/charger/phoenix-em-eth.yaml index 761150c49..dca253571 100644 --- a/templates/definition/charger/phoenix-em-eth.yaml +++ b/templates/definition/charger/phoenix-em-eth.yaml @@ -1,5 +1,6 @@ template: phoenix-em-eth -description: Phoenix EM-CP-PP-ETH Controller (Modbus TCP) +description: + generic: Phoenix EM-CP-PP-ETH Controller (Modbus TCP) generic: true requirements: description: diff --git a/templates/definition/charger/phoenix-ev-eth.yaml b/templates/definition/charger/phoenix-ev-eth.yaml index 99e19a0ec..f90dcc36a 100644 --- a/templates/definition/charger/phoenix-ev-eth.yaml +++ b/templates/definition/charger/phoenix-ev-eth.yaml @@ -1,5 +1,6 @@ template: phoenix-ev-eth -description: Phoenix EV-ETH Controller (Modbus TCP) +description: + generic: Phoenix EV-ETH Controller (Modbus TCP) generic: true requirements: description: diff --git a/templates/definition/charger/phoenix-ev-ser.yaml b/templates/definition/charger/phoenix-ev-ser.yaml index 6df5d96f5..e781685ed 100644 --- a/templates/definition/charger/phoenix-ev-ser.yaml +++ b/templates/definition/charger/phoenix-ev-ser.yaml @@ -1,5 +1,6 @@ template: phoenix-ev-ser -description: Phoenix EV-SER Controller (Modbus RTU) +description: + generic: Phoenix EV-SER Controller (Modbus RTU) generic: true params: - name: modbus diff --git a/templates/definition/charger/porsche-pmcc.yaml b/templates/definition/charger/porsche-pmcc.yaml index a48454227..8ec9847cd 100644 --- a/templates/definition/charger/porsche-pmcc.yaml +++ b/templates/definition/charger/porsche-pmcc.yaml @@ -1,5 +1,8 @@ template: pmcc -description: Porsche Mobile Charger Connect +description: + generic: Porsche Mobile Charger Connect +capabilities: + iso151182: true requirements: eebus: true params: diff --git a/templates/definition/charger/porsche-pmcp.yaml b/templates/definition/charger/porsche-pmcp.yaml index 3ea1482d0..a0b0801f7 100644 --- a/templates/definition/charger/porsche-pmcp.yaml +++ b/templates/definition/charger/porsche-pmcp.yaml @@ -1,5 +1,6 @@ template: pmcp -description: Porsche Mobile Charger Plus +description: + generic: Porsche Mobile Charger Plus requirements: eebus: true params: diff --git a/templates/definition/charger/shelly.yaml b/templates/definition/charger/shelly.yaml index 2fc5b85ec..2ed5a4ce2 100644 --- a/templates/definition/charger/shelly.yaml +++ b/templates/definition/charger/shelly.yaml @@ -1,5 +1,6 @@ template: shelly -description: Shelly +description: + generic: Shelly params: - name: host required: true diff --git a/templates/definition/charger/tasmota.yaml b/templates/definition/charger/tasmota.yaml index 2ca2c3924..04a7707c4 100644 --- a/templates/definition/charger/tasmota.yaml +++ b/templates/definition/charger/tasmota.yaml @@ -1,5 +1,6 @@ template: tasmota -description: Tasmota +description: + generic: Tasmota params: - name: host required: true diff --git a/templates/definition/charger/tinkerforge-warp-pro.yaml b/templates/definition/charger/tinkerforge-warp-pro.yaml index bf1973d09..b53eca9ba 100644 --- a/templates/definition/charger/tinkerforge-warp-pro.yaml +++ b/templates/definition/charger/tinkerforge-warp-pro.yaml @@ -1,5 +1,6 @@ template: tinkerforge-warp-pro -description: TinkerForge WARP Charger Pro +description: + generic: TinkerForge WARP Charger Pro requirements: description: en: A MQTT Broker software needs to be running on a computer. The MQTT connection also needs to be configured in the wallbox. diff --git a/templates/definition/charger/tinkerforge-warp.yaml b/templates/definition/charger/tinkerforge-warp.yaml index d8476ca2f..bdd918cb0 100644 --- a/templates/definition/charger/tinkerforge-warp.yaml +++ b/templates/definition/charger/tinkerforge-warp.yaml @@ -1,5 +1,6 @@ template: tinkerforge-warp -description: TinkerForge WARP Charger +description: + generic: TinkerForge WARP Charger requirements: description: en: A MQTT Broker software needs to be running on a computer. The MQTT connection also needs to be configured in the wallbox. diff --git a/templates/definition/charger/tplink.yaml b/templates/definition/charger/tplink.yaml index edceafcf4..d67d799d4 100644 --- a/templates/definition/charger/tplink.yaml +++ b/templates/definition/charger/tplink.yaml @@ -1,5 +1,6 @@ template: tplink -description: TP-LINK Smart Plug +description: + generic: TP-LINK Smart Plug params: - name: host required: true diff --git a/templates/definition/charger/wallbe-meter.yaml b/templates/definition/charger/wallbe-meter.yaml index 7083f5583..33f369da6 100644 --- a/templates/definition/charger/wallbe-meter.yaml +++ b/templates/definition/charger/wallbe-meter.yaml @@ -1,5 +1,7 @@ template: wallbe-meter -description: Wallbe (Eco, Pro) with Meter +description: + de: Wallbe (Eco, Pro) mit Strommessgerät + en: Wallbe (Eco, Pro) with Meter requirements: description: en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'. diff --git a/templates/definition/charger/wallbe-pre2019-meter.yaml b/templates/definition/charger/wallbe-pre2019-meter.yaml index c978c5b18..0489f492a 100644 --- a/templates/definition/charger/wallbe-pre2019-meter.yaml +++ b/templates/definition/charger/wallbe-pre2019-meter.yaml @@ -1,5 +1,7 @@ template: wallbe-pre2019-meter -description: Wallbe (Eco, Pro) (pre ~2019) with Meter +description: + de: Wallbe (Eco, Pro) (vor ~2019) mit Strommessgerät + en: Wallbe (Eco, Pro) (pre ~2019) with Meter requirements: description: en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'. diff --git a/templates/definition/charger/wallbe-pre2019.yaml b/templates/definition/charger/wallbe-pre2019.yaml index 52ccbf07c..3171acefb 100644 --- a/templates/definition/charger/wallbe-pre2019.yaml +++ b/templates/definition/charger/wallbe-pre2019.yaml @@ -1,5 +1,7 @@ template: wallbe-pre2019 -description: Wallbe (Eco, Pro) (pre ~2019) +description: + de: Wallbe (Eco, Pro) (vor ~2019) + en: Wallbe (Eco, Pro) (pre ~2019) requirements: description: en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'. diff --git a/templates/definition/charger/wallbe.yaml b/templates/definition/charger/wallbe.yaml index 8def77291..7d8fdfbd9 100644 --- a/templates/definition/charger/wallbe.yaml +++ b/templates/definition/charger/wallbe.yaml @@ -1,5 +1,6 @@ template: wallbe -description: Wallbe (Eco, Pro) +description: + generic: Wallbe (Eco, Pro) requirements: description: en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'. diff --git a/templates/definition/meter/cfos.yaml b/templates/definition/meter/cfos.yaml index 961791831..085550e58 100644 --- a/templates/definition/meter/cfos.yaml +++ b/templates/definition/meter/cfos.yaml @@ -1,5 +1,6 @@ -template: cfos-meter -description: cFos PowerBrain Meter +template: cfos +description: + generic: cFos PowerBrain Meter requirements: sponsorship: true params: diff --git a/templates/definition/meter/discovergy.yaml b/templates/definition/meter/discovergy.yaml index 9bcc16905..137ffb40b 100644 --- a/templates/definition/meter/discovergy.yaml +++ b/templates/definition/meter/discovergy.yaml @@ -1,5 +1,6 @@ template: discovergy -description: Discovergy (Cloud) +description: + generic: Discovergy (Cloud) params: - name: usage choice: ["grid", "pv"] diff --git a/templates/definition/meter/e3dc.yaml b/templates/definition/meter/e3dc.yaml index 0a8aeb511..72464c258 100644 --- a/templates/definition/meter/e3dc.yaml +++ b/templates/definition/meter/e3dc.yaml @@ -1,5 +1,6 @@ template: e3dc -description: E3DC +description: + generic: E3DC guidedsetup: enable: true params: diff --git a/templates/definition/meter/eastron.yaml b/templates/definition/meter/eastron.yaml index 0fd4b2663..3db56d451 100644 --- a/templates/definition/meter/eastron.yaml +++ b/templates/definition/meter/eastron.yaml @@ -1,5 +1,7 @@ template: eastron -description: Eastron SDM Modbus Meter +description: + de: Eastron SDM Modbus Strommessgeräte + en: Eastron SDM Modbus Meter params: - name: usage choice: ["grid", "pv", "battery", "charge"] diff --git a/templates/definition/meter/fritzdect.yaml b/templates/definition/meter/fritzdect.yaml index e10873518..755223caa 100644 --- a/templates/definition/meter/fritzdect.yaml +++ b/templates/definition/meter/fritzdect.yaml @@ -1,5 +1,6 @@ template: fritzdect -description: FritzDECT +description: + generic: FritzDECT params: - name: usage choice: ["pv", "charge"] @@ -17,12 +18,9 @@ params: help: en: The AIN is printed on the type label on the back of the device. de: Die AIN ist auf dem Typenschild auf der Geräterückseite aufgedruckt. -- name: standbypower - default: 15 render: | type: fritzdect uri: {{ .uri }} user: {{ .user }} password: {{ .password }} ain: {{ .ain }} # switch actor identification number without blanks (see AIN number on switch sticker) - standbypower: {{ .standbypower }} # treat as charging above this power diff --git a/templates/definition/meter/fronius-gen24.yaml b/templates/definition/meter/fronius-gen24.yaml index 11b56d00c..3e14b98f7 100644 --- a/templates/definition/meter/fronius-gen24.yaml +++ b/templates/definition/meter/fronius-gen24.yaml @@ -1,5 +1,6 @@ template: fronius-gen24 -description: Fronius Symo GEN24 Plus +description: + generic: Fronius Symo GEN24 Plus guidedsetup: enable: true params: diff --git a/templates/definition/meter/fronius-solarapi-v1.yaml b/templates/definition/meter/fronius-solarapi-v1.yaml index ed3875f13..f7b6c4558 100644 --- a/templates/definition/meter/fronius-solarapi-v1.yaml +++ b/templates/definition/meter/fronius-solarapi-v1.yaml @@ -1,5 +1,6 @@ template: fronius-solarapi-v1 -description: Fronius Solar API V1 +description: + generic: Fronius Solar API V1 guidedsetup: enable: true params: diff --git a/templates/definition/meter/huawei-sun2000-8ktl.yaml b/templates/definition/meter/huawei-sun2000-8ktl.yaml index 2f1c667fd..23a79ee87 100644 --- a/templates/definition/meter/huawei-sun2000-8ktl.yaml +++ b/templates/definition/meter/huawei-sun2000-8ktl.yaml @@ -1,5 +1,6 @@ template: huawei-sun2000-8ktl -description: Huawei SUN2000-8KTL +description: + generic: Huawei SUN2000-8KTL params: - name: usage choice: [ "pv" ] diff --git a/templates/definition/meter/kostal-ksem-inverter.yaml b/templates/definition/meter/kostal-ksem-inverter.yaml index 131051c55..67e4f245e 100644 --- a/templates/definition/meter/kostal-ksem-inverter.yaml +++ b/templates/definition/meter/kostal-ksem-inverter.yaml @@ -1,5 +1,7 @@ template: kostal-ksem-inverter -description: Kostal Smart Energy Meter via inverter +description: + de: Kostal Smart Energy Meter über den Wechselrichter + en: Kostal Smart Energy Meter via inverter params: - name: usage choice: [ "grid" ] diff --git a/templates/definition/meter/kostal-ksem.yaml b/templates/definition/meter/kostal-ksem.yaml index bcf2622eb..214415c26 100644 --- a/templates/definition/meter/kostal-ksem.yaml +++ b/templates/definition/meter/kostal-ksem.yaml @@ -1,5 +1,6 @@ template: kostal-ksem -description: Kostal Smart Energy Meter +description: + generic: Kostal Smart Energy Meter params: - name: usage choice: [ "grid" ] diff --git a/templates/definition/meter/kostal-piko-mp-plus.yaml b/templates/definition/meter/kostal-piko-mp-plus.yaml index 5c6cff60c..747e752bd 100644 --- a/templates/definition/meter/kostal-piko-mp-plus.yaml +++ b/templates/definition/meter/kostal-piko-mp-plus.yaml @@ -1,5 +1,6 @@ template: kostal-piko-mp-plus -description: Kostal Piko MP Plus +description: + generic: Kostal Piko MP Plus guidedsetup: enable: true linked: diff --git a/templates/definition/meter/kostal-piko.yaml b/templates/definition/meter/kostal-piko.yaml index 65bcab575..13f707c6c 100644 --- a/templates/definition/meter/kostal-piko.yaml +++ b/templates/definition/meter/kostal-piko.yaml @@ -1,5 +1,6 @@ template: kostal-piko -description: Kostal Piko + Piko BA +description: + generic: Kostal Piko + Piko BA guidedsetup: enable: true params: @@ -17,18 +18,18 @@ render: | add: - source: http uri: http://{{ .host }}/api/dxs.json?dxsEntries=67109120 # PV AC Ausgang - jq: .dxsEntries[0].value + jq: .dxsEntries[0].value | if . == null then 0 else . end scale: -1.0 - source: http uri: http://{{ .host }}/api/dxs.json?dxsEntries=83886848 # Netzbezug - jq: .dxsEntries[0].value + jq: .dxsEntries[0].value | if . == null then 0 else . end - source: http uri: http://{{ .host }}/api/dxs.json?dxsEntries=83886336 # PV Eigenverbrauch - jq: .dxsEntries[0].value + jq: .dxsEntries[0].value | if . == null then 0 else . end {{- end -}} {{- if eq .usage "pv" }} # PV source: http uri: http://{{ .host }}/api/dxs.json?dxsEntries=67109120 # PV AC Ausgang - jq: .dxsEntries[0].value + jq: .dxsEntries[0].value | if . == null then 0 else . end {{- end -}} diff --git a/templates/definition/meter/kostal-plenticore.yaml b/templates/definition/meter/kostal-plenticore.yaml index 625435932..35b055eb7 100644 --- a/templates/definition/meter/kostal-plenticore.yaml +++ b/templates/definition/meter/kostal-plenticore.yaml @@ -1,5 +1,6 @@ template: kostal-plenticore -description: Kostal Plenticore Hybrid +description: + generic: Kostal Plenticore Hybrid guidedsetup: enable: true linked: diff --git a/templates/definition/meter/lg-ess-home-8-10.yaml b/templates/definition/meter/lg-ess-home-8-10.yaml index d95657c04..c9649f1f6 100644 --- a/templates/definition/meter/lg-ess-home-8-10.yaml +++ b/templates/definition/meter/lg-ess-home-8-10.yaml @@ -1,5 +1,6 @@ template: lg-ess-home-8-10 -description: LG ESS Home 8/10 +description: + generic: LG ESS Home 8/10 guidedsetup: enable: true params: diff --git a/templates/definition/meter/mqtt-meter.yaml b/templates/definition/meter/mqtt-meter.yaml new file mode 100644 index 000000000..edfa289cb --- /dev/null +++ b/templates/definition/meter/mqtt-meter.yaml @@ -0,0 +1,105 @@ +template: mqtt-meter +description: + de: MQTT Strommessgerät + en: MQTT Meter +generic: true +requirements: + mqtt: true +params: +- name: usage + choice: [ "grid", "pv", "charge", "battery" ] +- name: power + description: + de: MQTT Topic für die Leistung (W) + en: MQTT Topic for power (W) + required: true +- name: scalepower + description: + de: Skalierung der Leistungswerte + en: Scaling of the power value + default: 1 + help: + de: Die Leistung wird in Watt erwartet. Falls z.b. kW geliefert wird, kann dies hier mit dem Wert 1000 angepasst werden + en: Power is expected to be provided in Watt. If it is provided in kW instead, set this value to 1000 to correct it +- name: energy + description: + de: MQTT Topic für Energiemenge (Wh) + en: MQTT Topic for energy (Wh) +- name: scaleenergy + dependencies: + - name: energy + check: notempty + description: + de: Skalierung der Energiement + en: Scaling of the energy value + default: 1 + help: + de: Die Energiemenge wird in kWh erwartet. Falls z.b. Wh geliefert wird, kann dies hier mit dem Wert 0.001 angepasst werden + en: Power is expected to be provided in kWh. If it is provided in Wh instead, set this value to 0.001 to correct it +- name: soc + description: + de: MQTT Topic für den SoC der Batterie (%) + en: MQTT Topic for battery SoC (%) + dependencies: + - name: usage + check: equal + value: battery +- name: currentp1 + description: + de: MQTT Topic Stromstärke (A) Phase 1 + en: MQTT Topic Amperage (A) phase 1 +- name: currentp2 + description: + de: MQTT Topic Stromstärke (A) Phase 2 + en: MQTT Topic Amperage (A) phase 2 + dependencies: + - name: currentp1 + check: notempty +- name: currentp3 + description: + de: MQTT Topic Stromstärke (A) Phase 3 + en: MQTT Topic Amperage (A) phase 3 + dependencies: + - name: currentp1 + check: notempty +- name: timeout + default: 30 + help: + de: Akzeptiere keine Daten die älter als dieser Wert in Sekunden ist + en: Don't accept values older than this value in seconds +render: | + type: custom + power: + source: mqtt + topic: {{ .power }} + scale: {{ .scalepower }} + timeout: {{ .timeout }} + {{- if ne .energy1 "" }} + energy: + source: mqtt + topic: {{ .energy }} + scale: {{ .scaleenergy }} + timeout: {{ .timeout }} + {{- end -}} + {{- if eq .usage "battery" }} + soc: + source: mqtt + topic: {{ .soc }} + timeout: {{ .timeout }} + {{- end -}} + {{- if ne .currentp1 "" }} + currents: + - source: mqtt + topic: {{ .currentp1 }} + timeout: {{ .timeout }} + {{- if ne .currentp2 "" }} + - source: mqtt + topic: {{ .currentp2 }} + timeout: {{ .timeout }} + {{- end -}} + {{- if ne .currentp3 "" }} + - source: mqtt + topic: {{ .currentp3 }} + timeout: {{ .timeout }} + {{- end -}} + {{- end -}} diff --git a/templates/definition/meter/powerdog.yaml b/templates/definition/meter/powerdog.yaml index 946527561..358c762b5 100644 --- a/templates/definition/meter/powerdog.yaml +++ b/templates/definition/meter/powerdog.yaml @@ -1,5 +1,6 @@ template: powerdog -description: Powerdog +description: + generic: Powerdog guidedsetup: enable: true params: diff --git a/templates/definition/meter/powerfox-poweropti.yaml b/templates/definition/meter/powerfox-poweropti.yaml index 13c07991c..99087936e 100644 --- a/templates/definition/meter/powerfox-poweropti.yaml +++ b/templates/definition/meter/powerfox-poweropti.yaml @@ -1,5 +1,6 @@ template: powerfox-poweropti -description: Powerfox Poweropti (Cloud) +description: + generic: Powerfox Poweropti (Cloud) params: - name: usage choice: [ "grid" ] diff --git a/templates/definition/meter/rct-power.yaml b/templates/definition/meter/rct-power.yaml index 744c20524..afe5d0b3e 100644 --- a/templates/definition/meter/rct-power.yaml +++ b/templates/definition/meter/rct-power.yaml @@ -1,5 +1,6 @@ template: rct-power -description: RCT Power +description: + generic: RCT Power guidedsetup: enable: true params: diff --git a/templates/definition/meter/senec-home.yaml b/templates/definition/meter/senec-home.yaml index f9a5871f4..f26ce2fde 100644 --- a/templates/definition/meter/senec-home.yaml +++ b/templates/definition/meter/senec-home.yaml @@ -1,5 +1,6 @@ template: senec-home -description: SENEC.Home +description: + generic: SENEC.Home guidedsetup: enable: true params: diff --git a/templates/definition/meter/shelly-3em.yaml b/templates/definition/meter/shelly-3em.yaml index e63187d95..720aeb44c 100644 --- a/templates/definition/meter/shelly-3em.yaml +++ b/templates/definition/meter/shelly-3em.yaml @@ -1,5 +1,6 @@ template: shelly-3em -description: Shelly 3EM +description: + generic: Shelly 3EM params: - name: usage choice: [ "grid" ] diff --git a/templates/definition/meter/sma-energymeter.yaml b/templates/definition/meter/sma-energymeter.yaml index 122dad10d..d9a608202 100644 --- a/templates/definition/meter/sma-energymeter.yaml +++ b/templates/definition/meter/sma-energymeter.yaml @@ -1,5 +1,6 @@ template: sma-energy-meter -description: SMA Energy Meter +description: + generic: SMA Energy Meter (Produktname) params: - name: usage choice: ["grid", "pv", "battery"] diff --git a/templates/definition/meter/sma-homemanager.yaml b/templates/definition/meter/sma-homemanager.yaml index e185e365d..bc89825a1 100644 --- a/templates/definition/meter/sma-homemanager.yaml +++ b/templates/definition/meter/sma-homemanager.yaml @@ -1,5 +1,6 @@ template: sma-home-manager -description: SMA Sunny Home Manager 2.0 +description: + generic: SMA Sunny Home Manager 2.0 requirements: hems: sma guidedsetup: diff --git a/templates/definition/meter/sma-inverter.yaml b/templates/definition/meter/sma-inverter.yaml index d6df0a586..25d85b360 100644 --- a/templates/definition/meter/sma-inverter.yaml +++ b/templates/definition/meter/sma-inverter.yaml @@ -1,5 +1,7 @@ template: sma-inverter -description: SMA Inverter/Wechselrichter +description: + de: SMA Wechselrichter + en: SMA Inverter params: - name: usage choice: ["pv", "battery"] diff --git a/templates/definition/meter/solaredge-hybrid.yaml b/templates/definition/meter/solaredge-hybrid.yaml index 83732f55e..ee504c9cf 100644 --- a/templates/definition/meter/solaredge-hybrid.yaml +++ b/templates/definition/meter/solaredge-hybrid.yaml @@ -1,7 +1,12 @@ template: solaredge-hybrid -description: Solaredge Hybrid +description: + generic: Solaredge Hybrid guidedsetup: enable: true +requirements: + description: + de: Nur ein System kann auf den Wechselrichter zugreifen! + en: Only one system may access the inverter! params: - name: usage choice: [ "grid", "pv", "battery" ] diff --git a/templates/definition/meter/solaredge-inverter.yaml b/templates/definition/meter/solaredge-inverter.yaml new file mode 100644 index 000000000..5dd77b6bd --- /dev/null +++ b/templates/definition/meter/solaredge-inverter.yaml @@ -0,0 +1,17 @@ +template: solaredge-inverter +description: + de: Solaredge Wechselrichter + en: Solaredge Inverter +guidedsetup: + enable: true +params: +- name: usage + choice: [ "pv" ] +- name: modbus + choice: [ "tcpip" ] + id: 1 + port: 1502 +render: | + type: modbus + model: sunspec + {{ include "modbus" . }} diff --git a/templates/definition/meter/solarlog.yaml b/templates/definition/meter/solarlog.yaml index fb305aa0a..bf9c56012 100644 --- a/templates/definition/meter/solarlog.yaml +++ b/templates/definition/meter/solarlog.yaml @@ -1,5 +1,6 @@ template: solarlog -description: Solarlog +description: + generic: Solarlog guidedsetup: enable: true params: diff --git a/templates/definition/meter/solarwatt-myreserve.yaml b/templates/definition/meter/solarwatt-myreserve.yaml index 9456bfb3e..1ad877eab 100644 --- a/templates/definition/meter/solarwatt-myreserve.yaml +++ b/templates/definition/meter/solarwatt-myreserve.yaml @@ -1,5 +1,6 @@ template: solarwatt-myreserve -description: Solarwatt MyReserve +description: + generic: Solarwatt MyReserve guidedsetup: enable: true params: diff --git a/templates/definition/meter/sonnenbatterie_eco10.yaml b/templates/definition/meter/sonnenbatterie_eco10.yaml index 45497330b..cd62979f4 100644 --- a/templates/definition/meter/sonnenbatterie_eco10.yaml +++ b/templates/definition/meter/sonnenbatterie_eco10.yaml @@ -1,5 +1,6 @@ template: sonnenbatterie-eco10 -description: Sonnenbatterie Eco/10 +description: + generic: Sonnenbatterie Eco/10 guidedsetup: enable: true params: diff --git a/templates/definition/meter/sungrow.yaml b/templates/definition/meter/sungrow.yaml new file mode 100644 index 000000000..ef0201478 --- /dev/null +++ b/templates/definition/meter/sungrow.yaml @@ -0,0 +1,39 @@ +template: sungrow +description: + generic: Sungrow (Beta) +guidedsetup: + enable: true +params: +- name: usage + choice: [ "grid", "pv", "battery" ] +- name: modbus + choice: [ "rs485", "tcpip" ] +render: | + type: custom + power: + source: modbus + {{include "modbus" . | indent 2}} + register: + type: input + {{- if eq .usage "grid" }} + address: 13009 # Export power + decode: int32s + scale: -1 + {{- end }} + {{- if eq .usage "pv" }} + address: 5016 # Total DC power + decode: uint32s + {{- end }} + {{- if eq .usage "battery" }} + address: 13021 # Battery power + decode: int16 + #scale: -1 # charging sign form 13000 & 0x2 + soc: + source: modbus + {{include "modbus" . | indent 2}} + register: + address: 13022 # Battery level + type: input + decode: int16 + scale: 0.1 + {{- end }} diff --git a/templates/definition/meter/sunspec.yaml b/templates/definition/meter/sunspec.yaml index 6d866ec5e..8f87ea803 100644 --- a/templates/definition/meter/sunspec.yaml +++ b/templates/definition/meter/sunspec.yaml @@ -1,5 +1,7 @@ template: sunspec -description: Inverter / Wechselrichter (SunSpec) +description: + de: Wechselrichter (SunSpec) + en: Inverter (SunSpec) generic: true params: - name: usage diff --git a/templates/definition/meter/tesla-powerwall.yaml b/templates/definition/meter/tesla-powerwall.yaml index c25a7b272..f0b3a7804 100644 --- a/templates/definition/meter/tesla-powerwall.yaml +++ b/templates/definition/meter/tesla-powerwall.yaml @@ -1,5 +1,6 @@ template: tesla-powerwall -description: Tesla Powerwall +description: + generic: Tesla Powerwall guidedsetup: enable: true params: diff --git a/templates/definition/meter/varta-energiespeicher.yaml b/templates/definition/meter/varta-energiespeicher.yaml index d42cbbead..19cb3fe86 100644 --- a/templates/definition/meter/varta-energiespeicher.yaml +++ b/templates/definition/meter/varta-energiespeicher.yaml @@ -1,5 +1,6 @@ template: varta-energiespeicher -description: VARTA Energiespeicher +description: + generic: VARTA Energiespeicher guidedsetup: enable: true params: diff --git a/templates/definition/meter/victron-energy.yaml b/templates/definition/meter/victron-energy.yaml new file mode 100644 index 000000000..d1e73c11d --- /dev/null +++ b/templates/definition/meter/victron-energy.yaml @@ -0,0 +1,69 @@ +template: victron-energy +description: + generic: Victron Energy +guidedsetup: + enable: true +params: +- name: usage + choice: [ "grid", "pv", "battery" ] +- name: host + required: true + example: 192.0.2.2 +- name: port + default: 502 +render: | + type: custom + power: + {{- if eq .usage "grid" }} + source: calc + add: + - source: modbus + uri: {{ .host }}:{{ .port }} + id: 50 # com.victronenergy.grid + register: + address: 2600 # L1 grid power + type: input + decode: int16 + - source: modbus + uri: {{ .host }}:{{ .port }} + id: 50 # com.victronenergy.grid + register: + address: 2601 # L2 grid power + type: input + decode: int16 + - source: modbus + uri: {{ .host }}:{{ .port }} + id: 50 # com.victronenergy.grid + register: + address: 2602 # L3 grid power + type: input + decode: int16 + {{- end }} + {{- if eq .usage "pv" }} + source: modbus + uri: {{ .host }}:{{ .port }} + id: 20 # com.victronenergy.pvinverter + register: + address: 1052 # Total AC Power + type: input + decode: int32 + {{- end }} + {{- if eq .usage "battery" }} + source: modbus + uri: {{ .host }}:{{ .port }} + id: 100 # com.victronenergy.system + register: + address: 842 # active DC power + type: input + decode: int16 + scale: -1 + soc: + source: modbus + uri: {{ .host }}:{{ .port }} + id: 225 # com.victronenergy.battery + register: + address: 266 # SoC + type: input + decode: uint16 + scale: 0.1 + {{- end }} diff --git a/templates/definition/meter/volkszaehler-http.yaml b/templates/definition/meter/volkszaehler-http.yaml index 84e0a4063..7effafdd7 100644 --- a/templates/definition/meter/volkszaehler-http.yaml +++ b/templates/definition/meter/volkszaehler-http.yaml @@ -1,5 +1,6 @@ template: volkszaehler-http -description: Volkszähler (HTTP API) +description: + generic: Volkszähler (HTTP API) generic: true params: - name: usage diff --git a/templates/definition/meter/volkszaehler-importexport.yaml b/templates/definition/meter/volkszaehler-importexport.yaml index 6c57e24cc..33a53c233 100644 --- a/templates/definition/meter/volkszaehler-importexport.yaml +++ b/templates/definition/meter/volkszaehler-importexport.yaml @@ -1,5 +1,6 @@ template: volkszaehler-importexport -description: Volkszähler (HTTP API, Import & Export) +description: + generic: Volkszähler (HTTP API, Import & Export) generic: true params: - name: usage diff --git a/templates/definition/meter/volkszaehler-ws.yaml b/templates/definition/meter/volkszaehler-ws.yaml index f57bb46ca..83b46dcf5 100644 --- a/templates/definition/meter/volkszaehler-ws.yaml +++ b/templates/definition/meter/volkszaehler-ws.yaml @@ -1,5 +1,6 @@ template: volkszaehler-ws -description: Volkszähler (WebSocket API) +description: + generic: Volkszähler (WebSocket API) generic: true params: - name: usage diff --git a/templates/definition/meter/vzlogger.yaml b/templates/definition/meter/vzlogger.yaml index 8ef3c2f39..1a287531b 100644 --- a/templates/definition/meter/vzlogger.yaml +++ b/templates/definition/meter/vzlogger.yaml @@ -1,5 +1,6 @@ template: vzlogger -description: vzlogger +description: + generic: vzlogger generic: true params: - name: usage diff --git a/templates/definition/vehicle/audi.yaml b/templates/definition/vehicle/audi.yaml index 863ce987b..9deb03080 100644 --- a/templates/definition/vehicle/audi.yaml +++ b/templates/definition/vehicle/audi.yaml @@ -1,5 +1,6 @@ template: audi -description: Audi +description: + generic: Audi params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/bmw.yaml b/templates/definition/vehicle/bmw.yaml index dbdaa9435..ebc640478 100644 --- a/templates/definition/vehicle/bmw.yaml +++ b/templates/definition/vehicle/bmw.yaml @@ -1,5 +1,6 @@ template: bmw -description: BMW +description: + generic: BMW params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/carwings.yaml b/templates/definition/vehicle/carwings.yaml index 4333e2f60..76b368d73 100644 --- a/templates/definition/vehicle/carwings.yaml +++ b/templates/definition/vehicle/carwings.yaml @@ -1,5 +1,6 @@ template: carwings -description: Nissan Leaf (pre 2019) +description: + generic: Nissan Leaf (pre 2019) params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/citroen.yaml b/templates/definition/vehicle/citroen.yaml index deb2b78e1..2077ee400 100644 --- a/templates/definition/vehicle/citroen.yaml +++ b/templates/definition/vehicle/citroen.yaml @@ -1,5 +1,6 @@ template: citroen -description: Citroen +description: + generic: Citroen params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/dacia.yaml b/templates/definition/vehicle/dacia.yaml index a78bc3558..182636786 100644 --- a/templates/definition/vehicle/dacia.yaml +++ b/templates/definition/vehicle/dacia.yaml @@ -1,5 +1,6 @@ template: dacia -description: Dacia +description: + generic: Dacia params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/ds.yaml b/templates/definition/vehicle/ds.yaml index 7c1ff91b7..81e81b699 100644 --- a/templates/definition/vehicle/ds.yaml +++ b/templates/definition/vehicle/ds.yaml @@ -1,5 +1,6 @@ template: ds -description: DS +description: + generic: DS params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/evnotify.yaml b/templates/definition/vehicle/evnotify.yaml index f2101d60c..cea1b6fb7 100644 --- a/templates/definition/vehicle/evnotify.yaml +++ b/templates/definition/vehicle/evnotify.yaml @@ -1,5 +1,7 @@ template: evnotify -description: evNotify +description: + generic: evNotify +generic: true params: - name: title - name: akey diff --git a/templates/definition/vehicle/fiat.yaml b/templates/definition/vehicle/fiat.yaml index 937c2de57..8fc58367e 100644 --- a/templates/definition/vehicle/fiat.yaml +++ b/templates/definition/vehicle/fiat.yaml @@ -1,5 +1,6 @@ template: fiat -description: Fiat +description: + generic: Fiat params: - base: vehiclebase - name: vin diff --git a/templates/definition/vehicle/ford.yaml b/templates/definition/vehicle/ford.yaml index a85f07898..0d2d0ae92 100644 --- a/templates/definition/vehicle/ford.yaml +++ b/templates/definition/vehicle/ford.yaml @@ -1,5 +1,6 @@ template: ford -description: Ford +description: + generic: Ford params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/hyundai.yaml b/templates/definition/vehicle/hyundai.yaml index 1b7485475..de7daddc1 100644 --- a/templates/definition/vehicle/hyundai.yaml +++ b/templates/definition/vehicle/hyundai.yaml @@ -1,5 +1,6 @@ template: hyundai -description: Hyundai +description: + generic: Hyundai params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/kia.yaml b/templates/definition/vehicle/kia.yaml index 437c404f3..4e79d48f2 100644 --- a/templates/definition/vehicle/kia.yaml +++ b/templates/definition/vehicle/kia.yaml @@ -1,5 +1,6 @@ template: kia -description: Kia +description: + generic: Kia params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/mini.yaml b/templates/definition/vehicle/mini.yaml index 1a92ae454..ba428a9c6 100644 --- a/templates/definition/vehicle/mini.yaml +++ b/templates/definition/vehicle/mini.yaml @@ -1,5 +1,6 @@ template: mini -description: Mini +description: + generic: Mini params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/nissan.yaml b/templates/definition/vehicle/nissan.yaml index 303535532..91fdfc105 100644 --- a/templates/definition/vehicle/nissan.yaml +++ b/templates/definition/vehicle/nissan.yaml @@ -1,5 +1,6 @@ template: nissan -description: Nissan +description: + generic: Nissan params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/niu-e-scooter.yaml b/templates/definition/vehicle/niu-e-scooter.yaml index c2bbf8595..d97939e40 100644 --- a/templates/definition/vehicle/niu-e-scooter.yaml +++ b/templates/definition/vehicle/niu-e-scooter.yaml @@ -1,5 +1,6 @@ template: niu-e-scooter -description: NIU E-Scooter +description: + generic: NIU E-Scooter params: - name: title - name: user diff --git a/templates/definition/vehicle/opel.yaml b/templates/definition/vehicle/opel.yaml index fa809f84f..89ede3a24 100644 --- a/templates/definition/vehicle/opel.yaml +++ b/templates/definition/vehicle/opel.yaml @@ -1,5 +1,6 @@ template: opel -description: Opel +description: + generic: Opel params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/ovms.yaml b/templates/definition/vehicle/ovms.yaml index 463e7661e..ae81c0e51 100644 --- a/templates/definition/vehicle/ovms.yaml +++ b/templates/definition/vehicle/ovms.yaml @@ -1,5 +1,7 @@ template: ovms -description: Open Vehicle Monitoring System +description: + generic: Open Vehicle Monitoring System +generic: true params: - name: title - name: user diff --git a/templates/definition/vehicle/peugeot.yaml b/templates/definition/vehicle/peugeot.yaml index 2a9eef928..06ddaf91d 100644 --- a/templates/definition/vehicle/peugeot.yaml +++ b/templates/definition/vehicle/peugeot.yaml @@ -1,5 +1,6 @@ template: peugeot -description: Peugeot +description: + generic: Peugeot params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/porsche.yaml b/templates/definition/vehicle/porsche.yaml index a9afa229a..8b49a0732 100644 --- a/templates/definition/vehicle/porsche.yaml +++ b/templates/definition/vehicle/porsche.yaml @@ -1,5 +1,6 @@ template: porsche -description: Porsche +description: + generic: Porsche params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/renault.yaml b/templates/definition/vehicle/renault.yaml index e6dab8de3..77e88551a 100644 --- a/templates/definition/vehicle/renault.yaml +++ b/templates/definition/vehicle/renault.yaml @@ -1,5 +1,6 @@ template: renault -description: Renault +description: + generic: Renault params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/seat.yaml b/templates/definition/vehicle/seat.yaml index 8c727fb78..ea0b8da43 100644 --- a/templates/definition/vehicle/seat.yaml +++ b/templates/definition/vehicle/seat.yaml @@ -1,5 +1,6 @@ template: seat -description: Seat (Cupra, Mii) +description: + generic: Seat (Cupra, Mii) params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/skoda.yaml b/templates/definition/vehicle/skoda.yaml index 69386ba41..ad05f2639 100644 --- a/templates/definition/vehicle/skoda.yaml +++ b/templates/definition/vehicle/skoda.yaml @@ -1,5 +1,6 @@ template: skoda -description: Skoda (Citigo) +description: + generic: Skoda (Citigo) params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/skodaenyaq.yaml b/templates/definition/vehicle/skodaenyaq.yaml index e9eef716c..775d5c930 100644 --- a/templates/definition/vehicle/skodaenyaq.yaml +++ b/templates/definition/vehicle/skodaenyaq.yaml @@ -1,5 +1,6 @@ template: enyaq -description: Skoda (Enyaq) +description: + generic: Skoda (Enyaq) params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/tesla.yaml b/templates/definition/vehicle/tesla.yaml index 229b223d5..13b6d0a31 100644 --- a/templates/definition/vehicle/tesla.yaml +++ b/templates/definition/vehicle/tesla.yaml @@ -1,5 +1,6 @@ template: tesla -description: Tesla +description: + generic: Tesla params: - name: title - name: accessToken diff --git a/templates/definition/vehicle/tronity.yaml b/templates/definition/vehicle/tronity.yaml index 9a1ba905e..7c8e0d734 100644 --- a/templates/definition/vehicle/tronity.yaml +++ b/templates/definition/vehicle/tronity.yaml @@ -1,5 +1,7 @@ template: tronity -description: Tronity +description: + generic: Tronity +generic: true requirements: sponsorship: true params: diff --git a/templates/definition/vehicle/volvo.yaml b/templates/definition/vehicle/volvo.yaml index 380250cd4..ffc41e446 100644 --- a/templates/definition/vehicle/volvo.yaml +++ b/templates/definition/vehicle/volvo.yaml @@ -1,5 +1,6 @@ template: volvo -description: Volvo +description: + generic: Volvo params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/vw.yaml b/templates/definition/vehicle/vw.yaml index e4099df77..441a239f3 100644 --- a/templates/definition/vehicle/vw.yaml +++ b/templates/definition/vehicle/vw.yaml @@ -1,5 +1,6 @@ template: vw -description: Volkswagen (We Connect) +description: + generic: Volkswagen (We Connect) params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/definition/vehicle/vwid.yaml b/templates/definition/vehicle/vwid.yaml index c7c14c4e0..35dc0e41a 100644 --- a/templates/definition/vehicle/vwid.yaml +++ b/templates/definition/vehicle/vwid.yaml @@ -1,5 +1,6 @@ template: id -description: Volkswagen (We Connect ID) +description: + generic: Volkswagen (We Connect ID) params: - base: vehiclebase - base: vehicleidentify diff --git a/templates/docs/charger/cfos_charger.yaml b/templates/docs/charger/cfos.yaml similarity index 53% rename from templates/docs/charger/cfos_charger.yaml rename to templates/docs/charger/cfos.yaml index 29f6afacf..e9b8bd564 100644 --- a/templates/docs/charger/cfos_charger.yaml +++ b/templates/docs/charger/cfos.yaml @@ -1,4 +1,4 @@ type: template -template: cfos_charger +template: cfos description: cFos PowerBrain host: 192.0.2.2 \ No newline at end of file diff --git a/templates/docs/charger/wallbe-meter.yaml b/templates/docs/charger/wallbe-meter.yaml index 706027628..3436bb40f 100644 --- a/templates/docs/charger/wallbe-meter.yaml +++ b/templates/docs/charger/wallbe-meter.yaml @@ -1,5 +1,5 @@ type: template template: wallbe-meter -description: Wallbe (Eco, Pro) with Meter +description: Wallbe (Eco, Pro) mit Strommessgerät host: 192.0.2.2 port: 502 \ No newline at end of file diff --git a/templates/docs/charger/wallbe-pre2019-meter.yaml b/templates/docs/charger/wallbe-pre2019-meter.yaml index 4c707e9d5..52603fb04 100644 --- a/templates/docs/charger/wallbe-pre2019-meter.yaml +++ b/templates/docs/charger/wallbe-pre2019-meter.yaml @@ -1,5 +1,5 @@ type: template template: wallbe-pre2019-meter -description: Wallbe (Eco, Pro) (pre ~2019) with Meter +description: Wallbe (Eco, Pro) (vor ~2019) mit Strommessgerät host: 192.0.2.2 port: 502 \ No newline at end of file diff --git a/templates/docs/charger/wallbe-pre2019.yaml b/templates/docs/charger/wallbe-pre2019.yaml index d1f7e8ac3..49eadb4a3 100644 --- a/templates/docs/charger/wallbe-pre2019.yaml +++ b/templates/docs/charger/wallbe-pre2019.yaml @@ -1,5 +1,5 @@ type: template template: wallbe-pre2019 -description: Wallbe (Eco, Pro) (pre ~2019) +description: Wallbe (Eco, Pro) (vor ~2019) host: 192.0.2.2 port: 502 \ No newline at end of file diff --git a/templates/docs/meter/cfos-meter-charge.yaml b/templates/docs/meter/cfos-charge.yaml similarity index 59% rename from templates/docs/meter/cfos-meter-charge.yaml rename to templates/docs/meter/cfos-charge.yaml index 716790ce8..c47b403a7 100644 --- a/templates/docs/meter/cfos-meter-charge.yaml +++ b/templates/docs/meter/cfos-charge.yaml @@ -1,4 +1,4 @@ type: template -template: cfos-meter +template: cfos description: cFos PowerBrain Meter usage: charge \ No newline at end of file diff --git a/templates/docs/meter/eastron-battery.yaml b/templates/docs/meter/eastron-battery.yaml index 2fef1fa1c..da4f1e7dd 100644 --- a/templates/docs/meter/eastron-battery.yaml +++ b/templates/docs/meter/eastron-battery.yaml @@ -1,4 +1,4 @@ type: template template: eastron -description: Eastron SDM Modbus Meter +description: Eastron SDM Modbus Strommessgeräte usage: battery \ No newline at end of file diff --git a/templates/docs/meter/eastron-charge.yaml b/templates/docs/meter/eastron-charge.yaml index d835a6a02..d08b9b75c 100644 --- a/templates/docs/meter/eastron-charge.yaml +++ b/templates/docs/meter/eastron-charge.yaml @@ -1,4 +1,4 @@ type: template template: eastron -description: Eastron SDM Modbus Meter +description: Eastron SDM Modbus Strommessgeräte usage: charge \ No newline at end of file diff --git a/templates/docs/meter/eastron-grid.yaml b/templates/docs/meter/eastron-grid.yaml index cbc64a895..08168f2f0 100644 --- a/templates/docs/meter/eastron-grid.yaml +++ b/templates/docs/meter/eastron-grid.yaml @@ -1,4 +1,4 @@ type: template template: eastron -description: Eastron SDM Modbus Meter +description: Eastron SDM Modbus Strommessgeräte usage: grid \ No newline at end of file diff --git a/templates/docs/meter/eastron-pv.yaml b/templates/docs/meter/eastron-pv.yaml index 3b2df884f..190e2574f 100644 --- a/templates/docs/meter/eastron-pv.yaml +++ b/templates/docs/meter/eastron-pv.yaml @@ -1,4 +1,4 @@ type: template template: eastron -description: Eastron SDM Modbus Meter +description: Eastron SDM Modbus Strommessgeräte usage: pv \ No newline at end of file diff --git a/templates/docs/meter/fritzdect-charge.yaml b/templates/docs/meter/fritzdect-charge.yaml index 59d217693..4ec8ce1b6 100644 --- a/templates/docs/meter/fritzdect-charge.yaml +++ b/templates/docs/meter/fritzdect-charge.yaml @@ -5,5 +5,4 @@ usage: charge uri: https://fritz.box user: password: -ain: 007788992233 # Die AIN ist auf dem Typenschild auf der Geräterückseite aufgedruckt. -standbypower: 15 \ No newline at end of file +ain: 007788992233 # Die AIN ist auf dem Typenschild auf der Geräterückseite aufgedruckt. \ No newline at end of file diff --git a/templates/docs/meter/fritzdect-pv.yaml b/templates/docs/meter/fritzdect-pv.yaml index 99f87626a..45700aa03 100644 --- a/templates/docs/meter/fritzdect-pv.yaml +++ b/templates/docs/meter/fritzdect-pv.yaml @@ -5,5 +5,4 @@ usage: pv uri: https://fritz.box user: password: -ain: 007788992233 # Die AIN ist auf dem Typenschild auf der Geräterückseite aufgedruckt. -standbypower: 15 \ No newline at end of file +ain: 007788992233 # Die AIN ist auf dem Typenschild auf der Geräterückseite aufgedruckt. \ No newline at end of file diff --git a/templates/docs/meter/kostal-ksem-inverter-grid.yaml b/templates/docs/meter/kostal-ksem-inverter-grid.yaml index a8b93b2e5..c24333d39 100644 --- a/templates/docs/meter/kostal-ksem-inverter-grid.yaml +++ b/templates/docs/meter/kostal-ksem-inverter-grid.yaml @@ -1,4 +1,4 @@ type: template template: kostal-ksem-inverter -description: Kostal Smart Energy Meter via inverter +description: Kostal Smart Energy Meter über den Wechselrichter usage: grid \ No newline at end of file diff --git a/templates/docs/meter/mqtt-meter-battery.yaml b/templates/docs/meter/mqtt-meter-battery.yaml new file mode 100644 index 000000000..35b9ba7ed --- /dev/null +++ b/templates/docs/meter/mqtt-meter-battery.yaml @@ -0,0 +1,8 @@ +type: template +template: mqtt-meter +description: MQTT Strommessgerät +usage: battery +power: +scalepower: 1 # Die Leistung wird in Watt erwartet. Falls z.b. kW geliefert wird, kann dies hier mit dem Wert 1000 angepasst werden +scaleenergy: 1 # Die Energiemenge wird in kWh erwartet. Falls z.b. Wh geliefert wird, kann dies hier mit dem Wert 0.001 angepasst werden +timeout: 30 # Akzeptiere keine Daten die älter als dieser Wert in Sekunden ist \ No newline at end of file diff --git a/templates/docs/meter/mqtt-meter-charge.yaml b/templates/docs/meter/mqtt-meter-charge.yaml new file mode 100644 index 000000000..71ba2f291 --- /dev/null +++ b/templates/docs/meter/mqtt-meter-charge.yaml @@ -0,0 +1,8 @@ +type: template +template: mqtt-meter +description: MQTT Strommessgerät +usage: charge +power: +scalepower: 1 # Die Leistung wird in Watt erwartet. Falls z.b. kW geliefert wird, kann dies hier mit dem Wert 1000 angepasst werden +scaleenergy: 1 # Die Energiemenge wird in kWh erwartet. Falls z.b. Wh geliefert wird, kann dies hier mit dem Wert 0.001 angepasst werden +timeout: 30 # Akzeptiere keine Daten die älter als dieser Wert in Sekunden ist \ No newline at end of file diff --git a/templates/docs/meter/mqtt-meter-grid.yaml b/templates/docs/meter/mqtt-meter-grid.yaml new file mode 100644 index 000000000..081edad49 --- /dev/null +++ b/templates/docs/meter/mqtt-meter-grid.yaml @@ -0,0 +1,8 @@ +type: template +template: mqtt-meter +description: MQTT Strommessgerät +usage: grid +power: +scalepower: 1 # Die Leistung wird in Watt erwartet. Falls z.b. kW geliefert wird, kann dies hier mit dem Wert 1000 angepasst werden +scaleenergy: 1 # Die Energiemenge wird in kWh erwartet. Falls z.b. Wh geliefert wird, kann dies hier mit dem Wert 0.001 angepasst werden +timeout: 30 # Akzeptiere keine Daten die älter als dieser Wert in Sekunden ist \ No newline at end of file diff --git a/templates/docs/meter/mqtt-meter-pv.yaml b/templates/docs/meter/mqtt-meter-pv.yaml new file mode 100644 index 000000000..e56759c40 --- /dev/null +++ b/templates/docs/meter/mqtt-meter-pv.yaml @@ -0,0 +1,8 @@ +type: template +template: mqtt-meter +description: MQTT Strommessgerät +usage: pv +power: +scalepower: 1 # Die Leistung wird in Watt erwartet. Falls z.b. kW geliefert wird, kann dies hier mit dem Wert 1000 angepasst werden +scaleenergy: 1 # Die Energiemenge wird in kWh erwartet. Falls z.b. Wh geliefert wird, kann dies hier mit dem Wert 0.001 angepasst werden +timeout: 30 # Akzeptiere keine Daten die älter als dieser Wert in Sekunden ist \ No newline at end of file diff --git a/templates/docs/meter/sma-energy-meter-battery.yaml b/templates/docs/meter/sma-energy-meter-battery.yaml index a7ccb34f5..f16464a0b 100644 --- a/templates/docs/meter/sma-energy-meter-battery.yaml +++ b/templates/docs/meter/sma-energy-meter-battery.yaml @@ -1,5 +1,5 @@ type: template template: sma-energy-meter -description: SMA Energy Meter +description: SMA Energy Meter (Produktname) usage: battery host: 192.0.2.2 \ No newline at end of file diff --git a/templates/docs/meter/sma-energy-meter-grid.yaml b/templates/docs/meter/sma-energy-meter-grid.yaml index 0041dd7f5..e7a2c7569 100644 --- a/templates/docs/meter/sma-energy-meter-grid.yaml +++ b/templates/docs/meter/sma-energy-meter-grid.yaml @@ -1,5 +1,5 @@ type: template template: sma-energy-meter -description: SMA Energy Meter +description: SMA Energy Meter (Produktname) usage: grid host: 192.0.2.2 \ No newline at end of file diff --git a/templates/docs/meter/sma-energy-meter-pv.yaml b/templates/docs/meter/sma-energy-meter-pv.yaml index a67d886a1..390b4fae9 100644 --- a/templates/docs/meter/sma-energy-meter-pv.yaml +++ b/templates/docs/meter/sma-energy-meter-pv.yaml @@ -1,5 +1,5 @@ type: template template: sma-energy-meter -description: SMA Energy Meter +description: SMA Energy Meter (Produktname) usage: pv host: 192.0.2.2 \ No newline at end of file diff --git a/templates/docs/meter/sma-inverter-battery.yaml b/templates/docs/meter/sma-inverter-battery.yaml index a3df62e64..322a3f4d8 100644 --- a/templates/docs/meter/sma-inverter-battery.yaml +++ b/templates/docs/meter/sma-inverter-battery.yaml @@ -1,5 +1,5 @@ type: template template: sma-inverter -description: SMA Inverter/Wechselrichter +description: SMA Wechselrichter usage: battery host: 192.0.2.2 \ No newline at end of file diff --git a/templates/docs/meter/sma-inverter-pv.yaml b/templates/docs/meter/sma-inverter-pv.yaml index bf885f385..73a3640cc 100644 --- a/templates/docs/meter/sma-inverter-pv.yaml +++ b/templates/docs/meter/sma-inverter-pv.yaml @@ -1,5 +1,5 @@ type: template template: sma-inverter -description: SMA Inverter/Wechselrichter +description: SMA Wechselrichter usage: pv host: 192.0.2.2 \ No newline at end of file diff --git a/templates/docs/meter/solaredge-inverter-pv.yaml b/templates/docs/meter/solaredge-inverter-pv.yaml new file mode 100644 index 000000000..ebc5e557a --- /dev/null +++ b/templates/docs/meter/solaredge-inverter-pv.yaml @@ -0,0 +1,4 @@ +type: template +template: solaredge-inverter +description: Solaredge Wechselrichter +usage: pv \ No newline at end of file diff --git a/templates/docs/meter/sungrow-battery.yaml b/templates/docs/meter/sungrow-battery.yaml new file mode 100644 index 000000000..b8797fed2 --- /dev/null +++ b/templates/docs/meter/sungrow-battery.yaml @@ -0,0 +1,4 @@ +type: template +template: sungrow +description: Sungrow (Beta) +usage: battery \ No newline at end of file diff --git a/templates/docs/meter/sungrow-grid.yaml b/templates/docs/meter/sungrow-grid.yaml new file mode 100644 index 000000000..3e06f823f --- /dev/null +++ b/templates/docs/meter/sungrow-grid.yaml @@ -0,0 +1,4 @@ +type: template +template: sungrow +description: Sungrow (Beta) +usage: grid \ No newline at end of file diff --git a/templates/docs/meter/sungrow-pv.yaml b/templates/docs/meter/sungrow-pv.yaml new file mode 100644 index 000000000..cba151278 --- /dev/null +++ b/templates/docs/meter/sungrow-pv.yaml @@ -0,0 +1,4 @@ +type: template +template: sungrow +description: Sungrow (Beta) +usage: pv \ No newline at end of file diff --git a/templates/docs/meter/sunspec-battery.yaml b/templates/docs/meter/sunspec-battery.yaml index c2e5bc540..4e1a23ec2 100644 --- a/templates/docs/meter/sunspec-battery.yaml +++ b/templates/docs/meter/sunspec-battery.yaml @@ -1,4 +1,4 @@ type: template template: sunspec -description: Inverter / Wechselrichter (SunSpec) +description: Wechselrichter (SunSpec) usage: battery \ No newline at end of file diff --git a/templates/docs/meter/sunspec-grid.yaml b/templates/docs/meter/sunspec-grid.yaml index b90a5a35b..cc3da840e 100644 --- a/templates/docs/meter/sunspec-grid.yaml +++ b/templates/docs/meter/sunspec-grid.yaml @@ -1,4 +1,4 @@ type: template template: sunspec -description: Inverter / Wechselrichter (SunSpec) +description: Wechselrichter (SunSpec) usage: grid \ No newline at end of file diff --git a/templates/docs/meter/sunspec-pv.yaml b/templates/docs/meter/sunspec-pv.yaml index e5770741e..095a838c7 100644 --- a/templates/docs/meter/sunspec-pv.yaml +++ b/templates/docs/meter/sunspec-pv.yaml @@ -1,4 +1,4 @@ type: template template: sunspec -description: Inverter / Wechselrichter (SunSpec) +description: Wechselrichter (SunSpec) usage: pv \ No newline at end of file diff --git a/templates/docs/meter/victron-energy-battery.yaml b/templates/docs/meter/victron-energy-battery.yaml new file mode 100644 index 000000000..c31f8f5dd --- /dev/null +++ b/templates/docs/meter/victron-energy-battery.yaml @@ -0,0 +1,6 @@ +type: template +template: victron-energy +description: Victron Energy +usage: battery +host: 192.0.2.2 +port: 502 \ No newline at end of file diff --git a/templates/docs/meter/victron-energy-grid.yaml b/templates/docs/meter/victron-energy-grid.yaml new file mode 100644 index 000000000..ed71e1b29 --- /dev/null +++ b/templates/docs/meter/victron-energy-grid.yaml @@ -0,0 +1,6 @@ +type: template +template: victron-energy +description: Victron Energy +usage: grid +host: 192.0.2.2 +port: 502 \ No newline at end of file diff --git a/templates/docs/meter/victron-energy-pv.yaml b/templates/docs/meter/victron-energy-pv.yaml new file mode 100644 index 000000000..a86b3e0e6 --- /dev/null +++ b/templates/docs/meter/victron-energy-pv.yaml @@ -0,0 +1,6 @@ +type: template +template: victron-energy +description: Victron Energy +usage: pv +host: 192.0.2.2 +port: 502 \ No newline at end of file diff --git a/util/templates/generate/generate.go b/util/templates/generate/generate.go index 5e8e2a76a..3a3bccf37 100644 --- a/util/templates/generate/generate.go +++ b/util/templates/generate/generate.go @@ -61,7 +61,7 @@ func generateClass(class string) error { } func writeTemplate(class string, tmpl templates.Template, usage string) error { - values := tmpl.Defaults(true) + values := tmpl.Defaults(templates.TemplateRenderModeDocs) if usage != "" { values["usage"] = usage @@ -78,7 +78,7 @@ func writeTemplate(class string, tmpl templates.Template, usage string) error { values[templates.ModbusTCPIP] = true } } - b, err := tmpl.RenderProxyWithValues(values, true) + b, err := tmpl.RenderProxyWithValues(values, "de", true) if err != nil { println(string(b)) diff --git a/util/templates/modbus.tpl b/util/templates/modbus.tpl index bf4ef5daa..aac91cdba 100644 --- a/util/templates/modbus.tpl +++ b/util/templates/modbus.tpl @@ -1,4 +1,4 @@ -{{define "modbus"}} +{{- define "modbus"}} id: {{ .id }} {{- if or (eq .modbus "rs485serial") .modbusrs485serial }} # RS485 via adapter: @@ -15,4 +15,4 @@ rtu: true # serial modbus rtu (rs485) device connected using simple ethernet ada # TCPIP uri: {{ .host }}:{{ .port }} {{- end }} -{{end}} \ No newline at end of file +{{- end}} diff --git a/util/templates/template.go b/util/templates/template.go index 2fddc6b80..c068b5a7f 100644 --- a/util/templates/template.go +++ b/util/templates/template.go @@ -49,6 +49,10 @@ const ( ModbusParamNamePort = "port" ModbusParamValuePort = 502 ModbusParamNameRTU = "rtu" + + TemplateRenderModeDocs = "docs" + TemplateRenderModeUnitTest = "unittest" + TemplateRenderModeInstance = "instance" ) var HemsValueTypes = []string{HemsTypeSMA} @@ -62,18 +66,35 @@ const ( ParamValueTypeChargeModes = "chargemodes" ) +const ( + DependencyCheckEmpty = "empty" + DependencyCheckNotEmpty = "notempty" + DependencyCheckEqual = "equal" +) + var ParamValueTypes = []string{ParamValueTypeString, ParamValueTypeNumber, ParamValueTypeFloat, ParamValueTypeBool, ParamValueTypeStringList, ParamValueTypeChargeModes} var ValidModbusChoices = []string{ModbusChoiceRS485, ModbusChoiceTCPIP} var ValidUsageChoices = []string{UsageChoiceGrid, UsageChoicePV, UsageChoiceBattery, UsageChoiceCharge} +var predefinedTemplateProperties = []string{"type", "template", "name", + ModbusParamNameId, ModbusParamNameDevice, ModbusParamNameBaudrate, ModbusParamNameComset, + ModbusParamNameURI, ModbusParamNameHost, ModbusParamNamePort, ModbusParamNameRTU, + ModbusRS485Serial, ModbusRS485TCPIP, ModbusTCPIP, + ModbusKeyTCPIP, ModbusKeyRS485Serial, ModbusKeyRS485TCPIP, +} + // language specific texts type TextLanguage struct { - DE string // german text - EN string // english text + Generic string // language independent + DE string // german text + EN string // english text } func (t *TextLanguage) String(lang string) string { + if t.Generic != "" { + return t.Generic + } switch lang { case "de": return t.DE @@ -94,10 +115,16 @@ func (t *TextLanguage) SetString(lang, value string) { } } +// Capabilities +type Capabilities struct { + ISO151182 bool // ISO 15118-2 support +} + // Requirements type Requirements struct { Hems string // HEMS Type Eebus bool // EEBUS Setup is required + Mqtt bool // MQTT Setup is required Sponsorship bool // Sponsorship is required Description TextLanguage // Description of requirements, e.g. how the device needs to be prepared URI string // URI to a webpage with more details about the preparation requirements @@ -116,26 +143,34 @@ type LinkedTemplate struct { ExcludeTemplate string // only consider this if no device of the named linked template was added } +type Dependency struct { + Name string // the Param name value this depends on + Check string // the check to perform, valid values see const DependencyCheck... + Value string // the string value to check against +} + // Param is a proxy template parameter type Param struct { - Base string // Reference a predefined se of params - Name string // Param name which is used for assigning defaults properties and referencing in render - Required bool // cli if the user has to provide a non empty value - Mask bool // cli if the value should be masked, e.g. for passwords - Advanced bool // cli if the user does not need to be asked. Requires a "Default" to be defined. - Default string // default value if no user value is provided in the configuration - Example string // cli example value - Help TextLanguage // cli configuration help - Test string // testing default value - Value string // user provided value via cli configuration - Values []string // user provided list of values - ValueType string // string representation of the value type, "string" is default - Choice []string // defines which usage choices this config supports, valid elemtents are "grid", "pv", "battery", "charge" - Usages []string - Baudrate int // device specific default for modbus RS485 baudrate - Comset string // device specific default for modbus RS485 comset - Port int // device specific default for modbus TCPIP port - ID int // device specific default for modbus ID + Base string // Reference a predefined se of params + Name string // Param name which is used for assigning defaults properties and referencing in render + Description TextLanguage // language specific titles (presented in UI instead of Name) + Dependencies []Dependency // List of dependencies, when this param should be presented + Required bool // cli if the user has to provide a non empty value + Mask bool // cli if the value should be masked, e.g. for passwords + Advanced bool // cli if the user does not need to be asked. Requires a "Default" to be defined. + Default string // default value if no user value is provided in the configuration + Example string // cli example value + Help TextLanguage // cli configuration help + Test string // testing default value + Value string // user provided value via cli configuration + Values []string // user provided list of values + ValueType string // string representation of the value type, "string" is default + Choice []string // defines which usage choices this config supports, valid elemtents are "grid", "pv", "battery", "charge" + Usages []string + Baudrate int // device specific default for modbus RS485 baudrate + Comset string // device specific default for modbus RS485 comset + Port int // device specific default for modbus TCPIP port + ID int // device specific default for modbus ID } type ParamBase struct { @@ -148,7 +183,8 @@ var paramBaseList map[string]ParamBase // Template describes is a proxy device for use with cli and automated testing type Template struct { Template string - Description string // user friendly description of the device this template describes + Description TextLanguage // user friendly description of the device this template describes + Capabilities Capabilities Requirements Requirements GuidedSetup GuidedSetup Generic bool // if this describes a generic device type rather than a product @@ -200,7 +236,7 @@ func (t *Template) ResolveParamBases() error { continue } - if i, item := t.paramWithName(p.Name); item != nil { + if i, item := t.ParamByName(p.Name); item != nil { // we only allow overwriting a few fields if p.Default != "" { t.Params[i].Default = p.Default @@ -217,7 +253,7 @@ func (t *Template) ResolveParamBases() error { } // Defaults returns a map of default values for the template -func (t *Template) Defaults(docsOrTests bool) map[string]interface{} { +func (t *Template) Defaults(renderMode string) map[string]interface{} { values := make(map[string]interface{}) for _, p := range t.Params { switch p.ValueType { @@ -228,7 +264,7 @@ func (t *Template) Defaults(docsOrTests bool) map[string]interface{} { default: if p.Test != "" { values[p.Name] = p.Test - } else if p.Example != "" && docsOrTests { + } else if p.Example != "" && funk.ContainsString([]string{TemplateRenderModeDocs, TemplateRenderModeUnitTest}, renderMode) { values[p.Name] = p.Example } else { values[p.Name] = p.Default // may be empty @@ -240,7 +276,7 @@ func (t *Template) Defaults(docsOrTests bool) map[string]interface{} { } // return the param with the given name -func (t *Template) paramWithName(name string) (int, *Param) { +func (t *Template) ParamByName(name string) (int, *Param) { for i, p := range t.Params { if p.Name == name { return i, &p @@ -251,7 +287,7 @@ func (t *Template) paramWithName(name string) (int, *Param) { // Usages returns the list of supported usages func (t *Template) Usages() []string { - if _, p := t.paramWithName(ParamUsage); p != nil { + if _, p := t.ParamByName(ParamUsage); p != nil { return p.Choice } @@ -259,7 +295,7 @@ func (t *Template) Usages() []string { } func (t *Template) ModbusChoices() []string { - if _, p := t.paramWithName(ParamModbus); p != nil { + if _, p := t.ParamByName(ParamModbus); p != nil { return p.Choice } @@ -270,7 +306,7 @@ func (t *Template) ModbusChoices() []string { var proxyTmpl string // RenderProxy renders the proxy template -func (t *Template) RenderProxyWithValues(values map[string]interface{}, includeDescription bool) ([]byte, error) { +func (t *Template) RenderProxyWithValues(values map[string]interface{}, lang string, includeDescription bool) ([]byte, error) { tmpl, err := template.New("yaml").Funcs(template.FuncMap(sprig.FuncMap())).Parse(proxyTmpl) if err != nil { panic(err) @@ -326,7 +362,7 @@ func (t *Template) RenderProxyWithValues(values map[string]interface{}, includeD "Params": t.Params, } if includeDescription { - data["Description"] = t.Description + data["Description"] = t.Description.String(lang) } err = tmpl.Execute(out, data) @@ -334,13 +370,13 @@ func (t *Template) RenderProxyWithValues(values map[string]interface{}, includeD } // RenderResult renders the result template to instantiate the proxy -func (t *Template) RenderResult(docs bool, other map[string]interface{}) ([]byte, map[string]interface{}, error) { - values := t.Defaults(docs) +func (t *Template) RenderResult(renderMode string, other map[string]interface{}) ([]byte, map[string]interface{}, error) { + values := t.Defaults(renderMode) if err := util.DecodeOther(other, &values); err != nil { return nil, values, err } - t.ModbusValues(values) + t.ModbusValues(renderMode, values) // add the common templates for _, v := range paramBaseList { @@ -350,6 +386,11 @@ func (t *Template) RenderResult(docs bool, other map[string]interface{}) ([]byte } for item, p := range values { + _, param := t.ParamByName(item) + if param == nil && !funk.ContainsString(predefinedTemplateProperties, item) { + return nil, values, fmt.Errorf("invalid element 'name: %s'", item) + } + switch p := p.(type) { case []interface{}: var list []string diff --git a/util/templates/template_modbus.go b/util/templates/template_modbus.go index 9a286a7d7..45a30b13f 100644 --- a/util/templates/template_modbus.go +++ b/util/templates/template_modbus.go @@ -48,7 +48,7 @@ func (t *Template) ModbusParams(values map[string]interface{}) { } // set the modbus values required from modbus.tpl and and the template to the render -func (t *Template) ModbusValues(values map[string]interface{}) { +func (t *Template) ModbusValues(renderMode string, values map[string]interface{}) { if len(t.ModbusChoices()) == 0 { return } @@ -105,13 +105,15 @@ func (t *Template) ModbusValues(values map[string]interface{}) { } } - if funk.ContainsString(p.Choice, ModbusChoiceRS485) { - values[ModbusRS485Serial] = true - values[ModbusRS485TCPIP] = true - } + if renderMode == TemplateRenderModeDocs { + if funk.ContainsString(p.Choice, ModbusChoiceRS485) { + values[ModbusRS485Serial] = true + values[ModbusRS485TCPIP] = true + } - if funk.ContainsString(p.Choice, ModbusChoiceTCPIP) { - values[ModbusTCPIP] = true + if funk.ContainsString(p.Choice, ModbusChoiceTCPIP) { + values[ModbusTCPIP] = true + } } } } diff --git a/vehicle/template.go b/vehicle/template.go index 0de82c7d1..bfb27ecdf 100644 --- a/vehicle/template.go +++ b/vehicle/template.go @@ -26,7 +26,7 @@ func NewVehicleFromTemplateConfig(other map[string]interface{}) (api.Vehicle, er return nil, err } - b, _, err := tmpl.RenderResult(false, other) + b, _, err := tmpl.RenderResult(templates.TemplateRenderModeInstance, other) if err != nil { return nil, err } diff --git a/vehicle/template_test.go b/vehicle/template_test.go index 7e4f8af5e..474e8c5f8 100644 --- a/vehicle/template_test.go +++ b/vehicle/template_test.go @@ -31,6 +31,7 @@ var acceptable = []string{ "login failed: no auth code", // Porsche "invalid_client:Client authentication failed (e.g., login failure, unknown client, no client authentication included or unsupported authentication method)", // BMW, Mini "login failed: oauth2: cannot fetch token: 400 Bad Request Response: {\"error\":\"invalid_request\",\"error_description\":\"Missing parameter, 'username'\"}", // Opel, DS, Citroen, PSA + "401: Unauthorized: Invalid credentials", // Volvo } func TestVehicleTemplates(t *testing.T) { @@ -40,7 +41,7 @@ func TestVehicleTemplates(t *testing.T) { tmpl := tmpl // set default values for all params - values := tmpl.Defaults(true) + values := tmpl.Defaults(templates.TemplateRenderModeUnitTest) // set the template value which is needed for rendering values["template"] = tmpl.Template @@ -48,15 +49,17 @@ func TestVehicleTemplates(t *testing.T) { t.Run(tmpl.Template, func(t *testing.T) { t.Parallel() - b, values, err := tmpl.RenderResult(true, values) + b, values, err := tmpl.RenderResult(templates.TemplateRenderModeUnitTest, values) if err != nil { - t.Logf("%s: %s", tmpl.Template, b) + t.Logf("Template: %s", tmpl.Template) + t.Logf("%s", string(b)) t.Error(err) } _, err = NewFromConfig("template", values) if err != nil && !test.Acceptable(err, acceptable) { - t.Logf("%s", tmpl.Template) + t.Logf("Template: %s", tmpl.Template) + t.Logf("%s", string(b)) t.Error(err) } })