In this section you will learn how to control Arm Virtual Hardware via the AVH API . This can be used stand-alone, or as part of your overall CI/CD workflow.
Applications to interface with the API can be written in JavaScript, Python, or C. This example uses JavaScript.
You shall extend the workflow from the previous section to automatically transmit the chip-tool
commands.
In either Arm Virtual Hardware
browser, navigate to Profile
> API
.
Generate and copy your API Token
. This is a unique key that enables remote access to your instance(s).
In the GitHub browser, go to your forked repository, and navigate to Settings
> Secrets
> Actions
.
Create a New repository secret
. Name the secret:
API_TOKEN
Paste the above API Token
as the secret value.
The secret name must be exactly API_TOKEN
, as this is used by the workflow later.
In the lighting-app
instance console, edit the previously created workflow.
cd ~/connectedhomeip
nano .github/workflows/cicd_demo.yml
Append this job
to the file:
chip_tool:
needs: rebuild_lighting_app
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node
uses: actions/setup-node@aa759c6c94d3800c55b8601f21ba4b2371704cb7
- name: Install AVH API and Websocket
run: npm install @arm-avh/avh-api websocket --save
- name: Run script
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
run: node .github/workflows/chip_tool.js
Save and exit.
This job invokes the following JavaScript
which will transmit the on/off
commands to the chip-tool
instance via the Websocket
interface.
Create a script:
nano .github/workflows/chip_tool.js
containing the below:
const readline = require('readline')
const { ArmApi, ApiClient } = require('@arm-avh/avh-api');
const W3CWebSocket = require('websocket').w3cwebsocket;
const BearerAuth = ApiClient.instance.authentications['BearerAuth']
const api = new ArmApi()
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
async function main() {
console.log('Logging in...');
const apiToken = process.env.API_TOKEN
const authInfo = await api.v1AuthLogin({ apiToken });
BearerAuth.accessToken = authInfo.token
console.log("Locate instance named chip-tool...");
console.log("[User must edit JavaScript if instance has different name (or >10000 instances)]");
let instances = await api.v1GetInstances()
for(let i=0; i<10000; i++){
var instance = instances[i];
if (instance.name == "chip-tool") break;
}
console.log("Open Websocket...");
let url = await api.v1GetInstanceConsole(instance.id);
var mySocket = await new W3CWebSocket(url.url);
mySocket.onopen = function() {
console.log(`WebSocket open.`);};
mySocket.onerror = function() {
console.log('WebSocket Connection Error.')};
// Log in - comment the lines below if user has already logged in using the UI console
mySocket.send("pi\n");
await delay(1000);
mySocket.send("raspberry\n");
await delay(1000);
console.log("Wait 60s to ensure lighting-app is initialized...");
await delay(60000);
console.log("Turn light on...");
mySocket.send("/home/pi/connectedhomeip/examples/chip-tool/out/debug/chip-tool onoff on 0x11 1\n");
console.log("Wait 5 seconds...");
await delay(5000);
console.log("Turn light off...");
mySocket.send("/home/pi/connectedhomeip/examples/chip-tool/out/debug/chip-tool onoff off 0x11 1\n");
console.log("Wait 5 seconds...");
await delay(5000);
console.log("Turn light on again...");
mySocket.send("/home/pi/connectedhomeip/examples/chip-tool/out/debug/chip-tool onoff on 0x11 1\n");
console.log("Wait 5 seconds...");
await delay(5000);
console.log("Turn light off again...");
mySocket.send("/home/pi/connectedhomeip/examples/chip-tool/out/debug/chip-tool onoff off 0x11 1\n");
console.log("Wait 5 seconds...");
await delay(5000);
console.log('Closing WebSocket...');
mySocket.close();
mySocket.onclose = function() {
console.log(`WebSocket closed.`);};
mySocket.onerror = function() {
console.log('WebSocket Error.')};
return;
}
main().catch((err) => {
console.error(err);
});
Note that the JavaScript refers to instance name chip-tool
, and API_TOKEN
secret. The job
refers to the script chip_tool.js
, as well as the API_TOKEN
secret. If these were named differently, you will need to update the script(s) appropriately.
When all edits are complete, push the changes back to GitHub:
cd ~/connectedhomeip
git add .
git commit -m "added chip-tool automation"
git push
You will again be prompted for your GitHub username and Personal Access Token (password).
A new run of the Action will be triggered.
Navigate to the Actions
tab of your GitHub repository, and open the current workflow to follow progress. Observe that there are now three jobs
, with the jobs to run lighting-app
and chip-tool
executing in parallel. You can follow progress in GitHub Actions log, and observe chip-tool
toggling lighting-app
automatically. You will also see the commands appear in the chip-tool
console.
Congratulations! You have entirely automated the process to build and test your applications.
You have built up a rudimentary CI/CD environment to start Matter
development. Through the powerful AVH API and workflow methodology of GitHub Actions and other similar technologies, it is possible to construct an intelligent and always available CI/CD scheme, instantiating (and terminating) Virtual Hardware targets as required for your unit tests in a highly scalable way.