Template enhancements (#2274)
- Only add SMA HEMS Setup, if required values exist (e.g. machine-id). Also asks the user if this should be added - New templates: Alfen, PC Electric Garo, go-e V3 (moved into separate template), Tasmota meter, Huawei inverter with Sdongle - Updated templates: SolarEdge Inverter, Sunspec - New capabilities can be assigned: 1p3p, RFID - Added group information instead of `generic` flag. Used e.g. for marking power plugs or generic devices - Requirement description text can now be markdown text (required for documentation page) - Replaced `description` with product list, separating brand from description (required for documentation page) - Generate newly structured documentation yaml files - Fix https://github.com/evcc-io/evcc/issues/2385
This commit is contained in:
parent
ba662fb9b7
commit
a52f52b406
388 changed files with 4442 additions and 1808 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -6,6 +6,7 @@ __debug_bin
|
|||
*.json
|
||||
*.yaml
|
||||
!templates/**/*.yaml
|
||||
!util/templates/**/*.yaml
|
||||
!package*.json
|
||||
!evcc.dist.yaml
|
||||
evcc
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ var acceptable = []string{
|
|||
"sponsorship required, see https://github.com/evcc-io/evcc#sponsorship",
|
||||
"eebus not configured",
|
||||
"unexpected status: 400", // easee
|
||||
"Get \"http://192.0.2.2/getParameters\": context deadline exceeded", // evsewifi
|
||||
}
|
||||
|
||||
func TestChargerTemplates(t *testing.T) {
|
||||
|
|
@ -45,9 +46,9 @@ func TestChargerTemplates(t *testing.T) {
|
|||
modbusChoices := tmpl.ModbusChoices()
|
||||
// we only test one modbus setup
|
||||
if funk.ContainsString(modbusChoices, templates.ModbusChoiceTCPIP) {
|
||||
values[templates.ModbusTCPIP] = true
|
||||
values[templates.ModbusKeyTCPIP] = true
|
||||
} else {
|
||||
values[templates.ModbusRS485TCPIP] = true
|
||||
values[templates.ModbusKeyRS485TCPIP] = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ loadpoints:
|
|||
- title: {{ .Title }}
|
||||
charger: {{ .Charger }}
|
||||
{{- if .ChargeMeter }}
|
||||
meters:
|
||||
charge: {{ .ChargeMeter }}
|
||||
meter: {{ .ChargeMeter }}
|
||||
{{- end }}
|
||||
{{- if ne (len .Vehicles) 0 }}
|
||||
vehicles:
|
||||
|
|
|
|||
|
|
@ -101,9 +101,16 @@ func (d *DeviceTest) testCharger(v interface{}) (DeviceTestResult, error) {
|
|||
// testMeter tests a meter device
|
||||
func (d *DeviceTest) testMeter(deviceCategory DeviceCategory, v interface{}) (DeviceTestResult, error) {
|
||||
if v, ok := v.(api.Meter); ok {
|
||||
if _, err := v.CurrentPower(); err != nil {
|
||||
power, err := v.CurrentPower()
|
||||
if err != nil {
|
||||
return DeviceTestResultInvalid, err
|
||||
}
|
||||
// check if the grid meter reports power 0, which should be impossible
|
||||
// happens with Kostal Piko charger that do not have a grid meter attached
|
||||
// but we can't determine this
|
||||
if power == 0 && deviceCategory == DeviceCategoryGridMeter {
|
||||
return DeviceTestResultInvalid, errors.New("grid meter reports power 0")
|
||||
}
|
||||
|
||||
if deviceCategory == DeviceCategoryBatteryMeter {
|
||||
if v, ok := v.(api.Battery); ok {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ func (c *CmdConfigure) configureDeviceGuidedSetup() {
|
|||
}
|
||||
|
||||
c.configuration.AddDevice(deviceItem, deviceCategory)
|
||||
c.processDeviceCapabilities(templateItem.Capabilities)
|
||||
|
||||
if len(supportedDeviceCategories) > 1 {
|
||||
for _, additionalCategory := range supportedDeviceCategories[1:] {
|
||||
|
|
@ -86,7 +87,7 @@ func (c *CmdConfigure) configureDeviceGuidedSetup() {
|
|||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(templateItem.Description.String(c.lang) + " " + c.localizedString("Device_Added", nil))
|
||||
fmt.Println(templateItem.Title() + " " + c.localizedString("Device_Added", nil))
|
||||
|
||||
c.configureLinkedTypes(templateItem)
|
||||
}
|
||||
|
|
@ -118,11 +119,12 @@ func (c *CmdConfigure) configureLinkedTypes(templateItem templates.Template) {
|
|||
if len(linkedTemplateItem.Params) == 0 || linkedTemplate.Usage == "" {
|
||||
break
|
||||
}
|
||||
linkedTemplateItem.SetCombinedTitle()
|
||||
|
||||
category := DeviceCategory(linkedTemplate.Usage)
|
||||
|
||||
localizeMap := localizeMap{
|
||||
"Linked": linkedTemplateItem.Description.String(c.lang),
|
||||
"Linked": linkedTemplateItem.Title(),
|
||||
"Article": DeviceCategories[category].article,
|
||||
"Additional": DeviceCategories[category].additional,
|
||||
"Category": DeviceCategories[category].title,
|
||||
|
|
@ -152,12 +154,12 @@ func (c *CmdConfigure) configureLinkedTypes(templateItem templates.Template) {
|
|||
|
||||
// configureLinkedTemplate lets the user configure a device that is marked as being linked to a guided device
|
||||
// returns true if a device was added
|
||||
func (c *CmdConfigure) configureLinkedTemplate(template templates.Template, category DeviceCategory) bool {
|
||||
func (c *CmdConfigure) configureLinkedTemplate(templateItem templates.Template, category DeviceCategory) bool {
|
||||
for ok := true; ok; {
|
||||
deviceItem := device{}
|
||||
|
||||
values := c.processConfig(template, category)
|
||||
deviceItem, err := c.processDeviceValues(values, template, deviceItem, category)
|
||||
values := c.processConfig(templateItem, category)
|
||||
deviceItem, err := c.processDeviceValues(values, templateItem, deviceItem, category)
|
||||
if err != nil {
|
||||
if !errors.Is(err, c.errDeviceNotValid) {
|
||||
fmt.Println()
|
||||
|
|
@ -170,9 +172,10 @@ func (c *CmdConfigure) configureLinkedTemplate(template templates.Template, cate
|
|||
|
||||
} else {
|
||||
c.configuration.AddDevice(deviceItem, category)
|
||||
c.processDeviceCapabilities(templateItem.Capabilities)
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(template.Description.String(c.lang) + " " + c.localizedString("Device_Added", nil))
|
||||
fmt.Println(templateItem.Title() + " " + c.localizedString("Device_Added", nil))
|
||||
return true
|
||||
}
|
||||
break
|
||||
|
|
@ -181,7 +184,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, templates.Capabilities, error) {
|
||||
func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (device, []string, error) {
|
||||
fmt.Println()
|
||||
fmt.Printf("- %s %s\n", c.localizedString("Device_Configure", nil), DeviceCategories[deviceCategory].title)
|
||||
|
||||
|
|
@ -190,7 +193,7 @@ func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (d
|
|||
}
|
||||
|
||||
var deviceDescription string
|
||||
var capabilities templates.Capabilities
|
||||
var capabilities []string
|
||||
|
||||
// repeat until the device is added or the user chooses to continue without adding a device
|
||||
for ok := true; ok; {
|
||||
|
|
@ -201,7 +204,7 @@ func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (d
|
|||
return device, capabilities, c.errItemNotPresent
|
||||
}
|
||||
|
||||
deviceDescription = templateItem.Description.String(c.lang)
|
||||
deviceDescription = templateItem.Title()
|
||||
capabilities = templateItem.Capabilities
|
||||
values := c.processConfig(templateItem, deviceCategory)
|
||||
|
||||
|
|
@ -223,6 +226,7 @@ func (c *CmdConfigure) configureDeviceCategory(deviceCategory DeviceCategory) (d
|
|||
}
|
||||
|
||||
c.configuration.AddDevice(device, deviceCategory)
|
||||
c.processDeviceCapabilities(capabilities)
|
||||
|
||||
var deviceTitle string
|
||||
if device.Title != "" {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
"github.com/evcc-io/evcc/util/templates"
|
||||
"github.com/thoas/go-funk"
|
||||
stripmd "github.com/writeas/go-strip-markdown"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
|
@ -17,7 +18,7 @@ import (
|
|||
func (c *CmdConfigure) processDeviceSelection(deviceCategory DeviceCategory) (templates.Template, error) {
|
||||
templateItem := c.selectItem(deviceCategory)
|
||||
|
||||
if templateItem.Description.String(c.lang) == c.localizedString("ItemNotPresent", nil) {
|
||||
if templateItem.Title() == c.localizedString("ItemNotPresent", nil) {
|
||||
return templateItem, c.errItemNotPresent
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +34,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.String(c.lang)
|
||||
device.Title = templateItem.Title()
|
||||
for item, value := range values {
|
||||
if strings.ToLower(item) != "title" {
|
||||
continue
|
||||
|
|
@ -47,9 +48,9 @@ func (c *CmdConfigure) processDeviceValues(values map[string]interface{}, templa
|
|||
|
||||
fmt.Println()
|
||||
if categoryWithUsage {
|
||||
fmt.Println(c.localizedString("TestingDevice_TitleUsage", localizeMap{"Device": templateItem.Description.String(c.lang), "Usage": deviceCategory.String()}))
|
||||
fmt.Println(c.localizedString("TestingDevice_TitleUsage", localizeMap{"Device": templateItem.Title(), "Usage": deviceCategory.String()}))
|
||||
} else {
|
||||
fmt.Println(c.localizedString("TestingDevice_Title", localizeMap{"Device": templateItem.Description.String(c.lang)}))
|
||||
fmt.Println(c.localizedString("TestingDevice_Title", localizeMap{"Device": templateItem.Title()}))
|
||||
}
|
||||
|
||||
deviceTest := DeviceTest{
|
||||
|
|
@ -63,9 +64,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.String(c.lang)})
|
||||
question := c.localizedString("TestingDevice_AddFailed", localizeMap{"Device": templateItem.Title()})
|
||||
if categoryWithUsage {
|
||||
question = c.localizedString("TestingDevice_AddFailedUsage", localizeMap{"Device": templateItem.Description.String(c.lang), "Usage": deviceCategory.String()})
|
||||
question = c.localizedString("TestingDevice_AddFailedUsage", localizeMap{"Device": templateItem.Title(), "Usage": deviceCategory.String()})
|
||||
}
|
||||
if !c.askYesNo(question) {
|
||||
c.addedDeviceIndex--
|
||||
|
|
@ -79,7 +80,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, c.lang, false)
|
||||
b, err := templateItem.RenderProxyWithValues(values, c.lang)
|
||||
if err != nil {
|
||||
c.addedDeviceIndex--
|
||||
return device, err
|
||||
|
|
@ -105,33 +106,35 @@ func (c *CmdConfigure) processDeviceValues(values map[string]interface{}, templa
|
|||
return device, nil
|
||||
}
|
||||
|
||||
func (c *CmdConfigure) processDeviceCapabilities(capabilitites []string) {
|
||||
if funk.ContainsString(capabilitites, templates.CapabilitySMAHems) {
|
||||
c.capabilitySMAHems = true
|
||||
}
|
||||
}
|
||||
|
||||
// processDeviceRequirements handles device requirements
|
||||
func (c *CmdConfigure) processDeviceRequirements(templateItem templates.Template) error {
|
||||
if len(templateItem.Requirements.Description.String(c.lang)) > 0 {
|
||||
requirementDescription := stripmd.Strip(templateItem.Requirements.Description.String(c.lang))
|
||||
if len(requirementDescription) > 0 {
|
||||
fmt.Println()
|
||||
fmt.Println("-------------------------------------------------")
|
||||
fmt.Println(c.localizedString("Requirements_Title", nil))
|
||||
fmt.Println(" ", templateItem.Requirements.Description.String(c.lang))
|
||||
fmt.Println(requirementDescription)
|
||||
if len(templateItem.Requirements.URI) > 0 {
|
||||
fmt.Println(" " + c.localizedString("Requirements_More", nil) + " " + templateItem.Requirements.URI)
|
||||
}
|
||||
fmt.Println("-------------------------------------------------")
|
||||
}
|
||||
|
||||
// check if sponsorship is required
|
||||
if templateItem.Requirements.Sponsorship && c.configuration.config.SponsorToken == "" {
|
||||
if funk.ContainsString(templateItem.Requirements.EVCC, templates.RequirementSponsorship) && c.configuration.config.SponsorToken == "" {
|
||||
if err := c.askSponsortoken(true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// check if we need to setup a HEMS
|
||||
if templateItem.Requirements.Hems != "" && funk.ContainsString(templates.HemsValueTypes, templateItem.Requirements.Hems) {
|
||||
switch templateItem.Requirements.Hems {
|
||||
case templates.HemsTypeSMA:
|
||||
c.configuration.config.Hems = "type: sma\nAllowControl: false\n"
|
||||
}
|
||||
}
|
||||
|
||||
// check if we need to setup an MQTT broker
|
||||
if templateItem.Requirements.Mqtt {
|
||||
if funk.ContainsString(templateItem.Requirements.EVCC, templates.RequirementMQTT) {
|
||||
if c.configuration.config.MQTT == "" {
|
||||
mqttConfig, err := c.configureMQTT()
|
||||
if err != nil {
|
||||
|
|
@ -148,7 +151,7 @@ func (c *CmdConfigure) processDeviceRequirements(templateItem templates.Template
|
|||
}
|
||||
|
||||
// check if we need to setup an EEBUS HEMS
|
||||
if templateItem.Requirements.Eebus {
|
||||
if funk.ContainsString(templateItem.Requirements.EVCC, templates.RequirementEEBUS) {
|
||||
if c.configuration.config.EEBUS == "" {
|
||||
fmt.Println()
|
||||
fmt.Println("-- EEBUS -----------------------------------")
|
||||
|
|
@ -185,6 +188,9 @@ func (c *CmdConfigure) askSponsortoken(required bool) error {
|
|||
if required {
|
||||
fmt.Println()
|
||||
fmt.Println(c.localizedString("Requirements_Sponsorship_Title", nil))
|
||||
} else {
|
||||
fmt.Println()
|
||||
fmt.Println(c.localizedString("Requirements_Sponsorship_Optional_Title", nil))
|
||||
}
|
||||
fmt.Println()
|
||||
if !c.askYesNo(c.localizedString("Requirements_Sponsorship_Token", nil)) {
|
||||
|
|
@ -261,33 +267,49 @@ func (c *CmdConfigure) configureMQTT() (map[string]interface{}, error) {
|
|||
// 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.String(c.lang)) == 0 {
|
||||
if len(tmpl.Params) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if deviceCategory == DeviceCategoryGuidedSetup {
|
||||
if tmpl.GuidedSetup.Enable {
|
||||
items = append(items, tmpl)
|
||||
for _, t := range tmpl.Titles(c.lang) {
|
||||
titleTmpl := templates.Template{
|
||||
TemplateDefinition: tmpl.TemplateDefinition,
|
||||
ConfigDefaults: tmpl.ConfigDefaults,
|
||||
Lang: c.lang,
|
||||
}
|
||||
} else {
|
||||
if len(DeviceCategories[deviceCategory].categoryFilter) == 0 ||
|
||||
c.paramChoiceContains(tmpl.Params, templates.ParamUsage, DeviceCategories[deviceCategory].categoryFilter.String()) {
|
||||
items = append(items, tmpl)
|
||||
title := t
|
||||
groupTitle := titleTmpl.GroupTitle()
|
||||
if groupTitle != "" {
|
||||
title += " [" + groupTitle + "]"
|
||||
}
|
||||
titleTmpl.SetTitle(title)
|
||||
|
||||
if deviceCategory == DeviceCategoryGuidedSetup {
|
||||
if tmpl.GuidedSetup.Enable {
|
||||
items = append(items, titleTmpl)
|
||||
}
|
||||
} else {
|
||||
if len(DeviceCategories[deviceCategory].categoryFilter) == 0 ||
|
||||
c.paramChoiceContains(tmpl.Params, templates.ParamUsage, DeviceCategories[deviceCategory].categoryFilter.String()) {
|
||||
items = append(items, titleTmpl)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(items[:], func(i, j int) bool {
|
||||
// sort generic templates to the bottom
|
||||
if items[i].Generic && !items[j].Generic {
|
||||
if items[i].Group != "" && items[j].Group == "" {
|
||||
return false
|
||||
}
|
||||
if !items[i].Generic && items[j].Generic {
|
||||
if items[i].Group == "" && items[j].Group != "" {
|
||||
return true
|
||||
}
|
||||
return strings.ToLower(items[i].Description.String(c.lang)) < strings.ToLower(items[j].Description.String(c.lang))
|
||||
if items[i].Group != items[j].Group {
|
||||
return strings.ToLower(items[i].GroupTitle()) < strings.ToLower(items[j].GroupTitle())
|
||||
}
|
||||
return strings.ToLower(items[i].Title()) < strings.ToLower(items[j].Title())
|
||||
})
|
||||
|
||||
return items
|
||||
|
|
@ -319,31 +341,50 @@ func (c *CmdConfigure) paramChoiceValues(params []templates.Param, name string)
|
|||
// Returns:
|
||||
// a map with param name and values
|
||||
func (c *CmdConfigure) processConfig(templateItem templates.Template, deviceCategory DeviceCategory) map[string]interface{} {
|
||||
usageFilter := DeviceCategories[deviceCategory].categoryFilter
|
||||
|
||||
additionalConfig := make(map[string]interface{})
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(c.localizedString("Config_Title", nil))
|
||||
fmt.Println()
|
||||
|
||||
for _, param := range templateItem.Params {
|
||||
c.processModbusConfig(&templateItem, deviceCategory)
|
||||
|
||||
return c.processParams(templateItem, templateItem.Params, deviceCategory)
|
||||
}
|
||||
|
||||
// process a list of params
|
||||
func (c *CmdConfigure) processParams(templateItem templates.Template, params []templates.Param, deviceCategory DeviceCategory) map[string]interface{} {
|
||||
usageFilter := DeviceCategories[deviceCategory].categoryFilter
|
||||
|
||||
additionalConfig := make(map[string]interface{})
|
||||
|
||||
for _, param := range params {
|
||||
if param.Dependencies != nil {
|
||||
valid := true
|
||||
for _, dep := range param.Dependencies {
|
||||
_, valueParam := templateItem.ParamByName(dep.Name)
|
||||
if valueParam == nil {
|
||||
i, valueParam := templateItem.ParamByName(dep.Name)
|
||||
if i == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
value := valueParam.Value
|
||||
switch dep.Check {
|
||||
case templates.DependencyCheckEmpty:
|
||||
valid = value == ""
|
||||
if additionalConfig[dep.Name] != nil {
|
||||
valid = additionalConfig[dep.Name] == ""
|
||||
} else {
|
||||
valid = value == ""
|
||||
}
|
||||
case templates.DependencyCheckNotEmpty:
|
||||
valid = value != ""
|
||||
if additionalConfig[dep.Name] != nil {
|
||||
valid = additionalConfig[dep.Name] != ""
|
||||
} else {
|
||||
valid = value != ""
|
||||
}
|
||||
case templates.DependencyCheckEqual:
|
||||
valid = value == dep.Value
|
||||
if additionalConfig[dep.Name] != nil {
|
||||
valid = additionalConfig[dep.Name] == dep.Value
|
||||
} else {
|
||||
valid = value == dep.Value
|
||||
}
|
||||
}
|
||||
if !valid {
|
||||
break
|
||||
|
|
@ -356,7 +397,8 @@ func (c *CmdConfigure) processConfig(templateItem templates.Template, deviceCate
|
|||
|
||||
switch param.Name {
|
||||
case templates.ParamModbus:
|
||||
c.processModbusConfig(param, deviceCategory, additionalConfig)
|
||||
additionalConfig[param.Name] = param.Value
|
||||
|
||||
case templates.ParamUsage:
|
||||
if usageFilter != "" {
|
||||
additionalConfig[param.Name] = usageFilter.String()
|
||||
|
|
@ -366,6 +408,11 @@ func (c *CmdConfigure) processConfig(templateItem templates.Template, deviceCate
|
|||
continue
|
||||
}
|
||||
|
||||
if param.Hidden && param.Default != "" {
|
||||
additionalConfig[param.Name] = param.Default
|
||||
continue
|
||||
}
|
||||
|
||||
switch param.ValueType {
|
||||
case templates.ParamValueTypeStringList:
|
||||
additionalConfig[param.Name] = c.processListInputConfig(param)
|
||||
|
|
@ -401,9 +448,7 @@ 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
|
||||
label := param.Name
|
||||
langLabel := param.Description.String(c.lang)
|
||||
if langLabel != "" {
|
||||
label = langLabel
|
||||
|
|
@ -411,110 +456,52 @@ func (c *CmdConfigure) processInputConfig(param templates.Param) string {
|
|||
|
||||
return c.askValue(question{
|
||||
label: label,
|
||||
defaultValue: userFriendly.Default,
|
||||
exampleValue: userFriendly.Example,
|
||||
help: userFriendly.Help.String(c.lang),
|
||||
valueType: userFriendly.ValueType,
|
||||
mask: userFriendly.Mask,
|
||||
required: userFriendly.Required})
|
||||
defaultValue: param.Default,
|
||||
exampleValue: param.Example,
|
||||
help: param.Help.String(c.lang),
|
||||
valueType: param.ValueType,
|
||||
mask: param.Mask,
|
||||
required: param.Required})
|
||||
}
|
||||
|
||||
// handle user input for a device modbus configuration
|
||||
func (c *CmdConfigure) processModbusConfig(param templates.Param, deviceCategory DeviceCategory, additionalConfig map[string]interface{}) {
|
||||
var selectedModbusKey string
|
||||
|
||||
// baudrate and comset defaults can be overwritten, as they are device specific
|
||||
deviceDefaultBaudrate := templates.ModbusParamValueBaudrate
|
||||
deviceDefaultComset := templates.ModbusParamValueComset
|
||||
deviceDefaultPort := templates.ModbusParamValuePort
|
||||
deviceDefaultId := templates.ModbusParamValueId
|
||||
|
||||
if param.Baudrate != 0 {
|
||||
deviceDefaultBaudrate = param.Baudrate
|
||||
}
|
||||
if param.Comset != "" {
|
||||
deviceDefaultComset = param.Comset
|
||||
}
|
||||
if param.Port != 0 {
|
||||
deviceDefaultPort = param.Port
|
||||
}
|
||||
if param.ID != 0 {
|
||||
deviceDefaultId = param.ID
|
||||
}
|
||||
|
||||
func (c *CmdConfigure) processModbusConfig(templateItem *templates.Template, deviceCategory DeviceCategory) {
|
||||
var choices []string
|
||||
var choiceKeys []string
|
||||
var choiceTypes []string
|
||||
|
||||
for _, choice := range param.Choice {
|
||||
switch choice {
|
||||
case templates.ModbusChoiceRS485:
|
||||
choices = append(choices, "Serial (USB-RS485 Adapter)")
|
||||
choiceKeys = append(choiceKeys, templates.ModbusKeyRS485Serial)
|
||||
choices = append(choices, "Serial (Ethernet-RS485 Adapter)")
|
||||
choiceKeys = append(choiceKeys, templates.ModbusKeyRS485TCPIP)
|
||||
case templates.ModbusChoiceTCPIP:
|
||||
choices = append(choices, "TCP/IP")
|
||||
choiceKeys = append(choiceKeys, templates.ModbusKeyTCPIP)
|
||||
modbusIndex, modbusParam := templateItem.ParamByName(templates.ParamModbus)
|
||||
if modbusIndex == -1 {
|
||||
return
|
||||
}
|
||||
|
||||
config := templateItem.ConfigDefaults.Config.Modbus
|
||||
|
||||
for _, choice := range modbusParam.Choice {
|
||||
if config.Interfaces[choice] == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, itype := range config.Interfaces[choice] {
|
||||
title := config.Types[itype].Description
|
||||
choices = append(choices, title.String(c.lang))
|
||||
choiceTypes = append(choiceTypes, itype)
|
||||
}
|
||||
}
|
||||
|
||||
if len(choices) > 0 {
|
||||
// ask for modbus address
|
||||
id := c.askValue(question{
|
||||
label: "ID",
|
||||
help: "Modbus ID",
|
||||
defaultValue: deviceDefaultId,
|
||||
valueType: templates.ParamValueTypeNumber,
|
||||
required: true})
|
||||
additionalConfig[templates.ModbusParamNameId] = id
|
||||
|
||||
// ask for modbus interface type
|
||||
var index int
|
||||
if len(choices) > 1 {
|
||||
index, _ = c.askChoice(c.localizedString("Config_ModbusInterface", nil), choices)
|
||||
}
|
||||
selectedModbusKey = choiceKeys[index]
|
||||
additionalConfig[templates.ParamModbus] = selectedModbusKey
|
||||
|
||||
switch selectedModbusKey {
|
||||
case templates.ModbusKeyRS485Serial:
|
||||
device := c.askValue(question{
|
||||
label: c.localizedString("UserFriendly_Device_Name", nil),
|
||||
help: c.localizedString("UserFriendly_Device_Help", nil),
|
||||
exampleValue: templates.ModbusParamValueDevice,
|
||||
required: true})
|
||||
additionalConfig[templates.ModbusParamNameDevice] = device
|
||||
|
||||
baudrate := c.askValue(question{
|
||||
label: c.localizedString("UserFriendly_Baudrate_Name", nil),
|
||||
help: c.localizedString("UserFriendly_Baudrate_Help", nil),
|
||||
defaultValue: deviceDefaultBaudrate,
|
||||
valueType: templates.ParamValueTypeNumber,
|
||||
required: true})
|
||||
additionalConfig[templates.ModbusParamNameBaudrate] = baudrate
|
||||
|
||||
comset := c.askValue(question{
|
||||
label: c.localizedString("UserFriendly_ComSet_Name", nil),
|
||||
defaultValue: deviceDefaultComset,
|
||||
required: true})
|
||||
additionalConfig[templates.ModbusParamNameComset] = comset
|
||||
|
||||
case templates.ModbusKeyRS485TCPIP, templates.ModbusKeyTCPIP:
|
||||
if selectedModbusKey == templates.ModbusKeyRS485TCPIP {
|
||||
additionalConfig[templates.ModbusParamNameRTU] = "true"
|
||||
}
|
||||
host := c.askValue(question{
|
||||
label: c.localizedString("UserFriendly_Host_Name", nil),
|
||||
exampleValue: templates.ModbusParamValueHost,
|
||||
required: true})
|
||||
additionalConfig[templates.ModbusParamNameHost] = host
|
||||
|
||||
port := c.askValue(question{
|
||||
label: c.localizedString("UserFriendly_Port_Name", nil),
|
||||
defaultValue: deviceDefaultPort,
|
||||
valueType: templates.ParamValueTypeNumber,
|
||||
required: true})
|
||||
additionalConfig[templates.ModbusParamNamePort] = port
|
||||
}
|
||||
if len(choices) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// ask for modbus interface type
|
||||
var index int
|
||||
if len(choices) > 1 {
|
||||
index, _ = c.askChoice(c.localizedString("Config_ModbusInterface", nil), choices)
|
||||
}
|
||||
|
||||
values := make(map[string]interface{})
|
||||
templateItem.Params[modbusIndex].Value = choiceTypes[index]
|
||||
// add the interface type specific modbus params
|
||||
templateItem.ModbusParams(choiceTypes[index], values)
|
||||
// Update the modbus default values
|
||||
templateItem.ModbusValues(templates.TemplateRenderModeInstance, values)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ Flow_SingleDevice_Setup = "- Ein Gerät konfigurieren"
|
|||
Flow_SingleDevice_Select = "Wähle eines der folgenden Gerätekategorien aus"
|
||||
Flow_SingleDevice_Config = "Die Konfiguration lautet:"
|
||||
|
||||
Flow_SMAHems_Setup = "- SMA HEMS konfigurieren"
|
||||
Flow_SMAHems_Add = "Möchtest du die Wallboxen an den SMA Home Manager anbinden, damit diese z.B. für die Steuerung der Hausbatterie berücksichtigt werden können?"
|
||||
|
||||
ItemNotPresent = "Mein Gerät ist nicht in der Liste"
|
||||
|
||||
AddDeviceInCategory = "Möchtest du {{ .Article }} {{ .Category }} hinzufügen?"
|
||||
|
|
@ -37,35 +40,6 @@ File_SaveSuccess = "Die Konfiguration wurde erfolgreich in der Datei {{ .FileNam
|
|||
|
||||
Choose = "Wähle"
|
||||
|
||||
UserFriendly_Title_Name = "Titel"
|
||||
UserFriendly_Title_Help = "Wird in der Benutzeroberfläche angezeigt"
|
||||
UserFriendly_Device_Name = "Geräteadresse"
|
||||
UserFriendly_Device_Help = "USB-RS485 Adapter Adresse"
|
||||
UserFriendly_Baudrate_Name = "Baudrate"
|
||||
UserFriendly_Baudrate_Help = "Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200"
|
||||
UserFriendly_ComSet_Name = "ComSet"
|
||||
UserFriendly_Host_Name = "IP-Adresse oder Hostname"
|
||||
UserFriendly_Port_Name = "Port"
|
||||
UserFriendly_User_Name = "Benutzername"
|
||||
UserFriendly_Password_Name = "Passwort"
|
||||
UserFriendly_Capacity_Name = "Akku-Kapazität in kWh"
|
||||
UserFriendly_Vin_Name = "Fahrzeugidentifikationsnummer"
|
||||
UserFriendly_Vin_Help = "Erforderlich, wenn mehrere Fahrzeuge des Herstellers vorhanden sind"
|
||||
UserFriendly_Cache_Name = "Cache"
|
||||
UserFriendly_Cache_Help = "Das zeitliche Interval, in welchem Daten vom Fahrzeug neu geladen werden soll"
|
||||
UserFriendly_MinSoC_Name = "Minimaler Ladestand (SoC) in %"
|
||||
UserFriendly_MinSoC_Help = "Lade sofort mit maximaler Geschwindigkeit bis zu dem angegeben Ladestand, wenn der Lademodus nicht auf 'Aus' steht"
|
||||
UserFriendly_TargetSoC_Name = "Ziel-Ladestand (SoC) in %"
|
||||
UserFriendly_TargetSoC_Help = "Bis zu welchem Ladestand (SoC) soll das Fahrzeug geladen werden"
|
||||
UserFriendly_MinCurrent_Name = "Minimale Stromstärke in Ampere (A)"
|
||||
UserFriendly_MinCurrent_Help = "Definiert die minimale Stromstärke pro angeschlossener Phase mit welcher das Fahrzeug geladen werden soll"
|
||||
UserFriendly_MaxCurrent_Name = "Maximale Stromstärke in Ampere (A)"
|
||||
UserFriendly_MaxCurrent_Help = "Definiert die maximale Stromstärke pro angeschlossener Phase mit welcher das Fahrzeug geladen werden soll"
|
||||
UserFriendly_Identifier_Name = "Identifikationsnummer"
|
||||
UserFriendly_Identifier_Help = "Kann meist erst später eingetragen werden, siehe: https://docs.evcc.io/docs/guides/vehicles/#erkennung-des-fahrzeugs-an-der-wallbox"
|
||||
UserFriendly_StandByPower_Name = "Standby-Leistung in W"
|
||||
UserFriendly_StandByPower_Help = "Leistung oberhalb des angegebenen Wertes wird als Ladeleistung gewertet"
|
||||
|
||||
Category_ChargerTitle = "Wallbox"
|
||||
Category_ChargerArticle = "eine"
|
||||
Category_ChargerAdditional = "eine weitere"
|
||||
|
|
@ -96,10 +70,11 @@ TestingDevice_AddFailedUsage = "Der Test der {{ .Usage }} Konfiguration von {{ .
|
|||
|
||||
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_Title = "Das Gerät hat die folgenden Voraussetzungen:"
|
||||
Requirements_More = "Weitere Informationen:"
|
||||
|
||||
Requirements_Sponsorship_Title = "Dieses Gerät benötigt ein Sponsorship von evcc. Wie das funktioniert und was ist, findest du hier: https://docs.evcc.io/docs/sponsorship"
|
||||
Requirements_Sponsorship_Optional_Title = "Die Entwicklung von evcc kann über Sponsoring unterstützt werden. Wie das funktioniert und was ist, findest du hier: https://docs.evcc.io/docs/sponsorship"
|
||||
Requirements_Sponsorship_Token = "Bist du ein Sponsor?"
|
||||
Requirements_Sponsorship_Token_Input = "Bitte gib das Sponsortoken ein"
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ Flow_SingleDevice_Setup = "- Setup a device"
|
|||
Flow_SingleDevice_Select = "Choose one of the following device categories"
|
||||
Flow_SingleDevice_Config = "The configuration:"
|
||||
|
||||
Flow_SMAHems_Setup = "- Setup SMA HEMS"
|
||||
Flow_SMAHems_Add = "Do you want to report your wallboxes to the SMA Home Manager anbinden, so that it can consider them e.g. for controlling the in-house battery?"
|
||||
|
||||
ItemNotPresent = "My device is not in this list"
|
||||
|
||||
AddDeviceInCategory = "Do you want to add {{ .Article }} {{ .Category }}?"
|
||||
|
|
@ -37,35 +40,6 @@ File_SaveSuccess = "The configuration was successfully saved in the file {{ .Fil
|
|||
|
||||
Choose = "Choose"
|
||||
|
||||
UserFriendly_Title_Name = "Title"
|
||||
UserFriendly_Title_Help = "Will be displayed in the user interface"
|
||||
UserFriendly_Device_Name = "Device address"
|
||||
UserFriendly_Device_Help = "USB-RS485 Adapter address"
|
||||
UserFriendly_Baudrate_Name = "Baudrate"
|
||||
UserFriendly_Baudrate_Help = "Check the device settings, typical values are 9600, 19200, 38400, 57600, 115200"
|
||||
UserFriendly_ComSet_Name = "ComSet"
|
||||
UserFriendly_Host_Name = "IP-Address or Hostname"
|
||||
UserFriendly_Port_Name = "Port"
|
||||
UserFriendly_User_Name = "Username"
|
||||
UserFriendly_Password_Name = "Password"
|
||||
UserFriendly_Capacity_Name = "Battery-Capacity in kWh"
|
||||
UserFriendly_Vin_Name = "Vehicle Identification Number"
|
||||
UserFriendly_Vin_Help = "Required if you own multiple vehicles of the same brand"
|
||||
UserFriendly_Cache_Name = "Cache"
|
||||
UserFriendly_Cache_Help = "Time interval with when data should be reloaded from the vehicle"
|
||||
UserFriendly_MinSoC_Name = "Minimum state of charge (SoC) in %"
|
||||
UserFriendly_MinSoC_Help = "Charge immediately with maximum power up to the defined state of charge, if the charge mode is not set to 'OFF'"
|
||||
UserFriendly_TargetSoC_Name = "Target state of charge (SoC) in %"
|
||||
UserFriendly_TargetSoC_Help = "Until which sate of charge (SoC) should the vehicle be charged"
|
||||
UserFriendly_MinCurrent_Name = "Minimum amperage (A)"
|
||||
UserFriendly_MinCurrent_Help = "The minimum amperage per connected phase with which the car should be charged"
|
||||
UserFriendly_MaxCurrent_Name = "Maximum amperage (A)"
|
||||
UserFriendly_MaxCurrent_Help = "The maximum amperage per connected phase with which the car shuold be charged"
|
||||
UserFriendly_Identifier_Name = "Identification"
|
||||
UserFriendly_Identifier_Help = "Mostly this can be added later, see: https://docs.evcc.io/docs/guides/vehicles/#erkennung-des-fahrzeugs-an-der-wallbox"
|
||||
UserFriendly_StandByPower_Name = "Standby power in W"
|
||||
UserFriendly_StandByPower_Help = "Power values above this value will be considered as charging power"
|
||||
|
||||
Category_ChargerTitle = "wallbox"
|
||||
Category_ChargerArticle = "a"
|
||||
Category_ChargerAdditional = "one more"
|
||||
|
|
@ -96,10 +70,11 @@ TestingDevice_AddFailedUsage = "Testing of the {{ .Usage }} configuration of {{
|
|||
|
||||
TestingMQTTFailed = "Testing the MQTT configuration failed. Do you want to repeat its configuration?"
|
||||
|
||||
Requirements_Title = "The device needs to provide the following requirements:"
|
||||
Requirements_Title = "The device has the following requirements:"
|
||||
Requirements_More = "Additional information:"
|
||||
|
||||
Requirements_Sponsorship_Title = "This device requires an evcc sponsorship. Check the following link for what this is and how it works: https://docs.evcc.io/docs/sponsorship"
|
||||
Requirements_Sponsorship_Optional_Title = "The development of evcc can be supported via sponsoring. Check the following link for what this is and how it works: https://docs.evcc.io/docs/sponsorship"
|
||||
Requirements_Sponsorship_Token = "Are you already a sponsor?"
|
||||
Requirements_Sponsorship_Token_Input = "Please enter the sponsortoken"
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,12 @@ import (
|
|||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/cloudfoundry/jibber_jabber"
|
||||
"github.com/evcc-io/evcc/hems/semp"
|
||||
"github.com/evcc-io/evcc/server"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/templates"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/thoas/go-funk"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
|
|
@ -33,6 +35,8 @@ type CmdConfigure struct {
|
|||
advancedMode, expandedMode bool
|
||||
addedDeviceIndex int
|
||||
errItemNotPresent, errDeviceNotValid error
|
||||
|
||||
capabilitySMAHems bool
|
||||
}
|
||||
|
||||
// Run starts the interactive configuration
|
||||
|
|
@ -152,11 +156,17 @@ func (c *CmdConfigure) flowNewConfigFile() {
|
|||
_ = c.configureDevices(DeviceCategoryPVMeter, true, true)
|
||||
_ = c.configureDevices(DeviceCategoryBatteryMeter, true, true)
|
||||
_ = c.configureDevices(DeviceCategoryVehicle, true, true)
|
||||
|
||||
c.configureLoadpoints()
|
||||
c.configureSite()
|
||||
|
||||
// check if SMA HEMS is available and ask the user if it should be added
|
||||
if c.capabilitySMAHems {
|
||||
c.configureSMAHems()
|
||||
}
|
||||
|
||||
if c.advancedMode && c.configuration.config.SponsorToken == "" {
|
||||
_ = c.askSponsortoken(true)
|
||||
_ = c.askSponsortoken(false)
|
||||
}
|
||||
|
||||
yaml, err := c.configuration.RenderConfiguration()
|
||||
|
|
@ -223,12 +233,14 @@ func (c *CmdConfigure) configureDevices(deviceCategory DeviceCategory, askAdding
|
|||
}
|
||||
|
||||
for ok := true; ok; {
|
||||
device, _, err := c.configureDeviceCategory(deviceCategory)
|
||||
device, capabilities, err := c.configureDeviceCategory(deviceCategory)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
devices = append(devices, device)
|
||||
|
||||
c.processDeviceCapabilities(capabilities)
|
||||
|
||||
if !askMultiple {
|
||||
break
|
||||
}
|
||||
|
|
@ -242,6 +254,25 @@ func (c *CmdConfigure) configureDevices(deviceCategory DeviceCategory, askAdding
|
|||
return devices
|
||||
}
|
||||
|
||||
// configureSMAHems asks the user if he wants to add the SMA HEMS
|
||||
func (c *CmdConfigure) configureSMAHems() {
|
||||
// check if the system provides a machine-id
|
||||
if _, err := semp.UniqueDeviceID(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(c.localizedString("Flow_SMAHems_Setup", nil))
|
||||
|
||||
fmt.Println()
|
||||
if !c.askYesNo(c.localizedString("Flow_SMAHems_Add", nil)) {
|
||||
return
|
||||
}
|
||||
|
||||
// check if we need to setup a HEMS
|
||||
c.configuration.config.Hems = "type: sma\nAllowControl: false\n"
|
||||
}
|
||||
|
||||
// configureLoadpoints asks loadpoint specific questions
|
||||
func (c *CmdConfigure) configureLoadpoints() {
|
||||
fmt.Println()
|
||||
|
|
@ -289,7 +320,7 @@ func (c *CmdConfigure) configureLoadpoints() {
|
|||
}
|
||||
|
||||
var minValue int = 6
|
||||
if capabilities.ISO151182 {
|
||||
if funk.ContainsString(capabilities, templates.CapabilityISO151182) {
|
||||
minValue = 2
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,16 +63,16 @@ 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.SetString(c.localizedString("ItemNotPresent", nil), c.lang)
|
||||
emptyItem := templates.Template{Lang: c.lang}
|
||||
emptyItem.SetTitle(c.localizedString("ItemNotPresent", nil))
|
||||
|
||||
elements := c.fetchElements(deviceCategory)
|
||||
elements = append(elements, emptyItem)
|
||||
|
||||
var items []string
|
||||
for _, item := range elements {
|
||||
if item.Description.String(c.lang) != "" {
|
||||
items = append(items, item.Description.String(c.lang))
|
||||
if item.Title() != "" {
|
||||
items = append(items, item.Title())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,8 @@ package configure
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/evcc-io/evcc/util/templates"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
// setDefaultTexts sets default language specific texts
|
||||
|
|
@ -39,59 +36,3 @@ func (c *CmdConfigure) localizedString(key string, templateData localizeMap) str
|
|||
TemplateData: templateData,
|
||||
})
|
||||
}
|
||||
|
||||
// userFriendlyTexts sets user friendly texts for a set of known param names and
|
||||
// returns them as a new set as we don't want to overwrite the template values
|
||||
func (c *CmdConfigure) userFriendlyTexts(param templates.Param) templates.Param {
|
||||
result := param
|
||||
|
||||
if result.ValueType == "" || (result.ValueType != "" && !funk.ContainsString(templates.ParamValueTypes, result.ValueType)) {
|
||||
result.ValueType = templates.ParamValueTypeString
|
||||
}
|
||||
|
||||
type replacements struct {
|
||||
Name string
|
||||
Help string
|
||||
Example string
|
||||
ValueType string
|
||||
}
|
||||
resultNameMap := map[string]replacements{
|
||||
"title": {Name: "UserFriendly_Title_Name", Help: "UserFriendly_Title_Help"},
|
||||
"device": {Name: "UserFriendly_Device_Name"},
|
||||
"baudrate": {Name: "UserFriendly_Baudrate_Name"},
|
||||
"comset": {Name: "UserFriendly_ComSet_Name"},
|
||||
"host": {Name: "UserFriendly_Host_Name"},
|
||||
"port": {Name: "UserFriendly_Port_Name", ValueType: templates.ParamValueTypeNumber},
|
||||
"user": {Name: "UserFriendly_User_Name"},
|
||||
"password": {Name: "UserFriendly_Password_Name"},
|
||||
"capacity": {Name: "UserFriendly_Capacity_Name", Example: "41.5", ValueType: templates.ParamValueTypeFloat},
|
||||
"vin": {Name: "UserFriendly_Vin_Name", Help: "UserFriendly_Vin_Help"},
|
||||
"cache": {Name: "UserFriendly_Cache_Name", Help: "UserFriendly_Cache_Help", Example: "5m"},
|
||||
"mode": {Name: "ChargeMode_Question", ValueType: templates.ParamValueTypeChargeModes},
|
||||
"minsoc": {Name: "UserFriendly_MinSoC_Name", Help: "UserFriendly_MinSoC_Help", Example: "25", ValueType: templates.ParamValueTypeNumber},
|
||||
"targetsoc": {Name: "UserFriendly_TargetSoC_Name", Help: "UserFriendly_TargetSoC_Help", Example: "80", ValueType: templates.ParamValueTypeNumber},
|
||||
"mincurrent": {Name: "UserFriendly_MinCurrent_Name", Help: "UserFriendly_MinCurrent_Help", Example: "6", ValueType: templates.ParamValueTypeNumber},
|
||||
"maxcurrent": {Name: "UserFriendly_MaxCurrent_Name", Help: "UserFriendly_MaxCurrent_Help", Example: "16", ValueType: templates.ParamValueTypeNumber},
|
||||
"identifiers": {Name: "UserFriendly_Identifier_Name", Help: "UserFriendly_Identifier_Help"},
|
||||
"standbypower": {Name: "UserFriendly_StandByPower_Name", Help: "UserFriendly_StandByPower_Help", ValueType: templates.ParamValueTypeNumber},
|
||||
}
|
||||
|
||||
if resultMapItem := resultNameMap[strings.ToLower(result.Name)]; resultMapItem != (replacements{}) {
|
||||
// always overwrite if defined
|
||||
if resultMapItem.Name != "" {
|
||||
result.Name = c.localizedString(resultMapItem.Name, nil)
|
||||
}
|
||||
if resultMapItem.ValueType != "" {
|
||||
result.ValueType = resultMapItem.ValueType
|
||||
}
|
||||
// only set if empty
|
||||
if result.Help.String(c.lang) == "" && resultMapItem.Help != "" {
|
||||
result.Help.SetString(c.lang, c.localizedString(resultMapItem.Help, nil))
|
||||
}
|
||||
if result.Example == "" && resultMapItem.Example != "" {
|
||||
result.Example = resultMapItem.Example
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
1
go.mod
1
go.mod
|
|
@ -89,6 +89,7 @@ require (
|
|||
github.com/thoas/go-funk v0.9.1
|
||||
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c
|
||||
github.com/volkszaehler/mbmd v0.0.0-20220108103619-de9b2cf95ebe
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible
|
||||
gitlab.com/bboehmke/sunny v0.15.1-0.20211022160056-2fba1c86ade6
|
||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect
|
||||
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -800,6 +800,8 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh
|
|||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||
github.com/volkszaehler/mbmd v0.0.0-20220108103619-de9b2cf95ebe h1:pxQR+cX7Wl31hX1YRmYNMx3dWydSWhEk8Pzzv02WguM=
|
||||
github.com/volkszaehler/mbmd v0.0.0-20220108103619-de9b2cf95ebe/go.mod h1:Re4O+TyZ5p3Z4L0zODnzPyEZofTKF2kgLSmxG79h0Xs=
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6FkrCNfXkvbR+Nbu1ls48pXYcw=
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ func New(conf map[string]interface{}, site site.API, httpd *server.HTTPd) (*SEMP
|
|||
|
||||
var did []byte
|
||||
if cc.DeviceID == "" {
|
||||
if did, err = uniqueDeviceID(); err != nil {
|
||||
if did, err = UniqueDeviceID(); err != nil {
|
||||
return nil, fmt.Errorf("creating device id: %w", err)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -338,7 +338,7 @@ func (s *SEMP) serialNumber(id int) string {
|
|||
}
|
||||
|
||||
// uniqueDeviceID creates a 6-bytes base device id from machine id
|
||||
func uniqueDeviceID() ([]byte, error) {
|
||||
func UniqueDeviceID() ([]byte, error) {
|
||||
bytes := 6
|
||||
|
||||
mid, err := machineid.ProtectedID("evcc-semp")
|
||||
|
|
|
|||
|
|
@ -21,9 +21,10 @@ var acceptable = []string{
|
|||
"no ping response for 192.0.2.2", // SMA
|
||||
"network is unreachable",
|
||||
"[1ESY1161052714 1ESY1161229249 1EMH0008842285 1ESY1161978584 1EMH0004864048 1ESY1161979033 7ELS8135823805]", // Discovergy
|
||||
"can only have either uri or device", // modbus
|
||||
"(Client.Timeout exceeded while awaiting headers)", // http
|
||||
"cannot create meter 'discovergy': unexpected status: 401", //Discovergy Proxy
|
||||
"can only have either uri or device", // modbus
|
||||
"(Client.Timeout exceeded while awaiting headers)", // http
|
||||
"cannot create meter 'discovergy': unexpected status: 401", // Discovergy Proxy
|
||||
"login failed: Put \"https://192.0.2.2/v1/login\": context deadline exceeded", // LG ESS
|
||||
}
|
||||
|
||||
func TestMeterTemplates(t *testing.T) {
|
||||
|
|
@ -43,9 +44,9 @@ func TestMeterTemplates(t *testing.T) {
|
|||
modbusChoices := tmpl.ModbusChoices()
|
||||
// we only test one modbus setup
|
||||
if funk.ContainsString(modbusChoices, templates.ModbusChoiceTCPIP) {
|
||||
values[templates.ModbusTCPIP] = true
|
||||
values[templates.ModbusKeyTCPIP] = true
|
||||
} else {
|
||||
values[templates.ModbusRS485TCPIP] = true
|
||||
values[templates.ModbusKeyRS485TCPIP] = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,20 @@ The following describes each possible element in a yaml file
|
|||
|
||||
`template` expects a unique template name for the current device class (charger, meter, vehicle are device classes)
|
||||
|
||||
## `description`
|
||||
## `products`
|
||||
|
||||
`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)
|
||||
`products` expects a list of products that work with this template.
|
||||
|
||||
## `generic`
|
||||
Each product contains:
|
||||
|
||||
`generic: true` defines templates that are typically not a hardware product, but rather generic implementations that can be used by a variety of products (e.g. inverters with sunspec support) or for software components like vzlogger.
|
||||
- `brand`: an optional brand description of the product
|
||||
- `description`: an optional description e.g. of the product model. Expects `generic`, `de`, `en`: an optional description of the product
|
||||
|
||||
Either `brand`, or `description` need to be set.
|
||||
|
||||
## `group`
|
||||
|
||||
`group` contains the reference to a `groups.yaml` entry. This is used to group switchable sockets and generic device support (e.g. SunSpec) templates.
|
||||
|
||||
## `guidedsetup`
|
||||
|
||||
|
|
@ -62,23 +69,36 @@ Example Use Case: With SMA Home Manager, there can be a SMA Energy Meter used fo
|
|||
|
||||
## `capabilities`
|
||||
|
||||
`capabilities` provides an option to define special capabilities of the devie
|
||||
`capabilities` provides an option to define special capabilities of the device as a list of strings
|
||||
|
||||
**Possible Values**:
|
||||
|
||||
- `iso151182: true`: If the charger supports communicating via ISO15118-2
|
||||
- `iso151182`: If the charger supports communicating via ISO15118-2
|
||||
- `rfid`: If the charger supports RFID
|
||||
- `1p3p`: If the charger supports 1P/3P-phase switching
|
||||
- `smahems`: If the device can be used as an SMA HEMS device, only used for the SMA Home Manager 2.0 right now
|
||||
|
||||
## `requirements`
|
||||
|
||||
`requirements` provides an option to define various requirements / dependencies that need to be setup
|
||||
|
||||
### `evcc`
|
||||
|
||||
`evcc` is a list of evcc specific system requirements
|
||||
|
||||
**Possible Values**:
|
||||
|
||||
- `sponsorshipt: true`: If the device requires a sponsorship token
|
||||
- `eebus: true`: If the device is accessed via the eebus protocol and thus requires the corresponding setup
|
||||
- `hems: sma`: If the device can be used as an SMA HEMS device, only used for the SMA Home Manager 2.0 right now
|
||||
- `description`: expects language specific texts via `de`, `en` to provide specific things the user has to do, e.g. minimum firmware versions or specific hardware setup requirements
|
||||
- `uri`: a link providing more help on the requirements
|
||||
- `sponsorship`: If the device requires a sponsorship token
|
||||
- `eebus`: If the device is accessed via the eebus protocol and thus requires the corresponding setup
|
||||
- `mqtt`: If the device a MQTT setup
|
||||
|
||||
### `description`
|
||||
|
||||
`description` expects language specific texts via `de`, `en` to provide specific things the user has to do, e.g. minimum firmware versions or specific hardware setup requirements. The content can be multiline and Markdown
|
||||
|
||||
### `uri`
|
||||
|
||||
`uri` is a link providing more help on the requirements
|
||||
|
||||
## `loglevel`
|
||||
|
||||
|
|
@ -171,7 +191,7 @@ Example Use Case: With SMA Home Manager, there can be a SMA Energy Meter used fo
|
|||
|
||||
### `help`
|
||||
|
||||
`help` expects language specific help texts via `de`, `en`
|
||||
`help` expects language specific help texts via `generic` (language independent), `de`, `en`
|
||||
|
||||
## `render`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
template: abl
|
||||
description:
|
||||
generic: ABL eMH / SENEC.Wallbox pro
|
||||
requirements:
|
||||
sponsorship: true
|
||||
products:
|
||||
- brand: ABL
|
||||
description:
|
||||
generic: eMH
|
||||
- brand: SENEC
|
||||
description:
|
||||
generic: Wallbox pro
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
params:
|
||||
- name: modbus
|
||||
choice: ["rs485"]
|
||||
|
|
|
|||
14
templates/definition/charger/alfen.yaml
Normal file
14
templates/definition/charger/alfen.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
template: alfen
|
||||
products:
|
||||
- brand: Alfen
|
||||
description:
|
||||
generic: Eve
|
||||
capabilities: ["1p3p"]
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
params:
|
||||
- name: modbus
|
||||
choice: ["tcpip"]
|
||||
render: |
|
||||
type: alfen
|
||||
{{include "modbus" .}}
|
||||
15
templates/definition/charger/alphatec.yaml
Normal file
15
templates/definition/charger/alphatec.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
template: alphatec
|
||||
products:
|
||||
- brand: Alphatec
|
||||
description:
|
||||
generic: Wallbox Mini
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
params:
|
||||
- name: modbus
|
||||
choice: ["rs485"]
|
||||
baudrate: 9600
|
||||
comset: "8N1"
|
||||
render: |
|
||||
type: alphatec
|
||||
{{include "modbus" .}}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
template: cfos
|
||||
description:
|
||||
generic: cFos PowerBrain
|
||||
requirements:
|
||||
sponsorship: true
|
||||
products:
|
||||
- brand: cFos
|
||||
description:
|
||||
generic: PowerBrain
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: daheimladen
|
||||
description:
|
||||
generic: Daheimladen (Cloud API)
|
||||
products:
|
||||
- brand: DaheimLaden
|
||||
description:
|
||||
generic: Wallbox (Cloud API)
|
||||
params:
|
||||
- name: token
|
||||
help:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
template: easee
|
||||
description:
|
||||
generic: Easee Home (Cloud API)
|
||||
requirements:
|
||||
sponsorship: true
|
||||
products:
|
||||
- brand: Easee
|
||||
description:
|
||||
generic: Home (Cloud API)
|
||||
capabilities: ["1p3p"]
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
params:
|
||||
- name: user
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
template: eebus
|
||||
description:
|
||||
de: EEBUS kompatible Wallbox
|
||||
en: EEBUS compatible Wallbox
|
||||
generic: true
|
||||
capabilities:
|
||||
iso151182: true
|
||||
requirements:
|
||||
eebus: true
|
||||
products:
|
||||
- description:
|
||||
de: EEBUS kompatible Wallbox
|
||||
en: EEBUS compatible Wallbox
|
||||
group: generic
|
||||
capabilities: ["iso151182"]
|
||||
requirements:
|
||||
evcc: ["eebus"]
|
||||
params:
|
||||
- name: ski
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
template: evse_din
|
||||
description:
|
||||
generic: EVSE DIN
|
||||
products:
|
||||
- description:
|
||||
generic: EVSE DIN
|
||||
params:
|
||||
- name: modbus
|
||||
choice: ["rs485"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
template: evsewifi
|
||||
description:
|
||||
generic: EVSE-Wifi
|
||||
products:
|
||||
- description:
|
||||
generic: EVSE-Wifi
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
template: fritzdect
|
||||
description:
|
||||
generic: FritzDECT
|
||||
products:
|
||||
- brand: AVM
|
||||
description:
|
||||
generic: FritzDECT
|
||||
group: switchsockets
|
||||
params:
|
||||
- name: uri
|
||||
default: https://fritz.box
|
||||
|
|
|
|||
27
templates/definition/charger/goe-v3.yaml
Normal file
27
templates/definition/charger/goe-v3.yaml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
template: go-e-v3
|
||||
products:
|
||||
- brand: go-e
|
||||
description:
|
||||
generic: Charger HOME+ (V3)
|
||||
- brand: go-e
|
||||
description:
|
||||
generic: Charger HOMEfix (V3)
|
||||
capabilities: ["1p3p"]
|
||||
requirements:
|
||||
description:
|
||||
de: |
|
||||
Benötigt mindestens Firmware 052.1 oder neuer.
|
||||
|
||||
Für 1P/3P-Phasenumschaltung muss die HTTP API v2 im Charger aktiviert sein.
|
||||
en: |
|
||||
Requires firmware 052.1 or later.
|
||||
|
||||
For 1P/3P-Phase switching the HTTP API v2 in the charger setup needs to be activated.
|
||||
uri: https://docs.evcc.io/docs/devices/chargers#go-echarger-homeprov3
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
example: 192.0.2.2
|
||||
render: |
|
||||
type: go-e
|
||||
uri: http://{{ .host }}
|
||||
|
|
@ -1,11 +1,18 @@
|
|||
template: go-e
|
||||
description:
|
||||
generic: go-eCharger Home/Pro/V3
|
||||
products:
|
||||
- brand: go-e
|
||||
description:
|
||||
generic: Charger HOME+
|
||||
- brand: go-e
|
||||
description:
|
||||
generic: Charger HOMEfix
|
||||
- brand: go-e
|
||||
description:
|
||||
generic: Charger Pro
|
||||
requirements:
|
||||
description:
|
||||
en: Home und PRO require firmware 040.0 or later, V3 requires firmware 052.1 or later.
|
||||
de: Home und PRO benötigen mindestens Firmware 040.0 oder neuer, V3 benötigt mindestens Firmware 052.1 oder neuer.
|
||||
uri: https://docs.evcc.io/docs/devices/chargers#go-echarger-homeprov3
|
||||
en: Require firmware 040.0 or later.
|
||||
de: Benötigen mindestens Firmware 040.0 oder neuer.
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
template: heidelberg
|
||||
description:
|
||||
generic: Heidelberg Energy Control (Modbus RTU)
|
||||
requirements:
|
||||
sponsorship: true
|
||||
products:
|
||||
- brand: Heidelberg
|
||||
description:
|
||||
generic: Energy Control (Modbus RTU)
|
||||
- brand: Wahlter Werke
|
||||
description:
|
||||
generic: Basic Evo Pro
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
params:
|
||||
- name: modbus
|
||||
choice: ["rs485"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: ichargecion
|
||||
description:
|
||||
generic: i-CHARGE CION (Modbus RTU-over-TCP)
|
||||
products:
|
||||
- brand: i-CHARGE
|
||||
description:
|
||||
generic: CION
|
||||
params:
|
||||
- name: modbus
|
||||
choice: ["tcpip"]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
template: innogy-ebox
|
||||
description:
|
||||
generic: Innogy eBox
|
||||
requirements:
|
||||
sponsorship: true
|
||||
products:
|
||||
- brand: Innogy
|
||||
description:
|
||||
generic: eBox
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
params:
|
||||
- name: modbus
|
||||
choice: ["tcpip"]
|
||||
|
|
|
|||
|
|
@ -1,16 +1,34 @@
|
|||
template: keba
|
||||
description:
|
||||
generic: KEBA Connect
|
||||
products:
|
||||
- brand: KEBA
|
||||
description:
|
||||
generic: KeContact P20
|
||||
- brand: KEBA
|
||||
description:
|
||||
generic: KeContact P30
|
||||
- brand: BMW
|
||||
description:
|
||||
generic: i Wallbox
|
||||
capabilities: ["rfid"]
|
||||
requirements:
|
||||
description:
|
||||
en: This requires the UDP function to be enabled with DIP 1.3 = ON, see the installation manual.
|
||||
de: Es muss eine sogenannte UDP Funktion über den DIP Schalter 1.3 eingeschaltet (ON) werden. Die Installationsanleitung der Wallbox hilft hier weiter.
|
||||
uri: https://docs.evcc.io/docs/devices/chargers#keba-connect
|
||||
en: This requires the UDP function to be enabled with DIP 1.3 = ON, see the installation manual.
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
example: 192.0.2.2
|
||||
- name: rfid
|
||||
example: 765765348
|
||||
advanced: true
|
||||
help:
|
||||
de: Die Kennung eines RFID Tags um den Lademodus zu starten, selbst wenn die Wallbox gesperrt ist.
|
||||
en: A RFID tag ID to enable charging even when the wallbox is locked.
|
||||
- name: serial
|
||||
advanced: true
|
||||
help:
|
||||
de: Die Seriennummer, ermöglicht es auch mit der Wallbox zu kommunizieren wenn evcc in Docker läuft.
|
||||
en: The serial number, allows to communicate with the Wallbox when running evcc in docker
|
||||
render: |
|
||||
type: keba
|
||||
uri: {{ .host }}
|
||||
|
|
@ -18,3 +36,6 @@ render: |
|
|||
rfid:
|
||||
tag: {{ .rfid }}
|
||||
{{ end }}
|
||||
{{ if ne .serial "" }}
|
||||
serial: {{ .serial }}
|
||||
{{ end }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: nrgkick-bluetooth
|
||||
description:
|
||||
generic: NRGKick Bluetooth
|
||||
products:
|
||||
- brand: NRGKick
|
||||
description:
|
||||
generic: Bluetooth
|
||||
params:
|
||||
- name: mac
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: nrgkick-connect
|
||||
description:
|
||||
generic: NRGKick Connect
|
||||
products:
|
||||
- brand: NRGKick
|
||||
description:
|
||||
generic: Connect
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
template: openwb
|
||||
description:
|
||||
generic: openWB (MQTT)
|
||||
products:
|
||||
- description:
|
||||
generic: openWB (MQTT)
|
||||
requirements:
|
||||
description:
|
||||
en: The wallbox has to be configured running as a loadpoint.
|
||||
|
|
|
|||
17
templates/definition/charger/pcelectric-garo.yaml
Normal file
17
templates/definition/charger/pcelectric-garo.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
template: pcelectric-garo
|
||||
products:
|
||||
- brand: PC Electric
|
||||
description:
|
||||
generic: Garo
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
description:
|
||||
de: Es können momentan nur als Master konfigurierte Geräte verwendet werden!
|
||||
en: Only devices configured as master can be used right now!
|
||||
params:
|
||||
- name: host
|
||||
- name: port
|
||||
default: 8080
|
||||
render: |
|
||||
type: garo
|
||||
uri: http://{{ .host }}:{{ .port }}/servlet
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
template: phoenix-em-eth
|
||||
description:
|
||||
generic: Phoenix EM-CP-PP-ETH Controller (Modbus TCP)
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
generic: Phoenix EM-CP-PP-ETH Controller (Modbus TCP)
|
||||
group: generic
|
||||
requirements:
|
||||
description:
|
||||
en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
template: phoenix-ev-eth
|
||||
description:
|
||||
generic: Phoenix EV-ETH Controller (Modbus TCP)
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
generic: Phoenix EV-ETH Controller (Modbus TCP)
|
||||
group: generic
|
||||
requirements:
|
||||
description:
|
||||
en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
template: phoenix-ev-ser
|
||||
description:
|
||||
generic: Phoenix EV-SER Controller (Modbus RTU)
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
generic: Phoenix EV-SER Controller (Modbus RTU)
|
||||
group: generic
|
||||
params:
|
||||
- name: modbus
|
||||
choice: ["rs485"]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
template: pmcc
|
||||
description:
|
||||
generic: Porsche Mobile Charger Connect
|
||||
capabilities:
|
||||
iso151182: true
|
||||
requirements:
|
||||
eebus: true
|
||||
products:
|
||||
- brand: Porsche
|
||||
description:
|
||||
generic: Mobile Charger Connect
|
||||
capabilities: ["iso151182"]
|
||||
requirements:
|
||||
evcc: ["eebus"]
|
||||
params:
|
||||
- name: ski
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
template: pmcp
|
||||
description:
|
||||
generic: Porsche Mobile Charger Plus
|
||||
requirements:
|
||||
eebus: true
|
||||
products:
|
||||
- brand: Porsche
|
||||
description:
|
||||
generic: Mobile Charger Plus
|
||||
requirements:
|
||||
evcc: ["eebus"]
|
||||
params:
|
||||
- name: ski
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: shelly
|
||||
description:
|
||||
generic: Shelly
|
||||
products:
|
||||
- description:
|
||||
generic: Shelly
|
||||
group: switchsockets
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: tasmota
|
||||
description:
|
||||
generic: Tasmota
|
||||
products:
|
||||
- description:
|
||||
generic: Tasmota
|
||||
group: switchsockets
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: tinkerforge-warp-pro
|
||||
description:
|
||||
generic: TinkerForge WARP Charger Pro
|
||||
products:
|
||||
- brand: TinkerForge
|
||||
description:
|
||||
generic: 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.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: tinkerforge-warp
|
||||
description:
|
||||
generic: TinkerForge WARP Charger
|
||||
products:
|
||||
- brand: TinkerForge
|
||||
description:
|
||||
generic: 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.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
template: tplink
|
||||
description:
|
||||
generic: TP-LINK Smart Plug
|
||||
products:
|
||||
- brand: TP-LINK
|
||||
description:
|
||||
generic: Smart Plug
|
||||
group: switchsockets
|
||||
params:
|
||||
- name: host
|
||||
required: true
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
template: wallbe-meter
|
||||
description:
|
||||
de: Wallbe (Eco, Pro) mit Strommessgerät
|
||||
en: Wallbe (Eco, Pro) with Meter
|
||||
products:
|
||||
- brand: Wallbe
|
||||
description:
|
||||
de: Eco (mit Strommessgerät)
|
||||
en: Eco (with Meter)
|
||||
- brand: Wallbe
|
||||
description:
|
||||
de: Pro (mit Strommessgerät)
|
||||
en: Pro (with Meter)
|
||||
requirements:
|
||||
description:
|
||||
en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
template: wallbe-pre2019-meter
|
||||
description:
|
||||
de: Wallbe (Eco, Pro) (vor ~2019) mit Strommessgerät
|
||||
en: Wallbe (Eco, Pro) (pre ~2019) with Meter
|
||||
products:
|
||||
- brand: Wallbe
|
||||
description:
|
||||
de: Eco (vor ~2019, mit Strommessgerät)
|
||||
en: Eco (pre ~2019, with Meter)
|
||||
- brand: Wallbe
|
||||
description:
|
||||
de: Pro (vor ~2019, mit Strommessgerät)
|
||||
en: 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'.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
template: wallbe-pre2019
|
||||
description:
|
||||
de: Wallbe (Eco, Pro) (vor ~2019)
|
||||
en: Wallbe (Eco, Pro) (pre ~2019)
|
||||
products:
|
||||
- brand: Wallbe
|
||||
description:
|
||||
de: Eco (vor ~2019)
|
||||
en: Eco (pre ~2019)
|
||||
- brand: Wallbe
|
||||
description:
|
||||
de: Pro (vor ~2019)
|
||||
en: Pro (pre ~2019)
|
||||
requirements:
|
||||
description:
|
||||
en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
template: wallbe
|
||||
description:
|
||||
generic: Wallbe (Eco, Pro)
|
||||
products:
|
||||
- brand: Wallbe
|
||||
description:
|
||||
generic: Eco
|
||||
- brand: Wallbe
|
||||
description:
|
||||
generic: Pro
|
||||
requirements:
|
||||
description:
|
||||
en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'.
|
||||
|
|
|
|||
286
templates/definition/defaults.yaml
Normal file
286
templates/definition/defaults.yaml
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
params:
|
||||
- name: title
|
||||
description:
|
||||
de: Titel
|
||||
en: Title
|
||||
help:
|
||||
de: Wird in der Benutzeroberfläche angezeigt
|
||||
en: Will be displayed in the user interface
|
||||
- name: modbusid
|
||||
description:
|
||||
generic: Modbus ID
|
||||
default: 1
|
||||
valuetype: number
|
||||
- name: modbusdevice
|
||||
description:
|
||||
de: Geräteadresse
|
||||
en: Device address
|
||||
help:
|
||||
de: USB-RS485 Adapter Adresse
|
||||
en: USB-RS485 Adapter address
|
||||
example: /dev/ttyUSB0
|
||||
- name: modbusbaudrate
|
||||
description:
|
||||
de: Baudrate
|
||||
en: Baudrate
|
||||
help:
|
||||
de: Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200
|
||||
en: Check the device settings, typical values are 9600, 19200, 38400, 57600, 115200
|
||||
default: 9600
|
||||
valuetype: number
|
||||
- name: modbuscomset
|
||||
description:
|
||||
de: ComSet
|
||||
en: ComSet
|
||||
help:
|
||||
de: Kommunikationsparameter für den Adapter
|
||||
en: Communication parameter for the adapter
|
||||
default: "8N1"
|
||||
- name: host
|
||||
description:
|
||||
de: IP-Adresse oder Hostname
|
||||
en: IP-Address or Hostname
|
||||
help:
|
||||
de: IP-Adresse oder Hostname
|
||||
en: IP-Address or Hostname
|
||||
example: "192.0.2.2"
|
||||
- name: port
|
||||
description:
|
||||
de: Port
|
||||
en: Port
|
||||
help:
|
||||
de: Port
|
||||
en: Port
|
||||
valuetype: number
|
||||
- name: user
|
||||
description:
|
||||
de: Benutzername
|
||||
en: Username
|
||||
help:
|
||||
de: Benutzername um auf das Gerät zuzugreifen
|
||||
en: Username to access the device
|
||||
- name: password
|
||||
description:
|
||||
de: Passwort
|
||||
en: Password
|
||||
help:
|
||||
de: Passwort des Benutzerkontos
|
||||
en: Password of the account
|
||||
mask: true
|
||||
- name: capacity
|
||||
description:
|
||||
de: Akku-Kapazität in kWh
|
||||
en: Battery-Capacity in kWh
|
||||
help:
|
||||
de: Akku-Kapazität in kWh
|
||||
en: Battery-Capacity in kWh
|
||||
example: '41.5'
|
||||
valuetype: float
|
||||
- name: vin
|
||||
description:
|
||||
de: Fahrzeugidentifikationsnummer
|
||||
en: Vehicle Identification Number
|
||||
help:
|
||||
de: Erforderlich, wenn mehrere Fahrzeuge des Herstellers vorhanden sind
|
||||
en: Required if you own multiple vehicles of the same brand
|
||||
example: W...
|
||||
- name: cache
|
||||
description:
|
||||
de: Cache
|
||||
en: Cache
|
||||
help:
|
||||
de: Das zeitliche Interval, in welchem Daten vom Fahrzeug neu geladen werden soll
|
||||
en: Time interval with when data should be reloaded from the vehicle
|
||||
example: 5m
|
||||
- name: mode
|
||||
description:
|
||||
de: Standard-Lademodus, wenn ein Fahrzeug angeschlossen ist
|
||||
en: Default charging mode when a vehicle is connected
|
||||
help:
|
||||
de: Möglich sind Off, Now, MinPV und PV, oder leer wenn keiner definiert werden soll
|
||||
en: Possible values are Off, Now, MinPV and PV, or empty if none should be set
|
||||
valuetype: chargemodes
|
||||
- name: minsoc
|
||||
description:
|
||||
de: Minimaler Ladestand (SoC) in %
|
||||
en: Minimum state of charge (SoC) in %
|
||||
help:
|
||||
de: Lade sofort mit maximaler Geschwindigkeit bis zu dem angegeben Ladestand, wenn der Lademodus nicht auf 'Aus' steht
|
||||
en: Charge immediately with maximum power up to the defined state of charge, if the charge mode is not set to 'OFF'
|
||||
example: 25
|
||||
valuetype: number
|
||||
- name: targetsoc
|
||||
description:
|
||||
de: Ziel-Ladestand (SoC) in %
|
||||
en: Target state of charge (SoC) in %
|
||||
help:
|
||||
de: Bis zu welchem Ladestand (SoC) soll das Fahrzeug geladen werden
|
||||
en: Until which state of charge (SoC) should the vehicle be charged
|
||||
example: 80
|
||||
valuetype: number
|
||||
- name: mincurrent
|
||||
description:
|
||||
de: Minimale Stromstärke in Ampere (A)
|
||||
en: Minimum amperage (A)
|
||||
help:
|
||||
de: Definiert die minimale Stromstärke pro angeschlossener Phase mit welcher das Fahrzeug geladen werden soll
|
||||
en: The minimum amperage per connected phase with which the car should be charged
|
||||
example: 6
|
||||
valuetype: number
|
||||
- name: maxcurrent
|
||||
description:
|
||||
de: Maximale Stromstärke in Ampere (A)
|
||||
en: Maximum amperage (A)
|
||||
help:
|
||||
de: Definiert die maximale Stromstärke pro angeschlossener Phase mit welcher das Fahrzeug geladen werden soll
|
||||
en: The maximum amperage per connected phase with which the car shuold be charged
|
||||
example: 16
|
||||
valuetype: number
|
||||
- name: identifiers
|
||||
description:
|
||||
de: Identifikationsnummer
|
||||
en: Identification
|
||||
help:
|
||||
de: "Kann meist erst später eingetragen werden, siehe: https://docs.evcc.io/docs/guides/vehicles/#erkennung-des-fahrzeugs-an-der-wallbox"
|
||||
en: "Mostly this can be added later, see: https://docs.evcc.io/docs/guides/vehicles/#erkennung-des-fahrzeugs-an-der-wallbox"
|
||||
valuetype: stringlist
|
||||
- name: standbypower
|
||||
description:
|
||||
de: Standby-Leistung in W"
|
||||
en: Standby power in W
|
||||
help:
|
||||
de: Leistung oberhalb des angegebenen Wertes wird als Ladeleistung gewertet
|
||||
en: Power values above this value will be considered as charging pow
|
||||
valuetype: number
|
||||
|
||||
presets:
|
||||
vehiclebase:
|
||||
params:
|
||||
- name: title
|
||||
- name: user
|
||||
required: true
|
||||
- name: password
|
||||
required: true
|
||||
- name: vin
|
||||
- name: capacity
|
||||
- name: cache
|
||||
advanced: true
|
||||
render: |
|
||||
{{define "vehicle-base"}}
|
||||
{{- if ne .title "" }}
|
||||
title: {{ .title }}
|
||||
{{- end }}
|
||||
user: {{ .user }}
|
||||
password: {{ .password }}
|
||||
{{- if ne .capacity "" }}
|
||||
capacity: {{ .capacity }}
|
||||
{{- end }}
|
||||
{{- if ne .vin "" }}
|
||||
vin: {{ .vin }}
|
||||
{{- end }}
|
||||
{{- if ne .cache "" }}
|
||||
cache: {{ .cache }}
|
||||
{{- end }}
|
||||
{{end}}
|
||||
vehicleidentify:
|
||||
params:
|
||||
- name: mode
|
||||
advanced: true
|
||||
- name: minSoC
|
||||
advanced: true
|
||||
- name: targetSoC
|
||||
advanced: true
|
||||
- name: minCurrent
|
||||
advanced: true
|
||||
- name: maxCurrent
|
||||
advanced: true
|
||||
- name: identifiers
|
||||
advanced: true
|
||||
valueType: stringlist
|
||||
render: |
|
||||
{{define "vehicle-identify"}}
|
||||
{{- if or (ne .mode "") (ne .minSoC "") (ne .targetSoC "") (ne .minCurrent "") (ne .maxCurrent "") }}
|
||||
onIdentify:
|
||||
{{- if (ne .mode "") }}
|
||||
mode: {{ .mode }}
|
||||
{{- end }}
|
||||
{{- if (ne .minSoC "") }}
|
||||
minSoC: {{ .minSoC }}
|
||||
{{- end }}
|
||||
{{- if (ne .targetSoC "") }}
|
||||
targetSoC: {{ .targetSoC }}
|
||||
{{- end }}
|
||||
{{- if (ne .minCurrent "") }}
|
||||
minCurrent: {{ .minCurrent }}
|
||||
{{- end }}
|
||||
{{- if (ne .maxCurrent "") }}
|
||||
maxCurrent: {{ .maxCurrent }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if ne (len .identifiers) 0 }}
|
||||
identifiers:
|
||||
{{- range .identifiers }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{end}}
|
||||
|
||||
modbus:
|
||||
interfaces:
|
||||
rs485: ["rs485serial", "rs485tcpip"]
|
||||
tcpip: ["tcpip"]
|
||||
types:
|
||||
rs485serial:
|
||||
description:
|
||||
generic: Serial (USB-RS485 Adapter)
|
||||
params:
|
||||
- reference: true
|
||||
referencename: modbusid
|
||||
name: id
|
||||
- reference: true
|
||||
referencename: modbusdevice
|
||||
name: device
|
||||
- reference: true
|
||||
referencename: modbusbaudrate
|
||||
name: baudrate
|
||||
- reference: true
|
||||
referencename: modbuscomset
|
||||
name: comset
|
||||
rs485tcpip:
|
||||
description:
|
||||
generic: Serial (Ethernet-RS485 Adapter)
|
||||
params:
|
||||
- reference: true
|
||||
referencename: modbusid
|
||||
name: id
|
||||
- reference: true
|
||||
name: host
|
||||
- reference: true
|
||||
name: port
|
||||
default: 502
|
||||
- name: rtu
|
||||
default: true
|
||||
hidden: true
|
||||
tcpip:
|
||||
description:
|
||||
generic: TCP/IP
|
||||
params:
|
||||
- reference: true
|
||||
referencename: modbusid
|
||||
name: id
|
||||
- reference: true
|
||||
name: host
|
||||
- reference: true
|
||||
name: port
|
||||
default: 502
|
||||
|
||||
devicegroups:
|
||||
generic:
|
||||
de: Generische Unterstützung
|
||||
en: generic support
|
||||
switchsockets:
|
||||
de: Schaltbare Steckdosen
|
||||
en: switchable sockets
|
||||
sockets:
|
||||
de: Steckdosen
|
||||
en: power sockets
|
||||
|
|
@ -6,6 +6,6 @@ var (
|
|||
//go:embed charger/*.yaml meter/*.yaml vehicle/*.yaml
|
||||
YamlTemplates embed.FS
|
||||
|
||||
//go:embed parambaselist.yaml
|
||||
ParamBaseListDefinition string
|
||||
//go:embed defaults.yaml
|
||||
DefaultsContent string
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
template: cfos
|
||||
description:
|
||||
generic: cFos PowerBrain Meter
|
||||
requirements:
|
||||
sponsorship: true
|
||||
products:
|
||||
- brand: cFos
|
||||
description:
|
||||
generic: PowerBrain Meter
|
||||
requirements:
|
||||
evcc: ["sponsorship"]
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "charge" ]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
template: discovergy
|
||||
description:
|
||||
generic: Discovergy (Cloud)
|
||||
products:
|
||||
- description:
|
||||
generic: Discovergy (Cloud)
|
||||
params:
|
||||
- name: usage
|
||||
choice: ["grid", "pv"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
template: e3dc
|
||||
description:
|
||||
generic: E3DC
|
||||
products:
|
||||
- description:
|
||||
generic: E3DC
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
template: eastron
|
||||
description:
|
||||
de: Eastron SDM Modbus Strommessgeräte
|
||||
en: Eastron SDM Modbus Meter
|
||||
products:
|
||||
- brand: Eastron
|
||||
description:
|
||||
de: SDM Modbus Strommessgeräte
|
||||
en: SDM Modbus Meter
|
||||
params:
|
||||
- name: usage
|
||||
choice: ["grid", "pv", "battery", "charge"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
template: fritzdect
|
||||
description:
|
||||
generic: FritzDECT
|
||||
products:
|
||||
- brand: AVM
|
||||
description:
|
||||
generic: FritzDECT
|
||||
group: sockets
|
||||
params:
|
||||
- name: usage
|
||||
choice: ["pv", "charge"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: fronius-gen24
|
||||
description:
|
||||
generic: Fronius Symo GEN24 Plus
|
||||
products:
|
||||
- brand: Fronius
|
||||
description:
|
||||
generic: Symo GEN24 Plus
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: fronius-solarapi-v1
|
||||
description:
|
||||
generic: Fronius Solar API V1
|
||||
products:
|
||||
- brand: Fronius
|
||||
description:
|
||||
generic: Solar API V1
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
103
templates/definition/meter/huawei-dongle-powersensor.yaml
Normal file
103
templates/definition/meter/huawei-dongle-powersensor.yaml
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
template: huawei-dongle-powersensor
|
||||
products:
|
||||
- brand: Huawei
|
||||
description:
|
||||
generic: SUN2000 with Sdongle & Power Sensor
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid", "pv", "battery" ]
|
||||
- name: modbus
|
||||
choice: ["tcpip"]
|
||||
render: |
|
||||
type: custom
|
||||
{{- if eq .usage "grid" }}
|
||||
power:
|
||||
source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
timeout: 30s
|
||||
connectdelay: 5
|
||||
delay: 2s
|
||||
register:
|
||||
address: 37113 # Grid import export power
|
||||
type: holding
|
||||
decode: int32
|
||||
scale: -1
|
||||
energy:
|
||||
source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
timeout: 30s
|
||||
connectdelay: 5
|
||||
delay: 2s
|
||||
register:
|
||||
address: 37121 # Grid active energy
|
||||
type: holding
|
||||
decode: int32
|
||||
scale: 0.01
|
||||
currents:
|
||||
- source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
register:
|
||||
address: 37107 # Huawei phase A grid current
|
||||
type: holding
|
||||
decode: int32
|
||||
scale: -0.01
|
||||
- source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
register:
|
||||
address: 37109 # Huawei phase B grid current
|
||||
type: holding
|
||||
decode: int32
|
||||
scale: -0.01
|
||||
- source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
register:
|
||||
address: 37111 # Huawei phase C grid current
|
||||
type: holding
|
||||
decode: int32
|
||||
scale: -0.01
|
||||
{{- end }}
|
||||
{{- if eq .usage "pv" }}
|
||||
power:
|
||||
source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
timeout: 30s
|
||||
connectdelay: 5
|
||||
delay: 2s
|
||||
register:
|
||||
address: 32080 # Active generation power
|
||||
type: holding
|
||||
decode: int32
|
||||
{{- end }}
|
||||
{{- if eq .usage "battery" }}
|
||||
power:
|
||||
source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
timeout: 30s
|
||||
connectdelay: 5
|
||||
delay: 2s
|
||||
register:
|
||||
address: 37001
|
||||
type: holding
|
||||
decode: int32
|
||||
soc:
|
||||
source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
timeout: 30s
|
||||
connectdelay: 5
|
||||
delay: 2s
|
||||
register:
|
||||
address: 37004
|
||||
type: holding
|
||||
decode: uint16
|
||||
scale: 0.1
|
||||
{{- end }}
|
||||
25
templates/definition/meter/huawei-dongle.yaml
Normal file
25
templates/definition/meter/huawei-dongle.yaml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
template: huawei-dongle
|
||||
products:
|
||||
- brand: Huawei
|
||||
description:
|
||||
generic: SUN2000 with Sdongle
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "pv" ]
|
||||
- name: modbus
|
||||
choice: ["tcpip"]
|
||||
render: |
|
||||
type: custom
|
||||
power:
|
||||
source: modbus
|
||||
{{include "modbus" . | indent 2}}
|
||||
model: huawei
|
||||
timeout: 30s
|
||||
connectdelay: 5s
|
||||
delay: 2s
|
||||
register:
|
||||
address: 32080 # Active generation power
|
||||
type: holding
|
||||
decode: int32
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
template: huawei-sun2000-8ktl
|
||||
description:
|
||||
generic: Huawei SUN2000-8KTL
|
||||
products:
|
||||
- brand: Huawei
|
||||
description:
|
||||
generic: SUN2000-8KTL
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "pv" ]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
template: kostal-ksem-inverter
|
||||
description:
|
||||
de: Kostal Smart Energy Meter über den Wechselrichter
|
||||
en: Kostal Smart Energy Meter via inverter
|
||||
products:
|
||||
- brand: Kostal
|
||||
description:
|
||||
de: Smart Energy Meter (über den Wechselrichter)
|
||||
en: Smart Energy Meter (via inverter)
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid" ]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: kostal-ksem
|
||||
description:
|
||||
generic: Kostal Smart Energy Meter
|
||||
products:
|
||||
- brand: Kostal
|
||||
description:
|
||||
generic: Smart Energy Meter
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid" ]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: kostal-piko-mp-plus
|
||||
description:
|
||||
generic: Kostal Piko MP Plus
|
||||
products:
|
||||
- brand: Kostal
|
||||
description:
|
||||
generic: Piko MP Plus
|
||||
guidedsetup:
|
||||
enable: true
|
||||
linked:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
template: kostal-piko
|
||||
description:
|
||||
generic: Kostal Piko + Piko BA
|
||||
products:
|
||||
- brand: Kostal
|
||||
description:
|
||||
generic: Piko
|
||||
- brand: Kostal
|
||||
description:
|
||||
generic: Piko BA
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: kostal-plenticore
|
||||
description:
|
||||
generic: Kostal Plenticore Hybrid
|
||||
products:
|
||||
- brand: Kostal
|
||||
description:
|
||||
generic: Plenticore Hybrid
|
||||
guidedsetup:
|
||||
enable: true
|
||||
linked:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: lg-ess-home-8-10
|
||||
description:
|
||||
generic: LG ESS Home 8/10
|
||||
products:
|
||||
- brand: LG
|
||||
description:
|
||||
generic: ESS Home 8/10
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
template: mqtt-meter
|
||||
description:
|
||||
de: MQTT Strommessgerät
|
||||
en: MQTT Meter
|
||||
generic: true
|
||||
requirements:
|
||||
mqtt: true
|
||||
products:
|
||||
- description:
|
||||
de: MQTT Strommessgerät
|
||||
en: MQTT Meter
|
||||
group: generic
|
||||
requirements:
|
||||
evcc: ["mqtt"]
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid", "pv", "charge", "battery" ]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
template: powerdog
|
||||
description:
|
||||
generic: Powerdog
|
||||
products:
|
||||
- description:
|
||||
generic: Powerdog
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: powerfox-poweropti
|
||||
description:
|
||||
generic: Powerfox Poweropti (Cloud)
|
||||
products:
|
||||
- brand: Powerfox
|
||||
description:
|
||||
generic: Poweropti (Cloud)
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid" ]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: rct-power
|
||||
description:
|
||||
generic: RCT Power
|
||||
products:
|
||||
- brand: RCT
|
||||
description:
|
||||
generic: Power
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: senec-home
|
||||
description:
|
||||
generic: SENEC.Home
|
||||
products:
|
||||
- brand: SENEC
|
||||
description:
|
||||
generic: .Home
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
template: shelly-3em
|
||||
description:
|
||||
generic: Shelly 3EM
|
||||
products:
|
||||
- brand: Shelly
|
||||
description:
|
||||
generic: 3EM
|
||||
group: sockets
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid" ]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: sma-energy-meter
|
||||
description:
|
||||
generic: SMA Energy Meter (Produktname)
|
||||
products:
|
||||
- brand: SMA
|
||||
description:
|
||||
generic: Energy Meter
|
||||
params:
|
||||
- name: usage
|
||||
choice: ["grid", "pv", "battery"]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
template: sma-home-manager
|
||||
description:
|
||||
generic: SMA Sunny Home Manager 2.0
|
||||
requirements:
|
||||
hems: sma
|
||||
products:
|
||||
- brand: SMA
|
||||
description:
|
||||
generic: Sunny Home Manager 2.0
|
||||
capabilities: ["smahems"]
|
||||
guidedsetup:
|
||||
enable: true
|
||||
linked:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
template: sma-inverter
|
||||
description:
|
||||
de: SMA Wechselrichter
|
||||
en: SMA Inverter
|
||||
products:
|
||||
- brand: SMA
|
||||
description:
|
||||
de: Wechselrichter
|
||||
en: Inverter
|
||||
params:
|
||||
- name: usage
|
||||
choice: ["pv", "battery"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: solaredge-hybrid
|
||||
description:
|
||||
generic: Solaredge Hybrid
|
||||
products:
|
||||
- brand: Solaredge
|
||||
description:
|
||||
generic: Hybrid
|
||||
guidedsetup:
|
||||
enable: true
|
||||
requirements:
|
||||
|
|
|
|||
|
|
@ -1,17 +1,27 @@
|
|||
template: solaredge-inverter
|
||||
description:
|
||||
de: Solaredge Wechselrichter
|
||||
en: Solaredge Inverter
|
||||
products:
|
||||
- brand: Solaredge
|
||||
description:
|
||||
de: Wechselrichter
|
||||
en: Inverter
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "pv" ]
|
||||
choice: [ "grid", "pv" ]
|
||||
- name: modbus
|
||||
choice: [ "tcpip" ]
|
||||
id: 1
|
||||
port: 1502
|
||||
- name: timeout
|
||||
default: 3s
|
||||
render: |
|
||||
type: modbus
|
||||
model: sunspec
|
||||
{{ include "modbus" . }}
|
||||
timeout: {{ .timeout }}
|
||||
{{- if eq .usage "grid" }}
|
||||
subdevice: 1
|
||||
power: 203:W # sunspec 3-phase meter power reading
|
||||
scale: -1
|
||||
{{- end -}}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
template: solarlog
|
||||
description:
|
||||
generic: Solarlog
|
||||
products:
|
||||
- description:
|
||||
generic: Solarlog
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: solarwatt-myreserve
|
||||
description:
|
||||
generic: Solarwatt MyReserve
|
||||
products:
|
||||
- brand: Solarwatt
|
||||
description:
|
||||
generic: MyReserve
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: sonnenbatterie-eco10
|
||||
description:
|
||||
generic: Sonnenbatterie Eco/10
|
||||
products:
|
||||
- brand: Sonnenbatterie
|
||||
description:
|
||||
generic: Eco/10
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: sungrow
|
||||
description:
|
||||
generic: Sungrow (Beta)
|
||||
products:
|
||||
- brand: Sungrow
|
||||
description:
|
||||
generic: Inverter (Beta)
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
template: sunspec
|
||||
description:
|
||||
de: Wechselrichter (SunSpec)
|
||||
en: Inverter (SunSpec)
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
de: Wechselrichter (SunSpec)
|
||||
en: Inverter (SunSpec)
|
||||
group: generic
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid", "pv", "battery" ]
|
||||
|
|
@ -13,6 +14,7 @@ render: |
|
|||
model: sunspec
|
||||
{{ include "modbus" .}}
|
||||
{{- if eq .usage "grid" }}
|
||||
subdevice: 1
|
||||
power: 203:W # sunspec 3-phase meter power reading
|
||||
{{- end -}}
|
||||
{{- if eq .usage "battery" }}
|
||||
|
|
|
|||
21
templates/definition/meter/tasmota.yaml
Normal file
21
templates/definition/meter/tasmota.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
template: tasmota
|
||||
products:
|
||||
- description:
|
||||
generic: Tasmota
|
||||
group: sockets
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid", "pv", "charge" ]
|
||||
- name: host
|
||||
required: true
|
||||
example: 192.0.2.2
|
||||
render: |
|
||||
type: custom
|
||||
power: # power reading (W)
|
||||
source: http
|
||||
uri: http://{{ .host }}/cm?cmnd=Status%208
|
||||
jq: .StatusSNS.ENERGY.Power
|
||||
energy: # energy reading (Wh)
|
||||
source: http
|
||||
uri: http://{{ .host }}/cm?cmnd=Status%208
|
||||
jq: .StatusSNS.ENERGY.Total * 1000
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
template: tesla-powerwall
|
||||
description:
|
||||
generic: Tesla Powerwall
|
||||
products:
|
||||
- brand: Tesla
|
||||
description:
|
||||
generic: Powerwall
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: varta-energiespeicher
|
||||
description:
|
||||
generic: VARTA Energiespeicher
|
||||
products:
|
||||
- brand: VARTA
|
||||
description:
|
||||
generic: Energiespeicher
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
template: victron-energy
|
||||
description:
|
||||
generic: Victron Energy
|
||||
products:
|
||||
- brand: Victron
|
||||
description:
|
||||
generic: Energy
|
||||
guidedsetup:
|
||||
enable: true
|
||||
params:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
template: volkszaehler-http
|
||||
description:
|
||||
generic: Volkszähler (HTTP API)
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
generic: Volkszähler (HTTP API)
|
||||
group: generic
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid" ]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
template: volkszaehler-importexport
|
||||
description:
|
||||
generic: Volkszähler (HTTP API, Import & Export)
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
generic: Volkszähler (HTTP API, Import & Export)
|
||||
group: generic
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid" ]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
template: volkszaehler-ws
|
||||
description:
|
||||
generic: Volkszähler (WebSocket API)
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
generic: Volkszähler (WebSocket API)
|
||||
group: generic
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid" ]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
template: vzlogger
|
||||
description:
|
||||
generic: vzlogger
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
generic: vzlogger
|
||||
group: generic
|
||||
params:
|
||||
- name: usage
|
||||
choice: [ "grid" ]
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
vehiclebase:
|
||||
params:
|
||||
- name: title
|
||||
- name: user
|
||||
required: true
|
||||
- name: password
|
||||
required: true
|
||||
mask: true
|
||||
- name: vin
|
||||
example: W...
|
||||
- name: capacity
|
||||
default: '50'
|
||||
- name: cache
|
||||
advanced: true
|
||||
render: |
|
||||
{{define "vehicle-base"}}
|
||||
{{- if ne .title "" }}
|
||||
title: {{ .title }}
|
||||
{{- end }}
|
||||
user: {{ .user }}
|
||||
password: {{ .password }}
|
||||
{{- if ne .capacity "" }}
|
||||
capacity: {{ .capacity }}
|
||||
{{- end }}
|
||||
{{- if ne .vin "" }}
|
||||
vin: {{ .vin }}
|
||||
{{- end }}
|
||||
{{- if ne .cache "" }}
|
||||
cache: {{ .cache }}
|
||||
{{- end }}
|
||||
{{end}}
|
||||
vehicleidentify:
|
||||
params:
|
||||
- name: mode
|
||||
advanced: true
|
||||
- name: minSoC
|
||||
advanced: true
|
||||
- name: targetSoC
|
||||
advanced: true
|
||||
- name: minCurrent
|
||||
advanced: true
|
||||
- name: maxCurrent
|
||||
advanced: true
|
||||
- name: identifiers
|
||||
advanced: true
|
||||
valueType: stringlist
|
||||
render: |
|
||||
{{define "vehicle-identify"}}
|
||||
{{- if or (ne .mode "") (ne .minSoC "") (ne .targetSoC "") (ne .minCurrent "") (ne .maxCurrent "") }}
|
||||
onIdentify:
|
||||
{{- if (ne .mode "") }}
|
||||
mode: {{ .mode }}
|
||||
{{- end }}
|
||||
{{- if (ne .minSoC "") }}
|
||||
minSoC: {{ .minSoC }}
|
||||
{{- end }}
|
||||
{{- if (ne .targetSoC "") }}
|
||||
targetSoC: {{ .targetSoC }}
|
||||
{{- end }}
|
||||
{{- if (ne .minCurrent "") }}
|
||||
minCurrent: {{ .minCurrent }}
|
||||
{{- end }}
|
||||
{{- if (ne .maxCurrent "") }}
|
||||
maxCurrent: {{ .maxCurrent }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if ne (len .identifiers) 0 }}
|
||||
identifiers:
|
||||
{{- range .identifiers }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{end}}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
template: audi
|
||||
description:
|
||||
generic: Audi
|
||||
products:
|
||||
- brand: Audi
|
||||
params:
|
||||
- base: vehiclebase
|
||||
- base: vehicleidentify
|
||||
- preset: vehiclebase
|
||||
- preset: vehicleidentify
|
||||
- name: vin
|
||||
example: WAUZZZ...
|
||||
- name: capacity
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
template: bmw
|
||||
description:
|
||||
generic: BMW
|
||||
products:
|
||||
- brand: BMW
|
||||
params:
|
||||
- base: vehiclebase
|
||||
- base: vehicleidentify
|
||||
- preset: vehiclebase
|
||||
- preset: vehicleidentify
|
||||
- name: vin
|
||||
example: WBMW...
|
||||
- name: capacity
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
template: carwings
|
||||
description:
|
||||
generic: Nissan Leaf (pre 2019)
|
||||
products:
|
||||
- brand: Nissan
|
||||
description:
|
||||
generic: Leaf (pre 2019)
|
||||
params:
|
||||
- base: vehiclebase
|
||||
- base: vehicleidentify
|
||||
- preset: vehiclebase
|
||||
- preset: vehicleidentify
|
||||
- name: capacity
|
||||
default: 50
|
||||
render: |
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
template: citroen
|
||||
description:
|
||||
generic: Citroen
|
||||
products:
|
||||
- brand: Citroen
|
||||
params:
|
||||
- base: vehiclebase
|
||||
- base: vehicleidentify
|
||||
- preset: vehiclebase
|
||||
- preset: vehicleidentify
|
||||
- name: capacity
|
||||
default: 50
|
||||
render: |
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
template: dacia
|
||||
description:
|
||||
generic: Dacia
|
||||
products:
|
||||
- brand: Dacia
|
||||
params:
|
||||
- base: vehiclebase
|
||||
- base: vehicleidentify
|
||||
- preset: vehiclebase
|
||||
- preset: vehicleidentify
|
||||
- name: capacity
|
||||
default: 27.4
|
||||
render: |
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
template: ds
|
||||
description:
|
||||
generic: DS
|
||||
products:
|
||||
- brand: DS
|
||||
params:
|
||||
- base: vehiclebase
|
||||
- base: vehicleidentify
|
||||
- preset: vehiclebase
|
||||
- preset: vehicleidentify
|
||||
- name: capacity
|
||||
default: 50
|
||||
render: |
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
template: evnotify
|
||||
description:
|
||||
generic: evNotify
|
||||
generic: true
|
||||
products:
|
||||
- description:
|
||||
generic: evNotify
|
||||
group: generic
|
||||
params:
|
||||
- name: title
|
||||
- name: akey
|
||||
|
|
@ -11,7 +12,7 @@ params:
|
|||
- name: capacity
|
||||
default: 64
|
||||
valuetype: float
|
||||
- base: vehicleidentify
|
||||
- preset: vehicleidentify
|
||||
render: |
|
||||
type: custom
|
||||
{{- if ne .title "" }}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue