From 1077a1024cd14a18508ed023d7aa422002c46147 Mon Sep 17 00:00:00 2001 From: Peter Wood Date: Sun, 9 Feb 2020 14:22:50 +0000 Subject: [PATCH] Complete support for querying an endpoints description, closes #6. --- go.mod | 2 +- go.sum | 2 + node_endpoint_description.go | 69 +++++++++++++++++ node_endpoint_description_test.go | 119 ++++++++++++++++++++++++++++++ node_simple_description.go | 30 -------- node_simple_description_test.go | 54 -------------- 6 files changed, 191 insertions(+), 85 deletions(-) create mode 100644 node_endpoint_description.go create mode 100644 node_endpoint_description_test.go delete mode 100644 node_simple_description.go delete mode 100644 node_simple_description_test.go diff --git a/go.mod b/go.mod index 5bc72f8..ab7f583 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,6 @@ go 1.13 require ( github.com/shimmeringbee/bytecodec v0.0.0-20191116111328-f873abddc0ca github.com/shimmeringbee/unpi v0.0.0-20200208214536-ae03ffed80df - github.com/shimmeringbee/zigbee v0.0.0-20200120203528-41c732360d3b + github.com/shimmeringbee/zigbee v0.0.0-20200209141444-4751de36c63a github.com/stretchr/testify v1.4.0 ) diff --git a/go.sum b/go.sum index f08ad92..4d46a1f 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ github.com/shimmeringbee/zigbee v0.0.0-20191117130828-cab4fe16ac87 h1:Yi9tjP5tI8 github.com/shimmeringbee/zigbee v0.0.0-20191117130828-cab4fe16ac87/go.mod h1:WVZ5totAgMhUc1ubHym27LsKRnXv1MAiGyaDEs4dzak= github.com/shimmeringbee/zigbee v0.0.0-20200120203528-41c732360d3b h1:t2oXaGn3t/PFHs4PhlDEkDdTXunyNC3b46ecqEmKxyE= github.com/shimmeringbee/zigbee v0.0.0-20200120203528-41c732360d3b/go.mod h1:WVZ5totAgMhUc1ubHym27LsKRnXv1MAiGyaDEs4dzak= +github.com/shimmeringbee/zigbee v0.0.0-20200209141444-4751de36c63a h1:2arwf+RSJlxeyNuDwbfdvjC2Bhe9K0ZVvtvliT/m238= +github.com/shimmeringbee/zigbee v0.0.0-20200209141444-4751de36c63a/go.mod h1:WVZ5totAgMhUc1ubHym27LsKRnXv1MAiGyaDEs4dzak= github.com/shimmeringbee/zstack v0.0.0-20191118220231-acddb74ca28e/go.mod h1:U7Upz3GOefZyV1IA28N3v/iY4MLBqkujTspCZr5mv6k= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/node_endpoint_description.go b/node_endpoint_description.go new file mode 100644 index 0000000..7307f45 --- /dev/null +++ b/node_endpoint_description.go @@ -0,0 +1,69 @@ +package zstack + +import ( + "context" + "github.com/shimmeringbee/zigbee" +) + +func (z *ZStack) QueryNodeEndpointDescription(ctx context.Context, networkAddress zigbee.NetworkAddress, endpoint byte) (zigbee.EndpointDescription, error) { + request := ZdoSimpleDescReq{ + DestinationAddress: networkAddress, + OfInterestAddress: networkAddress, + Endpoint: endpoint, + } + + resp, err := z.nodeRequest(ctx, &request, &ZdoSimpleDescReqReply{}, &ZdoSimpleDescRsp{}, func(i interface{}) bool { + msg := i.(*ZdoSimpleDescRsp) + return msg.OfInterestAddress == networkAddress && msg.Endpoint == endpoint + }) + + castResp, ok := resp.(*ZdoSimpleDescRsp) + + if ok { + return zigbee.EndpointDescription{ + Endpoint: castResp.Endpoint, + ProfileID: castResp.ProfileID, + DeviceID: castResp.DeviceID, + DeviceVersion: castResp.DeviceVersion, + InClusterList: castResp.InClusterList, + OutClusterList: castResp.OutClusterList, + }, nil + } else { + return zigbee.EndpointDescription{}, err + } +} + +type ZdoSimpleDescReq struct { + DestinationAddress zigbee.NetworkAddress + OfInterestAddress zigbee.NetworkAddress + Endpoint byte +} + +const ZdoSimpleDescReqID uint8 = 0x04 + +type ZdoSimpleDescReqReply GenericZStackStatus + +func (r ZdoSimpleDescReqReply) WasSuccessful() bool { + return r.Status == ZSuccess +} + +const ZdoSimpleDescReqReplyID uint8 = 0x04 + +type ZdoSimpleDescRsp struct { + SourceAddress zigbee.NetworkAddress + Status ZStackStatus + OfInterestAddress zigbee.NetworkAddress + Length uint8 + Endpoint byte + ProfileID uint16 + DeviceID uint16 + DeviceVersion uint8 + InClusterList []zigbee.ZCLClusterID `bclength:"8"` + OutClusterList []zigbee.ZCLClusterID `bclength:"8"` +} + +func (r ZdoSimpleDescRsp) WasSuccessful() bool { + return r.Status == ZSuccess +} + +const ZdoSimpleDescRspID uint8 = 0x84 diff --git a/node_endpoint_description_test.go b/node_endpoint_description_test.go new file mode 100644 index 0000000..5db8e9f --- /dev/null +++ b/node_endpoint_description_test.go @@ -0,0 +1,119 @@ +package zstack + +import ( + "context" + "github.com/shimmeringbee/bytecodec" + . "github.com/shimmeringbee/unpi" + unpiTest "github.com/shimmeringbee/unpi/testing" + "github.com/shimmeringbee/zigbee" + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func Test_QueryNodeEndpointDescription(t *testing.T) { + t.Run("returns an success on query, response for requested network address is received", func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + + unpiMock := unpiTest.NewMockAdapter() + zstack := New(unpiMock) + defer unpiMock.Stop() + + unpiMock.On(SREQ, ZDO, ZdoSimpleDescReqID).Return(Frame{ + MessageType: SRSP, + Subsystem: ZDO, + CommandID: ZdoSimpleDescReqReplyID, + Payload: []byte{0x00}, + }) + + go func() { + time.Sleep(10 * time.Millisecond) + unpiMock.InjectOutgoing(Frame{ + MessageType: AREQ, + Subsystem: ZDO, + CommandID: ZdoSimpleDescRspID, + Payload: []byte{0x00, 0x20, 0x00, 0x00, 0x40, 0xff, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x01, 0x01, 0x00, 0x01, 0x02, 0x00}, + }) + }() + + endpoints, err := zstack.QueryNodeEndpointDescription(ctx, zigbee.NetworkAddress(0x4000), 0x01) + assert.NoError(t, err) + assert.Equal(t, zigbee.EndpointDescription{ + Endpoint: 0x01, + ProfileID: 0x0101, + DeviceID: 1, + DeviceVersion: 2, + InClusterList: []zigbee.ZCLClusterID{0x0001}, + OutClusterList: []zigbee.ZCLClusterID{0x0002}, + }, endpoints) + + unpiMock.AssertCalls(t) + }) +} + +func Test_SimpleDescriptionMessages(t *testing.T) { + t.Run("verify ZdoSimpleDescReq marshals", func(t *testing.T) { + req := ZdoSimpleDescReq{ + DestinationAddress: zigbee.NetworkAddress(0x2000), + OfInterestAddress: zigbee.NetworkAddress(0x4000), + Endpoint: 0x08, + } + + data, err := bytecodec.Marshall(req) + + assert.NoError(t, err) + assert.Equal(t, []byte{0x00, 0x20, 0x00, 0x40, 0x08}, data) + }) + + t.Run("verify ZdoSimpleDescReqReply marshals", func(t *testing.T) { + req := ZdoSimpleDescReqReply{ + Status: 1, + } + + data, err := bytecodec.Marshall(req) + + assert.NoError(t, err) + assert.Equal(t, []byte{0x01}, data) + }) + + t.Run("generic ZdoSimpleDescReqReply returns true if success", func(t *testing.T) { + g := ZdoSimpleDescReqReply{Status:ZSuccess} + assert.True(t, g.WasSuccessful()) + }) + + t.Run("generic ZdoSimpleDescReqReply returns false if not success", func(t *testing.T) { + g := ZdoSimpleDescReqReply{Status:ZFailure} + assert.False(t, g.WasSuccessful()) + }) + + t.Run("verify ZdoSimpleDescRsp marshals", func(t *testing.T) { + req := ZdoSimpleDescRsp{ + SourceAddress: zigbee.NetworkAddress(0x2000), + Status: 1, + OfInterestAddress: zigbee.NetworkAddress(0x4000), + Length: 0x0a, + Endpoint: 0x08, + ProfileID: 0x1234, + DeviceID: 0x5678, + DeviceVersion: 0, + InClusterList: []zigbee.ZCLClusterID{0x1234}, + OutClusterList: []zigbee.ZCLClusterID{0x5678}, + } + + data, err := bytecodec.Marshall(req) + + assert.NoError(t, err) + assert.Equal(t, []byte{0x00, 0x20, 0x01, 0x00, 0x40, 0x0a, 0x08, 0x34, 0x12, 0x78, 0x56, 0x00, 0x01, 0x34, 0x12, 0x01, 0x78, 0x56}, data) + }) + + t.Run("generic ZdoSimpleDescRsp returns true if success", func(t *testing.T) { + g := ZdoSimpleDescRsp{Status:ZSuccess} + assert.True(t, g.WasSuccessful()) + }) + + t.Run("generic ZdoSimpleDescRsp returns false if not success", func(t *testing.T) { + g := ZdoSimpleDescRsp{Status:ZFailure} + assert.False(t, g.WasSuccessful()) + }) +} diff --git a/node_simple_description.go b/node_simple_description.go deleted file mode 100644 index e8681c7..0000000 --- a/node_simple_description.go +++ /dev/null @@ -1,30 +0,0 @@ -package zstack - -import "github.com/shimmeringbee/zigbee" - -type ZdoSimpleDescReq struct { - DestinationAddress zigbee.NetworkAddress - OfInterestAddress zigbee.NetworkAddress - Endpoint byte -} - -const ZdoSimpleDescReqID uint8 = 0x04 - -type ZdoSimpleDescReqReply GenericZStackStatus - -const ZdoSimpleDescReqReplyID uint8 = 0x04 - -type ZdoSimpleDescRsp struct { - SourceAddress zigbee.NetworkAddress - Status ZStackStatus - OfInterestAddress zigbee.NetworkAddress - Length uint8 - Endpoint byte - ProfileID uint16 - DeviceID uint16 - DeviceVersion uint8 - InClusterList []zigbee.ZCLClusterID `bclength:"8"` - OutClusterList []zigbee.ZCLClusterID `bclength:"8"` -} - -const ZdoSimpleDescRspID uint8 = 0x84 diff --git a/node_simple_description_test.go b/node_simple_description_test.go deleted file mode 100644 index ad1a93e..0000000 --- a/node_simple_description_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package zstack - -import ( - "github.com/shimmeringbee/bytecodec" - "github.com/shimmeringbee/zigbee" - "github.com/stretchr/testify/assert" - "testing" -) - -func Test_SimpleDescriptionMessages(t *testing.T) { - t.Run("verify ZdoSimpleDescReq marshals", func(t *testing.T) { - req := ZdoSimpleDescReq{ - DestinationAddress: zigbee.NetworkAddress(0x2000), - OfInterestAddress: zigbee.NetworkAddress(0x4000), - Endpoint: 0x08, - } - - data, err := bytecodec.Marshall(req) - - assert.NoError(t, err) - assert.Equal(t, []byte{0x00, 0x20, 0x00, 0x40, 0x08}, data) - }) - - t.Run("verify ZdoSimpleDescReqReply marshals", func(t *testing.T) { - req := ZdoSimpleDescReqReply{ - Status: 1, - } - - data, err := bytecodec.Marshall(req) - - assert.NoError(t, err) - assert.Equal(t, []byte{0x01}, data) - }) - - t.Run("verify ZdoSimpleDescRsp marshals", func(t *testing.T) { - req := ZdoSimpleDescRsp{ - SourceAddress: zigbee.NetworkAddress(0x2000), - Status: 1, - OfInterestAddress: zigbee.NetworkAddress(0x4000), - Length: 0x0a, - Endpoint: 0x08, - ProfileID: 0x1234, - DeviceID: 0x5678, - DeviceVersion: 0, - InClusterList: []zigbee.ZCLClusterID{0x1234}, - OutClusterList: []zigbee.ZCLClusterID{0x5678}, - } - - data, err := bytecodec.Marshall(req) - - assert.NoError(t, err) - assert.Equal(t, []byte{0x00, 0x20, 0x01, 0x00, 0x40, 0x0a, 0x08, 0x34, 0x12, 0x78, 0x56, 0x00, 0x01, 0x34, 0x12, 0x01, 0x78, 0x56}, data) - }) -}