OK, so the data returned is an object with a couple of keys, the only one of which we care about is called data
. The value at that key is an array containing node information. Each array element is an object with keys for the different data values.
If we decode the JSON like this: local u = json.decode( UnifiController() )
Then u
is the top-level object. The array of nodes is in u.data
. The first node is u.data[1]
, and the hostname of that node is u.data[1].hostname
.
So you have to use a combination of dereferencing through the object keys and array elements to get to the data.
Here’s a loop that just prints some of the data about the nodes:
for _,entry in ipairs( u.data ) {
print("ip=" .. entry.ip
.. ", hostname=" .. String(entry.hostname)
.. ", oui=" .. String(entry.oui)
.. ", first_seen=" .. String(entry.first_seen)
.. ", last_seen=" .. String(entry.last_seen)
)
end
The ipairs()
function returns two data values for every array element (see we are using u.data
, the node array, as the argument to ipairs()
). The _
for the first return value just tells Lua we don’t care about that value and it can discard it. It’s the index into the array… 1, 2, 3, 4, 5, etc. The second return value is the array element at the index. This is an object that contains the data keys. We can access the data keys here using “dot” notation, like entry.hostname
. This will give us the value of the hostname
key in the current entry (which changes each trip through the ipairs()
loop). If the key contains any special characters (non-alphanumeric), then you can use “square bracket” notation to get to the key value. For example, if for some reason the node data had a key last-wakeup
, we could not use entry.last-wakeup
, because Lua will think we are asking it to subtract wakeup
from entry.last
. To fix this, we write instead entry['last-wakeup']
. This is just an alternate syntax for the dot notation.
Let’s say we wanted to just extract some of the data from the response into a lighter, more useful structure, where we could quickly test to see if an IP address has a host on it, or if a particular host is on the network:
-- This makes a table as a map/dictionary indexed by ip (access like nodes['192.168.102.134'])
-- This form would be more appropriate for quickly locating a single device, as shown below. You can
-- change the value used to make the "nodes" entry to change the table's lookup key.
local nodes = {}
for _,entry in ipairs( u.data ) do
-- To index by IP address, use this line:
nodes[entry.ip] = { ip=entry.ip, hostname=entry.hostname, oui=entry.oui, first_seen=entry.first_seen, last_seen=entry.last_seen }
-- Or, to index by hostname, use this line:
nodes[entry.hostname] = { ip=entry.ip, hostname=entry.hostname, oui=entry.oui, first_seen=entry.first_seen, last_seen=entry.last_seen }
end
What this does is create a new table called nodes
that is set up for direct access to a device by either its IP address or hostname (depending on which of the two key lines you used, above–either/or there, not both).
Here’s an example of how you use that:
-- Try it. This assumes you used the IP address as key above. We have to use the square-bracket
-- syntax because the key contains special characters (the dots).
if nodes['192.168.102.134'] then
-- Print the hostname of the node with that IP
print("The node at 192.168.102.134 is ", nodes['192.168.102.134'].hostname)
else
print("There is no node at 192.168.102.134 on the WiFi network")
end
-- And this version assumes you used the hostname as key above.
if not nodes['Vera 3'] then
print("Oh no! The Vera3 is not on the WiFi network!")
end
-- For hostnames that don't have special characters, you can use the dot syntax:
if nodes.SonosZP then
print("I see the Sonos Play 1 at " .. nodes.SonosZP.ip)
end