package main import ( "encoding/xml" "flag" "fmt" "io" "os" "github.com/BurntSushi/toml" ) type Project struct { XMLName xml.Name `xml:"Project"` ChannelList []Channel `xml:"ChannelList>Channel"` } type Channel struct { Name string `xml:"Name"` DeviceList []Device `xml:"DeviceList>Device"` } type Device struct { Name string `xml:"Name"` TagList []Tag `xml:"TagList>Tag"` } type Tag struct { Name string `xml:"Name"` Description string `xml:"Description"` } type TelegrafConfig struct { Inputs struct { OPCUA []struct { Nodes []map[string]interface{} `toml:"nodes"` } `toml:"inputs.opcua"` } `toml:"inputs"` } func printStatistics(project Project, nodes []map[string]interface{}) { groupSet := make(map[string]bool) roomSet := make(map[string]bool) for _, channel := range project.ChannelList { groupSet[channel.Name] = true for _, device := range channel.DeviceList { roomSet[fmt.Sprintf("%s.%s", channel.Name, device.Name)] = true } } fmt.Printf("Statistics:\n") fmt.Printf(" Number of groups: %d\n", len(groupSet)) fmt.Printf(" Number of rooms: %d\n", len(roomSet)) fmt.Printf(" Total number of nodes: %d\n", len(nodes)) } func main() { // Parse CLI args flag.Parse() if flag.NArg() != 3 { fmt.Println("Usage: program ") flag.PrintDefaults() return } kepwareXML := flag.Arg(0) inputFile := flag.Arg(1) outputFile := flag.Arg(2) // Read the XML file xmlFile, err := os.Open(kepwareXML) if err != nil { fmt.Println("Error opening file:", err) return } defer xmlFile.Close() byteValue, _ := io.ReadAll(xmlFile) var project Project xml.Unmarshal(byteValue, &project) // Read the base Telegraf config var config map[string]interface{} if _, err := toml.DecodeFile(inputFile, &config); err != nil { fmt.Println("Error reading base config:", err) return } // Generate node definitions var nodes []map[string]interface{} for _, channel := range project.ChannelList { for _, device := range channel.DeviceList { for _, tag := range device.TagList { node := map[string]interface{}{ "name": tag.Name, "identifier_type": "s", "namespace": "2", "identifier": fmt.Sprintf("%s.%s.%s", channel.Name, device.Name, tag.Name), "tags": [][]string{ {"group", channel.Name}, {"room", device.Name}, }, } nodes = append(nodes, node) } } } // Print statistics printStatistics(project, nodes) // Update the config inputs, ok := config["inputs"].(map[string]interface{}) if !ok { fmt.Println("Error: 'inputs' section not found in config") return } opcuaInputs, ok := inputs["opcua_listener"].([]map[string]interface{}) if !ok || len(opcuaInputs) == 0 { fmt.Println("Warn: 'inputs.opcua_listener' section not found in config") // return } else { opcuaInputs[0]["nodes"] = nodes } opcuaListenerInputs, ok := inputs["opcua"].([]map[string]interface{}) if !ok || len(opcuaListenerInputs) == 0 { fmt.Println("Warn: 'inputs.opcua' section not found in config") // return } else { opcuaListenerInputs[0]["nodes"] = nodes } // Write the updated config to a new file f, err := os.Create(outputFile) if err != nil { fmt.Println("Error creating output file:", err) return } defer f.Close() encoder := toml.NewEncoder(f) encoder.Indent = " " if err := encoder.Encode(config); err != nil { fmt.Println("Error encoding TOML:", err) return } fmt.Println("Config generated successfully: generated_telegraf.conf.toml") }