Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve connecting to WIFI, add UdpLogging, OTA Restart Command and Updates #93

Merged
merged 8 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Source/Clima_Demo/Commands/RestartCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Meadow;
using Meadow.Cloud;
using System.Threading;

namespace Clima_Demo.Commands;

/// <summary>
/// Restart Clima
/// </summary>
public class RestartCommand : IMeadowCommand
{
/// <summary>
/// Delay to restart
/// </summary>
public int Delay { get; set; }

/// <summary>
/// Initialise the command and register handler.
/// </summary>
public static void Initialise()
{
Resolver.CommandService.Subscribe<RestartCommand>(command =>
{
Resolver.Log.Info($"RestartCommand: Meadow will restart in {command.Delay} seconds.");
Thread.Sleep(command.Delay * 1000);
Resolver.Device.PlatformOS.Reset();
});

}
}
51 changes: 50 additions & 1 deletion Source/Clima_Demo/MeadowApp.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Meadow;
using Clima_Demo.Commands;
using Meadow;
using Meadow.Devices;
using Meadow.Devices.Esp32.MessagePayloads;
using Meadow.Hardware;
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions Source/Clima_Demo/app.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ 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
2 changes: 1 addition & 1 deletion Source/Clima_Demo/meadow.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions Source/Meadow.Clima.sln
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet", "..\..\MQTTnet\So
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serialization.MicroJson", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Libraries_and_Frameworks\Serialization.MicroJson\Driver\Serialization.MicroJson.csproj", "{6300EAB4-806F-4C18-8FE0-57C45A2C0C58}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meadow.Logging.LogProviders", "..\..\Meadow.Logging\Source\Meadow.Logging.LogProviders\Driver\Meadow.Logging.LogProviders.csproj", "{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -364,6 +366,24 @@ Global
{6300EAB4-806F-4C18-8FE0-57C45A2C0C58}.Release|iPhone.Build.0 = Release|Any CPU
{6300EAB4-806F-4C18-8FE0-57C45A2C0C58}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{6300EAB4-806F-4C18-8FE0-57C45A2C0C58}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|iPhone.Build.0 = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|iPhone.Deploy.0 = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|Any CPU.Build.0 = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|Any CPU.Deploy.0 = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|iPhone.ActiveCfg = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|iPhone.Build.0 = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|iPhone.Deploy.0 = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -386,6 +406,7 @@ Global
{85DC9E85-3472-418A-8065-5EF99323E6FE} = {2889A476-F914-49E8-9F97-4CC6CA34A901}
{F6EB1347-3926-4308-BE20-70AC53BEBF1D} = {2889A476-F914-49E8-9F97-4CC6CA34A901}
{6300EAB4-806F-4C18-8FE0-57C45A2C0C58} = {2889A476-F914-49E8-9F97-4CC6CA34A901}
{07E3B02A-5D79-4551-A77E-DC445E2A6A6A} = {2889A476-F914-49E8-9F97-4CC6CA34A901}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CA61E123-F783-4CB3-8EB2-099EE930ADD4}
Expand Down
12 changes: 8 additions & 4 deletions Source/Meadow.Clima/Controllers/NetworkController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Meadow.Hardware;
using Meadow.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -27,18 +28,18 @@ public class NetworkController
/// <summary>
/// Gets a value indicating whether the network is connected.
/// </summary>
public bool IsConnected { get; private set; }
public bool IsConnected => networkAdapter.IsConnected;

/// <summary>
/// Gets the total time the network has been down.
/// </summary>
public TimeSpan DownTime { get; private set; }
public TimeSpan DownTime => lastDown == null ? TimeSpan.Zero : DateTime.UtcNow - lastDown.Value;

/// <summary>
/// Gets the period for triggering network down events.
/// </summary>
public TimeSpan DownEventPeriod { get; private set; }

public TimeSpan DownEventPeriod { get; } = TimeSpan.FromSeconds(30);
/// <summary>
/// Initializes a new instance of the <see cref="NetworkController"/> class.
/// </summary>
Expand Down Expand Up @@ -150,6 +151,9 @@ private async Task ReportWiFiScan(IWiFiNetworkAdapter wifi)

private void OnNetworkConnected(INetworkAdapter sender, NetworkConnectionEventArgs args)
{
Resolver.Log.Info("Add UdpLogger");
Resolver.Log.AddProvider(new UdpLogger(/*port = */5100));

if (sender is IWiFiNetworkAdapter wifi)
{
_ = ReportWiFiScan(wifi);
Expand Down
1 change: 1 addition & 0 deletions Source/Meadow.Clima/Controllers/NotificationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public NotificationController(IRgbPwmLed? rgbLed)
/// <param name="status">The system status to set.</param>
public void SetSystemStatus(SystemStatus status)
{
Resolver.Log.Info($"SetSystemStatus = {status}");
switch (status)
{
case SystemStatus.LowPower:
Expand Down
35 changes: 28 additions & 7 deletions Source/Meadow.Clima/Controllers/PowerController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class PowerController
/// <summary>
/// Gets the interval at which power data is updated.
/// </summary>
public TimeSpan UpdateInterval { get; } = TimeSpan.FromSeconds(5);
public TimeSpan UpdateInterval { get; private set; } = TimeSpan.FromSeconds(10);

/// <summary>
/// Gets the voltage level below which a battery warning is issued.
Expand All @@ -59,12 +59,35 @@ public class PowerController
public PowerController(IClimaHardware clima)
{
this.clima = clima;
}

/// <summary>
/// Remove event handler and stop updating
/// </summary>
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()
/// <summary>
/// Add event handler and start updating
/// </summary>
/// <param name="powerControllerUpdateInterval"></param>
public void StartUpdating(TimeSpan powerControllerUpdateInterval)
{
UpdateInterval = powerControllerUpdateInterval;

if (clima.SolarVoltageInput is { } solarVoltage)
{
solarVoltage.Updated += SolarVoltageUpdated;
Expand All @@ -84,13 +107,11 @@ private void Initialize()
/// <returns>A task that represents the asynchronous operation. The task result contains the power data.</returns>
public Task<PowerData> GetPowerData()
{
var data = new PowerData
return Task.FromResult(new PowerData
{
BatteryVoltage = clima.BatteryVoltageInput?.Voltage ?? null,
SolarVoltage = clima.SolarVoltageInput?.Voltage ?? null,
};

return new Task<PowerData>(() => data);
});
}

/// <summary>
Expand Down
71 changes: 69 additions & 2 deletions Source/Meadow.Clima/Controllers/SensorController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Meadow.Devices.Clima.Controllers;
/// </summary>
public class SensorController
{
private readonly IClimaHardware clima;
private readonly CircularBuffer<Azimuth> windVaneBuffer = new CircularBuffer<Azimuth>(12);
private readonly SensorData latestData;

Expand All @@ -22,7 +23,7 @@ public class SensorController
/// <summary>
/// Gets the interval at which sensor data is updated.
/// </summary>
public TimeSpan UpdateInterval { get; } = TimeSpan.FromSeconds(15);
public TimeSpan UpdateInterval { get; private set; } = TimeSpan.FromSeconds(15);

/// <summary>
/// Initializes a new instance of the <see cref="SensorController"/> class.
Expand All @@ -31,6 +32,67 @@ public class SensorController
public SensorController(IClimaHardware clima)
{
latestData = new SensorData();
this.clima = clima;
}

/// <summary>
/// Stop the update events and remove event handler.
/// </summary>
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();
}
}

/// <summary>
/// Add event handlers and start updating
/// </summary>
/// <param name="updateInterval"></param>
public void StartUpdating(TimeSpan updateInterval)
{
UpdateInterval = updateInterval;

if (clima.TemperatureSensor is { } temperatureSensor)
{
Expand Down Expand Up @@ -135,10 +197,15 @@ private void AnemometerUpdated(object sender, IChangeResult<Speed> e)
{
lock (latestData)
{
latestData.WindSpeed = e.New;
// sanity check on windspeed to avoid reporting Infinity
if (e.New.KilometersPerHour <= 250)
{
latestData.WindSpeed = e.New;
}
}

Resolver.Log.InfoIf(LogSensorData, $"Anemometer: {e.New.MetersPerSecond:0.#} m/s");
Resolver.Log.InfoIf(LogSensorData, $"Anemometer: {e.New.KilometersPerHour:0.#} km/hr");
}

private void RainGaugeUpdated(object sender, IChangeResult<Length> e)
Expand Down
Loading
Loading