Maple makes it easy to build connected devices with Meadow by exposing control via a Web API. Maple is an ultra-lightweight, JSON enabled, RESTful web server. It also has an advertise feature, meaning that you could discover Maple servers in your network by listening to UDP broadcast messages with its name and IP Address.
The Maple Web Server is primarily intended to provide RESTful endpoints from a device. It is modelled after ASP.NET Core and provides an easy to extend architecture with integrated JSON support via System.Text.Json.
Starting Maple on a Meadow board wont necesarily come with a display, so enabling Maple's discovery feature will broadcast the server's name along with its IP Address accross the network it joined to its easily discoverable by Maple Client's UDP listener built-in.
mapleServer = new MapleServer(
ipAddress: wifi.IpAddress,
port: 5417,
advertise: true); // <= Advertise Server over the network
mapleServer.Start();
A web API consists of one or more request handler classes that derive from RequestHandlerBase:
public class MyRequestHandler : RequestHandlerBase
Maple determines API call routing based on Attribute routing of handler methods.
Routing is supported to either absolute or relative paths.
If your route begins with a forward slash (/
) then it is considered an absolute route, and requests will be routed to the provided route regardless of the Handler class name.
For example, the following will respond to GET
requests to http://[meadow.address]/hello
public class MyRequestHandler : RequestHandlerBase
{
[HttpGet("/hello")]
public OkObjectResult Hello()
{ ... }
}
If your route does not begin with a forward slash (/
) then it is considered a relative route, and requests will be routed to the provided route prefixed with an appreviated RequestHandler
prefix. The route prefix is determined by using the class name and trimming off any "Requesthandler" suffix.
For example, the following will respond to GET
requests to http://[meadow.address]/my/hello
public class MyRequestHandler : RequestHandlerBase
{
[HttpGet("hello")]
public OkObjectResult Hello()
{ ... }
}
But the following will respond to GET
requests to http://[meadow.address]/webapi/hello
public class WebAPI : RequestHandlerBase
{
[HttpGet("hello")]
public OkObjectResult Hello()
{ ... }
}
NOTE: Maple supports only a single parameter in a Route.
Maple supports providing a handler method parameter through the route path. Parameters are delineated by curly braces, and the parameter name in the route must exactly match the parameter name in the handler method signature.
As an example, a GET
to the path http://[meadow.address]/orders/history/1234
would end up calling the following GetOrderHistory
handler method with a parameter value of 1234
:
public class OrdersRequestHandler : RequestHandlerBase
{
[HttpGet("history/{orderID}")]
public void GetOrderHistory(int orderID)
{
Debug.WriteLine($"{paramName}");
}
}
Supported parameter types are:
- Numerics (byte, short, int, long, float, double)
- bool
- string
- DateTime
- Guid
By default Maple will create a new instance of an API handler for every request received. If you want your application to reuse the same handler instance, which provides faster handler execution and decreases GC allocation, simply override the IsResuable
base property and return true
.
public override bool IsReusable => true;
It is recommended that all Handler methods return an IActionResult
implementation. Extension methods are provided by Maple for common return objects including, but not limited to, ActionResult
, JsonResult
, OkResult
and NotFoundResult
.
For example, the following will automatically serialize and return a JSON string array with the proper content-type
and return code.
[HttpGet("/JsonSample")]
public IActionResult GetJsonList()
{
var names = new List<string> {
"George",
"John",
"Thomas",
"Benjamin"
};
return new JsonResult(names);
}
Maple Client is a convenience library intended to easily discover Maple servers over the network with their advertise feature turned on, and also send GET/POST request seamlessly to control a peripheral like a servo, or get data logs from environmental sensors.
Its dependency is .NET Standard 2.0, so it compatible with all sorts of .NET mobile and desktop apps built using Xamarin, WPF and even MAUI.
When a Meadow application is running Maple with its broadcasting feature turned on, we can use Maple Client to easily find it over the network. This snippet shows how you would discover Maple servers from a mobile/desktop:
ObservableCollection<ServerModel> HostList = new ObservableCollection<ServerModel>();
.
.
MapleClient client = new MapleClient();
client.Servers.CollectionChanged += ServersCollectionChanged;
await client.StartScanningForAdvertisingServers();
.
.
void ServersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (ServerModel server in e.NewItems)
{
HostList.Add(new ServerModel() { Name = $"{server.Name} ({server.IpAddress})", IpAddress = server.IpAddress });
}
break;
}
}
You'll need a list of ServerModel
that has both Name
and IPAddress
fields, and once a MapleClient
object has been created, register the ServerCollectionChanged
event handler that is triggered everytime a Maple
server has been detected. Finally, call the StartScanningForAdvertisingServers
async method to start listening for Maple servers broadcasting its information over UDP.
To send HTTP requests to Maple, you could do it with the standard HttpClient, and do regular GET/POST requests just like any other web API. Maple Client has simplified, encapsulated methods to send request to Maple servers.
Sending a POST request, used to control peripherals on Meadow such as a servo, an LED, a relay, etc., will look something like this:
bool response = await client.PostAsync(IpAddress, ServerPort, "rotateservo", "90");
In this snippet above, we're calling the endpoint /RotateServo
, and a value of 90, which Meadow will interpret to make a servo rotate 90 degrees.
Sending a GET request, ideal to get information such as data logs from an environmental sensor, will look like this:
var response = await client.GetAsync(IpAddress, ServerPort, "gettemperaturelogs");
This example will return a string that could be in plain text, xml
or json
format, and depending in the format its up to the developer to interpret the response. Maybe use System.Text.Json
to deserialize a json
response, for example.
The following sample projects are using Maple to control a Meadow board using a MAUI application.
Control a RGB LED with Meadow and MAUI using REST Hackster | Source Code |
Control a Servo with Meadow and MAUI using REST Hackster | Source Code |
Get temperature logs with Meadow and MAUI using REST Hackster | Source Code |
Control a Project Lab board over Wi-Fi with a MAUI app Source Code |
Make your own OnAir sign with Meadow and a MAUI using REST Hackster | Source Code |
Get Weather data via Wi-Fi with a MAUI app and a Clima Kit Source Code |
|
|
|