protected override void UpdateInternal(SwimmingPool pool, List <SwimmingPoolLastMeasurementsGetResponse> measurements, SwimmingPoolLastMeasurementsGetResponse latest)
        {
            if (!TryGetMeasurement(latest.Data, out SwpLastMeasurements measurement))
            {
                return;
            }

            ISensorContainer sensor = HassMqttManager
                                      .GetSensor(HassUniqueIdBuilder.GetPoolDeviceId(pool), $"{_measurement}_status")
                                      .SetPoolAttributes(pool);

            MeasurementUtility.AddAttributes(sensor.GetAttributesSender(), measurement);

            MeasurementStatus status = MeasurementUtility.GetStatus(measurement);

            sensor.SetValue(HassTopicKind.State, status.AsString(EnumFormat.EnumMemberValue));
        }
 protected override void CreateSensor(SwimmingPool pool, List <SwimmingPoolLastMeasurementsGetResponse> measurements, SwimmingPoolLastMeasurementsGetResponse latest)
 {
     HassMqttManager.ConfigureSensor <MqttSensor>(HassUniqueIdBuilder.GetPoolDeviceId(pool), $"{_measurement}_status")
     .ConfigureTopics(HassTopicKind.State, HassTopicKind.JsonAttributes)
     .SetHassPoolProperties(pool)
     .ConfigureDiscovery(discovery =>
     {
         discovery.Name = $"{pool.Name} {_displayName}";
     })
     .ConfigureAliveService();
 }
        protected override void UpdateInternal(SwimmingPool pool, List <SwimmingPoolLastMeasurementsGetResponse> measurements, SwimmingPoolLastMeasurementsGetResponse latest)
        {
            ISensorContainer sensor = HassMqttManager
                                      .GetSensor(HassUniqueIdBuilder.GetPoolDeviceId(pool), "last_measurement")
                                      .SetPoolAttributes(pool);

            if (latest == null)
            {
                // No measurements
                sensor.SetValue(HassTopicKind.State, null);
                sensor.SetAttribute(AttributeMeasurement, "none");

                return;
            }

            SwpLastMeasurements lastMeasurement = null;

            if (latest.LastBlueMeasureTimestamp.HasValue &&
                (!latest.LastStripTimestamp.HasValue || latest.LastBlueMeasureTimestamp > latest.LastStripTimestamp))
            {
                // Blue measurement is latest
                lastMeasurement = latest.Data.OrderByDescending(s => s.Timestamp).FirstOrDefault();

                sensor.SetValue(HassTopicKind.State, latest.LastBlueMeasureTimestamp);
                sensor.SetAttribute("method", "blue");
            }
            else if (latest.LastStripTimestamp.HasValue)
            {
                // Strip measurement is latest
                lastMeasurement = latest.Data.OrderByDescending(s => s.Timestamp).FirstOrDefault();

                sensor.SetValue(HassTopicKind.State, latest.LastStripTimestamp);
                sensor.SetAttribute("method", "strip");
            }
            else
            {
                // No measurements
                sensor.SetAttribute(AttributeMeasurement, "none");
                sensor.SetValue(HassTopicKind.State, null);
            }

            if (lastMeasurement != null)
            {
                sensor.SetAttribute(AttributeMeasurement, lastMeasurement.Name);
            }
        }
 protected override bool AppliesTo(SwimmingPool pool, List <SwimmingPoolLastMeasurementsGetResponse> measurements, SwimmingPoolLastMeasurementsGetResponse latest)
 {
     return(latest != null && TryGetMeasurement(latest.Data, out _));
 }
        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();
                }
            }
        }