Ignition integration with Peplink Incontrol2 API

Hey Guys

Been playing around with Ignition for a week now and absolutely love it.
I’m looking to integrate API calls to Peplink’s InControl2

I can get the calls working on Postman for example

PUT or DELETE
URL - https://api.ic.peplink.com/rest/o/{organization_id}/g/{group_id}/device_tags
(Authentication token) ****************************
(body - raw data)
{data:
{device_ids:[1,10],
tag_names:[allowinternet]}
}

This call allows me to add or delete a tag (not a tag in Ignition) to a device in InControl2’s management which allows for rules to be acted upon e.g. firewall rules change to allow or block internet

Could someone please explain to me how to take a functioning call in Postman and integrate it into a tag in Ignition.
I have already tired following some examples but nothing seams to quite function.

Have a great day!

This thread should help you out
Connecting to Smart Home Devices - Maker - Inductive Automation Forum

Awesome, that’s a great one. Will work my way through it now

I use the same method for the API helper functions I am writing for Ecobee Smart Thermostats.

Peplink do provide a sample shell script.
I think it needs to be completely re-written in python to work in Ignition though.

#!/bin/bash

## Sample script for making IC2 API calls
## Revision 1.3
## Last modified: 2019-06-21
## By Billy Lau, Michael Chan

#
## Please input your InControl 2 OAuth client_id, client_secret and redirect_uri below
## You can optain a set of client ID and secret from your user profile page by clicking 
## your email address on the top of the InControl 2 screen, scrolling to the "Client 
## Application" section, clicking the "New Client" button, and filling in the form.
##
## For the redirect_uri, you may fill in http://www.peplink.com in the above form
## and the redirect_uri variable below
client_id=""
client_secret=""
redirect_uri=""

# For InControl 2, the api_server_prefix is https://api.ic.peplink.com.  
# For InControl appliances, this is https://{SERVER_NAME_HERE}.
api_server_prefix="https://api.ic.peplink.com"

# For InControl 2, set 1 to verify the API service's SSL certificate.
# For InControl appliances without a valid SSL certificate, set this to 0 to ignore the certificate validity.
verify_ssl_cert=1

################# Code for OAuth2 token handling goes below ##################
access_token_file="${HOME}/.access_token"
refresh_token_file="${HOME}/.refresh_token"
tmpfile="/tmp/ic2.tmpfile.$$"
# InControl token endpoint
ic2_token_url="${api_server_prefix}/api/oauth2/token"
# InControl authorization endpoint
ic2_auth_url="${api_server_prefix}/api/oauth2/auth?client_id=${client_id}&response_type=code"

if [ "${client_id}" == "" ] || [ "${client_secret}" == "" ] || [ "${redirect_uri}" == "" ]; then
	echo "Please edit this script and enter Client ID and Client Secret"
	exit 1
fi

# Check if jq has been installed
if ! command -v jq > /dev/null 2>&1 ; then
	echo "Error: Missing jq command."
	echo "Run \"apt install jq\" or \"yum install jq\" to install."
	exit 2
fi

if [ "$verify_ssl_cert" != "0" ]; then
	curl_opt=" -k "
else
	curl_opt=""
fi

function save_tokens() {
	result=$(cat)
	local -n access_token_tmp=$1
	local -n refresh_token_tmp=$2
	access_token_tmp=`echo "${result}"|jq -r .access_token`
	refresh_token_tmp=`echo "${result}"|jq -r .refresh_token`
	expires_in=`echo "${result}"|jq -r .expires_in`
	if [ "${access_token_tmp}" == "" ]; then
		echo "Unable to obtain an access token. Process aborted"
		echo "Returned: $result"
		exit 3
	fi
	# Save the access token and refresh token."
	echo ${access_token_tmp} > ${access_token_file}
	echo ${refresh_token_tmp} > ${refresh_token_file}
	# Set the files' last modified date to the tokens' expiry date
	touch -d @$(( $(date +%s) + expires_in )) ${access_token_file}
	touch -d @$(( $(date +%s) + expires_in + 30*60*60 )) ${refresh_token_file}
}

# If the access token file has not expired
if [ -f ${access_token_file} ] && [ $(stat -c %Y ${access_token_file}) -gt $(date +%s) ]; then
	access_token=$(cat ${access_token_file})
# If the access token is invalid but the refresh token has not expired, acquire new access and refresh tokens
elif [ -f ${refresh_token_file} ] && [ $(stat -c %Y ${refresh_token_file}) -gt $(date +%s) ]; then
	ic2_token_params="client_id=${client_id}&client_secret=${client_secret}&grant_type=refresh_token&refresh_token=$(cat ${refresh_token_file})"
	curl $curl_opt -so $tmpfile -X POST -d "$ic2_token_params" "${ic2_token_url}"
	if ! save_tokens access_token refresh_token < $tmpfile; then
		rm -f $tmpfile
		exit 4
	fi
else
	echo ""
	echo "Start a web browser, visit the following URL and follow the instructions."
	echo ""
	echo "${ic2_auth_url}"
	echo ""
	echo "You will be redirected to $redirect_uri?code=CODE_HERE."
	echo -n "Please enter the 'code' in the redirected URL here: "
	read code

	if [ "${code}" == "" ]; then
		echo "Error: The code is empty.  Process aborted"
		exit 5
	fi

	ic2_token_params="client_id=${client_id}&client_secret=${client_secret}&grant_type=authorization_code&code=${code}&redirect_uri=${redirect_uri}"

	## POST data to token endpoint
	curl $curl_opt -so $tmpfile --data "${ic2_token_params}" "${ic2_token_url}"
	if ! save_tokens access_token refresh_token < $tmpfile; then
		rm -f $tmpfile
		exit 6
	fi
fi
rm -f $tmpfile

##################################################################################
# Application code goes below.  This sample script firstly gets all accessible   #
# organizations. Then for each organization, print its name and list all groups' #
# name under it.                                                                 #
##################################################################################
echo ""
echo "Listing all accessible organizations' group names."
echo ""

curl $curl_opt -so $tmpfile "${api_server_prefix}/rest/o?access_token=${access_token}"
if grep -q Unauthorized $tmpfile ; then
	echo "The saved access token is invalid.  Rerun this script to obtain a new one"
	rm -f ${access_token_file}
	exit 7
fi

for org in $(jq -r '.data[] | @base64' $tmpfile); do
	org_name=$(echo $org |base64 --decode | jq -r '.name')
	org_id=$(echo $org |base64 --decode | jq -r '.id')
	echo "Groups under the organization: $org_name"
	curl $curl_opt -s "${api_server_prefix}/rest/o/$org_id/g?access_token=${access_token}" | \
		jq -r '.data[] | .name'
	echo ""
done
rm -f $tmpfile

Is there a simple way to convert this code or does it need to be completely re-written?

It needs to be re-written in my opinion. I would start with getting your tokens and saving them. To start you can save them into tags, then worry about securely storing them later. I have my API helper functions also save and monitor the expiration time of the token. Once expired I automatically refresh the tokens, so I never have to worry about an expired token during a call. Once you have that, it really isn’t that bad to convert a curl into a system.net.httpPost call.

If you need some more inspiration, when I have my API project finished, I will be posting it to Ignition Exchange where you can download it and use it as a guide.

You can call this shell script from Ignition using system.util.execute() but I don’t think it will do what you need it to this way.

So I can get the following working in postman and PyCharm as a PUT and DELETE but can not get it running in Ignition. Any ideas?

I have tried system.net.httpPut system.net.httpDelete but I keep getting error in the script consul. Any pointers on how to format the information below for it to function in the script editor?

import http.client

import json

conn = http.client.HTTPSConnection("api.ic.peplink.com")

payload = "{data:{device_ids:[31,32],tag_names:[(CREATE_THE_TAG_HERE)]}}"

headers = {

'Authorization': 'Bearer (REPLACE_WITH_BEARER_ID)',

'Content-Type': 'application/json',

'Cookie': 'JSESSIONID=(REPLACE_WITH_COOKIE)'

}

conn.request("DELETE", "/rest/o/(ORG_ID)/device_tags", payload, headers)

res = conn.getresponse()

data = res.read()

print(data.decode("utf-8"))

Thank You

Did you get this working?

Hello, stupid question but how do I find my Peplink Organization_ID , group_id , and device_id ?? Thank you

Hi @Brandon_VanDenBosch
You can find that info in the URL of each device in InControl2. o = Org ID, n = Group ID & d= Device ID.
e.g. https://mars.ic.peplink.com/o/{orgID}/n/{groupID}/d/{deviceID}/overview
If you need any help with the API’s let me know as I have extensive knowledge of the for both InControl2 & device level APIs.

Taupo, maybe you can help with an API we are looking at to get the “event log” and “event log archive” for all of our devices on InControl2. I’m trying to have the event logs downloaded as CSV, and then input to Caspio our web page application data tables.