{"_id":"582789abbe5c080f00a5a817","project":"568bdc1483d2061900d86cdc","version":{"_id":"582789aabe5c080f00a5a7fe","__v":10,"project":"568bdc1483d2061900d86cdc","createdAt":"2016-11-12T21:29:14.915Z","releaseDate":"2016-11-12T21:29:14.915Z","categories":["582789abbe5c080f00a5a7ff","582789abbe5c080f00a5a800","582789abbe5c080f00a5a801","582789abbe5c080f00a5a802","582789abbe5c080f00a5a803","582789abbe5c080f00a5a804","582789abbe5c080f00a5a805","582789abbe5c080f00a5a806","582789abbe5c080f00a5a807","582789abbe5c080f00a5a808","5827ea984ca29e0f00137a9e","583df597887db62f00644283","583df5d9c622791900e78da5","5845cd8763c11b250037967d","5845d13063c11b2500379681","5859e859e3306d1900126725","587aeb9a01cf3a0f008359eb","587c422af45e2d0f005e200d","587d84dc82f6f30f004ceee5"],"is_deprecated":false,"is_hidden":false,"is_beta":true,"is_stable":true,"codename":"beta2","version_clean":"0.0.0","version":"0"},"user":"568bdbc4fe6fcc0d006dc970","__v":0,"parentDoc":null,"category":{"_id":"587c422af45e2d0f005e200d","__v":0,"version":"582789aabe5c080f00a5a7fe","project":"568bdc1483d2061900d86cdc","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2017-01-16T03:46:50.263Z","from_sync":false,"order":2,"slug":"device-modeling","title":"Device Modeling"},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-01-06T06:16:28.508Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":0,"body":"[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Why Device Modeling\"\n}\n[/block]\nDevice modeling is a way to define what a device’s capabilities are.\n\nUsing models, you can prescribe the set of commands that can be executed on a device. This takes the place of having to interact with a fully custom protocol for each device.\n\nDevices are modeled in your Droplit.io ecosystem using a set of service classes.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Introduction to Service Classes\"\n}\n[/block]\nA service class is template that defines a set of device capabilities. It has **properties**, **methods**, and **events** collectively known as _service members_.\n\nService classes group a related set of functionality in a single template and provides a common interface to those functions. A single device may implement multiple services to define how it operates.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Service Properties\"\n}\n[/block]\nProperties describe a single attribute state of a device.\n\nFor example, a `switch` property could indicate if a device is `on` or `off`.\n\nProperties are stateful because they have a value that can be _read_ and _written_.\n\nWriting to a device property will cause the device to change state. For example, If you write `on` to a device’s `switch` property, the device will turn on.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Service Methods\"\n}\n[/block]\nMethods execute a device action.\n\nFor example, a `brew` method on a coffee maker could cause the brewing process to begin.\n\nMethods are not stateful - they do not have any stored values associated with them.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Future Feature - Parameters and Returns\",\n  \"body\": \"Methods cannot currently accept parameters or return values, but will be able to in the future.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Service Events\"\n}\n[/block]\nEvents indicate when something takes place at the device.\n\nFor example, a `motion` event on a motion sensor could indicate that motion was detected.\n\nEvents are not stateful—they fire once when the event takes place on the device. You do not need to define events for property changes; all property changes automatically raise an event.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Defining Services\"\n}\n[/block]\nServices are defined with a single .json file.\n\nThe service definition is a hash consisting of `name`, `properties`, `methods`, and `events` fields.\n\nThe name of the file doesn’t matter. The name field determines the service name.\n\nService names must meet the following requirements:\n - Between 1 and 23 characters\n - Only the contain characters: `a-z`, `A-Z`, `0-9`, `_`\n - No spaces\n - Service names are case-sensitive\n\nService definitions can be viewed and updated using the Droplit developer command line tools.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Example: BinarySwitch\"\n}\n[/block]\nLets look at the _BinarySwitch_ service for an example of how a service class might be defined.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"name\\\":\\\"BinarySwitch\\\",\\n    \\\"properties\\\": {\\n        \\\"switch\\\": {\\n            \\\"values\\\": [\\\"on\\\", \\\"off\\\"]\\n        }\\n    },\\n    \\\"methods\\\": {\\n        \\\"switchOn\\\": {\\n            \\\"description\\\": \\\"Sets switch to on\\\"\\n        },\\n        \\\"switchOff\\\": {\\n            \\\"description\\\": \\\"Sets switch to off\\\"\\n        }\\n    }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nThe `properties` field defines a property called `switch`. The property value can be one of a constrained set including `on` and `off`.\n\nThe `methods` field defines two methods: `switchOn` and `switchOff`. Descriptions of any member can be added using a `description` attribute. These descriptions are not used by the system, but are a pleasantry for the developer.\n\nAll service members must be unique within the service. For example, a service cannot have both a “switch” property and a “switch” method.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Modularity Example: MediaControl, MediaInfo, and AudioOutput\"\n}\n[/block]\nLet’s look at the _MediaControl_, _MediaInfo_, and _AudioOutput_ services as an example of how to define services with property modularity.\n\nProperly defined modular services should be re-usable for other devices. While a smart speaker might have volume, play/pause, and album info, each of these things may also exist independently on other devices. A traditional Bluetooth speaker would be able to change volume, and play/pause the media, but wouldn’t know what track is playing. Some Bluetooth speakers can simply change volume; and not pause or skip the track.\n\nThe **MediaControl** service provides control of a play queue:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"name\\\": \\\"MediaControl\\\",\\n    \\\"properties\\\": [\\n        {\\n            \\\"state\\\": {\\n                \\\"values\\\": [\\\"play\\\", \\\"pause\\\", \\\"stop\\\"]\\n            }\\n        }\\n    ],\\n    \\\"methods\\\": {\\n        \\\"next\\\": {\\n            \\\"description\\\": \\\"Plays next track\\\"\\n        },\\n        \\\"pause\\\": {\\n            \\\"description\\\": \\\"Pauses the audio\\\"\\n        },\\n        \\\"play\\\": {\\n            \\\"description\\\": \\\"Plays the audio\\\"\\n        },\\n        \\\"previous\\\": {\\n            \\\"description\\\": \\\"Plays previous track\\\"\\n        }\\n    }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nNotice that there are `next` and `previous` methods, as opposed to properties. The `next` and `previous` methods are actions that can be performed on the play queue, but have no state associated with them.\n\nThe **MediaInfo** service provides information about the current media:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"name\\\": \\\"MediaInfo\\\",\\n    \\\"properties\\\": {\\n        \\\"albumArt\\\": {\\n            \\\"valueType\\\": \\\"uri\\\",\\n            \\\"access\\\": \\\"read\\\"\\n        },\\n        \\\"albumTitle\\\": {\\n            \\\"valueType\\\": \\\"string\\\",\\n            \\\"access\\\": \\\"read\\\"\\n        },\\n        \\\"artist\\\": {\\n            \\\"valueType\\\": \\\"string\\\",\\n            \\\"access\\\": \\\"read\\\"\\n        },\\n        \\\"nextAlbumTitle\\\": {\\n            \\\"valueType\\\": \\\"string\\\",\\n            \\\"access\\\": \\\"read\\\"\\n        },\\n        \\\"nextArtist\\\": {\\n            \\\"valueType\\\": \\\"string\\\",\\n            \\\"access\\\": \\\"read\\\"\\n        },\\n        \\\"nextTrackName\\\": {\\n            \\\"valueType\\\": \\\"string\\\",\\n            \\\"access\\\": \\\"read\\\"\\n        },\\n        \\\"trackName\\\": {\\n            \\\"valueType\\\": \\\"string\\\",\\n            \\\"access\\\": \\\"read\\\"\\n        }\\n    },\\n    \\\"methods\\\": {},\\n    \\\"events\\\": {\\n        \\\"trackChanged\\\": {\\n            \\\"description\\\": \\\"Indicates the currently playing track has changed\\\"\\n        }\\n    }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nNotice that we get information for the currently playing track as well as the next track. Also notice the large number of properties associated with `MediaInfo`. If we wanted to know if the track changed, there isn’t a good property to monitor. The `albumArt`, `albumTitle`, `artist`, and even `trackName` properties don’t necessary change value for a new track. To address this issue, there is a `trackChanged` event.\n\nThe **AudioOutput** service controls the volume of a speaker:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"name\\\": \\\"AudioOutput\\\",\\n    \\\"properties\\\": {\\n        \\\"volume\\\": {\\n            \\\"value-min\\\": 0,\\n            \\\"value-max\\\": 100\\n        },\\n        \\\"mute\\\": {\\n            \\\"values\\\": [true, false]\\n        }\\n    },\\n    \\\"methods\\\": {\\n        \\\"mute\\\": {\\n            \\\"description\\\": \\\"Mutes the audio\\\"\\n        },\\n        \\\"stepUp\\\": {\\n            \\\"description\\\": \\\"Increment the volume one level\\\"\\n        },\\n        \\\"stepDown\\\": {\\n            \\\"description\\\": \\\"Decrement the volume one level\\\"\\n        },\\n        \\\"unmute\\\": {\\n            \\\"description\\\": \\\"Unmutes the audio\\\"\\n        }\\n    }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nNotice that the `volume` property has a valid range rather than having a set of valid values like the `switch` property of `BinarySwitch`.\n\nLooking at the _MediaControl_, _MediaInfo_, and _AudioOutput_ services, you can see how the three services work together to model a smart speaker. You could even apply _BinarySwitch_ to a smart speaker so it can handle simple on/off switch states.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/4FvMdJR4QsGP5kV5k3ao_ServiceClass-Speaker-trans.png\",\n        \"ServiceClass-Speaker-trans.png\",\n        \"740\",\n        \"508\",\n        \"#54286c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Reusability Example: DimmableLight, MulticolorLight\"\n}\n[/block]\nA well-defined service definition should consider how it would be reused by other devices.\n\nUsing smart lighting as an example, some lights can change in brightness while others can change in both color and brightness, while others yet can change in brightness and color temperature within the white spectrum.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/dd6I5r1eRiufvdynULnM_ServiceClass-Shared-Trans.png\",\n        \"ServiceClass-Shared-Trans.png\",\n        \"740\",\n        \"508\",\n        \"#d4d4d4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Indexed Services\"\n}\n[/block]\nJust as a device can implement more than one service, it can also implement more than once instance of a service. Imagine a power strip with 5 individually switchable outlets numbered P1 though P5.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/28fe006-power_strip.png\",\n        \"power strip.png\",\n        140,\n        302,\n        \"#040404\"\n      ],\n      \"caption\": \"Power Strip\"\n    }\n  ]\n}\n[/block]\nRather than having a proprietary service class with 5 separate `switch` properties and `switchOn` and `switchOff` methods, the power strip could simply have 5 `BinarySwitch` services accessible by indexes named after the ports.\n\nTo switch outlet `P1` on, set `BinarySwitch[P1].switch` to `on`.\n\nRanges of service indexes can also be switched at once with service selectors. To switch outlets 3, 4, and 5 on at once, set `BinarySwitch[P3..5].switch` to `on`.\n\nTo learn more about service selectors, see [Service Selectors](doc:service-selectors).","excerpt":"Chose your own adventure","slug":"services","type":"basic","title":"Service Classes"}

Service Classes

Chose your own adventure

[block:api-header] { "type": "basic", "title": "Why Device Modeling" } [/block] Device modeling is a way to define what a device’s capabilities are. Using models, you can prescribe the set of commands that can be executed on a device. This takes the place of having to interact with a fully custom protocol for each device. Devices are modeled in your Droplit.io ecosystem using a set of service classes. [block:api-header] { "type": "basic", "title": "Introduction to Service Classes" } [/block] A service class is template that defines a set of device capabilities. It has **properties**, **methods**, and **events** collectively known as _service members_. Service classes group a related set of functionality in a single template and provides a common interface to those functions. A single device may implement multiple services to define how it operates. [block:api-header] { "type": "basic", "title": "Service Properties" } [/block] Properties describe a single attribute state of a device. For example, a `switch` property could indicate if a device is `on` or `off`. Properties are stateful because they have a value that can be _read_ and _written_. Writing to a device property will cause the device to change state. For example, If you write `on` to a device’s `switch` property, the device will turn on. [block:api-header] { "type": "basic", "title": "Service Methods" } [/block] Methods execute a device action. For example, a `brew` method on a coffee maker could cause the brewing process to begin. Methods are not stateful - they do not have any stored values associated with them. [block:callout] { "type": "info", "title": "Future Feature - Parameters and Returns", "body": "Methods cannot currently accept parameters or return values, but will be able to in the future." } [/block] [block:api-header] { "type": "basic", "title": "Service Events" } [/block] Events indicate when something takes place at the device. For example, a `motion` event on a motion sensor could indicate that motion was detected. Events are not stateful—they fire once when the event takes place on the device. You do not need to define events for property changes; all property changes automatically raise an event. [block:api-header] { "type": "basic", "title": "Defining Services" } [/block] Services are defined with a single .json file. The service definition is a hash consisting of `name`, `properties`, `methods`, and `events` fields. The name of the file doesn’t matter. The name field determines the service name. Service names must meet the following requirements: - Between 1 and 23 characters - Only the contain characters: `a-z`, `A-Z`, `0-9`, `_` - No spaces - Service names are case-sensitive Service definitions can be viewed and updated using the Droplit developer command line tools. [block:api-header] { "type": "basic", "title": "Example: BinarySwitch" } [/block] Lets look at the _BinarySwitch_ service for an example of how a service class might be defined. [block:code] { "codes": [ { "code": "{\n \"name\":\"BinarySwitch\",\n \"properties\": {\n \"switch\": {\n \"values\": [\"on\", \"off\"]\n }\n },\n \"methods\": {\n \"switchOn\": {\n \"description\": \"Sets switch to on\"\n },\n \"switchOff\": {\n \"description\": \"Sets switch to off\"\n }\n }\n}", "language": "json" } ] } [/block] The `properties` field defines a property called `switch`. The property value can be one of a constrained set including `on` and `off`. The `methods` field defines two methods: `switchOn` and `switchOff`. Descriptions of any member can be added using a `description` attribute. These descriptions are not used by the system, but are a pleasantry for the developer. All service members must be unique within the service. For example, a service cannot have both a “switch” property and a “switch” method. [block:api-header] { "type": "basic", "title": "Modularity Example: MediaControl, MediaInfo, and AudioOutput" } [/block] Let’s look at the _MediaControl_, _MediaInfo_, and _AudioOutput_ services as an example of how to define services with property modularity. Properly defined modular services should be re-usable for other devices. While a smart speaker might have volume, play/pause, and album info, each of these things may also exist independently on other devices. A traditional Bluetooth speaker would be able to change volume, and play/pause the media, but wouldn’t know what track is playing. Some Bluetooth speakers can simply change volume; and not pause or skip the track. The **MediaControl** service provides control of a play queue: [block:code] { "codes": [ { "code": "{\n \"name\": \"MediaControl\",\n \"properties\": [\n {\n \"state\": {\n \"values\": [\"play\", \"pause\", \"stop\"]\n }\n }\n ],\n \"methods\": {\n \"next\": {\n \"description\": \"Plays next track\"\n },\n \"pause\": {\n \"description\": \"Pauses the audio\"\n },\n \"play\": {\n \"description\": \"Plays the audio\"\n },\n \"previous\": {\n \"description\": \"Plays previous track\"\n }\n }\n}", "language": "json" } ] } [/block] Notice that there are `next` and `previous` methods, as opposed to properties. The `next` and `previous` methods are actions that can be performed on the play queue, but have no state associated with them. The **MediaInfo** service provides information about the current media: [block:code] { "codes": [ { "code": "{\n \"name\": \"MediaInfo\",\n \"properties\": {\n \"albumArt\": {\n \"valueType\": \"uri\",\n \"access\": \"read\"\n },\n \"albumTitle\": {\n \"valueType\": \"string\",\n \"access\": \"read\"\n },\n \"artist\": {\n \"valueType\": \"string\",\n \"access\": \"read\"\n },\n \"nextAlbumTitle\": {\n \"valueType\": \"string\",\n \"access\": \"read\"\n },\n \"nextArtist\": {\n \"valueType\": \"string\",\n \"access\": \"read\"\n },\n \"nextTrackName\": {\n \"valueType\": \"string\",\n \"access\": \"read\"\n },\n \"trackName\": {\n \"valueType\": \"string\",\n \"access\": \"read\"\n }\n },\n \"methods\": {},\n \"events\": {\n \"trackChanged\": {\n \"description\": \"Indicates the currently playing track has changed\"\n }\n }\n}", "language": "json" } ] } [/block] Notice that we get information for the currently playing track as well as the next track. Also notice the large number of properties associated with `MediaInfo`. If we wanted to know if the track changed, there isn’t a good property to monitor. The `albumArt`, `albumTitle`, `artist`, and even `trackName` properties don’t necessary change value for a new track. To address this issue, there is a `trackChanged` event. The **AudioOutput** service controls the volume of a speaker: [block:code] { "codes": [ { "code": "{\n \"name\": \"AudioOutput\",\n \"properties\": {\n \"volume\": {\n \"value-min\": 0,\n \"value-max\": 100\n },\n \"mute\": {\n \"values\": [true, false]\n }\n },\n \"methods\": {\n \"mute\": {\n \"description\": \"Mutes the audio\"\n },\n \"stepUp\": {\n \"description\": \"Increment the volume one level\"\n },\n \"stepDown\": {\n \"description\": \"Decrement the volume one level\"\n },\n \"unmute\": {\n \"description\": \"Unmutes the audio\"\n }\n }\n}", "language": "json" } ] } [/block] Notice that the `volume` property has a valid range rather than having a set of valid values like the `switch` property of `BinarySwitch`. Looking at the _MediaControl_, _MediaInfo_, and _AudioOutput_ services, you can see how the three services work together to model a smart speaker. You could even apply _BinarySwitch_ to a smart speaker so it can handle simple on/off switch states. [block:image] { "images": [ { "image": [ "https://files.readme.io/4FvMdJR4QsGP5kV5k3ao_ServiceClass-Speaker-trans.png", "ServiceClass-Speaker-trans.png", "740", "508", "#54286c", "" ] } ] } [/block] [block:api-header] { "type": "basic", "title": "Reusability Example: DimmableLight, MulticolorLight" } [/block] A well-defined service definition should consider how it would be reused by other devices. Using smart lighting as an example, some lights can change in brightness while others can change in both color and brightness, while others yet can change in brightness and color temperature within the white spectrum. [block:image] { "images": [ { "image": [ "https://files.readme.io/dd6I5r1eRiufvdynULnM_ServiceClass-Shared-Trans.png", "ServiceClass-Shared-Trans.png", "740", "508", "#d4d4d4", "" ] } ] } [/block] [block:api-header] { "type": "basic", "title": "Indexed Services" } [/block] Just as a device can implement more than one service, it can also implement more than once instance of a service. Imagine a power strip with 5 individually switchable outlets numbered P1 though P5. [block:image] { "images": [ { "image": [ "https://files.readme.io/28fe006-power_strip.png", "power strip.png", 140, 302, "#040404" ], "caption": "Power Strip" } ] } [/block] Rather than having a proprietary service class with 5 separate `switch` properties and `switchOn` and `switchOff` methods, the power strip could simply have 5 `BinarySwitch` services accessible by indexes named after the ports. To switch outlet `P1` on, set `BinarySwitch[P1].switch` to `on`. Ranges of service indexes can also be switched at once with service selectors. To switch outlets 3, 4, and 5 on at once, set `BinarySwitch[P3..5].switch` to `on`. To learn more about service selectors, see [Service Selectors](doc:service-selectors).