using System; using System.Collections.Generic; using System.Device.I2c; using System.Threading.Tasks; using Iot.Device.Bmxx80; using Iot.Device.Bmxx80.PowerMode; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NucuCar.Domain.Telemetry; using NucuCarSensorsProto; namespace NucuCar.Sensors.EnvironmentSensor { /// /// Abstraction for the BME680 sensor. /// See: https://www.bosch-sensortec.com/bst/products/all_products/bme680 /// public class Bme680Sensor : IDisposable, ITelemeter, ISensor { private readonly ILogger _logger; private I2cConnectionSettings _i2CSettings; private I2cDevice _i2CDevice; private Bme680 _bme680; private Dictionary _lastMeasurement; private SensorStateEnum _sensorStateEnum; public Bme680Sensor() { } public Bme680Sensor(ILogger logger, IOptions options) { _sensorStateEnum = SensorStateEnum.Uninitialized; _logger = logger; if (!options.Value.ServiceEnabled) { _logger?.LogInformation("BME680 Sensor is disabled!"); _sensorStateEnum = SensorStateEnum.Disabled; } Object = this; } public virtual Dictionary GetMeasurement() { return _lastMeasurement; } public virtual SensorStateEnum GetState() { return _sensorStateEnum; } public void Dispose() { _bme680?.Dispose(); } public virtual void InitializeSensor() { if (_sensorStateEnum == SensorStateEnum.Initialized || _sensorStateEnum == SensorStateEnum.Disabled) { return; } _lastMeasurement = new Dictionary(); try { /* Connect to default i2c address 0x76 */ _i2CSettings = new I2cConnectionSettings(1, Bme680.DefaultI2cAddress); _i2CDevice = I2cDevice.Create(_i2CSettings); _bme680 = new Bme680(_i2CDevice); /* Initialize measurement */ _bme680.Reset(); _bme680.SetHumiditySampling(Sampling.UltraLowPower); _bme680.SetTemperatureSampling(Sampling.UltraHighResolution); _bme680.SetPressureSampling(Sampling.UltraLowPower); _sensorStateEnum = SensorStateEnum.Initialized; _logger?.LogInformation($"{DateTimeOffset.Now}:BME680 Sensor initialization OK."); } catch (System.IO.IOException e) { _logger?.LogError($"{DateTimeOffset.Now}:BME680 Sensor initialization FAIL."); _logger?.LogTrace(e.Message); _sensorStateEnum = SensorStateEnum.Error; } } public virtual async Task TakeMeasurement() { if (_sensorStateEnum != SensorStateEnum.Initialized) { _logger?.LogWarning( $"{DateTimeOffset.Now}:BME680: Attempting to take measurement while sensor is not initialized!"); return; } /* Force the sensor to take a measurement. */ _bme680.SetPowerMode(Bme680PowerMode.Forced); _lastMeasurement["temperature"] = (await _bme680.ReadTemperatureAsync()).Celsius; _lastMeasurement["pressure"] = await _bme680.ReadPressureAsync(); _lastMeasurement["humidity"] = await _bme680.ReadHumidityAsync(); _lastMeasurement["voc"] = 0.0; // Not implemented. _logger?.LogDebug($"{DateTimeOffset.Now}:BME680: reading"); _logger?.LogInformation( $"temperature:{_lastMeasurement.GetValueOrDefault("temperature"):N2} \u00B0C|" + $"pressure:{_lastMeasurement.GetValueOrDefault("pressure"):N2} hPa|" + $"humidity:{_lastMeasurement.GetValueOrDefault("humidity"):N2} %rH|" + $"voc:{_lastMeasurement.GetValueOrDefault("voc")}"); } public string GetIdentifier() { return nameof(EnvironmentSensor); } public Dictionary GetTelemetryData() { Dictionary returnValue = null; if (_lastMeasurement != null) { returnValue = new Dictionary { ["sensor_state"] = _sensorStateEnum, ["temperature"] = _lastMeasurement.GetValueOrDefault("temperature"), ["humidity"] = _lastMeasurement.GetValueOrDefault("humidity"), ["pressure"] = _lastMeasurement.GetValueOrDefault("pressure"), ["voc"] = _lastMeasurement.GetValueOrDefault("voc") }; } return returnValue; } public Bme680Sensor Object { get; } } }