blob: 6ccb6732e1c4375854d68a4d09a4fd9983e968cf [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package main
import (
"os"
"time"
"github.com/apache/plc4x/plc4go/pkg/api"
"github.com/apache/plc4x/plc4go/pkg/api/drivers"
"github.com/apache/plc4x/plc4go/pkg/api/logging"
apiModel "github.com/apache/plc4x/plc4go/pkg/api/model"
"github.com/apache/plc4x/plc4go/spi/utils"
"github.com/rs/zerolog/log"
)
func main() {
// Set logging to INFO
logging.InfoLevel()
driverManager := plc4go.NewPlcDriverManager()
drivers.RegisterKnxDriver(driverManager)
var connectionStrings []string
if len(os.Args) < 2 {
// Try to auto-find KNX gateways via broadcast-message discovery
_ = driverManager.Discover(func(event apiModel.PlcDiscoveryItem) {
connStr := event.GetProtocolCode() + "://" + event.GetTransportUrl().Host
log.Info().Str("connection string", connStr).Msg("Found KNX Gateway")
connectionStrings = append(connectionStrings, connStr)
})
// Wait for 5 seconds for incoming responses
time.Sleep(time.Second * 5)
} else {
connStr := "knxnet-ip://" + os.Args[1] + ":3671"
log.Info().Str("connection string", connStr).Msg("Using manually provided KNX Gateway")
connectionStrings = append(connectionStrings, connStr)
}
for _, connStr := range connectionStrings {
log.Info().Str("connection string", connStr).Msg("Connecting")
crc := driverManager.GetConnection(connStr)
// Wait for the driver to connect (or not)
connectionResult := <-crc
if connectionResult.GetErr() != nil {
log.Error().Msgf("error connecting to PLC: %s", connectionResult.GetErr().Error())
return
}
log.Info().Str("connection string", connStr).Msg("Connected")
connection := connectionResult.GetConnection()
connection.BlockingClose()
// Try to find all KNX devices on the current network
browseRequest, err := connection.BrowseRequestBuilder().
AddQuery("allDevices", "[1-15].[1-15].[0-255]").
//AddQuery("allMyDevices", "[1-3].[1-6].[0-60]").
//AddQuery("onlyOneDevice", "1.1.20")
Build()
if err != nil {
log.Error().Err(err).Msg("error creating browse request")
return
}
brr := browseRequest.ExecuteWithInterceptor(func(result apiModel.PlcBrowseItem) bool {
knxTag := result.GetTag()
knxAddress := knxTag.GetAddressString()
log.Info().Msgf("Inspecting detected Device at KNX Address: %s", knxAddress)
// Try to get all the com-objects and the group addresses they are attached to.
browseRequest, err := connection.BrowseRequestBuilder().
AddQuery("comObjects", knxAddress+"#com-obj").
Build()
if err != nil {
log.Error().Err(err).Msg("error creating read request")
return false
}
brr := browseRequest.Execute()
browseResult := <-brr
if browseResult.GetErr() != nil {
log.Error().Err(browseResult.GetErr()).Msg("error executing the browse request for com-objects")
return false
}
for _, result := range browseResult.GetResponse().GetQueryResults("comObjects") {
permissions := ""
if result.IsReadable() {
permissions += "R"
} else {
permissions += " "
}
if result.IsWritable() {
permissions += "W"
} else {
permissions += " "
}
if result.IsSubscribable() {
permissions += "S"
} else {
permissions += " "
}
log.Info().Msgf(" - %15s (%s) %s", result.GetTag().GetAddressString(), permissions, result.GetName())
}
readRequest, err := connection.ReadRequestBuilder().
AddTagAddress("applicationProgramVersion", knxAddress+"#3/13").
AddTagAddress("interfaceProgramVersion", knxAddress+"#4/13").
Build()
if err != nil {
log.Error().Msgf("Error creating read request for scanning %s", knxAddress)
return false
}
rrr := readRequest.Execute()
readRequestResult := <-rrr
if readRequestResult.GetErr() != nil {
log.Error().Msgf("Error executing read request for reading device identification information %s", knxAddress)
return false
}
readResponse := readRequestResult.GetResponse()
var programVersion []byte
if readResponse.GetResponseCode("applicationProgramVersion") == apiModel.PlcResponseCode_OK {
programVersion = utils.PlcValueUint8ListToByteArray(readResponse.GetValue("applicationProgramVersion"))
} else if readResponse.GetResponseCode("interfaceProgramVersion") == apiModel.PlcResponseCode_OK {
programVersion = utils.PlcValueUint8ListToByteArray(readResponse.GetValue("interfaceProgramVersion"))
}
rb := utils.NewReadBufferByteBased(programVersion)
manufacturerId := uint16(0)
applicationId := uint16(0)
applicationVersionMajor := uint8(0)
applicationVersionMinor := uint8(0)
if rb.GetTotalBytes() == 5 {
manufacturerId, err = rb.ReadUint16("manufacturerId", 16)
if err != nil {
log.Error().Err(err).Msgf("Error reading manufacturer id from")
return false
}
applicationId, err = rb.ReadUint16("applicationId", 16)
if err != nil {
log.Error().Err(err).Msgf("Error reading application id from")
return false
}
applicationVersionMajor, err = rb.ReadUint8("applicationVersionMajor", 4)
if err != nil {
log.Error().Err(err).Msgf("Error reading application version major from %s", knxAddress)
return false
}
applicationVersionMinor, err = rb.ReadUint8("applicationVersionMinor", 4)
if err != nil {
log.Error().Err(err).Msgf("Error reading application version minor from %s", knxAddress)
return false
}
}
log.Info().Msgf(" manufacturer id: %d", manufacturerId)
log.Info().Msgf(" program id: %d version %d.%d", applicationId, applicationVersionMajor, applicationVersionMinor)
return true
})
if brr == nil {
log.Error().Msg("error executing browse request")
return
}
select {
case browseRequestResult := <-brr:
log.Info().Msgf("Browse Request Result:\n%v", browseRequestResult)
}
return
}
}