protected override void UpdateInternal(SwimmingPool pool, SwimmingPool _)
        {
            ISensorContainer sensor = HassMqttManager.GetSensor(HassUniqueIdBuilder.GetPoolDeviceId(pool), "pump_schedule");

            SwimmingPoolCharacteristicsFilterPump pump = pool.Characteristics?.FilterPump;

            if (pump == null)
            {
                return;
            }

            MqttAttributesTopic attributes = sensor.GetAttributesSender();

            // The new schedule may have fewer time ranges
            attributes.Clear();

            sensor.SetPoolAttributes(pool);

            if (!pump.IsPresent)
            {
                // No pump
                sensor.SetValue(HassTopicKind.State, "None");
            }
            else if (pump.OperatingType == "Manual")
            {
                // Pump exists, but is not scheduled
                sensor.SetValue(HassTopicKind.State, "Manual");
            }
            else if (pump.OperatingType == "Scheduled")
            {
                sensor.SetValue(HassTopicKind.State, "Scheduled");

                if (pump.OperatingHours != null && pump.OperatingHours.Any())
                {
                    string allTimes = string.Join(", ", pump.OperatingHours.Select(s => s.Start.ToString(TimeFormat) + "-" + s.End.ToString(TimeFormat)));
                    attributes.SetAttribute("schedule", allTimes);

                    attributes.SetAttribute("schedules", pump.OperatingHours.Count);

                    for (int index = 0; index < pump.OperatingHours.Count; index++)
                    {
                        TimeRange range = pump.OperatingHours[index];

                        attributes.SetAttribute($"schedule_{index}", $"{range.Start.ToString(TimeFormat)}-{range.End.ToString(TimeFormat)}");
                        attributes.SetAttribute($"schedule_{index}_start", range.Start.ToString(TimeFormat));
                        attributes.SetAttribute($"schedule_{index}_end", range.End.ToString(TimeFormat));
                    }
                }
            }
        }
Exemplo n.º 2
0
            protected override void Update(ISensorContainer sensor, SwimmingPool pool, SwimmingPoolWeather obj)
            {
                sensor.SetAttribute("temp_min", obj.TemperatureMin);
                sensor.SetAttribute("temp_max", obj.TemperatureMax);

                sensor.SetValue(HassTopicKind.State, obj.TemperatureCurrent);
            }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            ISensorContainer operationalSensor = CreateSystemEntities();

            try
            {
                // Update loop
                while (!stoppingToken.IsCancellationRequested)
                {
                    _logger.LogDebug("Beginning update");

                    try
                    {
                        await PerformUpdate(stoppingToken);

                        // Track API operational status
                        operationalSensor.SetValue(HassTopicKind.State, OkMessage);
                        operationalSensor.SetAttribute("last_ok", DateTime.UtcNow.ToString("O"));
                    }
                    catch (OperationCanceledException) when(stoppingToken.IsCancellationRequested)
                    {
                        // Do nothing
                    }
                    catch (Exception e)
                    {
                        _logger.LogError(e, "An error occurred while performing the update");

                        // Track API operational status
                        operationalSensor.SetValue(HassTopicKind.State, ProblemMessage);
                        operationalSensor.SetAttribute("last_bad", DateTime.UtcNow.ToString("O"));
                        operationalSensor.SetAttribute("last_bad_status", e.Message);
                    }

                    await Task.Delay(_config.DiscoveryInterval, stoppingToken);
                }
            }
            finally
            {
                // Stop all updaters
                _logger.LogInformation("Stopping all pool updaters");

                foreach (SingleBlueRiiotPoolUpdater updater in _updaters.Values)
                {
                    updater.Stop();
                }
            }
        }
        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);
            }
        }
Exemplo n.º 5
0
            protected override void Update(ISensorContainer sensor, SwimmingPool pool, SwimmingPoolWeather obj)
            {
                sensor.SetAttribute("temp_min", obj.TemperatureMin);
                sensor.SetAttribute("temp_max", obj.TemperatureMax);
                sensor.SetAttribute("temp", obj.TemperatureCurrent);
                sensor.SetAttribute("wind_speed", obj.WindSpeedCurrent);
                sensor.SetAttribute("uv", obj.UvCurrent);

                sensor.SetValue(HassTopicKind.State, obj.WeatherCurrentDescription);
            }
Exemplo n.º 6
0
        protected override void UpdateInternal(SwimmingPool pool, SwimmingPoolDevice data)
        {
            string           deviceId     = HassUniqueIdBuilder.GetBlueDeviceId(data);
            ISensorContainer deviceSensor = HassMqttManager
                                            .GetSensor(deviceId, "device")
                                            .SetPoolAttributes(pool);
            ISensorContainer batterySensor = HassMqttManager
                                             .GetSensor(deviceId, "battery")
                                             .SetPoolAttributes(pool);
            ISensorContainer statusSensor = HassMqttManager
                                            .GetSensor(deviceId, "status")
                                            .SetPoolAttributes(pool);

            // Device
            // Determine last contact
            DateTime?latestContact = ComparisonHelper.GetMax(data.Created,
                                                             data.BlueDevice.LastHelloMessageV,
                                                             data.BlueDevice.LastMeasureMessage,
                                                             data.BlueDevice.LastMeasureMessageBle,
                                                             data.BlueDevice.LastMeasureMessageSigfox);

            deviceSensor.SetValue(HassTopicKind.State, latestContact);

            // Device attributes
            deviceSensor.SetAttribute("serial", data.BlueDevice.Serial);
            deviceSensor.SetAttribute("serial_number", data.BlueDevice.Sn);
            deviceSensor.SetAttribute("wake_interval", data.BlueDevice.WakePeriod);
            deviceSensor.SetAttribute("firmware", data.BlueDevice.FwVersionPsoc);
            deviceSensor.SetAttribute("firmware_installed", data.BlueDevice.FwVersionHistory?.OrderByDescending(s => s.Timestamp).Select(s => s.Timestamp).FirstOrDefault());

            // Battery
            if (data.BlueDevice.BatteryLow)
            {
                batterySensor.SetValue(HassTopicKind.State, 10);
            }
            else
            {
                batterySensor.SetValue(HassTopicKind.State, 100);
            }

            // Status (awake, sleeping, ..)
            statusSensor.SetValue(HassTopicKind.State, data.BlueDevice.SleepState);
        }
Exemplo n.º 7
0
        protected override void UpdateInternal(SwimmingPool pool, SwimmingPoolGuidanceGetResponse guidance)
        {
            ISensorContainer sensor = HassMqttManager
                                      .GetSensor(HassUniqueIdBuilder.GetPoolDeviceId(pool), "guidance")
                                      .SetPoolAttributes(pool);

            if (guidance.Guidance?.IssueToFix == null)
            {
                sensor.SetValue(HassTopicKind.State, "No guidance at this time");
                sensor.SetAttribute("status", "ok");

                return;
            }

            string text = $"{guidance.Guidance.IssueToFix.IssueTitle}: {guidance.Guidance.IssueToFix.ActionTitle}";

            sensor.SetValue(HassTopicKind.State, text);
            sensor.SetAttribute("status", "alert");
        }
Exemplo n.º 8
0
        private Task UponorClientOnOnSuccessfulResponse()
        {
            ISensorContainer sensor = _hassMqttManager.GetSensor(DeviceId, EntityId);

            sensor.SetValue(HassTopicKind.State, OkMessage);
            sensor.SetAttribute("last_ok", DateTime.UtcNow.ToString("O"));

            _shouldFlush.Set();

            return(Task.CompletedTask);
        }
Exemplo n.º 9
0
        private Task UponorClientOnOnFailedResponse(string message)
        {
            ISensorContainer sensor = _hassMqttManager.GetSensor(DeviceId, EntityId);

            sensor.SetValue(HassTopicKind.State, ProblemMessage);
            sensor.SetAttribute("last_bad", DateTime.UtcNow.ToString("O"));
            sensor.SetAttribute("last_bad_status", message);

            _shouldFlush.Set();

            return(Task.CompletedTask);
        }
        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));
        }
Exemplo n.º 11
0
 protected override void Update(ISensorContainer sensor, SwimmingPool pool, SwimmingPoolWeather obj)
 {
     sensor.SetValue(HassTopicKind.State, obj.UvCurrent);
 }
        public override void Process(UponorResponseContainer values)
        {
            List <string> problems = new List <string>();

            foreach ((int controller, int thermostat) in _systemDetails.GetAvailableThermostats())
            {
                string deviceId = HassUniqueIdBuilder.GetThermostatDeviceId(controller, thermostat);

                // Battery sensor
                // We don't know what the battery level is with Uponor. So we can only say it's "good" or "bad"
                ISensorContainer sensor = HassMqttManager.GetSensor(deviceId, "battery");

                if (values.TryGetValue(
                        UponorObjects.Thermostat(UponorThermostats.BatteryAlarm, controller, thermostat),
                        UponorProperties.Value, out object objVal) && objVal != null)
                {
                    sensor.SetValue(HassTopicKind.State, BatteryLow);
                }
                else
                {
                    sensor.SetValue(HassTopicKind.State, BatteryOk);
                }

                // Alarm sensor
                sensor = HassMqttManager.GetSensor(deviceId, "alarms");

                problems.Clear();

                // Check one of: RfAlarm, BatteryAlarm, TechnicalAlarm, TamperIndication
                if (values.TryGetValue(
                        UponorObjects.Thermostat(UponorThermostats.RfAlarm, controller, thermostat),
                        UponorProperties.Value, out objVal) && objVal != null)
                {
                    problems.Add("No signal");
                    sensor.SetAttribute("signal", "alarm");
                }
                else
                {
                    sensor.SetAttribute("signal", "ok");
                }

                if (values.TryGetValue(
                        UponorObjects.Thermostat(UponorThermostats.TechnicalAlarm, controller, thermostat),
                        UponorProperties.Value, out objVal) && objVal != null)
                {
                    problems.Add("Technical (?)");
                    sensor.SetAttribute("technical", "alarm");
                }
                else
                {
                    sensor.SetAttribute("technical", "ok");
                }

                if (values.TryGetValue(
                        UponorObjects.Thermostat(UponorThermostats.TamperIndication, controller, thermostat),
                        UponorProperties.Value, out objVal) && objVal != null)
                {
                    problems.Add("Tampering");
                    sensor.SetAttribute("tampering", "alarm");
                }
                else
                {
                    sensor.SetAttribute("tampering", "ok");
                }

                if (problems.Any())
                {
                    sensor.SetValue(HassTopicKind.State, "on");
                    sensor.SetAttribute("problem", string.Join(", ", problems));
                }
                else
                {
                    sensor.SetValue(HassTopicKind.State, "off");
                    sensor.SetAttribute("problem", string.Empty);
                }
            }
        }
Exemplo n.º 13
0
        public override void Process(UponorResponseContainer values)
        {
            foreach ((int controller, int thermostat) in _systemDetails.GetAvailableThermostats())
            {
                string deviceId = HassUniqueIdBuilder.GetThermostatDeviceId(controller, thermostat);

                // Temperature
                ISensorContainer sensor = HassMqttManager.GetSensor(deviceId, "temp");

                if (values.TryGetValue(
                        UponorObjects.Thermostat(UponorThermostats.RoomTemperature, controller, thermostat),
                        UponorProperties.Value, out float floatVal))
                {
                    if (IsValid.Temperature(floatVal))
                    {
                        sensor.SetValue(HassTopicKind.CurrentTemperature, floatVal);
                    }
                    else
                    {
                        _logger.LogWarning("Received an invalid temperature of {Value} for {Device}", floatVal, deviceId);
                    }
                }

                // Setpoint
                if (values.TryGetValue(
                        UponorObjects.Thermostat(UponorThermostats.RoomSetpoint, controller, thermostat),
                        UponorProperties.Value, out floatVal))
                {
                    sensor.SetValue(HassTopicKind.TemperatureState, floatVal);
                }

                // Action & Mode
                if (values.TryGetValue(
                        UponorObjects.Thermostat(UponorThermostats.RoomInDemand, controller, thermostat),
                        UponorProperties.Value, out int intVal))
                {
                    // If this value is >0, the room is heating/cooling (see H/C mode)
                    string action, mode;

                    // Valid values: off, heating, cooling, drying, idle, fan.
                    if (intVal <= 0)
                    {
                        action = "idle";
                        mode   = "off";
                    }
                    else if (_systemDetails.HcMode == HcMode.Heating)
                    {
                        action = "heating";
                        mode   = "heat";
                    }
                    else
                    {
                        action = "cooling";
                        mode   = "cool";
                    }

                    // Override Mode as auto
                    if (_operationConfig.OperationMode == OperationMode.Normal)
                    {
                        mode = "auto";
                    }

                    sensor.SetValue(HassTopicKind.Action, action);
                    sensor.SetValue(HassTopicKind.ModeState, mode);
                }

                // Home/away
                if (values.TryGetValue(
                        UponorObjects.Thermostat(UponorThermostats.HomeAwayModeStatus, controller, thermostat),
                        UponorProperties.Value, out intVal))
                {
                    if (intVal > 0)
                    {
                        // Away
                        sensor.SetValue(HassTopicKind.AwayModeState, "on");
                    }
                    else
                    {
                        // Home
                        sensor.SetValue(HassTopicKind.AwayModeState, "off");
                    }
                }
            }
        }
        private async Task Run()
        {
            ISensorContainer operationalSensor = CreateSystemEntities();

            // Update loop
            while (!_stoppingToken.Token.IsCancellationRequested)
            {
                _logger.LogDebug("Beginning update for pool {Pool}", _pool.SwimmingPoolId);

                try
                {
                    await PerformUpdate(_stoppingToken.Token);

                    // Track API operational status
                    operationalSensor.SetValue(HassTopicKind.State, BlueRiiotMqttService.OkMessage);
                    operationalSensor.SetAttribute("last_ok", DateTime.UtcNow);
                }
                catch (OperationCanceledException) when(_stoppingToken.Token.IsCancellationRequested)
                {
                    // Do nothing
                }
                catch (Exception e)
                {
                    _logger.LogError(e, "An error occurred while performing the update for pool {Pool}", _pool.SwimmingPoolId);

                    // Track API operational status
                    operationalSensor.SetValue(HassTopicKind.State, BlueRiiotMqttService.ProblemMessage);
                    operationalSensor.SetAttribute("last_bad", DateTime.UtcNow);
                    operationalSensor.SetAttribute("last_bad_status", e.Message);
                }

                TimeSpan?runDelay;
                if (_config.EnableSchedule)
                {
                    // Calculate time to next update
                    runDelay = _delayCalculator.CalculateNextRun(DateTime.UtcNow);
                    DateTime runNext = DateTime.UtcNow + runDelay.Value;

                    operationalSensor.SetAttribute("next_run", runNext);
                }
                else
                {
                    // We will forever wait for manual sync
                    runDelay = null;

                    operationalSensor.SetAttribute("next_run", "manual");
                }

                try
                {
                    await _hassMqttManager.FlushAll(_stoppingToken.Token);
                }
                catch (OperationCanceledException) when(_stoppingToken.Token.IsCancellationRequested)
                {
                    // Do nothing
                }
                catch (Exception e)
                {
                    _logger.LogError(e, "An error occurred while pushing updated data to MQTT for pool {Pool}", _pool.SwimmingPoolId);
                }

                // Wait on the force sync reset event, for the specified time.
                // If either the reset event or the time runs out, we do an update
                using (CancellationTokenSource cts = new CancellationTokenSource())
                    using (CancellationTokenSource linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, _stoppingToken.Token))
                    {
                        if (runDelay.HasValue)
                        {
                            cts.CancelAfter(runDelay.Value);
                        }

                        try
                        {
                            await _forceSyncResetEvent.WaitAsync(linkedToken.Token);

                            // We were forced
                            _logger.LogDebug("Forcing a sync for pool {Pool} with BlueRiiot", _pool.SwimmingPoolId);
                        }
                        catch (OperationCanceledException)
                        {
                        }
                    }
            }
        }