Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ require (
github.com/google/uuid v1.6.0
github.com/gorilla/handlers v1.5.2
github.com/gorilla/mux v1.8.1
github.com/gosimple/slug v1.15.0
github.com/gregdel/pushover v1.3.1
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
github.com/grid-x/modbus v0.0.0-20250516072809-4b99c910e8e7
Expand Down Expand Up @@ -151,6 +152,7 @@ require (
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e // indirect
github.com/google/renameio/v2 v2.0.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWS
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo=
github.com/gosimple/slug v1.15.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
github.com/gregdel/pushover v1.3.1 h1:4bMLITOZ15+Zpi6qqoGqOPuVHCwSUvMCgVnN5Xhilfo=
github.com/gregdel/pushover v1.3.1/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
Expand Down
2 changes: 1 addition & 1 deletion templates/definition/charger/ocpp-abb-tac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ covers: ["ocpp-abb"]
products:
- brand: ABB
description:
generic: Terra AC
generic: Terra AC (OCPP)
capabilities: ["mA", "rfid"]
requirements:
evcc: ["sponsorship", "skiptest"]
Expand Down
2 changes: 1 addition & 1 deletion templates/definition/charger/ocpp-alfen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ template: ocpp-alfen
products:
- brand: Alfen
description:
generic: Eve
generic: Eve (OCPP)
capabilities: ["mA", "rfid", "1p3p"]
requirements:
evcc: ["sponsorship", "skiptest"]
Expand Down
8 changes: 4 additions & 4 deletions templates/definition/charger/ocpp-goe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ covers: ["ocpp-fronius-wattpilot"]
products:
- brand: go-e
description:
generic: Charger V3
generic: Charger V3 (OCPP)
- brand: go-e
description:
generic: Charger Gemini
generic: Charger Gemini (OCPP)
- brand: go-e
description:
generic: Charger PRO
generic: Charger PRO (OCPP)
- brand: Fronius
description:
generic: Wattpilot
generic: Wattpilot (OCPP)
capabilities: ["rfid", "1p3p"]
requirements:
evcc: ["sponsorship", "skiptest"]
Expand Down
2 changes: 1 addition & 1 deletion templates/definition/charger/ocpp-zaptec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ template: ocpp-zaptec
products:
- brand: Zaptec
description:
generic: Go
generic: Go (OCPP)
Comment thread
andig marked this conversation as resolved.
capabilities: ["rfid"]
requirements:
description:
Expand Down
4 changes: 3 additions & 1 deletion util/templates/documentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ func (t *Template) RenderDocumentation(product Product, lang string) ([]byte, er
}

var modbusRender string
modbusData := make(map[string]interface{})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warum brauchts das?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plan ist auf der Produkt-Seite in der Doku die einzelnen Parameter tabellarisch zu erklären. Bei den Modbus-Geräten haben wir ja implizite Parameter erzeugt, die durch die Modbus Eigenschaft erzeugt werden. Dafür braucht es die Modbus Infos (Defaults, ...) des Geräts. Quasi das Äquivalent zur documentation_modbus.tpl.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Die werden doch aber- falls modbus- weiter unten eh angelegt?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was meinst du damit? Modbus ist ja immer eine Sonderbehandlung in der Darstellung. Unterschiedliche Optionen/Spielarten aus denen der Nutzer auswählen muss und so.

Wenns um die konkrete Zeile geht. Die hab ich nur weiter nach vorne geschoben, damit die Daten nicht nur in documentation_modbus.tpl verwendet werden können, sondern auch als strukturierte Daten mit in die Doku-Yaml Datei aufgenommen werden.

Bildschirmfoto 2025-06-06 um 23 14 31

if modbusChoices := t.ModbusChoices(); len(modbusChoices) > 0 {
if i, _ := t.ParamByName(ParamModbus); i > -1 {
modbusTmpl, err := template.New("yaml").Funcs(sprig.FuncMap()).Parse(documentationModbusTmpl)
if err != nil {
panic(err)
}

modbusData := make(map[string]interface{})
t.ModbusValues(RenderModeDocs, modbusData)

out := new(bytes.Buffer)
Expand Down Expand Up @@ -91,6 +91,7 @@ func (t *Template) RenderDocumentation(product Product, lang string) ([]byte, er

data := map[string]interface{}{
"Template": t.Template,
"ProductIdentifier": product.Identifier(),
"ProductBrand": product.Brand,
"ProductDescription": product.Description.String(lang),
"ProductGroup": t.GroupTitle(lang),
Expand All @@ -102,6 +103,7 @@ func (t *Template) RenderDocumentation(product Product, lang string) ([]byte, er
"AdvancedParams": hasAdvancedParams,
"Usages": t.Usages(),
"Modbus": modbusRender,
"ModbusData": modbusData,
}

out := new(bytes.Buffer)
Expand Down
28 changes: 26 additions & 2 deletions util/templates/documentation.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
- {{ . }}
{{- end }}
{{- $unit := .Unit -}}
{{- $description := localize .Description | replace "\n" " " -}}
{{- $help := localize .Help | replace "\n" " " -}}
{{- $description := localize .Description | replace "\n" " " | trim -}}
{{- $help := localize .Help | replace "\n" " " | trim -}}
{{- $choices := join ", " .Choice -}}
{{- $optional := not .IsRequired -}}
{{- if or $help $choices $optional $description }} # {{end}}
Expand Down Expand Up @@ -52,7 +52,9 @@
{{- end }}
{{- end -}}

template: {{ .Template }}
product:
identifier: {{ .ProductIdentifier }}
{{- if .ProductBrand }}
brand: {{ .ProductBrand }}
{{- end }}
Expand Down Expand Up @@ -96,3 +98,25 @@ render:
{{- include "advanced" . | indent 4 }}
{{- end }}
{{- end }}
params:
{{- range .Params }}
{{- if and (not (eq .Name "usage")) (not .IsDeprecated) }}
- name: {{ .Name | quote }}
example: {{ .Example | quote }}
default: {{ .Default }}
choice: [{{ join ", " .Choice }}]
unit: {{ .Unit }}
{{- $description := localize .Description | replace "\n" " " | trim }}
description: {{ $description | quote }}
{{- $help := localize .Help | replace "\n" " " | trim }}
help: {{ $help | quote }}
advanced: {{ .IsAdvanced }}
optional: {{ not .IsRequired }}
{{- end }}
{{- end }}
{{- if .ModbusData }}
modbus:
{{- range $key, $value := .ModbusData }}
{{ $key }}: {{ $value }}
{{- end }}
{{- end }}
53 changes: 51 additions & 2 deletions util/templates/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@ import (
"strings"

"github.com/evcc-io/evcc/util/templates"
"github.com/gosimple/slug"
)

const (
docsPath = "../../../templates/docs"
websitePath = "../../../templates/evcc.io"
iconsPath = "../../../templates/icons"
)

//go:generate go run main.go

func main() {
slug.CustomSub = map[string]string{"+": "plus"}

for _, lang := range []string{"de", "en"} {
if err := generateDocs(lang); err != nil {
panic(err)
Expand All @@ -28,6 +32,10 @@ func main() {
if err := generateBrandJSON(); err != nil {
panic(err)
}

if err := generateProductJSON(); err != nil {
panic(err)
}
}

func generateDocs(lang string) error {
Expand Down Expand Up @@ -57,15 +65,20 @@ func generateClass(class templates.Class, lang string) error {
return err
}

for index, product := range tmpl.Products {
for _, product := range tmpl.Products {
fmt.Println(tmpl.Template + ": " + product.Title(lang))

b, err := tmpl.RenderDocumentation(product, lang)
if err != nil {
return err
}

filename := fmt.Sprintf("%s/%s/%s/%s_%d.yaml", docsPath, lang, strings.ToLower(class.String()), tmpl.Template, index)
filename := fmt.Sprintf("%s/%s/%s/%s.yaml", docsPath, lang, strings.ToLower(class.String()), product.Identifier())

if _, err := os.Stat(filename); err == nil {
return fmt.Errorf("file already exists: %s - product titles must be unique", filename)
}

if err := os.WriteFile(filename, b, 0o644); err != nil {
return err
}
Expand Down Expand Up @@ -164,3 +177,39 @@ func generateBrandJSON() error {

return err
}

func generateProductJSON() error {
type ProductInfo struct {
Brand string `json:"brand"`
Description string `json:"description"`
}

products := make(map[string]map[string]ProductInfo)

for _, class := range templates.ClassValues() {
classKey := strings.ToLower(class.String())
products[classKey] = make(map[string]ProductInfo)

for _, tmpl := range templates.ByClass(class) {
for _, product := range tmpl.Products {
products[classKey][product.Identifier()] = ProductInfo{
Brand: product.Brand,
Description: product.Description.String("en"),
}
}
}
}

if _, err := os.Stat(iconsPath); os.IsNotExist(err) {
if err := os.MkdirAll(iconsPath, 0o755); err != nil {
return err
}
}

file, err := json.MarshalIndent(products, "", " ")
if err == nil {
err = os.WriteFile(iconsPath+"/products.json", file, 0o644)
}

return err
}
7 changes: 7 additions & 0 deletions util/templates/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"dario.cat/mergo"
"github.com/gosimple/slug"
)

const (
Expand Down Expand Up @@ -259,10 +260,16 @@ type Product struct {
Description TextLanguage `json:",omitempty"` // product name
}

// Title returns the product title in the given language
func (p Product) Title(lang string) string {
return strings.TrimSpace(fmt.Sprintf("%s %s", p.Brand, p.Description.String(lang)))
}

// Identifier returns a unique language-independent identifier for the product
func (p Product) Identifier() string {
Comment thread
naltatis marked this conversation as resolved.
return slug.Make(p.Title("en"))
}

type CountryCode string

func (c CountryCode) IsValid() bool {
Expand Down
Loading