- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 02-12-2024 08:27 AM
In my previous article, I introduced the IT Operation Management product in an unusual way. I promised to also share the technical details of the solution.
Before we jump into the details, I would shortly summarise the topic of the previously mentioned article:
I have built a Lego vehicle, which can be controlled via Bluetooth (BLE-API), using Lego Boost MoveHub. Then I configured ServiceNow in order to control the vehicle, based on the capabilities of Discovery, Service Mapping and Event Management. If you haven't read this article yet, I highly recommend starting with that.
I am going to introduce the implementation steps, touching on the following topics:
- Lego Vehicle control via BLE-API
- RESTFul WebService implementation
- Color sensor and SNMP trap
- CMDB setup
- Discovery configuration
- Service Mapping configuration
- Event Management configuration
Lego Boost MoveHub
The first milestone was to implement a solution, which can be used to control the Lego vehicle via Bluetooth (BLE - Bluetooth Low Energy). I used the Lego Boost MoveHub for this purpose.
Lego has released a documentation about its wireless BLE protocol. This is a massive documentation, so I finally decided to look for available implementations on the Internet. I found multiple ones, tested them and I selected a Javascript module, called node-poweredup. This one is quite well documented and can be used easily. It contains several types of useful API calls, which I decided to use in order to control the vehicle.
Bluetooth connection
The first challenge was to establish the BLE connection between my laptop and the MoveHub using a NodeJs application. There is a Javascript module, called bluetooth-hci-socket, which can be used for this purpose. Linux and MacOS operating systems can handle it well, but I have Windows on my laptop, so I had to do a small trick, changing the Bluetooth driver to a special one. There is a tool for this purpose, called Zadig.
There was another challenge, because my laptop is an older one, so the base source code of bluetooth-hci-socket did not contain the USB ID of my Bluetooth device. I had to add some enhancements to fix the issue. As you can see on the image above, the tool shows the USB ID, which I added to the original source code, into the following file: bluetooth-hci-socket/lib/usb.js
...
if (process.env.BLUETOOTH_HCI_SOCKET_USB_VID && process.env.BLUETOOTH_HCI_SOCKET_USB_PID) {
var usbVid = parseInt(process.env.BLUETOOTH_HCI_SOCKET_USB_VID);
var usbPid = parseInt(process.env.BLUETOOTH_HCI_SOCKET_USB_PID);
debug('using USB VID = ' + usbVid + ', PID = ' + usbPid);
if (process.env.BLUETOOTH_HCI_SOCKET_USB_BUS
&& process.env.BLUETOOTH_HCI_SOCKET_USB_ADDRESS) {
var usbBus = parseInt(process.env.BLUETOOTH_HCI_SOCKET_USB_BUS);
var usbAddress = parseInt(process.env.BLUETOOTH_HCI_SOCKET_USB_ADDRESS);
debug('using USB BUS = ' + usbBus + ', Address = ' + usbAddress);
var usbDevices = usb.getDeviceList();
for (var i = 0; i < usbDevices.length; i++) {
var usbDeviceDesc = usbDevices[i].deviceDescriptor;
if ((usbDeviceDesc.idVendor == usbVid) &&
(usbDeviceDesc.idProduct == usbPid) &&
(usbDevices[i].busNumber == usbBus) &&
(usbDevices[i].deviceAddress == usbAddress)) {
this._usbDevice = usbDevices[i];
}
}
} else {
this._usbDevice = usb.findByIds(usbVid, usbPid);
}
} else {
this._usbDevice = usb.findByIds(0x0a5c, 0x21e8) ||
usb.findByIds(0x19ff, 0x0239) ||
usb.findByIds(0x0a12, 0x0001) ||
usb.findByIds(0x0b05, 0x17cb) ||
usb.findByIds(0x8087, 0x07dc ||
/* MOD AV - custom BLE Driver */ usb.findByIds(0x8087, 0x0a2a));
}
if (!this._usbDevice) {
throw new Error('No compatible USB Bluetooth 4.0 device found!');
}
...
The NodeJS application was able to identify my laptop's Bluetooth device after this modification, so I could execute the sample code of node-poweredup module to check how it works.
Lego wireless control via Bluetooth
Based on the example source code and the documentation, I could test all the commands, which I planned to use in order to control the vehicle:
- Go Forward
- Stop
- Turn
- Reading data from Color & Distance sensor
The following example shows the code of starting the vehicle and moving forward for a pre-defined time-frame.
async startMoving(activeTimeInSec, speed, waitResponse) {
const activeTimeInMS = activeTimeInSec * 1000;
this.motorA.setSpeed(speed, activeTimeInMS);
if (waitResponse) {
await this.motorB.setSpeed(speed, activeTimeInMS);
}
else {
this.motorB.setSpeed(speed, activeTimeInMS);
}
}
The MoveHub has two motors (motor A and B), which have to be controlled separately.
Implementing RESTFul Web Service
Once I could execute all planned commands, I had to implement a kind of remote controller. I used RESTFul Web service for this purpose. I created some HTTP endpoints in order to send commands to MoveHub from any type of web client.
For creating a RESTFul Web service, I used the express NodeJs web application framework. The following source code snippet is the HTTP endpoint, which can be used to start the vehicle moving forwards or backwards:
...
app = express();
...
this.app.get('/go/:time/:speed/:direction', async (req, res) => {
this.legoApi.movingForward = req.params.direction == "forward";
let speed: number = Number(req.params.speed);
await this.legoApi.startMoving(req.params.time, req.params.direction == "forward" ? (speed) : (-1 * speed), false);
res.setHeader('content-type', 'application/JSON');
res.send({ result: "command was executed" });
});
All the requests are similar to the example shown above. The implementation of the turning of the vehicle was somewhat difficult, because I had to calculate the turning angle based on the speed of the motor and the size of the "wheel". (In the case of a tracked vehicle one side goes forwards the other side goes backwards).
In addition to the control operations, I also created a special endpoint, which provides information about the connected device in JSON format:
{
"uuid":"001653ad6b1f",
"address":"00:16:53:ad:6b:1f",
"localName":"LEGO Move Hub"
}
I will detail the importance of this HTTP endpoint in the Discovery chapter.
Color sensor and SNMP trap
Color sensor
Getting data from the Color sensor is a simple operation. Once the connection is established between MoveHub and the manager application and the sensor is activated, it starts sending information. This information is coming from the MoveHub as an asynchronous event, which the application has to subscribe to.
The code snippet below is an example to read the incoming information about sensed colors:
...
await hub.connect();
...
hub.on("color", (device, { color }) => {
// Color processing
});
The color sensor sends a lot of data in a very short time, so I had to 'slow it down' a bit. I used a kind of queue-ing solution because of three reasons:
- avoid sending the same information multiple times in a short duration
- ensuring that data sending to ServiceNow will happen in the right sequence
- ServiceNow is not able to react to a message fast, so I wanted to avoid incorrect data processing
At this point, I was able to read the colors from the sensor and process them. The next step was to create an SNMP trap and send it to ServiceNow.
SNMP trap
I used the net-snmp Javascript module for creating and sending SNMP trap to ServiceNow. As I wrote in the previous article I used the ENTITY-MIB because this is a known library. Sending an SNMP trap is quite easy, there are three pre-requirements:
- Need to establish a MID server
- Need to define an SNMP trap listener (It can be done easily, just need to follow the description on ServiceNow docs).
- Need to send a well formatted message via UDP port
The code snippet below shows how I used net-snmp JS module to send SNMP trap to ServiceNow:
...
this.snmpSession = snmp.createSession(LISTENER_IP, "public", {
port: 1162
});
let varbinds: any = [{
oid: "1.3.6.1.2.1.47.1.1.1.1.7", // PhysicalName
type: snmp.ObjectType.OctetString,
value: vehicleAddress
},
{
oid: "1.3.6.1.2.1.47.1.1.1.1.13", // PhysicalModelName
type: snmp.ObjectType.OctetString,
value: "LEGO Move Hub"
},
{
oid: "1.3.6.1.2.1.47.1.1.1.1.2",
type: snmp.ObjectType.OctetString,
value: color
},
{
oid: "1.3.6.1.2.1.47.1.1.1.1.2", // PhysicalDescription is used for threshold management
type: snmp.ObjectType.OctetString,
value: (color == "green" ? "300" : "100")
},
{
oid: "1.3.6.1.2.1.47.1.1.1.1.5", // PhysicalClass
type: snmp.ObjectType.Integer,
value: 8
},
{
oid: "1.3.6.1.2.1.47.1.1.1.1.8",
type: snmp.ObjectType.OctetString,
value: color == "red" ? "critical" : (color == "blue" ? "major" : "none")
}
];
// version 2c should have been specified when creating the session
let oid: string = "1.3.6.1.2.1.47";
this.snmpSession.trap(oid, varbinds, function(error) {
if (error)
console.error(error);
});
Emergency stop logic
As the last topic of Lego MoveHub implementation part is the emergency stop. Once the color sensor receives the color red, the the application calls a function which stops the vehicle. During the different use-case testing I recognised, that ServiceNow needs some time to process messages coming from the MoveHub. To make the demonstration more attractive, I added a delay of a few seconds between the detection of the red signal and the application sending the stop command to the MoveHub.
Configuration steps on ServiceNow side
CMDB setup
The Lego MoveHub and the RESTFul Web service are ready to be used and need to be stored in CMDB in order for Event management to be able to control them. I defined two additional CI classes in ServiceNow:
- LEGO MoveHUB ➡️ This is a physical Hardware, inherited from Configuration Item (cmdb_ci)
- Lego Vehicle Manager ➡️ This is a Software, inherited from Application (cmdb_ci_appl)
I used CMDB CI Class Manager for creating the tables, because it provides one layout for managing and organising Configuration Items and the related data rules. Furthermore, it provides an easy-to-understand layout for the quick management of CMDB. I used this tool for defining the tables, columns, identification rules and the CI class icons. I wanted to add my icons to the CI classes, so I followed a description which is available on the Community. The result can be seen on the image below:
Discovery configuration
The CMDB enhancement is ready, the next step is to fill the tables with data. I used Process classification based on a horizontal pattern probe in order to discover the Web Service and the MoveHub.
First I had to create the filter condition to find the NodeJS process on the host, which makes the Web Service available.
Then, I created a new Horizontal Discovery pattern and related it to the Process Classification record.
The pattern has to contain at least one element in the Identification Section. This element defines the steps which are executed during the process.
I defined five steps for gathering all the necessary information from the Web Service, MoveHub and storing them in CMDB.
1. Step: This simply checks if the process is a NodeJs one. Otherwise, the operation is terminated.
2. Step: This step executes an HTTP GET request for collecting the connected Lego MoveHub details. Here I would refer back to the chapter about Web Service, where I wrote, that I implemented an end-point to get information from the MoveHub in order to be able identify it.
3. Step, 4. Step: The next two steps are about storing the gathered data into the corresponding tables in CMDB:
5. Step: The last step is responsible for creating the relationship between Vehicle Manager and MoveHub.
Once I was done, I tested all the steps using the debug capability of Pattern designer. Finally I saved and published the pattern. Afterwards I executed a quick discovery process. The result can be seen on the image below:
The discovery process is done the next phase is the Service Mapping.
Service Mapping configuration
If you read my previous article, you remember that I decided to use the Tag-based Service Mapping. I spent a lot of time figuring out the best solution for creating the Service Map. The goal was to create a CI structure, which accurately represents reality. This is the configuration I came up with.
Configuration steps
As its name suggests, this mapping type is based on CI related Tag(s), so as a first step I had to define a CI Tag category and CI Tag key element. This key will be related to all CIs and used for building the service.
The next step was creating a new Tag-based service family record to define how to correlate the selected tag values to each other and create a Service Map.
I didn't want to add the Tag manually to the CIs, so I created a Pattern Post script which does this operation during the Discovery process.
Let me give a short explanation to the script above. The logic is simple. The payload.items variable is an array, which contains data from all discovered CIs. The script iterates through these CI elements and if necessary creates a new Tag.
I executed the discovery again and the new Tag records were created and related to the corresponding CIs.
I opened again the Tag-based service family record and I clicked Manually update candidates and then, View service candidates UI actions.
A modal window appeared where I could select the corresponding service candidate and clicked the Map selected button. The result of these steps was that the new Application Service was generated in the system and related to the Mapped Services section of the Tag-based service family record.
I clicked the View map link and checked the generated Service Map. It looked like how I expected it to. The service is related directly to the Remote Manager, which is running on a computer and manages the Lego MoveHub.
The service configuration is done and ready to be managed by the Event Management.
Event Management configuration
So we have a Lego vehicle, which can be controlled via a Web Service. The RESTFul API is hosted by a NodeJS Express Web application Framework. The vehicle remote management software is able to get and process information from the color sensor and send SNMP traps to ServiceNow via the configured SNMP listener. Furthermore the CMDB configuration is also done and the Service Map is ready to be used.
The OOTB behaviour of SNMP listener is the following:
When a trap is sent to ServiceNow, an Event is created into the em_event table. This is the first point where we have to decide that the Event is a valid one or it can be correlated.
Event rules can be used for making decisions about incoming events. I created a new one with the following settings:
- a filter definition so that the rule is evaluated only in my specific case
- a field transformation definition to use and store the corresponding data from the event
- threshold for correlating noises
- a data binding in order for ServiceNow to be able to identify the correct CI
If the conditions match, the system generates an Alert. I created two Alert Management rules, one for the Critical, and another one for the Major alert handling.
Critical alert handler
This alert handler is executed when the Alert's Severity is Critical. I added some additional filter conditions, which can be seen on the image below:
If the conditions match, three different actions can be used:
- Executing one or multiple Remediation Subflows
- Executing one or multiple Remediation Workflows (This action is marked as a deprecated action by ServiceNow, the recommendation is using Subflows instead of this.)
- Launching a web application
In this use-case I used an OOTB available Subflow for creating an ITSM Incident.
Major alert handling
This alert handler is executed when the Alert's Severity is Major. It is very similar to the previous one.
In this case I used a custom Subflow, which controls the vehicle and finally closes the Alert.
Custom remediation flow
The purpose of the custom remediation flow is to stop the vehicle and turn it back, afterwards close the Alert. I created some Flow actions, which contain a REST step in order to send commands to the Lego vehicle via Lego Remote Manager RESTFul API. I used these actions in the Subflow definition. As a final step, I added the Close Alert Subflow (which is an OOTB one) to the process definition.
ServiceNow gives an easy way to call REST APIs from Flow Designer, it is called REST step. This action is not available if one of the IntegrationHub plugins is not installed. The configuration, which I used, can be seen on the following image.
In order to see real time information on the Service Map, I clicked the Monitor Service button. After this step I could follow the events on the Map in real time, which I demonstrated in the videos in the previous article.
Final thoughts
This was a great opportunity to try a lot of capabilities of ServiceNow, test them, and introduce the IT Operation Management core features in a unique way. There were several challenges during the implementation. One time I accidentally upgraded the firmware of MoveHub, which caused a lot of headache for me 🙂.
The question may arise, was the time invested worth it? Well, if these two articles give motivation to people to try something new, or to help them understand how ITOM works, I would say yes, it was worth it.
If you have comments or suggested improvements on this topic, please feel free to share them with the community.
I know this was a quite long article, thank you for reading, I hope you enjoyed it 🙂.
- 1,501 Views

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Wow! Thank you for writing such a detailed article and sharing with the community! Great work!
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thank you for sharing the details. This was much awaited one after your initial one!!