In a lot of my apartment installs, I use Zigbee sensors to track things such as occupancy.

Unfortunately, in some apartments, many devices drop off the network frequently, and I can't see any pattern to this behaviour.

In this thread, it was suggested that decreasing the max report time down to 1 hour can improve the reliability, but it seems that I can't make those changes without re-pairing the device, which requires physical access. Once paired, you then have a bit of a race to get the setting made before the device locks you out.

I used ChatGPT to write the following extension to Zigbee2MQTT, which sets the maximum report interval to 1 hour for all devices as they join. It can be added in the Extensions tab of the Zigbee2MQTT Web UI.

class BatteryPercentageReportingExtension {
   constructor(zigbee, mqtt, state, publishEntityState, eventBus, settings, logger) {
       this.zigbee = zigbee;
       this.logger = logger;
       this.eventBus = eventBus;
       this.eventBus.on('deviceInterview', this.onDeviceInterview.bind(this), this.constructor.name);
   }

   async onDeviceInterview(data) {
       const { device, status } = data;
       if (status === 'successful') {
           const endpoint = device.getEndpoint(1);
           if (endpoint && endpoint.supportsInputCluster('genPowerCfg')) {
               try {
                   const cluster = 'genPowerCfg';
                   const attribute = 'batteryPercentageRemaining';
                   const minReportInterval = 0;
                   const maxReportInterval = 3600;
                   const reportableChange = 0;

                   await endpoint.bind(cluster);
                   await endpoint.configureReporting(cluster, [{
                       attribute: { ID: 0x0021, type: 32 }, // batteryPercentageRemaining
                       minimumReportInterval: minReportInterval,
                       maximumReportInterval: maxReportInterval,
                       reportableChange: reportableChange
                   }]);
                   this.logger.info(`Configured reporting for ${device.ieeeAddr} ${cluster} ${attribute}`);
               } catch (e) {
                   this.logger.error(`Failed to configure reporting for ${device.ieeeAddr} genPowerCfg batteryPercentageRemaining`, e);
               }
           }
       }
   }

   async stop() {
       this.eventBus.removeListeners(this.constructor.name);
   }
}

module.exports = BatteryPercentageReportingExtension;