Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to send association request with zigpy-znp #152

Closed
jbgod opened this issue May 16, 2022 · 12 comments
Closed

how to send association request with zigpy-znp #152

jbgod opened this issue May 16, 2022 · 12 comments

Comments

@jbgod
Copy link

jbgod commented May 16, 2022

i can't find the document abot zigpy-znp.i read the source code.
i find there is not RSP about the c.MAC only REQ find.
i also try the c.ZDO.JoinReq.Req and c.ZDO.NwkAddrReq.Req but it is no work.
i want to use my cc2652 work as an endpoit to join my normal zigbee gateway.

@puddly
Copy link
Collaborator

puddly commented May 16, 2022

Zigpy currently focuses on managing the device as a coordinator, not a router, so this isn't directly supported.

However, you can use the low-level operations in zigpy-znp to join an existing network:

import sys
import asyncio
import logging

import zigpy.types as t
import zigpy.exceptions
import zigpy.zdo.types as zdo_t
import zigpy_znp.commands as c
import zigpy_znp.types as znp_t

from zigpy_znp.tools.common import setup_parser
from zigpy_znp.zigbee.application import (
    ControllerApplication as ZNPControllerApplication,
)

LOGGER = logging.getLogger(__name__)


async def test_join_as_router(radio_path):
    app = ZNPControllerApplication({"device": {"path": radio_path}})
    await app.connect()

    try:
        # Always throws `NetworkNotFormed`, needs to be fixed for routers
        await app.load_network_info()
    except zigpy.exceptions.NetworkNotFormed:
        await app.form_network()

    if app.state.node_info.logical_type != zdo_t.LogicalType.Router:
        await app.write_network_info(
            node_info=app.state.node_info.replace(
                logical_type=zdo_t.LogicalType.Router, nwk=0x1234
            ),
            network_info=app.state.network_info,
        )

    joined_as_router = app._znp.wait_for_response(
        c.ZDO.StateChangeInd.Callback(State=znp_t.DeviceState.JoinedAsRouter)
    )

    # Run `zigpy_znp/tools/network_scan.py` to scan for networks
    await app._znp.request(
        c.ZDO.JoinReq.Req(
            LogicalChannel=25,
            PanId=0xABCD,
            ExtendedPanId=t.EUI64.convert("AA:BB:CC:DD:AA:BB:CC:DD"),
            ChosenParent=0x380A,
            Depth=1,
            StackProfile=2,
        ),
        callback=c.ZDO.JoinCnf.Callback(partial=True),
    )

    # TODO: how do you re-join a network? The network key is not stored in NVRAM...
    await joined_as_router
    await asyncio.sleep(60)
    await app.shutdown()


async def main(argv):
    parser = setup_parser("Test joining a network as a router")

    args = parser.parse_args(argv)

    await test_join_as_router(args.serial)


if __name__ == "__main__":
    asyncio.run(main(sys.argv[1:]))  # pragma: no cover

After the device joined my network, however, it did not respond to the coordinator's node descriptor request and I can't figure out how to re-join a network. Z-Stack's serial MT interface isn't documented very well so you will have to figure out how to get router mode properly working (if it's even possible using the coordinator firmware). If you do, please post an update!

@jbgod
Copy link
Author

jbgod commented May 16, 2022

oh thank you!!!
what is the capture struct for the transport key packet,
i also want to capture the packet.
i read many classes in the zdo,but i can't sure what is that

Zigpy currently focuses on managing the device as a coordinator, not a router, so this isn't directly supported.

However, you can use the low-level operations in zigpy-znp to join an existing network:

import sys
import asyncio
import logging

import zigpy.types as t
import zigpy.exceptions
import zigpy.zdo.types as zdo_t
import zigpy_znp.commands as c
import zigpy_znp.types as znp_t

from zigpy_znp.tools.common import setup_parser
from zigpy_znp.zigbee.application import (
    ControllerApplication as ZNPControllerApplication,
)

LOGGER = logging.getLogger(__name__)


async def test_join_as_router(radio_path):
    app = ZNPControllerApplication({"device": {"path": radio_path}})
    await app.connect()

    try:
        # Always throws `NetworkNotFormed`, needs to be fixed for routers
        await app.load_network_info()
    except zigpy.exceptions.NetworkNotFormed:
        await app.form_network()

    if app.state.node_info.logical_type != zdo_t.LogicalType.Router:
        await app.write_network_info(
            node_info=app.state.node_info.replace(
                logical_type=zdo_t.LogicalType.Router, nwk=0x1234
            ),
            network_info=app.state.network_info,
        )

    joined_as_router = app._znp.wait_for_response(
        c.ZDO.StateChangeInd.Callback(State=znp_t.DeviceState.JoinedAsRouter)
    )

    # Run `zigpy_znp/tools/network_scan.py` to scan for networks
    await app._znp.request(
        c.ZDO.JoinReq.Req(
            LogicalChannel=25,
            PanId=0xABCD,
            ExtendedPanId=t.EUI64.convert("AA:BB:CC:DD:AA:BB:CC:DD"),
            ChosenParent=0x380A,
            Depth=1,
            StackProfile=2,
        ),
        callback=c.ZDO.JoinCnf.Callback(partial=True),
    )

    # TODO: how do you re-join a network? The network key is not stored in NVRAM...
    await joined_as_router
    await asyncio.sleep(60)
    await app.shutdown()


async def main(argv):
    parser = setup_parser("Test joining a network as a router")

    args = parser.parse_args(argv)

    await test_join_as_router(args.serial)


if __name__ == "__main__":
    asyncio.run(main(sys.argv[1:]))  # pragma: no cover

After the device joined my network, however, it did not respond to the coordinator's node descriptor request and I can't figure out how to re-join a network. Z-Stack's serial MT interface isn't documented very well so you will have to figure out how to get router mode properly working (if it's even possible using the coordinator firmware). If you do, please post an update!

@puddly
Copy link
Collaborator

puddly commented May 16, 2022

I didn't see one, nor could I find the key in NVRAM. I think there is something that must be done after the join request succeeds.

You should be able to sniff it being sent over-the-air though.

@jbgod
Copy link
Author

jbgod commented May 16, 2022

i had try to use killerbee to forge an end device,which send and recv capture at sametime.
but the association response is reply in 0.0004 second,but the chip deal with the capture too slow. i cant cap it.
i use an cc2531 dongle on my windows capture the packet when i control a dongle communicate with a zigbee router
tomorrow i will try this code when i back to my Lab.
could u leave a email for me to communicate with u,i cost two week about this problem.

@jbgod
Copy link
Author

jbgod commented May 17, 2022

there is something wrong with the code
i should change my zigpy-znp version?
image

@puddly
Copy link
Collaborator

puddly commented May 17, 2022

My mistake. The above code depends on the new radio API: zigpy/zigpy-cli#2

@jbgod
Copy link
Author

jbgod commented May 17, 2022

`
async def connect_network(
path: str, beacon: t.structs.Beacon
)-> None:

app = ZNPControllerApplication({"device": {"path": path}})
await app.connect()

try:
    # Always throws `NetworkNotFormed`, needs to be fixed for routers
    await app.load_network_info()
except zigpy.exceptions.NetworkNotFormed:
    await app.form_network()

if app.state.node_info.logical_type != zdo_t.LogicalType.Router:
    await app.write_network_info(
        node_info=app.state.node_info.replace(
            logical_type=zdo_t.LogicalType.Router, nwk=0x1234
        ),
        network_info=app.state.network_info,
    )

joined_as_router = app._znp.wait_for_response(
    c.ZDO.StateChangeInd.Callback(State=znp_t.DeviceState.JoinedAsRouter)
)

await app._znp.request(
    c.SYS.StackTune.Req(
        Operation = StackTuneOperation.SetRxOnWhenIdle,
        Value = 0x01,
    ),
    RspValue=0x01,
)    

# Run `zigpy_znp/tools/network_scan.py` to scan for networks
await app._znp.request(
    c.ZDO.JoinReq.Req(
        LogicalChannel = beacon.Channel,
        PanId = beacon.PanId,
        ExtendedPanId = beacon.ExtendedPanId,
        ChosenParent = beacon.Src,
        Depth = beacon.Depth,
        StackProfile = beacon.StackProfile
    ),
    RspStatus=t.Status.SUCCESS,
)

# TODO: how do you re-join a network? The network key is not stored in NVRAM...
await joined_as_router
await asyncio.sleep(60)
await app.shutdown()

`
i had install your new branch,and i add this function to the zigpy_znp/tools/network_scan.py
i can't change the 'Rx on when Idle'
there is something wrong when i try to change the 'Rx on when Idle',it is alway be 0x00
image

@jbgod
Copy link
Author

jbgod commented May 17, 2022

the error show i should set the callback to status,so i change the callback of c.ZDO.JoinReq.Req
image

@puddly
Copy link
Collaborator

puddly commented May 17, 2022

Z-Stack has two types of requests:

  1. Request/response: you can use rsp = await znp.request(Some.Req(), OptionalRspValidator=123):
    await self._znp.request(
  2. Request/acknowledgement/callback: you can use callback = await znp.request_callback_rsp(Some.Req(), RspOptionalValidator=123, callback=...):
    response = await self._znp.request_callback_rsp(

If your command returns a response and then a callback, you would use request_callback_rsp. Otherwise, use request.

@jbgod
Copy link
Author

jbgod commented May 17, 2022

how can i define the "Rx on When Idle" in the packet which i send to the coordinator
the normal zigbee device send the packet with Rx on When Idle = 0x01
image
i use c.ZDO.JoinReq.Req send the association request with this on,and without the transport key packet back
the transport key packet contain the network key of coordinator
image

@jbgod jbgod closed this as completed May 23, 2022
@puddly
Copy link
Collaborator

puddly commented May 25, 2022

@jbgod how did you resolve this?

@jbgod
Copy link
Author

jbgod commented May 26, 2022

i can't solve this by zigpy.
i back to try solve this by killerbee
riverloopsec/killerbee#256

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants