- 
                Notifications
    
You must be signed in to change notification settings  - Fork 19
 
Description
I'd like to start a discussion on how to back up the network key on XBee coordinators.
The issue is that on XBee devices the network key is write-only, so we have to remember it from the moment we set it. Luckily, we have a backup mechanism that we can use. Currently, however, we only use the last backup to restore the state if the device is not already configured, and optionally for verification.
Current flow:
- For a new network, we generate a new random key and write it to the device
 - The key is kept in memory until the next restart, and will be saved in the backup once it is created.
 - After the restart, we set the key to the default value (unknown), and because we can't get the key from the device, it remains unknown.
 
Suggestions:
- Enhance zigpy 
ControllerApplication.initialize()function to use last_backup to set the initial network_info (instead of default) before trying to load it from the device. Something like: 
     async def initialize(self, *, auto_form: bool = False) -> None:
         """Starts the network on a connected radio, optionally forming one with random
         settings if necessary.
         """
         last_backup = self.backups.most_recent_backup()
+        if last_backup:
+            self.state.network_info = zigpy.state.NetworkInfo.from_dict(last_backup.network_info.as_dict())
+
         try:
             await self.load_network_info(load_devices=False)
         except zigpy.exceptions.NetworkNotFormed:
So the radio library would only update what it can, and the rest will remain from the backup.
- Pass 
last_backupas a new optional parameter toControllerApplication.load_network_info and let the radio library (zigpy-xbee`) handle it as it wishes. 
         try:
-            await self.load_network_info(load_devices=False)
+            await self.load_network_info(load_devices=False, last_backup=last_backup)
         except zigpy.exceptions.NetworkNotFormed:
- To avoid changes to 
zigpy, overloadControllerApplication.initialize()function inzigpy_xbee.zigbee.ControllerApplication, load last backup inside it and restore the network key in memory there: 
    async def initialize(self, *, auto_form: bool = False) -> None:
        """Overloaded initialize() to restore unreadable info from backup."""
        last_backup = self.backups.most_recent_backup()
        if last_backup:
            self.state.network_info = zigpy.state.NetworkInfo.from_dict(last_backup.network_info.as_dict())
        await super().initialize(auto_form=auto_form)
- 
Do not try to read the key from backup, but perform implicit key rotation when making a new backup and the network key is not known. We can simply generate a new network key and write it to the device (and the backup), and it will be distributed to all devices in the network. Might be a bit tricky to implement it to do it only when the backup is created, and I also don't really like the idea of doing implicit actions like rotating the key when a user might not expect it.
 - 
There is also a native backup functionality in newer firmwares (the 'BK' AT command), it requires an additional investigation and is not available for legacy modules.