Closed jbgod closed 2 years ago
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!
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!
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.
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.
there is something wrong with the code i should change my zigpy-znp version?
My mistake. The above code depends on the new radio API: https://github.com/zigpy/zigpy-cli/pull/2
` 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
the error show i should set the callback to status,so i change the callback of c.ZDO.JoinReq.Req
Z-Stack has two types of requests:
rsp = await znp.request(Some.Req(), OptionalRspValidator=123)
: https://github.com/zigpy/zigpy-znp/blob/19df5c01e9f4675ad1e206446575c4a02e28c073/zigpy_znp/zigbee/application.py#L229callback = await znp.request_callback_rsp(Some.Req(), RspOptionalValidator=123, callback=...)
: https://github.com/zigpy/zigpy-znp/blob/19df5c01e9f4675ad1e206446575c4a02e28c073/zigpy_znp/zigbee/application.py#L517If your command returns a response and then a callback, you would use request_callback_rsp
. Otherwise, use request
.
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 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
@jbgod how did you resolve this?
i can't solve this by zigpy. i back to try solve this by killerbee https://github.com/riverloopsec/killerbee/issues/256
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.