├── .github └── workflows │ └── trigger_website.yml ├── .travis.yml ├── LICENSE.md ├── convention.md ├── extensions ├── documents │ ├── homie_legacy_firmware_extension.md │ ├── homie_legacy_stats_extension.md │ └── homie_meta_extension.md └── extension_template.md └── readme.md /.github/workflows/trigger_website.yml: -------------------------------------------------------------------------------- 1 | name: Trigger Website CI 2 | 3 | on: 4 | push: 5 | branches: [develop] 6 | tags: ['**'] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-22.04 11 | steps: 12 | - name: Repository Dispatch 13 | uses: peter-evans/repository-dispatch@v3 14 | with: 15 | token: ${{ secrets.WEBSITE_DISPATCH_PAT }} 16 | repository: homieiot/homieiot.github.io 17 | event-type: website-deploy -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | script: | 2 | rtn=$(curl -X POST \ 3 | -H "Content-Type: application/json" \ 4 | -H "Accept: application/json" \ 5 | -H "Travis-API-Version: 3" \ 6 | -H "Authorization: token ${TRAVIS_ACCESS_TOKEN}" \ 7 | -d "{\"request\":{\"branch\":\"master\",\"message\":\"Triggered by convention change\"}}" \ 8 | https://api.travis-ci.com/repo/homieiot%2Fconvention-website/requests) 9 | echo $rtn 10 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # Creative Commons Attribution 4.0 International Public License 2 | 3 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. 4 | 5 | ### Section 1 – Definitions. 6 | 7 | a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. 8 | 9 | b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. 10 | 11 | c. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 12 | 13 | d. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. 14 | 15 | e. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. 16 | 17 | f. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. 18 | 19 | g. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. 20 | 21 | h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. 22 | 23 | i. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. 24 | 25 | j. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. 26 | 27 | k. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. 28 | 29 | ### Section 2 – Scope. 30 | 31 | a. ___License grant.___ 32 | 33 | 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: 34 | 35 | A. reproduce and Share the Licensed Material, in whole or in part; and 36 | 37 | B. produce, reproduce, and Share Adapted Material. 38 | 39 | 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 40 | 41 | 3. __Term.__ The term of this Public License is specified in Section 6(a). 42 | 43 | 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 44 | 45 | 5. __Downstream recipients.__ 46 | 47 | A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. 48 | 49 | B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 50 | 51 | 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). 52 | 53 | b. ___Other rights.___ 54 | 55 | 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 56 | 57 | 2. Patent and trademark rights are not licensed under this Public License. 58 | 59 | 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. 60 | 61 | ### Section 3 – License Conditions. 62 | 63 | Your exercise of the Licensed Rights is expressly made subject to the following conditions. 64 | 65 | a. ___Attribution.___ 66 | 67 | 1. If You Share the Licensed Material (including in modified form), You must: 68 | 69 | A. retain the following if it is supplied by the Licensor with the Licensed Material: 70 | 71 | i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); 72 | 73 | ii. a copyright notice; 74 | 75 | iii. a notice that refers to this Public License; 76 | 77 | iv. a notice that refers to the disclaimer of warranties; 78 | 79 | v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; 80 | 81 | B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and 82 | 83 | C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 84 | 85 | 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 86 | 87 | 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 88 | 89 | 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. 90 | 91 | ### Section 4 – Sui Generis Database Rights. 92 | 93 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: 94 | 95 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; 96 | 97 | b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and 98 | 99 | c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. 100 | 101 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. 102 | 103 | ### Section 5 – Disclaimer of Warranties and Limitation of Liability. 104 | 105 | a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ 106 | 107 | b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ 108 | 109 | c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. 110 | 111 | ### Section 6 – Term and Termination. 112 | 113 | a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. 114 | 115 | b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 116 | 117 | 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 118 | 119 | 2. upon express reinstatement by the Licensor. 120 | 121 | For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. 122 | 123 | c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. 124 | 125 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 126 | 127 | ### Section 7 – Other Terms and Conditions. 128 | 129 | a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. 130 | 131 | b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. 132 | 133 | ### Section 8 – Interpretation. 134 | 135 | a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. 136 | 137 | b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. 138 | 139 | c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. 140 | 141 | d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 142 | 143 | > Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. 144 | > 145 | > Creative Commons may be contacted at creativecommons.org 146 | -------------------------------------------------------------------------------- /convention.md: -------------------------------------------------------------------------------- 1 | # The Homie Convention 2 | 3 | Version: **x.x.x** 4 | Date: **01. Jan 2000** 5 | 6 | ## Introduction 7 | 8 | ​The Homie convention is an open standard framework designed to facilitate the 9 | communication and integration of Internet of Things (IoT) devices using the 10 | [MQTT protocol](https://mqtt.org). 11 | 12 | In particular, the Homie convention defines a consistent topic structure and 13 | messaging format that enables devices to represent themselves, their data and 14 | their supported controls/commands in a uniform manner, enabling automatic 15 | discovery. 16 | 17 | ## Roles 18 | 19 | When interacting through a shared MQTT broker, implementations of the Homie 20 | convention can take on one or both of the following roles simultaneously: 21 | 22 | - **Device**: an implementation that publishes the representation of a physical 23 | appliance or logical entity, such as a car, a coffee machine or a protocol 24 | bridge, to an MQTT broker. 25 | - **Controller**: an implementation that discovers and interacts with *devices* 26 | over MQTT. For example a mobile app, or an if-this-then-that rules engine. 27 | 28 | Note that, for brevity and simplicity, the word "device" is often used 29 | to denote the combination of an appliance, the computer managing the appliance's 30 | MQTT representation and the representation itself. 31 | 32 | ## MQTT Restrictions 33 | 34 | Homie communicates through [MQTT](https://mqtt.org) and is hence based on the basic principles of MQTT topic publication and subscription. 35 | 36 | ### Topic IDs 37 | 38 | An MQTT topic consists of one or more topic levels, separated by the slash character (`/`). 39 | A topic level ID MAY ONLY contain lowercase letters from `a` to `z`, numbers from `0` to `9` as well as the hyphen character (`-`). 40 | 41 | The special character `$` is used and reserved for Homie *attributes*. 42 | 43 | ### QoS and retained messages 44 | 45 | The recommended QoS level is **Exactly once (QoS 2)** (except for non-retained, see below). 46 | 47 | * All messages MUST be sent as **retained**, UNLESS stated otherwise. 48 | * Controllers setting values for device properties publish to the Property `set` topic with **non-retained** messages only. 49 | * Controllers setting values for **non-retained** device properties should publish to the Property `/set` topic with a QoS of **At most once (QoS 0)**. 50 | * Devices publishing values for their **non-retained** properties must use **non-retained** messages, with a QoS of **At most once (QoS 0)**. 51 | 52 | For QoS details see [the explanation](#qos-choices-explained). 53 | 54 | ### Last Will 55 | 56 | Homie requires the last will (LWT) to set the `homie` / `5` / `[device ID]` / `$state` attribute to the value **`lost`**, see [Device Lifecycle](#device-lifecycle). 57 | MQTT only allows one last will message per connection, but since a device can have children, the LWT message MUST be set on the 58 | root device (the device at the root of the parent-child tree). 59 | 60 | ### Empty string values 61 | 62 | MQTT will treat an empty string payload as a "delete" instruction for the topic, therefor an 63 | empty string value is represented by a 1-character string containing a single byte value 0 (Hex: `0x00`, Dec: `0`). 64 | 65 | The empty string (passed as an MQTT payload) can only occur in 3 places; 66 | 67 | - `homie` / `5` / `[device ID]` / `[node ID]` / `[property ID]`; reported property values (for string types) 68 | - `homie` / `5` / `[device ID]` / `[node ID]` / `[property ID]` / `set`; the topic to set properties (of string types) 69 | - `homie` / `5` / `[device ID]` / `[node ID]` / `[property ID]` / `$target`; the target property value (for string types) 70 | 71 | This convention specifies no way to represent an actual value of a 1-character string with a single byte 0. If a device 72 | needs this, then it should provide an escape mechanism on the application level. 73 | 74 | ## Payloads 75 | 76 | - Every MQTT message payload MUST be sent as a UTF-8 encoded string 77 | - The message MUST NOT include the UTF-8 [BOM](https://en.wikipedia.org/wiki/Byte_order_mark) 78 | - The value published as payload MUST be valid for the respective property/attribute type as per the list below 79 | 80 | ### String 81 | 82 | - String types are limited to 268,435,456 characters 83 | - An [empty string](#empty-string-values) ("") is a valid payload 84 | 85 | ### Integer 86 | 87 | - Integer types are string literal representations of 64-bit signed whole numbers 88 | - Integers range from -9,223,372,036,854,775,808 (-263) to 9,223,372,036,854,775,807 (263-1) 89 | - The payload may only contain whole numbers and the negation character "-". No other characters including spaces (" ") are permitted 90 | - A string with just a negation sign ("-") is not a valid payload 91 | - An [empty string](#empty-string-values) ("") is not a valid payload 92 | 93 | ### Float 94 | 95 | - Float types are string literal representations of 64-bit signed floating point numbers 96 | - Floats range from +/-(2^-1074) to +/-((2 - 2^-52) * 2^1023) 97 | - The payload may only contain whole numbers, the negation character "-", the exponent character "e" or "E" and the decimal separator ".", no other characters, including spaces (" ") are permitted 98 | - The dot character (".") is the decimal separator (used if necessary) and may only have a single instance present in the payload 99 | - Representations of numeric concepts such as "NaN" (Not a Number) and "Infinity" are not a valid payload 100 | - A string with just a negation sign ("-") is not a valid payload 101 | - An [empty string](#empty-string-values) ("") is not a valid payload 102 | 103 | ### Boolean 104 | 105 | - Booleans must be converted to the string literals "true" or "false" 106 | - Representation is case sensitive, e.g. "TRUE" or "FALSE" are not valid payloads. 107 | - An [empty string](#empty-string-values) ("") is not a valid payload 108 | 109 | ### Enum 110 | 111 | - Enum payloads must be one of the values specified in the format definition of the property 112 | - Enum payloads are case sensitive, e.g. "Car" will not match a format definition of "car" 113 | - Leading- and trailing-whitespace is significant, e.g. "Car" will not match " Car". 114 | - An [empty string](#empty-string-values) ("") is not a valid payload 115 | 116 | ### Color 117 | 118 | - Color payload validity varies depending on the property format definition of either "rgb", "hsv", or "xyz" 119 | - All payload types contain comma-separated data of differing restricted ranges. The first being the type, followed by numbers. The numbers must conform to the [float](#float) format 120 | - The encoded string may only contain the type, the [float](#float) numbers and the comma character ",", no other characters are permitted, including spaces (" ") 121 | - Payloads for type "rgb" contain 3 comma-separated values of [floats](#float) (`r`, `g`, `b`) with a valid range between 0 and 255 (inclusive). e.g. `"rgb,100,100,100"` 122 | - Payloads for type "hsv" contain 3 comma-separated values of [floats](#float). The first number (`h`) has a range of 0 to 360 (inclusive), and the second and third numbers (`s` and `v`) have a range of 0 to 100 (inclusive). e.g. `"hsv,300,50,75"` 123 | - Payloads for type "xyz" contain 2 comma separated values of [floats](#float) (`x`, `y`) with a valid range between 0 and 1 (inclusive). The "z" value can be calculated via `z=1-x-y` and is therefore not transmitted. (see [CIE_1931_color_space](https://en.wikipedia.org/wiki/CIE_1931_color_space)). e.g. `"xyz,0.25,0.34"` 124 | - *Note*: The `rgb` and `hsv` formats encode both color and brightness, whereas `xyz` only encodes the color, so; 125 | - when brightness encoding is required: do not use `xyz`, or optionally add another property for the brightness (such that setting `hsv` and `rgb` values changes both the color property and the brightness one if required) 126 | - if color only is encoded: ignore the `v` value in `hsv`, and use the relative colors of `rgb` 127 | eg. `color_only_r = 255 * r / max(r, g, b)`, etc. 128 | - An [empty string](#empty-string-values) ("") is not a valid payload 129 | 130 | ### DateTime 131 | 132 | - DateTime payloads must use the ISO [8601 format](https://en.wikipedia.org/wiki/ISO_8601). 133 | - An [empty string](#empty-string-values) ("") is not a valid payload 134 | 135 | ### Duration 136 | 137 | - Duration payloads must use the [ISO 8601 duration format](https://en.wikipedia.org/wiki/ISO_8601#Durations) 138 | - The format is `PTxHxMxS`, where: 139 | `P`: Indicates a period/duration (required). 140 | `T`: Indicates a time (required). 141 | `xH`: Hours, where `x` represents the number of hours (optional). 142 | `xM`: Minutes, where `x` represents the number of minutes (optional). 143 | `xS`: Seconds, where `x` represents the number of seconds (optional). 144 | - Examples: `PT12H5M46S` (12 hours, 5 minutes, 46 seconds), `PT5M` (5 minutes) 145 | - An [empty string](#empty-string-values) ("") is not a valid payload 146 | 147 | ### JSON 148 | 149 | - Contains a JSON string for transporting complex data formats that cannot be exposed as single value attributes. 150 | - The payload MUST be either a JSON-Array or JSON-Object type, for other types the standard Homie types should be used. 151 | 152 | ## Domain and Root Topic 153 | 154 | The root topic in this convention is `"homie/5/"`. It consists of 2 segments, the first being the homie-domain, 155 | and the second indicating the major version number of this convention. 156 | The homie-domain must be a single segment and defaults to `"homie"`. If it does not suit your needs (in case of, 157 | e.g., a public broker or because of branding), you can change the domain part. The second segment, containing the version, may not be customized. This allows controllers to subscribe to only the devices they are compatible with. 158 | 159 | ## Auto-Discovery 160 | 161 | Homie 5 controllers must by default perform auto-discovery on the wildcard topic `"+/5/+/$state"`. 162 | Controllers are free to restrict discovery to a specific homie-domain, configurable by the user. 163 | A zero length payload published on the `$state` topic indicates a device removal, see [device lifecycle](#device-lifecycle). 164 | 165 | ## Topology and structure 166 | 167 | **Devices:** 168 | Within the convention devices can be modelled to have children. For example, bridge 169 | devices; a zwave bridge device (the parent) exposes many child devices (the 170 | zwave devices). There is no depth limit set on additionally nested children. 171 | 172 | **Nodes:** 173 | A *device* can expose multiple *nodes*. 174 | Nodes are independent or logically separable parts of a device. 175 | For example, a car might expose a `wheels` node, an `engine` node, and a `lights` node. 176 | 177 | **Properties:** 178 | A *node* can have multiple *properties*. 179 | Properties represent basic characteristics of the node, often given as numbers or finite states. 180 | For example, the `wheels` node might expose an `angle` property. 181 | The `engine` node might expose a `speed`, `direction`, and `temperature` property. 182 | The `lights` node might expose an `intensity` and a `color` property. 183 | 184 | **Attributes:** 185 | *Devices, nodes and properties* have specific *attributes* characterizing them. 186 | Attributes are represented by a topic identifier starting with `$`. 187 | The precise definition of attributes is important for the automatic discovery of devices following the Homie convention. 188 | 189 | Examples: A device might have an `IP` attribute, a node will have a `name` attribute, and a property will have a `unit` attribute. 190 | 191 | ### Devices 192 | 193 | * `homie` / `5` / **`[device ID]`**: this is the base topic of a device. 194 | Each device must have a unique device ID that adheres to the [ID format](#topic-ids). 195 | 196 | #### Device Attributes 197 | 198 | The following topic structure will be used to expose the device attributes: 199 | 200 | * `homie` / `5` / `[device ID]` / **`[$device-attribute]`**: 201 | 202 | Devices have the following attributes: 203 | 204 | | Attribute | Required | Description | 205 | |-------------|----------|----------------------------------------------------------------| 206 | | `$state` | yes | Reflects the current state of the device. See [Device Lifecycle](#device-lifecycle) | 207 | | `$description`| yes | The description document (JSON), describing the device, nodes, and properties of this device. **Important**: this value may only change when the device `$state` is either `init`, `disconnected`, or `lost`. | 208 | | `$log` | no | A topic that allows devices to log messages. See [Logging](#logging) | 209 | 210 | The JSON description document is a JSON object with the following fields; 211 | 212 | | Field | Type | Required | Default | Nullable | Description | 213 | |-----------|--------------|----------|---------|----------|-------------| 214 | | `homie` |string | yes | | no | The implemented Homie convention version, without the "patch" level. So the format is `"5.x"`, where the `'x'` is the minor version. | 215 | | `version` | integer | yes | | no | The version of the description document. Whenever the document changes, a new version must be assigned. This does not need to be sequential, eg. a timestamp or a random number could be used. | 216 | | `nodes` |object | no | `{}` | no | The [Nodes](#nodes) the device exposes. An object containing the [Nodes](#nodes), indexed by their [ID](#topic-ids). Defaults to an empty object.| 217 | | `name` |string | no | [device-id] | no | Friendly name of the device. Defaults to the [ID](#topic-ids) of the device. | 218 | | `type` |string | no | | no | Type of Device. Please ensure proper namespacing to prevent naming collisions. | 219 | | `children` |array-strings | no | `[]` | no | Array of [ID](#topic-ids)'s of child devices. Defaults to an empty array.| 220 | | `root` |string | yes/no | | no | [ID](#topic-ids) of the root parent device. **Required** if the device is NOT the root device, MUST be omitted otherwise. | 221 | | `parent` |string | yes/no | same as `root`| no | [ID](#topic-ids) of the parent device. **Required** if the parent is NOT the root device. Defaults to the value of the `root` property. | 222 | | `extensions`|array-strings | no | `[]` | no | Array of supported extensions. Defaults to an empty array.| 223 | 224 | For example, a device with an ID of `super-car` that comprises of a `wheels`, `engine`, and a `lights` node would send: 225 | ```java 226 | homie/5/super-car/$state → "init" 227 | homie/5/super-car/$description → following JSON document; 228 | ``` 229 | ```json 230 | { 231 | "homie": "5.0", 232 | "name": "Supercar", 233 | "version": 7, 234 | "nodes": { 235 | "wheels": { ... }, 236 | "engine": { ... }, 237 | "lights": { ... } 238 | } 239 | } 240 | ``` 241 | 242 | #### Device hierarchy 243 | 244 | Devices can be organized in parent-child relationships. These are expressed via the device 245 | attributes `root`, `parent`, and `children`. In any parent-child tree, there is only one 246 | "root" device, which is the top-level device that has no parent, but only children. 247 | 248 | Example: a ZWave bridge (`id = "bridge"`), which exposes a ZWave device with a dual-relay (`id = "dualrelay"`), 249 | which respectively control Light1 (`id = "light1"`) and Light2 (`id = "light2"`). So there are 4 devices in total. 250 | Then these are the attribute values: 251 | 252 | | | id | children | root | parent | 253 | |--------------|-------------|----------------------|----------|-------------| 254 | | Zwave bridge | "bridge" | ["dualrelay"] | | | 255 | | Zwave relay | "dualrelay" | ["light1", "light2"] | "bridge" | | 256 | | First light | "light1" | | "bridge" | "dualrelay" | 257 | | Second light | "light2" | | "bridge" | "dualrelay" | 258 | 259 | To monitor the state of child devices in this tree 2 topic subscriptions are needed. The `$state` attribute of the device itself, as well as the `$state` attribute of its root device. 260 | Because if the root device loses its connection to the MQTT server, the last will (LWT), will set its `$state` attribute to `"lost"`, but it will not update the child-device states. Hence the need for 2 topic subscriptions. 261 | 262 | The `state` of any device should be determined as follows: 263 | | has a `root` set | `root` state | device state | 264 | |------------------|--------------|--------------| 265 | | no | n.a. | device state is the `$state` attribute of the device itself 266 | | yes | not `"lost"` | device state is the `$state` attribute of the device itself 267 | | yes | `"lost"` | device state is `"lost"` (`$state` attribute of the root device) 268 | 269 | 270 | #### Device Lifecycle 271 | 272 | The `$state` device attribute represents the current state of the device. A device exists once a valid value is set in the `$state` attribute. It doesn't mean the device is complete and valid (yet), but it does mean it exists. 273 | 274 | There are 5 possible state values: 275 | 276 | * **`init`**: this is the state the device is in when it is connected to the MQTT broker, but has not yet sent all Homie messages and is not yet ready to operate. 277 | This state is optional and may be sent if the device takes a long time to initialize, but wishes to announce to consumers that it is coming online. 278 | A device may fall back into this state to do some reconfiguration. 279 | * **`ready`**: this is the state the device is in when it is connected to the MQTT broker and has sent all Homie messages describing the device attributes, nodes, properties, and their values. The device has subscribed to all appropriate `/set` topics and is ready to receive messages. 280 | * **`disconnected`**: this is the state the device is in when it is cleanly disconnected from the MQTT broker. 281 | You must send this message before cleanly disconnecting. 282 | * **`sleeping`**: this is the state the device is in when the device is sleeping. 283 | You have to send this message before sleeping. 284 | * **`lost`**: this is the state the device is in when the device has been "badly" disconnected. **Important**: If a root-device `$state` is `"lost"` then the state of **every child device in its tree** is also `"lost"`. 285 | You must define this message as the last will (LWT) for root devices. 286 | 287 | In order to permanently remove a device the following steps should be performed in order: 288 | 1. remove the retained `$state` attribute from the broker by publishing a zero length payload message to its topic. The device will cease to exist. 289 | 2. any other retained attributes or property values should be cleared via the same method afterwards. 290 | 291 | ### Nodes 292 | 293 | * `homie` / `5` / `[device ID]` / **`[node ID]`**: this is the base topic of a node. 294 | Each node must have a unique node ID on a per-device basis which adheres to the [ID format](#topic-ids). 295 | 296 | #### Node Attributes 297 | 298 | There are no node attributes in MQTT topics for this level. 299 | 300 | The Node object itself is described in the `homie` / `5` / `[device ID]` / `$description` JSON document. The Node object has the following fields: 301 | 302 | | Field | Type | Required | Default | Nullable | Description | 303 | |-------------|--------------|----------|---------|----------|-------------| 304 | | `name` |string | no | [node-id] | no | Friendly name of the Node. Defaults to the [ID](#topic-ids) of the node. | 305 | | `type` |string | no | | no | Type of Node. Please ensure proper namespacing to prevent naming collisions. | 306 | | `properties`|object | no | `{}` | no | The [Properties](#properties) the Node exposes. An object containing the [Properties](#properties), indexed by their [ID](#topic-ids). Defaults to an empty object.| 307 | 308 | For example, our `engine` node would look like this: 309 | 310 | ```json 311 | ... 312 | "engine": { 313 | "name": "Car engine", 314 | "properties": { 315 | "speed": { ... }, 316 | "direction": { ... }, 317 | "temperature": { ... } 318 | } 319 | } 320 | ... 321 | ``` 322 | 323 | ### Properties 324 | 325 | * `homie` / `5` / `[device ID]` / `[node ID]` / **`[property ID]`**: this is the base topic of a property. 326 | Each property must have a unique property ID on a per-node basis which adheres to the [ID format](#topic-ids). 327 | 328 | #### Property Attributes 329 | 330 | | Attribute | Required | Description | 331 | |-----------|----------|----------------------------------------------------------------| 332 | | | yes | A property value (e.g. a sensor reading) is directly published to the property topic, e.g.: `homie/5/super-car/engine/temperature → "21.5"` | 333 | | `$target` | no | Describes an intended state change. The `$target` attribute must either be used for every value update (including the initial one), or it must never be used. | 334 | 335 | The Property object itself is described in the `homie` / `5` / `device ID` / `$description` JSON document. The Property object has the following fields: 336 | 337 | | Field | Type | Required | Default | Nullable | Description | 338 | |-----------|--------------|----------|----------|----|---------| 339 | | `name` | string | no | [property-id] | no | Friendly name of the Property. Defaults to the [ID](#topic-ids) of the property. | 340 | | `datatype`| string | yes | | no | The data type. See [Payloads](#payload). Any of the following values: `"integer", "float", "boolean", "string", "enum", "color", "datetime", "duration", "json"`. | 341 | | `format` | string | see [formats](#formats) | see [formats](#formats) | no | Specifies restrictions or options for the given data type. | 342 | | `settable`| boolean | no | `false` | no | Whether the Property is settable. | 343 | | `retained`| boolean | no | `true` | no | Whether the Property is retained. | 344 | | `unit` | string | no | | no | Unit of this property. See [units](#units). | 345 | 346 | 347 | For example, our `temperature` property would look like this in the device/node description document: 348 | 349 | ```json 350 | ... 351 | "temperature": { 352 | "name": "Engine temperature", 353 | "unit": "°C", 354 | "datatype": "float", 355 | "format": "-20:120" 356 | } 357 | ... 358 | ``` 359 | And the following MQTT topic with the reported property value: 360 | ```java 361 | homie/5/super-car/engine/temperature → "21.5" 362 | ``` 363 | 364 | #### Settable and retained properties 365 | 366 | Properties can be **settable** and/or **retained**. For example, you don't want your `temperature` 367 | property to be settable in case of a temperature sensor (like the car example), but it should be 368 | settable in the case of a thermostat setpoint. 369 | 370 | A property is retained by default. A non-retained property would be useful for momentary events 371 | (e.g. doorbell pressed). See also [QoS settings](#qos-and-retained-messages). 372 | 373 | A combination of the **settable** and **retained** flags compiles into this list: 374 | 375 | | retained | settable | description | 376 | |----------|----------|-------------| 377 | | yes | yes | The node publishes a property state and can receive commands for the property (by a controller or other party) (lamp power) 378 | | yes | no | (**default**) The node publishes a property state (temperature sensor) 379 | | no | yes | The node publishes momentary events and can receive commands for the property from a controller (brew coffee) 380 | | no | no | The node publishes momentary events (doorbell pressed) 381 | 382 | 383 | #### Formats 384 | 385 | The format attribute specifies restrictions or options for the given data type. User interfaces can derive hints from 386 | the formats for displaying values. 387 | 388 | | Type | Required | Default | Description | 389 | |--------------|----------|----------|-------------| 390 | | float | no | `:` | `[min]:[max][:step]` where min and max are the respective minimum and maximum (inclusive) allowed values, both represented in the format for [float types](#float). Eg. `10.123:15.123`. If the minimum and/or maximum are missing from the format, then they are open-ended, so `0:` allows a value >= 0.
The optional `step` determines the step size, eg. `2:6:2` will allow values `2`, `4`, and `6`. It must be greater than 0. See notes below this table on calculations. | 391 | | integer | no | `:` | `[min]:[max][:step]` where min and max are the respective minimum and maximum (inclusive) allowed values, both represented in the format for [integer types](#integer). Eg. `5:35`. If the minimum and/or maximum are missing from the format, then they are open-ended, so `:10` allows a value <= 10.
The optional `step` determines the step size, eg. `2:6:2` will allow values `2`, `4`, and `6`. It must be greater than 0. See notes below this table on calculations. | 392 | | enum | yes | | A comma-separated list of non-quoted values. Eg. `value1,value2,value3`. Leading- and trailing whitespace is significant. Individual values can not be an empty string, hence at least 1 value must be specified in the format. Duplicates are not allowed. | 393 | | color | yes | | A comma-separated list of color formats supported; `rgb`, `hsv`, and/or `xyz`. The formats should be listed in order of preference (most preferred first, least preferred last). See the [color type](#color) for the resulting value formats. E.g. a device supporting RGB and HSV, where RGB is preferred, would have its format set to `"rgb,hsv"`. | 394 | | boolean | no | `false,true` | Identical to an enum with 2 entries. The first represents the `false` value and the second is the `true` value. Eg. `close,open` or `off,on`. If provided, then both entries must be specified. **Important**: the format does NOT specify valid payloads, they are descriptions of the valid payloads `false` and `true`. | 395 | | json | no | `{\"anyOf\": [{\"type\": \"array\"},{\"type\": \"object\"}]}` | A [JSONschema](https://json-schema.org/) definition, which is added as a string (escaped), NOT as a nested json-object. See [JSON considerations](#json-considerations), for some ideas wrt compatibility. If a client fails to parse/compile the JSONschema, then it should ignore the given schema and fall back to the default schema. 396 | 397 | **Note on numeric formats and step-sizes**: 398 | 399 | The base for calculating a proper value based on `step` should be `min`, `max`, or the current property value (in that order). The implementation should round property values to the nearest step (which can be outside the min/max range). The min/max validation must be done after rounding. In case of integers, the input MUST already be a valid integer, before rounding to a step. 400 | 401 | There is a caveat when rounding towards a step: if the value to be rounded, is less than the base then the intermediate values might round differently since proper mathematical rounding is done "away from 0". A positive 1.5 rounds to 2 (so up), and negative -1.5 rounds to -2 (so down), but both round "away from 0". Example showing the unexpected effect: 402 | 403 | input | format | result | explanation 404 | -|-|-|- 405 | `5` | `"0:10:2"` | `6` | base = 0; result = round((5-base)/stepsize) * stepsize + base = 6 406 | `5` | `":10:2"` | `4` | base = 10; result = round((5-base)/stepsize) * stepsize + base = 4 407 | 408 | To mitigate this do not use `round(x)`, but use `floor(x + 0.5)` instead. Such that rounding always goes up: 409 | 410 | input | format | result | explanation 411 | -|-|-|- 412 | `5` | `"0:10:2"` | `6` | base = 0; result = floor((5-base)/stepsize + 0.5) * stepsize + base = 6 413 | `5` | `":10:2"` | `6` | base = 10; result = floor((5-base)/stepsize + 0.5) * stepsize + base = 6 414 | 415 | 416 | #### Units 417 | 418 | Recommended unit strings: 419 | 420 | * `°C`: Degree Celsius (see 'Degree' for encoding) 421 | * `°F`: Degree Fahrenheit (see 'Degree' for encoding) 422 | * `°`: Degree 423 | * Character '°' is [Unicode: `U+00B0`](https://www.compart.com/en/unicode/U+00B0), Hex: `0xc2 0xb0`, Dec: `194 176` 424 | * `L`: Liter 425 | * `gal`: Gallon 426 | * `V`: Volts 427 | * `W`: Watt 428 | * `kW`: Kilowatt 429 | * `kWh`: Kilowatt-hour 430 | * `A`: Ampere 431 | * `Hz`: Hertz 432 | * `rpm`: Revolutions per minute 433 | * `%`: Percent 434 | * `m`: Meter 435 | * `m³`: Cubic meter 436 | * Character '³' is [Unicode: `U+00B3`](https://www.compart.com/en/unicode/U+00B3), Hex: `0xc2 0xb3`, Dec: `194 179` 437 | * `ft`: Feet 438 | * `m/s`: Meters per Second 439 | * `kn`: Knots 440 | * `Pa`: Pascal 441 | * `psi`: PSI 442 | * `ppm`: Parts Per Million 443 | * `s`: Seconds 444 | * `min`: Minutes 445 | * `h`: Hours 446 | * `lx`: Lux 447 | * `K`: Kelvin 448 | * `MK⁻¹`: Mired 449 | * Character '⁻' is [Unicode: `U+207B`](https://www.compart.com/en/unicode/U+207B), Hex: `0xe2 0x81 0xbb`, Dec: `226 129 187` 450 | * Character '¹' is [Unicode: `U+00B9`](https://www.compart.com/en/unicode/U+00B9), Hex: `0xc2 0xb9`, Dec: `194 185` 451 | * `#`: Count or Amount 452 | 453 | The non-ASCII characters are specified as Unicode codepoints and the UTF-8 byte sequence that represents them. Since the same characters can be created in many visually similar ways it is important to stick to the exact byte sequences to enable proper interoperability. 454 | 455 | You are not limited to the recommended values, although they are the only well known ones that will have to be recognized by any Homie consumer. 456 | 457 | #### Target attribute 458 | 459 | The `$target` attribute for properties allows a device to communicate an intended state change of a property. This serves 2 main 460 | purposes; 461 | 462 | 1. closing the control loop for a controller setting a value (if the property is settable). 463 | 2. feedback in case a change is not instantaneous (e.g. a light that slowly dimms over a longer period, or a 464 | motorized valve that takes several minutes to fully open) 465 | 466 | If implemented, then a device must first update the `$target` attribute, then start the transition (with 467 | optional state-value updates during the transition), and when done update the property value to match the 468 | `$target` value (functional equivalent, not necessarily a byte-by-byte equality). 469 | 470 | If a new target is received (and accepted) from a controller by publishing to the property's `set` topic, then the exact value received must be published to the `$target` topic (byte-by-byte equality). To allow for closing the control loop. 471 | 472 | **Notes:** 473 | 474 | - a controller can only assume that the command it send to the `set` topic was received and accepted. Not necessarily that it will ever reach the target state, since if another controller updates the property again, it might never reach the target state. 475 | - The same goes for possible conversions (colors), rounding (number formats), etc. it will be very hard to check functional equivalence, since the value published may have a different format. So a controller should NOT implement a retry loop checking the final value. At best they should implement retries until the value set is being accepted. 476 | - Homie devices representing remote hardware (typically when bridging) should NOT set the `$target` attribute upon receiving a change from the hardware device. This is only allowed if the hardware explicitly distinguishes between current value and target value. This is to prevent a loop; e.g. a homie controller sets 100% as target, software instructs hardware to change, intermediate updates received from hardware; 20%, 40%, etc, should NOT overwrite the `$target` value, since that still is 100. 477 | 478 | 479 | #### Property command topic 480 | 481 | * `homie` / `5` / `[device ID]` / `[node ID]` / `[property ID]` / **`set`**: The device must subscribe to this topic if the property is **settable** (in the case of actuators for example). 482 | 483 | A Homie controller publishes to the `set` command topic with non-retained messages only. See [retained messages](#qos-and-retained-messages). 484 | 485 | The assigned and processed payload must be reflected by the Homie device in the property topic `homie` / `5` / `[device ID]` / `[node ID]` / `[property ID]` or target attribute `homie` / `5` / `[device ID]` / `[node ID]` / `[property ID]` / `$target` as soon as possible. 486 | This property state update not only informs other devices about the change but closes the control loop for the commanding controller, important for deterministic interaction with the client device. 487 | 488 | To give an example: A `kitchen-light` device exposing the `light` node with a settable `power` property subscribes to the topic `homie/5/kitchen-light/light/power/set` for commands: 489 | 490 | ```java 491 | homie/5/kitchen-light/light/power/set ← "true" 492 | ``` 493 | 494 | In response, the device will turn on the light and upon success update its `power` property state accordingly: 495 | 496 | ```java 497 | homie/5/kitchen-light/light/power → "true" 498 | ``` 499 | 500 | If the `light` were a dimmable light with a `brightness` property (0-100%), and it would be set to slowly dim over 5 seconds, then the `$target` attribute can be used (assuming once per second updates); 501 | 502 | ```java 503 | homie/5/kitchen-light/light/brightness/set ← 100 504 | homie/5/kitchen-light/light/brightness/$target → 100 505 | homie/5/kitchen-light/light/brightness → 20 (after 1 second) 506 | homie/5/kitchen-light/light/brightness → 40 (after 2 seconds) 507 | homie/5/kitchen-light/light/brightness → 60 (after 3 seconds) 508 | homie/5/kitchen-light/light/brightness → 80 (after 4 seconds) 509 | homie/5/kitchen-light/light/brightness → 100 (after 5 seconds) 510 | ``` 511 | 512 | ## Alert topic 513 | 514 | Devices can raise alerts. Alerts are user facing messages that have an ID, they can be set and removed. 515 | The alert topic is defined as; 516 | 517 | * `homie` / `5` / `[device ID]` / `$alert` / `[alert ID]` → "alert message" 518 | 519 | A device can raise a message on a specific ID. Once the alert is no longer usefull or has been resolved, it can be removed by deleting the topic. Alerts must be send as retained messages. The alert ID must have a valid [ID format](#topic-ids), where topic ID's starting with `$` are reserved for Homie usage. 520 | 521 | Examples; 522 | ```java 523 | /homie/5/mydevid/$alert/childlost = "Sensor xyz in livingroom hasn't reported updates for 3 hours" 524 | /homie/5/mydevid/$alert/battery = "Battery is low, at 8%" 525 | ``` 526 | 527 | In the examples above, once the situation is resolved (the sensor comes back to live, or the batteries are replaced), the device will delete the topics again, indicating the alerts have been handled. 528 | 529 | ## Broadcast Topic 530 | 531 | Homie defines a broadcast topic, so a controller can broadcast a message to all Homie devices: 532 | 533 | * `homie` / `5` / `$broadcast` / **`[subtopic]`**: where `subtopic` can be any topic with single or multiple levels. Each segement must adhere to the [ID format](#topic-ids). 534 | 535 | The messages SHOULD be non-retained. 536 | 537 | For example, you might want to broadcast an `alert` event with the alert reason as the payload. 538 | Devices are then free to react or not. 539 | In our case, every buzzer of your home automation system would start buzzing. 540 | 541 | ```java 542 | homie/5/$broadcast/alert ← "Intruder detected" 543 | homie/5/$broadcast/security/alert ← "Intruder detected" 544 | ``` 545 | 546 | ## Logging 547 | 548 | Since devices may be resource constraint they might not have logging capabilities. Homie provides a specific 549 | topic where devices can send log messages. The topic is defined as; 550 | 551 | * `homie` / `5` / `[device ID]` / `$log` / `[level]` 552 | 553 | The topic-value is the logged message, no sub-topics are allowed. 554 | All log messages send should be non-retained. 555 | The `level` is set according to the following table: 556 | 557 | level | description 558 | --------|------------ 559 | `debug` | detailed information for troubleshooting purposes 560 | `info` | informational message, device is working as expected 561 | `warn` | something potentially harmful happened 562 | `error` | an error happened, the device will continue to operate but functionality might be impaired 563 | `fatal` | a non-recoverable error occured, operation of the device is likely suspended/stopped 564 | 565 | ```java 566 | homie/5/my-device/$log/warn → "battery low" 567 | homie/5/my-device/$log/error → "sensor value is out of range" 568 | ``` 569 | 570 | Note that MQTT is not meant to be a logging solution, and hence it should be used with care. The implementation should 571 | try and limit the traffic on the MQTT bus. If devices implement messages and levels that can be "noisy", then the 572 | device should provide a configuration option to turn them off, to limit the bandwidth consumed. 573 | 574 | ## Extensions 575 | 576 | This convention only covers the discoverability of devices and their capabilities. 577 | The aim is to have standardized MQTT topics for all kinds of complex scenarios. 578 | A Homie device may therefore support extensions, defined in separate documents. 579 | Every extension is identified by a unique ID. 580 | 581 | The ID consists of the reverse domain name and a freely chosen suffix. 582 | The proper term `homie` is reserved and must not be used as a suffix or as part of the domain name. 583 | 584 | For example, an organization `example.org` wanting to add a feature `our-feature` would choose the extension ID `org.example.our-feature`. 585 | 586 | Every extension must be published using a license. 587 | The license can be chosen freely, even proprietary licenses are possible. 588 | The recommended license is the [CCA 4.0](https://homieiot.github.io/license) since this is the license Homie itself uses. 589 | 590 | 591 | ## Implementation notes 592 | 593 | ### Device initialization 594 | 595 | Some devices require knowledge of their settable retained properties to function properly. 596 | The homie convention does not specify how to initialize/recover them e.g. after a power cycle. 597 | A few common approaches are: 598 | 599 | * A device can simply load default values from some configuration file. 600 | * A device can restore its previous state from some local storage. This is the recommended way. 601 | * A device may try to restore its state using MQTT. This can be done by subscribing to the respective channels. 602 | The controller could set all properties of a device once it becomes `ready`. 603 | An alternative way is to recover the state from other MQTT channels that are external to the Homie specification. 604 | * If a property is not critical for correctly functioning, there is no need to recover it. 605 | 606 | ### Device reconfiguration 607 | 608 | If a device wishes to modify any of its nodes or properties, it can 609 | 610 | * disconnect and reconnect with other values, or 611 | * set `$state=init` and then modify any of the attributes. 612 | 613 | Devices can remove old properties and nodes by deleting the respective MQTT topics by publishing an empty message 614 | to those topics (an actual empty string on MQTT level, so NOT the escaped `0x00` byte, see also [empty string values](#empty-string-values)). 615 | 616 | When adding many child devices, implementations should take care of not publishing too many parent-updates, since every controller would have to parse the description again and again. 617 | 618 | #### Adding children 619 | 620 | The recommended way to add child device is as follows: 621 | 622 | 1. first publish any child-devices, as any other device 623 | 1. set child-device state to `"init"` 624 | 1. publish child-device details (including parent details in `root` and `parent` fields) 625 | 1. set child-device state to `"ready"` 626 | 1. update the parent device, as any other change 627 | 1. set parent state to `"init"` 628 | 1. update parent description (add any child IDs to its `children` array) 629 | 1. set parent state to `"ready"` 630 | 631 | Be aware that due to MQTT message ordering the consistency at any stage in this process cannot be guaranteed. 632 | 633 | #### Removing children 634 | 635 | The recommended way to remove child device is as follows: 636 | 637 | 1. update the parent device 638 | 1. set parent state to `"init"` 639 | 1. update parent description (remove any child IDs from its `children` array) 640 | 1. set parent state to `"ready"` 641 | 1. clear any child-device(s) topics, starting with the `$state` topic 642 | 643 | Be aware that due to MQTT message ordering the consistency at any stage in this process cannot be guaranteed. 644 | 645 | ### Versioning 646 | 647 | Some considerations related to versioning in this specification; 648 | 649 | * compatibility is assumed to be major version only, so version 5 for this spec. 650 | * the base topic includes the major version. This allows controllers to only subscribe to devices they are 651 | compatible with. 652 | 653 | #### Backward compatibility 654 | 655 | * backward compatibility: a v5 controller controlling a v5 device with a smaller minor version. Eg. a v5.3 656 | controller sending commands to a v5.0 device. 657 | * Controllers should be aware of unsupported features in older major or minor versions they subscribe to because the spec for that version is known. 658 | 659 | #### Forward compatibility 660 | 661 | * forward compatibility: a v5 controller controlling a v5 device with a higher minor version. Eg. a v5.0 662 | controller sending commands to a v5.2 device. 663 | * Controllers should ignore unknown fields, properties, attributes, etc. within an object (device, node, or property), but keep the object itself. 664 | * Controllers should ignore the entire object (device, node, or property) if in a known field, property, or attribute an illegal value is encountered. For example; 665 | * illegal characters in a topic or name 666 | * unknown data type 667 | * unknown/illegal format 668 | * required element missing 669 | 670 | ### JSON considerations 671 | 672 | Validation of JSON payloads is hard. The most common approach to validate JSON data is to use [JSONschema](https://json-schema.org/). 673 | Unfortunately JSONschema is not a standard, it is a long list of mostly incompatible drafts of a potential standard. And as such one 674 | has to take into account the potential differences in implementations. This is about the JSONschema specifics itself as well as its reliance on RegEx engines for string validations, which are also known to be riddled with incompatibilities (typically language/platform specific). 675 | 676 | The most popular JSONschema versions over time tend to be [`draft 4`](https://json-schema.org/specification-links.html#draft-4), [`draft 7`](https://json-schema.org/specification-links.html#draft-7) and the latest (at the time of writing) [`2020-12`](https://json-schema.org/specification-links.html#2020-12). 677 | 678 | General recommendations; 679 | - If possible use a library that implements the latest JSONschema version available 680 | - When writing schema's make sure they are compatible with the popular versions mentioned above 681 | - Try to avoid RegEx'es, if you have to use them, then; 682 | - restrict them to character classes and modifiers (`"+", "-", "*", "?"`) 683 | - do not use back-tracking and OR (`"|"`) constructs (the OR construct can typically be handled on the JSONschema level using an `anyOf` construct) 684 | - If a device fails to parse the JSONschema, or a RegEx, then by default it should skip validation and assume the payload is valid. 685 | 686 | ### QoS choices explained 687 | 688 | The nature of the Homie convention makes it safe about duplicate messages, so QoS levels for reliability **At least once (QoS 1)** 689 | and **Exactly once (QoS 2)** should both be fine. The recommended level is **Exactly once (QoS 2)**, since a resend on QoS 1 might have a different order, and hence is slightly less reliable, in case another device sends a new message that lands in between the 'send' and 'resend' of the first message. However, the probability of that happening is most likely negligible. 690 | 691 | Keep in mind that if you change the QoS level to **At least once (QoS 1)**, then it should be done so for the entire Homie network. 692 | Because the MQTT order will not hold if the QoS levels of messages are different. That said; anyone who accepts the lesser reliability of 693 | **At least once (QoS 1)**, will most likely also not care about the potential ordering issue of mixed QoS levels. 694 | 695 | For **non-retained** properties the QoS level is **At most once (QoS 0)** to ensure that events don't arrive late or multiple times. Because the events and commands are time-sensitive. With **At most once (QoS 0)** messages will not be queued by the broker for delivery if the subscriber (a device or controller) is currently disconnected. Which effectively translates to "either you get it now, or you don't get it at all". 696 | -------------------------------------------------------------------------------- /extensions/documents/homie_legacy_firmware_extension.md: -------------------------------------------------------------------------------- 1 | # Legacy Firmware 2 | 3 | Version: **0.1.1** 4 | Date: **12. Jul 2019** 5 | Authors: **The Homie Community** 6 | License: **[CCA 4.0](https://homieiot.github.io/license)** 7 | 8 | ## Abstract 9 | This extension adds the firmware, mac and localip device attributes of Homie `3.0.1` to Homie `4.0`. 10 | 11 | Version `3.0.1` of the Homie Convention specifies some required device attributes. 12 | Newer versions on the other hand, do not specify them. 13 | If a device of a newer Homie version implements this extension, the above mentioned attributes are backwards-compatible to older Homie versions. 14 | Respectively, these attributes of an older device can be made Homie `4.0` compliant, by simply advertising this extension as implemented. 15 | By doing this, these legacy attribute can be kept, and the device doesn't have to be altered much. 16 | In addition to this extension, a second extension, [Legacy Stats](https://github.com/homieiot/convention/blob/develop/extensions/documents/homie_legacy_stats_extension.md) exists. 17 | If this extension is implemented, too, not only the firmware attributes are backwards-compatible, but the whole device. 18 | 19 | ## Homie Version 20 | This extension supports Homie `4.x`. 21 | 22 | ## Extension Identifier 23 | The ID of this extension is `org.homie.legacy-firmware`. 24 | Therefore the **$extensions entry** is `org.homie.legacy-firmware:0.1.1:[4.x]`. 25 | 26 | ## Extension Datatypes 27 | This extension defines no new datatypes. 28 | 29 | ## Extension Attributes 30 | 31 | ### Device Attributes 32 | 33 | This extension defines **no optional** and **two required** direct device attributes: 34 | 35 | | Topic | Description | Payload type | 36 | |----------|-------------------------------------------------------------------------------------------------|-----------------| 37 | | $localip | IP of the device on the local network | String | 38 | | $mac | Mac address of the device network interface; The format MUST be of the type `A1:B2:C3:D4:E5:F6` | String | 39 | 40 | **Examples** 41 | Assuming the base topic is *homie* and device ID is *super-car* then: 42 | ```java 43 | homie/super-car/$localip → "192.168.0.10" 44 | homie/super-car/$mac → "DE:AD:BE:EF:FE:ED" 45 | ``` 46 | 47 | #### Nested Device Attributes 48 | 49 | This extension defines one nested device attribute. 50 | 51 | ##### $fw 52 | 53 | The **$fw** nesting attribute is **required**. 54 | 55 | It defines **no optional** and **two required** nested attributes: 56 | 57 | | Topic | Description | Payload type | 58 | |-------------|----------------------------------------------------------------------------------------------|--------------| 59 | | $fw/name | Name of the firmware running on the device; Allowed characters are the same as the device ID | String | 60 | | $fw/version | Version of the firmware running on the device | String | 61 | 62 | **Examples** 63 | Assuming the base topic is *homie* and device ID is *super-car* then: 64 | ```java 65 | homie/super-car/$fw/name → "weatherstation-firmware" 66 | homie/super-car/$fw/version → "1.0.0" 67 | ``` -------------------------------------------------------------------------------- /extensions/documents/homie_legacy_stats_extension.md: -------------------------------------------------------------------------------- 1 | # Legacy Stats 2 | 3 | Version: **0.1.1** 4 | Date: **12. Jul 2019** 5 | Authors: **The Homie Community** 6 | License: **[CCA 4.0](https://homieiot.github.io/license)** 7 | 8 | ## Abstract 9 | This extension adds the stats functionality of Homie `3.0.1` to Homie `4.0`. 10 | 11 | Version `3.0.1` of the Homie Convention specifies, how device stats should be published. 12 | The community decided, that in subsequent versions of the convention, this feature should be optional, 13 | so it was removed from the convention and decided to offer it as extension (see [issue 102](https://github.com/homieiot/convention/issues/102)). 14 | If a device of a newer Homie version implements this extension, the stats of the device are backwards-compatible to older Homie versions. 15 | Respectively, the *$stats* attribute of an older device can be made Homie `4.0` compliant, by simply advertising this extension as implemented. 16 | By doing this, the legacy *$stats* attribute can be kept, and the device doesn't have to be altered much. 17 | In addition to this extension, a second extension, [Legacy Firmware](https://github.com/homieiot/convention/blob/develop/extensions/documents/homie_legacy_firmware_extension.md) exists. 18 | If this extension is implemented, too, not only the stats are backwards-compatible, but the whole device. 19 | 20 | ## Homie Version 21 | This extension supports Homie `4.x`. 22 | 23 | ## Extension Identifier 24 | The ID of this extension is `org.homie.legacy-stats`. 25 | Therefore the **$extensions entry** is `org.homie.legacy-stats:0.1.1:[4.x]`. 26 | 27 | ## Extension Datatypes 28 | This extension defines no new datatypes. 29 | 30 | ## Extension Attributes 31 | 32 | ### Device Attributes 33 | 34 | This extension defines no direct device attributes. 35 | 36 | #### Nested Device Attributes 37 | 38 | This extension defines one nested device attribute. 39 | 40 | ##### $stats 41 | The **$stats** nesting attribute is **required**. 42 | 43 | It defined **two required** nested attributes: 44 | 45 | | Topic | Description | Payload type | 46 | |-----------------|-------------------------------------------------------------------------|----------------------------| 47 | | $stats/interval | Interval in seconds at which the device refreshes its `$stats/+` | Positive Integer greater 0 | 48 | | $stats/uptime | Time elapsed in seconds since the boot of the device | Positive Integer | 49 | 50 | **Examples** 51 | Assuming the base topic is *homie* and device ID is *super-car* then: 52 | ```java 53 | homie/super-car/$stats/interval → "60" 54 | homie/super-car/$stats/uptime → "120" 55 | ``` 56 | Every *$stats/interval* the device MUST publish new values for each implemented nested **$stats** attribute (except *$stats/interval* itself). 57 | This includes the required *$stats/uptime*. 58 | The following **optional** nested stats attributes exists. If they where used once, they also MUST be refreshed: 59 | 60 | | Topic | Description | Payload type | 61 | |-----------------|---------------------------------------------------------------------|------------------| 62 | | $stats/signal | Signal strength in % | Integer | 63 | | $stats/cputemp | CPU Temperature in °C | Float | 64 | | $stats/cpuload | CPU Load in %. Average of last *$stats\interval* including all CPUs | Integer | 65 | | $stats/battery | Battery level in % | Integer | 66 | | $stats/freeheap | Free heap in bytes | Positive Integer | 67 | | $stats/supply | Supply Voltage in V | Float | -------------------------------------------------------------------------------- /extensions/documents/homie_meta_extension.md: -------------------------------------------------------------------------------- 1 | # Meta 2 | 3 | Version: **1.1.0** 4 | Date: **12. Jul 2019** 5 | Authors: **[EPNW](https://epnw.eu)** 6 | License: **[CCA 4.0](https://homieiot.github.io/license)** 7 | 8 | ## Abstract 9 | This extension defines how to add metadata and tags to devices, nodes and properties. 10 | 11 | Tags are simple annotations that every device, node or property can have. 12 | Metadata on the other hand are more complex. They allow the definition of multiple *mainkeys* and *mainvalues* for each device, node or property. 13 | Each main-key-value-pair may have nested sub-key-value-pairs. 14 | Having metadata might be useful for Homie controllers. 15 | A concrete usecase is the openHAB controller, which relies on metadata and tags to make voice assistants like Amazons Alexa or the Google Assistant able to control it. 16 | With this extension, properties are able to advertise how they want to be treated. 17 | 18 | ## Homie Version 19 | This extension supports Homie `3.0.1` and `4.x`. 20 | 21 | ## Extension Identifier 22 | The ID of this extension is `eu.epnw.meta`. 23 | Therefore the **$extensions entry** is `eu.epnw.meta:1.1.0:[3.0.1;4.x]`. 24 | 25 | ## Extension Datatypes 26 | This extension defines no new datatypes. 27 | 28 | ## Extension Attributes 29 | 30 | ### Extension Attributes for any kind of Items 31 | 32 | The following attributes are all **optional** and may be added to any kind of item (devices, nodes or properties). 33 | 34 | | Topic | Description | Payload type | Default value| 35 | |----------------------|-----------------------------|----------------------------|--------------| 36 | | $tags | List of *tags* for the item | Comma (`,`) separated list | | 37 | | $meta/$mainkey-ids | List of IDs for *mainkeys* | Comma (`,`) separated list | | 38 | 39 | Since *tags* are represented by a comma separated list, a limitation is that a tag itself MUST NOT contain a comma. 40 | The elements in the `$mainkey-ids` list are **not** the names of the keys. 41 | Instead, these entries are just used for topic IDs. 42 | Therefore, the entries have to be valid topic IDs (see [the Homie convention](https://homieiot.github.io/specification/#topic-ids))! 43 | 44 | **Examples** 45 | Assuming the base topic is *homie*, device ID is *super-car*, the node is *engine* and the property is *temperature* then: 46 | ```java 47 | homie/super-car/engine/temperature/$meta/$mainkey-ids → "alexa,homekit" 48 | homie/super-car/engine/temperature/$tags → "Lighting,Switchable,Thermostat" 49 | ``` 50 | 51 | For each element in the `$mainkey-ids` list, two nested attributes are **required**: 52 | 53 | | Topic | Description | Payload type | 54 | |---------------------------|-----------------------------------|--------------| 55 | | $meta/*mainkey id*/$key | The *mainkey*s name | String | 56 | | $meta/*mainkey id*/$value | The *mainvalue* for the *mainkey* | String | 57 | 58 | **Examples** 59 | With respect to the previous example: 60 | ```java 61 | homie/super-car/engine/temperature/$meta/homekit/$key → "HomeKit" 62 | homie/super-car/engine/temperature/$meta/homekit/$value → "Fan.v2" 63 | homie/super-car/engine/temperature/$meta/alexa/$key → "Alexa" 64 | homie/super-car/engine/temperature/$meta/alexa/$value → "Fan" 65 | ``` 66 | 67 | Notice that in this example, the *mainkey ids* are *alexa* and *homekit*, but the actual key names are *Alexa* and *HomeKit*. 68 | 69 | A *mainkey* can have an arbitrary number of *subkeys*. 70 | Analogous to how *mainkeys* are advertised, each *mainkey* may have an **optional** list of *subkey ids*: 71 | 72 | | Topic | Description | Payload type | Default value | 73 | |-------------------------------|--------------------------------------------|--------------|---------------| 74 | | $meta/*mainkey id*/$subkey-ids | List of IDs for *subkeys* | Comma (`,`) separated list | | 75 | 76 | Again, elements in the `$subkey-ids` list are **not** the names of the keys, and have to be valid topic IDs. 77 | 78 | **Examples** 79 | With respect to the previous example: 80 | ```java 81 | homie/super-car/engine/temperature/$meta/alexa/$subkey-ids → "type,step-speed" 82 | ``` 83 | 84 | For each element in the `$subkey-ids` list, two nested attributes are **required**: 85 | 86 | | Topic | Description | Payload type | 87 | |---------------------------------------|--------------------------------------|--------------| 88 | | $meta/*mainkey id*/*subkey id*/$key | The *subkey*s name | String | 89 | | $meta/*mainkey id*/*subkey id*/$value | Value for the *subkey* | String | 90 | 91 | 92 | **Examples** 93 | With respect to the previous example: 94 | ```java 95 | homie/super-car/engine/temperature/$meta/alexa/type/$key → "type" 96 | homie/super-car/engine/temperature/$meta/alexa/type/$value → "oscillating" 97 | homie/super-car/engine/temperature/$meta/alexa/step-speed/$key → "stepSpeed" 98 | homie/super-car/engine/temperature/$meta/alexa/step-speed/$value → "3" 99 | ``` 100 | -------------------------------------------------------------------------------- /extensions/extension_template.md: -------------------------------------------------------------------------------- 1 | # Name of the Extension 2 | 3 | Version: **x.x.x** 4 | Date: **01. Jan 2000** 5 | Authors: **Your Name or Organization** 6 | License: **[CCA 4.0](https://homieiot.github.io/license)** 7 | 8 | ## Abstract 9 | The abstract of an extension document should consist of two paragraphs. 10 | 11 | The first one should be very short, only one or two sentences and serves as a short description of the extension. 12 | The second paragraph should be longer and should explain the intention of an extension. 13 | This is the extension template document. 14 | It is used to create an extension according to the [Homie Extension Convention](). 15 | "A Homie device may therefore support extensions, defined in separate documents. Every extension is identified by a unique ID and will be linked from this section"\[1\]. 16 | The above was a quote from the Homie Convention to illustrate the usage of the [Attribution](#Attribution) section. 17 | 18 | ## Homie Version 19 | This extension supports Homie `3.0.1` and `4.x`. 20 | 21 | ## Extension Identifier 22 | The ID of this extension is `org.example.our-feature`. 23 | Therefore the **$extensions entry** is `org.example.our-feature:x.x.x:[3.0.1;4.x]`. 24 | 25 | ## Extension Datatypes 26 | This extension defines one new datatype. 27 | 28 | ### Vector 29 | - Vector payload validity varies depending on the property format definition 30 | - Vector types are represented in format (f1,...,fn) where f1 to fn are string literal representations of 64-bit signed floating point numbers 31 | - Vector entries range from 2-1074 to (2-2-52)*21023 32 | - An empty string ("") is not a valid payload 33 | 34 | #### Vector format 35 | - The format of a Vector type specifies its mathematical dimension `n` 36 | - Therefor the format has to be a natrual number greater then 0 37 | 38 | ## Extension Attributes 39 | 40 | ### Device Attributes 41 | 42 | This extension defines no device attributes. 43 | 44 | ### Node Attributes 45 | This extension defines no direct node attributes. 46 | 47 | #### Nested Node Attributes 48 | 49 | This extension defines one nested node attribute. 50 | 51 | ##### $coordinate-system 52 | 53 | The **$coordinate-system** nesting attribute is **optional**. 54 | If its used, it defines one **required** nested attribute: 55 | 56 | | Topic | Description | Payload type | 57 | |---------------------------------------|---------------------------------------------------|------------------------------------| 58 | | $coordinate-system/$handedness | Handedness of the coordinate system. | Enum: \[left_handed,right_handed\] | 59 | 60 | **Examples** 61 | Assuming the base topic is *homie*, device ID is *super-car* and node is *wheels* then: 62 | ```java 63 | homie/super-car/wheels/$coordinate-system/$handedness → "left_handed" 64 | ``` 65 | 66 | If the **$coordinate-system** nesting attribute is used, following nested attributes are **optional**. 67 | Not that the following table has a `Default value` row. Only tables for **optional** attributes have this row. 68 | 69 | | Topic | Description | Payload type | Default value| 70 | |---------------------------------------|---------------------------------------------------|------------------------------------|--------------| 71 | | $coordinate-system/$first-axis-name | Name of the first axis of the coordinate system. | String | "x-Axis" | 72 | | $coordinate-system/$second-axis-name | Name of the second axis of the coordinate system. | String | "y-Axis" | 73 | | $coordinate-system/$third-axis-name | Name of the third axis of the coordinate system. | String | "z-Axis" | 74 | | $coordinate-system/$axis-unit | The unit of the coordinate axis | String | | 75 | 76 | **Examples** 77 | Assuming the base topic is *homie*, device ID is *super-car* and node is *wheels* then: 78 | ```java 79 | homie/super-car/wheels/$coordinate-system/$first-axis-name → "Pitch" 80 | homie/super-car/wheels/$coordinate-system/$second-axis-name → "Yaw" 81 | homie/super-car/wheels/$coordinate-system/$third-axis-name → "Roll" 82 | homie/super-car/wheels/$coordinate-system/$axis-unit → "meter" 83 | ``` 84 | 85 | ### Property Attributes 86 | 87 | This extension defines no property attributes. 88 | 89 | ## Attribution 90 | - \[1\]: [The Homie Convention](https://homieiot.github.io/specification/#), [CCA 4.0](https://homieiot.github.io/license) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |


The Homie Convention

2 | A lightweight MQTT convention for the IoT 3 | 4 | ## Motivation 5 | 6 | The Homie convention strives to be a messageing convention that makes it easy to interconnect IoT devices. In such a way that devices will not need to know anything about other devices internal implementations, hardware, or connectivity. 7 | 8 | The Homie convention is a **communication definition on top of MQTT** between IoT devices and controlling entities. 9 | 10 | > [MQTT](http://mqtt.org) is a machine-to-machine (M2M)/"Internet of Things" connectivity protocol. 11 | > It was designed as an extremely lightweight publish/subscribe messaging transport. 12 | 13 | MQTT supports easy and unrestricted message-based communication. 14 | However, MQTT doesn't define the structure and content of these messages and their relation. 15 | An IoT device publishes data and provides interaction possibilities but a controlling entity will need to be specifically configured to be able to interface with the device. 16 | 17 | The Homie convention defines a **standardized way** of how IoT devices and services announce themselves and their data on the communication channel. 18 | The Homie convention is thereby a crucial aspect in the support of **automatic discovery, configuration and usage** of devices and services over the MQTT protocol. 19 | 20 | Find the convention here: https://homieiot.github.io 21 | 22 | --- 23 | 24 | ## Guiding design principles 25 | 26 | These principles should be taken into account when proposing changes to the conventuion. 27 | 28 | ### Separation of concerns 29 | Many of todays HA applications, both commercial and free, take the approach of an all-in-one package (monolith). This creates closed eco systems and a duplication of work. The biggest challeng in IoT is connecting devices by writing driver-software to integrate them (because of the ever growing number of connected devices available). Each of the available monolithical HA applications duplicates this effort because of their integrated, tightly-coupled designs. 30 | 31 | The Homie based stack consists of multiple layers and components; 32 | * MQTT as the central communications bus 33 | * Homie as a MQTT-topic convention to discover and interact with devices and controllers in a standardized way without knowing the device specifics 34 | * Each device presents itself on this network, according to a well specified format 35 | 36 | This provides a way to only write device interfaces/drivers once, whilst at the same time allows for app developers to build competing apps without having to do the entire infrastructure as well. Which will provide more choice for the users in how they interact with the system. 37 | 38 | ### Message bus 39 | Use an industry standard communications bus, no home grown protocols; MQTT. 40 | There are many implementations available both free and commercial. 41 | 42 | ### Easy for users 43 | It should have a low entry barrier to use. The only central component required is an MQTT server. So set up an MQTT server, connect a device and a controller application and start controlling your devices 44 | 45 | ### Easy for developers 46 | It should have a low entry barrier for developers. Set up an MQTT server and grab a Homie library and start coding. 47 | 48 | ### Resource constraints 49 | Devices with very limited resources should still be able to use the Homie Convention (provided they are MQTT capable). 50 | Controllers are assumed to have more resources available, to be able to build multiple device representations and control many devices simultaneously. 51 | 52 | ### No control logic 53 | Homie does specify control logic for devices. It specifies the means by wich other devices or controllers can interact but does not have any logic by itself. Logic engines (if-this then-that) are separate and can be build on top of the convention. 54 | 55 | ### No GUI type specifications 56 | Homie does not specify how a GUI should present a device. At most it provides metadata in the device/service descriptions for display etc. GUI's are seperate implementations and can be build on top of the convention. 57 | The convention is considerate to specify devices descriptions in a way that will provide hints to a GUI 58 | See also [device state](#device-state) below 59 | 60 | ### Debugging and troubleshooting 61 | It should be easy to debug applications, and get feedback from users what is happening in case of problems/support. This is implemented with simple basic types, transmitted in plain text over the MQTT topics. 62 | 63 | --- 64 | 65 | ## Device design 66 | 67 | Some guidelines for designing Homie device interfaces 68 | 69 | 70 | ### Eventual consistency 71 | An MQTT bus does not guarantee the order of delivery of messages. This might cause messages to arrive in an order that might be considered invalid. This is an eventual consistency problem, since over time, after all messages have been received, the state should be consistent again. Developers should take this into account. 72 | 73 | ### Device state 74 | The Homie convention allows devices to specify an unambiguous state. This is not necessarily the same state as would be present in a GUI. 75 | 76 | The typical example would be a dimmable light. In a GUI this is often represented as switch (on/off) and a slider (0-100%). Consider the brigtness to be at 0%, and then the user switches the light on. What will now happen? this is an example of an ambiguous state. To make it unambiguous the slider should be designed as 1-100%, taking out the 0% option, since that is perceived as "off". 77 | 78 | So the Homie device can use the on/off and 1-100% settings to be unambiguous. However a GUI can choose how it maps those values and settings to a user interface. 79 | --------------------------------------------------------------------------------