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

Feature/app features #82

Merged
merged 9 commits into from
Jun 6, 2024
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
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
Loading