Unifi Integration

I use the Ubiquiti Unifi network platform at home, and here is how I integrate it into Ignition. I primarily use it for presence detection and to analyze my network The script as is, in my usage, generates about 6000 tags, so I presume you will want to implement some changes for it to work better with Maker.

endpoint = "https://yourcontrolleriporhostname:8443"
username = 'yourusername'
password = 'yourpassword'
class unifi():
	client = system.net.httpClient(bypass_cert_validation = True,cookie_policy = "ACCEPT_ALL")
	logged_in = False
	endpoint = None
	username = None
	password = None
	LOG = system.util.getLogger("unifi")
	
	def __init__(self,endpoint,username=None,password=None):
		self.endpoint = endpoint
		if username:
			self.username = username
		if password:
			self.password = password
	def login(self,username=None,password=None):
		self.LOG.info("logging in")
		if username:
			self.username = username
		if password:
			self.password = password
		data = {"username":self.username,"password":self.password,"remember":True}
		response = self.client.post(endpoint+"/api/login",data = data)
		self.logged_in = True
		
	def getHealth(self):
		if not self.logged_in:
			self.login()
		self.LOG.info(self.logged_in)
		if self.logged_in:
			response = self.client.get(self.endpoint+"/api/s/default/stat/health")
			if response.json['meta']['rc'] == u'ok':
				return response.json['data']
			elif response.json['meta']['rc'] == u'error' and response.json['meta']['msg'] == u'api.err.LoginRequired':
				self.logged_in = False
	
	def getSta(self):
		if not self.logged_in:
			self.login()
		if self.logged_in:
			response = self.client.get(self.endpoint+"/api/s/default/stat/sta")
			if response.json['meta']['rc'] == u'ok':
				return response.json['data']
			elif response.json['meta']['rc'] == u'error' and response.json['meta']['msg'] == u'api.err.LoginRequired':
				self.logged_in = False

	def get(self,uri):
		if not self.logged_in:
			self.login()
		if self.logged_in:
			response = self.client.get(self.endpoint+"/api/s/default/"+uri)
			if response.json['meta']['rc'] == u'ok':
				return response.json['data']
			elif response.json['meta']['rc'] == u'error' and response.json['meta']['msg'] == u'api.err.LoginRequired':
				self.logged_in = False
client = unifi(endpoint,username,password)

def processResult(_r = None,tagProvider = "unifi",prefix = ""):
	writePaths = []
	writeValues = []
	tags = []
	typeMap = {str:"String",bool:"Boolean",unicode:"String",float:"Float4"}
	for folder in _r:
		fname = folder["name"] if "name" in folder else folder["mac"] if "mac" in folder else folder["subsystem"] if "subsystem" in folder else folder["bssid"] if "bssid" in folder else None
		for item in folder:
			if isinstance(folder[item],tuple(typeMap.keys())):
				tagPath = '[{}]{}{}/{}'.format(tagProvider,prefix,fname,item)
				if system.tag.exists(tagPath):
					writePaths.append(tagPath)
					writeValues.append(folder[item])
				else:
					tag = {
						"name":item,
						"dataType":typeMap[type(folder[item])],
						"value":folder[item]
					}
					system.tag.configure('[{}]{}{}'.format(tagProvider,prefix,fname),[tag])
	if len(writePaths):
		system.tag.writeBlocking(writePaths,writeValues)

To call and generate your tags, I use this on a tag that triggers periodically.

d1 = system.date.now()
_r = unifi.client.get("stat/health")
unifi.processResult(_r,"api","unifi/health/")
_r = unifi.client.get("stat/sysinfo")
unifi.processResult(_r,"api","unifi/sysinfo/")
_r = unifi.client.get("stat/sta")
unifi.processResult(_r,"api","unifi/sta/")
_r = unifi.client.get("stat/device")
unifi.processResult(_r,"api","unifi/device/")
d2 = system.date.now()
system.tag.writeBlocking(["[.]last duration"],[d2.time-d1.time])
9 Likes

This is really freaking cool. Thank you for this!

This seems very promissing. However when I try and run it I get the following error:

ValueError: Invalid URL - no protocol: stat/health

Any idea what this could be?

Is your endpoint set properly? It needs to be the address of your unifi controller.

Yes the endpoint is set to the same ip address I use to log into the device with. I wonder if this has something to do with the fact that I am running a Dream Machine Pro instead of the standard cloud key or hosted controller.

So it looks like devices running UnifiOS (UDM, UDM Pro) have a slightly different api. If someone can get me read only access to a udm or udm pro via a VPN, I can work on ad support for that as well.