CIQ Tools

In an effort to contribute more to our Connect IQ developer community, with the hope of making it easier and faster to make better apps, I have been spending a considerable amount of time working to extract useful code from my various projects and turn them into shareable barrels. In some cases it has been easy as they are my projects and in many cases I have had to work with clients to get permission. Regardless, I now have half a dozen barrels in various states of readiness that I am going to release on GitHub. I am also working to make public some useful API endpoints. I have decided to group these barrels and APIs collectively under the name "CIQ Tools".

The barrels will all be licensed under the MIT License, which will allow for the most flexible use and the API endpoints will all be available for free (and hopefully without the need for any kind of API key).

In all cases right now, the published code will not be anywhere near to feature complete, so if there are suggestions then please create an issue within GitHub on the repo. Or, even better, provide more functionality or fixes by contributing via a GitHub's pull request.

Barrels

The source code for all barrels is in separate repos within GitHub. Because you don't need the actual source code for the barrel to include it in your project, I have made the barrel (and associated debug.xml) available in the releases sidebar section.

API Endpoints

  • Today I've released two pieces within CIQ Tools:

    1. a barrel to make use of built-in cryptography easier; and
    2. an API endpoint to identify a device based on part number.

    The cryptography barrel is an attempt to make it easier to use the Connect IQ cryptography functionality for simple encryption/decryption. It currently supports encrypt/decrypt of AES128 using ECB mode.

    The API endpoint is useful if you want/need to identify the device being used. In one project I use it so I can change the way certain things are done and in another I use it so that a human-readable device name is displayed on a companion app and website.

  • Nice! I didn't really understand the use-case for the api. It's basically parsing the device directories compiler/simulator json files and extracts a small portion from it I guess, but if you use it offline then why not just grep it or parse the device files and create a static map for it (for the companion app website). And if it's used from CIQ app to query about itself then I believe it would be way less complicated to generate the necessary constants into source-<device> folders and use it. I'm pretty sure it would be less code than the code to download it from the internet (and it would always be there, no need for internet)

  • I believe it would be way less complicated to generate the necessary constants into source-<device> folders

    It's not.

    First, a static map would be (and is) far bigger. There are currently 216 device part numbers which means that the map of part numbers to names is 4350 bytes just in characters, without any associated objects. The code to retrieve the device info from this endpoint is as simple as 12 lines of code (plus the length of the API endpoint string).

    Second, the source/resource folders method doesn't provide enough granularity. For example, there is no way to extract out the Tactix 7 (which has it's own part number) as it's grouped within the "fenix7x".

    Finally, I don't care about offline in either use-case as the apps require Internet for their functionality. And with an API endpoint, the device or the companion app/website can retrieve the device info without needing to replicate the list in three places.

  • OK, if you anyway use internet, then it's probably OK. However just to put things straight: you would only need to include a small map in each souurce-<device> folder. i.e: source-fenix7 would only need the map of those part numbers that can be found in the fenix7 device json files. I guess it's not that a fr255 will need to translate the part number of a fenix7 or any other device to human readable string :) 

  • However just to put things straight: you would only need to include a small map in each souurce-<device> folder.

    Okay, but who wants to maintain that kind of thing, especially across multiple projects? If it was an offline app as you suggest, I would still use the API endpoint as part of the build process to generate the map. There is no constraint saying the API endpoint has to be used by a Garmin device directly.

    And there's still code associated with using a map. If you are storing it as a JSON resource it must be retrieved and then compared. 

  • Actually if we're talking about community effort I have an idea: one thing I'm always missing is the ability to test things in specific devices I don't have.

    This sounds like something that deserves it own thread.

  • MessagePack support is now publicly available on GitHub as a barrel -- https://github.com/douglasr/msgpack-monkeyc

    MessagePack is like JSON, but smaller. It's an efficient binary serialization format that lets you exchange data among multiple languages like JSON. Small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves.

    MessagePack has many uses but I have found it most common when communicating with IoT devices, especially over BLE. I also use it as an easy way to encrypt and store sensitive objects on device.

    The MessagePack community will claim the MessagePack is "faster", but that is based on that fact that most implementations (eg. Ruby) use native extensions/libraries for the heavy lifting and so shorter messages do indeed happen faster (because they're shorter). In the case of Monkey C, we don't have that ability so the serialization/deserialization has to be done with Monkey C only. However, if you need to talk to a devices using MessagePack serialized messages then this is your option, regardless of size/speed.

    NOTE: only the serialization code is currently in the repo, as I need to finish cleaning up the deserialize code.

  • I don't understand the assertNotEqual-s in the tests. Can you either add a comment so it's clear why you test it for what it is not, and why that value (I mean there are endless other things it is not equal to :) OR just convert them to assertEqual?

  • I don't understand the assertNotEqual-s in the tests.

    All the assertNotEqual() tests are edge cases, and in most cases is one of: the upper edge of an unsigned int, the lower edge of a signed int or the upper edge of the available data length for that type. For example, 65535 is the upper edge of an unsigned 16-bit integer. So we need to test that and the next value (65536) to ensure it wasn't rolled around/wrapped but instead was stored as a 32-bit unsigned integer.

    All of the tests are group based on their type and if you compare the tested values to the available bits/bytes you will see that most are related (with some other, random values thrown in for good measure).