Skip to content

Commit

Permalink
Merge pull request #82 from WildernessLabs/feature/app-features
Browse files Browse the repository at this point in the history
Feature/app features
  • Loading branch information
ctacke authored Jun 6, 2024
2 parents f0d2634 + 74ef1b6 commit 9f37036
Show file tree
Hide file tree
Showing 16 changed files with 491 additions and 52 deletions.
59 changes: 53 additions & 6 deletions Source/Clima_Demo/MeadowApp.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Meadow;
using Meadow.Devices;
using Meadow.Devices.Esp32.MessagePayloads;
using Meadow.Hardware;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Clima_Demo;
Expand All @@ -15,16 +15,63 @@ public MeadowApp()
mainController = new MainController();
}

public override void OnBootFromCrash(IEnumerable<string> crashReports)
{
mainController.LogAppStartupAfterCrash(crashReports);
}

public override Task Initialize()
{
var reliabilityService = Resolver.Services.Get<IReliabilityService>();
reliabilityService!.MeadowSystemError += OnMeadowSystemError;
if (reliabilityService.LastBootWasFromCrash)
{
mainController.LogAppStartupAfterCrash(reliabilityService.GetCrashData());
reliabilityService.ClearCrashData();
}

var wifi = Device.NetworkAdapters.Primary<IWiFiNetworkAdapter>();
mainController.Initialize(Clima.Create(), wifi);

return Task.CompletedTask;
}

private void OnMeadowSystemError(MeadowSystemErrorInfo error, bool recommendReset, out bool forceReset)
{
if (error is Esp32SystemErrorInfo espError)
{
Resolver.Log.Warn($"The ESP32 has had an error ({espError.StatusCode}).");
}
else
{
Resolver.Log.Info($"We've had a system error: {error}");
}

if (recommendReset)
{
Resolver.Log.Warn($"Meadow is recommending a device reset");
}

forceReset = recommendReset;

// override the reset recommendation
//forceReset = false;
}

private void OnMeadowSystemError(object sender, MeadowSystemErrorInfo e)
{
Resolver.Log.Error($"App has detected a system error: {e.Message}");
if (e is Esp32SystemErrorInfo esp)
{
Resolver.Log.Error($"ESP function: {esp.Function}");
Resolver.Log.Error($"ESP status code: {esp.StatusCode}");
}
if (e.Exception != null)
{
Resolver.Log.Error($"Exception: {e.Exception.Message}");
Resolver.Log.Error($"ErrorNumber: {e.ErrorNumber}");
Resolver.Log.Error($"HResult: {e.Exception.HResult}");

if (e.Exception.InnerException != null)
{
Resolver.Log.Error($"InnerException: {e.Exception.InnerException.Message}");
Resolver.Log.Error($"HResult: {e.Exception.InnerException.HResult}");
}
}
}
}
6 changes: 3 additions & 3 deletions Source/Clima_Demo/meadow.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
Name: Clima

Coprocessor:
AutomaticallyStartNetwork: true
AutomaticallyReconnect: true
MaximumRetryCount: 7
AutomaticallyStartNetwork: false
AutomaticallyReconnect: false
MaximumRetryCount: 0

Network:
DefaultInterface: WiFi
Expand Down
27 changes: 27 additions & 0 deletions Source/Clima_Demo/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
```mermaid
flowchart TD
%% Nodes
A("Boot")
B{"Connect to Cloud"}
C("Deliver Data")
D("Shutdown network")
E("Device Sleep")
F("Device Wake")
G("Collect Telemetry")
H{{"`tick++ % pubcount`"}}
ne_0("== 0")
eq_0("!= 0")
%% Edge connections between nodes
A --> B
B --> yes --> C
B --> no --> E
C --> D
D --> E
E -.-> F
F --> G
G --> H
H --> eq_0 --> E
H --> ne_0 --> B
```
15 changes: 15 additions & 0 deletions Source/Meadow.Clima.sln
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "CommonContracts", "Addition
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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sensors.Light.Veml7700", "..\..\Meadow.Foundation\Source\Meadow.Foundation.Peripherals\Sensors.Light.Veml7700\Driver\Sensors.Light.Veml7700.csproj", "{C5925D96-F9F4-4F42-AC8D-97E464252A4D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -502,6 +504,18 @@ 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
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Debug|iPhone.Build.0 = Debug|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Release|Any CPU.Build.0 = Release|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Release|iPhone.ActiveCfg = Release|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Release|iPhone.Build.0 = Release|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{C5925D96-F9F4-4F42-AC8D-97E464252A4D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -532,6 +546,7 @@ Global
{494082D7-2C48-45A6-8FF7-DD553D27BC4A} = {4AB0FC09-05D2-4F55-9C2D-13C133456E2F}
{567267B3-ED96-4FEA-B555-2EE203372EA4} = {4AB0FC09-05D2-4F55-9C2D-13C133456E2F}
{6300EAB4-806F-4C18-8FE0-57C45A2C0C58} = {2889A476-F914-49E8-9F97-4CC6CA34A901}
{C5925D96-F9F4-4F42-AC8D-97E464252A4D} = {2889A476-F914-49E8-9F97-4CC6CA34A901}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CA61E123-F783-4CB3-8EB2-099EE930ADD4}
Expand Down
4 changes: 3 additions & 1 deletion Source/Meadow.Clima/Clima.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ public static IClimaHardware Create()
logger?.Info("Failed to instantiate version MCP23008");
}

if (version > 4)
logger?.Info($"MCP Version: {version}");

if (version >= 4)
{
logger?.Info("Instantiating Clima v4 specific hardware");
hardware = new ClimaHardwareV4(ccm, i2cBus, mcpVersion!);
Expand Down
12 changes: 12 additions & 0 deletions Source/Meadow.Clima/Controllers/CloudController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,23 @@
using Meadow.Cloud;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace Clima_Demo;

public class CloudController
{
public async Task WaitForDataToSend()
{
// TODO: add a timeout here
while (Resolver.MeadowCloudService.QueueCount > 0)
{
// Resolver.Log.Info($"Waiting for {Resolver.MeadowCloudService.QueueCount} items to be delivered...");
await Task.Delay(1000);
}
Resolver.Log.Info($"All cloud data has been sent");
}

public void LogAppStartupAfterCrash()
{
SendEvent(CloudEventIds.DeviceStarted, $"Device restarted after crash");
Expand Down
74 changes: 74 additions & 0 deletions Source/Meadow.Clima/Controllers/NetworkController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Meadow.Hardware;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Meadow.Devices;

Expand All @@ -19,6 +20,16 @@ public class NetworkController

public NetworkController(INetworkAdapter networkAdapter)
{
if (networkAdapter is IWiFiNetworkAdapter wifi)
{
if (wifi.IsConnected)
{
_ = ReportWiFiScan(wifi);
}

// TODO: make this configurable
wifi.SetAntenna(AntennaType.External);
}
this.networkAdapter = networkAdapter;

networkAdapter.NetworkConnected += OnNetworkConnected;
Expand All @@ -27,6 +38,39 @@ public NetworkController(INetworkAdapter networkAdapter)
downEventTimer = new Timer(DownEventTimerProc, null, -1, -1);
}

public async Task<bool> ConnectToCloud()
{
if (networkAdapter is IWiFiNetworkAdapter wifi)
{
if (!wifi.IsConnected)
{
Resolver.Log.Info("Connecting to network...");
await wifi.Connect("interwebs", "1234567890");
}
}

Resolver.Log.Info($"Connecting to network {(networkAdapter.IsConnected ? "succeeded" : "FAILED")}");

return networkAdapter.IsConnected;
}

public async Task ShutdownNetwork()
{
if (networkAdapter is IWiFiNetworkAdapter wifi)
{
Resolver.Log.Info("Disconnecting network...");
try
{
await wifi.Disconnect(true);
Resolver.Log.Info("Network disconnected");
}
catch (Exception ex)
{
Resolver.Log.Info($"Network disconnect failed: {ex.Message}");
}
}
}

private void DownEventTimerProc(object _)
{
if (networkAdapter.IsConnected)
Expand All @@ -46,8 +90,38 @@ private void OnNetworkDisconnected(INetworkAdapter sender, NetworkDisconnectionE
ConnectionStateChanged?.Invoke(this, false);
}

private async Task ReportWiFiScan(IWiFiNetworkAdapter wifi)
{
var networks = await wifi.Scan();

Resolver.Log.Info("WiFi Scan Results");
if (networks.Count == 0)
{
Resolver.Log.Info("No networks found");
}
else
{
foreach (var network in networks)
{
if (string.IsNullOrEmpty(network.Ssid))
{
Resolver.Log.Info($"[no ssid]: {network.SignalDbStrength}dB");
}
else
{
Resolver.Log.Info($"{network.Ssid}: {network.SignalDbStrength}dB");
}
}
}
}

private void OnNetworkConnected(INetworkAdapter sender, NetworkConnectionEventArgs args)
{
if (sender is IWiFiNetworkAdapter wifi)
{
_ = ReportWiFiScan(wifi);
}

lastDown = null;
ConnectionStateChanged?.Invoke(this, true);
}
Expand Down
45 changes: 39 additions & 6 deletions Source/Meadow.Clima/Controllers/NotificationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ public enum Warnings
BatteryLow = 1 << 2,
}

public enum SystemStatus
{
LowPower,
Starting,
SearchingForNetwork,
NetworkConnected,
ConnectingToCloud,
Connected,

}

private readonly IRgbPwmLed? rgbLed;
private Warnings activeWarnings = Warnings.None;

Expand All @@ -22,14 +33,36 @@ public NotificationController(IRgbPwmLed? rgbLed)
this.rgbLed = rgbLed;
}

public void SystemStarting()
public void SetSystemStatus(SystemStatus status)
{
rgbLed?.SetColor(RgbLedColors.Red);
}
switch (status)
{
case SystemStatus.LowPower:
if (rgbLed != null)
{
rgbLed.StopAnimation();
rgbLed.IsOn = false;
}
break;
case SystemStatus.Starting:
rgbLed?.SetColor(RgbLedColors.Red);
break;
case SystemStatus.SearchingForNetwork:
rgbLed?.StartBlink(RgbLedColors.Red);
break;
case SystemStatus.NetworkConnected:
rgbLed?.StopAnimation();
rgbLed?.SetColor(RgbLedColors.Magenta);
break;
case SystemStatus.ConnectingToCloud:
rgbLed?.StartBlink(RgbLedColors.Cyan);
break;
case SystemStatus.Connected:
rgbLed?.StopAnimation();
rgbLed?.SetColor(RgbLedColors.Green);
break;

public void SystemUp()
{
ReportWarnings();
}
}

public void SetWarning(Warnings warning)
Expand Down
9 changes: 9 additions & 0 deletions Source/Meadow.Clima/Controllers/PowerController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ public async Task<PowerData> GetPowerData()
};
}

public void TimedSleep(TimeSpan duration)
{
Resolver.Log.Info("Going to sleep...");

Resolver.Device.PlatformOS.Sleep(duration);

Resolver.Log.Info("PowerController completed sleep");
}

private void SolarVoltageUpdated(object sender, IChangeResult<Voltage> e)
{
Resolver.Log.InfoIf(LogPowerData, $"Solar Voltage: {e.New.Volts:0.#} volts");
Expand Down
Loading

0 comments on commit 9f37036

Please sign in to comment.