diff --git a/README.md b/README.md index 31c94ad..37f5bc6 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,9 @@ ## Background -Z-Stack is a Zigbee Stack made available by Texas Instruments for use on their CC253X 2.4Ghz SOC processors. This +Z-Stack is a Zigbee Stack made available by Texas Instruments for use on their CC 2.4Ghz SOC processors. This library implements a Zigbee Network Processor that is capable of controlling a Z-Stack implementation, specifically it -supports the CC253X series of Zigbee sniffers flashed with the +supports the CC series of Zigbee sniffers flashed with the [zigbee2mqtt](https://www.zigbee2mqtt.io/getting_started/flashing_the_cc2531.html) Z-Stack coordinator firmware. More information about Z-Stack is available from [Texas Instruments](https://www.ti.com/tool/Z-STACK) directly or from @@ -29,6 +29,17 @@ More information about Z-Stack is available from [Texas Instruments](https://www and the author could not be contacted. This has been rectified, so it may be of interest you. This is a complete reimplementation of the library, however it is likely there will be strong coincidences due to Golang standards. +## Supported Devices + +The following chips and sticks are known to work, though it's likely others in the series will too: + +* CC253X + * Cheap Zigbee Sniffers from AliExpress - CC2531 +* CC26X2R1 + * [Electrolama zig-a-sig-ah!](https://electrolama.com/projects/zig-a-zig-ah/) - CC2652R + +Huge thanks to @Koenkk for his work in providing Z-Stack firmware for these chips. You can [grab the firmware from GitHub](https://github.com/Koenkk/Z-Stack-firmware/). + ## Install Add an import and most IDEs will `go get` automatically, if it doesn't `go build` will fetch. diff --git a/adapter_initialise.go b/adapter_initialise.go index 1561f1c..57da515 100644 --- a/adapter_initialise.go +++ b/adapter_initialise.go @@ -7,7 +7,6 @@ import ( "github.com/shimmeringbee/retry" "github.com/shimmeringbee/zigbee" "reflect" - "time" ) func (z *ZStack) Initialise(pctx context.Context, nc zigbee.NetworkConfiguration) error { @@ -34,7 +33,7 @@ func (z *ZStack) Initialise(pctx context.Context, nc zigbee.NetworkConfiguration return err } - z.logger.LogInfo(ctx, "Converting adapter to coordinator.") + z.logger.LogInfo(ctx, "Setting adapter to coordinator.") if err := z.makeCoordinator(ctx); err != nil { return err } @@ -50,11 +49,6 @@ func (z *ZStack) Initialise(pctx context.Context, nc zigbee.NetworkConfiguration return err } - //z.logger.LogInfo(ctx, "Waiting for coordinator to start.") - //if err := z.waitForCoordinatorStart(ctx); err != nil { - // return err - //} - z.logger.LogInfo(ctx, "Fetching adapter IEEE and Network addresses.") if err := z.retrieveAdapterAddresses(ctx); err != nil { return err @@ -65,9 +59,6 @@ func (z *ZStack) Initialise(pctx context.Context, nc zigbee.NetworkConfiguration return err } - channelBits := channelToBits(z.NetworkProperties.Channel) - z.writeNVRAM(ctx, ZCDNVChanList{Channels: channelBits}) - z.startNetworkManager() z.startMessageReceiver() @@ -161,6 +152,7 @@ func (z *ZStack) configureNetwork(ctx context.Context, version Version) error { } if !version.IsV3() { + /* Less than Z-Stack 3.X.X requires the Trust Centre key to be loaded. */ return retryFunctions(ctx, []func(context.Context) error{ func(invokeCtx context.Context) error { return z.writeNVRAM(invokeCtx, ZCDNVUseDefaultTCLK{Enabled: 1}) @@ -205,32 +197,26 @@ func (z *ZStack) configureNetwork(ctx context.Context, version Version) error { func (z *ZStack) retrieveAdapterAddresses(ctx context.Context) error { return retryFunctions(ctx, []func(context.Context) error{ func(invokeCtx context.Context) error { - address, err := z.GetAdapterIEEEAddress(ctx) - - if err != nil { + if address, err := z.GetAdapterIEEEAddress(ctx); err != nil { return err + } else { + z.NetworkProperties.IEEEAddress = address + return nil } - - z.NetworkProperties.IEEEAddress = address - - return nil }, func(ctx context.Context) error { - address, err := z.GetAdapterNetworkAddress(ctx) - - if err != nil { + if address, err := z.GetAdapterNetworkAddress(ctx); err != nil { return err + } else { + z.NetworkProperties.NetworkAddress = address + return nil } - - z.NetworkProperties.NetworkAddress = address - - return nil }, }) } func (z *ZStack) startZigbeeStack(ctx context.Context) error { - return retry.Retry(ctx, 30*time.Second, DefaultZStackRetries, func(invokeCtx context.Context) error { + return retry.Retry(ctx, DefaultZStackTimeout, DefaultZStackRetries, func(invokeCtx context.Context) error { return z.requestResponder.RequestResponse(invokeCtx, ZDOStartUpFromAppRequest{StartDelay: 100}, &ZDOStartUpFromAppRequestReply{}) }) } diff --git a/adapter_initialise_test.go b/adapter_initialise_test.go index e4096a0..7de756f 100644 --- a/adapter_initialise_test.go +++ b/adapter_initialise_test.go @@ -142,14 +142,14 @@ func Test_Initialise(t *testing.T) { Subsystem: SYS, CommandID: SysOSALNVWriteReplyID, Payload: nvramWriteResponse, - }).Times(9) - // - //unpiMock.On(SREQ, SAPI, SAPIZBStartRequestID).Return(Frame{ - // MessageType: SRSP, - // Subsystem: SAPI, - // CommandID: SAPIZBStartRequestReplyID, - // Payload: nil, - //}) + }).Times(8) + + unpiMock.On(SREQ, ZDO, ZDOStartUpFromAppRequestId).Return(Frame{ + MessageType: SRSP, + Subsystem: ZDO, + CommandID: ZDOStartUpFromAppRequestReplyID, + Payload: []byte{0x00}, + }) go func() { time.Sleep(10 * time.Millisecond) @@ -167,29 +167,20 @@ func Test_Initialise(t *testing.T) { Payload: []byte{0x09}, }) }() - // - //unpiMock.On(SREQ, SAPI, SAPIZBGetDeviceInfoID).Return( - // Frame{ - // MessageType: SRSP, - // Subsystem: SAPI, - // CommandID: SAPIZBGetDeviceInfoReplyID, - // Payload: []byte{0x01, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08}, - // }, - // Frame{ - // MessageType: SRSP, - // Subsystem: SAPI, - // CommandID: SAPIZBGetDeviceInfoReplyID, - // Payload: []byte{0x02, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - // }, - //).Times(2) - // - //unpiMock.On(SREQ, SAPI, SAPIZBPermitJoiningRequestID).Return( - // Frame{ - // MessageType: SRSP, - // Subsystem: SAPI, - // CommandID: SAPIZBPermitJoiningRequestReplyID, - // Payload: []byte{0x00}, - // }) + + unpiMock.On(SREQ, UTIL, UtilGetDeviceInfoRequestID).Return(Frame{ + MessageType: SRSP, + Subsystem: UTIL, + CommandID: UtilGetDeviceInfoRequestReplyID, + Payload: []byte{0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x09, 0x08}, + }).Times(2) + + unpiMock.On(SREQ, ZDO, ZDOMgmtPermitJoinRequestID).Return(Frame{ + MessageType: SRSP, + Subsystem: ZDO, + CommandID: ZDOMgmtPermitJoinRequestReplyID, + Payload: []byte{0x00}, + }) bdbSetChannel := unpiMock.On(SREQ, APP_CNF, APPCNFBDBSetChannelRequestID).Return( Frame{ @@ -237,13 +228,12 @@ func Test_Initialise(t *testing.T) { assert.Equal(t, []byte{0x01}, resetOn.CapturedCalls[1].Frame.Payload) assert.Equal(t, []byte{0x87, 0x00, 0x00, 0x01, 0x00}, nvramOn.CapturedCalls[1].Frame.Payload) assert.Equal(t, []byte{0x01}, resetOn.CapturedCalls[2].Frame.Payload) - assert.Equal(t, []byte{0x64, 0x00, 0x00, 0x01, 0x1}, nvramOn.CapturedCalls[2].Frame.Payload) - assert.Equal(t, []byte{0x63, 0x00, 0x00, 0x01, 0x1}, nvramOn.CapturedCalls[3].Frame.Payload) - assert.Equal(t, []byte{0x62, 0x00, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, nvramOn.CapturedCalls[4].Frame.Payload) - assert.Equal(t, []byte{0x8f, 0x00, 0x00, 0x01, 0x01}, nvramOn.CapturedCalls[5].Frame.Payload) - assert.Equal(t, []byte{0x84, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00}, nvramOn.CapturedCalls[6].Frame.Payload) - assert.Equal(t, []byte{0x83, 0x00, 0x00, 0x02, 0x02, 0x01}, nvramOn.CapturedCalls[7].Frame.Payload) - assert.Equal(t, []byte{0x2d, 0x00, 0x00, 0x08, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}, nvramOn.CapturedCalls[8].Frame.Payload) + assert.Equal(t, []byte{0x63, 0x00, 0x00, 0x01, 0x1}, nvramOn.CapturedCalls[2].Frame.Payload) + assert.Equal(t, []byte{0x62, 0x00, 0x00, 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, nvramOn.CapturedCalls[3].Frame.Payload) + assert.Equal(t, []byte{0x8f, 0x00, 0x00, 0x01, 0x01}, nvramOn.CapturedCalls[4].Frame.Payload) + assert.Equal(t, []byte{0x84, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00}, nvramOn.CapturedCalls[5].Frame.Payload) + assert.Equal(t, []byte{0x83, 0x00, 0x00, 0x02, 0x02, 0x01}, nvramOn.CapturedCalls[6].Frame.Payload) + assert.Equal(t, []byte{0x2d, 0x00, 0x00, 0x08, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}, nvramOn.CapturedCalls[7].Frame.Payload) assert.Equal(t, []byte{0x01, 0x00, 0x80, 0x00, 0x00}, bdbSetChannel.CapturedCalls[0].Frame.Payload) assert.Equal(t, []byte{0x00, 0x00, 0x00, 0x00, 0x00}, bdbSetChannel.CapturedCalls[1].Frame.Payload) assert.Equal(t, []byte{0x04}, bdbStartCommissioning.CapturedCalls[0].Frame.Payload)