I’ve been working on one of the world’s largest Meridian deployments with over 5,000 beacons. The web-based Meridian Editor defaults to showing 10 beacons at a time as a user you must click 'Load More' to expand the list by another ten for each click. I haven’t tried clicking ‘Load More’ 500+ times to see if I can eventually load the entire list - this sounds like a better job for the API.
Specifically today I am interested in seeing the beacon battery level. Access Points are externally powered so they can be overlooked for this purpose and anything reporting 100% is OK. I want to use a script that lists all the beacons with less than 100% battery and builds a special list of beacons with less than 30% battery. Obviously these thresholds could be fine tuned within the script. In this post I’m going to share my Python script and run through it step by step to explain how it works.
PyCharm is my tool of choice when it comes to building out a Python project. I have been using PyCharm Edu (Free Version)
because I was simply playing around and learning Python. Python is clearly growing in popularity as the language of choice for Network Engineers so I needed to give it a go. Now I am a paying user of PyCharm - it has been a great tool and I want to support it’s development. Another useful tool that helps you learn about APIs is Postman
NOTE: It's important to understand the API as much as possible before using it beyond the scope of this article. Data can be overwriten with the API and so caution should be taken. Also, Only documented APIs are supported by Aruba. https://docs.meridianapps.com/article/369-rest-api
The Meridian APIs used in this project are:
Download the getBeaconPower_lesson.py attachment (it’s zipped).
Open the python file onin your favourite editor (I use PyCharm).
Step through the file with the following breakdown to see what it does.
Break it Down:
Lines 1 and 2 import modules that we need throughout the python code.
Lines 4 and 5 need to be edited to include the appropriate location ID and authtoken for your Meridian environment. You can learn more about these details here.
Lines 7 to 11 build out various URLs and URIs to interact with the applicable APIs.
Lines 13 to 18 is the contents used in the API GET requests which includes a reference to the authtoken (Line 5) for authenticating to the API.
Line 20 contains the first API request. It is asking for information about the Meridian Location. The response to this is in JSON format and it contains loads of information about when the location was created, it’s name, the features enabled, GPS coordinates and more.
Line 21 parses the JSON API response and puts it in a variable called loc_parsed for use below.
Line 22 prints some info on the screen. It tells us the location name which is extracted from the previous API request.
Line 23 isn’t incredibly important. It just prints the URI used for the beacons API (see line 9). In PyCharm this displays as a clickable hyperlink.
Line 24 creates a list called maps_info getting ready for the next API GET request.
Line 26 and 27 prints a notification letting us know that information about maps is being retrieved and that it may take a while. If the location has lots of maps the information may need to be accessed across multiple requests.
Line 30 to 39 builds a function called get_maps. This function requests information about the maps from the Meridian Maps API.
Line 31 makes it so the maps_info list (created in Line 24) is editable from this function.
Line 32 requests the info and Line 33 parses the JSON response into a variable called maps_parsed.
Line 34 adds the information about each map from the JSON response into the maps_info list. The information is in dictionary format.
Line 35 to 37 checks the results to see if there is any other information that needs subsequent requests. If there is it fixes up the maps_api URI so that the next request will pull the new info. Then it re-runs get_maps.
Line 38 and 39 is the next step if the response indicates no other requests are required so it returns to the point after the initial call of get_maps (after Line 42).
Line 42 runs the get_maps function.
Lines 45 to 56 sets up some new variables and lists which become useful in the upcoming functions.
api_call will help count the times the Beacons API is used. For large environments multiple GET cycles may be required in order to get all the Beacon data. The default page size is 100, which means the information on 100 beacons is returned per request.
ap_count will count the Beacons that are Access Points.
beacon_count will help count the number of Beacons that are not Access Points.
full_count will help count the battery powered beacons that have 100% battery.
low_count will help count Beacons with a power level below the percentage indicated by the variable low.
not100_count will help count Beacons with a power level below 100% and above the percentage indicated by the variable low.
low is the variable (which can be changed) that indicates a Beacon power should be considered low.
ap_regex is the regular expression to help search for Beacons that are Access Points.
beacons_datab creates a list which will be populated with Beacon data returned by the API.
low_beacons creates a list which will hold information specific to Beacons that match the low category.
not100_beacons creates a list which will hold information specific to Beacons that don’t match the low category but are below 100%.
aps is commented out but could be used to create a list that would hold information specific to Access Points.
Lines 59 to 74 builds a function called get_beacons. The function requests Beacon data from the Location Beacons API, parses the JSON response and adds the Beacons data to the beacons_datab list.
Lines 60 to 62 makes it so that api_call, jparse and beacons_data can be used in this function.
Line 63 prints an indication of how many rounds of API request is being processed. This variable is incremented by Line 71.
Line 64 requests data via the GET method from the Beacons API.
Line 65 parses the JSON response.
Line 66 strips out only the Beacons data from the parsed data.
Line 67 adds the Beacons data which is now in list form to the beacons_datab list which was created in Line 53.
Line 68 prints the count of Beacons that have been added to the beacons_datab list.
Line 69 calls the beacon_power function (see the below breakdown of the beacon_power function Lines 86 to 110).
Line 70 prints the total number of Beacons that have been processed.
Line 71 increments the api_call variable that is used to print the count in Line 63.
Line 72 calls the check_for_more function to see if there is any more Beacons data on subsequent pages which would require another API request.
Lines 75 to 83 builds a function called check_for_more. The function checks the last API response returned in get_beacons to see if there is an indication of more Beacon data on further pages. The API returns 100 Beacons worth of data per page by default. On Line 9 this was set to return 200 Beacons per page.
Line 76 is an if statement which checks the ‘next’ key in the response is not equal to None.
If ‘next' contains data that is not equal to None then Line 77 to 80 resets the beacons_api URI to the value specified by ‘next’ and calls the get_beacons function for another round of Beacons data request.
If ‘next’ was equal to None then there is no more Beacons data to collect. Line 82 would print an indication that the API requests are done and Line 83 returns us to process the rest of the script.
Lines 86 to 110 builds a function called beacon_power. The function checks the value of ‘battery_level’ for each Beacon that is listed in beacons_data. It collects specific info for Beacons with low or not 100% battery and adds that data to the respective lists low_beaons and not100_beacons.
Line 87 iterates through each Beacon in the list beacons_data. Note we don’t use the beacons_datab list which contains all Beacons because beacon_power runs for each pass through get_beacons, if beacons_datab was used the same data would be re-used for each run of beacon_power. The script could have been written to run beacon_power once at the end but it does things like counts APs vs battery beacons for each Beacon API pass. Just note there are multiple ways to do this.
Line 88 to 90 makes it so that low_count, not100_count and beacon_count can be used by this function.
Line 91 iterates through maps that are listed in maps_info. So this is an iteration (of maps) in an iteration of Beacons. There might be a smarter way to achieve the goal here with a search of maps rather than iteratively hopping through each map, per beacon.
Line 93 matches the ‘id’ of the Map from maps_info to the value of ‘map’ from the beacons_data. So we can use the info about that map in Line 94.
Line 94 creates a variable beaconinfo which holds information about the Beacon being processed (ID, battery level, hardware type and map name).
Line 95 checks for Access Points using the regex setup in Line 52. If the Beacon is an AP then increment ap_count otherwise continue from else at Line 99.
Line 100 increments beacon_count which is the counter for non Access Point Beacons (or battery powered Beacons).
Line 101 checks for Beacons where the value of ‘battery_level’ is less than 100. Within this if statement is a nested if statement. The else corresponding to this if is on Line 108.
Line 102 checks for Beacons where the value of ‘battery_level’ is less than or equal to the variable low which was set to 30 on Line 51. If this is met then Line 103 writes the corresponding beaconinfo to the low_beacons list then low_count is incremented up by 1 with Line 104. The else for this if begins at Line 105.
If the ‘battery_level’ is not less than or equal to 30 (the variable low) and less than 100 (indicated by Line 101) then Line 106 will append the beaconinfo to the list not100_beacons. Line 107 will increment the low_count up by 1.
Line 109 and 110 increment the full_count up by 1 for all other beacons that do not match the if statements from Lines 101 and 102. These are the remaining beacons which are not Access Points, therefore are battery Beacons with a ‘battery_level’ of 100.
Line 113 calls the get_beacons function. This kick starts the bulk of the work of the Python script. Up until this point only get_maps and some minor location requests have been run along with the setup of functions, lists and variables.
Line 114 prints the Total Beacons Processed which is made up of the ap_count and beacon_count added together.
Line 115 prints the ap_count.
Line 116 prints the beacon_count.
Line 118 prints the full_count (Beacons with a full battery).
Line 120 prints the not100_count (Beacons <100 and > low).
Line 121 checks the not100_count is greater than 0. If this is true then Line 122 prints a header for columns to follow - Beacon ID, Battery, Beacon Type, Map, Editor URL.
Line 123 iterates through all the Beacons listed in not100_beacons.
Line 126 prints the low_count.
Line 127 checks the low_count is great than 0. If this is true then Line 128 prints a header for the columns as in Line 122.
Line 129 iterates through all the Beacons listed in low_beacons.
Line 136 exists the script.
Let me know if you have any questions or suggestions about the use of the Meridian API.#ALE#Meridian#LocationServices#ArubaBeacons