diff --git a/Source/Clima_Demo/Commands/RestartCommand.cs b/Source/Clima_Demo/Commands/RestartCommand.cs
new file mode 100644
index 0000000..c89dfe8
--- /dev/null
+++ b/Source/Clima_Demo/Commands/RestartCommand.cs
@@ -0,0 +1,30 @@
+using Meadow;
+using Meadow.Cloud;
+using System.Threading;
+
+namespace Clima_Demo.Commands;
+
+///
+/// Restart Clima
+///
+public class RestartCommand : IMeadowCommand
+{
+ ///
+ /// Delay to restart
+ ///
+ public int Delay { get; set; }
+
+ ///
+ /// Initialise the command and register handler.
+ ///
+ public static void Initialise()
+ {
+ Resolver.CommandService.Subscribe(command =>
+ {
+ Resolver.Log.Info($"RestartCommand: Meadow will restart in {command.Delay} seconds.");
+ Thread.Sleep(command.Delay * 1000);
+ Resolver.Device.PlatformOS.Reset();
+ });
+
+ }
+}
\ No newline at end of file
diff --git a/Source/Clima_Demo/MeadowApp.cs b/Source/Clima_Demo/MeadowApp.cs
index b7794fa..7b4652a 100644
--- a/Source/Clima_Demo/MeadowApp.cs
+++ b/Source/Clima_Demo/MeadowApp.cs
@@ -1,4 +1,5 @@
-using Meadow;
+using Clima_Demo.Commands;
+using Meadow;
using Meadow.Devices;
using Meadow.Devices.Esp32.MessagePayloads;
using Meadow.Hardware;
@@ -31,6 +32,54 @@ public override Task Initialize()
return Task.CompletedTask;
}
+ public override Task Run()
+ {
+ var svc = Resolver.UpdateService;
+
+ // Uncomment to clear any persisted update info. This allows installing
+ // the same update multiple times, such as you might do during development.
+ // svc.ClearUpdates();
+
+ svc.StateChanged += (sender, updateState) =>
+ {
+ Resolver.Log.Info($"UpdateState {updateState}");
+ if (updateState == UpdateState.DownloadingFile)
+ {
+ mainController?.StopUpdating();
+ }
+ };
+
+ svc.RetrieveProgress += (updateService, info) =>
+ {
+ short percentage = (short)((double)info.DownloadProgress / info.FileSize * 100);
+
+ Resolver.Log.Info($"Downloading... {percentage}%");
+ };
+
+ svc.UpdateAvailable += async (updateService, info) =>
+ {
+ Resolver.Log.Info($"Update available!");
+
+ // Queue update for retrieval "later"
+ await Task.Delay(5000);
+
+ updateService.RetrieveUpdate(info);
+ };
+
+ svc.UpdateRetrieved += async (updateService, info) =>
+ {
+ Resolver.Log.Info($"Update retrieved!");
+
+ await Task.Delay(5000);
+
+ updateService.ApplyUpdate(info);
+ };
+
+ RestartCommand.Initialise();
+
+ return Task.CompletedTask;
+ }
+
private void OnMeadowSystemError(MeadowSystemErrorInfo error, bool recommendReset, out bool forceReset)
{
if (error is Esp32SystemErrorInfo espError)
diff --git a/Source/Clima_Demo/app.config.yaml b/Source/Clima_Demo/app.config.yaml
index 55fbb50..633dfcd 100644
--- a/Source/Clima_Demo/app.config.yaml
+++ b/Source/Clima_Demo/app.config.yaml
@@ -23,10 +23,15 @@ MeadowCloud:
Enabled: true
# Enable Over-the-air Updates
-# EnableUpdates: false
+ EnableUpdates: true
# Enable Health Metrics
EnableHealthMetrics: true
# How often to send metrics to Meadow.Cloud
- HealthMetricsIntervalMinutes: 60
+ HealthMetricsIntervalMinutes: 5
+
+
+# Settings for Clima
+Clima:
+ OffsetToNorth: 0.0
\ No newline at end of file
diff --git a/Source/Clima_Demo/meadow.config.yaml b/Source/Clima_Demo/meadow.config.yaml
index e1b04ee..dd369f3 100644
--- a/Source/Clima_Demo/meadow.config.yaml
+++ b/Source/Clima_Demo/meadow.config.yaml
@@ -16,7 +16,7 @@ Coprocessor:
# Should the ESP32 automatically attempt to connect to an access point at startup?
# If set to true, wifi.yaml credentials must be stored in the device.
- AutomaticallyStartNetwork: true
+ AutomaticallyStartNetwork: false
# Should the ESP32 automatically reconnect to the configured access point?
AutomaticallyReconnect: true
diff --git a/Source/Meadow.Clima/Controllers/CloudController.cs b/Source/Meadow.Clima/Controllers/CloudController.cs
index 18d41ca..945bc39 100644
--- a/Source/Meadow.Clima/Controllers/CloudController.cs
+++ b/Source/Meadow.Clima/Controllers/CloudController.cs
@@ -2,6 +2,7 @@
using Meadow.Devices.Clima.Constants;
using Meadow.Devices.Clima.Models;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -47,21 +48,19 @@ public void LogAppStartup(string hardwareRevision)
/// Logs the device information including name and location.
///
/// The name of the device.
- /// The latitude of the device location.
+ /// The latitude of the device location.
/// The longitude of the device location.
- public void LogDeviceInfo(string deviceName, double latitiude, double longitude)
+ public void LogDeviceInfo(string deviceName, double latitude, double longitude)
{
- var cloudEvent = new CloudEvent
+ Resolver.Log.Info("LogDeviceInfo: Create CloudEvent");
+ CloudEvent cloudEvent = new CloudEvent
{
Description = "Clima Position Telemetry",
Timestamp = DateTime.UtcNow,
EventId = 109,
+ Measurements = new Dictionary { { "device_name", deviceName }, { "lat", latitude }, { "long", longitude } }
};
-
- cloudEvent.Measurements.Add("device_name", deviceName);
- cloudEvent.Measurements.Add("lat", latitiude);
- cloudEvent.Measurements.Add("long", longitude);
-
+
SendEvent(cloudEvent);
}
diff --git a/Source/Meadow.Clima/Controllers/LocationController.cs b/Source/Meadow.Clima/Controllers/LocationController.cs
index 9b93946..8b82911 100644
--- a/Source/Meadow.Clima/Controllers/LocationController.cs
+++ b/Source/Meadow.Clima/Controllers/LocationController.cs
@@ -1,6 +1,8 @@
using Meadow.Devices.Clima.Hardware;
using Meadow.Peripherals.Sensors.Location.Gnss;
+using Meadow.Units;
using System;
+using System.Threading;
namespace Meadow.Devices.Clima.Controllers;
@@ -21,6 +23,8 @@ public class LocationController
///
public event EventHandler? PositionReceived = null;
+ private ManualResetEvent positionReceived = new ManualResetEvent(false);
+
///
/// Initializes a new instance of the class.
///
@@ -31,21 +35,66 @@ public LocationController(IClimaHardware clima)
{
this.gnss = gnss;
this.gnss.GnssDataReceived += OnGnssDataReceived;
- this.gnss.StartUpdating();
}
}
+ ///
+ /// Gets the current geographic position as a .
+ ///
+ ///
+ /// The geographic position, including latitude, longitude, and altitude, if available.
+ ///
+ ///
+ /// This property is updated when valid GNSS data is received. It represents the last known position
+ /// and remains unchanged until new valid data is processed.
+ ///
+ public GeographicCoordinate? Position { get; private set; } = default;
+
private void OnGnssDataReceived(object sender, IGnssResult e)
{
if (e is GnssPositionInfo pi)
{
if (pi.IsValid && pi.Position != null)
{
+ // remember our position
+ Position = pi.Position;
// we only need one position fix - weather stations don't move
Resolver.Log.InfoIf(LogData, $"GNSS Position: lat: [{pi.Position.Latitude}], long: [{pi.Position.Longitude}]");
+ positionReceived.Set();
PositionReceived?.Invoke(this, pi);
- gnss?.StopUpdating();
+ StopUpdating();
}
}
}
-}
\ No newline at end of file
+
+ ///
+ /// Starts the GNSS sensor to begin updating location data.
+ ///
+ ///
+ /// This method invokes the method on the associated GNSS sensor,
+ /// if it is available, to start receiving GNSS data updates.
+ ///
+ public void StartUpdating(bool forced = false)
+ {
+ // start updating if forced to find new data or we don;t have current location
+ if (forced || !positionReceived.WaitOne(0))
+ {
+ gnss?.StartUpdating();
+ };
+ }
+
+ ///
+ /// Stops the GNSS sensor from updating location data.
+ ///
+ ///
+ /// This method halts the GNSS data updates by invoking the
+ /// method on the associated GNSS sensor, if it is available.
+ ///
+ public void StopUpdating()
+ {
+ // stop listening to data arriving from GNSS
+ gnss?.StopUpdating();
+
+ // TODO: can we tell GNSS sensor to stop calculating GPS location and stop sending data to reduce power consumption?
+ }
+}
diff --git a/Source/Meadow.Clima/Controllers/NetworkController.cs b/Source/Meadow.Clima/Controllers/NetworkController.cs
index 4a1ffe4..530421d 100644
--- a/Source/Meadow.Clima/Controllers/NetworkController.cs
+++ b/Source/Meadow.Clima/Controllers/NetworkController.cs
@@ -1,4 +1,5 @@
using Meadow.Hardware;
+using Meadow.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
@@ -27,17 +28,35 @@ public class NetworkController
///
/// Gets a value indicating whether the network is connected.
///
- public bool IsConnected { get; private set; }
+ public bool IsConnected => networkAdapter.IsConnected;
///
/// Gets the total time the network has been down.
///
- public TimeSpan DownTime { get; private set; }
+ public TimeSpan DownTime => lastDown == null ? TimeSpan.Zero : DateTime.UtcNow - lastDown.Value;
///
/// Gets the period for triggering network down events.
///
- public TimeSpan DownEventPeriod { get; private set; }
+ public TimeSpan DownEventPeriod { get; } = TimeSpan.FromSeconds(30);
+
+
+ ///
+ /// Port used for UdpLogging.
+ ///
+ ///
+ /// Default set in constructor is port 5100
+ ///
+ private int UdpLoggingPort { get; set; }
+
+ ///
+ /// Instance of UdpLogger. Use to remove UdpLogger if the network disconnects
+ ///
+ private UdpLogger? UdpLogger { get; set; }
+
+ private string WifiSsid { get; set; } = "SSID";
+ private string WifiPassword { get; set; } = "PASSWORD";
+
///
/// Initializes a new instance of the class.
@@ -73,8 +92,8 @@ public async Task ConnectToCloud()
{
if (!wifi.IsConnected)
{
- Resolver.Log.Info("Connecting to network...");
- await wifi.Connect("interwebs", "1234567890");
+ Resolver.Log.Info($"Connecting to network: {WifiSsid}");
+ await wifi.Connect(WifiSsid, WifiPassword);
}
}
@@ -118,6 +137,14 @@ private void DownEventTimerProc(object _)
private void OnNetworkDisconnected(INetworkAdapter sender, NetworkDisconnectionEventArgs args)
{
+ // Remove the UdpLogger if it's in the LogProviderCollection.
+ if (UdpLogger != null)
+ {
+ Resolver.Log.RemoveProvider(UdpLogger);
+ UdpLogger.Dispose();
+ UdpLogger = null;
+ }
+
lastDown = DateTimeOffset.UtcNow;
downEventTimer.Change(DownEventPeriod, TimeSpan.FromMilliseconds(-1));
ConnectionStateChanged?.Invoke(this, false);
@@ -150,6 +177,9 @@ private async Task ReportWiFiScan(IWiFiNetworkAdapter wifi)
private void OnNetworkConnected(INetworkAdapter sender, NetworkConnectionEventArgs args)
{
+ Resolver.Log.Info("Add UdpLogger");
+ Resolver.Log.AddProvider(UdpLogger = new UdpLogger(UdpLoggingPort));
+
if (sender is IWiFiNetworkAdapter wifi)
{
_ = ReportWiFiScan(wifi);
diff --git a/Source/Meadow.Clima/Controllers/NotificationController.cs b/Source/Meadow.Clima/Controllers/NotificationController.cs
index 3899520..050238e 100644
--- a/Source/Meadow.Clima/Controllers/NotificationController.cs
+++ b/Source/Meadow.Clima/Controllers/NotificationController.cs
@@ -81,6 +81,7 @@ public NotificationController(IRgbPwmLed? rgbLed)
/// The system status to set.
public void SetSystemStatus(SystemStatus status)
{
+ Resolver.Log.Info($"SetSystemStatus = {status}");
switch (status)
{
case SystemStatus.LowPower:
diff --git a/Source/Meadow.Clima/Controllers/PowerController.cs b/Source/Meadow.Clima/Controllers/PowerController.cs
index a9a1770..826b053 100644
--- a/Source/Meadow.Clima/Controllers/PowerController.cs
+++ b/Source/Meadow.Clima/Controllers/PowerController.cs
@@ -35,7 +35,7 @@ public class PowerController
///
/// Gets the interval at which power data is updated.
///
- public TimeSpan UpdateInterval { get; } = TimeSpan.FromSeconds(5);
+ public TimeSpan UpdateInterval { get; private set; } = TimeSpan.FromSeconds(10);
///
/// Gets the voltage level below which a battery warning is issued.
@@ -59,12 +59,35 @@ public class PowerController
public PowerController(IClimaHardware clima)
{
this.clima = clima;
+ }
+
+ ///
+ /// Remove event handler and stop updating
+ ///
+ public void StopUpdating()
+ {
+ Resolver.Log.Info($"PowerController: Stop Updating");
+ if (clima.SolarVoltageInput is { } solarVoltage)
+ {
+ solarVoltage.Updated -= SolarVoltageUpdated;
+ solarVoltage.StopUpdating();
+ }
- Initialize();
+ if (clima.BatteryVoltageInput is { } batteryVoltage)
+ {
+ batteryVoltage.Updated -= BatteryVoltageUpdated;
+ batteryVoltage.StopUpdating();
+ }
}
- private void Initialize()
+ ///
+ /// Add event handler and start updating
+ ///
+ ///
+ public void StartUpdating(TimeSpan powerControllerUpdateInterval)
{
+ UpdateInterval = powerControllerUpdateInterval;
+
if (clima.SolarVoltageInput is { } solarVoltage)
{
solarVoltage.Updated += SolarVoltageUpdated;
@@ -84,13 +107,11 @@ private void Initialize()
/// A task that represents the asynchronous operation. The task result contains the power data.
public Task GetPowerData()
{
- var data = new PowerData
+ return Task.FromResult(new PowerData
{
BatteryVoltage = clima.BatteryVoltageInput?.Voltage ?? null,
SolarVoltage = clima.SolarVoltageInput?.Voltage ?? null,
- };
-
- return new Task(() => data);
+ });
}
///
diff --git a/Source/Meadow.Clima/Controllers/SensorController.cs b/Source/Meadow.Clima/Controllers/SensorController.cs
index ff52443..17b3b60 100644
--- a/Source/Meadow.Clima/Controllers/SensorController.cs
+++ b/Source/Meadow.Clima/Controllers/SensorController.cs
@@ -3,6 +3,7 @@
using Meadow.Units;
using System;
using System.Threading.Tasks;
+using YamlDotNet.Core.Tokens;
namespace Meadow.Devices.Clima.Controllers;
@@ -11,7 +12,9 @@ namespace Meadow.Devices.Clima.Controllers;
///
public class SensorController
{
+ private readonly IClimaHardware clima;
private readonly CircularBuffer windVaneBuffer = new CircularBuffer(12);
+ private readonly CircularBuffer windSpeedBuffer = new CircularBuffer(12);
private readonly SensorData latestData;
///
@@ -22,7 +25,7 @@ public class SensorController
///
/// Gets the interval at which sensor data is updated.
///
- public TimeSpan UpdateInterval { get; } = TimeSpan.FromSeconds(15);
+ public TimeSpan UpdateInterval { get; private set; } = TimeSpan.FromSeconds(15);
///
/// Initializes a new instance of the class.
@@ -31,6 +34,75 @@ public class SensorController
public SensorController(IClimaHardware clima)
{
latestData = new SensorData();
+ this.clima = clima;
+
+ if (Resolver.App.Settings.TryGetValue("Clima.OffsetToNorth", out string offsetToNorthSetting))
+ {
+ if (Double.TryParse(offsetToNorthSetting, out double trueNorth))
+ {
+ OffsetToNorth = new Azimuth(trueNorth);
+ }
+ }
+ }
+
+ ///
+ /// Stop the update events and remove event handler.
+ ///
+ public void StopUpdating()
+ {
+ if (clima.TemperatureSensor is { } temperatureSensor)
+ {
+ temperatureSensor.Updated -= TemperatureUpdated;
+ temperatureSensor.StopUpdating();
+ }
+ if (clima.BarometricPressureSensor is { } pressureSensor)
+ {
+ pressureSensor.Updated -= PressureUpdated;
+ // barometric pressure is slow to change
+ pressureSensor.StopUpdating();
+ }
+
+ if (clima.HumiditySensor is { } humiditySensor)
+ {
+ humiditySensor.Updated -= HumidityUpdated;
+ // humidity is slow to change
+ humiditySensor.StopUpdating();
+ }
+
+ if (clima.CO2ConcentrationSensor is { } co2Sensor)
+ {
+ co2Sensor.Updated -= Co2Updated;
+ // CO2 levels are slow to change
+ co2Sensor.StopUpdating();
+ }
+
+ if (clima.WindVane is { } windVane)
+ {
+ windVane.Updated -= WindvaneUpdated;
+ windVane.StopUpdating();
+ }
+
+ if (clima.RainGauge is { } rainGuage)
+ {
+ rainGuage.Updated -= RainGaugeUpdated;
+ // rain does not change frequently
+ rainGuage.StopUpdating();
+ }
+
+ if (clima.Anemometer is { } anemometer)
+ {
+ anemometer.Updated -= AnemometerUpdated;
+ anemometer.StopUpdating();
+ }
+ }
+
+ ///
+ /// Add event handlers and start updating
+ ///
+ ///
+ public void StartUpdating(TimeSpan updateInterval)
+ {
+ UpdateInterval = updateInterval;
if (clima.TemperatureSensor is { } temperatureSensor)
{
@@ -133,12 +205,22 @@ private void Co2Updated(object sender, IChangeResult e)
private void AnemometerUpdated(object sender, IChangeResult e)
{
+ Speed? mean = new Speed(0);
lock (latestData)
{
- latestData.WindSpeed = e.New;
+ // sanity check on windspeed to avoid reporting Infinity
+ if (e.New.KilometersPerHour <= 250)
+ {
+ latestData.WindSpeed = e.New;
+
+ windSpeedBuffer.Append(e.New);
+ latestData.WindSpeedAverage = mean = windSpeedBuffer.Mean();
+ }
}
- Resolver.Log.InfoIf(LogSensorData, $"Anemometer: {e.New.MetersPerSecond:0.#} m/s");
+ //Resolver.Log.InfoIf(true, $"Anemometer: {e.New.MetersPerSecond:0.#} m/s");
+ Resolver.Log.InfoIf(LogSensorData, $"Anemometer: {e.New.KilometersPerHour:0.#} km/hr, Average = {mean?.KilometersPerHour:0.#} km/hr");
+
}
private void RainGaugeUpdated(object sender, IChangeResult e)
@@ -151,15 +233,33 @@ private void RainGaugeUpdated(object sender, IChangeResult e)
Resolver.Log.InfoIf(LogSensorData, $"Rain Gauge: {e.New.Millimeters:0.#} mm");
}
+ ///
+ /// 0 to 360 degree offset to true north updated from app.config.yaml
+ ///
+ ///
+ /// After install of Clima, point wind vane at true north, run Clima_Demo and record uncalibrated WindDirection.
+ /// Update app.config.yaml with the uncalibrated WindDirection.
+ /// Deploy the updated app.config.yaml and this direction will be reported as 0 Degrees.
+ ///
+ ///
+ /// # Settings for Clima
+ /// Clima:
+ /// OffsetToNorth: 0.0
+ ///
+ public Azimuth OffsetToNorth { get; private set; } = new Azimuth(0.0);
+
private void WindvaneUpdated(object sender, IChangeResult e)
{
- windVaneBuffer.Append(e.New);
+ Azimuth newAzimuth = e.New - OffsetToNorth;
+ windVaneBuffer.Append(newAzimuth);
+
+ Azimuth mean = windVaneBuffer.Mean();
lock (latestData)
{
- latestData.WindDirection = windVaneBuffer.Mean();
+ latestData.WindDirection = mean;
}
- Resolver.Log.InfoIf(LogSensorData, $"Wind Vane: {e.New.DecimalDegrees} (mean: {windVaneBuffer.Mean().DecimalDegrees})");
+ Resolver.Log.InfoIf(LogSensorData, $"Wind Vane: {newAzimuth}, Average: {mean.DecimalDegrees} (uncalibrated: {e.New})");
}
}
\ No newline at end of file
diff --git a/Source/Meadow.Clima/MainController.cs b/Source/Meadow.Clima/MainController.cs
index 642566e..ff0245e 100644
--- a/Source/Meadow.Clima/MainController.cs
+++ b/Source/Meadow.Clima/MainController.cs
@@ -50,14 +50,17 @@ public Task Initialize(IClimaHardware hardware, INetworkAdapter? networkAdapter)
Resolver.Log.Info($"Running on Clima Hardware {hardware.RevisionString}");
sensorController = new SensorController(hardware);
+ sensorController.StartUpdating(sensorController.UpdateInterval); // TODO: consider calling after network, time etc are ready?
powerController = new PowerController(hardware);
+ powerController.StartUpdating(powerController.UpdateInterval); // TODO: consider calling after network, time
+
powerController.SolarVoltageWarning += OnSolarVoltageWarning;
powerController.BatteryVoltageWarning += OnBatteryVoltageWarning;
- locationController = new LocationController(hardware);
- locationController.PositionReceived += OnPositionReceived;
+
+
if (networkAdapter == null)
{
@@ -76,6 +79,7 @@ public Task Initialize(IClimaHardware hardware, INetworkAdapter? networkAdapter)
}
else
{
+ Resolver.Log.Info("Network is connected.");
notificationController.SetSystemStatus(NotificationController.SystemStatus.NetworkConnected);
if (Resolver.MeadowCloudService.ConnectionState == CloudConnectionState.Connecting)
{
@@ -87,6 +91,9 @@ public Task Initialize(IClimaHardware hardware, INetworkAdapter? networkAdapter)
Resolver.MeadowCloudService.ConnectionStateChanged += OnMeadowCloudServiceConnectionStateChanged;
cloudController.LogAppStartup(hardware.RevisionString);
+ locationController = new LocationController(hardware);
+ locationController.PositionReceived += OnPositionReceived;
+
Resolver.Device.PlatformOS.AfterWake += PlatformOS_AfterWake;
if (!lowPowerMode)
@@ -96,9 +103,34 @@ public Task Initialize(IClimaHardware hardware, INetworkAdapter? networkAdapter)
_ = SystemPreSleepStateProc();
+ Resolver.Log.Info($"Initialize hardware Task.CompletedTask");
+
return Task.CompletedTask;
}
+ ///
+ /// Start sensor and power controller updates
+ ///
+ public void StartUpdating()
+ {
+ Resolver.Log.Info($"Start Updating");
+ sensorController.StartUpdating(sensorController.UpdateInterval);
+ powerController.StartUpdating(powerController.UpdateInterval);
+ locationController.StartUpdating();
+ }
+
+ ///
+ /// Stop sensor and power controller updates
+ ///
+ public void StopUpdating()
+ {
+ Resolver.Log.Info($"Stop Updating");
+ sensorController.StopUpdating();
+ powerController.StopUpdating();
+ locationController.StopUpdating();
+ sleepSimulationTimer.Change(-1, -1); // stop timer
+ }
+
private void OnPositionReceived(object sender, Peripherals.Sensors.Location.Gnss.GnssPositionInfo e)
{
if (e.Position != null)
@@ -179,7 +211,15 @@ private void OnMeadowCloudServiceConnectionStateChanged(object sender, CloudConn
{
case CloudConnectionState.Connected:
notificationController.SetSystemStatus(NotificationController.SystemStatus.Connected);
+
+ locationController.StartUpdating();
break;
+
+ case CloudConnectionState.Disconnected:
+ case CloudConnectionState.Unknown:
+ locationController.StopUpdating();
+ break;
+
default:
notificationController.SetSystemStatus(NotificationController.SystemStatus.ConnectingToCloud);
break;
@@ -285,4 +325,4 @@ public void LogAppStartupAfterCrash(IEnumerable crashReports)
Resolver.Log.Info(report);
}
}
-}
\ No newline at end of file
+}
diff --git a/Source/Meadow.Clima/Meadow.Clima.csproj b/Source/Meadow.Clima/Meadow.Clima.csproj
index 31623d8..230ceff 100644
--- a/Source/Meadow.Clima/Meadow.Clima.csproj
+++ b/Source/Meadow.Clima/Meadow.Clima.csproj
@@ -22,13 +22,14 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/Source/Meadow.Clima/Models/SensorData.cs b/Source/Meadow.Clima/Models/SensorData.cs
index e67eec1..2b8c117 100644
--- a/Source/Meadow.Clima/Models/SensorData.cs
+++ b/Source/Meadow.Clima/Models/SensorData.cs
@@ -33,6 +33,11 @@ public class SensorData
///
public Speed? WindSpeed { get; set; }
+ ///
+ /// Gets or sets the average wind speed.
+ ///
+ public Speed? WindSpeedAverage { get; set; }
+
///
/// Gets or sets the wind direction.
///
@@ -53,10 +58,12 @@ public class SensorData
///
public void Clear()
{
- Co2Level = null;
Temperature = null;
Pressure = null;
+ Humidity = null;
+ Co2Level = null;
WindSpeed = null;
+ WindSpeedAverage = null;
WindDirection = null;
Rain = null;
Light = null;
@@ -69,10 +76,12 @@ public SensorData Copy()
{
return new SensorData
{
- Co2Level = Co2Level,
Temperature = Temperature,
Pressure = Pressure,
+ Humidity = Humidity,
+ Co2Level = Co2Level,
WindSpeed = WindSpeed,
+ WindSpeedAverage = WindSpeedAverage,
WindDirection = WindDirection,
Rain = Rain,
Light = Light,
@@ -107,13 +116,17 @@ public Dictionary AsTelemetryDictionary()
{
d.Add(nameof(WindSpeed), WindSpeed.Value.KilometersPerHour);
}
+ if (WindSpeedAverage != null)
+ {
+ d.Add(nameof(WindSpeedAverage), WindSpeedAverage.Value.KilometersPerHour);
+ }
if (WindDirection != null)
{
d.Add(nameof(WindDirection), WindDirection.Value.DecimalDegrees);
}
if (Rain != null)
{
- d.Add(nameof(Rain), Rain.Value.Centimeters);
+ d.Add(nameof(Rain), Rain.Value.Millimeters);
}
if (Light != null)
{