private async Task PerformUpdate(CancellationToken stoppingToken)
        {
            DateTime lastAutomaticMeasurement = DateTime.MinValue;
            DateTime lastMeasurement          = DateTime.MinValue;
            TimeSpan?measureInterval          = null;

            List <SwimmingPoolLastMeasurementsGetResponse> measurements = new List <SwimmingPoolLastMeasurementsGetResponse>();

            SwimmingPool pool = _pool;

            _updateManager.Process(pool, pool);

            _logger.LogDebug("Fetching blue devices for {Id} ({Name})", pool.SwimmingPoolId, pool.Name);
            SwimmingPoolBlueDevicesGetResponse blueDevices = await _blueClient.GetSwimmingPoolBlueDevices(pool.SwimmingPoolId, stoppingToken);

            bool anyBlueDeviceIsAwake = false;

            foreach (SwimmingPoolDevice blueDevice in blueDevices.Data)
            {
                _logger.LogDebug("Fetching measurements for {Id}, blue {Serial} ({Name})", pool.SwimmingPoolId, blueDevice.BlueDeviceSerial, pool.Name);
                _updateManager.Process(pool, blueDevice);

                SwimmingPoolLastMeasurementsGetResponse blueMeasurement = await _blueClient.GetBlueLastMeasurements(pool.SwimmingPoolId, blueDevice.BlueDeviceSerial, token : stoppingToken);

                if (blueDevice.BlueDevice.WakePeriod > 0)
                {
                    measureInterval = ComparisonHelper.GetMin(measureInterval, TimeSpan.FromSeconds(blueDevice.BlueDevice.WakePeriod));
                }

                measurements.Add(blueMeasurement);

                // Track the last measurement time in order to calculate the next expected measurement.
                // For now, this includes Gateway & sigfox measurements, as these are automated.
                // Manual bluetooth measurements do not affect the interval
                lastAutomaticMeasurement = ComparisonHelper.GetMax(lastAutomaticMeasurement,
                                                                   blueDevice.BlueDevice.LastMeasureMessageSigfox,
                                                                   blueDevice.BlueDevice.LastMeasureMessageGateway).GetValueOrDefault();

                lastMeasurement = ComparisonHelper.GetMax(lastMeasurement,
                                                          blueDevice.BlueDevice.LastMeasureMessage,
                                                          blueDevice.BlueDevice.LastMeasureMessageBle,
                                                          blueDevice.BlueDevice.LastMeasureMessageSigfox).GetValueOrDefault();

                // Track sleep states
                anyBlueDeviceIsAwake |= blueDevice.BlueDevice.SleepState == "awake";
            }

            _logger.LogDebug("Fetching guidance for {Id} ({Name})", pool.SwimmingPoolId, pool.Name);

            SwimmingPoolGuidanceGetResponse guidance = await _blueClient.GetSwimmingPoolGuidance(pool.SwimmingPoolId, _config.Language, token : stoppingToken);

            _updateManager.Process(pool, guidance);

            _logger.LogDebug("Fetching measurements for {Id} ({Name})", pool.SwimmingPoolId, pool.Name);

            SwimmingPoolLastMeasurementsGetResponse measurement = await _blueClient.GetSwimmingPoolLastMeasurements(pool.SwimmingPoolId, stoppingToken);

            measurements.Add(measurement);

            lastMeasurement = ComparisonHelper.GetMax(lastMeasurement,
                                                      measurement.LastStripTimestamp,
                                                      measurement.LastBlueMeasureTimestamp).GetValueOrDefault();

            _updateManager.Process(pool, measurements);

            _logger.LogDebug("Fetching weather for {Id} ({Name})", pool.SwimmingPoolId, pool.Name);

            SwimmingPoolWeatherGetResponse weather = await _blueClient.GetSwimmingPoolWeather(pool.SwimmingPoolId, _config.Language, stoppingToken);

            _updateManager.Process(pool, weather.Data);

            //_logger.LogDebug("Fetching status for {Id} ({Name})", pool.SwimmingPoolId, pool.Name);
            //SwimmingPoolStatusGetResponse status = await _blueClient.GetSwimmingPoolStatus(pool.SwimmingPoolId, stoppingToken);
            //_updateManager.Update(pool, status);

            _delayCalculator.TrackMeasureInterval(measureInterval);
            _delayCalculator.TrackLastAutoMeasurement(lastAutomaticMeasurement);
            _delayCalculator.TrackSleepState(anyBlueDeviceIsAwake);

            if (lastMeasurement > _lastMeasurement)
            {
                _lastMeasurement = lastMeasurement;

                if (_config.ReportUnchangedValues)
                {
                    // A new measurement was made, report potentially unchanged values
                    _hassMqttManager.MarkAllValuesDirty();
                }
            }
        }