{ "info": { "author": "Ian A Wilson", "author_email": "UNKNOWN", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "Intended Audience :: Information Technology", "License :: OSI Approved :: MIT License", "Programming Language :: Python" ], "description": "# Crowsnest capabilities\n\n*I got 99 problems, and naming is all of them.*\n\nThis repository is home to definitions for the high-level language of the Crowsnest API and\nplugin system. This provides defnitions of all actions and events, all of which is\ndone in yaml (found in `/crowsnest_capabilities/definitions/`; schema explained below).\n\nThe definitions provided here are not of devices themselves, but of the building blocks for devices.\nA device is a collection of the actions and events defined here.\n\n\n## Python API\n\nIn addition to the definitions, this module provides a Python API, the core of which is a\n`capabilities` object for interacting with the definitions programmatically. Each entry includes\ncleaning helper functions that are used to sanitize and validate data as it flows through the\nsystem.\n\nAs an example, let's inspect the generic action for turning a device on,\n`action.generic.power.set`:\n\n```python\n>>> from crowsnest_capabilities import capabilities\n>>> power_set = capabilities['action.generic.power.set']\n```\n\nThe schema for this action is\n\n```yaml\naction.generic.power.set:\n inputs:\n value:\n - on\n - off\n outputs: {}\n async_generated_event: event.generic.power.changed\n```\n\nso, we know that the valid values for inputs are `on` and `off` (`True` and `False` in Python).\nInputs are validated and cleaned with `.clean_input()`:\n\n```python\n>>> power_set.clean_input({'value': True})\n{'value': True}\n>>> # extraneous entries are removed\n>>> power_set.clean_input({'value': False, 'foo': 'bar'})\n{'value': False}\n>>> # bad values raise a ValidationError\n>>> power_set.clean_input({'value': 10})\n ValidationError: `value` must be one of [True, False]\n```\n\n`.clean_output()` on both `Action` and `Event` work the same way.\n\nYou can get a group of entries under a common prefix using `.group()`.\n\n```python\n>>> capabilities.group('event.generic.power')\n[, ]\n>>> # any number of dots are allowed\n>>> capabilities.group('event.generic') # 6 Events\n>>> capabilities.group('event') # all of the Events\n>>> capabilities.group() # all of the entries\n>>> # bogus prefixes return an empty list\n>>> capabilities.group('asdf')\n[]\n```\n\n\n## Requirements\n\n- The layout of a capabilities hierarchy (ie, every level of `...`) should be semantically the same for each device that implements it.\n - Examples:\n - `action.camera.still.capture` - Capture a still image from a camera\n - `action.microwave.power_level.set` - Set the power level of the magnetron\n - `action.generic.power.set` - Turn the master power on and off for a device\n - `action.sensor.dissolved_ions.read` - Read the sensor for disolved ion content\n - `action.sensor.magnet.read` - Read the value of the magnetic sensor\n - `event.sensor.magnet.changed` - Fired when the value of the magnetic sensors changes (when this is fired may be configurable by the device plugin using thresholds)\n - `event.generic.boolean.changed` - Fired when a two-stage switch changes state\n- Actions and events (or whatever they're eventually called) should be distinctly different\n - They should, however, be related and able to interact with one another (eg, requesting some action from a device that results in async handling as an \"event\")\n - They should be easily relatable semantically\n- Actions and events should be specific enough to not complicate their usage, but simple enough to be reused. \"We'll know it when we see it.\"\n- The inputs and outputs should be well definied, and not overly complex objects.\n\n\n## Definition schema\n\n(Our schema is loosely based on [Rx](http://rx.codesimply.com/).)\n\nLet's start with an annotated example, adapted from `/crowsnest_capabilities/definitions/generic.yml`.\n\n```yaml\naction.generic.power.get: # definitions are type.class.attribute.action\n inputs: {} # no inputs for this action\n outputs:\n value: # output dict has one entry named `value`\n valid_values:\n - on # valid values for `value` are `on` and `off`\n - off\n async_generated_event: event.generic.power.changed\n # if fired asynchronously, this will generate the event\n # named `event.generic.power.changed`\n\naction.generic.power.set:\n inputs:\n value: # the `value` field is the only input, allowing booleans\n type: //bool\n outputs: {} # no outputs\n async_generated_event: event.generic.power.changed\n\nevent.generic.power.changed:\n outputs: # has the same outputs as `action.generic.power.get`,\n # which is linked to this\n value:\n - on # `value` field uses the valid_values short-hand\n - off\n```\n\nThe details:\n\n- Definitions are in yaml\n- Definition files are stored in `/crowsnest_capabilities/definitions/`; they are discovered and loaded automatically\n- Top level entries must be a unique 4-dot-separated name of the form `...`, eg `action.generic.power.set`\n- `action` entries must be a dictionary with the following keys:\n - `inputs`: data pass-through schema (see below) sent to the device describing what to do\n - `outputs`: data pass-through schema (see below) sent by the device as a response\n - `async_generated_event`: fully qualified name of an event this action turns into if handled\n asynchronously, eg `event.generic.power.changed`\n- `event` entires must be a dictionary with the following keys:\n - `outputs`: data pass through schema (see below) sent by the device describing what happened\n- The \"data pass-through schema\" (used for passing data to and from devices through Crowsnest) is a\ndictionary of keys, where each key is the name of the data entry. For example, if you want to send\n`{value: 10}`, then `value` is the name of the entry you define as an integer field.\n - Each data entry is a dictionary that may define any of the following:\n - `type`: one of DataField types: `//str`, `//num`, `//int`, `//bool`, or `//bytes`\n - `valid_values`: a list of allowed values\n - `required`: boolean specifying whether or not the field is required to be valid; defaults to `yes`\n - `default`: default value if one is not provided; implies `required: no`\n - Although not strictly required, it is *highly recommended* that you supply `type` or `valid_values`\n unless you can make a strong case for why complete genericness is needed.\n - There are several shortcuts for simple cases:\n - You can supply a `type` value directly as the value to the data entry.\n\n This means that\n\n entry:\n type: //str\n and\n\n entry: //str\n are equivalent.\n - You can supply a list of `valid_values` directly as the value to the data entry.\n\n This means that\n\n entry:\n valid_values:\n - red\n - green\n - blue\n and\n\n entry:\n - red\n - green\n - blue\n are equivalent.\n - `valid_values` must match the type exactly, while `type` entries will generally try to coerce\n to the correct type. For example,\n - `//bool` will coerce `\"foo\"` and `1` to `True`; `\"\"`, `0`, and `null` to `False`\n - `valid_values` of `yes` and `no` will require an exact match of the booleans (no coersion)\n\n\n## Contributions and community\n\nTo contribute your own entries, fork us and create a pull request. Please be sure to follow\nthe guidelines, as we require strict adherence to accept pull requests. All new submissions\nwill be subject to review before acceptance; these definitions are curated to provide a\nconsistent experience across all Crowsnest devices.\n\nIdeas, comments, and suggestions are always welcome!", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "UNKNOWN", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "crowsnest-capabilities", "package_url": "https://pypi.org/project/crowsnest-capabilities/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/crowsnest-capabilities/", "project_urls": { "Download": "UNKNOWN", "Homepage": "UNKNOWN" }, "release_url": "https://pypi.org/project/crowsnest-capabilities/0.1.1/", "requires_dist": null, "requires_python": null, "summary": "High-level language for Crowsnest API and plugin systm", "version": "0.1.1" }, "last_serial": 1328648, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "fe228ea9073481f8f2e30405e17fdea2", "sha256": "eeae5a999021a2682a91525f04a8af5c4b7fe7aadd331570a537f6f49073fb60" }, "downloads": -1, "filename": "crowsnest-capabilities-0.1.0.tar.gz", "has_sig": true, "md5_digest": "fe228ea9073481f8f2e30405e17fdea2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13027, "upload_time": "2014-08-17T00:25:16", "url": "https://files.pythonhosted.org/packages/5b/c3/151dbea9b843f3799df983fb9c749fcfac5a84f2d815e568ed7e5783fe82/crowsnest-capabilities-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "fc0a149ebe0261be117cc17ed2b0e176", "sha256": "8a333d45985770164af9318265606ee330f5fd447075a59712af2036632ecdbe" }, "downloads": -1, "filename": "crowsnest-capabilities-0.1.1.tar.gz", "has_sig": true, "md5_digest": "fc0a149ebe0261be117cc17ed2b0e176", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13598, "upload_time": "2014-09-03T20:58:09", "url": "https://files.pythonhosted.org/packages/17/be/4c596e2823d746af0aba524fc509dd4c0bdb4567ff19885d629c2b5ad4d2/crowsnest-capabilities-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "fc0a149ebe0261be117cc17ed2b0e176", "sha256": "8a333d45985770164af9318265606ee330f5fd447075a59712af2036632ecdbe" }, "downloads": -1, "filename": "crowsnest-capabilities-0.1.1.tar.gz", "has_sig": true, "md5_digest": "fc0a149ebe0261be117cc17ed2b0e176", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13598, "upload_time": "2014-09-03T20:58:09", "url": "https://files.pythonhosted.org/packages/17/be/4c596e2823d746af0aba524fc509dd4c0bdb4567ff19885d629c2b5ad4d2/crowsnest-capabilities-0.1.1.tar.gz" } ] }