From 3191c0dbfb9e39e816bd16b22ea5d77e0008d9c4 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 27 Jul 2024 12:47:42 +0200 Subject: [PATCH] Add UDP, support connection cloning (#343) --- go.mod | 28 +++++++------- go.sum | 52 +++++++++++++------------ meters/ascii.go | 15 ++++++-- meters/asciiovertcp.go | 15 ++++++-- meters/connection.go | 3 ++ meters/mock.go | 10 +++-- meters/rtu.go | 15 ++++++-- meters/rtuovertcp.go | 15 ++++++-- meters/rtuoverudp.go | 86 ++++++++++++++++++++++++++++++++++++++++++ meters/tcp.go | 15 ++++++-- 10 files changed, 198 insertions(+), 56 deletions(-) create mode 100644 meters/rtuoverudp.go diff --git a/go.mod b/go.mod index baabf0be..3db899eb 100644 --- a/go.mod +++ b/go.mod @@ -11,25 +11,25 @@ require ( github.com/gorilla/handlers v1.5.2 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.1 - github.com/grid-x/modbus v0.0.0-20230713135356-d9fefd3ae5a5 + github.com/grid-x/modbus v0.0.0-20240429072715-02314cc902aa github.com/influxdata/influxdb-client-go/v2 v2.13.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.18.1 - github.com/stretchr/testify v1.8.4 + github.com/spf13/viper v1.18.2 + github.com/stretchr/testify v1.9.0 github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e - golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f ) require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/google/go-github v17.0.0+incompatible // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -38,9 +38,9 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/oapi-codegen/runtime v1.0.0 // indirect + github.com/oapi-codegen/runtime v1.1.1 // indirect github.com/pascaldekloe/name v1.0.1 // indirect - github.com/pelletier/go-toml/v2 v2.1.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect @@ -50,13 +50,15 @@ require ( github.com/spf13/cast v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.16.1 // indirect + golang.org/x/tools v0.20.0 // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/grid-x/modbus => github.com/evcc-io/modbus v0.0.0-20240419133105-829633e7c6b0 diff --git a/go.sum b/go.sum index b07a6415..a4a9b3cb 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,9 @@ github.com/andig/gosunspec v0.0.0-20231205122018-1daccfa17912/go.mod h1:c6P6szcR github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= -github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -14,6 +15,8 @@ github.com/dmarkham/enumer v1.5.9 h1:NM/1ma/AUNieHZg74w67GkHFBNB15muOt3sj486QVZk github.com/dmarkham/enumer v1.5.9/go.mod h1:e4VILe2b1nYK3JKJpRmNdl5xbDQvELc6tQ8b+GsGk6E= github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik= github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE= +github.com/evcc-io/modbus v0.0.0-20240419133105-829633e7c6b0 h1:TRyQYvEfiVsQup88bfboOmFy8bPYltAFJfzeS6JcSP4= +github.com/evcc-io/modbus v0.0.0-20240419133105-829633e7c6b0/go.mod h1:ei49YhPP0v5cVJZAX9k/VdqQakUYNKOEvKB/6vnkZaU= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -29,17 +32,14 @@ github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4r github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/grid-x/modbus v0.0.0-20210714071042-7af2b65ec03b/go.mod h1:YaK0rKJenZ74vZFcSSLlAQqtG74PMI68eDjpDCDDmTw= -github.com/grid-x/modbus v0.0.0-20230713135356-d9fefd3ae5a5 h1:yrEpKpnrEPDjgmhAugQG2Og9FV6HMliPjV70NioqP3Y= -github.com/grid-x/modbus v0.0.0-20230713135356-d9fefd3ae5a5/go.mod h1:qVX2WhsI5xyAoM6I/MV1bXSKBPdLAjp7pCvieO/S0AY= github.com/grid-x/serial v0.0.0-20191104121038-e24bc9bf6f08/go.mod h1:kdOd86/VGFWRrtkNwf1MPk0u1gIjc4Y7R2j7nhwc7Rk= github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa h1:Rsn6ARgNkXrsXJIzhkE4vQr5Gbx2LvtEMv4BJOK4LyU= github.com/grid-x/serial v0.0.0-20211107191517-583c7356b3aa/go.mod h1:kdOd86/VGFWRrtkNwf1MPk0u1gIjc4Y7R2j7nhwc7Rk= @@ -66,12 +66,12 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo= -github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A= +github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= +github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/pascaldekloe/name v1.0.1 h1:9lnXOHeqeHHnWLbKfH6X98+4+ETVqFqxN09UXSjcMb0= github.com/pascaldekloe/name v1.0.1/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM= -github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= -github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg= +github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -93,37 +93,39 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM= -github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e h1:IWllFTiDjjLIf2oeKxpIUmtiDV5sn71VgeQgg6vcE7k= github.com/tcnksm/go-latest v0.0.0-20170313132115-e3007ae9052e/go.mod h1:d7u6HkTYKSv5m6MCKkOQlHwaShTMl3HjqSGW3XtVhXM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4= -golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= diff --git a/meters/ascii.go b/meters/ascii.go index a79e3589..91ab2a28 100644 --- a/meters/ascii.go +++ b/meters/ascii.go @@ -10,7 +10,6 @@ import ( // ASCII is an ASCII modbus connection type ASCII struct { - device string Client modbus.Client Handler *modbus.ASCIIClientHandler prevID uint8 @@ -45,7 +44,6 @@ func NewASCII(device string, baudrate int, comset string) Connection { client := modbus.NewClient(handler) b := &ASCII{ - device: device, Client: client, Handler: handler, } @@ -55,7 +53,7 @@ func NewASCII(device string, baudrate int, comset string) Connection { // String returns the bus device func (b *ASCII) String() string { - return b.device + return b.Handler.Address } // ModbusClient returns the RTU modbus client @@ -96,3 +94,14 @@ func (b *ASCII) ConnectDelay(delay time.Duration) { func (b *ASCII) Close() { b.Handler.Close() } + +// Clone clones the modbus connection. +func (b *ASCII) Clone(deviceID byte) Connection { + handler := b.Handler.Clone() + handler.SetSlave(deviceID) + + return &ASCII{ + Client: modbus.NewClient(handler), + Handler: handler, + } +} diff --git a/meters/asciiovertcp.go b/meters/asciiovertcp.go index 97437d35..643c64b3 100644 --- a/meters/asciiovertcp.go +++ b/meters/asciiovertcp.go @@ -8,7 +8,6 @@ import ( // ASCIIOverTCP is an ASCII encoder over a TCP modbus connection type ASCIIOverTCP struct { - address string Client modbus.Client Handler *modbus.ASCIIOverTCPClientHandler prevID uint8 @@ -31,7 +30,6 @@ func NewASCIIOverTCP(address string) Connection { client := modbus.NewClient(handler) b := &ASCIIOverTCP{ - address: address, Client: client, Handler: handler, } @@ -41,7 +39,7 @@ func NewASCIIOverTCP(address string) Connection { // String returns the bus connection address (TCP) func (b *ASCIIOverTCP) String() string { - return b.address + return b.Handler.Address } // ModbusClient returns the TCP modbus client @@ -82,3 +80,14 @@ func (b *ASCIIOverTCP) ConnectDelay(delay time.Duration) { func (b *ASCIIOverTCP) Close() { b.Handler.Close() } + +// Clone clones the modbus connection. +func (b *ASCIIOverTCP) Clone(deviceID byte) Connection { + handler := b.Handler.Clone() + handler.SetSlave(deviceID) + + return &ASCIIOverTCP{ + Client: modbus.NewClient(handler), + Handler: handler, + } +} diff --git a/meters/connection.go b/meters/connection.go index fd12de8d..5ebce2f3 100644 --- a/meters/connection.go +++ b/meters/connection.go @@ -24,6 +24,9 @@ type Connection interface { // This forces the modbus client to reopen the connection before the next bus operations. Close() + // Clone clones the modbus connection, keeping the underlying transport. + Clone(deviceID byte) Connection + // Logger sets a logging instance for physical bus operations Logger(l Logger) diff --git a/meters/mock.go b/meters/mock.go index 361f7170..0c2bb6f0 100644 --- a/meters/mock.go +++ b/meters/mock.go @@ -45,7 +45,7 @@ func (b *Mock) Logger(l Logger) { } // Slave sets the modbus device id for the following operations -func (b *Mock) Slave(deviceID uint8) { +func (b *Mock) Slave(_ uint8) { } // Timeout sets the modbus timeout @@ -54,14 +54,18 @@ func (b *Mock) Timeout(timeout time.Duration) time.Duration { } // ConnectDelay sets the the initial delay after connecting before starting communication -func (b *Mock) ConnectDelay(delay time.Duration) { - // nop +func (b *Mock) ConnectDelay(_ time.Duration) { } // Close closes the modbus connection. func (b *Mock) Close() { } +// Clone clones the modbus connection. +func (b *Mock) Clone(_ byte) Connection { + return b +} + // MockClient is a mock modbus client for testing that // is able to simulate devices and errors type MockClient struct { diff --git a/meters/rtu.go b/meters/rtu.go index 35a6ba93..210066df 100644 --- a/meters/rtu.go +++ b/meters/rtu.go @@ -10,7 +10,6 @@ import ( // RTU is an RTU modbus connection type RTU struct { - device string Client modbus.Client Handler *modbus.RTUClientHandler prevID uint8 @@ -45,7 +44,6 @@ func NewRTU(device string, baudrate int, comset string) Connection { client := modbus.NewClient(handler) b := &RTU{ - device: device, Client: client, Handler: handler, } @@ -55,7 +53,7 @@ func NewRTU(device string, baudrate int, comset string) Connection { // String returns the bus device func (b *RTU) String() string { - return b.device + return b.Handler.Address } // ModbusClient returns the RTU modbus client @@ -95,3 +93,14 @@ func (b *RTU) ConnectDelay(delay time.Duration) { func (b *RTU) Close() { b.Handler.Close() } + +// Clone clones the modbus connection. +func (b *RTU) Clone(deviceID byte) Connection { + handler := b.Handler.Clone() + handler.SetSlave(deviceID) + + return &RTU{ + Client: modbus.NewClient(handler), + Handler: handler, + } +} diff --git a/meters/rtuovertcp.go b/meters/rtuovertcp.go index 52dfc68e..cc824a21 100644 --- a/meters/rtuovertcp.go +++ b/meters/rtuovertcp.go @@ -8,7 +8,6 @@ import ( // RTUOverTCP is a RTU encoder over a TCP modbus connection type RTUOverTCP struct { - address string Client modbus.Client Handler *modbus.RTUOverTCPClientHandler prevID uint8 @@ -31,7 +30,6 @@ func NewRTUOverTCP(address string) Connection { client := modbus.NewClient(handler) b := &RTUOverTCP{ - address: address, Client: client, Handler: handler, } @@ -41,7 +39,7 @@ func NewRTUOverTCP(address string) Connection { // String returns the bus connection address (TCP) func (b *RTUOverTCP) String() string { - return b.address + return b.Handler.Address } // ModbusClient returns the TCP modbus client @@ -82,3 +80,14 @@ func (b *RTUOverTCP) ConnectDelay(delay time.Duration) { func (b *RTUOverTCP) Close() { b.Handler.Close() } + +// Clone clones the modbus connection. +func (b *RTUOverTCP) Clone(deviceID byte) Connection { + handler := b.Handler.Clone() + handler.SetSlave(deviceID) + + return &RTUOverTCP{ + Client: modbus.NewClient(handler), + Handler: handler, + } +} diff --git a/meters/rtuoverudp.go b/meters/rtuoverudp.go new file mode 100644 index 00000000..1826adda --- /dev/null +++ b/meters/rtuoverudp.go @@ -0,0 +1,86 @@ +package meters + +import ( + "time" + + "github.com/grid-x/modbus" +) + +// RTUOverUDP is a RTU encoder over a TCP modbus connection +type RTUOverUDP struct { + address string + Client modbus.Client + Handler *modbus.RTUOverUDPClientHandler + prevID uint8 +} + +// NewRTUOverUDPClientHandler creates a RTU over TCP modbus handler +func NewRTUOverUDPClientHandler(device string) *modbus.RTUOverUDPClientHandler { + return modbus.NewRTUOverUDPClientHandler(device) +} + +// NewRTUOverUDP creates a TCP modbus client +func NewRTUOverUDP(address string) Connection { + handler := NewRTUOverUDPClientHandler(address) + client := modbus.NewClient(handler) + + b := &RTUOverUDP{ + address: address, + Client: client, + Handler: handler, + } + + return b +} + +// String returns the bus connection address (TCP) +func (b *RTUOverUDP) String() string { + return b.address +} + +// ModbusClient returns the TCP modbus client +func (b *RTUOverUDP) ModbusClient() modbus.Client { + return b.Client +} + +// Logger sets a logging instance for physical bus operations +func (b *RTUOverUDP) Logger(l Logger) { + b.Handler.Logger = l +} + +// Slave sets the modbus device id for the following operations +func (b *RTUOverUDP) Slave(deviceID uint8) { + // Some devices like SDM need to have a little pause between querying different device ids + if b.prevID != 0 && deviceID != b.prevID { + time.Sleep(time.Duration(100) * time.Millisecond) + } + + b.prevID = deviceID + b.Handler.SetSlave(deviceID) +} + +// Timeout sets the modbus timeout +func (b *RTUOverUDP) Timeout(timeout time.Duration) time.Duration { + return 0 +} + +// ConnectDelay sets the the initial delay after connecting before starting communication +func (b *RTUOverUDP) ConnectDelay(delay time.Duration) { +} + +// Close closes the modbus connection. +// This forces the modbus client to reopen the connection before the next bus operations. +func (b *RTUOverUDP) Close() { + b.Handler.Close() +} + +// Clone clones the modbus connection. +func (b *RTUOverUDP) Clone(deviceID byte) Connection { + handler := b.Handler.Clone() + handler.SetSlave(deviceID) + + return &RTUOverUDP{ + Client: modbus.NewClient(handler), + Handler: handler, + } +} diff --git a/meters/tcp.go b/meters/tcp.go index 2c50b94d..bec8f891 100644 --- a/meters/tcp.go +++ b/meters/tcp.go @@ -8,7 +8,6 @@ import ( // TCP is a TCP modbus connection type TCP struct { - address string Client modbus.Client Handler *modbus.TCPClientHandler } @@ -30,7 +29,6 @@ func NewTCP(address string) Connection { client := modbus.NewClient(handler) b := &TCP{ - address: address, Client: client, Handler: handler, } @@ -40,7 +38,7 @@ func NewTCP(address string) Connection { // String returns the bus connection address (TCP) func (b *TCP) String() string { - return b.address + return b.Handler.Address } // ModbusClient returns the TCP modbus client @@ -75,3 +73,14 @@ func (b *TCP) ConnectDelay(delay time.Duration) { func (b *TCP) Close() { b.Handler.Close() } + +// Clone clones the modbus connection. +func (b *TCP) Clone(deviceID byte) Connection { + handler := b.Handler.Clone() + handler.SetSlave(deviceID) + + return &TCP{ + Client: modbus.NewClient(handler), + Handler: handler, + } +}