The inspiration for my creation of this project is pretty simple: I play Destiny -> I wanted to do something that included their API. From that I included the voice-control element to the project to add an automation aspect, and then I had my two project aspects. After some brainstorming, I landed on having a loadout equipper that was controlled by a seperate mic. Originally that mic was going to be a small little one that was attached to the actual project, but due to time constraints caused by problems in more crucial parts of the project, I eventually switched to my backup idea of the voice control being from Siri instead. This wasn't unexpected, however, since from the beginning I planned on switching to the backup plan if time was a concern.
PhysicalChronologically, I did this near the end, but for purposes of documentation, I'll start with the physical aspect. It's pretty simple, only just some LEDS. Since the main product of my automation is itself also digital, the lights are just to have a visualization.
The main thing I needed to do was access the API and then get and push data to it. To acess it, I first had to register a application with the API in order to recieve an API acess key that would be used with all calls:
To register it I had to make a name(doesn't matter), a OAuth Type, a redirect URL, and because of my OAuth type, authorized API permissions. The OAuth type affected whether or not I would be making protected calls. Protected calls are any calls that push data to the API and affects stuff in-game. If I didn't need to make any protected calls, I could just not touch the OAuth at all, but unfortunately I did to move items. For OAuth permissions, I checked the box that gave item moving permissions. The redirect URL had to be where my program was recieving data, which for me was my "https" + local IP + "/bungie/callback". The required part of that is the "s" in https, because it needs to be secured(more on that later) and for the suffix it just has to match what your program will catch, it just has to be something additional. Finnally, there is another option for a confidential or public OAuth. This affects whether or not it can recieve a refresh token(more later)
Getting ValuesNext, I needed to get key values in order to make later calls to the API. I did this by querrying values using various calls that built off each other. Because my project requires a static account these values can be directly plugged into each call manually, but I did not know this fact when I initially started. Instead, I originally thought that I would have to do what the API documentation and all the guides said to do, which was to grab the API's entire manifest and scrape the data values that I needed. However, even with the most efficiently compressed and edited manifest, the file was still ~2-3mb. This was the original reason I chose to use a Rasberry Pi, as I thought I would need the extra storage space that the Argon didn't have. Once I found out I didn't need to use the manifest, I didn't think about it much and kept using my Pi (foreshadowing).
The values that I needed to get were:
- BungieID
- DestinyID
- IDType(s)
- CharacterID
- ItemID
First, the BungieID was given just through any Bungie account. When going on your profile settings page, your bID(censored) and bIDType(254) would be contained within the URL for that page, so that is where I got it from.
This was needed to get my destinyID, which is what is used for the rest of the calls (and from now on will be reffered to as just id unless otherwise specified). To get this I made a GET call to the default endpoint + GetMembershipById + {bungieID} + {bungieIdType} and included the API-Key as a header. This returned my destinyID and some other misc. info about my account as a json object. I printed the json, looked for my id value(it was towards the start so easy to find) and noted it for later. The idType for the destinyID is a constant based off of the service the account was created with, for me that was Playstation and therefore my idType was 2.
(Note: All API calls start with the default endpoint (bungie.net/Platform) and must contain the API-Key as a header, so from now on both are implied for all calls. )
For the rest of the calls, a new part will be needed by all of them which is a "component" parameter. This is just a constant value from the documentation(you can see what the values I use actually are in a comment in the code above) that is used to further specify which data I want back from the call. The rest of a calls followed a similar structure so I will quickly go through them:
- GET Profile required the id and idType and the component was for characterInfo. I recieved a list of the three characters I had, which within contained their respective ids.
- To get the item id, I typically would've had to scrape the manifest again because the items on the API aren't named, they just their unique ids which mean nothing without context. Luckily I found a shortcut. I used a third-party app that also acessed the API and also visualized the items, so I looked at the html and it turns out they kept the id values the same so I could just take them from there.
- I then also verified that those ids were in fact correct by testing them using the GET Item request, which through trial and error allowed me to confirm that they were in fact valid ids.
Once I had my item ids, I could make the loadouts that I would use. These would be lists containing 3 items each, each of those items represented by their respective ids. With this, I created the updateCurrentEquipped status method, which used the GET character request with a parameter that requested the currently equipped items. I then compared the response with the defined loadouts. If it matched any of the loadouts, it would return the loadout's name and if it didn't match any it would just return "none". This will be used later to turn on the LEDs.
To equip items I required quite a few things:
- Loadout to equip
- Auth_Token(next section)
- idType
- itemIds(from loadout definition or manually type it in, it doesn't matter)
- characterId
We have all of these at the time the method is run, so all that has to be done is format them correctly according to the API. This way is a bit different than the other API requests, but again, the documentation has the formatting so I don't need to put it here. Regardless, the first thing we do no matter the loadout is equip three preset items(our default items) by sending a post request. It doesn't matter what these default items are as long as they aren't of the highest rarity. For context, you can only have 1 item that is the highest rarity equipped at a time, so if we already have a rare item equipped and we try to equip another one, it might cause an error. Therefore, we wipe the slate by making sure no rarest items are equipped. Then, we simply equip the loadout items we do want by sending three more post requests.
It is worth noting that while this method is not the most elegant and could be more refined, that might cause less effieciency. While yes, we could avoid wiping the slate every time, to do so we would have to check each item for its rarity, then if there is one of the highest rarity we would have to check if an issue can occur, and then if it can we'd have to equip a default item to fix it anyways. While best scenario this could shave off two post requests(which granted are more intensive that get requests) it would require possibly 5-6 get requests in return and would be loads more complicated. Therefore, although simpler, my solution still works best for now.
Authentication








Comments