MuleSoft IoT - Make Max Dance!
Darren Ingram
Posted on November 26, 2020
IoT and MuleSoft
Introduction
I have just started learning how to use MuleSoft at work, where we will be using it for integration between our various systems. I completed the Anypoint Platform Development: Fundamentals (Mule 4) self-paced training and then started on this project to help get some hands-on-experience.
So, disclaimer: I don't really know what I'm doing, so don't rely on this for anything :)
Muley (Max) the Mule
After attending a MuleSoft user group event, the organizer sent me a little Max the Mule squishy. My colleagues and I renamed him to Muley, and during our project planning, whenever we noted a potential use for MuleSoft Anypoint, I'd make Muley do a little dance. I found myself doing this a lot, and wondered "could I automate this?"
Project Goal
- Create a IoT device that controls a motor attached to Muley to make him "dance"
- Control the IoT device from a Web API
- Have some sort of trigger to make Muley dance
Implementation Overview
IoT
A few years ago I started tinkering with Arduino and other hobby electronics boards. I haven't touched any of that for a couple of years, but I went out to the garage and found my old box of goodies. In there was an unopened Particle Photon WiFi Development Board. This allows you to build a little device and then expose functions over HTTP.
I connected a servo motor to the Photon board and attached it to the bottom of Muley (using some very professional sticks and tape from my 8-year-old's art supplies!)
I also found a LED light ring in my box of tricks, so connected that, just because I could. I later made up a reason to use it...
I wrote the code to make the servo move around and to flash the lights. These were exposed as functions on the Photon. I used the Particle Web IDE to do this (as described in the getting started information for the Photon).
-
The full code is available on GitHub:
but here are the important parts that register the dance and setMood functions as cloud functions:
bool setMoodSuccess = Particle.function("setMood", setMood);
bool danceSuccess = Particle.function("dance", dance);
Particle Cloud Functions API
Using the documentation, I was able to figure out how to call the Particle API to trigger my functions using Postman. The screenshot below shows how I just had to POST to the function name and include my device's unique ID and an access token (both from my Particle account):
That call resulted in Muley doing a little dance (and was a very exciting moment for me :))
MuleSoft Anypoint
My next step was to use Anypoint to design and implement a System API to make calls to my cloud functions.
System API Design
I used the Anypoint Platform API Designer to build up my RAML API specification.
While designing the System API, I quickly noticed that both of the cloud functions had the same request and response types, so I created API Fragments for these to allow me to reuse them. I also had a ton of fun working on this project, so I am very likely to want to use these data types again in future tinkerings!
The screenshot below shows how I was able to reference the reusable API Fragments that I published to my own Exchange:
Muley IoT System API
#%RAML 1.0
baseUri: https://anypoint.mulesoft.com/mocking/api/v1/links/3bd0afd8-1b41-43b1-a034-2842d75a2211/ #
title: iot-muley-sapi
description: System API to call Particle Photon IoT Muley project
protocols:
- HTTP
- HTTPS
/mood:
post:
description: Set the lighting based on mood
body:
application/json:
type: !include ../exchange_modules/f355980a-ec00-4935-8944-f5f13d8b08ba/particle-iot-function-request/1.0.2/particle-iot-function-request-data-type.raml
example: !include examples/iot-muley-function-request-example.json
responses:
200:
body:
application/json:
type: !include ../exchange_modules/f355980a-ec00-4935-8944-f5f13d8b08ba/particle-iot-function-response-data-type/1.0.2/particle-iot-function-response-data-type.raml
example: !include examples/iot-muley-function-response-example.json
/dance:
post:
description: Make Muley dance
body:
application/json:
type: !include ../exchange_modules/f355980a-ec00-4935-8944-f5f13d8b08ba/particle-iot-function-request/1.0.2/particle-iot-function-request-data-type.raml
example: !include examples/iot-muley-function-request-example.json
responses:
200:
body:
application/json:
type: !include ../exchange_modules/f355980a-ec00-4935-8944-f5f13d8b08ba/particle-iot-function-response-data-type/1.0.2/particle-iot-function-response-data-type.raml
example: !include examples/iot-muley-function-response-example.json
Particle IoT Function Request
#%RAML 1.0 DataType
displayName: Particle IoT Function Request
description: Representation of the information required when making calls to particle.io functions
properties:
accessToken:
type: string
required: true
displayName: Access Token
example: 123456ABC
arg:
type: string
required: false
displayName: Argument
example: "extra data"
example: !include particle-iot-function-request-example.json
Particle IoT Function Response
#%RAML 1.0 DataType
displayName: Particle IoT Function Response
description: Representation of the information returned from a particle.io function call
properties:
id:
type: string
displayName: Id
example: "30002e000347353137323334"
connected:
type: boolean
displayName: Connected
example: true
return-value:
type: integer
displayName: "Return value"
example: 12
example: !include particle-iot-reponse-example.json
System API Implementation
In Anypoint Studio I pulled in my System API RAML from Exchange. It kindly scaffolded it all out for me and I went to work implementing my flows to make HTTP POST requests over to the Particle REST API.
I included a config.yaml file and used the Configuration Properties to connect to this:
This allowed me to access these configuration properties within my implementation flows:
Since I created the particle API request and response types, I didn't need to do any additional DataWeave mapping before making the http request.
Integration Process Flow Implementation
So now I had a Muley IoT System API to handle communications to my IoT device.
Next I needed to create a Flow that handled some trigger and made calls the System API.
I decided to use an email as the trigger. This would allow me to send emails to muley.max.mule@gmail.com and have Muley dance.
I was able to pull in the Muley IoT System API from Exchange and get the generated connectors (which was pretty cool!)
Because I wanted to use this experience to learn, I decided to add another integration in at this point. I wanted to make Muley react to the content of the email. For this I found the Monkey Learn Sentiment Analysis API. I setup a developer account which gave me an authorization token and a model Id. I used these in an HTTP Request connector to pass through the body of the email message and get back a sentiment (of "Positive", "Negative", "Neutral" - along with a bunch of other stuff like the certainty rating).
So my flow needed to do something like this:
- Trigger on a new email to muley.max.mule@gmail.com
- Pass the content of the email to the Sentiment Analysis API
- Map the result into the request required for the Muley IoT System API Set Mood call
- Call the Muley IoT System API Set Mood method
- Call the Muley IoT System API Dance method
As you can see, I went a bit extra and made use of the JMS Queue connector. When a new email arrives, I simply published to a JMS queue. I then made the rest of my integration flow trigger on a new message to the queue. I really did this just to practice using JMS queues, but it also sets me up to make "other things" happen when Muley gets an email, without having to keep updating this flow.
Here is how I mapped from the email message payload into the request expected by the sentiment analysis API:
And another example of Dataweave, this time mapping from the sentiment analysis response into request format for our System API:
%dw 2.0
output application/json
---
{
"mood": lower(payload[0].classifications[0].tag_name)
}
The Result
Here is the end result of this Hackathon project. If we send a positive email to Muley, then the lights flash green while he dances:
But if we send a negative email then the lights flash red:
Source Code
The IoT Particle source code and Anypoint .jar files are available on GitHub:
Posted on November 26, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.